agor-live 0.22.0 → 0.23.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1006) 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 +7 -1
  38. package/dist/cli/commands/branch/env/start.d.ts.map +1 -1
  39. package/dist/cli/commands/branch/env/start.js +7 -1
  40. package/dist/cli/commands/branch/env/stop.d.ts.map +1 -1
  41. package/dist/cli/commands/branch/env/stop.js +7 -1
  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 +7 -2
  103. package/dist/core/api/index.d.ts +13 -4
  104. package/dist/core/api/index.d.ts.map +1 -1
  105. package/dist/core/api/index.js +7 -2
  106. package/dist/core/claude/index.cjs +518 -89
  107. package/dist/core/claude/index.js +515 -88
  108. package/dist/core/claude-cli/index.cjs +24 -0
  109. package/dist/core/claude-cli/index.js +24 -0
  110. package/dist/core/claude-cli/pricing.d.ts.map +1 -1
  111. package/dist/core/client/index.cjs +52 -7
  112. package/dist/core/client/index.js +48 -7
  113. package/dist/core/config/browser.cjs +3 -5
  114. package/dist/core/config/browser.js +3 -5
  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/index.cjs +4259 -4527
  118. package/dist/core/config/index.d.ts +1 -0
  119. package/dist/core/config/index.d.ts.map +1 -1
  120. package/dist/core/config/index.js +4295 -4583
  121. package/dist/core/config/key-resolver.d.ts.map +1 -1
  122. package/dist/core/config/multitenancy.d.ts +33 -0
  123. package/dist/core/config/multitenancy.d.ts.map +1 -0
  124. package/dist/core/config/security-resolver.d.ts +1 -0
  125. package/dist/core/config/security-resolver.d.ts.map +1 -1
  126. package/dist/core/config/types.d.ts +67 -4
  127. package/dist/core/config/types.d.ts.map +1 -1
  128. package/dist/core/db/client.d.ts +34 -2
  129. package/dist/core/db/client.d.ts.map +1 -1
  130. package/dist/core/db/database-wrapper.d.ts.map +1 -1
  131. package/dist/core/db/first-run-bootstrap.d.ts.map +1 -1
  132. package/dist/core/db/index.cjs +2767 -1232
  133. package/dist/core/db/index.d.ts +2 -1
  134. package/dist/core/db/index.d.ts.map +1 -1
  135. package/dist/core/db/index.js +2601 -1094
  136. package/dist/core/db/migrate.d.ts.map +1 -1
  137. package/dist/core/db/repositories/artifacts.d.ts +27 -2
  138. package/dist/core/db/repositories/artifacts.d.ts.map +1 -1
  139. package/dist/core/db/repositories/base.d.ts +18 -0
  140. package/dist/core/db/repositories/base.d.ts.map +1 -1
  141. package/dist/core/db/repositories/board-comments.d.ts +17 -1
  142. package/dist/core/db/repositories/board-comments.d.ts.map +1 -1
  143. package/dist/core/db/repositories/board-objects.d.ts.map +1 -1
  144. package/dist/core/db/repositories/boards.d.ts +54 -3
  145. package/dist/core/db/repositories/boards.d.ts.map +1 -1
  146. package/dist/core/db/repositories/branch-access.d.ts +32 -0
  147. package/dist/core/db/repositories/branch-access.d.ts.map +1 -1
  148. package/dist/core/db/repositories/branches.d.ts +52 -2
  149. package/dist/core/db/repositories/branches.d.ts.map +1 -1
  150. package/dist/core/db/repositories/cards.d.ts +15 -1
  151. package/dist/core/db/repositories/cards.d.ts.map +1 -1
  152. package/dist/core/db/repositories/gateway-channels.d.ts +9 -0
  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 +2 -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/sessions.d.ts +56 -5
  164. package/dist/core/db/repositories/sessions.d.ts.map +1 -1
  165. package/dist/core/db/repositories/tasks.d.ts +7 -2
  166. package/dist/core/db/repositories/tasks.d.ts.map +1 -1
  167. package/dist/core/db/repositories/user-api-keys.d.ts +10 -1
  168. package/dist/core/db/repositories/user-api-keys.d.ts.map +1 -1
  169. package/dist/core/db/repositories/users.d.ts +8 -8
  170. package/dist/core/db/repositories/users.d.ts.map +1 -1
  171. package/dist/core/db/schema.d.ts +1460 -38
  172. package/dist/core/db/schema.d.ts.map +1 -1
  173. package/dist/core/db/schema.postgres.d.ts +1082 -37
  174. package/dist/core/db/schema.postgres.d.ts.map +1 -1
  175. package/dist/core/db/schema.sqlite.d.ts +397 -1
  176. package/dist/core/db/schema.sqlite.d.ts.map +1 -1
  177. package/dist/core/db/tenant-context.d.ts +26 -0
  178. package/dist/core/db/tenant-context.d.ts.map +1 -0
  179. package/dist/core/db/tenant-scope.d.ts +31 -0
  180. package/dist/core/db/tenant-scope.d.ts.map +1 -0
  181. package/dist/core/db/user-utils.d.ts +2 -2
  182. package/dist/core/db/user-utils.d.ts.map +1 -1
  183. package/dist/core/drizzle/postgres/0052_gateway_outbound_messages.sql +45 -0
  184. package/dist/core/drizzle/postgres/0053_user_token_invalidation.sql +1 -0
  185. package/dist/core/drizzle/postgres/0054_app_level_multitenancy.sql +219 -0
  186. package/dist/core/drizzle/postgres/0055_app_level_multitenancy_rls.sql +411 -0
  187. package/dist/core/drizzle/postgres/0056_composite_indexes.sql +15 -0
  188. package/dist/core/drizzle/postgres/0057_message_timestamp_indexes.sql +3 -0
  189. package/dist/core/drizzle/postgres/meta/_journal.json +42 -0
  190. package/dist/core/drizzle/sqlite/0061_gateway_outbound_messages.sql +38 -0
  191. package/dist/core/drizzle/sqlite/0062_user_token_invalidation.sql +1 -0
  192. package/dist/core/drizzle/sqlite/0063_composite_indexes.sql +10 -0
  193. package/dist/core/drizzle/sqlite/0064_message_timestamp_indexes.sql +2 -0
  194. package/dist/core/drizzle/sqlite/meta/_journal.json +28 -0
  195. package/dist/core/environment/render-snapshot.cjs +7 -6
  196. package/dist/core/environment/render-snapshot.d.ts +2 -0
  197. package/dist/core/environment/render-snapshot.d.ts.map +1 -1
  198. package/dist/core/environment/render-snapshot.js +7 -6
  199. package/dist/core/environment/variable-resolver.cjs +3 -1
  200. package/dist/core/environment/variable-resolver.js +3 -1
  201. package/dist/core/environment/webhook.cjs +1 -4
  202. package/dist/core/environment/webhook.js +1 -4
  203. package/dist/core/gateway/connector.d.ts +10 -1
  204. package/dist/core/gateway/connector.d.ts.map +1 -1
  205. package/dist/core/gateway/connectors/slack-manifest.cjs +108 -0
  206. package/dist/core/gateway/connectors/slack-manifest.d.ts +85 -0
  207. package/dist/core/gateway/connectors/slack-manifest.d.ts.map +1 -0
  208. package/dist/core/gateway/connectors/slack-manifest.js +81 -0
  209. package/dist/core/gateway/connectors/slack.d.ts +101 -4
  210. package/dist/core/gateway/connectors/slack.d.ts.map +1 -1
  211. package/dist/core/gateway/index.cjs +495 -29
  212. package/dist/core/gateway/index.d.ts +4 -1
  213. package/dist/core/gateway/index.d.ts.map +1 -1
  214. package/dist/core/gateway/index.js +490 -28
  215. package/dist/core/gateway/system-message.d.ts.map +1 -1
  216. package/dist/core/git/exec.cjs +24 -0
  217. package/dist/core/git/exec.d.ts +6 -4
  218. package/dist/core/git/exec.d.ts.map +1 -1
  219. package/dist/core/git/exec.js +2 -0
  220. package/dist/core/git/index.cjs +3 -1363
  221. package/dist/core/git/index.d.ts +4 -614
  222. package/dist/core/git/index.d.ts.map +1 -1
  223. package/dist/core/git/index.js +1 -1304
  224. package/dist/core/git/pure.cjs +24 -0
  225. package/dist/core/git/pure.d.ts +2 -27
  226. package/dist/core/git/pure.d.ts.map +1 -1
  227. package/dist/core/git/pure.js +2 -0
  228. package/dist/core/index.cjs +11563 -10832
  229. package/dist/core/index.d.ts +2 -0
  230. package/dist/core/index.d.ts.map +1 -1
  231. package/dist/core/index.js +12203 -10962
  232. package/dist/core/lib/feathers-validation.cjs +9 -1
  233. package/dist/core/lib/feathers-validation.d.ts +2 -0
  234. package/dist/core/lib/feathers-validation.d.ts.map +1 -1
  235. package/dist/core/lib/feathers-validation.js +9 -1
  236. package/dist/core/local-actions/git-remotes.d.ts +7 -0
  237. package/dist/core/local-actions/git-remotes.d.ts.map +1 -0
  238. package/dist/core/local-actions/index.cjs +8008 -0
  239. package/dist/core/local-actions/index.d.ts +6 -0
  240. package/dist/core/local-actions/index.d.ts.map +1 -0
  241. package/dist/core/local-actions/index.js +8010 -0
  242. package/dist/core/local-actions/symlinks.d.ts +20 -0
  243. package/dist/core/local-actions/symlinks.d.ts.map +1 -0
  244. package/dist/core/local-actions/types.d.ts +14 -0
  245. package/dist/core/local-actions/types.d.ts.map +1 -0
  246. package/dist/core/local-actions/unix-groups.d.ts +16 -0
  247. package/dist/core/local-actions/unix-groups.d.ts.map +1 -0
  248. package/dist/core/local-actions/unix-users.d.ts +12 -0
  249. package/dist/core/local-actions/unix-users.d.ts.map +1 -0
  250. package/dist/core/mcp/index.cjs +373 -28
  251. package/dist/core/mcp/index.d.ts +1 -1
  252. package/dist/core/mcp/index.d.ts.map +1 -1
  253. package/dist/core/mcp/index.js +369 -27
  254. package/dist/core/mcp/template-patterns.d.ts +15 -0
  255. package/dist/core/mcp/template-patterns.d.ts.map +1 -0
  256. package/dist/core/mcp/template-resolver.d.ts +13 -0
  257. package/dist/core/mcp/template-resolver.d.ts.map +1 -1
  258. package/dist/core/models/browser.cjs +154 -25
  259. package/dist/core/models/browser.js +150 -25
  260. package/dist/core/models/claude.d.ts +2 -2
  261. package/dist/core/models/claude.d.ts.map +1 -1
  262. package/dist/core/models/codex.d.ts +205 -21
  263. package/dist/core/models/codex.d.ts.map +1 -1
  264. package/dist/core/models/index.cjs +154 -25
  265. package/dist/core/models/index.js +150 -25
  266. package/dist/core/package.json +24 -0
  267. package/dist/core/seed/demo-fixtures.d.ts +87 -0
  268. package/dist/core/seed/demo-fixtures.d.ts.map +1 -0
  269. package/dist/core/seed/dev-fixtures.d.ts.map +1 -1
  270. package/dist/core/seed/index.cjs +8569 -5519
  271. package/dist/core/seed/index.d.ts +1 -0
  272. package/dist/core/seed/index.d.ts.map +1 -1
  273. package/dist/core/seed/index.js +8580 -5535
  274. package/dist/core/sessions/index.cjs +110 -24
  275. package/dist/core/sessions/index.js +110 -24
  276. package/dist/core/telemetry/index.cjs +361 -0
  277. package/dist/core/telemetry/index.d.ts +5 -0
  278. package/dist/core/telemetry/index.d.ts.map +1 -0
  279. package/dist/core/telemetry/index.js +315 -0
  280. package/dist/core/telemetry/logger.d.ts +44 -0
  281. package/dist/core/telemetry/logger.d.ts.map +1 -0
  282. package/dist/core/telemetry/model-normalization.d.ts +3 -0
  283. package/dist/core/telemetry/model-normalization.d.ts.map +1 -0
  284. package/dist/core/telemetry/types.d.ts +47 -0
  285. package/dist/core/telemetry/types.d.ts.map +1 -0
  286. package/dist/core/telemetry/version.d.ts +9 -0
  287. package/dist/core/telemetry/version.d.ts.map +1 -0
  288. package/dist/core/templates/agor-system-prompt.md +1 -0
  289. package/dist/core/templates/handlebars-helpers.cjs +3 -1
  290. package/dist/core/templates/handlebars-helpers.d.ts +5 -0
  291. package/dist/core/templates/handlebars-helpers.d.ts.map +1 -1
  292. package/dist/core/templates/handlebars-helpers.js +3 -1
  293. package/dist/core/tools/mcp/auth-secrets.cjs +3460 -3
  294. package/dist/core/tools/mcp/auth-secrets.d.ts.map +1 -1
  295. package/dist/core/tools/mcp/auth-secrets.js +3477 -3
  296. package/dist/core/tools/mcp/http-headers.cjs +17 -1
  297. package/dist/core/tools/mcp/http-headers.d.ts.map +1 -1
  298. package/dist/core/tools/mcp/http-headers.js +15 -1
  299. package/dist/core/tools/mcp/oauth-refresh.cjs +568 -114
  300. package/dist/core/tools/mcp/oauth-refresh.js +566 -115
  301. package/dist/core/types/board.d.ts +14 -0
  302. package/dist/core/types/board.d.ts.map +1 -1
  303. package/dist/core/types/branch.d.ts +13 -0
  304. package/dist/core/types/branch.d.ts.map +1 -1
  305. package/dist/core/types/config-services.d.ts.map +1 -1
  306. package/dist/core/types/feathers.d.ts +6 -0
  307. package/dist/core/types/feathers.d.ts.map +1 -1
  308. package/dist/core/types/gateway.d.ts +90 -1
  309. package/dist/core/types/gateway.d.ts.map +1 -1
  310. package/dist/core/types/index.cjs +42 -0
  311. package/dist/core/types/index.d.ts +1 -0
  312. package/dist/core/types/index.d.ts.map +1 -1
  313. package/dist/core/types/index.js +38 -0
  314. package/dist/core/types/schedule.d.ts +4 -3
  315. package/dist/core/types/schedule.d.ts.map +1 -1
  316. package/dist/core/types/session.d.ts +7 -1
  317. package/dist/core/types/session.d.ts.map +1 -1
  318. package/dist/core/types/tenant.d.ts +15 -0
  319. package/dist/core/types/tenant.d.ts.map +1 -0
  320. package/dist/core/types/user.d.ts +61 -0
  321. package/dist/core/types/user.d.ts.map +1 -1
  322. package/dist/core/unix/index.cjs +1123 -674
  323. package/dist/core/unix/index.js +1071 -624
  324. package/dist/core/utils/emoji-shortcodes.d.ts +13 -0
  325. package/dist/core/utils/emoji-shortcodes.d.ts.map +1 -0
  326. package/dist/core/yaml/index.cjs +8 -8
  327. package/dist/core/yaml/index.d.ts +1 -1
  328. package/dist/core/yaml/index.d.ts.map +1 -1
  329. package/dist/core/yaml/index.js +7 -7
  330. package/dist/daemon/adapters/drizzle.d.ts +26 -4
  331. package/dist/daemon/adapters/drizzle.d.ts.map +1 -1
  332. package/dist/daemon/adapters/drizzle.js +68 -7
  333. package/dist/daemon/auth/api-key-strategy.js +1 -1
  334. package/dist/daemon/auth/executor-runtime-scope.d.ts.map +1 -1
  335. package/dist/daemon/auth/executor-runtime-scope.js +34 -6
  336. package/dist/daemon/auth/executor-session-token.d.ts +15 -0
  337. package/dist/daemon/auth/executor-session-token.d.ts.map +1 -0
  338. package/dist/daemon/auth/executor-session-token.js +17 -0
  339. package/dist/daemon/auth/issue-browser-tokens-hook.d.ts +24 -0
  340. package/dist/daemon/auth/issue-browser-tokens-hook.d.ts.map +1 -0
  341. package/dist/daemon/auth/issue-browser-tokens-hook.js +95 -0
  342. package/dist/daemon/auth/launch-auth.d.ts +5 -4
  343. package/dist/daemon/auth/launch-auth.d.ts.map +1 -1
  344. package/dist/daemon/auth/launch-auth.js +123 -39
  345. package/dist/daemon/auth/refresh-token-service.d.ts +22 -0
  346. package/dist/daemon/auth/refresh-token-service.d.ts.map +1 -0
  347. package/dist/daemon/auth/refresh-token-service.js +133 -0
  348. package/dist/daemon/auth/runtime-tokens.d.ts +3 -1
  349. package/dist/daemon/auth/runtime-tokens.d.ts.map +1 -1
  350. package/dist/daemon/auth/runtime-tokens.js +17 -4
  351. package/dist/daemon/auth/service-jwt-strategy.d.ts +2 -1
  352. package/dist/daemon/auth/service-jwt-strategy.d.ts.map +1 -1
  353. package/dist/daemon/auth/service-jwt-strategy.js +141 -3
  354. package/dist/daemon/auth/token-invalidation.d.ts +11 -0
  355. package/dist/daemon/auth/token-invalidation.d.ts.map +1 -0
  356. package/dist/daemon/auth/token-invalidation.js +38 -0
  357. package/dist/daemon/auth/user-redaction.d.ts +12 -0
  358. package/dist/daemon/auth/user-redaction.d.ts.map +1 -0
  359. package/dist/daemon/auth/user-redaction.js +13 -0
  360. package/dist/daemon/declarations.d.ts +5 -4
  361. package/dist/daemon/declarations.d.ts.map +1 -1
  362. package/dist/daemon/hooks/gateway-route.d.ts.map +1 -1
  363. package/dist/daemon/hooks/gateway-route.js +23 -13
  364. package/dist/daemon/index.d.ts.map +1 -1
  365. package/dist/daemon/index.js +8271 -2956
  366. package/dist/daemon/knowledge/pgvector.d.ts +3 -3
  367. package/dist/daemon/knowledge/pgvector.d.ts.map +1 -1
  368. package/dist/daemon/knowledge/pgvector.js +24 -0
  369. package/dist/daemon/knowledge/units.d.ts +2 -2
  370. package/dist/daemon/knowledge/units.d.ts.map +1 -1
  371. package/dist/daemon/main.js +8271 -2956
  372. package/dist/daemon/mcp/server.d.ts +3 -3
  373. package/dist/daemon/mcp/server.d.ts.map +1 -1
  374. package/dist/daemon/mcp/server.js +1740 -81
  375. package/dist/daemon/mcp/tokens.d.ts +2 -2
  376. package/dist/daemon/mcp/tokens.d.ts.map +1 -1
  377. package/dist/daemon/mcp/tokens.js +5 -1
  378. package/dist/daemon/mcp/tool-registry.d.ts.map +1 -1
  379. package/dist/daemon/mcp/tool-registry.js +1 -0
  380. package/dist/daemon/mcp/tools/analytics.d.ts.map +1 -1
  381. package/dist/daemon/mcp/tools/analytics.js +598 -24
  382. package/dist/daemon/mcp/tools/artifacts.js +560 -20
  383. package/dist/daemon/mcp/tools/boards.d.ts.map +1 -1
  384. package/dist/daemon/mcp/tools/boards.js +567 -21
  385. package/dist/daemon/mcp/tools/branches.d.ts.map +1 -1
  386. package/dist/daemon/mcp/tools/branches.js +624 -50
  387. package/dist/daemon/mcp/tools/card-types.js +558 -18
  388. package/dist/daemon/mcp/tools/cards.js +558 -18
  389. package/dist/daemon/mcp/tools/environment.js +566 -18
  390. package/dist/daemon/mcp/tools/gateway-channels.d.ts +4 -0
  391. package/dist/daemon/mcp/tools/gateway-channels.d.ts.map +1 -0
  392. package/dist/daemon/mcp/tools/gateway-channels.js +16187 -0
  393. package/dist/daemon/mcp/tools/knowledge.js +558 -18
  394. package/dist/daemon/mcp/tools/mcp-servers.d.ts.map +1 -1
  395. package/dist/daemon/mcp/tools/mcp-servers.js +893 -18
  396. package/dist/daemon/mcp/tools/messages.d.ts.map +1 -1
  397. package/dist/daemon/mcp/tools/messages.js +618 -32
  398. package/dist/daemon/mcp/tools/proxies.js +568 -20
  399. package/dist/daemon/mcp/tools/repos.js +558 -18
  400. package/dist/daemon/mcp/tools/schedules.d.ts.map +1 -1
  401. package/dist/daemon/mcp/tools/schedules.js +561 -19
  402. package/dist/daemon/mcp/tools/search.js +558 -18
  403. package/dist/daemon/mcp/tools/sessions.d.ts.map +1 -1
  404. package/dist/daemon/mcp/tools/sessions.js +571 -24
  405. package/dist/daemon/mcp/tools/tasks.js +558 -18
  406. package/dist/daemon/mcp/tools/users.d.ts.map +1 -1
  407. package/dist/daemon/mcp/tools/users.js +577 -23
  408. package/dist/daemon/mcp/tools/widgets.d.ts.map +1 -1
  409. package/dist/daemon/mcp/tools/widgets.js +759 -83
  410. package/dist/daemon/oauth-auth-helpers.d.ts +35 -0
  411. package/dist/daemon/oauth-auth-helpers.d.ts.map +1 -0
  412. package/dist/daemon/oauth-auth-helpers.js +14 -0
  413. package/dist/daemon/register-hooks.d.ts +4 -2
  414. package/dist/daemon/register-hooks.d.ts.map +1 -1
  415. package/dist/daemon/register-hooks.js +1158 -595
  416. package/dist/daemon/register-routes.d.ts +3 -2
  417. package/dist/daemon/register-routes.d.ts.map +1 -1
  418. package/dist/daemon/register-routes.js +3161 -812
  419. package/dist/daemon/register-services.d.ts +2 -2
  420. package/dist/daemon/register-services.d.ts.map +1 -1
  421. package/dist/daemon/register-services.js +2782 -739
  422. package/dist/daemon/services/artifacts.d.ts +34 -6
  423. package/dist/daemon/services/artifacts.d.ts.map +1 -1
  424. package/dist/daemon/services/artifacts.js +109 -8
  425. package/dist/daemon/services/assistant-knowledge.d.ts +2 -2
  426. package/dist/daemon/services/assistant-knowledge.d.ts.map +1 -1
  427. package/dist/daemon/services/board-comments.d.ts +8 -5
  428. package/dist/daemon/services/board-comments.d.ts.map +1 -1
  429. package/dist/daemon/services/board-comments.js +78 -13
  430. package/dist/daemon/services/board-objects.d.ts +8 -5
  431. package/dist/daemon/services/board-objects.d.ts.map +1 -1
  432. package/dist/daemon/services/board-objects.js +14 -4
  433. package/dist/daemon/services/boards.d.ts +39 -5
  434. package/dist/daemon/services/boards.d.ts.map +1 -1
  435. package/dist/daemon/services/boards.js +123 -8
  436. package/dist/daemon/services/branch-owners.d.ts +3 -1
  437. package/dist/daemon/services/branch-owners.d.ts.map +1 -1
  438. package/dist/daemon/services/branch-owners.js +31 -4
  439. package/dist/daemon/services/branches.d.ts +31 -8
  440. package/dist/daemon/services/branches.d.ts.map +1 -1
  441. package/dist/daemon/services/branches.js +272 -36
  442. package/dist/daemon/services/card-types.d.ts +3 -3
  443. package/dist/daemon/services/card-types.d.ts.map +1 -1
  444. package/dist/daemon/services/card-types.js +68 -7
  445. package/dist/daemon/services/cards.d.ts +19 -4
  446. package/dist/daemon/services/cards.d.ts.map +1 -1
  447. package/dist/daemon/services/cards.js +92 -8
  448. package/dist/daemon/services/check-auth.d.ts +2 -2
  449. package/dist/daemon/services/check-auth.d.ts.map +1 -1
  450. package/dist/daemon/services/claude-cli-integration.d.ts +4 -1
  451. package/dist/daemon/services/claude-cli-integration.d.ts.map +1 -1
  452. package/dist/daemon/services/claude-cli-integration.js +117 -65
  453. package/dist/daemon/services/claude-models.d.ts +3 -3
  454. package/dist/daemon/services/claude-models.d.ts.map +1 -1
  455. package/dist/daemon/services/claude-models.js +387 -273
  456. package/dist/daemon/services/config.d.ts +12 -4
  457. package/dist/daemon/services/config.d.ts.map +1 -1
  458. package/dist/daemon/services/config.js +39 -3
  459. package/dist/daemon/services/copilot-models.d.ts +3 -3
  460. package/dist/daemon/services/copilot-models.d.ts.map +1 -1
  461. package/dist/daemon/services/cursor-models.d.ts +3 -3
  462. package/dist/daemon/services/cursor-models.d.ts.map +1 -1
  463. package/dist/daemon/services/files.d.ts +3 -3
  464. package/dist/daemon/services/files.d.ts.map +1 -1
  465. package/dist/daemon/services/files.js +24 -5
  466. package/dist/daemon/services/gateway-channels-test.d.ts +24 -0
  467. package/dist/daemon/services/gateway-channels-test.d.ts.map +1 -0
  468. package/dist/daemon/services/gateway-channels-test.js +66 -0
  469. package/dist/daemon/services/gateway-channels.d.ts +3 -3
  470. package/dist/daemon/services/gateway-channels.d.ts.map +1 -1
  471. package/dist/daemon/services/gateway-channels.js +68 -7
  472. package/dist/daemon/services/gateway.d.ts +63 -3
  473. package/dist/daemon/services/gateway.d.ts.map +1 -1
  474. package/dist/daemon/services/gateway.js +640 -60
  475. package/dist/daemon/services/github-app-setup.d.ts +3 -3
  476. package/dist/daemon/services/github-app-setup.d.ts.map +1 -1
  477. package/dist/daemon/services/groups.d.ts +5 -5
  478. package/dist/daemon/services/groups.d.ts.map +1 -1
  479. package/dist/daemon/services/health-monitor.d.ts +34 -2
  480. package/dist/daemon/services/health-monitor.d.ts.map +1 -1
  481. package/dist/daemon/services/health-monitor.js +155 -30
  482. package/dist/daemon/services/knowledge-document-edits.d.ts +3 -3
  483. package/dist/daemon/services/knowledge-document-edits.d.ts.map +1 -1
  484. package/dist/daemon/services/knowledge-documents.d.ts +3 -3
  485. package/dist/daemon/services/knowledge-documents.d.ts.map +1 -1
  486. package/dist/daemon/services/knowledge-documents.js +92 -7
  487. package/dist/daemon/services/knowledge-embedding-indexer.d.ts +7 -2
  488. package/dist/daemon/services/knowledge-embedding-indexer.d.ts.map +1 -1
  489. package/dist/daemon/services/knowledge-embedding-indexer.js +37 -3
  490. package/dist/daemon/services/knowledge-graph.d.ts +3 -3
  491. package/dist/daemon/services/knowledge-graph.d.ts.map +1 -1
  492. package/dist/daemon/services/knowledge-indexing.d.ts +3 -3
  493. package/dist/daemon/services/knowledge-indexing.d.ts.map +1 -1
  494. package/dist/daemon/services/knowledge-namespaces.d.ts +3 -3
  495. package/dist/daemon/services/knowledge-namespaces.d.ts.map +1 -1
  496. package/dist/daemon/services/knowledge-namespaces.js +72 -8
  497. package/dist/daemon/services/knowledge-reindex.d.ts +3 -3
  498. package/dist/daemon/services/knowledge-reindex.d.ts.map +1 -1
  499. package/dist/daemon/services/knowledge-reindex.js +28 -1
  500. package/dist/daemon/services/knowledge-search.d.ts +3 -3
  501. package/dist/daemon/services/knowledge-search.d.ts.map +1 -1
  502. package/dist/daemon/services/knowledge-settings.d.ts +3 -3
  503. package/dist/daemon/services/knowledge-settings.d.ts.map +1 -1
  504. package/dist/daemon/services/knowledge-settings.js +24 -0
  505. package/dist/daemon/services/knowledge-versions.d.ts +3 -3
  506. package/dist/daemon/services/knowledge-versions.d.ts.map +1 -1
  507. package/dist/daemon/services/knowledge-versions.js +68 -7
  508. package/dist/daemon/services/leaderboard.d.ts +14 -6
  509. package/dist/daemon/services/leaderboard.d.ts.map +1 -1
  510. package/dist/daemon/services/leaderboard.js +74 -15
  511. package/dist/daemon/services/local-actions.d.ts +13 -0
  512. package/dist/daemon/services/local-actions.d.ts.map +1 -0
  513. package/dist/daemon/services/local-actions.js +120 -0
  514. package/dist/daemon/services/mcp-servers.d.ts +3 -3
  515. package/dist/daemon/services/mcp-servers.d.ts.map +1 -1
  516. package/dist/daemon/services/mcp-servers.js +68 -7
  517. package/dist/daemon/services/messages.d.ts +10 -6
  518. package/dist/daemon/services/messages.d.ts.map +1 -1
  519. package/dist/daemon/services/messages.js +87 -7
  520. package/dist/daemon/services/repos.d.ts +6 -6
  521. package/dist/daemon/services/repos.d.ts.map +1 -1
  522. package/dist/daemon/services/repos.js +131 -32
  523. package/dist/daemon/services/scheduler.d.ts +23 -27
  524. package/dist/daemon/services/scheduler.d.ts.map +1 -1
  525. package/dist/daemon/services/scheduler.js +55 -28
  526. package/dist/daemon/services/schedules.d.ts +3 -3
  527. package/dist/daemon/services/schedules.d.ts.map +1 -1
  528. package/dist/daemon/services/schedules.js +68 -7
  529. package/dist/daemon/services/session-env-selections.d.ts +3 -3
  530. package/dist/daemon/services/session-env-selections.d.ts.map +1 -1
  531. package/dist/daemon/services/session-mcp-servers.d.ts +3 -3
  532. package/dist/daemon/services/session-mcp-servers.d.ts.map +1 -1
  533. package/dist/daemon/services/session-streams.d.ts +29 -0
  534. package/dist/daemon/services/session-streams.d.ts.map +1 -0
  535. package/dist/daemon/services/session-streams.js +84 -0
  536. package/dist/daemon/services/session-token-service.d.ts.map +1 -1
  537. package/dist/daemon/services/session-token-service.js +11 -4
  538. package/dist/daemon/services/sessions.d.ts +9 -5
  539. package/dist/daemon/services/sessions.d.ts.map +1 -1
  540. package/dist/daemon/services/sessions.js +143 -10
  541. package/dist/daemon/services/tasks.d.ts +11 -5
  542. package/dist/daemon/services/tasks.d.ts.map +1 -1
  543. package/dist/daemon/services/tasks.js +199 -39
  544. package/dist/daemon/services/terminals.d.ts +21 -3
  545. package/dist/daemon/services/terminals.d.ts.map +1 -1
  546. package/dist/daemon/services/terminals.js +81 -25
  547. package/dist/daemon/services/thread-session-map.d.ts +3 -3
  548. package/dist/daemon/services/thread-session-map.d.ts.map +1 -1
  549. package/dist/daemon/services/thread-session-map.js +68 -7
  550. package/dist/daemon/services/user-avatar-sync.d.ts +21 -0
  551. package/dist/daemon/services/user-avatar-sync.d.ts.map +1 -0
  552. package/dist/daemon/services/user-avatar-sync.js +267 -0
  553. package/dist/daemon/services/users.d.ts +29 -9
  554. package/dist/daemon/services/users.d.ts.map +1 -1
  555. package/dist/daemon/services/users.js +383 -30
  556. package/dist/daemon/services/zone-trigger.d.ts.map +1 -1
  557. package/dist/daemon/services/zone-trigger.js +17 -4
  558. package/dist/daemon/setup/build-info.d.ts +1 -1
  559. package/dist/daemon/setup/build-info.d.ts.map +1 -1
  560. package/dist/daemon/setup/build-info.js +5 -1
  561. package/dist/daemon/setup/database.d.ts +8 -3
  562. package/dist/daemon/setup/database.d.ts.map +1 -1
  563. package/dist/daemon/setup/database.js +26 -6
  564. package/dist/daemon/setup/first-run-admin.d.ts +2 -2
  565. package/dist/daemon/setup/first-run-admin.d.ts.map +1 -1
  566. package/dist/daemon/setup/index.js +137 -25
  567. package/dist/daemon/setup/socketio.d.ts +10 -1
  568. package/dist/daemon/setup/socketio.d.ts.map +1 -1
  569. package/dist/daemon/setup/socketio.js +108 -18
  570. package/dist/daemon/startup.d.ts +13 -2
  571. package/dist/daemon/startup.d.ts.map +1 -1
  572. package/dist/daemon/startup.js +377 -94
  573. package/dist/daemon/utils/append-system-message.d.ts +2 -2
  574. package/dist/daemon/utils/append-system-message.d.ts.map +1 -1
  575. package/dist/daemon/utils/apply-session-config-defaults.d.ts.map +1 -1
  576. package/dist/daemon/utils/apply-session-config-defaults.js +12 -1
  577. package/dist/daemon/utils/authorization.d.ts +3 -1
  578. package/dist/daemon/utils/authorization.d.ts.map +1 -1
  579. package/dist/daemon/utils/authorization.js +36 -7
  580. package/dist/daemon/utils/branch-authorization.d.ts +30 -0
  581. package/dist/daemon/utils/branch-authorization.d.ts.map +1 -1
  582. package/dist/daemon/utils/branch-authorization.js +63 -5
  583. package/dist/daemon/utils/branch-inspect.d.ts +1 -0
  584. package/dist/daemon/utils/branch-inspect.d.ts.map +1 -1
  585. package/dist/daemon/utils/branch-inspect.js +11 -3
  586. package/dist/daemon/utils/emit-service-event.d.ts +56 -0
  587. package/dist/daemon/utils/emit-service-event.d.ts.map +1 -0
  588. package/dist/daemon/utils/emit-service-event.js +23 -0
  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-header-secrets.d.ts +3 -5
  597. package/dist/daemon/utils/mcp-header-secrets.d.ts.map +1 -1
  598. package/dist/daemon/utils/mcp-header-secrets.js +31 -2
  599. package/dist/daemon/utils/mcp-token-authorization.d.ts +18 -13
  600. package/dist/daemon/utils/mcp-token-authorization.d.ts.map +1 -1
  601. package/dist/daemon/utils/mcp-token-authorization.js +11 -5
  602. package/dist/daemon/utils/open-source-telemetry-config.d.ts +6 -0
  603. package/dist/daemon/utils/open-source-telemetry-config.d.ts.map +1 -0
  604. package/dist/daemon/utils/open-source-telemetry-config.js +21 -0
  605. package/dist/daemon/utils/open-source-telemetry-heartbeat.d.ts +7 -0
  606. package/dist/daemon/utils/open-source-telemetry-heartbeat.d.ts.map +1 -0
  607. package/dist/daemon/utils/open-source-telemetry-heartbeat.js +15 -0
  608. package/dist/daemon/utils/open-source-telemetry-usage.d.ts +9 -0
  609. package/dist/daemon/utils/open-source-telemetry-usage.d.ts.map +1 -0
  610. package/dist/daemon/utils/open-source-telemetry-usage.js +121 -0
  611. package/dist/daemon/utils/realign-repo-origin.d.ts +3 -3
  612. package/dist/daemon/utils/realign-repo-origin.d.ts.map +1 -1
  613. package/dist/daemon/utils/realign-repo-origin.js +47 -16
  614. package/dist/daemon/utils/realtime-access-cache.d.ts +9 -0
  615. package/dist/daemon/utils/realtime-access-cache.d.ts.map +1 -1
  616. package/dist/daemon/utils/realtime-access-cache.js +24 -0
  617. package/dist/daemon/utils/realtime-publish.d.ts +26 -0
  618. package/dist/daemon/utils/realtime-publish.d.ts.map +1 -1
  619. package/dist/daemon/utils/realtime-publish.js +171 -12
  620. package/dist/daemon/utils/session-queue-tenant-scope.d.ts +24 -0
  621. package/dist/daemon/utils/session-queue-tenant-scope.d.ts.map +1 -0
  622. package/dist/daemon/utils/session-queue-tenant-scope.js +133 -0
  623. package/dist/daemon/utils/session-state-hooks.d.ts +3 -3
  624. package/dist/daemon/utils/session-state-hooks.d.ts.map +1 -1
  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/gateway-token/index.d.ts +114 -0
  643. package/dist/daemon/widgets/gateway-token/index.d.ts.map +1 -0
  644. package/dist/daemon/widgets/gateway-token/index.js +14711 -0
  645. package/dist/daemon/widgets/index.d.ts.map +1 -1
  646. package/dist/daemon/widgets/index.js +327 -37
  647. package/dist/daemon/widgets/registry.d.ts +7 -0
  648. package/dist/daemon/widgets/registry.d.ts.map +1 -1
  649. package/dist/daemon/widgets/submissions.js +12 -9
  650. package/dist/executor/commands/environment.d.ts.map +1 -1
  651. package/dist/executor/commands/environment.js +9 -5
  652. package/dist/executor/commands/git.d.ts.map +1 -1
  653. package/dist/executor/commands/git.js +3 -1
  654. package/dist/executor/db/feathers-repositories.d.ts +19 -1
  655. package/dist/executor/db/feathers-repositories.d.ts.map +1 -1
  656. package/dist/executor/db/feathers-repositories.js +31 -1
  657. package/dist/executor/git/index.d.ts +8 -0
  658. package/dist/executor/git/index.d.ts.map +1 -0
  659. package/dist/executor/git/index.js +7 -0
  660. package/dist/executor/handlers/sdk/base-executor.d.ts.map +1 -1
  661. package/dist/executor/handlers/sdk/base-executor.js +4 -1
  662. package/dist/executor/handlers/sdk/claude.d.ts.map +1 -1
  663. package/dist/executor/handlers/sdk/claude.js +1 -1
  664. package/dist/executor/handlers/sdk/codex.d.ts.map +1 -1
  665. package/dist/executor/handlers/sdk/codex.js +1 -1
  666. package/dist/executor/handlers/sdk/copilot.d.ts.map +1 -1
  667. package/dist/executor/handlers/sdk/copilot.js +1 -1
  668. package/dist/executor/handlers/sdk/cursor.d.ts.map +1 -1
  669. package/dist/executor/handlers/sdk/cursor.js +1 -0
  670. package/dist/executor/handlers/sdk/gemini.d.ts.map +1 -1
  671. package/dist/executor/handlers/sdk/gemini.js +1 -1
  672. package/dist/executor/handlers/sdk/git-safe-directory.d.ts.map +1 -1
  673. package/dist/executor/handlers/sdk/git-safe-directory.js +1 -1
  674. package/dist/executor/handlers/sdk/opencode.d.ts.map +1 -1
  675. package/dist/executor/handlers/sdk/opencode.js +1 -1
  676. package/dist/executor/payload-types.d.ts +5 -5
  677. package/dist/executor/sdk-handlers/base/diff-enrichment.js +1 -1
  678. package/dist/executor/sdk-handlers/base/mcp-scoping.d.ts +8 -1
  679. package/dist/executor/sdk-handlers/base/mcp-scoping.d.ts.map +1 -1
  680. package/dist/executor/sdk-handlers/base/mcp-scoping.js +58 -6
  681. package/dist/executor/sdk-handlers/claude/claude-tool.d.ts +2 -2
  682. package/dist/executor/sdk-handlers/claude/claude-tool.d.ts.map +1 -1
  683. package/dist/executor/sdk-handlers/claude/claude-tool.js +2 -2
  684. package/dist/executor/sdk-handlers/claude/prompt-service.d.ts +13 -3
  685. package/dist/executor/sdk-handlers/claude/prompt-service.d.ts.map +1 -1
  686. package/dist/executor/sdk-handlers/claude/prompt-service.js +16 -3
  687. package/dist/executor/sdk-handlers/claude/query-builder.d.ts +2 -1
  688. package/dist/executor/sdk-handlers/claude/query-builder.d.ts.map +1 -1
  689. package/dist/executor/sdk-handlers/claude/query-builder.js +2 -1
  690. package/dist/executor/sdk-handlers/codex/codex-tool.d.ts +8 -12
  691. package/dist/executor/sdk-handlers/codex/codex-tool.d.ts.map +1 -1
  692. package/dist/executor/sdk-handlers/codex/codex-tool.js +14 -17
  693. package/dist/executor/sdk-handlers/codex/normalizer.d.ts.map +1 -1
  694. package/dist/executor/sdk-handlers/codex/normalizer.js +11 -1
  695. package/dist/executor/sdk-handlers/codex/pricing/litellm-openai-model-prices.json +3663 -0
  696. package/dist/executor/sdk-handlers/codex/pricing/litellm-pricing.d.ts +31 -0
  697. package/dist/executor/sdk-handlers/codex/pricing/litellm-pricing.d.ts.map +1 -0
  698. package/dist/executor/sdk-handlers/codex/pricing/litellm-pricing.js +46 -0
  699. package/dist/executor/sdk-handlers/codex/prompt-service.d.ts +3 -2
  700. package/dist/executor/sdk-handlers/codex/prompt-service.d.ts.map +1 -1
  701. package/dist/executor/sdk-handlers/codex/prompt-service.js +131 -12
  702. package/dist/executor/sdk-handlers/codex/usage.d.ts +14 -23
  703. package/dist/executor/sdk-handlers/codex/usage.d.ts.map +1 -1
  704. package/dist/executor/sdk-handlers/codex/usage.js +18 -33
  705. package/dist/executor/sdk-handlers/copilot/copilot-tool.d.ts +2 -2
  706. package/dist/executor/sdk-handlers/copilot/copilot-tool.d.ts.map +1 -1
  707. package/dist/executor/sdk-handlers/copilot/copilot-tool.js +2 -2
  708. package/dist/executor/sdk-handlers/copilot/prompt-service.d.ts +3 -2
  709. package/dist/executor/sdk-handlers/copilot/prompt-service.d.ts.map +1 -1
  710. package/dist/executor/sdk-handlers/copilot/prompt-service.js +4 -1
  711. package/dist/executor/sdk-handlers/gemini/gemini-tool.d.ts +2 -2
  712. package/dist/executor/sdk-handlers/gemini/gemini-tool.d.ts.map +1 -1
  713. package/dist/executor/sdk-handlers/gemini/gemini-tool.js +2 -2
  714. package/dist/executor/sdk-handlers/gemini/prompt-service.d.ts +3 -2
  715. package/dist/executor/sdk-handlers/gemini/prompt-service.d.ts.map +1 -1
  716. package/dist/executor/sdk-handlers/gemini/prompt-service.js +4 -1
  717. package/dist/executor/sdk-handlers/opencode/opencode-tool.d.ts +3 -2
  718. package/dist/executor/sdk-handlers/opencode/opencode-tool.d.ts.map +1 -1
  719. package/dist/executor/sdk-handlers/opencode/opencode-tool.js +4 -1
  720. package/dist/executor/services/feathers-client.d.ts.map +1 -1
  721. package/dist/executor/services/feathers-client.js +124 -25
  722. package/dist/git/index.cjs +1101 -0
  723. package/dist/git/index.d.ts +533 -0
  724. package/dist/git/index.d.ts.map +1 -0
  725. package/dist/git/index.js +1022 -0
  726. package/dist/git/package.json +21 -0
  727. package/dist/git/pure.cjs +185 -0
  728. package/dist/git/pure.d.ts +39 -0
  729. package/dist/git/pure.d.ts.map +1 -0
  730. package/dist/git/pure.js +139 -0
  731. package/dist/ui/assets/AgorEmojiPickerInner-leeNywMc.js +1 -0
  732. package/dist/ui/assets/App-Dpl4Cc0U.js +4 -0
  733. package/dist/ui/assets/App-Dpl4Cc0U.js.gz +0 -0
  734. package/dist/ui/assets/AppNode-wN3UZlFK.js +1 -0
  735. package/dist/ui/assets/AppNode-wN3UZlFK.js.gz +0 -0
  736. package/dist/ui/assets/ArtifactConsentModal-DjzXcP_L.js +1 -0
  737. package/dist/ui/assets/ArtifactConsentModal-DjzXcP_L.js.gz +0 -0
  738. package/dist/ui/assets/ArtifactFullscreenPage-B3b_EZ0F.js +9 -0
  739. package/dist/ui/assets/ArtifactFullscreenPage-B3b_EZ0F.js.gz +0 -0
  740. package/dist/ui/assets/ArtifactNode-DISy2T-6.js +9 -0
  741. package/dist/ui/assets/ArtifactNode-DISy2T-6.js.gz +0 -0
  742. package/dist/ui/assets/AutocompleteTextarea-DUpsoEGr.js +19 -0
  743. package/dist/ui/assets/AutocompleteTextarea-DUpsoEGr.js.gz +0 -0
  744. package/dist/ui/assets/BoardObjectNodes-BakeGpIX.js +34 -0
  745. package/dist/ui/assets/BoardObjectNodes-BakeGpIX.js.gz +0 -0
  746. package/dist/ui/assets/CodeEditor.inner-HmSdTLW5.js +7 -0
  747. package/dist/ui/assets/CodeEditor.inner-HmSdTLW5.js.gz +0 -0
  748. package/dist/ui/assets/ConversationView-mWaA-B1f.js +1 -0
  749. package/dist/ui/assets/ConversationView-mWaA-B1f.js.gz +0 -0
  750. package/dist/ui/assets/EmbeddedTerminal-NNoyPA81.js +2 -0
  751. package/dist/ui/assets/EmbeddedTerminal-NNoyPA81.js.gz +0 -0
  752. package/dist/ui/assets/KnowledgePage-CkxVnRvz.js +24 -0
  753. package/dist/ui/assets/KnowledgePage-CkxVnRvz.js.gz +0 -0
  754. package/dist/ui/assets/{MarketingScreenshotPage-zv5RUCuV.js → MarketingScreenshotPage-B86Gs8jx.js} +2 -2
  755. package/dist/ui/assets/MarketingScreenshotPage-B86Gs8jx.js.gz +0 -0
  756. package/dist/ui/assets/MobileApp-BPs-SXvz.js +1 -0
  757. package/dist/ui/assets/MobileApp-BPs-SXvz.js.gz +0 -0
  758. package/dist/ui/assets/{SessionCanvas-mEmYGZhC.css → SessionCanvas-Bh7Yg5dZ.css} +1 -1
  759. package/dist/ui/assets/SessionCanvas-Bh7Yg5dZ.css.gz +0 -0
  760. package/dist/ui/assets/SessionCanvas-xVfDoEtz.js +13 -0
  761. package/dist/ui/assets/SessionCanvas-xVfDoEtz.js.gz +0 -0
  762. package/dist/ui/assets/{StreamdownDemoPage-wzWaqWwr.js → StreamdownDemoPage-CvWLzVsv.js} +2 -2
  763. package/dist/ui/assets/StreamdownDemoPage-CvWLzVsv.js.gz +0 -0
  764. package/dist/ui/assets/TerminalModal-ExOgsuOP.js +2 -0
  765. package/dist/ui/assets/TerminalModal-ExOgsuOP.js.gz +0 -0
  766. package/dist/ui/assets/ThemeSwitcher-Cgyp5ruu.js +1 -0
  767. package/dist/ui/assets/ThemeSwitcher-Cgyp5ruu.js.gz +0 -0
  768. package/dist/ui/assets/ThemedSyntaxHighlighter.inner-rpCN9S6K.js +1 -0
  769. package/dist/ui/assets/{antd-CfbbHJOz.js → antd-BCqimh1J.js} +5 -5
  770. package/dist/ui/assets/{antd-CfbbHJOz.js.gz → antd-BCqimh1J.js.gz} +0 -0
  771. package/dist/ui/assets/architecture-U656AL7Q-BxSQIjrE.js +1 -0
  772. package/dist/ui/assets/architectureDiagram-VXUJARFQ-pDpGHSqT.js +36 -0
  773. package/dist/ui/assets/architectureDiagram-VXUJARFQ-pDpGHSqT.js.gz +0 -0
  774. package/dist/ui/assets/{blockDiagram-VD42YOAC-BhZaEN19.js → blockDiagram-VD42YOAC-uP8JTJpK.js} +4 -4
  775. package/dist/ui/assets/blockDiagram-VD42YOAC-uP8JTJpK.js.gz +0 -0
  776. package/dist/ui/assets/{c4Diagram-YG6GDRKO-Dk_UH-sY.js → c4Diagram-YG6GDRKO-qQe72Mm7.js} +2 -2
  777. package/dist/ui/assets/c4Diagram-YG6GDRKO-qQe72Mm7.js.gz +0 -0
  778. package/dist/ui/assets/channel-CoUBs6Zn.js +1 -0
  779. package/dist/ui/assets/{chunk-4BX2VUAB-XprbG2TG.js → chunk-4BX2VUAB-sz-YE8Nt.js} +1 -1
  780. package/dist/ui/assets/chunk-4ZMWKKQ3-3oKtfWXp.js +3 -0
  781. package/dist/ui/assets/chunk-4ZMWKKQ3-3oKtfWXp.js.gz +0 -0
  782. package/dist/ui/assets/chunk-55IACEB6-BS04dgKF.js +1 -0
  783. package/dist/ui/assets/{chunk-ABZYJK2D-BJcrryHK.js → chunk-ABZYJK2D-t3Gkphds.js} +3 -3
  784. package/dist/ui/assets/chunk-ABZYJK2D-t3Gkphds.js.gz +0 -0
  785. package/dist/ui/assets/{chunk-AGHRB4JF-DvxmfbM0.js → chunk-AGHRB4JF-D_QmWxbY.js} +1 -1
  786. package/dist/ui/assets/chunk-AGHRB4JF-D_QmWxbY.js.gz +0 -0
  787. package/dist/ui/assets/{chunk-ATLVNIR6-DbeJ0OrR.js → chunk-ATLVNIR6-Bmg7-Ufz.js} +1 -1
  788. package/dist/ui/assets/chunk-ATLVNIR6-Bmg7-Ufz.js.gz +0 -0
  789. package/dist/ui/assets/{chunk-B4BG7PRW-C53q2ggf.js → chunk-B4BG7PRW-dnSEE1u-.js} +3 -3
  790. package/dist/ui/assets/chunk-B4BG7PRW-dnSEE1u-.js.gz +0 -0
  791. package/dist/ui/assets/{chunk-CVBHYZKI-B3EBSlb3.js → chunk-CVBHYZKI-BStaYnF0.js} +1 -1
  792. package/dist/ui/assets/{chunk-DI55MBZ5-vIyNEQN-.js → chunk-DI55MBZ5-28dvx6o3.js} +1 -1
  793. package/dist/ui/assets/chunk-DI55MBZ5-28dvx6o3.js.gz +0 -0
  794. package/dist/ui/assets/chunk-EXTU4WIE-X-FURkEh.js +1 -0
  795. package/dist/ui/assets/{chunk-FMBD7UC4-rddmfK-Z.js → chunk-FMBD7UC4-C_63gC9S.js} +1 -1
  796. package/dist/ui/assets/{chunk-HN2XXSSU-Dttqcg3b.js → chunk-HN2XXSSU-UFD374KI.js} +1 -1
  797. package/dist/ui/assets/chunk-HN2XXSSU-UFD374KI.js.gz +0 -0
  798. package/dist/ui/assets/chunk-JA3XYJ7Z-B60hLNeR.js +11 -0
  799. package/dist/ui/assets/chunk-JA3XYJ7Z-B60hLNeR.js.gz +0 -0
  800. package/dist/ui/assets/{chunk-JZLCHNYA-EUmx2y4H.js → chunk-JZLCHNYA-ButC6pwN.js} +5 -5
  801. package/dist/ui/assets/chunk-JZLCHNYA-ButC6pwN.js.gz +0 -0
  802. package/dist/ui/assets/{chunk-MI3HLSF2-65n9Mkyc.js → chunk-MI3HLSF2-BivYzoSV.js} +1 -1
  803. package/dist/ui/assets/chunk-MI3HLSF2-BivYzoSV.js.gz +0 -0
  804. package/dist/ui/assets/chunk-N4CR4FBY-mVWzo5wJ.js +2 -0
  805. package/dist/ui/assets/chunk-N4CR4FBY-mVWzo5wJ.js.gz +0 -0
  806. package/dist/ui/assets/{chunk-QN33PNHL-DsRKK6NR.js → chunk-QN33PNHL-tXtHZpaG.js} +1 -1
  807. package/dist/ui/assets/{chunk-QXUST7PY-BCYnMiS3.js → chunk-QXUST7PY-DATib_Vv.js} +2 -2
  808. package/dist/ui/assets/chunk-QXUST7PY-DATib_Vv.js.gz +0 -0
  809. package/dist/ui/assets/chunk-QZHKN3VN-y6l249e5.js +1 -0
  810. package/dist/ui/assets/chunk-S3R3BYOJ-BEtfmflI.js +2 -0
  811. package/dist/ui/assets/chunk-S3R3BYOJ-BEtfmflI.js.gz +0 -0
  812. package/dist/ui/assets/{chunk-TZMSLE5B-BuQUQcTr.js → chunk-TZMSLE5B-BY1ZtogK.js} +1 -1
  813. package/dist/ui/assets/chunk-TZMSLE5B-BY1ZtogK.js.gz +0 -0
  814. package/dist/ui/assets/classDiagram-2ON5EDUG-BYvq-uPY.js +1 -0
  815. package/dist/ui/assets/classDiagram-v2-WZHVMYZB-BYvq-uPY.js +1 -0
  816. package/dist/ui/assets/constants-CYzQKfD1.js +1 -0
  817. package/dist/ui/assets/{cose-bilkent-S5V4N54A-CnPB3ARO.js → cose-bilkent-S5V4N54A-DPvYrqGG.js} +1 -1
  818. package/dist/ui/assets/cose-bilkent-S5V4N54A-DPvYrqGG.js.gz +0 -0
  819. package/dist/ui/assets/{dagre-6UL2VRFP-DhS-k_Se.js → dagre-6UL2VRFP-D800J6qb.js} +1 -1
  820. package/dist/ui/assets/dagre-6UL2VRFP-D800J6qb.js.gz +0 -0
  821. package/dist/ui/assets/{dagre-KgLoHEuy.js → dagre-TNc4wezg.js} +1 -1
  822. package/dist/ui/assets/dagre-TNc4wezg.js.gz +0 -0
  823. package/dist/ui/assets/diagram-PSM6KHXK-CGdP9F-X.js +24 -0
  824. package/dist/ui/assets/diagram-PSM6KHXK-CGdP9F-X.js.gz +0 -0
  825. package/dist/ui/assets/{diagram-QEK2KX5R-BPCitvbo.js → diagram-QEK2KX5R-BD5lOCe5.js} +1 -1
  826. package/dist/ui/assets/diagram-QEK2KX5R-BD5lOCe5.js.gz +0 -0
  827. package/dist/ui/assets/{diagram-S2PKOQOG-NW4uK6sx.js → diagram-S2PKOQOG-cp3l22vN.js} +1 -1
  828. package/dist/ui/assets/diagram-S2PKOQOG-cp3l22vN.js.gz +0 -0
  829. package/dist/ui/assets/editor-Cr0W5BQI.js +39 -0
  830. package/dist/ui/assets/editor-Cr0W5BQI.js.gz +0 -0
  831. package/dist/ui/assets/emoji-Bv3m24sO.js +3 -0
  832. package/dist/ui/assets/emoji-Bv3m24sO.js.gz +0 -0
  833. package/dist/ui/assets/{erDiagram-Q2GNP2WA-me1fboaf.js → erDiagram-Q2GNP2WA-CQSXRgqr.js} +2 -2
  834. package/dist/ui/assets/erDiagram-Q2GNP2WA-CQSXRgqr.js.gz +0 -0
  835. package/dist/ui/assets/flowDiagram-NV44I4VS-CKcKpkph.js +162 -0
  836. package/dist/ui/assets/flowDiagram-NV44I4VS-CKcKpkph.js.gz +0 -0
  837. package/dist/ui/assets/ganttDiagram-LVOFAZNH-DlAHzXO5.js +267 -0
  838. package/dist/ui/assets/ganttDiagram-LVOFAZNH-DlAHzXO5.js.gz +0 -0
  839. package/dist/ui/assets/{gitGraph-F6HP7TQM-CfFE_uAC.js → gitGraph-F6HP7TQM-DeuXy4B1.js} +1 -1
  840. package/dist/ui/assets/gitGraphDiagram-NY62KEGX-aB-AI4Vq.js +65 -0
  841. package/dist/ui/assets/gitGraphDiagram-NY62KEGX-aB-AI4Vq.js.gz +0 -0
  842. package/dist/ui/assets/index-B-qHc0o5.js +63 -0
  843. package/dist/ui/assets/index-B-qHc0o5.js.gz +0 -0
  844. package/dist/ui/assets/{index-DxuPq13l.css → index-qkT7Qqm2.css} +1 -1
  845. package/dist/ui/assets/index-qkT7Qqm2.css.gz +0 -0
  846. package/dist/ui/assets/{info-NVLQJR56-i_xHYg3f.js → info-NVLQJR56-B9PG7xsc.js} +1 -1
  847. package/dist/ui/assets/{infoDiagram-ER5ION4S-2NL93b78.js → infoDiagram-ER5ION4S-C5Wpoqim.js} +1 -1
  848. package/dist/ui/assets/{journeyDiagram-XKPGCS4Q-CZF-2DHU.js → journeyDiagram-XKPGCS4Q-CHLziqfS.js} +3 -3
  849. package/dist/ui/assets/journeyDiagram-XKPGCS4Q-CHLziqfS.js.gz +0 -0
  850. package/dist/ui/assets/{kanban-definition-3W4ZIXB7-CfvJIOny.js → kanban-definition-3W4ZIXB7-Dq7GzQE_.js} +1 -1
  851. package/dist/ui/assets/kanban-definition-3W4ZIXB7-Dq7GzQE_.js.gz +0 -0
  852. package/dist/ui/assets/{line-DDv8kOJk.js → line-DHKNg83I.js} +1 -1
  853. package/dist/ui/assets/{linear-Daef-l29.js → linear-BvUfn0I8.js} +1 -1
  854. package/dist/ui/assets/linear-BvUfn0I8.js.gz +0 -0
  855. package/dist/ui/assets/{mermaid-parser.core-CdK9QgYV.js → mermaid-parser.core-C6d9tKoo.js} +2 -2
  856. package/dist/ui/assets/mermaid-parser.core-C6d9tKoo.js.gz +0 -0
  857. package/dist/ui/assets/mermaid.core-CxE5KezR.js +11 -0
  858. package/dist/ui/assets/mermaid.core-CxE5KezR.js.gz +0 -0
  859. package/dist/ui/assets/{mindmap-definition-VGOIOE7T-Cb3QMflX.js → mindmap-definition-VGOIOE7T-DmPoQ48w.js} +1 -1
  860. package/dist/ui/assets/mindmap-definition-VGOIOE7T-DmPoQ48w.js.gz +0 -0
  861. package/dist/ui/assets/{packet-BFZMPI3H-Bm2uwz4i.js → packet-BFZMPI3H-JZEkVZxU.js} +1 -1
  862. package/dist/ui/assets/{particles-DsJFOarW.js → particles-CxMmUw86.js} +1 -1
  863. package/dist/ui/assets/particles-CxMmUw86.js.gz +0 -0
  864. package/dist/ui/assets/{pie-7BOR55EZ-5i17tVnF.js → pie-7BOR55EZ-_1II5pYQ.js} +1 -1
  865. package/dist/ui/assets/{pieDiagram-ADFJNKIX-BxIwQWvw.js → pieDiagram-ADFJNKIX-DrNkH33i.js} +1 -1
  866. package/dist/ui/assets/pieDiagram-ADFJNKIX-DrNkH33i.js.gz +0 -0
  867. package/dist/ui/assets/{quadrantDiagram-AYHSOK5B-B5HPe4ga.js → quadrantDiagram-AYHSOK5B-DOpC-HEF.js} +3 -3
  868. package/dist/ui/assets/quadrantDiagram-AYHSOK5B-DOpC-HEF.js.gz +0 -0
  869. package/dist/ui/assets/{radar-NHE76QYJ-BTn-tq0k.js → radar-NHE76QYJ-DDmqhzEZ.js} +1 -1
  870. package/dist/ui/assets/reactflow-D98uPOMq.js +2 -0
  871. package/dist/ui/assets/reactflow-D98uPOMq.js.gz +0 -0
  872. package/dist/ui/assets/{requirementDiagram-UZGBJVZJ-YfI6llkX.js → requirementDiagram-UZGBJVZJ-Bzx0iEPP.js} +1 -1
  873. package/dist/ui/assets/requirementDiagram-UZGBJVZJ-Bzx0iEPP.js.gz +0 -0
  874. package/dist/ui/assets/{sandpack-D7koO5op.js → sandpack-059Z4UWP.js} +38 -38
  875. package/dist/ui/assets/sandpack-059Z4UWP.js.gz +0 -0
  876. package/dist/ui/assets/sandpackDefaults-CPMNDsw7.js +1 -0
  877. package/dist/ui/assets/sandpackDefaults-CPMNDsw7.js.gz +0 -0
  878. package/dist/ui/assets/sankeyDiagram-TZEHDZUN-Do9pvfDv.js +10 -0
  879. package/dist/ui/assets/sankeyDiagram-TZEHDZUN-Do9pvfDv.js.gz +0 -0
  880. package/dist/ui/assets/{sequenceDiagram-WL72ISMW-DAe4Um17.js → sequenceDiagram-WL72ISMW-CN8neUTA.js} +6 -6
  881. package/dist/ui/assets/sequenceDiagram-WL72ISMW-CN8neUTA.js.gz +0 -0
  882. package/dist/ui/assets/src-DEbsv3pp.js +34 -0
  883. package/dist/ui/assets/src-DEbsv3pp.js.gz +0 -0
  884. package/dist/ui/assets/stateDiagram-FKZM4ZOC-BluWJi8n.js +1 -0
  885. package/dist/ui/assets/stateDiagram-FKZM4ZOC-BluWJi8n.js.gz +0 -0
  886. package/dist/ui/assets/stateDiagram-v2-4FDKWEC3-DeyqBMDR.js +1 -0
  887. package/dist/ui/assets/streamdown-BT1twtFc.js +521 -0
  888. package/dist/ui/assets/streamdown-BT1twtFc.js.gz +0 -0
  889. package/dist/ui/assets/syntax-CBu6nLfm.js +9 -0
  890. package/dist/ui/assets/syntax-CBu6nLfm.js.gz +0 -0
  891. package/dist/ui/assets/{timeline-definition-IT6M3QCI-D6P5txjT.js → timeline-definition-IT6M3QCI-WdUNkiRj.js} +16 -16
  892. package/dist/ui/assets/timeline-definition-IT6M3QCI-WdUNkiRj.js.gz +0 -0
  893. package/dist/ui/assets/{treemap-KMMF4GRG-Bitm3gy4.js → treemap-KMMF4GRG-CoriU4Jl.js} +1 -1
  894. package/dist/ui/assets/{useUserLocalStorage-Ckb8HsIw.js → useUserLocalStorage-GidNiOPC.js} +1 -1
  895. package/dist/ui/assets/useUserLocalStorage-GidNiOPC.js.gz +0 -0
  896. package/dist/ui/assets/{xychartDiagram-PRI3JC2R-CsybjUbd.js → xychartDiagram-PRI3JC2R-CgBAKNt2.js} +1 -1
  897. package/dist/ui/assets/xychartDiagram-PRI3JC2R-CgBAKNt2.js.gz +0 -0
  898. package/dist/ui/index.html +11 -11
  899. package/dist/ui/index.html.gz +0 -0
  900. package/package.json +6 -5
  901. package/scripts/postinstall.js +27 -19
  902. package/dist/cli/commands/daemon/sync.d.ts.map +0 -1
  903. package/dist/ui/assets/App-DcEY8Ota.js +0 -3
  904. package/dist/ui/assets/App-DcEY8Ota.js.gz +0 -0
  905. package/dist/ui/assets/ArtifactConsentModal-CiCbK9iv.js +0 -1
  906. package/dist/ui/assets/ArtifactConsentModal-CiCbK9iv.js.gz +0 -0
  907. package/dist/ui/assets/ArtifactFullscreenPage-CfsTEGKd.js +0 -9
  908. package/dist/ui/assets/ArtifactFullscreenPage-CfsTEGKd.js.gz +0 -0
  909. package/dist/ui/assets/AutocompleteTextarea-BAFFH_5e.js +0 -18
  910. package/dist/ui/assets/AutocompleteTextarea-BAFFH_5e.js.gz +0 -0
  911. package/dist/ui/assets/BoardObjectNodes-D-O6bZIG.js +0 -34
  912. package/dist/ui/assets/BoardObjectNodes-D-O6bZIG.js.gz +0 -0
  913. package/dist/ui/assets/CodeEditor.inner-DBgsP4tn.js +0 -8
  914. package/dist/ui/assets/CodeEditor.inner-DBgsP4tn.js.gz +0 -0
  915. package/dist/ui/assets/ConversationView-CUWR0gR6.js +0 -1
  916. package/dist/ui/assets/ConversationView-CUWR0gR6.js.gz +0 -0
  917. package/dist/ui/assets/KnowledgePage-B2bzlXfn.js +0 -24
  918. package/dist/ui/assets/KnowledgePage-B2bzlXfn.js.gz +0 -0
  919. package/dist/ui/assets/MarketingScreenshotPage-zv5RUCuV.js.gz +0 -0
  920. package/dist/ui/assets/MobileApp-VgVnsnsN.js +0 -1
  921. package/dist/ui/assets/MobileApp-VgVnsnsN.js.gz +0 -0
  922. package/dist/ui/assets/SessionCanvas-f1-1Gbcw.js +0 -20
  923. package/dist/ui/assets/SessionCanvas-f1-1Gbcw.js.gz +0 -0
  924. package/dist/ui/assets/SessionCanvas-mEmYGZhC.css.gz +0 -0
  925. package/dist/ui/assets/StreamdownDemoPage-wzWaqWwr.js.gz +0 -0
  926. package/dist/ui/assets/ThemeSwitcher-Dly2y9pi.js +0 -1
  927. package/dist/ui/assets/ThemeSwitcher-Dly2y9pi.js.gz +0 -0
  928. package/dist/ui/assets/architecture-U656AL7Q-CykGFbQU.js +0 -1
  929. package/dist/ui/assets/architectureDiagram-VXUJARFQ-C8HXAenz.js +0 -36
  930. package/dist/ui/assets/architectureDiagram-VXUJARFQ-C8HXAenz.js.gz +0 -0
  931. package/dist/ui/assets/blockDiagram-VD42YOAC-BhZaEN19.js.gz +0 -0
  932. package/dist/ui/assets/c4Diagram-YG6GDRKO-Dk_UH-sY.js.gz +0 -0
  933. package/dist/ui/assets/channel-D6_nUWlW.js +0 -1
  934. package/dist/ui/assets/chunk-55IACEB6-ByzqIgSb.js +0 -1
  935. package/dist/ui/assets/chunk-ABZYJK2D-BJcrryHK.js.gz +0 -0
  936. package/dist/ui/assets/chunk-AGHRB4JF-DvxmfbM0.js.gz +0 -0
  937. package/dist/ui/assets/chunk-ATLVNIR6-DbeJ0OrR.js.gz +0 -0
  938. package/dist/ui/assets/chunk-B4BG7PRW-C53q2ggf.js.gz +0 -0
  939. package/dist/ui/assets/chunk-DI55MBZ5-vIyNEQN-.js.gz +0 -0
  940. package/dist/ui/assets/chunk-EXTU4WIE-B3ObkuOm.js +0 -1
  941. package/dist/ui/assets/chunk-HN2XXSSU-Dttqcg3b.js.gz +0 -0
  942. package/dist/ui/assets/chunk-JA3XYJ7Z-DbNDev3D.js +0 -11
  943. package/dist/ui/assets/chunk-JA3XYJ7Z-DbNDev3D.js.gz +0 -0
  944. package/dist/ui/assets/chunk-JZLCHNYA-EUmx2y4H.js.gz +0 -0
  945. package/dist/ui/assets/chunk-MI3HLSF2-65n9Mkyc.js.gz +0 -0
  946. package/dist/ui/assets/chunk-N4CR4FBY-mv5koXqW.js +0 -2
  947. package/dist/ui/assets/chunk-N4CR4FBY-mv5koXqW.js.gz +0 -0
  948. package/dist/ui/assets/chunk-QXUST7PY-BCYnMiS3.js.gz +0 -0
  949. package/dist/ui/assets/chunk-QZHKN3VN-HucAw4xW.js +0 -1
  950. package/dist/ui/assets/chunk-S3R3BYOJ-CWMEa9Dc.js +0 -2
  951. package/dist/ui/assets/chunk-S3R3BYOJ-CWMEa9Dc.js.gz +0 -0
  952. package/dist/ui/assets/chunk-TZMSLE5B-BuQUQcTr.js.gz +0 -0
  953. package/dist/ui/assets/classDiagram-2ON5EDUG-CUT3rPTB.js +0 -1
  954. package/dist/ui/assets/classDiagram-v2-WZHVMYZB-CUT3rPTB.js +0 -1
  955. package/dist/ui/assets/cose-bilkent-S5V4N54A-CnPB3ARO.js.gz +0 -0
  956. package/dist/ui/assets/dagre-6UL2VRFP-DhS-k_Se.js.gz +0 -0
  957. package/dist/ui/assets/dagre-KgLoHEuy.js.gz +0 -0
  958. package/dist/ui/assets/diagram-PSM6KHXK-BZg3MJmb.js +0 -24
  959. package/dist/ui/assets/diagram-PSM6KHXK-BZg3MJmb.js.gz +0 -0
  960. package/dist/ui/assets/diagram-QEK2KX5R-BPCitvbo.js.gz +0 -0
  961. package/dist/ui/assets/diagram-S2PKOQOG-NW4uK6sx.js.gz +0 -0
  962. package/dist/ui/assets/editor-CzFWIUw2.js +0 -39
  963. package/dist/ui/assets/editor-CzFWIUw2.js.gz +0 -0
  964. package/dist/ui/assets/emoji-Dkz4Zzv_.js +0 -3
  965. package/dist/ui/assets/emoji-Dkz4Zzv_.js.gz +0 -0
  966. package/dist/ui/assets/erDiagram-Q2GNP2WA-me1fboaf.js.gz +0 -0
  967. package/dist/ui/assets/flowDiagram-NV44I4VS-DzE8dGsh.js +0 -162
  968. package/dist/ui/assets/flowDiagram-NV44I4VS-DzE8dGsh.js.gz +0 -0
  969. package/dist/ui/assets/ganttDiagram-LVOFAZNH-CFQD09Mi.js +0 -267
  970. package/dist/ui/assets/ganttDiagram-LVOFAZNH-CFQD09Mi.js.gz +0 -0
  971. package/dist/ui/assets/gitGraphDiagram-NY62KEGX-CaVoxU4C.js +0 -65
  972. package/dist/ui/assets/gitGraphDiagram-NY62KEGX-CaVoxU4C.js.gz +0 -0
  973. package/dist/ui/assets/index-BN5_Qq7R.js +0 -324
  974. package/dist/ui/assets/index-BN5_Qq7R.js.gz +0 -0
  975. package/dist/ui/assets/index-DxuPq13l.css.gz +0 -0
  976. package/dist/ui/assets/journeyDiagram-XKPGCS4Q-CZF-2DHU.js.gz +0 -0
  977. package/dist/ui/assets/kanban-definition-3W4ZIXB7-CfvJIOny.js.gz +0 -0
  978. package/dist/ui/assets/katex-CamJ39w1.js +0 -257
  979. package/dist/ui/assets/katex-CamJ39w1.js.gz +0 -0
  980. package/dist/ui/assets/linear-Daef-l29.js.gz +0 -0
  981. package/dist/ui/assets/mermaid-parser.core-CdK9QgYV.js.gz +0 -0
  982. package/dist/ui/assets/mermaid.core-D6GS9mU-.js +0 -11
  983. package/dist/ui/assets/mermaid.core-D6GS9mU-.js.gz +0 -0
  984. package/dist/ui/assets/message-SqLqNYcv.js +0 -36
  985. package/dist/ui/assets/message-SqLqNYcv.js.gz +0 -0
  986. package/dist/ui/assets/mindmap-definition-VGOIOE7T-Cb3QMflX.js.gz +0 -0
  987. package/dist/ui/assets/particles-DsJFOarW.js.gz +0 -0
  988. package/dist/ui/assets/pieDiagram-ADFJNKIX-BxIwQWvw.js.gz +0 -0
  989. package/dist/ui/assets/quadrantDiagram-AYHSOK5B-B5HPe4ga.js.gz +0 -0
  990. package/dist/ui/assets/reactflow-Bf74ngoo.js +0 -2
  991. package/dist/ui/assets/reactflow-Bf74ngoo.js.gz +0 -0
  992. package/dist/ui/assets/requirementDiagram-UZGBJVZJ-YfI6llkX.js.gz +0 -0
  993. package/dist/ui/assets/sandpack-D7koO5op.js.gz +0 -0
  994. package/dist/ui/assets/sankeyDiagram-TZEHDZUN-DOk_B10B.js +0 -10
  995. package/dist/ui/assets/sankeyDiagram-TZEHDZUN-DOk_B10B.js.gz +0 -0
  996. package/dist/ui/assets/sequenceDiagram-WL72ISMW-DAe4Um17.js.gz +0 -0
  997. package/dist/ui/assets/stateDiagram-FKZM4ZOC-CCesDu_C.js +0 -1
  998. package/dist/ui/assets/stateDiagram-FKZM4ZOC-CCesDu_C.js.gz +0 -0
  999. package/dist/ui/assets/stateDiagram-v2-4FDKWEC3-CMlIrsoO.js +0 -1
  1000. package/dist/ui/assets/syntax-C-M-8jOU.js +0 -10
  1001. package/dist/ui/assets/syntax-C-M-8jOU.js.gz +0 -0
  1002. package/dist/ui/assets/theme-BQZdiqwv.js +0 -1
  1003. package/dist/ui/assets/timeline-definition-IT6M3QCI-D6P5txjT.js.gz +0 -0
  1004. package/dist/ui/assets/useUserLocalStorage-Ckb8HsIw.js.gz +0 -0
  1005. package/dist/ui/assets/xychartDiagram-PRI3JC2R-CsybjUbd.js.gz +0 -0
  1006. /package/dist/cli/commands/{admin → local}/sync-unix.d.ts +0 -0
@@ -133,6 +133,13 @@ function generateTaskId() {
133
133
  return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
134
134
  }
135
135
  function findExecutorPath() {
136
+ const configuredPath = process.env.AGOR_EXECUTOR_PATH;
137
+ if (configuredPath) {
138
+ if (!existsSync(configuredPath)) {
139
+ throw new Error(`Configured AGOR_EXECUTOR_PATH does not exist: ${configuredPath}`);
140
+ }
141
+ return configuredPath;
142
+ }
136
143
  const dirname = typeof __dirname !== "undefined" ? __dirname : path.dirname(fileURLToPath(import.meta.url));
137
144
  const possiblePaths = [
138
145
  path.join(dirname, "../executor/cli.js"),
@@ -243,6 +250,12 @@ function spawnExecutorLocal(payload, options) {
243
250
  options.onExit?.(127);
244
251
  return;
245
252
  }
253
+ let reportedExit = false;
254
+ const reportExit = (code) => {
255
+ if (reportedExit) return;
256
+ reportedExit = true;
257
+ options.onExit?.(code);
258
+ };
246
259
  const executorProcess = spawn(cmd, args, {
247
260
  cwd,
248
261
  env: asUser ? void 0 : { ...envWithDaemonUrl },
@@ -256,6 +269,7 @@ function spawnExecutorLocal(payload, options) {
256
269
  onSpawn?.(executorProcess);
257
270
  executorProcess.on("error", (error) => {
258
271
  console.error(`${logPrefix} Spawn error:`, error.message);
272
+ reportExit(127);
259
273
  });
260
274
  executorProcess.on("exit", (code) => {
261
275
  if (code === 0) {
@@ -263,7 +277,7 @@ function spawnExecutorLocal(payload, options) {
263
277
  } else {
264
278
  console.error(`${logPrefix} Executor exited with code ${code}`);
265
279
  }
266
- options.onExit?.(code);
280
+ reportExit(code);
267
281
  });
268
282
  executorProcess.stdin?.write(JSON.stringify(payload));
269
283
  executorProcess.stdin?.end();
@@ -276,6 +290,12 @@ function spawnExecutorWithTemplate(payload, options) {
276
290
  console.log(`${logPrefix} Task ID: ${templateVariables.task_id}`);
277
291
  console.log(`${logPrefix} Command: ${payload.command}`);
278
292
  console.log(`${logPrefix} Template command (first 200 chars): ${command.slice(0, 200)}...`);
293
+ let reportedExit = false;
294
+ const reportExit = (code) => {
295
+ if (reportedExit) return;
296
+ reportedExit = true;
297
+ options.onExit?.(code);
298
+ };
279
299
  const executorProcess = spawn("sh", ["-c", command], {
280
300
  env: { ...process.env, LOG_LEVEL: logLevel },
281
301
  stdio: ["pipe", "pipe", "pipe"]
@@ -289,6 +309,7 @@ function spawnExecutorWithTemplate(payload, options) {
289
309
  });
290
310
  executorProcess.on("error", (error) => {
291
311
  console.error(`${logPrefix} Spawn error:`, error.message);
312
+ reportExit(127);
292
313
  });
293
314
  executorProcess.on("exit", (code) => {
294
315
  if (code === 0) {
@@ -300,7 +321,7 @@ function spawnExecutorWithTemplate(payload, options) {
300
321
  `${logPrefix} Executor exited with code ${code} (task: ${templateVariables.task_id})`
301
322
  );
302
323
  }
303
- options.onExit?.(code);
324
+ reportExit(code);
304
325
  });
305
326
  executorProcess.stdin?.write(JSON.stringify(payload));
306
327
  executorProcess.stdin?.end();
@@ -579,12 +600,19 @@ function createServiceToken(jwtSecret, expiresIn, scope = {}) {
579
600
  expiresIn || "5m"
580
601
  );
581
602
  }
582
- function generateSessionToken(app) {
603
+ function serviceTokenScopeForParams(params) {
604
+ const tenantId = params?.tenant?.tenant_id ?? params?.tenant_id ?? params?.user?.tenant_id;
605
+ return tenantId ? { tenant_id: tenantId } : {};
606
+ }
607
+ function generateSessionToken(app, scope = {}) {
583
608
  const jwtSecret = app.settings.authentication?.secret;
584
609
  if (!jwtSecret) {
585
610
  throw new Error("JWT secret not configured in app settings");
586
611
  }
587
- return createServiceToken(jwtSecret);
612
+ return createServiceToken(jwtSecret, void 0, scope);
613
+ }
614
+ function generateScopedServiceToken(app, params) {
615
+ return generateSessionToken(app, serviceTokenScopeForParams(params));
588
616
  }
589
617
  var configuredDaemonUrl, configuredExecutorDefaults, EXECUTOR_RESULT_PREFIX, spawnExecutorFireAndForget;
590
618
  var init_spawn_executor = __esm({
@@ -600,12 +628,21 @@ var init_spawn_executor = __esm({
600
628
  });
601
629
 
602
630
  // src/utils/mcp-token-authorization.ts
603
- import { hasMinimumRole as hasMinimumRole5, ROLES as ROLES6 } from "@agor/core/types";
631
+ import { hasMinimumRole as hasMinimumRole6, ROLES as ROLES7 } from "@agor/core/types";
632
+ function hasExplicitMinimumRole(userRole, minimumRole) {
633
+ return !!userRole && hasMinimumRole6(userRole, minimumRole);
634
+ }
604
635
  function canReceiveMcpTokenForSession(params) {
636
+ const { callerUserId, callerRole } = params;
637
+ const isServiceExecutor = callerRole === "service";
638
+ const isAuthenticatedMember = !!callerUserId && hasExplicitMinimumRole(callerRole, ROLES7.MEMBER);
639
+ return isAuthenticatedMember || isServiceExecutor;
640
+ }
641
+ function canControlCliSession(params) {
605
642
  const { callerUserId, callerRole, sessionCreatedBy } = params;
606
- const isSuperadmin = hasMinimumRole5(callerRole, ROLES6.SUPERADMIN);
643
+ const isSuperadmin = hasExplicitMinimumRole(callerRole, ROLES7.SUPERADMIN);
607
644
  const isServiceExecutor = callerRole === "service";
608
- const isCreatorMember = !!callerUserId && callerUserId === sessionCreatedBy && hasMinimumRole5(callerRole, ROLES6.MEMBER);
645
+ const isCreatorMember = !!callerUserId && callerUserId === sessionCreatedBy && hasExplicitMinimumRole(callerRole, ROLES7.MEMBER);
609
646
  return isCreatorMember || isSuperadmin || isServiceExecutor;
610
647
  }
611
648
  var init_mcp_token_authorization = __esm({
@@ -626,12 +663,16 @@ __export(tokens_exports, {
626
663
  validateSessionToken: () => validateSessionToken
627
664
  });
628
665
  import { MCP_TOKEN } from "@agor/core/config";
629
- import { generateId as generateId2, SessionRepository as SessionRepository2, shortId as shortId3 } from "@agor/core/db";
666
+ import {
667
+ generateId as generateId2,
668
+ SessionRepository as SessionRepository2,
669
+ shortId as shortId3
670
+ } from "@agor/core/db";
630
671
  import {
631
672
  MCP_TOKEN_AUDIENCE,
632
673
  MCP_TOKEN_ISSUER
633
674
  } from "@agor/core/types";
634
- import jwt2 from "jsonwebtoken";
675
+ import jwt4 from "jsonwebtoken";
635
676
  import { MCP_TOKEN_AUDIENCE as MCP_TOKEN_AUDIENCE2, MCP_TOKEN_ISSUER as MCP_TOKEN_ISSUER2 } from "@agor/core/types";
636
677
  function mcpTokenDebug(...args) {
637
678
  if (DEBUG_MCP_TOKENS) {
@@ -703,7 +744,7 @@ async function generateSessionToken2(app, sessionId, userId) {
703
744
  exp: expSec,
704
745
  jti
705
746
  };
706
- const token = jwt2.sign(payload, jwtSecret, { algorithm: "HS256" });
747
+ const token = jwt4.sign(payload, jwtSecret, { algorithm: "HS256" });
707
748
  s.tokenCache.set(cacheKey, { token, expiresAtMs });
708
749
  mcpTokenDebug(
709
750
  `\u{1F3AB} MCP token issued: session=${shortId3(sessionId)} jti=${jti.substring(0, 8)} exp=+${Math.floor(s.expirationMs / 1e3)}s`
@@ -719,15 +760,15 @@ async function validateSessionToken(app, token) {
719
760
  }
720
761
  let payload;
721
762
  try {
722
- payload = jwt2.verify(token, jwtSecret, {
763
+ payload = jwt4.verify(token, jwtSecret, {
723
764
  audience: MCP_TOKEN_AUDIENCE,
724
765
  issuer: MCP_TOKEN_ISSUER,
725
766
  algorithms: ["HS256"]
726
767
  });
727
768
  } catch (err) {
728
- if (err instanceof jwt2.TokenExpiredError) {
769
+ if (err instanceof jwt4.TokenExpiredError) {
729
770
  console.warn("[mcp-tokens] token rejected: expired");
730
- } else if (err instanceof jwt2.JsonWebTokenError) {
771
+ } else if (err instanceof jwt4.JsonWebTokenError) {
731
772
  console.warn(`[mcp-tokens] token rejected: ${err.message}`);
732
773
  } else {
733
774
  console.error("[mcp-tokens] token verify error:", err);
@@ -1179,6 +1220,7 @@ __export(claude_cli_integration_exports, {
1179
1220
  rehydrateCliWatchers: () => rehydrateCliWatchers,
1180
1221
  resolveClaudeCliMcpConfigTargetUnixUser: () => resolveClaudeCliMcpConfigTargetUnixUser,
1181
1222
  resolveHomeDirForCliSession: () => resolveHomeDirForCliSession,
1223
+ scanCliWatcherRehydrateSessions: () => scanCliWatcherRehydrateSessions,
1182
1224
  setPendingCliTask: () => setPendingCliTask,
1183
1225
  writeClaudeCliMcpConfigFile: () => writeClaudeCliMcpConfigFile,
1184
1226
  writeClaudeCliMcpConfigForSession: () => writeClaudeCliMcpConfigForSession
@@ -1195,8 +1237,12 @@ import {
1195
1237
  permissionModeForCli,
1196
1238
  slugForCwd
1197
1239
  } from "@agor/core/claude-cli";
1240
+ import { resolveMultiTenancyConfig as resolveMultiTenancyConfig3 } from "@agor/core/config";
1198
1241
  import {
1199
1242
  generateId as generateId4,
1243
+ getCurrentTenantId as getCurrentTenantId3,
1244
+ runWithoutTenantDatabaseScope as runWithoutTenantDatabaseScope2,
1245
+ runWithTenantDatabaseScope as runWithTenantDatabaseScope4,
1200
1246
  SessionRepository as SessionRepository3,
1201
1247
  shortId as shortId4,
1202
1248
  TaskRepository
@@ -1214,6 +1260,22 @@ function getDb(app) {
1214
1260
  const db = app.get("database") ?? app.get("db");
1215
1261
  return db ?? null;
1216
1262
  }
1263
+ function getCliFallbackTenantId(app) {
1264
+ const config = app.get("config");
1265
+ return resolveMultiTenancyConfig3(config ?? {}).static_tenant_id;
1266
+ }
1267
+ function captureCliWatcherTenantId(app) {
1268
+ return getCurrentTenantId3() ?? getCliFallbackTenantId(app);
1269
+ }
1270
+ function rememberCliWatcherTenant(sessionId, tenantId) {
1271
+ cliWatcherTenantBySession.set(sessionId, tenantId);
1272
+ }
1273
+ async function runCliCallbackDatabaseScope(app, sessionId, work) {
1274
+ const db = getDb(app);
1275
+ if (!db) return work();
1276
+ const tenantId = cliWatcherTenantBySession.get(sessionId) ?? captureCliWatcherTenantId(app);
1277
+ return runWithTenantDatabaseScope4(db, tenantId, work);
1278
+ }
1217
1279
  async function persistActiveTurnSnapshot(app, sessionId, turn) {
1218
1280
  const db = getDb(app);
1219
1281
  if (!db) return;
@@ -1287,52 +1349,60 @@ function stopTaskWatchdog(sessionId) {
1287
1349
  }
1288
1350
  function startTaskWatchdog(app, sessionId) {
1289
1351
  stopTaskWatchdog(sessionId);
1290
- const timer = setInterval(async () => {
1291
- const active = activeCliTurn.get(sessionId);
1292
- if (!active) {
1293
- stopTaskWatchdog(sessionId);
1294
- return;
1295
- }
1296
- const idleMs = Date.now() - (Date.parse(active.lastTimestamp) || active.startedAtMs);
1297
- if (idleMs < WATCHDOG_IDLE_THRESHOLD_MS) return;
1298
- const alive = await isClaudeRunningFor(sessionId);
1299
- if (alive) return;
1300
- console.log(
1301
- JSON.stringify({
1302
- layer: "claude-cli-watcher.watchdog",
1303
- sessionId,
1304
- idleMs,
1305
- note: "claude process not running \u2014 closing stale turn"
1306
- })
1307
- );
1308
- try {
1309
- await closeActiveTurnDispatch?.(sessionId, "claude_exited", (/* @__PURE__ */ new Date()).toISOString());
1310
- } catch (err) {
1311
- console.warn("[claude-cli-watcher.watchdog] close dispatch failed", err);
1312
- }
1313
- stopTaskWatchdog(sessionId);
1314
- }, WATCHDOG_TICK_MS);
1315
- timer.unref?.();
1316
- watchdogTimers.set(sessionId, timer);
1352
+ runWithoutTenantDatabaseScope2(() => {
1353
+ const timer = setInterval(() => {
1354
+ void runCliCallbackDatabaseScope(app, sessionId, async () => {
1355
+ const active = activeCliTurn.get(sessionId);
1356
+ if (!active) {
1357
+ stopTaskWatchdog(sessionId);
1358
+ return;
1359
+ }
1360
+ const idleMs = Date.now() - (Date.parse(active.lastTimestamp) || active.startedAtMs);
1361
+ if (idleMs < WATCHDOG_IDLE_THRESHOLD_MS) return;
1362
+ const alive = await isClaudeRunningFor(sessionId);
1363
+ if (alive) return;
1364
+ console.log(
1365
+ JSON.stringify({
1366
+ layer: "claude-cli-watcher.watchdog",
1367
+ sessionId,
1368
+ idleMs,
1369
+ note: "claude process not running \u2014 closing stale turn"
1370
+ })
1371
+ );
1372
+ try {
1373
+ await closeActiveTurnDispatch?.(sessionId, "claude_exited", (/* @__PURE__ */ new Date()).toISOString());
1374
+ } catch (err) {
1375
+ console.warn("[claude-cli-watcher.watchdog] close dispatch failed", err);
1376
+ }
1377
+ stopTaskWatchdog(sessionId);
1378
+ }).catch((err) => {
1379
+ console.warn("[claude-cli-watcher.watchdog] scoped tick failed", err);
1380
+ });
1381
+ }, WATCHDOG_TICK_MS);
1382
+ timer.unref?.();
1383
+ watchdogTimers.set(sessionId, timer);
1384
+ });
1317
1385
  }
1318
1386
  function buildCliPersister(app) {
1319
1387
  return {
1320
1388
  async saveOffset(sessionId, update2) {
1321
- const db = getDb(app);
1322
- if (!db) return;
1323
- const repo = new SessionRepository3(db);
1324
- const row = await repo.findById(sessionId).catch(() => null);
1325
- if (!row) return;
1326
- const existing = row.cli_state ?? {};
1327
- const patch = {
1328
- cli_state: {
1329
- ...existing,
1330
- watcher_offset: update2.watcher_offset,
1331
- last_event_ts: update2.last_event_ts ?? existing.last_event_ts,
1332
- last_event_uuid: update2.last_event_uuid ?? existing.last_event_uuid
1333
- }
1334
- };
1335
- await repo.update(sessionId, patch);
1389
+ await runCliCallbackDatabaseScope(app, sessionId, async () => {
1390
+ const db = getDb(app);
1391
+ if (!db) return;
1392
+ const repo = new SessionRepository3(db);
1393
+ const row = await repo.findById(sessionId).catch(() => null);
1394
+ if (!row) return;
1395
+ const existing = row.cli_state ?? {};
1396
+ const patch = {
1397
+ cli_state: {
1398
+ ...existing,
1399
+ watcher_offset: update2.watcher_offset,
1400
+ last_event_ts: update2.last_event_ts ?? existing.last_event_ts,
1401
+ last_event_uuid: update2.last_event_uuid ?? existing.last_event_uuid
1402
+ }
1403
+ };
1404
+ await repo.update(sessionId, patch);
1405
+ });
1336
1406
  }
1337
1407
  };
1338
1408
  }
@@ -1710,14 +1780,17 @@ function buildCliEventSink(app) {
1710
1780
  throw err;
1711
1781
  }
1712
1782
  };
1783
+ const scopedSink = (sessionId, event) => runCliCallbackDatabaseScope(app, sessionId, async () => {
1784
+ await sink(sessionId, event);
1785
+ });
1713
1786
  closeActiveTurnDispatch = async (sessionId, _reason, ts) => {
1714
- await sink(sessionId, {
1787
+ await scopedSink(sessionId, {
1715
1788
  type: "turn_end",
1716
1789
  messageId: "watchdog-synthetic",
1717
1790
  timestamp: ts
1718
1791
  });
1719
1792
  };
1720
- return sink;
1793
+ return scopedSink;
1721
1794
  }
1722
1795
  function resolveHomeDirForCliSession(session) {
1723
1796
  if (session.unix_username) {
@@ -1853,13 +1926,13 @@ function writeClaudeCliMcpConfigFile(params) {
1853
1926
  async function writeClaudeCliMcpConfigForSession(app, session, opts = {}) {
1854
1927
  const config = app.get("config");
1855
1928
  if (config?.daemon?.mcpEnabled === false) return void 0;
1856
- if (opts.actor && !canReceiveMcpTokenForSession({
1929
+ if (opts.actor && !canControlCliSession({
1857
1930
  callerUserId: opts.actor.user_id,
1858
1931
  callerRole: opts.actor.role,
1859
1932
  sessionCreatedBy: session.created_by
1860
1933
  })) {
1861
1934
  console.warn(
1862
- `[claude-cli-integration] not writing owner-scoped MCP config for session ${shortId4(session.session_id)}: caller ${opts.actor.user_id ?? "anonymous"} cannot receive session creator token`
1935
+ `[claude-cli-integration] not writing owner-scoped MCP config for session ${shortId4(session.session_id)}: caller ${opts.actor.user_id ?? "anonymous"} is not allowed to control the owner-scoped CLI MCP config`
1863
1936
  );
1864
1937
  return void 0;
1865
1938
  }
@@ -1938,13 +2011,18 @@ async function onCliSessionCreated(app, session, branchCwd) {
1938
2011
  }
1939
2012
  try {
1940
2013
  const reg = getCliWatcherRegistry(app);
1941
- await reg.register({
1942
- sessionId: session.session_id,
1943
- cwd: branchCwd,
1944
- homeDir,
1945
- startOffset: session.cli_state?.watcher_offset ?? 0
2014
+ const watcherTenantId = captureCliWatcherTenantId(app);
2015
+ await runWithoutTenantDatabaseScope2(async () => {
2016
+ rememberCliWatcherTenant(session.session_id, watcherTenantId);
2017
+ await reg.register({
2018
+ sessionId: session.session_id,
2019
+ cwd: branchCwd,
2020
+ homeDir,
2021
+ startOffset: session.cli_state?.watcher_offset ?? 0
2022
+ });
1946
2023
  });
1947
2024
  } catch (err) {
2025
+ cliWatcherTenantBySession.delete(session.session_id);
1948
2026
  console.warn(
1949
2027
  `[claude-cli-integration] watcher register failed for session ${session.session_id}:`,
1950
2028
  err
@@ -1974,30 +2052,37 @@ async function onCliSessionEnded(app, sessionId) {
1974
2052
  await reg.unregister(sessionId);
1975
2053
  stopTaskWatchdog(sessionId);
1976
2054
  activeCliTurn.delete(sessionId);
2055
+ cliWatcherTenantBySession.delete(sessionId);
1977
2056
  }
1978
- async function rehydrateCliWatchers(app, branchCwdLookup) {
2057
+ async function scanCliWatcherRehydrateSessions(app) {
1979
2058
  const db = getDb(app);
1980
- if (!db) return;
2059
+ if (!db) return [];
1981
2060
  const repo = new SessionRepository3(db);
1982
- const all = await repo.findAll().catch(() => []);
2061
+ return repo.findAll();
2062
+ }
2063
+ async function rehydrateCliWatchers(app, branchCwdLookup, sessions, options) {
1983
2064
  const reg = getCliWatcherRegistry(app);
1984
2065
  let rehydrated = 0;
1985
- for (const session of all) {
2066
+ for (const session of sessions) {
1986
2067
  if (session.agentic_tool !== "claude-code-cli") continue;
1987
2068
  if (session.status === "completed" || session.status === "failed") continue;
1988
2069
  if (session.archived) continue;
1989
2070
  const cwd = await branchCwdLookup(session.branch_id);
1990
2071
  if (!cwd) continue;
1991
- primeActiveCliTurnFromSession(app, session);
1992
2072
  try {
1993
- await reg.register({
1994
- sessionId: session.session_id,
1995
- cwd,
1996
- homeDir: resolveHomeDirForCliSession(session),
1997
- startOffset: session.cli_state?.watcher_offset ?? 0
2073
+ await runWithoutTenantDatabaseScope2(async () => {
2074
+ rememberCliWatcherTenant(session.session_id, options.tenantId);
2075
+ primeActiveCliTurnFromSession(app, session);
2076
+ await reg.register({
2077
+ sessionId: session.session_id,
2078
+ cwd,
2079
+ homeDir: resolveHomeDirForCliSession(session),
2080
+ startOffset: session.cli_state?.watcher_offset ?? 0
2081
+ });
1998
2082
  });
1999
2083
  rehydrated++;
2000
2084
  } catch (err) {
2085
+ cliWatcherTenantBySession.delete(session.session_id);
2001
2086
  console.warn(
2002
2087
  `[claude-cli-integration] failed to rehydrate watcher for ${session.session_id}:`,
2003
2088
  err
@@ -2008,7 +2093,7 @@ async function rehydrateCliWatchers(app, branchCwdLookup) {
2008
2093
  console.log(`[claude-cli-integration] rehydrated ${rehydrated} CLI watcher(s)`);
2009
2094
  }
2010
2095
  }
2011
- var activeCliTurn, WATCHDOG_TICK_MS, WATCHDOG_IDLE_THRESHOLD_MS, watchdogTimers, closeActiveTurnDispatch, pendingCliTask, registrySingleton;
2096
+ var cliWatcherTenantBySession, activeCliTurn, WATCHDOG_TICK_MS, WATCHDOG_IDLE_THRESHOLD_MS, watchdogTimers, closeActiveTurnDispatch, pendingCliTask, registrySingleton;
2012
2097
  var init_claude_cli_integration = __esm({
2013
2098
  "src/services/claude-cli-integration.ts"() {
2014
2099
  "use strict";
@@ -2018,6 +2103,7 @@ var init_claude_cli_integration = __esm({
2018
2103
  init_spawn_executor();
2019
2104
  init_claude_cli_watcher();
2020
2105
  init_claude_cli_watcher();
2106
+ cliWatcherTenantBySession = /* @__PURE__ */ new Map();
2021
2107
  activeCliTurn = /* @__PURE__ */ new Map();
2022
2108
  WATCHDOG_TICK_MS = 6e4;
2023
2109
  WATCHDOG_IDLE_THRESHOLD_MS = 9e4;
@@ -2033,12 +2119,16 @@ import { analyticsLogger } from "@agor/core/analytics";
2033
2119
  import {
2034
2120
  isUnixImpersonationEnabled,
2035
2121
  loadConfig,
2122
+ resolveExecutionSecurityMode,
2123
+ resolveMultiTenancyConfig as resolveMultiTenancyConfig4,
2124
+ resolveMultiTenancyDatabaseDialect,
2125
+ resolveTenantContext as resolveTenantContext3,
2126
+ TenantResolutionError as TenantResolutionError3,
2036
2127
  validateRepoEnvironment,
2037
2128
  wrapV1AsV2
2038
2129
  } from "@agor/core/config";
2039
2130
  import {
2040
2131
  ArtifactRepository,
2041
- BoardObjectRepository as BoardObjectRepository2,
2042
2132
  BoardRepository as BoardRepository2,
2043
2133
  ScheduleRepository,
2044
2134
  shortId as shortId5,
@@ -2050,7 +2140,7 @@ import {
2050
2140
  validateRenderedManagedEnvUrlFields,
2051
2141
  validateRepoEnvironmentLifecyclePolicy
2052
2142
  } from "@agor/core/environment/webhook";
2053
- import { BadRequest as BadRequest3, Forbidden as Forbidden8, NotAuthenticated as NotAuthenticated7 } from "@agor/core/feathers";
2143
+ import { BadRequest as BadRequest5, Forbidden as Forbidden9, NotAuthenticated as NotAuthenticated8 } from "@agor/core/feathers";
2054
2144
  import {
2055
2145
  boardCommentQueryValidator,
2056
2146
  boardObjectQueryValidator,
@@ -2063,17 +2153,50 @@ import {
2063
2153
  typedValidateQuery,
2064
2154
  userQueryValidator
2065
2155
  } from "@agor/core/lib/feathers-validation";
2066
- import { hasMinimumRole as hasMinimumRole8, ROLES as ROLES9 } from "@agor/core/types";
2156
+ import {
2157
+ GATEWAY_REDACTED_SENTINEL,
2158
+ GATEWAY_SENSITIVE_CONFIG_FIELDS,
2159
+ hasMinimumRole as hasMinimumRole9,
2160
+ ROLES as ROLES10
2161
+ } from "@agor/core/types";
2067
2162
 
2068
2163
  // src/auth/executor-runtime-scope.ts
2069
2164
  import { Forbidden } from "@agor/core/feathers";
2165
+
2166
+ // src/auth/executor-session-token.ts
2167
+ var EXECUTOR_SESSION_TOKEN_TYPE = "executor-session";
2168
+ var EXECUTOR_SESSION_TOKEN_PURPOSE = "executor-task";
2169
+ function isExecutorSessionTokenPayload(payload) {
2170
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) return false;
2171
+ const record = payload;
2172
+ return record.type === EXECUTOR_SESSION_TOKEN_TYPE && record.purpose === EXECUTOR_SESSION_TOKEN_PURPOSE;
2173
+ }
2174
+ function getExecutorSessionTokenSessionId(payload) {
2175
+ return payload.session_id ?? payload.sessionId;
2176
+ }
2177
+
2178
+ // src/auth/executor-runtime-scope.ts
2070
2179
  function scopedPayload(context) {
2071
- const payload = context.params.authentication?.payload;
2072
- if (payload?.type !== "executor-session") return null;
2073
- if (payload.purpose !== "executor-task") {
2074
- throw new Forbidden("Executor token is not valid for this request");
2180
+ const params = context.params;
2181
+ const payload = params.authentication?.payload;
2182
+ if (payload?.type === EXECUTOR_SESSION_TOKEN_TYPE) {
2183
+ if (!isExecutorSessionTokenPayload(payload)) {
2184
+ throw new Forbidden("Executor token is not valid for this request");
2185
+ }
2186
+ return payload;
2075
2187
  }
2076
- return payload;
2188
+ if (params.authentication?.strategy === "jwt" && params.task_id) {
2189
+ return {
2190
+ type: EXECUTOR_SESSION_TOKEN_TYPE,
2191
+ purpose: EXECUTOR_SESSION_TOKEN_PURPOSE,
2192
+ task_id: params.task_id,
2193
+ session_id: params.session_id,
2194
+ sessionId: params.sessionId,
2195
+ branch_id: params.branch_id
2196
+ };
2197
+ }
2198
+ if (payload?.type !== void 0) return null;
2199
+ return null;
2077
2200
  }
2078
2201
  function expectClaim(claim, label) {
2079
2202
  if (!claim) {
@@ -2175,7 +2298,7 @@ function executorRuntimeScopeGuard() {
2175
2298
  const payload = scopedPayload(context);
2176
2299
  if (!payload) return context;
2177
2300
  const scope = {
2178
- sessionId: payload.session_id ?? payload.sessionId,
2301
+ sessionId: getExecutorSessionTokenSessionId(payload),
2179
2302
  taskId: payload.task_id,
2180
2303
  branchId: payload.branch_id
2181
2304
  };
@@ -2352,13 +2475,16 @@ var gatewayRouteHook = async (context) => {
2352
2475
  const latestToolUse = extractLatestToolUseFromMessage(message);
2353
2476
  if (latestToolUse) {
2354
2477
  try {
2355
- void gatewayService.updateProgress({
2356
- session_id: message.session_id,
2357
- state: "working",
2358
- task_id: message.task_id,
2359
- tool_name: latestToolUse.name,
2360
- tool_input: latestToolUse.input
2361
- });
2478
+ gatewayService.updateProgressAfterCommit(
2479
+ {
2480
+ session_id: message.session_id,
2481
+ state: "working",
2482
+ task_id: message.task_id,
2483
+ tool_name: latestToolUse.name,
2484
+ tool_input: latestToolUse.input
2485
+ },
2486
+ context.params
2487
+ );
2362
2488
  } catch (error) {
2363
2489
  console.warn("[gateway-route] Failed to route tool progress:", error);
2364
2490
  }
@@ -2377,6 +2503,11 @@ var gatewayRouteHook = async (context) => {
2377
2503
  return context;
2378
2504
  }
2379
2505
  shouldRoute = true;
2506
+ } else if (message.role === "system") {
2507
+ const systemMeta = message.metadata?.system;
2508
+ if (systemMeta?.render_hint === "context" || /^\[system\]/i.test(messageText.trim())) {
2509
+ shouldRoute = true;
2510
+ }
2380
2511
  } else if (message.role === "user") {
2381
2512
  const source = message.metadata?.source;
2382
2513
  if (source === "agor") {
@@ -2403,37 +2534,25 @@ var gatewayRouteHook = async (context) => {
2403
2534
  return context;
2404
2535
  }
2405
2536
  try {
2406
- gatewayService.routeMessage({
2407
- session_id: message.session_id,
2408
- message: messageText
2409
- }).catch((error) => {
2410
- console.warn("[gateway-route] Failed to route message:", error);
2411
- });
2537
+ gatewayService.routeMessageAfterCommit(
2538
+ {
2539
+ session_id: message.session_id,
2540
+ message: messageText,
2541
+ metadata: message.metadata
2542
+ },
2543
+ context.params
2544
+ );
2412
2545
  } catch (error) {
2413
2546
  console.warn("[gateway-route] Failed to invoke gateway service:", error);
2414
2547
  }
2415
2548
  return context;
2416
2549
  };
2417
2550
 
2418
- // src/services/board-objects.ts
2419
- import {
2420
- BoardObjectRepository
2421
- } from "@agor/core/db";
2422
- function normalizeBoardObjectFindQuery(query = {}) {
2423
- const { board_id, branch_id, card_id, zone_id, entity_type } = query;
2424
- const requestedSkip = Number(query.$skip ?? 0);
2425
- const requestedLimit = typeof query.$limit === "number" ? query.$limit : void 0;
2426
- const filters = Object.fromEntries(
2427
- Object.entries({ board_id, branch_id, card_id, zone_id, entity_type }).filter(
2428
- ([, value]) => value !== void 0
2429
- )
2430
- );
2431
- return {
2432
- filters,
2433
- pagination: requestedLimit !== void 0 || requestedSkip > 0 ? { limit: requestedLimit, offset: requestedSkip } : {},
2434
- limit: requestedLimit ?? 100,
2435
- skip: requestedSkip
2436
- };
2551
+ // src/oauth-auth-helpers.ts
2552
+ import { runWithTenantDatabaseScope } from "@agor/core/db";
2553
+ function resolveForUserIdWithGate(opts) {
2554
+ const canUseExplicitUser = opts.isServiceAccount === true || opts.authPayloadType === "executor-session" && opts.queryForUserId === opts.callerUserId;
2555
+ return opts.queryForUserId && canUseExplicitUser ? opts.queryForUserId : opts.callerUserId;
2437
2556
  }
2438
2557
 
2439
2558
  // src/services/groups.ts
@@ -2670,37 +2789,6 @@ function paginateClientSide(rows, query, skipFilterKeys = /* @__PURE__ */ new Se
2670
2789
  data: filtered.slice(skip, skip + limit)
2671
2790
  };
2672
2791
  }
2673
- function scopeSessionQuery(sessionRepo, options) {
2674
- return async (context) => {
2675
- if (!context.params.provider) {
2676
- return context;
2677
- }
2678
- if (context.params.user?._isServiceAccount) {
2679
- return context;
2680
- }
2681
- if (context.method !== "find") {
2682
- return context;
2683
- }
2684
- const userId = context.params.user?.user_id;
2685
- if (!userId) {
2686
- context.result = {
2687
- total: 0,
2688
- limit: 0,
2689
- skip: 0,
2690
- data: []
2691
- };
2692
- return context;
2693
- }
2694
- const userRole = context.params.user?.role;
2695
- const allowSuperadmin = options?.allowSuperadmin ?? true;
2696
- const accessibleSessions = isSuperAdmin(userRole, allowSuperadmin) ? await sessionRepo.findAll() : await sessionRepo.findAccessibleSessions(userId);
2697
- context.result = paginateClientSide(
2698
- accessibleSessions,
2699
- context.params.query
2700
- );
2701
- return context;
2702
- };
2703
- }
2704
2792
  function loadSessionBranch(sessionService, branchRepo) {
2705
2793
  return async (context) => {
2706
2794
  if (!context.params.provider) {
@@ -2997,7 +3085,7 @@ function emptyFindResult(context) {
2997
3085
  };
2998
3086
  return context;
2999
3087
  }
3000
- async function resolveFindScopeAccess(context, options, loadAccessibleIds) {
3088
+ async function resolveFindSqlScopeAccess(context, options) {
3001
3089
  if (context.method !== "find") return { kind: "passThrough" };
3002
3090
  if (!context.params.provider) return { kind: "passThrough" };
3003
3091
  if (context.params.user?._isServiceAccount) return { kind: "passThrough" };
@@ -3009,57 +3097,30 @@ async function resolveFindScopeAccess(context, options, loadAccessibleIds) {
3009
3097
  const userRole = context.params.user?.role;
3010
3098
  const allowSuperadmin = options?.allowSuperadmin ?? true;
3011
3099
  if (isSuperAdmin(userRole, allowSuperadmin)) return { kind: "passThrough" };
3012
- const ids = await loadAccessibleIds(userId);
3013
- return { kind: "filter", accessibleIds: new Set(ids) };
3100
+ return { kind: "filter", userId };
3014
3101
  }
3015
- function intersectFindQuery(context, field, accessibleIds) {
3016
- const query = context.params.query ?? {};
3017
- const existing = query[field];
3018
- if (typeof existing === "string") {
3019
- if (!accessibleIds.has(existing)) return emptyFindResult(context);
3020
- return context;
3021
- }
3022
- if (existing && typeof existing === "object" && Array.isArray(existing.$in)) {
3023
- const intersect = existing.$in.filter((id) => accessibleIds.has(id));
3024
- if (intersect.length === 0) return emptyFindResult(context);
3025
- query[field] = { $in: intersect };
3026
- context.params.query = query;
3027
- return context;
3028
- }
3029
- if (accessibleIds.size === 0) return emptyFindResult(context);
3030
- query[field] = { $in: Array.from(accessibleIds) };
3031
- context.params.query = query;
3032
- return context;
3033
- }
3034
- function scopeFindToAccessibleBranches(branchRepo, options) {
3102
+ function scopeFindToAccessibleBranchesSql(options) {
3035
3103
  return async (context) => {
3036
- const decision = await resolveFindScopeAccess(context, options, async (uid) => {
3037
- const accessible = await branchRepo.findAccessibleBranches(uid);
3038
- return accessible.map((w) => w.branch_id);
3039
- });
3104
+ const decision = await resolveFindSqlScopeAccess(context, options);
3040
3105
  if (decision.kind !== "filter") return context;
3041
- return intersectFindQuery(context, "branch_id", decision.accessibleIds);
3106
+ context.params._agorSqlBranchAccessUserId = decision.userId;
3107
+ return context;
3042
3108
  };
3043
3109
  }
3044
- function scopeFindToAccessibleSessions(sessionRepo, options) {
3110
+ function scopeFindToAccessibleSessionsSql(options) {
3045
3111
  return async (context) => {
3046
- const decision = await resolveFindScopeAccess(context, options, async (uid) => {
3047
- const accessible = await sessionRepo.findAccessibleSessions(uid);
3048
- return accessible.map((s) => s.session_id);
3049
- });
3112
+ const decision = await resolveFindSqlScopeAccess(context, options);
3050
3113
  if (decision.kind !== "filter") return context;
3051
- return intersectFindQuery(context, "session_id", decision.accessibleIds);
3114
+ context.params._agorSqlSessionAccessUserId = decision.userId;
3115
+ return context;
3052
3116
  };
3053
3117
  }
3054
- function scopeFindToAccessibleBoards(boardRepo, options) {
3118
+ function scopeFindToAccessibleBoardsSql(options) {
3055
3119
  return async (context) => {
3056
- const decision = await resolveFindScopeAccess(
3057
- context,
3058
- options,
3059
- (uid) => boardRepo.findVisibleBoardIds(uid)
3060
- );
3120
+ const decision = await resolveFindSqlScopeAccess(context, options);
3061
3121
  if (decision.kind !== "filter") return context;
3062
- return intersectFindQuery(context, "board_id", decision.accessibleIds);
3122
+ context.params._agorSqlBoardAccessUserId = decision.userId;
3123
+ return context;
3063
3124
  };
3064
3125
  }
3065
3126
  function scopeScheduleQuery(scheduleRepo, options) {
@@ -3182,8 +3243,13 @@ import {
3182
3243
  SessionRepository,
3183
3244
  UsersRepository
3184
3245
  } from "@agor/core/db";
3185
- import { Forbidden as Forbidden4 } from "@agor/core/feathers";
3186
- import { formatModelToolMismatchWarning, lintModelToolMatch } from "@agor/core/models";
3246
+ import { BadRequest as BadRequest2, Forbidden as Forbidden4 } from "@agor/core/feathers";
3247
+ import {
3248
+ formatModelToolMismatchWarning,
3249
+ formatUnsupportedAgorCodexModelMessage,
3250
+ isUnsupportedAgorCodexModel,
3251
+ lintModelToolMatch
3252
+ } from "@agor/core/models";
3187
3253
  import { resolveChildSessionConfig } from "@agor/core/sessions";
3188
3254
  import { ROLES as ROLES3, SessionStatus } from "@agor/core/types";
3189
3255
  var remoteRelationshipsEnrichedResults = /* @__PURE__ */ new WeakSet();
@@ -3206,6 +3272,7 @@ import {
3206
3272
  validateEnvVar
3207
3273
  } from "@agor/core/config";
3208
3274
  import {
3275
+ and,
3209
3276
  compare,
3210
3277
  decryptApiKey,
3211
3278
  deleteFrom,
@@ -3217,16 +3284,29 @@ import {
3217
3284
  update,
3218
3285
  users
3219
3286
  } from "@agor/core/db";
3220
- import { Forbidden as Forbidden5, NotAuthenticated as NotAuthenticated3 } from "@agor/core/feathers";
3221
- import { isLikelyGitToken } from "@agor/core/git";
3287
+ import { Forbidden as Forbidden6, NotAuthenticated as NotAuthenticated3 } from "@agor/core/feathers";
3288
+ import { isLikelyGitToken } from "@agor/core/git/pure";
3222
3289
  import {
3223
3290
  extractAgenticToolsPublicValues,
3224
- hasMinimumRole as hasMinimumRole3,
3291
+ hasMinimumRole as hasMinimumRole4,
3225
3292
  normalizeRole,
3226
- ROLES as ROLES4,
3293
+ ROLES as ROLES5,
3227
3294
  toAgenticToolsStatus
3228
3295
  } from "@agor/core/types";
3296
+
3297
+ // src/services/user-avatar-sync.ts
3298
+ import {
3299
+ AppVariableRepository,
3300
+ GatewayChannelRepository,
3301
+ UsersRepository as UsersRepository2
3302
+ } from "@agor/core/db";
3303
+ import { Forbidden as Forbidden5 } from "@agor/core/feathers";
3304
+ import { SlackConnector } from "@agor/core/gateway";
3305
+ import { hasMinimumRole as hasMinimumRole3, ROLES as ROLES4 } from "@agor/core/types";
3306
+
3307
+ // src/services/users.ts
3229
3308
  var LOCAL_AUTH_LOOKUP_PARAM = Symbol("agor.users.local-auth-lookup");
3309
+ var AUTH_INTERNAL_USER_LOOKUP_PARAM = Symbol("agor.users.auth-internal-lookup");
3230
3310
  function isLocalAuthenticationLookup(params) {
3231
3311
  return params?.[LOCAL_AUTH_LOOKUP_PARAM] === true;
3232
3312
  }
@@ -3250,6 +3330,11 @@ function buildSessionCreatedAnalyticsProperties(session) {
3250
3330
  }
3251
3331
 
3252
3332
  // src/utils/apply-session-config-defaults.ts
3333
+ import { BadRequest as BadRequest3 } from "@agor/core/feathers";
3334
+ import {
3335
+ formatUnsupportedAgorCodexModelMessage as formatUnsupportedAgorCodexModelMessage2,
3336
+ isUnsupportedAgorCodexModel as isUnsupportedAgorCodexModel2
3337
+ } from "@agor/core/models";
3253
3338
  import { resolveSessionDefaults } from "@agor/core/sessions";
3254
3339
  function applySessionConfigDefaults(opts = {}) {
3255
3340
  const { warnOnExternalDefaultFill = true } = opts;
@@ -3261,9 +3346,12 @@ function applySessionConfigDefaults(opts = {}) {
3261
3346
  if (!data) return context;
3262
3347
  const hasPermission = data.permission_config != null;
3263
3348
  const hasModel = !!data.model_config?.model;
3264
- if (hasPermission && hasModel) return context;
3265
3349
  const agenticTool = data.agentic_tool;
3266
3350
  if (!agenticTool) return context;
3351
+ if (agenticTool === "codex" && data.model_config?.model && isUnsupportedAgorCodexModel2(data.model_config.model)) {
3352
+ throw new BadRequest3(formatUnsupportedAgorCodexModelMessage2(data.model_config.model));
3353
+ }
3354
+ if (hasPermission && hasModel) return context;
3267
3355
  const userId = data.created_by;
3268
3356
  if (!userId) return context;
3269
3357
  let user;
@@ -3282,6 +3370,9 @@ function applySessionConfigDefaults(opts = {}) {
3282
3370
  user,
3283
3371
  overrides: { modelConfig: data.model_config ?? void 0 }
3284
3372
  });
3373
+ if (resolved.model_config?.model && agenticTool === "codex" && isUnsupportedAgorCodexModel2(resolved.model_config.model)) {
3374
+ throw new BadRequest3(formatUnsupportedAgorCodexModelMessage2(resolved.model_config.model));
3375
+ }
3285
3376
  if (!hasPermission) {
3286
3377
  data.permission_config = resolved.permission_config;
3287
3378
  if (warnOnExternalDefaultFill && context.params.provider) {
@@ -3298,8 +3389,8 @@ function applySessionConfigDefaults(opts = {}) {
3298
3389
  }
3299
3390
 
3300
3391
  // src/utils/authorization.ts
3301
- import { Forbidden as Forbidden6, NotAuthenticated as NotAuthenticated4 } from "@agor/core/feathers";
3302
- import { hasMinimumRole as hasMinimumRole4, ROLES as ROLES5 } from "@agor/core/types";
3392
+ import { Forbidden as Forbidden7, NotAuthenticated as NotAuthenticated4 } from "@agor/core/feathers";
3393
+ import { hasMinimumRole as hasMinimumRole5, ROLES as ROLES6 } from "@agor/core/types";
3303
3394
  function ensureMinimumRole(params, minimumRole, action = "perform this action") {
3304
3395
  if (!params?.provider) {
3305
3396
  return;
@@ -3310,8 +3401,8 @@ function ensureMinimumRole(params, minimumRole, action = "perform this action")
3310
3401
  if (params.user._isServiceAccount === true) {
3311
3402
  return;
3312
3403
  }
3313
- if (!hasMinimumRole4(params.user.role, minimumRole)) {
3314
- throw new Forbidden6(`You need ${minimumRole} access to ${action}`);
3404
+ if (!hasMinimumRole5(params.user.role, minimumRole)) {
3405
+ throw new Forbidden7(`You need ${minimumRole} access to ${action}`);
3315
3406
  }
3316
3407
  }
3317
3408
  function requireMinimumRole(minimumRole, action) {
@@ -3320,7 +3411,7 @@ function requireMinimumRole(minimumRole, action) {
3320
3411
  return context;
3321
3412
  };
3322
3413
  }
3323
- var DEFAULT_MANAGED_ENVS_MINIMUM_ROLE = ROLES5.MEMBER;
3414
+ var DEFAULT_MANAGED_ENVS_MINIMUM_ROLE = ROLES6.MEMBER;
3324
3415
  var ENV_COMMAND_FIELDS = [
3325
3416
  "environment",
3326
3417
  // Repo-level: v2 named variants (source of truth)
@@ -3348,13 +3439,13 @@ function requireAdminForEnvConfig() {
3348
3439
  }
3349
3440
  ensureMinimumRole(
3350
3441
  context.params,
3351
- ROLES5.ADMIN,
3442
+ ROLES6.ADMIN,
3352
3443
  "modify environment commands (up_command, down_command, etc.)"
3353
3444
  );
3354
3445
  return context;
3355
3446
  };
3356
3447
  }
3357
- function registerAuthenticatedRoute(app, path4, service, authConfig, requireAuth) {
3448
+ function registerAuthenticatedRoute(app, path4, service, authConfig, requireAuth, options = {}) {
3358
3449
  app.use(path4, service);
3359
3450
  const hooks = {};
3360
3451
  for (const [method, config] of Object.entries(authConfig)) {
@@ -3365,6 +3456,7 @@ function registerAuthenticatedRoute(app, path4, service, authConfig, requireAuth
3365
3456
  ];
3366
3457
  }
3367
3458
  app.service(path4).hooks({
3459
+ ...options.around ? { around: { all: options.around } } : {},
3368
3460
  before: hooks
3369
3461
  });
3370
3462
  }
@@ -3376,7 +3468,8 @@ function isBranchInspectResult(value) {
3376
3468
  }
3377
3469
  async function inspectBranchViaExecutor(app, branchId, options = {}) {
3378
3470
  const sessionToken = generateSessionToken(
3379
- app
3471
+ app,
3472
+ options.serviceTokenScope
3380
3473
  );
3381
3474
  const result = await runExecutorCommand(
3382
3475
  {
@@ -3401,7 +3494,7 @@ async function inspectBranchViaExecutor(app, branchId, options = {}) {
3401
3494
 
3402
3495
  // src/utils/executor-read-impersonation.ts
3403
3496
  import { loadConfigSync as loadConfigSync2 } from "@agor/core/config";
3404
- import { UsersRepository as UsersRepository2 } from "@agor/core/db";
3497
+ import { UsersRepository as UsersRepository3 } from "@agor/core/db";
3405
3498
  async function resolveExecutorReadAsUser(db, userOrId) {
3406
3499
  const config = loadConfigSync2();
3407
3500
  const unixMode = config.execution?.unix_user_mode ?? "simple";
@@ -3410,7 +3503,7 @@ async function resolveExecutorReadAsUser(db, userOrId) {
3410
3503
  }
3411
3504
  let user;
3412
3505
  if (typeof userOrId === "string") {
3413
- user = await new UsersRepository2(db).findById(userOrId);
3506
+ user = await new UsersRepository3(db).findById(userOrId);
3414
3507
  } else {
3415
3508
  user = userOrId;
3416
3509
  }
@@ -3456,11 +3549,26 @@ function injectCreatedBy() {
3456
3549
  // src/utils/mcp-header-secrets.ts
3457
3550
  import { redactMCPAuthSecrets } from "@agor/core/tools/mcp/auth-secrets";
3458
3551
  import { redactMCPCustomHeaders } from "@agor/core/tools/mcp/http-headers";
3552
+ import jwt2 from "jsonwebtoken";
3459
3553
  function shouldExposeMCPServerSecretsForSessionToken(params, options = {}) {
3460
- const payload = params?.authentication?.payload;
3461
- const sessionId = params?.session_id ?? payload?.session_id ?? payload?.sessionId;
3554
+ const payload = params?.authentication?.payload ?? decodeExecutorSessionPayload(params);
3555
+ const sessionId = params?.session_id ?? getPayloadSessionId(payload);
3462
3556
  return !!params?.provider && (params.authentication?.strategy === "session-token" || payload?.type === "executor-session") && !!sessionId && (!options.sessionId || sessionId === options.sessionId);
3463
3557
  }
3558
+ function decodeExecutorSessionPayload(params) {
3559
+ if (params?.authentication?.strategy !== "jwt" || !params.authentication.accessToken) {
3560
+ return void 0;
3561
+ }
3562
+ const decoded = jwt2.decode(params.authentication.accessToken);
3563
+ if (!decoded || typeof decoded !== "object" || Array.isArray(decoded)) {
3564
+ return void 0;
3565
+ }
3566
+ if (!isExecutorSessionTokenPayload(decoded)) return void 0;
3567
+ return decoded;
3568
+ }
3569
+ function getPayloadSessionId(payload) {
3570
+ return payload ? getExecutorSessionTokenSessionId(payload) : void 0;
3571
+ }
3464
3572
  function shouldExposeMCPServerSecrets(params, options = {}) {
3465
3573
  if (!params?.provider) return true;
3466
3574
  if (params.user?._isServiceAccount || params.user?.role === "service") return true;
@@ -3482,12 +3590,13 @@ init_mcp_token_authorization();
3482
3590
 
3483
3591
  // src/utils/realign-repo-origin.ts
3484
3592
  init_spawn_executor();
3485
- async function ensureRepoOriginAlignedForRepo(app, repo) {
3593
+ async function ensureRepoOriginAlignedForRepo(app, repo, params) {
3486
3594
  if (repo.repo_type !== "remote") return;
3487
3595
  if (!repo.remote_url) return;
3488
3596
  if (!repo.local_path) return;
3489
- const sessionToken = generateSessionToken(
3490
- app
3597
+ const sessionToken = generateScopedServiceToken(
3598
+ app,
3599
+ params
3491
3600
  );
3492
3601
  spawnExecutorFireAndForget(
3493
3602
  {
@@ -3516,12 +3625,14 @@ function realignRepoOriginAfterPatchHook() {
3516
3625
  const repos = Array.isArray(result) ? result : [result];
3517
3626
  for (const repo of repos) {
3518
3627
  if (!repo?.repo_id) continue;
3519
- ensureRepoOriginAlignedForRepo(context.app, repo).catch((err) => {
3520
- const message = err instanceof Error ? err.message : String(err);
3521
- console.warn(
3522
- `\u26A0\uFE0F [repos.after.patch] ensureRepoOriginAlignedForRepo failed for repo ${repo.repo_id}: ${message}`
3523
- );
3524
- });
3628
+ ensureRepoOriginAlignedForRepo(context.app, repo, context.params).catch(
3629
+ (err) => {
3630
+ const message = err instanceof Error ? err.message : String(err);
3631
+ console.warn(
3632
+ `\u26A0\uFE0F [repos.after.patch] ensureRepoOriginAlignedForRepo failed for repo ${repo.repo_id}: ${message}`
3633
+ );
3634
+ }
3635
+ );
3525
3636
  }
3526
3637
  return context;
3527
3638
  };
@@ -3543,6 +3654,7 @@ var RealtimeAccessCache = class {
3543
3654
  }
3544
3655
  branchVisibility = /* @__PURE__ */ new Map();
3545
3656
  sessionBranches = /* @__PURE__ */ new Map();
3657
+ sessionOwners = /* @__PURE__ */ new Map();
3546
3658
  branchVisibilityTtlMs;
3547
3659
  sessionBranchTtlMs;
3548
3660
  now;
@@ -3559,6 +3671,27 @@ var RealtimeAccessCache = class {
3559
3671
  });
3560
3672
  return branchId;
3561
3673
  }
3674
+ /**
3675
+ * Owning user id for a session, cached on the same cadence as the
3676
+ * session→branch map. Used only to offer streaming events to the session
3677
+ * creator's own connections as a fallback when they haven't subscribed to
3678
+ * the per-session stream channel yet.
3679
+ */
3680
+ async getSessionOwnerId(sessionId) {
3681
+ const cached = this.sessionOwners.get(sessionId);
3682
+ const now = this.now();
3683
+ if (cached && cached.expiresAt > now) {
3684
+ return cached.ownerId;
3685
+ }
3686
+ const ownerId = await this.options.sessionsRepository.findCreatedByBySessionId(
3687
+ sessionId
3688
+ ) ?? null;
3689
+ this.sessionOwners.set(sessionId, {
3690
+ ownerId,
3691
+ expiresAt: now + this.sessionBranchTtlMs
3692
+ });
3693
+ return ownerId;
3694
+ }
3562
3695
  async getBranchVisibility(branchId) {
3563
3696
  const cached = this.branchVisibility.get(branchId);
3564
3697
  const now = this.now();
@@ -3594,6 +3727,7 @@ var RealtimeAccessCache = class {
3594
3727
  }
3595
3728
  invalidateSession(sessionId) {
3596
3729
  this.sessionBranches.delete(sessionId);
3730
+ this.sessionOwners.delete(sessionId);
3597
3731
  }
3598
3732
  clearVisibility() {
3599
3733
  this.branchVisibility.clear();
@@ -3601,6 +3735,7 @@ var RealtimeAccessCache = class {
3601
3735
  clearAll() {
3602
3736
  this.branchVisibility.clear();
3603
3737
  this.sessionBranches.clear();
3738
+ this.sessionOwners.clear();
3604
3739
  }
3605
3740
  visibilityFromEntry(entry) {
3606
3741
  return entry.mode === "allAuthenticated" ? { mode: "allAuthenticated" } : { mode: "explicitUsers", userIds: entry.userIds };
@@ -3608,8 +3743,22 @@ var RealtimeAccessCache = class {
3608
3743
  };
3609
3744
 
3610
3745
  // src/utils/realtime-publish.ts
3611
- import { shortId as shortId2 } from "@agor/core/db";
3612
- import { hasMinimumRole as hasMinimumRole6, ROLES as ROLES7 } from "@agor/core/types";
3746
+ import {
3747
+ resolveTenantContext,
3748
+ TenantResolutionError
3749
+ } from "@agor/core/config";
3750
+ import { getCurrentTenantId, shortId as shortId2 } from "@agor/core/db";
3751
+ import { hasMinimumRole as hasMinimumRole7, ROLES as ROLES8 } from "@agor/core/types";
3752
+ function tenantChannelName(tenantId) {
3753
+ return `tenant:${tenantId}`;
3754
+ }
3755
+ var SESSION_STREAM_CHANNEL_PREFIX = "session-stream:";
3756
+ function sessionStreamChannelName(sessionId) {
3757
+ return `${SESSION_STREAM_CHANNEL_PREFIX}${sessionId}`;
3758
+ }
3759
+ function existingChannel(app, name) {
3760
+ return (app.channels ?? []).includes(name) ? app.channel(name) : null;
3761
+ }
3613
3762
  var DEBUG_REALTIME_PUBLISH = process.env.AGOR_DEBUG_REALTIME_PUBLISH === "1" || process.env.DEBUG?.includes("realtime-publish");
3614
3763
  function realtimePublishDebug(...args) {
3615
3764
  if (DEBUG_REALTIME_PUBLISH) {
@@ -3625,8 +3774,27 @@ var SESSION_ID_SCOPED_PATHS = /* @__PURE__ */ new Set([
3625
3774
  "session-env-selections"
3626
3775
  ]);
3627
3776
  var OPTIONAL_BRANCH_OR_SESSION_SCOPED_PATHS = /* @__PURE__ */ new Set(["board-objects", "board-comments"]);
3777
+ var MESSAGE_STREAMING_EVENTS = /* @__PURE__ */ new Set([
3778
+ "streaming:start",
3779
+ "streaming:chunk",
3780
+ "streaming:end",
3781
+ "streaming:error",
3782
+ "thinking:start",
3783
+ "thinking:chunk",
3784
+ "thinking:end"
3785
+ ]);
3786
+ var TASK_STREAMING_EVENTS = /* @__PURE__ */ new Set(["thinking:chunk", "tool:start", "tool:complete"]);
3628
3787
  function isStreamingEvent(context) {
3629
- return context.path === "messages/streaming" || context.path === "messages" && context.event?.startsWith("streaming:") === true;
3788
+ if (context.path === "messages/streaming") return true;
3789
+ const event = context.event;
3790
+ if (!event) return false;
3791
+ if (context.path === "messages") {
3792
+ return event.startsWith("streaming:") || MESSAGE_STREAMING_EVENTS.has(event);
3793
+ }
3794
+ if (context.path === "tasks") {
3795
+ return TASK_STREAMING_EVENTS.has(event);
3796
+ }
3797
+ return false;
3630
3798
  }
3631
3799
  function asRecord2(value) {
3632
3800
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
@@ -3676,7 +3844,7 @@ function isServiceConnection(connection) {
3676
3844
  }
3677
3845
  function isAdminConnection(connection, allowSuperadmin) {
3678
3846
  const user = userFromConnection(connection);
3679
- if (!user?._isServiceAccount && user?.role && hasMinimumRole6(user.role, ROLES7.ADMIN)) {
3847
+ if (!user?._isServiceAccount && user?.role && hasMinimumRole7(user.role, ROLES8.ADMIN)) {
3680
3848
  return true;
3681
3849
  }
3682
3850
  return isSuperAdmin(user?.role, allowSuperadmin);
@@ -3762,6 +3930,47 @@ async function resolvePublishScope(data, context, accessCache) {
3762
3930
  function filterToServiceConnections(authenticated) {
3763
3931
  return authenticated.filter((connection) => isServiceConnection(connection));
3764
3932
  }
3933
+ async function resolveStreamingDelivery(app, data, tenantScoped, accessCache, branchRbacEnabled, allowSuperadmin) {
3934
+ const serviceConnections = filterToServiceConnections(tenantScoped);
3935
+ const sessionId = extractSessionId(data);
3936
+ if (!sessionId) return serviceConnections;
3937
+ const tenantConnections = new Set(
3938
+ tenantScoped.connections
3939
+ );
3940
+ const existingRoom = existingChannel(app, sessionStreamChannelName(sessionId));
3941
+ const room = existingRoom ? existingRoom.filter((connection) => tenantConnections.has(connection)) : null;
3942
+ let ownerId = null;
3943
+ try {
3944
+ ownerId = await accessCache.getSessionOwnerId(sessionId);
3945
+ } catch {
3946
+ }
3947
+ const ownerChannel = () => tenantScoped.filter(
3948
+ (connection) => userFromConnection(connection)?.user_id === ownerId
3949
+ );
3950
+ if (!branchRbacEnabled) {
3951
+ const channels2 = [serviceConnections];
3952
+ if (room) channels2.push(room);
3953
+ if (ownerId) channels2.push(ownerChannel());
3954
+ return channels2;
3955
+ }
3956
+ const branchId = await accessCache.getBranchIdForSession(sessionId);
3957
+ const visibility = branchId ? await accessCache.getBranchVisibility(branchId) : null;
3958
+ if (!visibility) return serviceConnections;
3959
+ if (visibility.mode === "allAuthenticated") {
3960
+ const channels2 = [serviceConnections];
3961
+ if (room) channels2.push(room);
3962
+ if (ownerId) channels2.push(ownerChannel());
3963
+ return channels2;
3964
+ }
3965
+ const channels = [serviceConnections];
3966
+ if (room) {
3967
+ channels.push(filterToUserIdsOrSuperadmins(room, visibility.userIds, allowSuperadmin));
3968
+ }
3969
+ if (ownerId && visibility.userIds.has(ownerId)) {
3970
+ channels.push(ownerChannel());
3971
+ }
3972
+ return channels;
3973
+ }
3765
3974
  function filterToUserIdsOrAdmins(authenticated, userIds, allowSuperadmin) {
3766
3975
  return authenticated.filter((connection) => {
3767
3976
  if (isServiceConnection(connection) || isAdminConnection(connection, allowSuperadmin)) {
@@ -3780,6 +3989,22 @@ function filterToUserIdsOrSuperadmins(authenticated, userIds, allowSuperadmin) {
3780
3989
  return typeof userId === "string" && userIds.has(userId);
3781
3990
  });
3782
3991
  }
3992
+ function extractConnectionTenantId(context) {
3993
+ const params = context.params;
3994
+ const tenant = params?.connection?.tenant ?? params?.connection?.data?.tenant;
3995
+ return tenant && typeof tenant === "object" && "tenant_id" in tenant ? typeof tenant.tenant_id === "string" ? tenant.tenant_id : void 0 : void 0;
3996
+ }
3997
+ function resolveRealtimeTenantId(multiTenancy, context) {
3998
+ try {
3999
+ return resolveTenantContext(multiTenancy, { params: context.params }).tenant_id;
4000
+ } catch (error) {
4001
+ const connectionTenantId = extractConnectionTenantId(context);
4002
+ if (error instanceof TenantResolutionError && connectionTenantId) return connectionTenantId;
4003
+ const ambientTenantId = getCurrentTenantId();
4004
+ if (error instanceof TenantResolutionError && ambientTenantId) return ambientTenantId;
4005
+ throw error;
4006
+ }
4007
+ }
3783
4008
  function configureRealtimePublish(options) {
3784
4009
  const {
3785
4010
  app,
@@ -3790,7 +4015,8 @@ function configureRealtimePublish(options) {
3790
4015
  branchRepository,
3791
4016
  sessionsRepository
3792
4017
  }),
3793
- allowSuperadmin = true
4018
+ allowSuperadmin = true,
4019
+ multiTenancy
3794
4020
  } = options;
3795
4021
  app.publish(async (data, context) => {
3796
4022
  if (context.path && context.method && !isStreamingEvent(context)) {
@@ -3801,12 +4027,39 @@ function configureRealtimePublish(options) {
3801
4027
  );
3802
4028
  }
3803
4029
  const authenticated = app.channel("authenticated");
3804
- if (!branchRbacEnabled) return authenticated;
4030
+ let tenantScoped = authenticated;
4031
+ if (multiTenancy) {
4032
+ try {
4033
+ const tenantId = resolveRealtimeTenantId(multiTenancy, context);
4034
+ tenantScoped = app.channel(tenantChannelName(tenantId));
4035
+ } catch (error) {
4036
+ if (error instanceof TenantResolutionError) {
4037
+ console.warn("[realtime] Suppressing event without tenant context", {
4038
+ path: context.path,
4039
+ event: context.event,
4040
+ method: context.method
4041
+ });
4042
+ return filterToServiceConnections(authenticated);
4043
+ }
4044
+ throw error;
4045
+ }
4046
+ }
4047
+ if (isStreamingEvent(context)) {
4048
+ return resolveStreamingDelivery(
4049
+ app,
4050
+ data,
4051
+ tenantScoped,
4052
+ accessCache,
4053
+ branchRbacEnabled,
4054
+ allowSuperadmin
4055
+ );
4056
+ }
4057
+ if (!branchRbacEnabled) return tenantScoped;
3805
4058
  const scope = await resolvePublishScope(data, context, accessCache);
3806
- if (scope.kind === "global") return authenticated;
3807
- if (scope.kind === "serviceOnly") return filterToServiceConnections(authenticated);
4059
+ if (scope.kind === "global") return tenantScoped;
4060
+ if (scope.kind === "serviceOnly") return filterToServiceConnections(tenantScoped);
3808
4061
  if (scope.kind === "users") {
3809
- return filterToUserIdsOrAdmins(authenticated, scope.userIds, allowSuperadmin);
4062
+ return filterToUserIdsOrAdmins(tenantScoped, scope.userIds, allowSuperadmin);
3810
4063
  }
3811
4064
  if (!scope.branchId) {
3812
4065
  console.warn("[realtime] Suppressing scoped event without resolvable branch context", {
@@ -3814,7 +4067,7 @@ function configureRealtimePublish(options) {
3814
4067
  event: context.event,
3815
4068
  method: context.method
3816
4069
  });
3817
- return filterToServiceConnections(authenticated);
4070
+ return filterToServiceConnections(tenantScoped);
3818
4071
  }
3819
4072
  const visibility = await accessCache.getBranchVisibility(scope.branchId);
3820
4073
  if (!visibility) {
@@ -3823,18 +4076,18 @@ function configureRealtimePublish(options) {
3823
4076
  event: context.event,
3824
4077
  method: context.method
3825
4078
  });
3826
- return filterToServiceConnections(authenticated);
4079
+ return filterToServiceConnections(tenantScoped);
3827
4080
  }
3828
4081
  if (visibility.mode === "allAuthenticated") {
3829
- return authenticated;
4082
+ return tenantScoped;
3830
4083
  }
3831
- return filterToUserIdsOrSuperadmins(authenticated, visibility.userIds, allowSuperadmin);
4084
+ return filterToUserIdsOrSuperadmins(tenantScoped, visibility.userIds, allowSuperadmin);
3832
4085
  });
3833
4086
  }
3834
4087
 
3835
4088
  // src/utils/schedule-hooks.ts
3836
- import { BadRequest as BadRequest2, Forbidden as Forbidden7, NotAuthenticated as NotAuthenticated6 } from "@agor/core/feathers";
3837
- import { hasMinimumRole as hasMinimumRole7, ROLES as ROLES8 } from "@agor/core/types";
4089
+ import { BadRequest as BadRequest4, Forbidden as Forbidden8, NotAuthenticated as NotAuthenticated6 } from "@agor/core/feathers";
4090
+ import { hasMinimumRole as hasMinimumRole8, ROLES as ROLES9 } from "@agor/core/types";
3838
4091
  function ensureCurrentScheduleLoaded(scheduleRepo) {
3839
4092
  return async (context) => {
3840
4093
  if (context.method !== "patch") return context;
@@ -3856,21 +4109,21 @@ function validateScheduleConfig() {
3856
4109
  const { isValidCron } = await import("@agor/core/utils/cron");
3857
4110
  const tz = merged.timezone_mode === "local" && merged.timezone ? merged.timezone : "UTC";
3858
4111
  if (!isValidCron(data.cron_expression, tz)) {
3859
- throw new BadRequest2(`Invalid cron expression: '${data.cron_expression}'`);
4112
+ throw new BadRequest4(`Invalid cron expression: '${data.cron_expression}'`);
3860
4113
  }
3861
4114
  }
3862
4115
  if (merged.timezone_mode === "local" && !merged.timezone) {
3863
- throw new BadRequest2("timezone_mode='local' requires a non-empty IANA timezone.");
4116
+ throw new BadRequest4("timezone_mode='local' requires a non-empty IANA timezone.");
3864
4117
  }
3865
4118
  if (data.timezone) {
3866
4119
  try {
3867
4120
  new Intl.DateTimeFormat("en-US", { timeZone: data.timezone });
3868
4121
  } catch {
3869
- throw new BadRequest2(`Unknown IANA timezone: '${data.timezone}'`);
4122
+ throw new BadRequest4(`Unknown IANA timezone: '${data.timezone}'`);
3870
4123
  }
3871
4124
  }
3872
4125
  if (data.prompt !== void 0 && data.prompt.trim() === "") {
3873
- throw new BadRequest2("Schedule prompt cannot be empty.");
4126
+ throw new BadRequest4("Schedule prompt cannot be empty.");
3874
4127
  }
3875
4128
  return context;
3876
4129
  };
@@ -3889,14 +4142,14 @@ function ensureScheduleRunsAsCaller(options) {
3889
4142
  }
3890
4143
  const data = context.data;
3891
4144
  if (data?.created_by !== void 0 && data.created_by !== schedule.created_by) {
3892
- throw new Forbidden7("Cannot change the user a schedule runs as.");
4145
+ throw new Forbidden8("Cannot change the user a schedule runs as.");
3893
4146
  }
3894
4147
  const allowSuperadmin = options?.allowSuperadmin ?? true;
3895
- if (allowSuperadmin && hasMinimumRole7(user.role, ROLES8.SUPERADMIN)) {
4148
+ if (allowSuperadmin && hasMinimumRole8(user.role, ROLES9.SUPERADMIN)) {
3896
4149
  return context;
3897
4150
  }
3898
4151
  if (schedule.created_by !== user.user_id) {
3899
- throw new Forbidden7(
4152
+ throw new Forbidden8(
3900
4153
  "Schedules run as the user who created them. You can only modify or run schedules you created."
3901
4154
  );
3902
4155
  }
@@ -3933,6 +4186,165 @@ function recomputeNextRunAt() {
3933
4186
  };
3934
4187
  }
3935
4188
 
4189
+ // src/utils/session-queue-tenant-scope.ts
4190
+ import { resolveMultiTenancyConfig as resolveMultiTenancyConfig2 } from "@agor/core/config";
4191
+ import { runWithTenantDatabaseScope as runWithTenantDatabaseScope3 } from "@agor/core/db";
4192
+
4193
+ // src/utils/tenant-db-scope.ts
4194
+ init_runtime_tokens();
4195
+ import {
4196
+ resolveMultiTenancyConfig,
4197
+ resolveTenantContext as resolveTenantContext2,
4198
+ TenantResolutionError as TenantResolutionError2
4199
+ } from "@agor/core/config";
4200
+ import {
4201
+ enqueueTenantDatabasePostCommitCallback,
4202
+ getCurrentTenantId as getCurrentTenantId2,
4203
+ runWithoutTenantDatabaseScope,
4204
+ runWithTenantDatabaseScope as runWithTenantDatabaseScope2
4205
+ } from "@agor/core/db";
4206
+ import { NotAuthenticated as NotAuthenticated7 } from "@agor/core/feathers";
4207
+ import jwt3 from "jsonwebtoken";
4208
+ function readHeaderValue(headers, name) {
4209
+ if (!headers) return null;
4210
+ const wanted = name.toLowerCase();
4211
+ for (const [key, value] of Object.entries(headers)) {
4212
+ if (key.toLowerCase() !== wanted) continue;
4213
+ const raw = Array.isArray(value) ? value[0] : value;
4214
+ return typeof raw === "string" && raw.trim() ? raw.trim() : null;
4215
+ }
4216
+ return null;
4217
+ }
4218
+ function resolveTenantIdForDeferredScope(params) {
4219
+ const scopedParams = params;
4220
+ return scopedParams?.tenant?.tenant_id ?? getCurrentTenantId2();
4221
+ }
4222
+ function deferWithTenantDatabaseScope(db, params, work, onError) {
4223
+ const tenantId = resolveTenantIdForDeferredScope(params);
4224
+ if (!tenantId) {
4225
+ const error = new Error("Missing tenant context for deferred tenant-scoped work");
4226
+ if (onError) {
4227
+ onError(error);
4228
+ } else {
4229
+ console.error("[tenant-db-scope] Deferred tenant-scoped work skipped:", error);
4230
+ }
4231
+ return;
4232
+ }
4233
+ const schedule = () => {
4234
+ runWithoutTenantDatabaseScope(() => {
4235
+ setImmediate(() => {
4236
+ void runWithTenantDatabaseScope2(db, tenantId, work).catch((error) => {
4237
+ if (onError) {
4238
+ onError(error);
4239
+ return;
4240
+ }
4241
+ console.error("[tenant-db-scope] Deferred tenant-scoped work failed:", error);
4242
+ });
4243
+ });
4244
+ });
4245
+ };
4246
+ if (enqueueTenantDatabasePostCommitCallback(async () => schedule())) {
4247
+ return;
4248
+ }
4249
+ schedule();
4250
+ }
4251
+ function createTenantDatabaseScopeAroundHook(options) {
4252
+ const multiTenancy = resolveMultiTenancyConfig(options.config);
4253
+ const bearerPayloadFromHeaders = (headers) => {
4254
+ const authorization = readHeaderValue(headers, "authorization");
4255
+ const match = authorization?.match(/^Bearer\s+(.+)$/i);
4256
+ if (!match || !options.jwtSecret) return void 0;
4257
+ try {
4258
+ return jwt3.verify(match[1], options.jwtSecret, {
4259
+ issuer: RUNTIME_JWT_ISSUER,
4260
+ audience: RUNTIME_JWT_AUDIENCE
4261
+ });
4262
+ } catch {
4263
+ return void 0;
4264
+ }
4265
+ };
4266
+ const resolveTenantForDatabaseScope = (context) => {
4267
+ const params = context.params;
4268
+ const connectionTenant = params.connection?.tenant ?? params.connection?.data?.tenant;
4269
+ const paramsWithConnectionTenant = connectionTenant && typeof connectionTenant === "object" && "tenant_id" in connectionTenant ? { ...params, tenant: params.tenant ?? connectionTenant } : params;
4270
+ try {
4271
+ return resolveTenantContext2(multiTenancy, {
4272
+ params: paramsWithConnectionTenant,
4273
+ authPayload: paramsWithConnectionTenant.authentication?.payload ?? bearerPayloadFromHeaders(paramsWithConnectionTenant.headers),
4274
+ headers: paramsWithConnectionTenant.headers
4275
+ });
4276
+ } catch (error) {
4277
+ const inheritedTenantId = getCurrentTenantId2();
4278
+ if (error instanceof TenantResolutionError2 && inheritedTenantId) {
4279
+ return { tenant_id: inheritedTenantId, source: "explicit" };
4280
+ }
4281
+ throw error;
4282
+ }
4283
+ };
4284
+ return async (context, next) => {
4285
+ try {
4286
+ context.params.tenant = resolveTenantForDatabaseScope(context);
4287
+ } catch (error) {
4288
+ if (error instanceof TenantResolutionError2) {
4289
+ throw new NotAuthenticated7(error.message);
4290
+ }
4291
+ throw error;
4292
+ }
4293
+ await runWithTenantDatabaseScope2(options.db, context.params.tenant?.tenant_id, next);
4294
+ };
4295
+ }
4296
+
4297
+ // src/utils/session-queue-tenant-scope.ts
4298
+ function staticTenantId(config) {
4299
+ const multiTenancy = resolveMultiTenancyConfig2(config);
4300
+ return multiTenancy.mode === "static" ? multiTenancy.static_tenant_id : void 0;
4301
+ }
4302
+ function trustedTenantIdHint(options) {
4303
+ const hint = options.tenantIdHint?.trim();
4304
+ return hint || void 0;
4305
+ }
4306
+ function queueTenantParams(params, tenantId, source = "explicit") {
4307
+ const currentTenant = params?.tenant;
4308
+ return {
4309
+ ...params ?? {},
4310
+ tenant: {
4311
+ ...currentTenant,
4312
+ tenant_id: tenantId,
4313
+ source: currentTenant?.source ?? source
4314
+ }
4315
+ };
4316
+ }
4317
+ function deferWithSessionQueueTenantScope(options, work, onError) {
4318
+ const handleError = (error) => {
4319
+ if (onError) {
4320
+ onError(error);
4321
+ return;
4322
+ }
4323
+ console.error(`\u274C [Queue] ${options.label} failed:`, error);
4324
+ };
4325
+ const capturedTenantId = resolveTenantIdForDeferredScope(options.params);
4326
+ if (capturedTenantId) {
4327
+ const scopedParams2 = queueTenantParams(options.params, capturedTenantId, "explicit");
4328
+ deferWithTenantDatabaseScope(options.db, scopedParams2, () => work(scopedParams2), handleError);
4329
+ return;
4330
+ }
4331
+ const tenantIdHint = trustedTenantIdHint(options);
4332
+ if (tenantIdHint) {
4333
+ const scopedParams2 = queueTenantParams(options.params, tenantIdHint, "explicit");
4334
+ deferWithTenantDatabaseScope(options.db, scopedParams2, () => work(scopedParams2), handleError);
4335
+ return;
4336
+ }
4337
+ const configuredStaticTenantId = staticTenantId(options.config);
4338
+ if (!configuredStaticTenantId) {
4339
+ handleError(
4340
+ new Error(`${options.label} skipped for session ${options.sessionId}: missing tenant context`)
4341
+ );
4342
+ return;
4343
+ }
4344
+ const scopedParams = queueTenantParams(options.params, configuredStaticTenantId, "static");
4345
+ deferWithTenantDatabaseScope(options.db, scopedParams, () => work(scopedParams), handleError);
4346
+ }
4347
+
3936
4348
  // src/utils/session-task-state.ts
3937
4349
  import {
3938
4350
  isTerminalTaskStatus,
@@ -3980,7 +4392,7 @@ function validateRepoEnvPolicyHook() {
3980
4392
  const env = validateRepoEnvironment(item.environment);
3981
4393
  validateRepoEnvironmentLifecyclePolicy(env, mode);
3982
4394
  } catch (error) {
3983
- throw new BadRequest3(error instanceof Error ? error.message : "Invalid repo environment");
4395
+ throw new BadRequest5(error instanceof Error ? error.message : "Invalid repo environment");
3984
4396
  }
3985
4397
  }
3986
4398
  if (Object.hasOwn(item, "environment_config") && shouldValidateRepoEnvironmentPayload(item.environment_config)) {
@@ -3988,7 +4400,7 @@ function validateRepoEnvPolicyHook() {
3988
4400
  const env = wrapV1AsV2(item.environment_config);
3989
4401
  if (env) validateRepoEnvironmentLifecyclePolicy(env, mode, "legacy repo environment");
3990
4402
  } catch (error) {
3991
- throw new BadRequest3(
4403
+ throw new BadRequest5(
3992
4404
  error instanceof Error ? error.message : "Invalid legacy repo environment"
3993
4405
  );
3994
4406
  }
@@ -4030,7 +4442,7 @@ function validateBranchEnvPolicyHook() {
4030
4442
  app: item.app_url
4031
4443
  });
4032
4444
  } catch (error) {
4033
- throw new BadRequest3(error instanceof Error ? error.message : "Invalid branch environment");
4445
+ throw new BadRequest5(error instanceof Error ? error.message : "Invalid branch environment");
4034
4446
  }
4035
4447
  }
4036
4448
  return context;
@@ -4057,6 +4469,10 @@ function shouldRunSessionPostTurnHooks(session) {
4057
4469
  function shouldDrainQueueAfterSessionPostTurnPatch(session, params) {
4058
4470
  return shouldRunSessionPostTurnHooks(session) && session.ready_for_prompt === true && !isTerminalQueueProcessingSuppressed(params);
4059
4471
  }
4472
+ function getTrustedSessionTenantId(session) {
4473
+ const tenantId = session?.tenant_id;
4474
+ return typeof tenantId === "string" && tenantId.length > 0 ? tenantId : void 0;
4475
+ }
4060
4476
  async function enrichSessionFindResultWithRemoteRelationships(result, sessionsService) {
4061
4477
  if (isRemoteRelationshipsEnrichedResult(result)) return result;
4062
4478
  if (Array.isArray(result)) {
@@ -4069,6 +4485,56 @@ async function enrichSessionFindResultWithRemoteRelationships(result, sessionsSe
4069
4485
  data: await sessionsService.enrichRemoteRelationships(result.data)
4070
4486
  });
4071
4487
  }
4488
+ var TENANT_OWNED_SERVICE_PATHS = [
4489
+ "sessions",
4490
+ "sessions/:id/mcp-servers",
4491
+ "session-relationships",
4492
+ "tasks",
4493
+ "messages",
4494
+ "boards",
4495
+ "repos",
4496
+ "branches",
4497
+ "branches/:id/owners",
4498
+ "boards/:id/owners",
4499
+ "schedules",
4500
+ "users",
4501
+ "groups",
4502
+ "group-memberships",
4503
+ "branches/:id/group-grants",
4504
+ "boards/:id/group-grants",
4505
+ "app-variables",
4506
+ "mcp-servers",
4507
+ "mcp-servers/discover",
4508
+ "mcp-servers/oauth-auth-headers",
4509
+ "mcp-servers/oauth-complete",
4510
+ "mcp-servers/oauth-disconnect",
4511
+ "mcp-servers/oauth-refresh",
4512
+ "mcp-servers/oauth-start",
4513
+ "mcp-servers/oauth-status",
4514
+ "mcp-servers/test-oauth",
4515
+ "card-types",
4516
+ "cards",
4517
+ "artifacts",
4518
+ "artifact-trust-grants",
4519
+ "board-objects",
4520
+ "session-mcp-servers",
4521
+ "user-mcp-oauth-tokens",
4522
+ "board-comments",
4523
+ "gateway-channels",
4524
+ "gateway",
4525
+ "thread-session-map",
4526
+ "gateway-outbound-messages",
4527
+ "session-env-selections",
4528
+ "kb/namespaces",
4529
+ "kb/documents",
4530
+ "kb/document-edits",
4531
+ "kb/versions",
4532
+ "kb/search",
4533
+ "kb/settings",
4534
+ "kb/indexing/status",
4535
+ "kb/indexing/reindex",
4536
+ "leaderboard"
4537
+ ];
4072
4538
  function registerHooks(ctx) {
4073
4539
  const {
4074
4540
  db,
@@ -4092,6 +4558,76 @@ function registerHooks(ctx) {
4092
4558
  return void 0;
4093
4559
  }
4094
4560
  };
4561
+ const multiTenancy = resolveMultiTenancyConfig4(config);
4562
+ const tenantColumnsEnabled = resolveMultiTenancyDatabaseDialect(config) === "postgresql";
4563
+ const executionMode = resolveExecutionSecurityMode(config);
4564
+ const tenantOwnedServicePaths = TENANT_OWNED_SERVICE_PATHS;
4565
+ const stampTenantData = (data, tenantId) => {
4566
+ if (Array.isArray(data)) return data.map((item) => stampTenantData(item, tenantId));
4567
+ if (!data || typeof data !== "object") return data;
4568
+ return { ...data, tenant_id: tenantId };
4569
+ };
4570
+ const stripTenantData = (data) => {
4571
+ if (Array.isArray(data)) return data.map(stripTenantData);
4572
+ if (!data || typeof data !== "object") return data;
4573
+ const clone = { ...data };
4574
+ delete clone.tenant_id;
4575
+ return clone;
4576
+ };
4577
+ const resultBelongsToTenant = (result, tenantId) => {
4578
+ if (Array.isArray(result)) return result.every((item) => resultBelongsToTenant(item, tenantId));
4579
+ if (!result || typeof result !== "object") return true;
4580
+ const record = result;
4581
+ if (Array.isArray(record.data))
4582
+ return record.data.every((item) => resultBelongsToTenant(item, tenantId));
4583
+ if (!("tenant_id" in record)) return true;
4584
+ return record.tenant_id === tenantId;
4585
+ };
4586
+ const tenantDatabaseScopeAround = createTenantDatabaseScopeAroundHook({
4587
+ db,
4588
+ config,
4589
+ jwtSecret
4590
+ });
4591
+ const ensureTenantContext = async (context) => {
4592
+ try {
4593
+ context.params.tenant = resolveTenantContext3(multiTenancy, { params: context.params });
4594
+ return context;
4595
+ } catch (error) {
4596
+ if (error instanceof TenantResolutionError3) {
4597
+ throw new NotAuthenticated8(error.message);
4598
+ }
4599
+ throw error;
4600
+ }
4601
+ };
4602
+ const scopeTenantBefore = async (context) => {
4603
+ await ensureTenantContext(context);
4604
+ const tenantId = context.params.tenant?.tenant_id;
4605
+ if (!tenantId) return context;
4606
+ if (context.method === "create") {
4607
+ context.data = stampTenantData(context.data, tenantId);
4608
+ } else if (context.method === "update" || context.method === "patch") {
4609
+ context.data = stripTenantData(context.data);
4610
+ }
4611
+ return context;
4612
+ };
4613
+ const assertTenantAfter = async (context) => {
4614
+ const tenantId = context.params.tenant?.tenant_id;
4615
+ if (tenantId && !resultBelongsToTenant(context.result, tenantId)) {
4616
+ throw new NotAuthenticated8("Tenant isolation check failed");
4617
+ }
4618
+ return context;
4619
+ };
4620
+ const registerTenantHooks = () => {
4621
+ for (const path4 of tenantOwnedServicePaths) {
4622
+ const service = safeService(path4);
4623
+ if (!service) continue;
4624
+ service.hooks({
4625
+ around: { all: [tenantDatabaseScopeAround] },
4626
+ before: { all: [scopeTenantBefore] },
4627
+ after: { all: [assertTenantAfter] }
4628
+ });
4629
+ }
4630
+ };
4095
4631
  const realtimeAccessCache = new RealtimeAccessCache({
4096
4632
  branchRepository,
4097
4633
  sessionsRepository
@@ -4114,12 +4650,21 @@ function registerHooks(ctx) {
4114
4650
  await invalidateRealtimeBranchAccess(context.params.route?.id);
4115
4651
  return context;
4116
4652
  };
4117
- const syncBranchUnixAccess = (branchId, logPrefix) => {
4118
- if (!jwtSecret) return;
4119
- const serviceToken = createServiceToken(jwtSecret, void 0, {
4653
+ const createExecutorServiceToken = (params, scope) => {
4654
+ if (!jwtSecret) return void 0;
4655
+ return createServiceToken(jwtSecret, void 0, {
4656
+ ...serviceTokenScopeForParams(params),
4657
+ ...scope
4658
+ });
4659
+ };
4660
+ const syncBranchUnixAccess = (branchId, logPrefix, params, options) => {
4661
+ if (!executionMode.unixFsIsolationEnabled) return;
4662
+ const serviceToken = createExecutorServiceToken(params, {
4663
+ ...options?.scope,
4120
4664
  branch_id: branchId,
4121
4665
  command: "unix.sync-branch"
4122
4666
  });
4667
+ if (!serviceToken) return;
4123
4668
  spawnExecutorFireAndForget(
4124
4669
  {
4125
4670
  command: "unix.sync-branch",
@@ -4127,14 +4672,16 @@ function registerHooks(ctx) {
4127
4672
  daemonUrl: getDaemonUrl(),
4128
4673
  params: {
4129
4674
  branchId,
4130
- daemonUser: config.daemon?.unix_user
4675
+ daemonUser: config.daemon?.unix_user,
4676
+ ...options?.delete ? { delete: true } : {}
4131
4677
  }
4132
4678
  },
4133
4679
  { logPrefix }
4134
4680
  );
4135
4681
  };
4136
- const syncUnixAccessForBoardAlignedBranches = async (boardId, logPrefix) => {
4137
- if (!jwtSecret || typeof boardId !== "string" || boardId.length === 0) return;
4682
+ const syncUnixAccessForBoardAlignedBranches = async (boardId, logPrefix, params) => {
4683
+ if (!executionMode.unixFsIsolationEnabled) return;
4684
+ if (typeof boardId !== "string" || boardId.length === 0) return;
4138
4685
  const alignedBranches = await branchRepository.findBoardAlignedBranches(boardId);
4139
4686
  if (alignedBranches.length === 0) return;
4140
4687
  console.log(
@@ -4143,10 +4690,11 @@ function registerHooks(ctx) {
4143
4690
  for (const branch of alignedBranches) {
4144
4691
  await invalidateRealtimeBranchAccess(branch.branch_id);
4145
4692
  }
4146
- const serviceToken = createServiceToken(jwtSecret, void 0, {
4693
+ const serviceToken = createExecutorServiceToken(params, {
4147
4694
  board_id: boardId,
4148
4695
  command: "unix.sync-board"
4149
4696
  });
4697
+ if (!serviceToken) return;
4150
4698
  spawnExecutorFireAndForget(
4151
4699
  {
4152
4700
  command: "unix.sync-board",
@@ -4161,15 +4709,43 @@ function registerHooks(ctx) {
4161
4709
  );
4162
4710
  };
4163
4711
  const syncUnixAccessForBoardFromRoute = async (context, logPrefix) => {
4164
- await syncUnixAccessForBoardAlignedBranches(context.params.route?.id, logPrefix);
4712
+ await syncUnixAccessForBoardAlignedBranches(
4713
+ context.params.route?.id,
4714
+ logPrefix,
4715
+ context.params
4716
+ );
4165
4717
  return context;
4166
4718
  };
4167
- const syncUnixAccessForAllBranches = async (context, logPrefix) => {
4168
- if (!jwtSecret) return context;
4169
- const branches = await branchRepository.findAll({ includeArchived: false });
4170
- for (const branch of branches) {
4171
- syncBranchUnixAccess(branch.branch_id, logPrefix);
4172
- await invalidateRealtimeBranchAccess(branch.branch_id);
4719
+ const membershipGroupIdFromContext = (context) => {
4720
+ const resultGroupId = context.result?.group_id;
4721
+ if (typeof resultGroupId === "string" && resultGroupId.length > 0) {
4722
+ return resultGroupId;
4723
+ }
4724
+ const dataGroupId = context.data?.group_id;
4725
+ if (typeof dataGroupId === "string" && dataGroupId.length > 0) return dataGroupId;
4726
+ const queryGroupId = context.params.query?.group_id;
4727
+ if (typeof queryGroupId === "string" && queryGroupId.length > 0) return queryGroupId;
4728
+ const routeGroupId = context.params.route?.groupId;
4729
+ if (typeof routeGroupId === "string" && routeGroupId.length > 0) return routeGroupId;
4730
+ return void 0;
4731
+ };
4732
+ const syncUnixAccessForGroupGrantedBranches = async (context, logPrefix) => {
4733
+ if (!executionMode.unixFsIsolationEnabled) return context;
4734
+ const groupId = membershipGroupIdFromContext(context);
4735
+ if (!groupId) {
4736
+ console.warn(
4737
+ `[Unix Integration] Could not resolve group_id for ${context.path}.${context.method}; skipping group membership permission sync`
4738
+ );
4739
+ return context;
4740
+ }
4741
+ const branchIds = await branchRepository.findExplicitFsAccessBranchIdsForGroup(groupId);
4742
+ if (branchIds.length === 0) return context;
4743
+ console.log(
4744
+ `[Unix Integration] Queueing group membership permission sync for ${branchIds.length} branch(es) granted to group ${shortId5(groupId)}`
4745
+ );
4746
+ for (const branchId of branchIds) {
4747
+ syncBranchUnixAccess(branchId, logPrefix, context.params);
4748
+ await invalidateRealtimeBranchAccess(branchId);
4173
4749
  }
4174
4750
  return context;
4175
4751
  };
@@ -4185,7 +4761,7 @@ function registerHooks(ctx) {
4185
4761
  // RBAC: Scope messages.find() to sessions the caller can access.
4186
4762
  // Without this backstop, any authenticated member could list messages
4187
4763
  // across every session/branch by omitting the session_id filter.
4188
- ...branchRbacEnabled ? [scopeFindToAccessibleSessions(sessionsRepository, superadminOpts)] : []
4764
+ ...branchRbacEnabled ? [scopeFindToAccessibleSessionsSql(superadminOpts)] : []
4189
4765
  ],
4190
4766
  get: [
4191
4767
  ...branchRbacEnabled ? [
@@ -4197,7 +4773,7 @@ function registerHooks(ctx) {
4197
4773
  ] : []
4198
4774
  ],
4199
4775
  create: [
4200
- requireMinimumRole(ROLES9.MEMBER, "create messages"),
4776
+ requireMinimumRole(ROLES10.MEMBER, "create messages"),
4201
4777
  ...branchRbacEnabled ? [
4202
4778
  resolveSessionContext(),
4203
4779
  loadSession(sessionsService),
@@ -4209,7 +4785,7 @@ function registerHooks(ctx) {
4209
4785
  ] : []
4210
4786
  ],
4211
4787
  patch: [
4212
- requireMinimumRole(ROLES9.MEMBER, "update messages"),
4788
+ requireMinimumRole(ROLES10.MEMBER, "update messages"),
4213
4789
  ...branchRbacEnabled ? [
4214
4790
  resolveSessionContext(),
4215
4791
  loadSession(sessionsService),
@@ -4219,7 +4795,7 @@ function registerHooks(ctx) {
4219
4795
  ] : []
4220
4796
  ],
4221
4797
  remove: [
4222
- requireMinimumRole(ROLES9.MEMBER, "delete messages"),
4798
+ requireMinimumRole(ROLES10.MEMBER, "delete messages"),
4223
4799
  ...branchRbacEnabled ? [
4224
4800
  resolveSessionContext(),
4225
4801
  loadSession(sessionsService),
@@ -4253,141 +4829,51 @@ function registerHooks(ctx) {
4253
4829
  ]
4254
4830
  }
4255
4831
  });
4256
- const boardObjectRepository = new BoardObjectRepository2(db);
4257
4832
  safeService("board-objects")?.hooks({
4258
4833
  before: {
4259
4834
  all: [
4260
4835
  typedValidateQuery(boardObjectQueryValidator),
4261
4836
  requireAuth,
4262
- requireMinimumRole(ROLES9.MEMBER, "manage board objects")
4837
+ requireMinimumRole(ROLES10.MEMBER, "manage board objects")
4263
4838
  ],
4264
- // NOTE: We deliberately do NOT add the generic scopeFindToAccessibleBranches here.
4265
- // Board-objects may reference `branch_id` (branch cards) OR `card_id`
4266
- // (kanban cards with no branch) OR neither (zones, layout objects).
4267
- // That generic hook would filter out rows with null branch_id, breaking
4268
- // card-only boards. The RBAC find hook below uses a board-object-specific
4269
- // SQL query that preserves card/zone rows while scoping branch-bound ones.
4270
- find: [
4271
- ...branchRbacEnabled ? [
4272
- async (context) => {
4273
- if (!context.params.provider) return context;
4274
- const userId = context.params.user?.user_id;
4275
- const normalized = normalizeBoardObjectFindQuery(context.params.query);
4276
- if (!userId) {
4277
- context.result = {
4278
- total: 0,
4279
- limit: normalized.limit,
4280
- skip: normalized.skip,
4281
- data: []
4282
- };
4283
- return context;
4284
- }
4285
- const [total, data] = await Promise.all([
4286
- boardObjectRepository.countVisibleToUser(userId, normalized.filters),
4287
- boardObjectRepository.findVisibleToUser(
4288
- userId,
4289
- normalized.filters,
4290
- normalized.pagination
4291
- )
4292
- ]);
4293
- context.result = {
4294
- total,
4295
- limit: normalized.limit,
4296
- skip: normalized.skip,
4297
- data
4298
- };
4299
- context.params._boardObjectsRbacScoped = true;
4300
- return context;
4301
- }
4302
- ] : []
4303
- ]
4304
- },
4305
- after: {
4306
- find: [
4307
- ...branchRbacEnabled ? [
4308
- // Filter board-objects based on branch access permissions
4309
- async (context) => {
4310
- if (context.params._boardObjectsRbacScoped) {
4311
- return context;
4312
- }
4313
- if (!context.params.provider) {
4314
- return context;
4315
- }
4316
- const userId = context.params.user?.user_id;
4317
- if (!userId) {
4318
- context.result = {
4319
- total: 0,
4320
- limit: context.result?.limit ?? 0,
4321
- skip: context.result?.skip ?? 0,
4322
- data: []
4323
- };
4324
- return context;
4325
- }
4326
- const boardObjects = context.result?.data ?? context.result ?? [];
4327
- const authorizedBoardObjects = [];
4328
- for (const boardObject of boardObjects) {
4329
- if (boardObject.branch_id) {
4330
- const branch = await branchRepository.findById(boardObject.branch_id);
4331
- if (!branch) {
4332
- continue;
4333
- }
4334
- const effectivePermission = await branchRepository.resolveUserPermission(
4335
- branch,
4336
- userId
4337
- );
4338
- const hasAccess = PERMISSION_RANK[effectivePermission] >= PERMISSION_RANK.view;
4339
- if (hasAccess) {
4340
- authorizedBoardObjects.push(boardObject);
4341
- }
4342
- } else if (boardObject.card_id) {
4343
- authorizedBoardObjects.push(boardObject);
4344
- } else {
4345
- authorizedBoardObjects.push(boardObject);
4346
- }
4347
- }
4348
- if (context.result?.data) {
4349
- context.result.data = authorizedBoardObjects;
4350
- context.result.total = authorizedBoardObjects.length;
4351
- } else {
4352
- context.result = authorizedBoardObjects;
4353
- }
4354
- return context;
4355
- }
4356
- ] : []
4357
- ]
4839
+ // Board-objects may reference a branch or may be loose board/card/layout
4840
+ // rows. The service composes this marker into an object-specific SQL
4841
+ // predicate: branch-bound rows require branch access; loose rows require
4842
+ // board visibility.
4843
+ find: [...branchRbacEnabled ? [scopeFindToAccessibleBoardsSql(superadminOpts)] : []]
4358
4844
  }
4359
4845
  });
4360
4846
  safeService("card-types")?.hooks({
4361
4847
  before: {
4362
4848
  all: [requireAuth],
4363
- create: [requireMinimumRole(ROLES9.MEMBER, "create card types")],
4364
- patch: [requireMinimumRole(ROLES9.MEMBER, "update card types")],
4365
- remove: [requireMinimumRole(ROLES9.MEMBER, "delete card types")]
4849
+ create: [requireMinimumRole(ROLES10.MEMBER, "create card types")],
4850
+ patch: [requireMinimumRole(ROLES10.MEMBER, "update card types")],
4851
+ remove: [requireMinimumRole(ROLES10.MEMBER, "delete card types")]
4366
4852
  }
4367
4853
  });
4368
4854
  safeService("cards")?.hooks({
4369
4855
  before: {
4370
4856
  all: [requireAuth],
4371
- create: [requireMinimumRole(ROLES9.MEMBER, "create cards"), injectCreatedBy()],
4372
- patch: [requireMinimumRole(ROLES9.MEMBER, "update cards")],
4373
- remove: [requireMinimumRole(ROLES9.MEMBER, "delete cards")]
4857
+ create: [requireMinimumRole(ROLES10.MEMBER, "create cards"), injectCreatedBy()],
4858
+ patch: [requireMinimumRole(ROLES10.MEMBER, "update cards")],
4859
+ remove: [requireMinimumRole(ROLES10.MEMBER, "delete cards")]
4374
4860
  }
4375
4861
  });
4376
4862
  const ensureArtifactOwnerOrAdmin = () => async (context) => {
4377
4863
  if (!context.params.provider) return context;
4378
4864
  const user = context.params?.user;
4379
- if (!user) throw new NotAuthenticated7("Authentication required");
4865
+ if (!user) throw new NotAuthenticated8("Authentication required");
4380
4866
  if (user._isServiceAccount) return context;
4381
- if (hasMinimumRole8(user.role, ROLES9.ADMIN)) return context;
4867
+ if (hasMinimumRole9(user.role, ROLES10.ADMIN)) return context;
4382
4868
  const artifactId = context.id;
4383
4869
  if (artifactId === void 0 || artifactId === null) return context;
4384
4870
  const artifactRepo = new ArtifactRepository(db);
4385
4871
  const artifact = await artifactRepo.findById(String(artifactId));
4386
4872
  if (!artifact) {
4387
- throw new Forbidden8(`Artifact ${artifactId} not found or not accessible`);
4873
+ throw new Forbidden9(`Artifact ${artifactId} not found or not accessible`);
4388
4874
  }
4389
4875
  if (artifact.created_by && artifact.created_by === user.user_id) return context;
4390
- throw new Forbidden8(
4876
+ throw new Forbidden9(
4391
4877
  "Only the artifact's creator or an admin may modify it. Use agor_artifacts_publish to create your own copy."
4392
4878
  );
4393
4879
  };
@@ -4396,15 +4882,14 @@ function registerHooks(ctx) {
4396
4882
  all: [requireAuth],
4397
4883
  find: [
4398
4884
  // RBAC: Artifacts carry a `branch_id` (nullable — survives branch deletion).
4399
- // Scope find() to the branches the caller can access. Rows with null
4400
- // branch_id (orphaned artifacts) will be excluded by the $in filter,
4401
- // which is the safe default orphans can only be surfaced via explicit
4402
- // board-scoped queries.
4403
- ...branchRbacEnabled ? [scopeFindToAccessibleBranches(branchRepository, superadminOpts)] : []
4885
+ // Scope find() to the branches the caller can access. The service pushes
4886
+ // this into SQL as a correlated visibility predicate rather than
4887
+ // preloading ids and injecting `branch_id IN (...)`.
4888
+ ...branchRbacEnabled ? [scopeFindToAccessibleBranchesSql(superadminOpts)] : []
4404
4889
  ],
4405
- create: [requireMinimumRole(ROLES9.MEMBER, "create artifacts"), injectCreatedBy()],
4406
- patch: [requireMinimumRole(ROLES9.MEMBER, "update artifacts"), ensureArtifactOwnerOrAdmin()],
4407
- remove: [requireMinimumRole(ROLES9.MEMBER, "delete artifacts"), ensureArtifactOwnerOrAdmin()]
4890
+ create: [requireMinimumRole(ROLES10.MEMBER, "create artifacts"), injectCreatedBy()],
4891
+ patch: [requireMinimumRole(ROLES10.MEMBER, "update artifacts"), ensureArtifactOwnerOrAdmin()],
4892
+ remove: [requireMinimumRole(ROLES10.MEMBER, "delete artifacts"), ensureArtifactOwnerOrAdmin()]
4408
4893
  }
4409
4894
  });
4410
4895
  if (svcEnabled("artifacts")) {
@@ -4419,7 +4904,7 @@ function registerHooks(ctx) {
4419
4904
  return artifactsService.getPayload(artifactId, _params.user?.user_id);
4420
4905
  }
4421
4906
  },
4422
- { find: { role: ROLES9.VIEWER, action: "get artifact payload" } },
4907
+ { find: { role: ROLES10.VIEWER, action: "get artifact payload" } },
4423
4908
  requireAuth
4424
4909
  );
4425
4910
  registerAuthenticatedRoute(
@@ -4446,7 +4931,7 @@ function registerHooks(ctx) {
4446
4931
  }
4447
4932
  },
4448
4933
  {
4449
- create: { role: ROLES9.MEMBER, action: "post artifact console logs" }
4934
+ create: { role: ROLES10.MEMBER, action: "post artifact console logs" }
4450
4935
  },
4451
4936
  requireAuth
4452
4937
  );
@@ -4475,7 +4960,7 @@ function registerHooks(ctx) {
4475
4960
  }
4476
4961
  },
4477
4962
  {
4478
- create: { role: ROLES9.MEMBER, action: "post artifact sandpack error" }
4963
+ create: { role: ROLES10.MEMBER, action: "post artifact sandpack error" }
4479
4964
  },
4480
4965
  requireAuth
4481
4966
  );
@@ -4516,7 +5001,7 @@ function registerHooks(ctx) {
4516
5001
  }
4517
5002
  },
4518
5003
  {
4519
- create: { role: ROLES9.MEMBER, action: "post artifact runtime response" }
5004
+ create: { role: ROLES10.MEMBER, action: "post artifact runtime response" }
4520
5005
  },
4521
5006
  requireAuth
4522
5007
  );
@@ -4538,7 +5023,7 @@ function registerHooks(ctx) {
4538
5023
  }
4539
5024
  },
4540
5025
  {
4541
- create: { role: ROLES9.MEMBER, action: "create artifact trust grant" }
5026
+ create: { role: ROLES10.MEMBER, action: "create artifact trust grant" }
4542
5027
  },
4543
5028
  requireAuth
4544
5029
  );
@@ -4562,8 +5047,8 @@ function registerHooks(ctx) {
4562
5047
  }
4563
5048
  },
4564
5049
  {
4565
- find: { role: ROLES9.VIEWER, action: "list artifact trust grants" },
4566
- remove: { role: ROLES9.MEMBER, action: "revoke artifact trust grant" }
5050
+ find: { role: ROLES10.VIEWER, action: "list artifact trust grants" },
5051
+ remove: { role: ROLES10.MEMBER, action: "revoke artifact trust grant" }
4567
5052
  },
4568
5053
  requireAuth
4569
5054
  );
@@ -4571,9 +5056,15 @@ function registerHooks(ctx) {
4571
5056
  safeService("board-comments")?.hooks({
4572
5057
  before: {
4573
5058
  all: [typedValidateQuery(boardCommentQueryValidator), requireAuth],
4574
- create: [requireMinimumRole(ROLES9.MEMBER, "create board comments"), injectCreatedBy()],
4575
- patch: [requireMinimumRole(ROLES9.MEMBER, "update board comments")],
4576
- remove: [requireMinimumRole(ROLES9.MEMBER, "delete board comments")]
5059
+ find: [
5060
+ // Board comments inherit board visibility for pure board/spatial
5061
+ // comments and branch/session/task/message visibility for attached
5062
+ // comments. The service pushes the marker into SQL.
5063
+ ...branchRbacEnabled ? [scopeFindToAccessibleBoardsSql(superadminOpts)] : []
5064
+ ],
5065
+ create: [requireMinimumRole(ROLES10.MEMBER, "create board comments"), injectCreatedBy()],
5066
+ patch: [requireMinimumRole(ROLES10.MEMBER, "update board comments")],
5067
+ remove: [requireMinimumRole(ROLES10.MEMBER, "delete board comments")]
4577
5068
  }
4578
5069
  });
4579
5070
  app.service("repos").hooks({
@@ -4581,24 +5072,24 @@ function registerHooks(ctx) {
4581
5072
  all: [
4582
5073
  typedValidateQuery(repoQueryValidator),
4583
5074
  requireAuth,
4584
- requireMinimumRole(ROLES9.MEMBER, "access repositories")
5075
+ requireMinimumRole(ROLES10.MEMBER, "access repositories")
4585
5076
  ],
4586
5077
  create: [
4587
- requireMinimumRole(ROLES9.MEMBER, "create repositories"),
5078
+ requireMinimumRole(ROLES10.MEMBER, "create repositories"),
4588
5079
  requireAdminForEnvConfig(),
4589
5080
  validateRepoEnvPolicyHook()
4590
5081
  ],
4591
5082
  update: [
4592
- requireMinimumRole(ROLES9.MEMBER, "update repositories"),
5083
+ requireMinimumRole(ROLES10.MEMBER, "update repositories"),
4593
5084
  requireAdminForEnvConfig(),
4594
5085
  validateRepoEnvPolicyHook()
4595
5086
  ],
4596
5087
  patch: [
4597
- requireMinimumRole(ROLES9.MEMBER, "update repositories"),
5088
+ requireMinimumRole(ROLES10.MEMBER, "update repositories"),
4598
5089
  requireAdminForEnvConfig(),
4599
5090
  validateRepoEnvPolicyHook()
4600
5091
  ],
4601
- remove: [requireMinimumRole(ROLES9.MEMBER, "delete repositories")]
5092
+ remove: [requireMinimumRole(ROLES10.MEMBER, "delete repositories")]
4602
5093
  },
4603
5094
  after: {
4604
5095
  patch: [realignRepoOriginAfterPatchHook()]
@@ -4610,12 +5101,12 @@ function registerHooks(ctx) {
4610
5101
  typedValidateQuery(branchQueryValidator),
4611
5102
  requireAuth,
4612
5103
  executorRuntimeScopeGuard(),
4613
- requireMinimumRole(ROLES9.MEMBER, "access branches")
5104
+ requireMinimumRole(ROLES10.MEMBER, "access branches")
4614
5105
  ],
4615
5106
  find: [
4616
- // RBAC: compose an accessible branch_id filter and let BranchesService.find()
4617
- // handle service-level filters/enrichment (including virtual zone_id).
4618
- ...branchRbacEnabled ? [scopeFindToAccessibleBranches(branchRepository, superadminOpts)] : []
5107
+ // RBAC: mark external regular-user finds for BranchesService to compose
5108
+ // the shared branch visibility predicate directly into its SQL read.
5109
+ ...branchRbacEnabled ? [scopeFindToAccessibleBranchesSql(superadminOpts)] : []
4619
5110
  ],
4620
5111
  get: [
4621
5112
  ...branchRbacEnabled ? [
@@ -4625,13 +5116,13 @@ function registerHooks(ctx) {
4625
5116
  ] : []
4626
5117
  ],
4627
5118
  create: [
4628
- requireMinimumRole(ROLES9.MEMBER, "create branches"),
5119
+ requireMinimumRole(ROLES10.MEMBER, "create branches"),
4629
5120
  requireAdminForEnvConfig(),
4630
5121
  validateBranchEnvPolicyHook(),
4631
5122
  injectCreatedBy()
4632
5123
  ],
4633
5124
  update: [
4634
- requireMinimumRole(ROLES9.MEMBER, "update branches"),
5125
+ requireMinimumRole(ROLES10.MEMBER, "update branches"),
4635
5126
  requireAdminForEnvConfig(),
4636
5127
  validateBranchEnvPolicyHook()
4637
5128
  ],
@@ -4643,13 +5134,13 @@ function registerHooks(ctx) {
4643
5134
  ensureBranchPermission("all", "update branches", superadminOpts)
4644
5135
  // Require 'all' permission to update
4645
5136
  ] : [],
4646
- // Capture previous others_fs_access for comparison in after hook
4647
- ...branchRbacEnabled ? [
5137
+ // Capture previous others_fs_access for comparison in after Unix sync hook.
5138
+ ...executionMode.unixFsIsolationEnabled ? [
4648
5139
  async (context) => {
4649
5140
  const patchData = context.data;
4650
5141
  const params = context.params;
4651
5142
  if (Object.hasOwn(patchData, "others_fs_access") && !params._skipUnixSync) {
4652
- const branch = await context.service.get(context.id);
5143
+ const branch = await context.service.get(context.id, context.params);
4653
5144
  params._previousOthersFsAccess = branch.others_fs_access;
4654
5145
  }
4655
5146
  return context;
@@ -4684,7 +5175,7 @@ function registerHooks(ctx) {
4684
5175
  ],
4685
5176
  patch: [
4686
5177
  invalidateRealtimeBranchFromResult,
4687
- ...branchRbacEnabled ? [
5178
+ ...executionMode.unixFsIsolationEnabled ? [
4688
5179
  async (context) => {
4689
5180
  const params = context.params;
4690
5181
  if (params._skipUnixSync) {
@@ -4708,56 +5199,29 @@ function registerHooks(ctx) {
4708
5199
  );
4709
5200
  return context;
4710
5201
  }
4711
- if (jwtSecret) {
4712
- console.log(
4713
- `[Unix Integration] Syncing permissions for branch ${shortId5(branch.branch_id)} (others_fs_access: ${previousValue} -> ${branch.others_fs_access})`
4714
- );
4715
- const serviceToken = createServiceToken(jwtSecret, void 0, {
4716
- branch_id: branch.branch_id,
4717
- command: "unix.sync-branch"
4718
- });
4719
- spawnExecutorFireAndForget(
4720
- {
4721
- command: "unix.sync-branch",
4722
- sessionToken: serviceToken,
4723
- daemonUrl: getDaemonUrl(),
4724
- params: {
4725
- branchId: branch.branch_id,
4726
- daemonUser: config.daemon?.unix_user
4727
- }
4728
- },
4729
- { logPrefix: "[Executor/branch.patch]" }
4730
- );
4731
- }
5202
+ console.log(
5203
+ `[Unix Integration] Syncing permissions for branch ${shortId5(branch.branch_id)} (others_fs_access: ${previousValue} -> ${branch.others_fs_access})`
5204
+ );
5205
+ syncBranchUnixAccess(
5206
+ branch.branch_id,
5207
+ "[Executor/branch.patch]",
5208
+ context.params
5209
+ );
4732
5210
  return context;
4733
5211
  }
4734
5212
  ] : []
4735
5213
  ],
4736
5214
  remove: [
4737
5215
  invalidateRealtimeBranchFromResult,
4738
- ...branchRbacEnabled ? [
5216
+ ...executionMode.unixFsIsolationEnabled ? [
4739
5217
  async (context) => {
4740
5218
  const branchId = context.id;
4741
- if (jwtSecret) {
4742
- const serviceToken = createServiceToken(jwtSecret, void 0, {
4743
- branch_id: branchId,
4744
- command: "unix.sync-branch"
4745
- });
4746
- spawnExecutorFireAndForget(
4747
- {
4748
- command: "unix.sync-branch",
4749
- sessionToken: serviceToken,
4750
- daemonUrl: getDaemonUrl(),
4751
- params: {
4752
- branchId,
4753
- daemonUser: config.daemon?.unix_user,
4754
- delete: true
4755
- // Signal to delete the group instead of syncing
4756
- }
4757
- },
4758
- { logPrefix: "[Executor/branch.remove]" }
4759
- );
4760
- }
5219
+ syncBranchUnixAccess(
5220
+ branchId,
5221
+ "[Executor/branch.remove]",
5222
+ context.params,
5223
+ { delete: true }
5224
+ );
4761
5225
  return context;
4762
5226
  }
4763
5227
  ] : []
@@ -4767,28 +5231,28 @@ function registerHooks(ctx) {
4767
5231
  safeService("kb/namespaces")?.hooks({
4768
5232
  before: {
4769
5233
  all: [requireAuth],
4770
- create: [requireMinimumRole(ROLES9.MEMBER, "create knowledge namespaces")],
4771
- patch: [requireMinimumRole(ROLES9.MEMBER, "update knowledge namespaces")],
4772
- update: [requireMinimumRole(ROLES9.MEMBER, "update knowledge namespaces")],
4773
- remove: [requireMinimumRole(ROLES9.MEMBER, "delete knowledge namespaces")],
4774
- saveWithAcl: [requireMinimumRole(ROLES9.MEMBER, "save knowledge namespace permissions")],
4775
- listAcl: [requireMinimumRole(ROLES9.MEMBER, "manage knowledge namespace permissions")],
4776
- setAcl: [requireMinimumRole(ROLES9.MEMBER, "manage knowledge namespace permissions")],
4777
- removeAcl: [requireMinimumRole(ROLES9.MEMBER, "manage knowledge namespace permissions")]
5234
+ create: [requireMinimumRole(ROLES10.MEMBER, "create knowledge namespaces")],
5235
+ patch: [requireMinimumRole(ROLES10.MEMBER, "update knowledge namespaces")],
5236
+ update: [requireMinimumRole(ROLES10.MEMBER, "update knowledge namespaces")],
5237
+ remove: [requireMinimumRole(ROLES10.MEMBER, "delete knowledge namespaces")],
5238
+ saveWithAcl: [requireMinimumRole(ROLES10.MEMBER, "save knowledge namespace permissions")],
5239
+ listAcl: [requireMinimumRole(ROLES10.MEMBER, "manage knowledge namespace permissions")],
5240
+ setAcl: [requireMinimumRole(ROLES10.MEMBER, "manage knowledge namespace permissions")],
5241
+ removeAcl: [requireMinimumRole(ROLES10.MEMBER, "manage knowledge namespace permissions")]
4778
5242
  }
4779
5243
  });
4780
5244
  safeService("kb/documents")?.hooks({
4781
5245
  before: {
4782
5246
  all: [requireAuth],
4783
- create: [requireMinimumRole(ROLES9.MEMBER, "create knowledge documents")],
4784
- patch: [requireMinimumRole(ROLES9.MEMBER, "update knowledge documents")],
4785
- update: [requireMinimumRole(ROLES9.MEMBER, "update knowledge documents")],
4786
- remove: [requireMinimumRole(ROLES9.MEMBER, "delete knowledge documents")]
5247
+ create: [requireMinimumRole(ROLES10.MEMBER, "create knowledge documents")],
5248
+ patch: [requireMinimumRole(ROLES10.MEMBER, "update knowledge documents")],
5249
+ update: [requireMinimumRole(ROLES10.MEMBER, "update knowledge documents")],
5250
+ remove: [requireMinimumRole(ROLES10.MEMBER, "delete knowledge documents")]
4787
5251
  }
4788
5252
  });
4789
5253
  safeService("kb/document-edits")?.hooks({
4790
5254
  before: {
4791
- all: [requireAuth, requireMinimumRole(ROLES9.MEMBER, "edit knowledge documents")]
5255
+ all: [requireAuth, requireMinimumRole(ROLES10.MEMBER, "edit knowledge documents")]
4792
5256
  }
4793
5257
  });
4794
5258
  safeService("kb/versions")?.hooks({
@@ -4803,29 +5267,35 @@ function registerHooks(ctx) {
4803
5267
  });
4804
5268
  safeService("kb/settings")?.hooks({
4805
5269
  before: {
4806
- all: [requireAuth, requireMinimumRole(ROLES9.ADMIN, "configure Knowledge semantic search")]
5270
+ all: [requireAuth, requireMinimumRole(ROLES10.ADMIN, "configure Knowledge semantic search")]
4807
5271
  }
4808
5272
  });
4809
5273
  safeService("kb/indexing/status")?.hooks({
4810
5274
  before: {
4811
- all: [requireAuth, requireMinimumRole(ROLES9.ADMIN, "view Knowledge indexing status")]
5275
+ all: [requireAuth, requireMinimumRole(ROLES10.ADMIN, "view Knowledge indexing status")]
4812
5276
  }
4813
5277
  });
4814
5278
  safeService("kb/indexing/reindex")?.hooks({
4815
5279
  before: {
4816
- all: [requireAuth, requireMinimumRole(ROLES9.ADMIN, "reindex Knowledge embeddings")]
5280
+ all: [requireAuth, requireMinimumRole(ROLES10.ADMIN, "reindex Knowledge embeddings")]
4817
5281
  }
4818
5282
  });
4819
5283
  safeService("kb/graph")?.hooks?.({
4820
5284
  before: {
4821
5285
  all: [requireAuth],
4822
- create: [requireMinimumRole(ROLES9.MEMBER, "link knowledge graph nodes")],
4823
- link: [requireMinimumRole(ROLES9.MEMBER, "link knowledge graph nodes")]
5286
+ create: [requireMinimumRole(ROLES10.MEMBER, "link knowledge graph nodes")],
5287
+ link: [requireMinimumRole(ROLES10.MEMBER, "link knowledge graph nodes")]
4824
5288
  }
4825
5289
  });
4826
5290
  const injectPerUserOAuthTokens = async (context) => {
4827
5291
  const queryForUserId = context.params?.query?.forUserId;
4828
- const userId = context.params?.user?.user_id || queryForUserId;
5292
+ const authPayloadType = context.params?.authentication?.payload?.type;
5293
+ const userId = resolveForUserIdWithGate({
5294
+ queryForUserId,
5295
+ isServiceAccount: context.params?.user?._isServiceAccount,
5296
+ authPayloadType,
5297
+ callerUserId: context.params?.user?.user_id
5298
+ });
4829
5299
  if (!userId) {
4830
5300
  return context;
4831
5301
  }
@@ -4908,9 +5378,9 @@ function registerHooks(ctx) {
4908
5378
  safeService("mcp-servers")?.hooks({
4909
5379
  before: {
4910
5380
  all: [typedValidateQuery(mcpServerQueryValidator), requireAuth],
4911
- create: [requireMinimumRole(ROLES9.ADMIN, "create MCP servers")],
4912
- patch: [requireMinimumRole(ROLES9.ADMIN, "update MCP servers")],
4913
- remove: [requireMinimumRole(ROLES9.ADMIN, "delete MCP servers")]
5381
+ create: [requireMinimumRole(ROLES10.ADMIN, "create MCP servers")],
5382
+ patch: [requireMinimumRole(ROLES10.ADMIN, "update MCP servers")],
5383
+ remove: [requireMinimumRole(ROLES10.ADMIN, "delete MCP servers")]
4914
5384
  },
4915
5385
  after: {
4916
5386
  find: [injectPerUserOAuthTokens, redactMCPServerSecretFields],
@@ -4924,9 +5394,9 @@ function registerHooks(ctx) {
4924
5394
  before: {
4925
5395
  all: [requireAuth],
4926
5396
  find: [
4927
- requireMinimumRole(ROLES9.MEMBER, "list session MCP servers"),
5397
+ requireMinimumRole(ROLES10.MEMBER, "list session MCP servers"),
4928
5398
  // RBAC: Scope to sessions the caller can access.
4929
- ...branchRbacEnabled ? [scopeFindToAccessibleSessions(sessionsRepository, superadminOpts)] : []
5399
+ ...branchRbacEnabled ? [scopeFindToAccessibleSessionsSql(superadminOpts)] : []
4930
5400
  ]
4931
5401
  },
4932
5402
  after: {
@@ -4937,9 +5407,9 @@ function registerHooks(ctx) {
4937
5407
  before: {
4938
5408
  all: [requireAuth],
4939
5409
  find: [
4940
- requireMinimumRole(ROLES9.MEMBER, "list session env selections"),
4941
- // RBAC: Scope to sessions the caller can access.
4942
- ...branchRbacEnabled ? [scopeFindToAccessibleSessions(sessionsRepository, superadminOpts)] : []
5410
+ requireMinimumRole(ROLES10.MEMBER, "list session env selections")
5411
+ // This top-level service is event-only and always returns []; do not
5412
+ // run RBAC preloads for an intentionally empty result set.
4943
5413
  ]
4944
5414
  }
4945
5415
  });
@@ -4970,7 +5440,7 @@ function registerHooks(ctx) {
4970
5440
  before: {
4971
5441
  all: [requireAuth],
4972
5442
  create: [
4973
- requireMinimumRole(ROLES9.ADMIN, "create gateway channels"),
5443
+ requireMinimumRole(ROLES10.ADMIN, "create gateway channels"),
4974
5444
  injectCreatedBy(),
4975
5445
  // Encrypt env var values at rest (same pattern as user env vars / API keys)
4976
5446
  async (context) => {
@@ -4988,7 +5458,7 @@ function registerHooks(ctx) {
4988
5458
  }
4989
5459
  ],
4990
5460
  patch: [
4991
- requireMinimumRole(ROLES9.ADMIN, "update gateway channels"),
5461
+ requireMinimumRole(ROLES10.ADMIN, "update gateway channels"),
4992
5462
  // Resolve redacted env var sentinel values ('••••••••') back to real
4993
5463
  // values from the database. Uses the repository directly to bypass
4994
5464
  // the after-hook redaction that the service layer applies.
@@ -5000,6 +5470,7 @@ function registerHooks(ctx) {
5000
5470
  async (context) => {
5001
5471
  const data = context.data;
5002
5472
  if (!data || !context.id) return context;
5473
+ if (data.agentic_config === null) return context;
5003
5474
  let ac = data.agentic_config;
5004
5475
  const hadAgenticConfigInPatch = ac !== void 0;
5005
5476
  const ensureAc = () => {
@@ -5009,12 +5480,12 @@ function registerHooks(ctx) {
5009
5480
  }
5010
5481
  return ac;
5011
5482
  };
5012
- const SENTINEL = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
5483
+ const SENTINEL = GATEWAY_REDACTED_SENTINEL;
5013
5484
  const incomingVars = ac?.envVars;
5014
5485
  if (incomingVars === void 0) {
5015
5486
  try {
5016
- const { GatewayChannelRepository } = await import("@agor/core/db");
5017
- const channelRepo = new GatewayChannelRepository(db);
5487
+ const { GatewayChannelRepository: GatewayChannelRepository2 } = await import("@agor/core/db");
5488
+ const channelRepo = new GatewayChannelRepository2(db);
5018
5489
  const existing = await channelRepo.findById(String(context.id));
5019
5490
  if (!hadAgenticConfigInPatch && existing?.agentic_config) {
5020
5491
  ac = { ...existing.agentic_config };
@@ -5034,8 +5505,8 @@ function registerHooks(ctx) {
5034
5505
  return context;
5035
5506
  }
5036
5507
  try {
5037
- const { GatewayChannelRepository } = await import("@agor/core/db");
5038
- const channelRepo = new GatewayChannelRepository(db);
5508
+ const { GatewayChannelRepository: GatewayChannelRepository2 } = await import("@agor/core/db");
5509
+ const channelRepo = new GatewayChannelRepository2(db);
5039
5510
  const existing = await channelRepo.findById(String(context.id));
5040
5511
  const existingVars = existing?.agentic_config?.envVars ?? [];
5041
5512
  const existingByKey = new Map(existingVars.map((v) => [v.key, v.value]));
@@ -5046,14 +5517,14 @@ function registerHooks(ctx) {
5046
5517
  return v;
5047
5518
  });
5048
5519
  } catch (error) {
5049
- throw new BadRequest3(
5520
+ throw new BadRequest5(
5050
5521
  `Failed to resolve redacted gateway env vars: ${error instanceof Error ? error.message : String(error)}`
5051
5522
  );
5052
5523
  }
5053
5524
  return context;
5054
5525
  }
5055
5526
  ],
5056
- remove: [requireMinimumRole(ROLES9.ADMIN, "delete gateway channels")]
5527
+ remove: [requireMinimumRole(ROLES10.ADMIN, "delete gateway channels")]
5057
5528
  },
5058
5529
  after: {
5059
5530
  all: [
@@ -5062,15 +5533,9 @@ function registerHooks(ctx) {
5062
5533
  const redact = (channel) => {
5063
5534
  if (channel?.config && typeof channel.config === "object") {
5064
5535
  const config2 = { ...channel.config };
5065
- for (const field of [
5066
- "bot_token",
5067
- "app_token",
5068
- "signing_secret",
5069
- "private_key",
5070
- "webhook_secret"
5071
- ]) {
5536
+ for (const field of GATEWAY_SENSITIVE_CONFIG_FIELDS) {
5072
5537
  if (config2[field]) {
5073
- config2[field] = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
5538
+ config2[field] = GATEWAY_REDACTED_SENTINEL;
5074
5539
  }
5075
5540
  }
5076
5541
  channel.config = config2;
@@ -5078,7 +5543,11 @@ function registerHooks(ctx) {
5078
5543
  if (channel?.agentic_config && typeof channel.agentic_config === "object") {
5079
5544
  const ac = channel.agentic_config;
5080
5545
  if (Array.isArray(ac.envVars)) {
5081
- ac.envVars = ac.envVars.map((v) => ({ key: v.key, value: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", forceOverride: v.forceOverride }));
5546
+ ac.envVars = ac.envVars.map((v) => ({
5547
+ key: v.key,
5548
+ value: GATEWAY_REDACTED_SENTINEL,
5549
+ forceOverride: v.forceOverride
5550
+ }));
5082
5551
  }
5083
5552
  }
5084
5553
  };
@@ -5100,12 +5569,17 @@ function registerHooks(ctx) {
5100
5569
  all: [requireAuth]
5101
5570
  }
5102
5571
  });
5572
+ safeService("admin/local-actions")?.hooks({
5573
+ before: {
5574
+ create: [requireAuth, requireMinimumRole(ROLES10.ADMIN, "run local admin actions")]
5575
+ }
5576
+ });
5103
5577
  app.service("config").hooks({
5104
5578
  before: {
5105
5579
  all: [requireAuth],
5106
- find: [requireMinimumRole(ROLES9.ADMIN, "view configuration")],
5107
- get: [requireMinimumRole(ROLES9.ADMIN, "view configuration")],
5108
- patch: [requireMinimumRole(ROLES9.ADMIN, "update configuration")]
5580
+ find: [requireMinimumRole(ROLES10.ADMIN, "view configuration")],
5581
+ get: [requireMinimumRole(ROLES10.ADMIN, "view configuration")],
5582
+ patch: [requireMinimumRole(ROLES10.ADMIN, "update configuration")]
5109
5583
  }
5110
5584
  });
5111
5585
  safeService("context")?.hooks({
@@ -5117,7 +5591,7 @@ function registerHooks(ctx) {
5117
5591
  before: {
5118
5592
  all: [
5119
5593
  requireAuth,
5120
- requireMinimumRole(ROLES9.MEMBER, "search files"),
5594
+ requireMinimumRole(ROLES10.MEMBER, "search files"),
5121
5595
  // RBAC: files service takes a sessionId query param and returns files
5122
5596
  // from that session's branch. Verify the caller can at least 'view'
5123
5597
  // that branch before running git ls-files. If sessionId is missing
@@ -5144,7 +5618,7 @@ function registerHooks(ctx) {
5144
5618
  before: {
5145
5619
  all: [
5146
5620
  requireAuth,
5147
- requireMinimumRole(ROLES9.MEMBER, "read files"),
5621
+ requireMinimumRole(ROLES10.MEMBER, "read files"),
5148
5622
  ...branchRbacEnabled ? [loadBranch(branchRepository, "branch_id"), ensureCanView(superadminOpts)] : []
5149
5623
  ]
5150
5624
  }
@@ -5156,13 +5630,13 @@ function registerHooks(ctx) {
5156
5630
  requireAuth,
5157
5631
  (context) => {
5158
5632
  if (!webTerminalEnabled) {
5159
- throw new Forbidden8(
5633
+ throw new Forbidden9(
5160
5634
  "Web terminal is disabled on this instance. Ask an administrator to unset or enable execution.allow_web_terminal in the daemon config."
5161
5635
  );
5162
5636
  }
5163
5637
  return context;
5164
5638
  },
5165
- requireMinimumRole(ROLES9.MEMBER, "access terminals")
5639
+ requireMinimumRole(ROLES10.MEMBER, "access terminals")
5166
5640
  ]
5167
5641
  }
5168
5642
  });
@@ -5178,11 +5652,11 @@ function registerHooks(ctx) {
5178
5652
  after: {
5179
5653
  create: [
5180
5654
  clearRealtimeBranchVisibility,
5181
- (context) => syncUnixAccessForAllBranches(context, "[Executor/group-memberships.create]")
5655
+ (context) => syncUnixAccessForGroupGrantedBranches(context, "[Executor/group-memberships.create]")
5182
5656
  ],
5183
5657
  remove: [
5184
5658
  clearRealtimeBranchVisibility,
5185
- (context) => syncUnixAccessForAllBranches(context, "[Executor/group-memberships.remove]")
5659
+ (context) => syncUnixAccessForGroupGrantedBranches(context, "[Executor/group-memberships.remove]")
5186
5660
  ]
5187
5661
  }
5188
5662
  });
@@ -5199,7 +5673,11 @@ function registerHooks(ctx) {
5199
5673
  (context) => {
5200
5674
  const branchId = context.params.route?.id;
5201
5675
  if (typeof branchId === "string") {
5202
- syncBranchUnixAccess(branchId, "[Executor/branch-group-grants.create]");
5676
+ syncBranchUnixAccess(
5677
+ branchId,
5678
+ "[Executor/branch-group-grants.create]",
5679
+ context.params
5680
+ );
5203
5681
  }
5204
5682
  return context;
5205
5683
  }
@@ -5209,7 +5687,11 @@ function registerHooks(ctx) {
5209
5687
  (context) => {
5210
5688
  const branchId = context.params.route?.id;
5211
5689
  if (typeof branchId === "string") {
5212
- syncBranchUnixAccess(branchId, "[Executor/branch-group-grants.patch]");
5690
+ syncBranchUnixAccess(
5691
+ branchId,
5692
+ "[Executor/branch-group-grants.patch]",
5693
+ context.params
5694
+ );
5213
5695
  }
5214
5696
  return context;
5215
5697
  }
@@ -5219,7 +5701,11 @@ function registerHooks(ctx) {
5219
5701
  (context) => {
5220
5702
  const branchId = context.params.route?.id;
5221
5703
  if (typeof branchId === "string") {
5222
- syncBranchUnixAccess(branchId, "[Executor/branch-group-grants.remove]");
5704
+ syncBranchUnixAccess(
5705
+ branchId,
5706
+ "[Executor/branch-group-grants.remove]",
5707
+ context.params
5708
+ );
5223
5709
  }
5224
5710
  return context;
5225
5711
  }
@@ -5264,7 +5750,7 @@ function registerHooks(ctx) {
5264
5750
  return context;
5265
5751
  }
5266
5752
  if (params.user) {
5267
- ensureMinimumRole(params, ROLES9.MEMBER, "list users");
5753
+ ensureMinimumRole(params, ROLES10.MEMBER, "list users");
5268
5754
  return context;
5269
5755
  }
5270
5756
  const query = params.query || {};
@@ -5272,12 +5758,12 @@ function registerHooks(ctx) {
5272
5758
  params.query = { ...query, $limit: 1 };
5273
5759
  return context;
5274
5760
  }
5275
- throw new NotAuthenticated7("Authentication required");
5761
+ throw new NotAuthenticated8("Authentication required");
5276
5762
  }
5277
5763
  ],
5278
5764
  get: [
5279
5765
  (context) => {
5280
- ensureMinimumRole(context.params, ROLES9.MEMBER, "view users");
5766
+ ensureMinimumRole(context.params, ROLES10.MEMBER, "view users");
5281
5767
  return context;
5282
5768
  }
5283
5769
  ],
@@ -5289,13 +5775,13 @@ function registerHooks(ctx) {
5289
5775
  }
5290
5776
  const existing = await usersService.find({ query: { $limit: 1 } });
5291
5777
  if (existing.total > 0) {
5292
- ensureMinimumRole(params, ROLES9.ADMIN, "create users");
5778
+ ensureMinimumRole(params, ROLES10.ADMIN, "create users");
5293
5779
  }
5294
5780
  const data = context.data;
5295
- if (hasMinimumRole8(data?.role, ROLES9.SUPERADMIN)) {
5781
+ if (hasMinimumRole9(data?.role, ROLES10.SUPERADMIN)) {
5296
5782
  const callerRole = params.user?.role;
5297
- if (!hasMinimumRole8(callerRole, ROLES9.SUPERADMIN)) {
5298
- throw new Forbidden8("Only superadmins can create superadmin users");
5783
+ if (!hasMinimumRole9(callerRole, ROLES10.SUPERADMIN)) {
5784
+ throw new Forbidden9("Only superadmins can create superadmin users");
5299
5785
  }
5300
5786
  }
5301
5787
  return context;
@@ -5306,28 +5792,28 @@ function registerHooks(ctx) {
5306
5792
  const params = context.params;
5307
5793
  const userId = context.id;
5308
5794
  const callerRole = params.user?.role;
5309
- const callerIsAdmin = hasMinimumRole8(callerRole, ROLES9.ADMIN);
5795
+ const callerIsAdmin = hasMinimumRole9(callerRole, ROLES10.ADMIN);
5310
5796
  if (!Array.isArray(context.data)) {
5311
5797
  if (context.data?.unix_username !== void 0) {
5312
5798
  if (!callerIsAdmin) {
5313
- throw new Forbidden8("Only admins can modify unix_username");
5799
+ throw new Forbidden9("Only admins can modify unix_username");
5314
5800
  }
5315
5801
  }
5316
5802
  if (context.data?.role !== void 0) {
5317
5803
  if (!callerIsAdmin) {
5318
- throw new Forbidden8("Only admins can modify user roles");
5804
+ throw new Forbidden9("Only admins can modify user roles");
5319
5805
  }
5320
- if (hasMinimumRole8(context.data.role, ROLES9.SUPERADMIN) && !hasMinimumRole8(callerRole, ROLES9.SUPERADMIN)) {
5806
+ if (hasMinimumRole9(context.data.role, ROLES10.SUPERADMIN) && !hasMinimumRole9(callerRole, ROLES10.SUPERADMIN)) {
5321
5807
  const allUsers = await usersService.find({});
5322
- const hasSuperadmin = allUsers.data.some((u) => u.role === ROLES9.SUPERADMIN);
5808
+ const hasSuperadmin = allUsers.data.some((u) => u.role === ROLES10.SUPERADMIN);
5323
5809
  if (hasSuperadmin) {
5324
- throw new Forbidden8("Only superadmins can assign the superadmin role");
5810
+ throw new Forbidden9("Only superadmins can assign the superadmin role");
5325
5811
  }
5326
5812
  }
5327
5813
  }
5328
5814
  if (context.data?.must_change_password !== void 0) {
5329
5815
  if (!callerIsAdmin) {
5330
- throw new Forbidden8("Only admins can force password changes");
5816
+ throw new Forbidden9("Only admins can force password changes");
5331
5817
  }
5332
5818
  }
5333
5819
  }
@@ -5340,22 +5826,22 @@ function registerHooks(ctx) {
5340
5826
  if (!context.params.provider && params.trustedEnvVarWrite === true) {
5341
5827
  const keys = Object.keys(context.data ?? {});
5342
5828
  if (!keys.every((k) => k === "env_vars" || k === "env_var_scopes")) {
5343
- throw new Forbidden8(
5829
+ throw new Forbidden9(
5344
5830
  "trustedEnvVarWrite only permits env_vars and env_var_scopes updates"
5345
5831
  );
5346
5832
  }
5347
5833
  return context;
5348
5834
  }
5349
- throw new Forbidden8("You can only update your own profile");
5835
+ throw new Forbidden9("You can only update your own profile");
5350
5836
  }
5351
5837
  ],
5352
- remove: [requireMinimumRole(ROLES9.ADMIN, "delete users")]
5838
+ remove: [requireMinimumRole(ROLES10.ADMIN, "delete users")]
5353
5839
  },
5354
5840
  after: {
5355
5841
  // After user create/patch: optionally ensure Unix user exists and sync password
5356
5842
  create: [
5357
5843
  async (context) => {
5358
- if (!jwtSecret) {
5844
+ if (!executionMode.unixImpersonationEnabled || !jwtSecret) {
5359
5845
  return context;
5360
5846
  }
5361
5847
  const user = context.result;
@@ -5368,10 +5854,14 @@ function registerHooks(ctx) {
5368
5854
  return context;
5369
5855
  }
5370
5856
  console.log(`[Unix Integration] Syncing Unix user for: ${user.unix_username}`);
5371
- const serviceToken = createServiceToken(jwtSecret, void 0, {
5372
- user_id: user.user_id,
5373
- command: "unix.sync-user"
5374
- });
5857
+ const serviceToken = createExecutorServiceToken(
5858
+ context.params,
5859
+ {
5860
+ user_id: user.user_id,
5861
+ command: "unix.sync-user"
5862
+ }
5863
+ );
5864
+ if (!serviceToken) return context;
5375
5865
  spawnExecutorFireAndForget(
5376
5866
  {
5377
5867
  command: "unix.sync-user",
@@ -5388,11 +5878,27 @@ function registerHooks(ctx) {
5388
5878
  { logPrefix: "[Executor/user.create]" }
5389
5879
  );
5390
5880
  return context;
5881
+ },
5882
+ async (context) => {
5883
+ if (context.params.skipAvatarRefresh) {
5884
+ return context;
5885
+ }
5886
+ const user = context.result;
5887
+ const avatarService = safeService("users");
5888
+ if (avatarService?.refreshAvatarFromSettings) {
5889
+ avatarService.refreshAvatarFromSettings(user.user_id).catch((error) => {
5890
+ console.warn(
5891
+ `[users/avatar-sync] Failed to refresh avatar for new user ${shortId5(user.user_id)}:`,
5892
+ error instanceof Error ? error.message : String(error)
5893
+ );
5894
+ });
5895
+ }
5896
+ return context;
5391
5897
  }
5392
5898
  ],
5393
5899
  patch: [
5394
5900
  async (context) => {
5395
- if (!jwtSecret) {
5901
+ if (!executionMode.unixImpersonationEnabled || !jwtSecret) {
5396
5902
  return context;
5397
5903
  }
5398
5904
  const data = context.data;
@@ -5408,10 +5914,14 @@ function registerHooks(ctx) {
5408
5914
  return context;
5409
5915
  }
5410
5916
  console.log(`[Unix Integration] Syncing Unix user for: ${user.unix_username}`);
5411
- const serviceToken = createServiceToken(jwtSecret, void 0, {
5412
- user_id: user.user_id,
5413
- command: "unix.sync-user"
5414
- });
5917
+ const serviceToken = createExecutorServiceToken(
5918
+ context.params,
5919
+ {
5920
+ user_id: user.user_id,
5921
+ command: "unix.sync-user"
5922
+ }
5923
+ );
5924
+ if (!serviceToken) return context;
5415
5925
  spawnExecutorFireAndForget(
5416
5926
  {
5417
5927
  command: "unix.sync-user",
@@ -5428,6 +5938,26 @@ function registerHooks(ctx) {
5428
5938
  { logPrefix: "[Executor/user.patch]" }
5429
5939
  );
5430
5940
  return context;
5941
+ },
5942
+ async (context) => {
5943
+ if (context.params.skipAvatarRefresh) {
5944
+ return context;
5945
+ }
5946
+ const data = context.data;
5947
+ if (data?.email === void 0 && data?.preferences === void 0) {
5948
+ return context;
5949
+ }
5950
+ const user = context.result;
5951
+ const avatarService = safeService("users");
5952
+ if (avatarService?.refreshAvatarFromSettings) {
5953
+ avatarService.refreshAvatarFromSettings(user.user_id).catch((error) => {
5954
+ console.warn(
5955
+ `[users/avatar-sync] Failed to refresh avatar for updated user ${shortId5(user.user_id)}:`,
5956
+ error instanceof Error ? error.message : String(error)
5957
+ );
5958
+ });
5959
+ }
5960
+ return context;
5431
5961
  }
5432
5962
  ]
5433
5963
  }
@@ -5438,14 +5968,16 @@ function registerHooks(ctx) {
5438
5968
  branchRepository,
5439
5969
  sessionsRepository,
5440
5970
  accessCache: realtimeAccessCache,
5441
- allowSuperadmin: superadminOpts.allowSuperadmin
5971
+ allowSuperadmin: superadminOpts.allowSuperadmin,
5972
+ multiTenancy
5442
5973
  });
5443
5974
  app.service("sessions").hooks({
5444
5975
  before: {
5445
5976
  all: [typedValidateQuery(sessionQueryValidator), requireAuth, executorRuntimeScopeGuard()],
5446
5977
  find: [
5447
- // RBAC: Optimized SQL-based filtering (single query with JOIN on branches, no N+1)
5448
- ...branchRbacEnabled ? [scopeSessionQuery(sessionsRepository, superadminOpts)] : []
5978
+ // RBAC: mark external regular-user finds for SessionsService to compose
5979
+ // the shared branch visibility predicate directly into its SQL read.
5980
+ ...branchRbacEnabled ? [scopeFindToAccessibleSessionsSql(superadminOpts)] : []
5449
5981
  ],
5450
5982
  get: [
5451
5983
  ...branchRbacEnabled ? [
@@ -5456,7 +5988,7 @@ function registerHooks(ctx) {
5456
5988
  ] : []
5457
5989
  ],
5458
5990
  create: [
5459
- requireMinimumRole(ROLES9.MEMBER, "create sessions"),
5991
+ requireMinimumRole(ROLES10.MEMBER, "create sessions"),
5460
5992
  ...branchRbacEnabled ? [
5461
5993
  setSessionUnixUsername(usersRepository),
5462
5994
  // Stamp session with creator's unix_username (MUST run first)
@@ -5467,7 +5999,7 @@ function registerHooks(ctx) {
5467
5999
  try {
5468
6000
  const branch = await branchRepository.findById(data.branch_id);
5469
6001
  if (!branch) {
5470
- throw new Forbidden8(`Branch not found: ${data.branch_id}`);
6002
+ throw new Forbidden9(`Branch not found: ${data.branch_id}`);
5471
6003
  }
5472
6004
  await cacheBranchAccess(context.params, branchRepository, branch);
5473
6005
  } catch (error) {
@@ -5513,7 +6045,10 @@ function registerHooks(ctx) {
5513
6045
  db,
5514
6046
  context.params.user?.user_id
5515
6047
  ),
5516
- logPrefix: `[sessions.create ${branch.name}]`
6048
+ logPrefix: `[sessions.create ${branch.name}]`,
6049
+ serviceTokenScope: serviceTokenScopeForParams(
6050
+ context.params
6051
+ )
5517
6052
  }
5518
6053
  );
5519
6054
  context.data.git_state = {
@@ -5535,7 +6070,7 @@ function registerHooks(ctx) {
5535
6070
  }
5536
6071
  }
5537
6072
  const cbConfig = context.data?.callback_config;
5538
- if (cbConfig?.callback_session_id) {
6073
+ if (cbConfig?.callback_session_id && context.params.provider) {
5539
6074
  const authenticatedUserId = context.params.user?.user_id || "unknown";
5540
6075
  await ensureCanPromptTargetSession(
5541
6076
  cbConfig.callback_session_id,
@@ -5574,10 +6109,13 @@ function registerHooks(ctx) {
5574
6109
  )(context);
5575
6110
  }
5576
6111
  ] : [],
5577
- // Validate user has prompt permission on callback target session's branch
6112
+ // Validate user has prompt permission on callback target session's branch.
6113
+ // Skip for internal calls (no provider) — patches from dispatchCompletionCallbacks
6114
+ // spread the existing callback_config (which includes callback_session_id) and must
6115
+ // not be blocked by this check.
5578
6116
  async (context) => {
5579
6117
  const patchCbConfig = context.data?.callback_config;
5580
- if (patchCbConfig?.callback_session_id) {
6118
+ if (patchCbConfig?.callback_session_id && context.params.provider) {
5581
6119
  const userId = context.params.user?.user_id || "unknown";
5582
6120
  await ensureCanPromptTargetSession(
5583
6121
  patchCbConfig.callback_session_id,
@@ -5618,13 +6156,15 @@ function registerHooks(ctx) {
5618
6156
  const callerUser = context.params.user;
5619
6157
  if (!canReceiveMcpTokenForSession({
5620
6158
  callerUserId: callerUser?.user_id,
5621
- callerRole: callerUser?.role,
5622
- sessionCreatedBy: session.created_by
6159
+ callerRole: callerUser?.role
5623
6160
  })) {
5624
6161
  return context;
5625
6162
  }
5626
6163
  const { generateSessionToken: generateSessionToken3 } = await Promise.resolve().then(() => (init_tokens(), tokens_exports));
5627
- const userId = session.created_by || "unknown";
6164
+ const userId = callerUser?.user_id;
6165
+ if (!userId) {
6166
+ return context;
6167
+ }
5628
6168
  const jwtSecret2 = app.settings.authentication?.secret;
5629
6169
  if (!jwtSecret2) {
5630
6170
  console.error("\u274C JWT secret not configured - cannot generate MCP token");
@@ -5675,13 +6215,19 @@ function registerHooks(ctx) {
5675
6215
  if (config.daemon?.mcpEnabled === false) {
5676
6216
  return context;
5677
6217
  }
5678
- const callerRole = context.params.user?.role;
5679
- if (!hasMinimumRole8(callerRole, ROLES9.MEMBER)) {
6218
+ const callerUser = context.params.user;
6219
+ if (!canReceiveMcpTokenForSession({
6220
+ callerUserId: callerUser?.user_id,
6221
+ callerRole: callerUser?.role
6222
+ })) {
5680
6223
  return context;
5681
6224
  }
5682
6225
  const { generateSessionToken: generateSessionToken3 } = await Promise.resolve().then(() => (init_tokens(), tokens_exports));
5683
6226
  const session = context.result;
5684
- const userId = session.created_by || "unknown";
6227
+ const userId = callerUser?.user_id;
6228
+ if (!userId) {
6229
+ return context;
6230
+ }
5685
6231
  const jwtSecret2 = app.settings.authentication?.secret;
5686
6232
  if (!jwtSecret2) {
5687
6233
  console.error("\u274C JWT secret not configured - cannot generate MCP token");
@@ -5702,7 +6248,7 @@ function registerHooks(ctx) {
5702
6248
  // unix groups. Without this, non-owners can't access the .git/ directory
5703
6249
  // (which uses 2770 = no others access) even if the branch directory itself
5704
6250
  // allows "others" access via ACLs.
5705
- ...branchRbacEnabled ? [
6251
+ ...executionMode.unixFsIsolationEnabled ? [
5706
6252
  async (context) => {
5707
6253
  const session = context.result;
5708
6254
  if (!session.branch_id || !session.unix_username) {
@@ -5717,28 +6263,15 @@ function registerHooks(ctx) {
5717
6263
  if (!branch?.others_fs_access || branch.others_fs_access === "none") {
5718
6264
  return context;
5719
6265
  }
5720
- if (jwtSecret) {
5721
- console.log(
5722
- `[Unix Integration] Non-owner session created in branch ${shortId5(session.branch_id)} by ${session.unix_username} (others_fs_access: ${branch.others_fs_access}), syncing group membership`
5723
- );
5724
- const serviceToken = createServiceToken(jwtSecret, void 0, {
5725
- branch_id: branch.branch_id,
5726
- session_id: session.session_id,
5727
- command: "unix.sync-branch"
5728
- });
5729
- spawnExecutorFireAndForget(
5730
- {
5731
- command: "unix.sync-branch",
5732
- sessionToken: serviceToken,
5733
- daemonUrl: getDaemonUrl(),
5734
- params: {
5735
- branchId: session.branch_id,
5736
- daemonUser: config.daemon?.unix_user
5737
- }
5738
- },
5739
- { logPrefix: "[Executor/session.create.unix-group]" }
5740
- );
5741
- }
6266
+ console.log(
6267
+ `[Unix Integration] Non-owner session created in branch ${shortId5(session.branch_id)} by ${session.unix_username} (others_fs_access: ${branch.others_fs_access}), syncing group membership`
6268
+ );
6269
+ syncBranchUnixAccess(
6270
+ branch.branch_id,
6271
+ "[Executor/session.create.unix-group]",
6272
+ context.params,
6273
+ { scope: { session_id: session.session_id } }
6274
+ );
5742
6275
  } catch (error) {
5743
6276
  console.error(
5744
6277
  `[Unix Integration] Failed to trigger group sync for session ${shortId5(session.session_id)}:`,
@@ -5753,7 +6286,7 @@ function registerHooks(ctx) {
5753
6286
  async (context) => {
5754
6287
  const session = Array.isArray(context.result) ? context.result[0] : context.result;
5755
6288
  if (session && shouldRunSessionPostTurnHooks(session)) {
5756
- setImmediate(async () => {
6289
+ deferWithTenantDatabaseScope(db, context.params, async () => {
5757
6290
  try {
5758
6291
  const gatewayService = context.app.service("gateway");
5759
6292
  await gatewayService.flushGitHubBuffer(session.session_id);
@@ -5769,19 +6302,33 @@ function registerHooks(ctx) {
5769
6302
  }
5770
6303
  });
5771
6304
  if (shouldDrainQueueAfterSessionPostTurnPatch(session, context.params)) {
5772
- setImmediate(async () => {
5773
- try {
6305
+ const sessionTenantId = getTrustedSessionTenantId(session);
6306
+ deferWithSessionQueueTenantScope(
6307
+ {
6308
+ db,
6309
+ config,
6310
+ sessionId: session.session_id,
6311
+ params: context.params,
6312
+ tenantIdHint: sessionTenantId,
6313
+ label: "SessionsService.after.patch queue drain"
6314
+ },
6315
+ async (queueParams) => {
5774
6316
  console.log(
5775
6317
  `\u{1F504} [SessionsService.after.patch] Session ${shortId5(session.session_id)} became promptable (${session.status}), checking for queued tasks...`
5776
6318
  );
5777
- await sessionsService.triggerQueueProcessing(session.session_id, context.params);
5778
- } catch (error) {
6319
+ await sessionsService.triggerQueueProcessing(session.session_id, queueParams);
6320
+ },
6321
+ (error) => {
5779
6322
  console.error(
5780
6323
  `\u274C [SessionsService.after.patch] Failed to process queue for session ${shortId5(session.session_id)}:`,
5781
6324
  error
5782
6325
  );
5783
6326
  }
5784
- });
6327
+ );
6328
+ } else {
6329
+ console.log(
6330
+ `\u23ED\uFE0F [SessionsService.after.patch] Queue drain suppressed for session ${shortId5(session.session_id)} (suppressTerminalQueueProcessing or not ready)`
6331
+ );
5785
6332
  }
5786
6333
  }
5787
6334
  return context;
@@ -5810,14 +6357,14 @@ function registerHooks(ctx) {
5810
6357
  ] : []
5811
6358
  ],
5812
6359
  create: [
5813
- requireMinimumRole(ROLES9.MEMBER, "create schedules"),
6360
+ requireMinimumRole(ROLES10.MEMBER, "create schedules"),
5814
6361
  ...branchRbacEnabled ? [loadBranch(branchRepository, "branch_id"), ensureCanCreateSession(superadminOpts)] : [],
5815
6362
  injectCreatedBy(),
5816
6363
  validateScheduleConfig(),
5817
6364
  recomputeNextRunAt()
5818
6365
  ],
5819
6366
  patch: [
5820
- requireMinimumRole(ROLES9.MEMBER, "update schedules"),
6367
+ requireMinimumRole(ROLES10.MEMBER, "update schedules"),
5821
6368
  ...branchRbacEnabled ? [
5822
6369
  loadScheduleAndBranch(scheduleRepository, branchRepository),
5823
6370
  ensureCanModifySchedule(superadminOpts)
@@ -5832,7 +6379,7 @@ function registerHooks(ctx) {
5832
6379
  recomputeNextRunAt()
5833
6380
  ],
5834
6381
  remove: [
5835
- requireMinimumRole(ROLES9.MEMBER, "delete schedules"),
6382
+ requireMinimumRole(ROLES10.MEMBER, "delete schedules"),
5836
6383
  ...branchRbacEnabled ? [
5837
6384
  loadScheduleAndBranch(scheduleRepository, branchRepository),
5838
6385
  ensureBranchPermission("all", "delete schedule", superadminOpts)
@@ -5845,7 +6392,7 @@ function registerHooks(ctx) {
5845
6392
  all: [typedValidateQuery(taskQueryValidator), requireAuth, executorRuntimeScopeGuard()],
5846
6393
  find: [
5847
6394
  // RBAC: Scope tasks.find() to sessions the caller can access.
5848
- ...branchRbacEnabled ? [scopeFindToAccessibleSessions(sessionsRepository, superadminOpts)] : []
6395
+ ...branchRbacEnabled ? [scopeFindToAccessibleSessionsSql(superadminOpts)] : []
5849
6396
  ],
5850
6397
  get: [
5851
6398
  ...branchRbacEnabled ? [
@@ -5857,7 +6404,7 @@ function registerHooks(ctx) {
5857
6404
  ] : []
5858
6405
  ],
5859
6406
  create: [
5860
- requireMinimumRole(ROLES9.MEMBER, "create tasks"),
6407
+ requireMinimumRole(ROLES10.MEMBER, "create tasks"),
5861
6408
  ...branchRbacEnabled ? [
5862
6409
  resolveSessionContext(),
5863
6410
  loadSession(sessionsService),
@@ -5879,7 +6426,7 @@ function registerHooks(ctx) {
5879
6426
  ] : []
5880
6427
  ],
5881
6428
  remove: [
5882
- requireMinimumRole(ROLES9.MEMBER, "delete tasks"),
6429
+ requireMinimumRole(ROLES10.MEMBER, "delete tasks"),
5883
6430
  // RBAC: deleting a task requires 'all' permission on the branch
5884
6431
  // (mirrors sessions.remove). Without this, any member with 'session'
5885
6432
  // access could delete tasks owned by other users on shared branches.
@@ -5897,21 +6444,21 @@ function registerHooks(ctx) {
5897
6444
  return async (context) => {
5898
6445
  if (!branchRbacEnabled || !context.params.provider) return context;
5899
6446
  const user = context.params.user;
5900
- if (!user) throw new NotAuthenticated7("Authentication required");
6447
+ if (!user) throw new NotAuthenticated8("Authentication required");
5901
6448
  if (user._isServiceAccount) return context;
5902
6449
  const allowSuperadmin = superadminOpts?.allowSuperadmin ?? true;
5903
- if (user.role === ROLES9.ADMIN || allowSuperadmin && user.role === ROLES9.SUPERADMIN) {
6450
+ if (user.role === ROLES10.ADMIN || allowSuperadmin && user.role === ROLES10.SUPERADMIN) {
5904
6451
  return context;
5905
6452
  }
5906
6453
  const args = context.arguments;
5907
6454
  const firstArg = args?.[0];
5908
6455
  const id = typeof context.id === "string" ? context.id : typeof context.params.route?.id === "string" ? context.params.route.id : typeof firstArg === "string" ? firstArg : firstArg && typeof firstArg === "object" ? firstArg.boardId ?? firstArg.id ?? firstArg.slug : void 0;
5909
- if (!id) throw new BadRequest3("Board ID is required");
6456
+ if (!id) throw new BadRequest5("Board ID is required");
5910
6457
  const board = await boardRepository.findBySlugOrId(id);
5911
- if (!board) throw new Forbidden8(`Board not found: ${id}`);
6458
+ if (!board) throw new Forbidden9(`Board not found: ${id}`);
5912
6459
  const allowed = mode === "view" ? await boardRepository.canView(board.board_id, user.user_id) : await boardRepository.canMutate(board.board_id, user.user_id);
5913
6460
  if (!allowed) {
5914
- throw new Forbidden8(
6461
+ throw new Forbidden9(
5915
6462
  mode === "view" ? `You need board access to ${action}` : `You need board owner or board group 'all' access to ${action}`
5916
6463
  );
5917
6464
  }
@@ -5925,16 +6472,16 @@ function registerHooks(ctx) {
5925
6472
  all: [typedValidateQuery(boardQueryValidator), requireAuth],
5926
6473
  find: [
5927
6474
  // RBAC: restrict boards.find to boards the caller created or has a
5928
- // branch on. Runs at the SQL layer via BoardRepository.findVisibleBoardIds
5929
- // to avoid hydrating every accessible branch in-memory.
5930
- ...branchRbacEnabled ? [scopeFindToAccessibleBoards(boardRepository, superadminOpts)] : []
6475
+ // branch on. The service pushes this into the repository query as one
6476
+ // SQL predicate, avoiding a preloaded `board_id IN (...)` list.
6477
+ ...branchRbacEnabled ? [scopeFindToAccessibleBoardsSql(superadminOpts)] : []
5931
6478
  ],
5932
6479
  get: [ensureCanViewBoard("view this board")],
5933
6480
  findBySlug: [ensureCanViewBoard("view this board")],
5934
6481
  findBySlugOrId: [ensureCanViewBoard("view this board")],
5935
- create: [requireMinimumRole(ROLES9.MEMBER, "create boards"), injectCreatedBy()],
6482
+ create: [requireMinimumRole(ROLES10.MEMBER, "create boards"), injectCreatedBy()],
5936
6483
  patch: [
5937
- requireMinimumRole(ROLES9.MEMBER, "update boards"),
6484
+ requireMinimumRole(ROLES10.MEMBER, "update boards"),
5938
6485
  ensureCanMutateBoard("update this board"),
5939
6486
  async (context) => {
5940
6487
  const contextData = context.data || {};
@@ -5986,6 +6533,17 @@ function registerHooks(ctx) {
5986
6533
  context.dispatch = result;
5987
6534
  return context;
5988
6535
  }
6536
+ if (_action === "mergeObjectFields" && objects) {
6537
+ if (!context.id) throw new Error("Board ID required");
6538
+ const result = await boardsService.mergeBoardObjectFields(
6539
+ context.id,
6540
+ objects
6541
+ );
6542
+ context.result = result;
6543
+ app.service("boards").emit("patched", result);
6544
+ context.dispatch = result;
6545
+ return context;
6546
+ }
5989
6547
  if (_action === "deleteZone" && objectId) {
5990
6548
  if (!context.id) throw new Error("Board ID required");
5991
6549
  const result = await boardsService.deleteZone(
@@ -6001,30 +6559,30 @@ function registerHooks(ctx) {
6001
6559
  }
6002
6560
  ],
6003
6561
  remove: [
6004
- requireMinimumRole(ROLES9.MEMBER, "delete boards"),
6562
+ requireMinimumRole(ROLES10.MEMBER, "delete boards"),
6005
6563
  ensureCanMutateBoard("delete this board")
6006
6564
  ],
6007
6565
  toBlob: [
6008
- requireMinimumRole(ROLES9.MEMBER, "export boards"),
6566
+ requireMinimumRole(ROLES10.MEMBER, "export boards"),
6009
6567
  ensureCanViewBoard("export boards")
6010
6568
  ],
6011
6569
  toYaml: [
6012
- requireMinimumRole(ROLES9.MEMBER, "export boards"),
6570
+ requireMinimumRole(ROLES10.MEMBER, "export boards"),
6013
6571
  ensureCanViewBoard("export boards")
6014
6572
  ],
6015
- fromBlob: [requireMinimumRole(ROLES9.MEMBER, "import boards")],
6016
- fromYaml: [requireMinimumRole(ROLES9.MEMBER, "import boards")],
6017
- clone: [requireMinimumRole(ROLES9.MEMBER, "clone boards"), ensureCanViewBoard("clone boards")],
6573
+ fromBlob: [requireMinimumRole(ROLES10.MEMBER, "import boards")],
6574
+ fromYaml: [requireMinimumRole(ROLES10.MEMBER, "import boards")],
6575
+ clone: [requireMinimumRole(ROLES10.MEMBER, "clone boards"), ensureCanViewBoard("clone boards")],
6018
6576
  setPrimaryAssistant: [
6019
- requireMinimumRole(ROLES9.MEMBER, "set primary assistant"),
6577
+ requireMinimumRole(ROLES10.MEMBER, "set primary assistant"),
6020
6578
  ensureCanMutateBoard("set primary assistant")
6021
6579
  ],
6022
6580
  clearPrimaryAssistant: [
6023
- requireMinimumRole(ROLES9.MEMBER, "clear primary assistant"),
6581
+ requireMinimumRole(ROLES10.MEMBER, "clear primary assistant"),
6024
6582
  ensureCanMutateBoard("clear primary assistant")
6025
6583
  ],
6026
6584
  ensureAssistantWelcomeNote: [
6027
- requireMinimumRole(ROLES9.MEMBER, "create assistant welcome note"),
6585
+ requireMinimumRole(ROLES10.MEMBER, "create assistant welcome note"),
6028
6586
  ensureCanMutateBoard("create assistant welcome note")
6029
6587
  ]
6030
6588
  },
@@ -6165,7 +6723,7 @@ function registerHooks(ctx) {
6165
6723
  before: {
6166
6724
  create: [
6167
6725
  requireAuth,
6168
- requireMinimumRole(ROLES9.MEMBER, "archive boards"),
6726
+ requireMinimumRole(ROLES10.MEMBER, "archive boards"),
6169
6727
  ensureCanMutateBoard("archive this board")
6170
6728
  ]
6171
6729
  },
@@ -6182,17 +6740,22 @@ function registerHooks(ctx) {
6182
6740
  before: {
6183
6741
  create: [
6184
6742
  requireAuth,
6185
- requireMinimumRole(ROLES9.MEMBER, "unarchive boards"),
6743
+ requireMinimumRole(ROLES10.MEMBER, "unarchive boards"),
6186
6744
  ensureCanMutateBoard("unarchive this board")
6187
6745
  ]
6188
6746
  },
6189
6747
  after: { create: [clearRealtimeBranchVisibility] }
6190
6748
  });
6191
6749
  }
6750
+ if (tenantColumnsEnabled) {
6751
+ registerTenantHooks();
6752
+ }
6192
6753
  }
6193
6754
  export {
6194
6755
  PROMPT_FLOW_PATCH_FIELDS,
6756
+ TENANT_OWNED_SERVICE_PATHS,
6195
6757
  enrichSessionFindResultWithRemoteRelationships,
6758
+ getTrustedSessionTenantId,
6196
6759
  isPromptFlowPatchOnly,
6197
6760
  registerHooks,
6198
6761
  shouldDrainQueueAfterSessionPostTurnPatch,