slackhive 0.1.37 → 0.1.39

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 (542) hide show
  1. package/.dockerignore +14 -0
  2. package/.env.example +44 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.yml +65 -0
  4. package/.github/ISSUE_TEMPLATE/config.yml +5 -0
  5. package/.github/ISSUE_TEMPLATE/feature_request.yml +38 -0
  6. package/.github/PULL_REQUEST_TEMPLATE.md +27 -0
  7. package/.github/dependabot.yml +20 -0
  8. package/.github/workflows/audit.yml +149 -0
  9. package/.github/workflows/ci.yml +135 -0
  10. package/CHANGELOG.md +52 -0
  11. package/CODE_OF_CONDUCT.md +37 -0
  12. package/CONTRIBUTING.md +204 -0
  13. package/LICENSE +21 -0
  14. package/README.md +19 -0
  15. package/SECURITY.md +47 -0
  16. package/apps/runner/Dockerfile +33 -0
  17. package/apps/runner/dist/__tests__/channel-restrictions.test.d.ts +8 -0
  18. package/apps/runner/dist/__tests__/channel-restrictions.test.js +63 -0
  19. package/apps/runner/dist/__tests__/channel-restrictions.test.js.map +1 -0
  20. package/apps/runner/dist/__tests__/claude-handler-resolve.test.d.ts +20 -0
  21. package/apps/runner/dist/__tests__/claude-handler-resolve.test.js +178 -0
  22. package/apps/runner/dist/__tests__/claude-handler-resolve.test.js.map +1 -0
  23. package/apps/runner/dist/__tests__/compile-claude-md.test.d.ts +13 -0
  24. package/apps/runner/dist/__tests__/compile-claude-md.test.js +144 -0
  25. package/apps/runner/dist/__tests__/compile-claude-md.test.js.map +1 -0
  26. package/apps/runner/dist/__tests__/memory-sync.test.d.ts +11 -0
  27. package/apps/runner/dist/__tests__/memory-sync.test.js +56 -0
  28. package/apps/runner/dist/__tests__/memory-sync.test.js.map +1 -0
  29. package/apps/runner/dist/__tests__/slack-file-support.test.d.ts +9 -0
  30. package/apps/runner/dist/__tests__/slack-file-support.test.js +271 -0
  31. package/apps/runner/dist/__tests__/slack-file-support.test.js.map +1 -0
  32. package/apps/runner/dist/__tests__/slack-formatting.test.d.ts +12 -0
  33. package/apps/runner/dist/__tests__/slack-formatting.test.js +400 -0
  34. package/apps/runner/dist/__tests__/slack-formatting.test.js.map +1 -0
  35. package/apps/runner/dist/__tests__/thread-context.test.d.ts +12 -0
  36. package/apps/runner/dist/__tests__/thread-context.test.js +182 -0
  37. package/apps/runner/dist/__tests__/thread-context.test.js.map +1 -0
  38. package/apps/runner/dist/agent-runner.d.ts +118 -0
  39. package/apps/runner/dist/agent-runner.js +352 -0
  40. package/apps/runner/dist/agent-runner.js.map +1 -0
  41. package/apps/runner/dist/claude-handler.d.ts +122 -0
  42. package/apps/runner/dist/claude-handler.js +402 -0
  43. package/apps/runner/dist/claude-handler.js.map +1 -0
  44. package/apps/runner/dist/compile-claude-md.d.ts +59 -0
  45. package/apps/runner/dist/compile-claude-md.js +291 -0
  46. package/apps/runner/dist/compile-claude-md.js.map +1 -0
  47. package/apps/runner/dist/correction-handler.d.ts +46 -0
  48. package/apps/runner/dist/correction-handler.js +162 -0
  49. package/apps/runner/dist/correction-handler.js.map +1 -0
  50. package/apps/runner/dist/correction-manager.d.ts +53 -0
  51. package/apps/runner/dist/correction-manager.js +241 -0
  52. package/apps/runner/dist/correction-manager.js.map +1 -0
  53. package/apps/runner/dist/db.d.ts +193 -0
  54. package/apps/runner/dist/db.js +492 -0
  55. package/apps/runner/dist/db.js.map +1 -0
  56. package/apps/runner/dist/index.d.ts +9 -0
  57. package/apps/runner/dist/index.js +43 -0
  58. package/apps/runner/dist/index.js.map +1 -0
  59. package/apps/runner/dist/job-scheduler.d.ts +57 -0
  60. package/apps/runner/dist/job-scheduler.js +150 -0
  61. package/apps/runner/dist/job-scheduler.js.map +1 -0
  62. package/apps/runner/dist/logger.d.ts +32 -0
  63. package/apps/runner/dist/logger.js +52 -0
  64. package/apps/runner/dist/logger.js.map +1 -0
  65. package/apps/runner/dist/mcp-process-manager.d.ts +38 -0
  66. package/apps/runner/dist/mcp-process-manager.js +189 -0
  67. package/apps/runner/dist/mcp-process-manager.js.map +1 -0
  68. package/apps/runner/dist/memory-mcp.d.ts +14 -0
  69. package/apps/runner/dist/memory-mcp.js +88 -0
  70. package/apps/runner/dist/memory-mcp.js.map +1 -0
  71. package/apps/runner/dist/memory-watcher.d.ts +78 -0
  72. package/apps/runner/dist/memory-watcher.js +220 -0
  73. package/apps/runner/dist/memory-watcher.js.map +1 -0
  74. package/apps/runner/dist/slack-handler.d.ts +120 -0
  75. package/apps/runner/dist/slack-handler.js +843 -0
  76. package/apps/runner/dist/slack-handler.js.map +1 -0
  77. package/apps/runner/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  78. package/apps/runner/package.json +42 -0
  79. package/apps/runner/src/__tests__/channel-restrictions.test.ts +75 -0
  80. package/apps/runner/src/__tests__/claude-handler-resolve.test.ts +160 -0
  81. package/apps/runner/src/__tests__/compile-claude-md.test.ts +139 -0
  82. package/apps/runner/src/__tests__/memory-sync.test.ts +59 -0
  83. package/apps/runner/src/__tests__/slack-file-support.test.ts +376 -0
  84. package/apps/runner/src/__tests__/slack-formatting.test.ts +495 -0
  85. package/apps/runner/src/__tests__/thread-context.test.ts +215 -0
  86. package/apps/runner/src/agent-runner.ts +397 -0
  87. package/apps/runner/src/claude-handler.ts +475 -0
  88. package/apps/runner/src/compile-claude-md.ts +283 -0
  89. package/apps/runner/src/correction-handler.ts +191 -0
  90. package/apps/runner/src/correction-manager.ts +285 -0
  91. package/apps/runner/src/db.ts +604 -0
  92. package/apps/runner/src/index.ts +46 -0
  93. package/apps/runner/src/job-scheduler.ts +165 -0
  94. package/apps/runner/src/logger.ts +49 -0
  95. package/apps/runner/src/mcp-process-manager.ts +195 -0
  96. package/apps/runner/src/memory-mcp.ts +85 -0
  97. package/apps/runner/src/memory-watcher.ts +215 -0
  98. package/apps/runner/src/slack-handler.ts +929 -0
  99. package/apps/runner/tsconfig.json +17 -0
  100. package/apps/runner/vitest.config.mts +17 -0
  101. package/apps/web/.eslintrc.json +3 -0
  102. package/apps/web/.next/app-build-manifest.json +323 -0
  103. package/apps/web/.next/app-path-routes-manifest.json +46 -0
  104. package/apps/web/.next/build-manifest.json +33 -0
  105. package/apps/web/.next/cache/.previewinfo +1 -0
  106. package/apps/web/.next/cache/.rscinfo +1 -0
  107. package/apps/web/.next/cache/webpack/client-production/0.pack +0 -0
  108. package/apps/web/.next/cache/webpack/client-production/1.pack +0 -0
  109. package/apps/web/.next/cache/webpack/client-production/2.pack +0 -0
  110. package/apps/web/.next/cache/webpack/client-production/3.pack +0 -0
  111. package/apps/web/.next/cache/webpack/client-production/4.pack +0 -0
  112. package/apps/web/.next/cache/webpack/client-production/index.pack +0 -0
  113. package/apps/web/.next/cache/webpack/client-production/index.pack.old +0 -0
  114. package/apps/web/.next/cache/webpack/edge-server-production/0.pack +0 -0
  115. package/apps/web/.next/cache/webpack/edge-server-production/1.pack +0 -0
  116. package/apps/web/.next/cache/webpack/edge-server-production/index.pack +0 -0
  117. package/apps/web/.next/cache/webpack/edge-server-production/index.pack.old +0 -0
  118. package/apps/web/.next/cache/webpack/server-production/0.pack +0 -0
  119. package/apps/web/.next/cache/webpack/server-production/1.pack +0 -0
  120. package/apps/web/.next/cache/webpack/server-production/2.pack +0 -0
  121. package/apps/web/.next/cache/webpack/server-production/index.pack +0 -0
  122. package/apps/web/.next/cache/webpack/server-production/index.pack.old +0 -0
  123. package/apps/web/.next/diagnostics/build-diagnostics.json +6 -0
  124. package/apps/web/.next/diagnostics/framework.json +1 -0
  125. package/apps/web/.next/package.json +1 -0
  126. package/apps/web/.next/react-loadable-manifest.json +1 -0
  127. package/apps/web/.next/server/app/_not-found/page.js +2 -0
  128. package/apps/web/.next/server/app/_not-found/page.js.nft.json +1 -0
  129. package/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
  130. package/apps/web/.next/server/app/agents/[slug]/page.js +4 -0
  131. package/apps/web/.next/server/app/agents/[slug]/page.js.nft.json +1 -0
  132. package/apps/web/.next/server/app/agents/[slug]/page_client-reference-manifest.js +1 -0
  133. package/apps/web/.next/server/app/agents/new/page.js +2 -0
  134. package/apps/web/.next/server/app/agents/new/page.js.nft.json +1 -0
  135. package/apps/web/.next/server/app/agents/new/page_client-reference-manifest.js +1 -0
  136. package/apps/web/.next/server/app/api/agents/[id]/access/route.js +1 -0
  137. package/apps/web/.next/server/app/api/agents/[id]/access/route.js.nft.json +1 -0
  138. package/apps/web/.next/server/app/api/agents/[id]/access/route_client-reference-manifest.js +1 -0
  139. package/apps/web/.next/server/app/api/agents/[id]/claude-md/route.js +6 -0
  140. package/apps/web/.next/server/app/api/agents/[id]/claude-md/route.js.nft.json +1 -0
  141. package/apps/web/.next/server/app/api/agents/[id]/claude-md/route_client-reference-manifest.js +1 -0
  142. package/apps/web/.next/server/app/api/agents/[id]/logs/route.js +3 -0
  143. package/apps/web/.next/server/app/api/agents/[id]/logs/route.js.nft.json +1 -0
  144. package/apps/web/.next/server/app/api/agents/[id]/logs/route_client-reference-manifest.js +1 -0
  145. package/apps/web/.next/server/app/api/agents/[id]/manifest/route.js +1 -0
  146. package/apps/web/.next/server/app/api/agents/[id]/manifest/route.js.nft.json +1 -0
  147. package/apps/web/.next/server/app/api/agents/[id]/manifest/route_client-reference-manifest.js +1 -0
  148. package/apps/web/.next/server/app/api/agents/[id]/mcps/route.js +1 -0
  149. package/apps/web/.next/server/app/api/agents/[id]/mcps/route.js.nft.json +1 -0
  150. package/apps/web/.next/server/app/api/agents/[id]/mcps/route_client-reference-manifest.js +1 -0
  151. package/apps/web/.next/server/app/api/agents/[id]/memories/[memId]/route.js +1 -0
  152. package/apps/web/.next/server/app/api/agents/[id]/memories/[memId]/route.js.nft.json +1 -0
  153. package/apps/web/.next/server/app/api/agents/[id]/memories/[memId]/route_client-reference-manifest.js +1 -0
  154. package/apps/web/.next/server/app/api/agents/[id]/memories/route.js +1 -0
  155. package/apps/web/.next/server/app/api/agents/[id]/memories/route.js.nft.json +1 -0
  156. package/apps/web/.next/server/app/api/agents/[id]/memories/route_client-reference-manifest.js +1 -0
  157. package/apps/web/.next/server/app/api/agents/[id]/permissions/route.js +1 -0
  158. package/apps/web/.next/server/app/api/agents/[id]/permissions/route.js.nft.json +1 -0
  159. package/apps/web/.next/server/app/api/agents/[id]/permissions/route_client-reference-manifest.js +1 -0
  160. package/apps/web/.next/server/app/api/agents/[id]/reload/route.js +1 -0
  161. package/apps/web/.next/server/app/api/agents/[id]/reload/route.js.nft.json +1 -0
  162. package/apps/web/.next/server/app/api/agents/[id]/reload/route_client-reference-manifest.js +1 -0
  163. package/apps/web/.next/server/app/api/agents/[id]/restrictions/route.js +1 -0
  164. package/apps/web/.next/server/app/api/agents/[id]/restrictions/route.js.nft.json +1 -0
  165. package/apps/web/.next/server/app/api/agents/[id]/restrictions/route_client-reference-manifest.js +1 -0
  166. package/apps/web/.next/server/app/api/agents/[id]/route.js +33 -0
  167. package/apps/web/.next/server/app/api/agents/[id]/route.js.nft.json +1 -0
  168. package/apps/web/.next/server/app/api/agents/[id]/route_client-reference-manifest.js +1 -0
  169. package/apps/web/.next/server/app/api/agents/[id]/skills/[skillId]/route.js +1 -0
  170. package/apps/web/.next/server/app/api/agents/[id]/skills/[skillId]/route.js.nft.json +1 -0
  171. package/apps/web/.next/server/app/api/agents/[id]/skills/[skillId]/route_client-reference-manifest.js +1 -0
  172. package/apps/web/.next/server/app/api/agents/[id]/skills/route.js +1 -0
  173. package/apps/web/.next/server/app/api/agents/[id]/skills/route.js.nft.json +1 -0
  174. package/apps/web/.next/server/app/api/agents/[id]/skills/route_client-reference-manifest.js +1 -0
  175. package/apps/web/.next/server/app/api/agents/[id]/slack-info/route.js +1 -0
  176. package/apps/web/.next/server/app/api/agents/[id]/slack-info/route.js.nft.json +1 -0
  177. package/apps/web/.next/server/app/api/agents/[id]/slack-info/route_client-reference-manifest.js +1 -0
  178. package/apps/web/.next/server/app/api/agents/[id]/snapshots/[sid]/restore/route.js +1 -0
  179. package/apps/web/.next/server/app/api/agents/[id]/snapshots/[sid]/restore/route.js.nft.json +1 -0
  180. package/apps/web/.next/server/app/api/agents/[id]/snapshots/[sid]/restore/route_client-reference-manifest.js +1 -0
  181. package/apps/web/.next/server/app/api/agents/[id]/snapshots/[sid]/route.js +1 -0
  182. package/apps/web/.next/server/app/api/agents/[id]/snapshots/[sid]/route.js.nft.json +1 -0
  183. package/apps/web/.next/server/app/api/agents/[id]/snapshots/[sid]/route_client-reference-manifest.js +1 -0
  184. package/apps/web/.next/server/app/api/agents/[id]/snapshots/route.js +1 -0
  185. package/apps/web/.next/server/app/api/agents/[id]/snapshots/route.js.nft.json +1 -0
  186. package/apps/web/.next/server/app/api/agents/[id]/snapshots/route_client-reference-manifest.js +1 -0
  187. package/apps/web/.next/server/app/api/agents/[id]/start/route.js +1 -0
  188. package/apps/web/.next/server/app/api/agents/[id]/start/route.js.nft.json +1 -0
  189. package/apps/web/.next/server/app/api/agents/[id]/start/route_client-reference-manifest.js +1 -0
  190. package/apps/web/.next/server/app/api/agents/[id]/stop/route.js +1 -0
  191. package/apps/web/.next/server/app/api/agents/[id]/stop/route.js.nft.json +1 -0
  192. package/apps/web/.next/server/app/api/agents/[id]/stop/route_client-reference-manifest.js +1 -0
  193. package/apps/web/.next/server/app/api/agents/route.js +91 -0
  194. package/apps/web/.next/server/app/api/agents/route.js.nft.json +1 -0
  195. package/apps/web/.next/server/app/api/agents/route_client-reference-manifest.js +1 -0
  196. package/apps/web/.next/server/app/api/auth/login/route.js +1 -0
  197. package/apps/web/.next/server/app/api/auth/login/route.js.nft.json +1 -0
  198. package/apps/web/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -0
  199. package/apps/web/.next/server/app/api/auth/logout/route.js +1 -0
  200. package/apps/web/.next/server/app/api/auth/logout/route.js.nft.json +1 -0
  201. package/apps/web/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -0
  202. package/apps/web/.next/server/app/api/auth/me/route.js +1 -0
  203. package/apps/web/.next/server/app/api/auth/me/route.js.nft.json +1 -0
  204. package/apps/web/.next/server/app/api/auth/me/route_client-reference-manifest.js +1 -0
  205. package/apps/web/.next/server/app/api/auth/users/[id]/route.js +1 -0
  206. package/apps/web/.next/server/app/api/auth/users/[id]/route.js.nft.json +1 -0
  207. package/apps/web/.next/server/app/api/auth/users/[id]/route_client-reference-manifest.js +1 -0
  208. package/apps/web/.next/server/app/api/auth/users/route.js +1 -0
  209. package/apps/web/.next/server/app/api/auth/users/route.js.nft.json +1 -0
  210. package/apps/web/.next/server/app/api/auth/users/route_client-reference-manifest.js +1 -0
  211. package/apps/web/.next/server/app/api/env-vars/[key]/route.js +1 -0
  212. package/apps/web/.next/server/app/api/env-vars/[key]/route.js.nft.json +1 -0
  213. package/apps/web/.next/server/app/api/env-vars/[key]/route_client-reference-manifest.js +1 -0
  214. package/apps/web/.next/server/app/api/env-vars/route.js +1 -0
  215. package/apps/web/.next/server/app/api/env-vars/route.js.nft.json +1 -0
  216. package/apps/web/.next/server/app/api/env-vars/route_client-reference-manifest.js +1 -0
  217. package/apps/web/.next/server/app/api/jobs/[id]/route.js +1 -0
  218. package/apps/web/.next/server/app/api/jobs/[id]/route.js.nft.json +1 -0
  219. package/apps/web/.next/server/app/api/jobs/[id]/route_client-reference-manifest.js +1 -0
  220. package/apps/web/.next/server/app/api/jobs/[id]/runs/route.js +1 -0
  221. package/apps/web/.next/server/app/api/jobs/[id]/runs/route.js.nft.json +1 -0
  222. package/apps/web/.next/server/app/api/jobs/[id]/runs/route_client-reference-manifest.js +1 -0
  223. package/apps/web/.next/server/app/api/jobs/route.js +1 -0
  224. package/apps/web/.next/server/app/api/jobs/route.js.nft.json +1 -0
  225. package/apps/web/.next/server/app/api/jobs/route_client-reference-manifest.js +1 -0
  226. package/apps/web/.next/server/app/api/mcps/[id]/route.js +1 -0
  227. package/apps/web/.next/server/app/api/mcps/[id]/route.js.nft.json +1 -0
  228. package/apps/web/.next/server/app/api/mcps/[id]/route_client-reference-manifest.js +1 -0
  229. package/apps/web/.next/server/app/api/mcps/[id]/test/route.js +1 -0
  230. package/apps/web/.next/server/app/api/mcps/[id]/test/route.js.nft.json +1 -0
  231. package/apps/web/.next/server/app/api/mcps/[id]/test/route_client-reference-manifest.js +1 -0
  232. package/apps/web/.next/server/app/api/mcps/route.js +1 -0
  233. package/apps/web/.next/server/app/api/mcps/route.js.nft.json +1 -0
  234. package/apps/web/.next/server/app/api/mcps/route_client-reference-manifest.js +1 -0
  235. package/apps/web/.next/server/app/api/settings/route.js +1 -0
  236. package/apps/web/.next/server/app/api/settings/route.js.nft.json +1 -0
  237. package/apps/web/.next/server/app/api/settings/route_client-reference-manifest.js +1 -0
  238. package/apps/web/.next/server/app/icon.svg/route.js +1 -0
  239. package/apps/web/.next/server/app/icon.svg/route.js.nft.json +1 -0
  240. package/apps/web/.next/server/app/jobs/page.js +2 -0
  241. package/apps/web/.next/server/app/jobs/page.js.nft.json +1 -0
  242. package/apps/web/.next/server/app/jobs/page_client-reference-manifest.js +1 -0
  243. package/apps/web/.next/server/app/login/page.js +2 -0
  244. package/apps/web/.next/server/app/login/page.js.nft.json +1 -0
  245. package/apps/web/.next/server/app/login/page_client-reference-manifest.js +1 -0
  246. package/apps/web/.next/server/app/page.js +2 -0
  247. package/apps/web/.next/server/app/page.js.nft.json +1 -0
  248. package/apps/web/.next/server/app/page_client-reference-manifest.js +1 -0
  249. package/apps/web/.next/server/app/settings/env-vars/page.js +2 -0
  250. package/apps/web/.next/server/app/settings/env-vars/page.js.nft.json +1 -0
  251. package/apps/web/.next/server/app/settings/env-vars/page_client-reference-manifest.js +1 -0
  252. package/apps/web/.next/server/app/settings/mcps/page.js +2 -0
  253. package/apps/web/.next/server/app/settings/mcps/page.js.nft.json +1 -0
  254. package/apps/web/.next/server/app/settings/mcps/page_client-reference-manifest.js +1 -0
  255. package/apps/web/.next/server/app/settings/page.js +2 -0
  256. package/apps/web/.next/server/app/settings/page.js.nft.json +1 -0
  257. package/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -0
  258. package/apps/web/.next/server/app-paths-manifest.json +46 -0
  259. package/apps/web/.next/server/chunks/1157.js +9 -0
  260. package/apps/web/.next/server/chunks/2287.js +1 -0
  261. package/apps/web/.next/server/chunks/3444.js +1 -0
  262. package/apps/web/.next/server/chunks/383.js +6 -0
  263. package/apps/web/.next/server/chunks/4012.js +58 -0
  264. package/apps/web/.next/server/chunks/6791.js +1 -0
  265. package/apps/web/.next/server/chunks/7171.js +1 -0
  266. package/apps/web/.next/server/chunks/8819.js +22 -0
  267. package/apps/web/.next/server/edge-runtime-webpack.js +2 -0
  268. package/apps/web/.next/server/edge-runtime-webpack.js.map +1 -0
  269. package/apps/web/.next/server/interception-route-rewrite-manifest.js +1 -0
  270. package/apps/web/.next/server/middleware-build-manifest.js +1 -0
  271. package/apps/web/.next/server/middleware-manifest.json +32 -0
  272. package/apps/web/.next/server/middleware-react-loadable-manifest.js +1 -0
  273. package/apps/web/.next/server/next-font-manifest.js +1 -0
  274. package/apps/web/.next/server/next-font-manifest.json +1 -0
  275. package/apps/web/.next/server/pages/_app.js +1 -0
  276. package/apps/web/.next/server/pages/_app.js.nft.json +1 -0
  277. package/apps/web/.next/server/pages/_document.js +1 -0
  278. package/apps/web/.next/server/pages/_document.js.nft.json +1 -0
  279. package/apps/web/.next/server/pages/_error.js +19 -0
  280. package/apps/web/.next/server/pages/_error.js.nft.json +1 -0
  281. package/apps/web/.next/server/pages-manifest.json +5 -0
  282. package/apps/web/.next/server/server-reference-manifest.js +1 -0
  283. package/apps/web/.next/server/server-reference-manifest.json +1 -0
  284. package/apps/web/.next/server/src/middleware.js +14 -0
  285. package/apps/web/.next/server/src/middleware.js.map +1 -0
  286. package/apps/web/.next/server/webpack-runtime.js +1 -0
  287. package/apps/web/.next/static/chunks/18-90b700ea37b686a2.js +1 -0
  288. package/apps/web/.next/static/chunks/87c73c54-24122e7b92478d00.js +1 -0
  289. package/apps/web/.next/static/chunks/9664-af80478aa73ba424.js +1 -0
  290. package/apps/web/.next/static/chunks/app/_not-found/page-b9cee17ed89ca24a.js +1 -0
  291. package/apps/web/.next/static/chunks/app/agents/[slug]/page-18369fc3fe1a9a7b.js +1 -0
  292. package/apps/web/.next/static/chunks/app/agents/new/page-bf11cf8901c7e2cd.js +1 -0
  293. package/apps/web/.next/static/chunks/app/api/agents/[id]/access/route-07f0f73ac9839899.js +1 -0
  294. package/apps/web/.next/static/chunks/app/api/agents/[id]/claude-md/route-07f0f73ac9839899.js +1 -0
  295. package/apps/web/.next/static/chunks/app/api/agents/[id]/logs/route-07f0f73ac9839899.js +1 -0
  296. package/apps/web/.next/static/chunks/app/api/agents/[id]/manifest/route-07f0f73ac9839899.js +1 -0
  297. package/apps/web/.next/static/chunks/app/api/agents/[id]/mcps/route-07f0f73ac9839899.js +1 -0
  298. package/apps/web/.next/static/chunks/app/api/agents/[id]/memories/[memId]/route-07f0f73ac9839899.js +1 -0
  299. package/apps/web/.next/static/chunks/app/api/agents/[id]/memories/route-07f0f73ac9839899.js +1 -0
  300. package/apps/web/.next/static/chunks/app/api/agents/[id]/permissions/route-07f0f73ac9839899.js +1 -0
  301. package/apps/web/.next/static/chunks/app/api/agents/[id]/reload/route-07f0f73ac9839899.js +1 -0
  302. package/apps/web/.next/static/chunks/app/api/agents/[id]/restrictions/route-07f0f73ac9839899.js +1 -0
  303. package/apps/web/.next/static/chunks/app/api/agents/[id]/route-07f0f73ac9839899.js +1 -0
  304. package/apps/web/.next/static/chunks/app/api/agents/[id]/skills/[skillId]/route-07f0f73ac9839899.js +1 -0
  305. package/apps/web/.next/static/chunks/app/api/agents/[id]/skills/route-07f0f73ac9839899.js +1 -0
  306. package/apps/web/.next/static/chunks/app/api/agents/[id]/slack-info/route-07f0f73ac9839899.js +1 -0
  307. package/apps/web/.next/static/chunks/app/api/agents/[id]/snapshots/[sid]/restore/route-07f0f73ac9839899.js +1 -0
  308. package/apps/web/.next/static/chunks/app/api/agents/[id]/snapshots/[sid]/route-07f0f73ac9839899.js +1 -0
  309. package/apps/web/.next/static/chunks/app/api/agents/[id]/snapshots/route-07f0f73ac9839899.js +1 -0
  310. package/apps/web/.next/static/chunks/app/api/agents/[id]/start/route-07f0f73ac9839899.js +1 -0
  311. package/apps/web/.next/static/chunks/app/api/agents/[id]/stop/route-07f0f73ac9839899.js +1 -0
  312. package/apps/web/.next/static/chunks/app/api/agents/route-07f0f73ac9839899.js +1 -0
  313. package/apps/web/.next/static/chunks/app/api/auth/login/route-07f0f73ac9839899.js +1 -0
  314. package/apps/web/.next/static/chunks/app/api/auth/logout/route-07f0f73ac9839899.js +1 -0
  315. package/apps/web/.next/static/chunks/app/api/auth/me/route-07f0f73ac9839899.js +1 -0
  316. package/apps/web/.next/static/chunks/app/api/auth/users/[id]/route-07f0f73ac9839899.js +1 -0
  317. package/apps/web/.next/static/chunks/app/api/auth/users/route-07f0f73ac9839899.js +1 -0
  318. package/apps/web/.next/static/chunks/app/api/env-vars/[key]/route-07f0f73ac9839899.js +1 -0
  319. package/apps/web/.next/static/chunks/app/api/env-vars/route-07f0f73ac9839899.js +1 -0
  320. package/apps/web/.next/static/chunks/app/api/jobs/[id]/route-07f0f73ac9839899.js +1 -0
  321. package/apps/web/.next/static/chunks/app/api/jobs/[id]/runs/route-07f0f73ac9839899.js +1 -0
  322. package/apps/web/.next/static/chunks/app/api/jobs/route-07f0f73ac9839899.js +1 -0
  323. package/apps/web/.next/static/chunks/app/api/mcps/[id]/route-07f0f73ac9839899.js +1 -0
  324. package/apps/web/.next/static/chunks/app/api/mcps/[id]/test/route-07f0f73ac9839899.js +1 -0
  325. package/apps/web/.next/static/chunks/app/api/mcps/route-07f0f73ac9839899.js +1 -0
  326. package/apps/web/.next/static/chunks/app/api/settings/route-07f0f73ac9839899.js +1 -0
  327. package/apps/web/.next/static/chunks/app/jobs/page-f5aa89a47c50efd8.js +1 -0
  328. package/apps/web/.next/static/chunks/app/layout-2079f4964aa7314e.js +1 -0
  329. package/apps/web/.next/static/chunks/app/login/layout-07f0f73ac9839899.js +1 -0
  330. package/apps/web/.next/static/chunks/app/login/page-aa259283dc38e8f9.js +1 -0
  331. package/apps/web/.next/static/chunks/app/page-e83437b608104dff.js +1 -0
  332. package/apps/web/.next/static/chunks/app/settings/env-vars/page-06479dbdfb78b76b.js +1 -0
  333. package/apps/web/.next/static/chunks/app/settings/mcps/page-75650686ed6490c7.js +1 -0
  334. package/apps/web/.next/static/chunks/app/settings/page-e1e62fc41ff6cddd.js +1 -0
  335. package/apps/web/.next/static/chunks/framework-811407f832a33072.js +1 -0
  336. package/apps/web/.next/static/chunks/main-3f1cddbdd67b1546.js +1 -0
  337. package/apps/web/.next/static/chunks/main-app-cebd8a6a5ccbf72d.js +1 -0
  338. package/apps/web/.next/static/chunks/pages/_app-50fa07b56b2d29ac.js +1 -0
  339. package/apps/web/.next/static/chunks/pages/_error-fed8688bdd23f211.js +1 -0
  340. package/apps/web/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  341. package/apps/web/.next/static/chunks/webpack-6c05566dba553c97.js +1 -0
  342. package/apps/web/.next/static/css/15371687405525e2.css +5 -0
  343. package/apps/web/.next/static/ikfNbLhuw7jntn35bz0lk/_buildManifest.js +1 -0
  344. package/apps/web/.next/static/ikfNbLhuw7jntn35bz0lk/_ssgManifest.js +1 -0
  345. package/apps/web/.next/trace +5 -0
  346. package/apps/web/.next/types/app/agents/[slug]/page.ts +84 -0
  347. package/apps/web/.next/types/app/agents/new/page.ts +84 -0
  348. package/apps/web/.next/types/app/api/agents/[id]/access/route.ts +347 -0
  349. package/apps/web/.next/types/app/api/agents/[id]/claude-md/route.ts +347 -0
  350. package/apps/web/.next/types/app/api/agents/[id]/logs/route.ts +347 -0
  351. package/apps/web/.next/types/app/api/agents/[id]/manifest/route.ts +347 -0
  352. package/apps/web/.next/types/app/api/agents/[id]/mcps/route.ts +347 -0
  353. package/apps/web/.next/types/app/api/agents/[id]/memories/[memId]/route.ts +347 -0
  354. package/apps/web/.next/types/app/api/agents/[id]/memories/route.ts +347 -0
  355. package/apps/web/.next/types/app/api/agents/[id]/permissions/route.ts +347 -0
  356. package/apps/web/.next/types/app/api/agents/[id]/reload/route.ts +347 -0
  357. package/apps/web/.next/types/app/api/agents/[id]/restrictions/route.ts +347 -0
  358. package/apps/web/.next/types/app/api/agents/[id]/route.ts +347 -0
  359. package/apps/web/.next/types/app/api/agents/[id]/skills/[skillId]/route.ts +347 -0
  360. package/apps/web/.next/types/app/api/agents/[id]/skills/route.ts +347 -0
  361. package/apps/web/.next/types/app/api/agents/[id]/slack-info/route.ts +347 -0
  362. package/apps/web/.next/types/app/api/agents/[id]/snapshots/[sid]/restore/route.ts +347 -0
  363. package/apps/web/.next/types/app/api/agents/[id]/snapshots/[sid]/route.ts +347 -0
  364. package/apps/web/.next/types/app/api/agents/[id]/snapshots/route.ts +347 -0
  365. package/apps/web/.next/types/app/api/agents/[id]/start/route.ts +347 -0
  366. package/apps/web/.next/types/app/api/agents/[id]/stop/route.ts +347 -0
  367. package/apps/web/.next/types/app/api/agents/route.ts +347 -0
  368. package/apps/web/.next/types/app/api/auth/login/route.ts +347 -0
  369. package/apps/web/.next/types/app/api/auth/logout/route.ts +347 -0
  370. package/apps/web/.next/types/app/api/auth/me/route.ts +347 -0
  371. package/apps/web/.next/types/app/api/auth/users/[id]/route.ts +347 -0
  372. package/apps/web/.next/types/app/api/auth/users/route.ts +347 -0
  373. package/apps/web/.next/types/app/api/env-vars/[key]/route.ts +347 -0
  374. package/apps/web/.next/types/app/api/env-vars/route.ts +347 -0
  375. package/apps/web/.next/types/app/api/jobs/[id]/route.ts +347 -0
  376. package/apps/web/.next/types/app/api/jobs/[id]/runs/route.ts +347 -0
  377. package/apps/web/.next/types/app/api/jobs/route.ts +347 -0
  378. package/apps/web/.next/types/app/api/mcps/[id]/route.ts +347 -0
  379. package/apps/web/.next/types/app/api/mcps/[id]/test/route.ts +347 -0
  380. package/apps/web/.next/types/app/api/mcps/route.ts +347 -0
  381. package/apps/web/.next/types/app/api/settings/route.ts +347 -0
  382. package/apps/web/.next/types/app/jobs/page.ts +84 -0
  383. package/apps/web/.next/types/app/login/layout.ts +84 -0
  384. package/apps/web/.next/types/app/login/page.ts +84 -0
  385. package/apps/web/.next/types/app/page.ts +84 -0
  386. package/apps/web/.next/types/app/settings/env-vars/page.ts +84 -0
  387. package/apps/web/.next/types/app/settings/mcps/page.ts +84 -0
  388. package/apps/web/.next/types/app/settings/page.ts +84 -0
  389. package/apps/web/.next/types/cache-life.d.ts +141 -0
  390. package/apps/web/.next/types/package.json +1 -0
  391. package/apps/web/.next/types/routes.d.ts +114 -0
  392. package/apps/web/.next/types/validator.ts +448 -0
  393. package/apps/web/Dockerfile +37 -0
  394. package/apps/web/next-env.d.ts +6 -0
  395. package/apps/web/next.config.js +6 -0
  396. package/apps/web/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  397. package/apps/web/package.json +48 -0
  398. package/apps/web/postcss.config.js +3 -0
  399. package/apps/web/public/logo.svg +17 -0
  400. package/apps/web/src/app/agents/[slug]/page.tsx +2235 -0
  401. package/apps/web/src/app/agents/new/page.tsx +1161 -0
  402. package/apps/web/src/app/api/agents/[id]/access/route.ts +76 -0
  403. package/apps/web/src/app/api/agents/[id]/claude-md/route.ts +111 -0
  404. package/apps/web/src/app/api/agents/[id]/logs/route.ts +84 -0
  405. package/apps/web/src/app/api/agents/[id]/manifest/route.ts +32 -0
  406. package/apps/web/src/app/api/agents/[id]/mcps/route.ts +73 -0
  407. package/apps/web/src/app/api/agents/[id]/memories/[memId]/route.ts +31 -0
  408. package/apps/web/src/app/api/agents/[id]/memories/route.ts +56 -0
  409. package/apps/web/src/app/api/agents/[id]/permissions/route.ts +74 -0
  410. package/apps/web/src/app/api/agents/[id]/reload/route.ts +33 -0
  411. package/apps/web/src/app/api/agents/[id]/restrictions/route.ts +85 -0
  412. package/apps/web/src/app/api/agents/[id]/route.ts +81 -0
  413. package/apps/web/src/app/api/agents/[id]/skills/[skillId]/route.ts +52 -0
  414. package/apps/web/src/app/api/agents/[id]/skills/route.ts +80 -0
  415. package/apps/web/src/app/api/agents/[id]/slack-info/route.ts +38 -0
  416. package/apps/web/src/app/api/agents/[id]/snapshots/[sid]/restore/route.ts +61 -0
  417. package/apps/web/src/app/api/agents/[id]/snapshots/[sid]/route.ts +53 -0
  418. package/apps/web/src/app/api/agents/[id]/snapshots/route.ts +84 -0
  419. package/apps/web/src/app/api/agents/[id]/start/route.ts +35 -0
  420. package/apps/web/src/app/api/agents/[id]/stop/route.ts +35 -0
  421. package/apps/web/src/app/api/agents/route.ts +99 -0
  422. package/apps/web/src/app/api/auth/login/route.ts +39 -0
  423. package/apps/web/src/app/api/auth/logout/route.ts +21 -0
  424. package/apps/web/src/app/api/auth/me/route.ts +24 -0
  425. package/apps/web/src/app/api/auth/users/[id]/route.ts +48 -0
  426. package/apps/web/src/app/api/auth/users/route.ts +63 -0
  427. package/apps/web/src/app/api/env-vars/[key]/route.ts +66 -0
  428. package/apps/web/src/app/api/env-vars/route.ts +59 -0
  429. package/apps/web/src/app/api/jobs/[id]/route.ts +51 -0
  430. package/apps/web/src/app/api/jobs/[id]/runs/route.ts +24 -0
  431. package/apps/web/src/app/api/jobs/route.ts +42 -0
  432. package/apps/web/src/app/api/mcps/[id]/route.ts +60 -0
  433. package/apps/web/src/app/api/mcps/[id]/test/route.ts +195 -0
  434. package/apps/web/src/app/api/mcps/route.ts +72 -0
  435. package/apps/web/src/app/api/settings/route.ts +42 -0
  436. package/apps/web/src/app/globals.css +124 -0
  437. package/apps/web/src/app/icon.svg +17 -0
  438. package/apps/web/src/app/jobs/page.tsx +543 -0
  439. package/apps/web/src/app/layout-shell.tsx +89 -0
  440. package/apps/web/src/app/layout.tsx +18 -0
  441. package/apps/web/src/app/login/layout.tsx +9 -0
  442. package/apps/web/src/app/login/page.tsx +150 -0
  443. package/apps/web/src/app/page.tsx +573 -0
  444. package/apps/web/src/app/settings/env-vars/page.tsx +216 -0
  445. package/apps/web/src/app/settings/mcps/page.tsx +763 -0
  446. package/apps/web/src/app/settings/page.tsx +528 -0
  447. package/apps/web/src/app/sidebar.tsx +345 -0
  448. package/apps/web/src/lib/__tests__/api-guard.test.ts +189 -0
  449. package/apps/web/src/lib/__tests__/auth.test.ts +262 -0
  450. package/apps/web/src/lib/__tests__/boss-registry.test.ts +323 -0
  451. package/apps/web/src/lib/__tests__/compile.test.ts +161 -0
  452. package/apps/web/src/lib/__tests__/db-agent-hierarchy.test.ts +136 -0
  453. package/apps/web/src/lib/__tests__/db-env-vars.test.ts +216 -0
  454. package/apps/web/src/lib/__tests__/db-restrictions.test.ts +117 -0
  455. package/apps/web/src/lib/__tests__/db.integration.test.ts +271 -0
  456. package/apps/web/src/lib/__tests__/diff.test.ts +102 -0
  457. package/apps/web/src/lib/__tests__/mcp-mask.test.ts +274 -0
  458. package/apps/web/src/lib/__tests__/skill-templates.test.ts +237 -0
  459. package/apps/web/src/lib/__tests__/slack-manifest.test.ts +105 -0
  460. package/apps/web/src/lib/api-guard.ts +68 -0
  461. package/apps/web/src/lib/auth-context.tsx +71 -0
  462. package/apps/web/src/lib/auth.ts +128 -0
  463. package/apps/web/src/lib/boss-registry.ts +90 -0
  464. package/apps/web/src/lib/compile.ts +51 -0
  465. package/apps/web/src/lib/db.ts +1196 -0
  466. package/apps/web/src/lib/diff.ts +43 -0
  467. package/apps/web/src/lib/mcp-mask.ts +91 -0
  468. package/apps/web/src/lib/portal.tsx +23 -0
  469. package/apps/web/src/lib/skill-templates.ts +148 -0
  470. package/apps/web/src/lib/slack-manifest.ts +85 -0
  471. package/apps/web/src/middleware.ts +68 -0
  472. package/apps/web/tailwind.config.js +6 -0
  473. package/apps/web/tsconfig.json +23 -0
  474. package/apps/web/vitest.config.mts +21 -0
  475. package/cli/.claude/settings.local.json +6 -0
  476. package/cli/README.md +281 -0
  477. package/cli/node_modules/.package-lock.json +427 -0
  478. package/cli/node_modules/commander/LICENSE +22 -0
  479. package/cli/node_modules/commander/Readme.md +1157 -0
  480. package/cli/node_modules/commander/esm.mjs +16 -0
  481. package/cli/node_modules/commander/index.js +24 -0
  482. package/cli/node_modules/commander/lib/argument.js +149 -0
  483. package/cli/node_modules/commander/lib/command.js +2509 -0
  484. package/cli/node_modules/commander/lib/error.js +39 -0
  485. package/cli/node_modules/commander/lib/help.js +520 -0
  486. package/cli/node_modules/commander/lib/option.js +330 -0
  487. package/cli/node_modules/commander/lib/suggestSimilar.js +101 -0
  488. package/cli/node_modules/commander/package-support.json +16 -0
  489. package/cli/node_modules/commander/package.json +84 -0
  490. package/cli/node_modules/commander/typings/esm.d.mts +3 -0
  491. package/cli/node_modules/commander/typings/index.d.ts +969 -0
  492. package/cli/package-lock.json +449 -0
  493. package/cli/package.json +44 -0
  494. package/cli/src/commands/init.ts +514 -0
  495. package/cli/src/commands/manage.ts +115 -0
  496. package/cli/src/index.ts +63 -0
  497. package/cli/tsconfig.json +14 -0
  498. package/docker-compose.yml +122 -0
  499. package/docs/agents/boss-agents.mdx +108 -0
  500. package/docs/agents/creating-agents.mdx +132 -0
  501. package/docs/agents/memory.mdx +113 -0
  502. package/docs/agents/tools.mdx +103 -0
  503. package/docs/configuration/env-vars.mdx +166 -0
  504. package/docs/configuration/mcp-servers.mdx +203 -0
  505. package/docs/configuration/slack-app.mdx +175 -0
  506. package/docs/docs.json +79 -0
  507. package/docs/favicon.svg +17 -0
  508. package/docs/features/history.mdx +60 -0
  509. package/docs/features/import-export.mdx +77 -0
  510. package/docs/features/logs.mdx +131 -0
  511. package/docs/features/multi-workspace.mdx +90 -0
  512. package/docs/features/scheduled-jobs.mdx +231 -0
  513. package/docs/features/users.mdx +92 -0
  514. package/docs/introduction.mdx +160 -0
  515. package/docs/logo/dark.svg +17 -0
  516. package/docs/logo/light.svg +17 -0
  517. package/docs/logo/wide-dark.svg +12 -0
  518. package/docs/logo/wide-light.svg +12 -0
  519. package/docs/quickstart.mdx +270 -0
  520. package/docs/self-hosting/docker.mdx +151 -0
  521. package/docs/self-hosting/production.mdx +176 -0
  522. package/package.json +20 -36
  523. package/packages/shared/dist/index.d.ts +8 -0
  524. package/packages/shared/dist/index.d.ts.map +1 -0
  525. package/packages/shared/dist/index.js +24 -0
  526. package/packages/shared/dist/index.js.map +1 -0
  527. package/packages/shared/dist/types.d.ts +584 -0
  528. package/packages/shared/dist/types.d.ts.map +1 -0
  529. package/packages/shared/dist/types.js +39 -0
  530. package/packages/shared/dist/types.js.map +1 -0
  531. package/packages/shared/package.json +15 -0
  532. package/packages/shared/src/db/schema.sql +354 -0
  533. package/packages/shared/src/index.ts +8 -0
  534. package/packages/shared/src/types.ts +683 -0
  535. package/packages/shared/tsconfig.json +17 -0
  536. package/scripts/dev.sh +45 -0
  537. /package/{dist → cli/dist}/commands/init.d.ts +0 -0
  538. /package/{dist → cli/dist}/commands/init.js +0 -0
  539. /package/{dist → cli/dist}/commands/manage.d.ts +0 -0
  540. /package/{dist → cli/dist}/commands/manage.js +0 -0
  541. /package/{dist → cli/dist}/index.d.ts +0 -0
  542. /package/{dist → cli/dist}/index.js +0 -0
@@ -0,0 +1,76 @@
1
+ /**
2
+ * @fileoverview Agent write-access management API.
3
+ *
4
+ * GET /api/agents/[id]/access — List users with explicit write access
5
+ * POST /api/agents/[id]/access — Grant write access to a user
6
+ * DELETE /api/agents/[id]/access — Revoke write access from a user
7
+ *
8
+ * @module web/api/agents/[id]/access
9
+ */
10
+
11
+ import { NextRequest, NextResponse } from 'next/server';
12
+ import { guardAdmin } from '@/lib/api-guard';
13
+ import { getAgentWriteUsers, grantAgentWrite, revokeAgentWrite, getAllUsers, userCanWriteAgent } from '@/lib/db';
14
+ import { getSessionFromRequest } from '@/lib/auth';
15
+
16
+ /**
17
+ * GET /api/agents/[id]/access
18
+ * - For admins: returns write-grant list + all users for the assignment UI.
19
+ * - For editors/viewers: returns { canWrite: bool } for the current session user.
20
+ */
21
+ export async function GET(
22
+ req: NextRequest,
23
+ { params }: { params: Promise<{ id: string }> }
24
+ ): Promise<NextResponse> {
25
+ const { id } = await params;
26
+ const session = getSessionFromRequest(req);
27
+ if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
28
+
29
+ if (session.role === 'admin' || session.role === 'superadmin') {
30
+ const [writeUsers, allUsers] = await Promise.all([
31
+ getAgentWriteUsers(id),
32
+ getAllUsers(),
33
+ ]);
34
+ return NextResponse.json({ writeUsers, allUsers: allUsers.map(u => ({ id: u.id, username: u.username, role: u.role })) });
35
+ }
36
+
37
+ // For editors/viewers — just return their own write permission
38
+ const canWrite = await userCanWriteAgent(id, session.username, session.role);
39
+ return NextResponse.json({ canWrite });
40
+ }
41
+
42
+ /**
43
+ * POST /api/agents/[id]/access
44
+ * Grants write access to a user (admin only).
45
+ * Body: { userId: string }
46
+ */
47
+ export async function POST(
48
+ req: NextRequest,
49
+ { params }: { params: Promise<{ id: string }> }
50
+ ): Promise<NextResponse> {
51
+ const denied = guardAdmin(req);
52
+ if (denied) return denied;
53
+ const { id } = await params;
54
+ const { userId } = await req.json().catch(() => ({}));
55
+ if (!userId) return NextResponse.json({ error: 'userId required' }, { status: 400 });
56
+ await grantAgentWrite(id, userId);
57
+ return new NextResponse(null, { status: 204 });
58
+ }
59
+
60
+ /**
61
+ * DELETE /api/agents/[id]/access
62
+ * Revokes write access from a user (admin only).
63
+ * Body: { userId: string }
64
+ */
65
+ export async function DELETE(
66
+ req: NextRequest,
67
+ { params }: { params: Promise<{ id: string }> }
68
+ ): Promise<NextResponse> {
69
+ const denied = guardAdmin(req);
70
+ if (denied) return denied;
71
+ const { id } = await params;
72
+ const { userId } = await req.json().catch(() => ({}));
73
+ if (!userId) return NextResponse.json({ error: 'userId required' }, { status: 400 });
74
+ await revokeAgentWrite(id, userId);
75
+ return new NextResponse(null, { status: 204 });
76
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @fileoverview REST API routes for an agent's CLAUDE.md instruction file.
3
+ *
4
+ * CLAUDE.md is the agent's main identity/instruction file, stored as
5
+ * agents.claude_md in the database. It is separate from skills — skills
6
+ * are Claude Code slash commands written to .claude/commands/ at runtime.
7
+ *
8
+ * GET /api/agents/[id]/claude-md — Returns the stored CLAUDE.md content
9
+ * with memories appended (read-only view).
10
+ * PUT /api/agents/[id]/claude-md — Updates agents.claude_md directly.
11
+ *
12
+ * @module web/api/agents/[id]/claude-md
13
+ */
14
+
15
+ import { NextRequest, NextResponse } from 'next/server';
16
+ import { getAgentById, getAgentMemories, updateAgentClaudeMd, publishAgentEvent, getAgentSkills, getAgentPermissions, getAgentMcpServers, createSnapshot } from '@/lib/db';
17
+ import { guardAgentWrite } from '@/lib/api-guard';
18
+ import { getSessionFromRequest } from '@/lib/auth';
19
+ import { skillToSnapshotSkill } from '@/lib/compile';
20
+
21
+ /**
22
+ * GET /api/agents/[id]/claude-md
23
+ * Returns the agent's CLAUDE.md content with memories appended.
24
+ *
25
+ * @param {NextRequest} _req
26
+ * @param {{ params: Promise<{ id: string }> }} ctx
27
+ * @returns {Promise<NextResponse>} Plain-text CLAUDE.md or 404.
28
+ */
29
+ export async function GET(
30
+ _req: NextRequest,
31
+ { params }: { params: Promise<{ id: string }> }
32
+ ) {
33
+ const { id } = await params;
34
+ const agent = await getAgentById(id);
35
+ if (!agent) return new NextResponse('Not found', { status: 404 });
36
+
37
+ const memories = await getAgentMemories(id);
38
+
39
+ const sections: string[] = [];
40
+
41
+ if (agent.claudeMd.trim()) {
42
+ sections.push(agent.claudeMd.trim());
43
+ } else {
44
+ // Fallback: minimal identity block if claude_md not yet set
45
+ const lines = [`# ${agent.name}`];
46
+ if (agent.persona) lines.push('', agent.persona);
47
+ if (agent.description) lines.push('', agent.description);
48
+ sections.push(lines.join('\n'));
49
+ }
50
+
51
+ if (memories.length > 0) {
52
+ const order = ['feedback', 'user', 'project', 'reference'];
53
+ const grouped = memories.reduce<Record<string, typeof memories>>((acc, m) => {
54
+ (acc[m.type] ??= []).push(m);
55
+ return acc;
56
+ }, {});
57
+ const memParts = order
58
+ .filter(t => grouped[t]?.length)
59
+ .map(t => `## ${t.charAt(0).toUpperCase() + t.slice(1)} Memories\n\n` +
60
+ grouped[t].map(m => `### ${m.name}\n${m.content}`).join('\n\n'));
61
+ sections.push(`# Agent Memory\n\n${memParts.join('\n\n')}`);
62
+ }
63
+
64
+ return new NextResponse(sections.join('\n\n'), {
65
+ headers: { 'Content-Type': 'text/plain; charset=utf-8' },
66
+ });
67
+ }
68
+
69
+ /**
70
+ * PUT /api/agents/[id]/claude-md
71
+ * Saves the CLAUDE.md content to agents.claude_md.
72
+ * Does NOT touch skills — skills are managed separately via /api/agents/[id]/skills.
73
+ * Body: raw text/plain content.
74
+ *
75
+ * @param {NextRequest} req
76
+ * @param {{ params: Promise<{ id: string }> }} ctx
77
+ * @returns {Promise<NextResponse>} 204 No Content or error.
78
+ */
79
+ export async function PUT(
80
+ req: NextRequest,
81
+ { params }: { params: Promise<{ id: string }> }
82
+ ) {
83
+ const { id } = await params;
84
+ const denied = await guardAgentWrite(req, id);
85
+ if (denied) return denied;
86
+ const agent = await getAgentById(id);
87
+ if (!agent) return new NextResponse('Not found', { status: 404 });
88
+
89
+ const content = await req.text();
90
+ if (!content.trim()) return new NextResponse('Empty content', { status: 400 });
91
+
92
+ // Snapshot current state before overwriting
93
+ const session = getSessionFromRequest(req);
94
+ const [currentSkills, currentPerms, currentMcps] = await Promise.all([
95
+ getAgentSkills(id),
96
+ getAgentPermissions(id),
97
+ getAgentMcpServers(id),
98
+ ]);
99
+ await createSnapshot(
100
+ id, 'claude-md', session?.username ?? 'system', null,
101
+ currentSkills.map(skillToSnapshotSkill),
102
+ currentPerms?.allowedTools ?? [],
103
+ currentPerms?.deniedTools ?? [],
104
+ currentMcps.map(m => m.id),
105
+ agent.claudeMd,
106
+ ).catch(() => {});
107
+
108
+ await updateAgentClaudeMd(id, content);
109
+ await publishAgentEvent({ type: 'reload', agentId: id });
110
+ return new NextResponse(null, { status: 204 });
111
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * @fileoverview GET /api/agents/[id]/logs
3
+ * Server-Sent Events (SSE) stream of live runner logs for a specific agent.
4
+ * Reads from the runner container's stdout via Docker logs API.
5
+ *
6
+ * NOTE: In Docker Compose, this uses `docker logs --follow --tail=100 <runner>`.
7
+ * The runner prefixes each log line with `[agentSlug]` so we filter by agent.
8
+ *
9
+ * @module web/api/agents/[id]/logs
10
+ */
11
+
12
+ import { NextRequest } from 'next/server';
13
+ import { getAgentById } from '@/lib/db';
14
+ import { spawn } from 'child_process';
15
+
16
+ /**
17
+ * GET /api/agents/[id]/logs
18
+ * Returns an SSE stream of filtered log lines for the agent.
19
+ *
20
+ * @param {NextRequest} _req
21
+ * @param {{ params: Promise<{ id: string }> }} ctx
22
+ * @returns {Response} SSE stream.
23
+ */
24
+ export async function GET(
25
+ _req: NextRequest,
26
+ { params }: { params: Promise<{ id: string }> }
27
+ ): Promise<Response> {
28
+ const { id } = await params;
29
+ const agent = await getAgentById(id).catch(() => null);
30
+ const slug = agent?.slug ?? id;
31
+
32
+ const encoder = new TextEncoder();
33
+
34
+ const stream = new ReadableStream({
35
+ start(controller) {
36
+ // Tail the runner container logs, filtering for lines containing [slug]
37
+ const proc = spawn('docker', [
38
+ 'logs', '--follow', '--tail=200',
39
+ 'slackhive-runner-1',
40
+ ]);
41
+
42
+ function send(line: string) {
43
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(line)}\n\n`));
44
+ }
45
+
46
+ let buffer = '';
47
+ proc.stdout.on('data', (chunk: Buffer) => {
48
+ buffer += chunk.toString();
49
+ const lines = buffer.split('\n');
50
+ buffer = lines.pop() ?? '';
51
+ for (const line of lines) {
52
+ if (line.includes(`"agent":"${slug}"`)) send(line);
53
+ }
54
+ });
55
+
56
+ proc.stderr.on('data', (chunk: Buffer) => {
57
+ buffer += chunk.toString();
58
+ const lines = buffer.split('\n');
59
+ buffer = lines.pop() ?? '';
60
+ for (const line of lines) {
61
+ if (line.includes(`"agent":"${slug}"`)) send(line);
62
+ }
63
+ });
64
+
65
+ proc.on('close', () => {
66
+ try { controller.close(); } catch { /* already closed */ }
67
+ });
68
+
69
+ // Clean up if client disconnects
70
+ _req.signal.addEventListener('abort', () => {
71
+ proc.kill();
72
+ try { controller.close(); } catch { /* already closed */ }
73
+ });
74
+ },
75
+ });
76
+
77
+ return new Response(stream, {
78
+ headers: {
79
+ 'Content-Type': 'text/event-stream',
80
+ 'Cache-Control': 'no-cache',
81
+ 'Connection': 'keep-alive',
82
+ },
83
+ });
84
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @fileoverview GET /api/agents/[id]/manifest
3
+ * Returns a generated Slack app manifest JSON for the agent onboarding wizard.
4
+ * Paste the output into api.slack.com/apps → Create from Manifest.
5
+ *
6
+ * @module web/api/agents/[id]/manifest
7
+ */
8
+
9
+ import { NextRequest, NextResponse } from 'next/server';
10
+ import { getAgentById } from '@/lib/db';
11
+ import { generateSlackManifest } from '@/lib/slack-manifest';
12
+
13
+ type RouteParams = { params: Promise<{ id: string }> };
14
+
15
+ /**
16
+ * GET /api/agents/[id]/manifest
17
+ *
18
+ * @param {NextRequest} _req
19
+ * @param {RouteParams} ctx
20
+ * @returns {Promise<NextResponse>} SlackAppManifest JSON or error.
21
+ */
22
+ export async function GET(_req: NextRequest, { params }: RouteParams): Promise<NextResponse> {
23
+ try {
24
+ const { id } = await params;
25
+ const agent = await getAgentById(id);
26
+ if (!agent) return NextResponse.json({ error: 'Not found' }, { status: 404 });
27
+ const manifest = generateSlackManifest({ name: agent.name, description: agent.description, isBoss: agent.isBoss });
28
+ return NextResponse.json(manifest);
29
+ } catch (err) {
30
+ return NextResponse.json({ error: (err as Error).message }, { status: 500 });
31
+ }
32
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @fileoverview REST API routes for agent MCP assignments.
3
+ *
4
+ * GET /api/agents/[id]/mcps — List MCPs assigned to this agent
5
+ * PUT /api/agents/[id]/mcps — Replace all MCP assignments, then trigger reload
6
+ *
7
+ * @module web/api/agents/[id]/mcps
8
+ */
9
+
10
+ import { NextRequest, NextResponse } from 'next/server';
11
+ import { getAgentById, getAgentSkills, getAgentPermissions, getAgentMcpServers, setAgentMcps, publishAgentEvent, createSnapshot } from '@/lib/db';
12
+ import { guardAgentWrite } from '@/lib/api-guard';
13
+ import { getSessionFromRequest } from '@/lib/auth';
14
+ import { skillToSnapshotSkill } from '@/lib/compile';
15
+
16
+ type RouteParams = { params: Promise<{ id: string }> };
17
+
18
+ /**
19
+ * GET /api/agents/[id]/mcps
20
+ *
21
+ * @param {NextRequest} _req
22
+ * @param {RouteParams} ctx
23
+ * @returns {Promise<NextResponse>} JSON array of assigned McpServer objects.
24
+ */
25
+ export async function GET(_req: NextRequest, { params }: RouteParams): Promise<NextResponse> {
26
+ try {
27
+ const { id } = await params;
28
+ const mcps = await getAgentMcpServers(id);
29
+ return NextResponse.json(mcps);
30
+ } catch (err) {
31
+ return NextResponse.json({ error: (err as Error).message }, { status: 500 });
32
+ }
33
+ }
34
+
35
+ /**
36
+ * PUT /api/agents/[id]/mcps
37
+ * Replaces all MCP assignments for an agent and triggers a reload.
38
+ *
39
+ * @param {NextRequest} req - Body: { mcpIds: string[] }
40
+ * @param {RouteParams} ctx
41
+ * @returns {Promise<NextResponse>} 200 ok or error.
42
+ */
43
+ export async function PUT(req: NextRequest, { params }: RouteParams): Promise<NextResponse> {
44
+ try {
45
+ const { id } = await params;
46
+ const denied = await guardAgentWrite(req, id);
47
+ if (denied) return denied;
48
+ const { mcpIds } = (await req.json()) as { mcpIds: string[] };
49
+
50
+ // Snapshot before mutation
51
+ const session = getSessionFromRequest(req);
52
+ const [agent, currentSkills, perms, currentMcps] = await Promise.all([
53
+ getAgentById(id),
54
+ getAgentSkills(id),
55
+ getAgentPermissions(id),
56
+ getAgentMcpServers(id),
57
+ ]);
58
+ await createSnapshot(
59
+ id, 'mcps', session?.username ?? 'system', null,
60
+ currentSkills.map(skillToSnapshotSkill),
61
+ perms?.allowedTools ?? [],
62
+ perms?.deniedTools ?? [],
63
+ currentMcps.map(m => m.id),
64
+ agent?.claudeMd ?? '',
65
+ ).catch(() => {});
66
+
67
+ await setAgentMcps(id, mcpIds ?? []);
68
+ await publishAgentEvent({ type: 'reload', agentId: id });
69
+ return NextResponse.json({ ok: true });
70
+ } catch (err) {
71
+ return NextResponse.json({ error: (err as Error).message }, { status: 500 });
72
+ }
73
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @fileoverview DELETE /api/agents/[id]/memories/[memId]
3
+ * Removes a single memory entry for an agent.
4
+ *
5
+ * @module web/api/agents/[id]/memories/[memId]
6
+ */
7
+
8
+ import { NextRequest, NextResponse } from 'next/server';
9
+ import { deleteMemory } from '@/lib/db';
10
+ import { guardAgentWrite } from '@/lib/api-guard';
11
+
12
+ type RouteParams = { params: Promise<{ id: string; memId: string }> };
13
+
14
+ /**
15
+ * DELETE /api/agents/[id]/memories/[memId]
16
+ *
17
+ * @param {NextRequest} _req
18
+ * @param {RouteParams} ctx
19
+ * @returns {Promise<NextResponse>} 204 No Content or error.
20
+ */
21
+ export async function DELETE(req: NextRequest, { params }: RouteParams): Promise<NextResponse> {
22
+ try {
23
+ const { id, memId } = await params;
24
+ const denied = await guardAgentWrite(req, id);
25
+ if (denied) return denied;
26
+ await deleteMemory(memId);
27
+ return new NextResponse(null, { status: 204 });
28
+ } catch (err) {
29
+ return NextResponse.json({ error: (err as Error).message }, { status: 500 });
30
+ }
31
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @fileoverview REST API routes for agent memories.
3
+ *
4
+ * GET /api/agents/[id]/memories — List all memories for an agent
5
+ * POST /api/agents/[id]/memories — Create or update a memory entry
6
+ *
7
+ * @module web/api/agents/[id]/memories
8
+ */
9
+
10
+ import { NextRequest, NextResponse } from 'next/server';
11
+ import { getAgentMemories, upsertMemory } from '@/lib/db';
12
+ import type { UpsertMemoryRequest } from '@slackhive/shared';
13
+ import { guardAgentWrite } from '@/lib/api-guard';
14
+
15
+ type RouteParams = { params: Promise<{ id: string }> };
16
+
17
+ /**
18
+ * GET /api/agents/[id]/memories
19
+ *
20
+ * @param {NextRequest} _req
21
+ * @param {RouteParams} ctx
22
+ * @returns {Promise<NextResponse>} JSON array of Memory objects.
23
+ */
24
+ export async function GET(_req: NextRequest, { params }: RouteParams): Promise<NextResponse> {
25
+ try {
26
+ const { id } = await params;
27
+ const memories = await getAgentMemories(id);
28
+ return NextResponse.json(memories);
29
+ } catch (err) {
30
+ return NextResponse.json({ error: (err as Error).message }, { status: 500 });
31
+ }
32
+ }
33
+
34
+ /**
35
+ * POST /api/agents/[id]/memories
36
+ * Creates or updates a memory entry.
37
+ *
38
+ * @param {NextRequest} req - Body: UpsertMemoryRequest
39
+ * @param {RouteParams} ctx
40
+ * @returns {Promise<NextResponse>} The upserted Memory or error.
41
+ */
42
+ export async function POST(req: NextRequest, { params }: RouteParams): Promise<NextResponse> {
43
+ try {
44
+ const { id } = await params;
45
+ const denied = await guardAgentWrite(req, id);
46
+ if (denied) return denied;
47
+ const body = (await req.json()) as UpsertMemoryRequest;
48
+ if (!body.type || !body.name || !body.content) {
49
+ return NextResponse.json({ error: 'type, name, content are required' }, { status: 400 });
50
+ }
51
+ const memory = await upsertMemory(id, body.type, body.name, body.content);
52
+ return NextResponse.json(memory, { status: 201 });
53
+ } catch (err) {
54
+ return NextResponse.json({ error: (err as Error).message }, { status: 500 });
55
+ }
56
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @fileoverview REST API routes for agent tool permissions.
3
+ *
4
+ * GET /api/agents/[id]/permissions — Get current permissions
5
+ * PUT /api/agents/[id]/permissions — Replace permissions, then trigger reload
6
+ *
7
+ * @module web/api/agents/[id]/permissions
8
+ */
9
+
10
+ import { NextRequest, NextResponse } from 'next/server';
11
+ import { getAgentById, getAgentSkills, getAgentPermissions, getAgentMcpServers, upsertPermissions, publishAgentEvent, createSnapshot } from '@/lib/db';
12
+ import type { UpdatePermissionsRequest } from '@slackhive/shared';
13
+ import { guardAgentWrite } from '@/lib/api-guard';
14
+ import { getSessionFromRequest } from '@/lib/auth';
15
+ import { skillToSnapshotSkill } from '@/lib/compile';
16
+
17
+ type RouteParams = { params: Promise<{ id: string }> };
18
+
19
+ /**
20
+ * GET /api/agents/[id]/permissions
21
+ *
22
+ * @param {NextRequest} _req
23
+ * @param {RouteParams} ctx
24
+ * @returns {Promise<NextResponse>} Permission object or null.
25
+ */
26
+ export async function GET(_req: NextRequest, { params }: RouteParams): Promise<NextResponse> {
27
+ try {
28
+ const { id } = await params;
29
+ const perms = await getAgentPermissions(id);
30
+ return NextResponse.json(perms ?? { allowedTools: [], deniedTools: [] });
31
+ } catch (err) {
32
+ return NextResponse.json({ error: (err as Error).message }, { status: 500 });
33
+ }
34
+ }
35
+
36
+ /**
37
+ * PUT /api/agents/[id]/permissions
38
+ * Replaces all tool permissions for an agent.
39
+ *
40
+ * @param {NextRequest} req - Body: { allowedTools: string[], deniedTools: string[] }
41
+ * @param {RouteParams} ctx
42
+ * @returns {Promise<NextResponse>} 200 ok or error.
43
+ */
44
+ export async function PUT(req: NextRequest, { params }: RouteParams): Promise<NextResponse> {
45
+ try {
46
+ const { id } = await params;
47
+ const denied = await guardAgentWrite(req, id);
48
+ if (denied) return denied;
49
+ const body = (await req.json()) as UpdatePermissionsRequest;
50
+
51
+ // Snapshot before mutation
52
+ const session = getSessionFromRequest(req);
53
+ const [agent, currentSkills, perms, mcps] = await Promise.all([
54
+ getAgentById(id),
55
+ getAgentSkills(id),
56
+ getAgentPermissions(id),
57
+ getAgentMcpServers(id),
58
+ ]);
59
+ await createSnapshot(
60
+ id, 'permissions', session?.username ?? 'system', null,
61
+ currentSkills.map(skillToSnapshotSkill),
62
+ perms?.allowedTools ?? [],
63
+ perms?.deniedTools ?? [],
64
+ mcps.map(m => m.id),
65
+ agent?.claudeMd ?? '',
66
+ ).catch(() => {});
67
+
68
+ await upsertPermissions(id, body.allowedTools ?? [], body.deniedTools ?? []);
69
+ await publishAgentEvent({ type: 'reload', agentId: id });
70
+ return NextResponse.json({ ok: true });
71
+ } catch (err) {
72
+ return NextResponse.json({ error: (err as Error).message }, { status: 500 });
73
+ }
74
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @fileoverview POST /api/agents/[id]/reload
3
+ * Publishes a reload event: runner stops the agent, recompiles CLAUDE.md, and restarts it.
4
+ *
5
+ * @module web/api/agents/[id]/reload
6
+ */
7
+
8
+ import { NextRequest, NextResponse } from 'next/server';
9
+ import { getAgentById, publishAgentEvent } from '@/lib/db';
10
+ import { guardAgentWrite } from '@/lib/api-guard';
11
+
12
+ type RouteParams = { params: Promise<{ id: string }> };
13
+
14
+ /**
15
+ * POST /api/agents/[id]/reload
16
+ *
17
+ * @param {NextRequest} _req
18
+ * @param {RouteParams} ctx
19
+ * @returns {Promise<NextResponse>} 200 on success, 404 or 500 on error.
20
+ */
21
+ export async function POST(req: NextRequest, { params }: RouteParams): Promise<NextResponse> {
22
+ try {
23
+ const { id } = await params;
24
+ const denied = await guardAgentWrite(req, id);
25
+ if (denied) return denied;
26
+ const agent = await getAgentById(id);
27
+ if (!agent) return NextResponse.json({ error: 'Not found' }, { status: 404 });
28
+ await publishAgentEvent({ type: 'reload', agentId: id });
29
+ return NextResponse.json({ ok: true });
30
+ } catch (err) {
31
+ return NextResponse.json({ error: (err as Error).message }, { status: 500 });
32
+ }
33
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * @fileoverview REST API routes for per-agent channel restrictions.
3
+ *
4
+ * GET /api/agents/[id]/restrictions — Get current restrictions
5
+ * PUT /api/agents/[id]/restrictions — Replace restrictions, then trigger reload
6
+ *
7
+ * @module web/api/agents/[id]/restrictions
8
+ */
9
+
10
+ import { NextRequest, NextResponse } from 'next/server';
11
+ import {
12
+ getAgentById,
13
+ getAgentSkills,
14
+ getAgentPermissions,
15
+ getAgentMcpServers,
16
+ getAgentRestrictions,
17
+ upsertRestrictions,
18
+ publishAgentEvent,
19
+ createSnapshot,
20
+ } from '@/lib/db';
21
+ import type { UpdateRestrictionsRequest } from '@slackhive/shared';
22
+ import { guardAgentWrite } from '@/lib/api-guard';
23
+ import { getSessionFromRequest } from '@/lib/auth';
24
+ import { skillToSnapshotSkill } from '@/lib/compile';
25
+
26
+ type RouteParams = { params: Promise<{ id: string }> };
27
+
28
+ /**
29
+ * GET /api/agents/[id]/restrictions
30
+ *
31
+ * @param {NextRequest} _req
32
+ * @param {RouteParams} ctx
33
+ * @returns {Promise<NextResponse>} Restriction object or empty default.
34
+ */
35
+ export async function GET(_req: NextRequest, { params }: RouteParams): Promise<NextResponse> {
36
+ try {
37
+ const { id } = await params;
38
+ const restrictions = await getAgentRestrictions(id);
39
+ return NextResponse.json(restrictions ?? { allowedChannels: [] });
40
+ } catch (err) {
41
+ return NextResponse.json({ error: (err as Error).message }, { status: 500 });
42
+ }
43
+ }
44
+
45
+ /**
46
+ * PUT /api/agents/[id]/restrictions
47
+ * Replaces channel restrictions for an agent.
48
+ *
49
+ * @param {NextRequest} req - Body: { allowedChannels: string[] }
50
+ * @param {RouteParams} ctx
51
+ * @returns {Promise<NextResponse>} 200 ok or error.
52
+ */
53
+ export async function PUT(req: NextRequest, { params }: RouteParams): Promise<NextResponse> {
54
+ try {
55
+ const { id } = await params;
56
+ const denied = await guardAgentWrite(req, id);
57
+ if (denied) return denied;
58
+ const body = (await req.json()) as UpdateRestrictionsRequest;
59
+
60
+ // Snapshot before mutation
61
+ const session = getSessionFromRequest(req);
62
+ const [agent, currentSkills, perms, mcps, currentRestrictions] = await Promise.all([
63
+ getAgentById(id),
64
+ getAgentSkills(id),
65
+ getAgentPermissions(id),
66
+ getAgentMcpServers(id),
67
+ getAgentRestrictions(id),
68
+ ]);
69
+ await createSnapshot(
70
+ id, 'restrictions', session?.username ?? 'system', null,
71
+ currentSkills.map(skillToSnapshotSkill),
72
+ perms?.allowedTools ?? [],
73
+ perms?.deniedTools ?? [],
74
+ mcps.map(m => m.id),
75
+ agent?.claudeMd ?? '',
76
+ currentRestrictions?.allowedChannels ?? [],
77
+ ).catch(() => {});
78
+
79
+ await upsertRestrictions(id, body.allowedChannels ?? []);
80
+ await publishAgentEvent({ type: 'reload', agentId: id });
81
+ return NextResponse.json({ ok: true });
82
+ } catch (err) {
83
+ return NextResponse.json({ error: (err as Error).message }, { status: 500 });
84
+ }
85
+ }