@bevel-software/platform-core-backend 0.7.5 → 0.9.0

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 (282) hide show
  1. package/LICENSE +202 -202
  2. package/THIRD-PARTY-NOTICES.md +428 -454
  3. package/dist/core/core-ports.d.ts +8 -1
  4. package/dist/core/core-ports.d.ts.map +1 -1
  5. package/dist/core/core-ports.js.map +1 -1
  6. package/dist/core/create-core-server.d.ts.map +1 -1
  7. package/dist/core/create-core-server.js +75 -18
  8. package/dist/core/create-core-server.js.map +1 -1
  9. package/dist/core/create-core-services.d.ts +12 -5
  10. package/dist/core/create-core-services.d.ts.map +1 -1
  11. package/dist/core/create-core-services.js +69 -36
  12. package/dist/core/create-core-services.js.map +1 -1
  13. package/dist/modules/access/access-control.interface.d.ts +8 -7
  14. package/dist/modules/access/access-control.interface.d.ts.map +1 -1
  15. package/dist/modules/access/access-control.service.d.ts +1 -1
  16. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  17. package/dist/modules/access/access-control.service.js +6 -6
  18. package/dist/modules/access/access-control.service.js.map +1 -1
  19. package/dist/modules/access/access-declarations.d.ts +5 -5
  20. package/dist/modules/access/access-declarations.js +3 -3
  21. package/dist/modules/access/access-mutation.service.d.ts +3 -3
  22. package/dist/modules/access/access-mutation.service.d.ts.map +1 -1
  23. package/dist/modules/access/access-mutation.service.js +3 -3
  24. package/dist/modules/access/access-mutation.service.js.map +1 -1
  25. package/dist/modules/access/access-splice.js +4 -4
  26. package/dist/modules/access/access-splice.js.map +1 -1
  27. package/dist/modules/access/access.routes.d.ts +3 -1
  28. package/dist/modules/access/access.routes.d.ts.map +1 -1
  29. package/dist/modules/access/access.routes.js +22 -20
  30. package/dist/modules/access/access.routes.js.map +1 -1
  31. package/dist/modules/access/creator-access.d.ts +2 -2
  32. package/dist/modules/access/creator-access.js +5 -5
  33. package/dist/modules/access/creator-access.js.map +1 -1
  34. package/dist/modules/access/render-roles-yaml.d.ts +22 -0
  35. package/dist/modules/access/render-roles-yaml.d.ts.map +1 -0
  36. package/dist/modules/access/render-roles-yaml.js +56 -0
  37. package/dist/modules/access/render-roles-yaml.js.map +1 -0
  38. package/dist/modules/access/roles-admin.service.d.ts +33 -5
  39. package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
  40. package/dist/modules/access/roles-admin.service.js +44 -19
  41. package/dist/modules/access/roles-admin.service.js.map +1 -1
  42. package/dist/modules/code-mode/code-mode-names.d.ts +5 -13
  43. package/dist/modules/code-mode/code-mode-names.d.ts.map +1 -1
  44. package/dist/modules/code-mode/code-mode-names.js +5 -27
  45. package/dist/modules/code-mode/code-mode-names.js.map +1 -1
  46. package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -1
  47. package/dist/modules/code-mode/code-mode.tool.js +29 -7
  48. package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
  49. package/dist/modules/mcp/mcp.service.d.ts +11 -52
  50. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  51. package/dist/modules/mcp/mcp.service.js +33 -395
  52. package/dist/modules/mcp/mcp.service.js.map +1 -1
  53. package/dist/modules/plugins/index.d.ts +7 -0
  54. package/dist/modules/plugins/index.d.ts.map +1 -0
  55. package/dist/modules/plugins/index.js +6 -0
  56. package/dist/modules/plugins/index.js.map +1 -0
  57. package/dist/modules/plugins/join-proposals.d.ts +53 -0
  58. package/dist/modules/plugins/join-proposals.d.ts.map +1 -0
  59. package/dist/modules/plugins/join-proposals.js +67 -0
  60. package/dist/modules/plugins/join-proposals.js.map +1 -0
  61. package/dist/modules/plugins/join-requests.service.d.ts +81 -0
  62. package/dist/modules/plugins/join-requests.service.d.ts.map +1 -0
  63. package/dist/modules/plugins/join-requests.service.js +135 -0
  64. package/dist/modules/plugins/join-requests.service.js.map +1 -0
  65. package/dist/modules/plugins/plugin-provision.service.d.ts +134 -0
  66. package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -0
  67. package/dist/modules/plugins/plugin-provision.service.js +344 -0
  68. package/dist/modules/plugins/plugin-provision.service.js.map +1 -0
  69. package/dist/modules/plugins/plugins.contract.d.ts +106 -0
  70. package/dist/modules/plugins/plugins.contract.d.ts.map +1 -0
  71. package/dist/modules/plugins/plugins.contract.js +36 -0
  72. package/dist/modules/plugins/plugins.contract.js.map +1 -0
  73. package/dist/modules/plugins/plugins.routes.d.ts +42 -0
  74. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -0
  75. package/dist/modules/plugins/plugins.routes.js +379 -0
  76. package/dist/modules/plugins/plugins.routes.js.map +1 -0
  77. package/dist/modules/plugins/plugins.service.d.ts +60 -0
  78. package/dist/modules/plugins/plugins.service.d.ts.map +1 -0
  79. package/dist/modules/plugins/plugins.service.js +172 -0
  80. package/dist/modules/plugins/plugins.service.js.map +1 -0
  81. package/dist/modules/settings/setup.routes.d.ts +10 -1
  82. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  83. package/dist/modules/settings/setup.routes.js +111 -6
  84. package/dist/modules/settings/setup.routes.js.map +1 -1
  85. package/dist/modules/skills/pending-skills.service.d.ts +2 -2
  86. package/dist/modules/skills/pending-skills.service.js +7 -7
  87. package/dist/modules/skills/pending-skills.service.js.map +1 -1
  88. package/dist/modules/skills/skills.contract.d.ts +4 -4
  89. package/dist/modules/skills/skills.contract.d.ts.map +1 -1
  90. package/dist/modules/skills/skills.contract.js +1 -1
  91. package/dist/modules/skills/skills.service.js +5 -5
  92. package/dist/modules/skills/skills.service.js.map +1 -1
  93. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +65 -0
  94. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -0
  95. package/dist/modules/tool-manuals/mcp-json-discovery.js +276 -0
  96. package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -0
  97. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +92 -0
  98. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -0
  99. package/dist/modules/tool-manuals/mcp-server-edit.service.js +328 -0
  100. package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -0
  101. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +38 -12
  102. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
  103. package/dist/modules/tool-manuals/tool-manuals.contract.js +1 -1
  104. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +13 -2
  105. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
  106. package/dist/modules/tool-manuals/tool-manuals.routes.js +233 -2
  107. package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
  108. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  109. package/dist/modules/tool-manuals/tool-manuals.service.js +74 -37
  110. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  111. package/dist/modules/tool-manuals/tool-manuals.tools.js +6 -3
  112. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  113. package/dist/modules/workflow/git/git.service.js +2 -2
  114. package/dist/modules/workflow/git/git.service.js.map +1 -1
  115. package/dist/modules/workspace/kb-seed.service.d.ts +2 -2
  116. package/dist/modules/workspace/kb-seed.service.d.ts.map +1 -1
  117. package/dist/modules/workspace/kb-seed.service.js +43 -10
  118. package/dist/modules/workspace/kb-seed.service.js.map +1 -1
  119. package/dist/modules/workspace/plugins-migration.d.ts +50 -0
  120. package/dist/modules/workspace/plugins-migration.d.ts.map +1 -0
  121. package/dist/modules/workspace/plugins-migration.js +379 -0
  122. package/dist/modules/workspace/plugins-migration.js.map +1 -0
  123. package/dist/modules/workspace/startup/kb-git.d.ts +23 -0
  124. package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -0
  125. package/dist/modules/workspace/startup/kb-git.js +86 -0
  126. package/dist/modules/workspace/startup/kb-git.js.map +1 -0
  127. package/dist/modules/workspace/startup/kb-startup-runner.d.ts +74 -0
  128. package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -0
  129. package/dist/modules/workspace/startup/kb-startup-runner.js +528 -0
  130. package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -0
  131. package/dist/modules/workspace/startup/on-server-start.d.ts +105 -0
  132. package/dist/modules/workspace/startup/on-server-start.d.ts.map +1 -0
  133. package/dist/modules/workspace/startup/on-server-start.js +21 -0
  134. package/dist/modules/workspace/startup/on-server-start.js.map +1 -0
  135. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +46 -0
  136. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts.map +1 -0
  137. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js +492 -0
  138. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js.map +1 -0
  139. package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts +23 -0
  140. package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts.map +1 -0
  141. package/dist/modules/workspace/startup/steps/roles-yaml.step.js +69 -0
  142. package/dist/modules/workspace/startup/steps/roles-yaml.step.js.map +1 -0
  143. package/dist/modules/workspace/startup/steps/seed-tree.d.ts +17 -0
  144. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -0
  145. package/dist/modules/workspace/startup/steps/seed-tree.js +109 -0
  146. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -0
  147. package/dist/modules/workspace/startup/steps/template-files.step.d.ts +103 -0
  148. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -0
  149. package/dist/modules/workspace/startup/steps/template-files.step.js +337 -0
  150. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -0
  151. package/dist/modules/workspace/workspace.routes.js +3 -3
  152. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  153. package/dist/modules/workspace/workspace.service.d.ts +0 -9
  154. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  155. package/dist/modules/workspace/workspace.service.js +2 -30
  156. package/dist/modules/workspace/workspace.service.js.map +1 -1
  157. package/dist/shared/kb-layout.test.js +3 -3
  158. package/dist/shared/kb-layout.test.js.map +1 -1
  159. package/dist/shared/utcp-namespace.d.ts +6 -27
  160. package/dist/shared/utcp-namespace.d.ts.map +1 -1
  161. package/dist/shared/utcp-namespace.js +6 -63
  162. package/dist/shared/utcp-namespace.js.map +1 -1
  163. package/dist/shared/variable-refs.d.ts +42 -0
  164. package/dist/shared/variable-refs.d.ts.map +1 -0
  165. package/dist/shared/variable-refs.js +60 -0
  166. package/dist/shared/variable-refs.js.map +1 -0
  167. package/kb-template/.bevelignore +1 -1
  168. package/kb-template/AGENTS.md +88 -35
  169. package/kb-template/KnowledgeBase/How to get started.md +10 -10
  170. package/kb-template/access.md +36 -36
  171. package/kb-template/gitignore.template +16 -0
  172. package/migrations/meta/0000_snapshot.json +1479 -1479
  173. package/package.json +5 -4
  174. package/src/assets.ts +25 -25
  175. package/src/core/core-ports.ts +113 -106
  176. package/src/core/create-core-server.ts +85 -20
  177. package/src/core/create-core-services.ts +83 -42
  178. package/src/index.ts +69 -69
  179. package/src/modules/access/__tests__/access-control.atref-batch.test.ts +98 -98
  180. package/src/modules/access/__tests__/access-declarations.test.ts +28 -28
  181. package/src/modules/access/__tests__/access-md-format.test.ts +18 -18
  182. package/src/modules/access/__tests__/access-mutation.service.test.ts +5 -5
  183. package/src/modules/access/__tests__/access-splice.test.ts +2 -2
  184. package/src/modules/access/__tests__/access.routes.overrides.test.ts +16 -16
  185. package/src/modules/access/__tests__/grant-sources.test.ts +12 -12
  186. package/src/modules/access/__tests__/roles-admin.service.test.ts +36 -2
  187. package/src/modules/access/access-control.interface.ts +8 -7
  188. package/src/modules/access/access-control.service.ts +7 -7
  189. package/src/modules/access/access-declarations.ts +5 -5
  190. package/src/modules/access/access-mutation.service.ts +3 -3
  191. package/src/modules/access/access-splice.ts +4 -4
  192. package/src/modules/access/access.routes.ts +23 -20
  193. package/src/modules/access/creator-access.ts +5 -5
  194. package/src/modules/access/render-roles-yaml.ts +65 -0
  195. package/src/modules/access/roles-admin.service.ts +45 -16
  196. package/src/modules/admin/admin-access.routes.ts +29 -29
  197. package/src/modules/auth/__tests__/auth.routes.test.ts +91 -91
  198. package/src/modules/auth/__tests__/rate-limit.test.ts +36 -36
  199. package/src/modules/auth/rate-limit.ts +45 -45
  200. package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +67 -0
  201. package/src/modules/code-mode/code-mode-names.ts +10 -36
  202. package/src/modules/code-mode/code-mode.tool.ts +27 -7
  203. package/src/modules/database/connection.ts +15 -15
  204. package/src/modules/database/schema.ts +11 -11
  205. package/src/modules/diff/__tests__/diff.routes.rejectPathsLocked.test.ts +150 -150
  206. package/src/modules/mcp/mcp.service.ts +57 -435
  207. package/src/modules/{groups → plugins}/__tests__/join-proposals.test.ts +1 -1
  208. package/src/modules/{groups → plugins}/__tests__/join-requests.service.test.ts +7 -7
  209. package/src/modules/{groups/__tests__/group-index.service.test.ts → plugins/__tests__/plugin-index.service.test.ts} +41 -41
  210. package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +312 -0
  211. package/src/modules/{groups/__tests__/groups.routes.test.ts → plugins/__tests__/plugins.routes.test.ts} +100 -100
  212. package/src/modules/plugins/index.ts +17 -0
  213. package/src/modules/{groups → plugins}/join-proposals.ts +2 -2
  214. package/src/modules/{groups → plugins}/join-requests.service.ts +8 -8
  215. package/src/modules/{groups/group-provision.service.ts → plugins/plugin-provision.service.ts} +139 -69
  216. package/src/modules/{groups/groups.contract.ts → plugins/plugins.contract.ts} +26 -26
  217. package/src/modules/{groups/groups.routes.ts → plugins/plugins.routes.ts} +102 -102
  218. package/src/modules/{groups/groups.service.ts → plugins/plugins.service.ts} +43 -43
  219. package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +143 -143
  220. package/src/modules/settings/__tests__/setup.routes.test.ts +124 -3
  221. package/src/modules/settings/setup.routes.ts +112 -5
  222. package/src/modules/skills/__tests__/pending-skills.service.test.ts +14 -14
  223. package/src/modules/skills/__tests__/skills.service.test.ts +13 -13
  224. package/src/modules/skills/pending-skills.service.ts +7 -7
  225. package/src/modules/skills/skills.contract.ts +4 -4
  226. package/src/modules/skills/skills.service.ts +5 -5
  227. package/src/modules/tool-auth/llm-usage-meter.ts +19 -19
  228. package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +198 -0
  229. package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +346 -0
  230. package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +101 -0
  231. package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +3 -3
  232. package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +2 -2
  233. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +27 -27
  234. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +3 -3
  235. package/src/modules/tool-manuals/mcp-json-discovery.ts +328 -0
  236. package/src/modules/tool-manuals/mcp-server-edit.service.ts +434 -0
  237. package/src/modules/tool-manuals/tool-manuals.contract.ts +35 -12
  238. package/src/modules/tool-manuals/tool-manuals.routes.ts +222 -1
  239. package/src/modules/tool-manuals/tool-manuals.service.ts +82 -42
  240. package/src/modules/tool-manuals/tool-manuals.tools.ts +6 -3
  241. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +1 -1
  242. package/src/modules/workflow/git/__tests__/branch-name.test.ts +3 -3
  243. package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +3 -3
  244. package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +13 -8
  245. package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +1 -1
  246. package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +1 -1
  247. package/src/modules/workflow/git/git.service.ts +2 -2
  248. package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +1 -1
  249. package/src/modules/workflow/review-workflow/__tests__/cancel-pr.test.ts +1 -1
  250. package/src/modules/workflow/workflow-hooks.ts +101 -101
  251. package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +237 -237
  252. package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +236 -236
  253. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +179 -179
  254. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +320 -320
  255. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +337 -337
  256. package/src/modules/workspace/__tests__/workspace.service.test.ts +27 -0
  257. package/src/modules/workspace/bevel-ignore.ts +66 -66
  258. package/src/modules/workspace/session-sink.ts +25 -25
  259. package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +495 -0
  260. package/src/modules/workspace/startup/kb-git.ts +94 -0
  261. package/src/modules/workspace/startup/kb-startup-runner.ts +597 -0
  262. package/src/modules/workspace/startup/on-server-start.ts +97 -0
  263. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +636 -0
  264. package/src/modules/workspace/startup/steps/groups-to-plugins.step.ts +561 -0
  265. package/src/modules/workspace/startup/steps/roles-yaml.step.ts +71 -0
  266. package/src/modules/workspace/startup/steps/seed-tree.ts +115 -0
  267. package/src/modules/workspace/startup/steps/template-files.step.ts +360 -0
  268. package/src/modules/workspace/workspace.routes.ts +3 -3
  269. package/src/modules/workspace/workspace.service.ts +2 -35
  270. package/src/modules/workspace/workspace.tools.ts +922 -922
  271. package/src/shared/__tests__/join-request.test.ts +13 -13
  272. package/src/shared/__tests__/kb-layout.plugin.test.ts +45 -0
  273. package/src/shared/kb-layout.test.ts +3 -3
  274. package/src/shared/utcp-namespace.ts +10 -68
  275. package/src/shared/variable-refs.ts +64 -0
  276. package/src/modules/groups/__tests__/group-provision.service.test.ts +0 -247
  277. package/src/modules/groups/index.ts +0 -17
  278. package/src/modules/workspace/__tests__/kb-seed.service.test.ts +0 -444
  279. package/src/modules/workspace/kb-seed.interface.ts +0 -36
  280. package/src/modules/workspace/kb-seed.service.ts +0 -555
  281. package/src/shared/__tests__/kb-layout.group.test.ts +0 -45
  282. /package/kb-template/{Groups → Plugins}/.gitkeep +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bevel-software/platform-core-backend",
3
- "version": "0.7.5",
3
+ "version": "0.9.0",
4
4
  "description": "Open-source core backend of the Bevel platform: git-backed knowledge workspace, workflow (branches/change requests/locks/SSE), skills, tools, secrets vault, access control and the remote MCP surface.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -36,7 +36,7 @@
36
36
  "@utcp/http": "^1.1.7",
37
37
  "@utcp/mcp": "^1.1.3",
38
38
  "@utcp/sdk": "^1.1.1",
39
- "adm-zip": "^0.5.17",
39
+ "adm-zip": "^0.6.0",
40
40
  "cors": "^2.8.5",
41
41
  "dotenv": "^16.4.0",
42
42
  "drizzle-orm": "^0.45.2",
@@ -46,7 +46,8 @@
46
46
  "pg": "^8.20.0",
47
47
  "yaml": "^2.9.0",
48
48
  "zod": "^3.24.0",
49
- "@bevel-software/platform-shared": "0.7.5"
49
+ "@bevel-software/platform-mcp-core": "0.9.0",
50
+ "@bevel-software/platform-shared": "0.9.0"
50
51
  },
51
52
  "devDependencies": {
52
53
  "@types/adm-zip": "^0.5.8",
@@ -60,7 +61,7 @@
60
61
  "drizzle-kit": "^0.31.10",
61
62
  "tsx": "^4.19.0",
62
63
  "typescript": "^5.8.0",
63
- "vitest": "^2.1.9"
64
+ "vitest": "^3.2.6"
64
65
  },
65
66
  "license": "Apache-2.0",
66
67
  "repository": {
package/src/assets.ts CHANGED
@@ -1,25 +1,25 @@
1
- import path from 'node:path';
2
- import { fileURLToPath } from 'node:url';
3
-
4
- /**
5
- * Locations of the assets shipped INSIDE this package (`files` in
6
- * package.json): the squashed core migration history (`migrations/`) and the
7
- * KB seed template (`kb-template/`). Both live at the PACKAGE ROOT, and this
8
- * module is a direct child of either `src/` (in-repo / tsx) or `dist/`
9
- * (compiled) — so one `..` hop from the module URL reaches the package root
10
- * in BOTH layouts. Resolved lazily so bundlers that rewrite `import.meta.url`
11
- * still get a sensible answer at call time.
12
- */
13
- function packageRoot(): string {
14
- return fileURLToPath(new URL('..', import.meta.url));
15
- }
16
-
17
- /** Absolute path of the packaged core Drizzle migrations folder. */
18
- export function coreMigrationsDir(): string {
19
- return path.join(packageRoot(), 'migrations');
20
- }
21
-
22
- /** Absolute path of the packaged KB seed template (`kb-template/`). */
23
- export function defaultKbTemplateDir(): string {
24
- return path.join(packageRoot(), 'kb-template');
25
- }
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+
4
+ /**
5
+ * Locations of the assets shipped INSIDE this package (`files` in
6
+ * package.json): the squashed core migration history (`migrations/`) and the
7
+ * KB seed template (`kb-template/`). Both live at the PACKAGE ROOT, and this
8
+ * module is a direct child of either `src/` (in-repo / tsx) or `dist/`
9
+ * (compiled) — so one `..` hop from the module URL reaches the package root
10
+ * in BOTH layouts. Resolved lazily so bundlers that rewrite `import.meta.url`
11
+ * still get a sensible answer at call time.
12
+ */
13
+ function packageRoot(): string {
14
+ return fileURLToPath(new URL('..', import.meta.url));
15
+ }
16
+
17
+ /** Absolute path of the packaged core Drizzle migrations folder. */
18
+ export function coreMigrationsDir(): string {
19
+ return path.join(packageRoot(), 'migrations');
20
+ }
21
+
22
+ /** Absolute path of the packaged KB seed template (`kb-template/`). */
23
+ export function defaultKbTemplateDir(): string {
24
+ return path.join(packageRoot(), 'kb-template');
25
+ }
@@ -1,106 +1,113 @@
1
- import type { ISessionSink } from '../modules/workspace/session-sink.js';
2
- import type {
3
- ISystemNoticeSink,
4
- RecoveryAgentRunner,
5
- } from '../modules/workflow/pending-commits.worker.js';
6
- import type { ILlmUsageMeter } from '../modules/tool-auth/llm-usage-meter.js';
7
- import type { AuthProviderPlugin } from '../modules/auth/auth.routes.js';
8
- import type { IErasureParticipant } from '../modules/auth/account-erasure.service.js';
9
-
10
- /**
11
- * Every seam the enterprise overlay can fill in the CORE composition
12
- * (`createCoreServices`). All fields are optional; each has a safe core-only
13
- * default, so `createCoreServices(config)` with no ports yields a fully
14
- * working core deployment.
15
- *
16
- * Two consumption patterns exist, and they matter for wiring order:
17
- *
18
- * - CONSTRUCTION-TIME ports (`recoveryAgent`, `systemNotice`,
19
- * `erasureParticipants`): dereferenced while core services are being
20
- * constructed. Enterprise implementations of these need core services that
21
- * don't exist yet at that point (the background-agent factory, the thread
22
- * service, …), so the enterprise root passes FORWARDING DELEGATORS / a
23
- * mutable array here and assigns the real targets right after
24
- * `createCoreServices` returns. That is safe because core only *calls* these
25
- * ports at request/commit/erasure time, long after boot — the same
26
- * late-binding pattern the composition root already uses for e.g. the MCP
27
- * OAuth revoke closure.
28
- *
29
- * - SERVER-TIME seams (`sessionSink`, `usageMeter`, `authProviders`): only
30
- * read when `createCoreServer` mounts routes / registers tools. Core seeds
31
- * them onto `CoreServices` from these ports (with the defaults below); the
32
- * enterprise root overwrites the `CoreServices` fields (or pushes into the
33
- * `authProviders` array) after construction, before the server is built.
34
- *
35
- * (Commit-time KB validation and the ontology write block are NOT ports:
36
- * they are workflow lifecycle HOOKS the enterprise root registers on
37
- * `workflowService.hooks` after construction — see
38
- * `modules/workflow/workflow-hooks.ts`.)
39
- */
40
- export interface CorePorts {
41
- /**
42
- * Backs the `start_session` tool. Core default: {@link UuidSessionSink}
43
- * (a bare random id). Enterprise substitutes a sink that mints a real chat
44
- * thread so the same id works end to end with `ask`.
45
- */
46
- sessionSink?: ISessionSink;
47
- /**
48
- * Recovery-agent dispatcher for the pending-commits worker. The worker
49
- * requires one, so the core default is {@link noopRecoveryAgent} — a run
50
- * that just returns, meaning the row stays pending until the recovery
51
- * budget is exhausted and the worker escalates via `systemNotice`.
52
- */
53
- recoveryAgent?: RecoveryAgentRunner;
54
- /**
55
- * Where the pending-commits worker escalates terminal failures. Core
56
- * default: {@link consoleSystemNoticeSink} (stderr, no dashboard).
57
- * Enterprise passes its feedback service.
58
- */
59
- systemNotice?: ISystemNoticeSink;
60
- /**
61
- * Per-connection-key LLM usage metering shown on the connection-key
62
- * management routes. Core default: {@link unmeteredLlmUsage} (no proxy,
63
- * nothing to meter). Enterprise passes the LLM proxy's usage service.
64
- */
65
- usageMeter?: ILlmUsageMeter;
66
- /**
67
- * SSO login plugins the auth router mounts. Core default: `[]` (password
68
- * login only). The array instance is kept on `CoreServices.authProviders`,
69
- * so an enterprise root may pass an array it fills after construction.
70
- */
71
- authProviders?: AuthProviderPlugin[];
72
- /**
73
- * Module-owned GDPR-erasure slices run by `AccountErasureService`. Core
74
- * default: `[]` (core erases only the rows it owns). The array reference is
75
- * held — not copied — so an enterprise root may pass an array it fills after
76
- * construction (participants are only iterated at erasure time).
77
- */
78
- erasureParticipants?: IErasureParticipant[];
79
- /**
80
- * Root folders THIS distribution reserves in the knowledge base, on top of
81
- * core's `KnowledgeBase/` + `Groups/`. Core default: `[]`.
82
- *
83
- * A name here does two things: the seeder guarantees the folder exists on
84
- * every branch it tops up, and — because the names are already reserved in
85
- * `kb-layout.ts` — the file tree keeps rendering it as its own root instead
86
- * of folding it into Knowledge as stray content.
87
- *
88
- * The folder is created as an empty `<dir>/.gitkeep`, written rather than
89
- * copied, so reserving a root does not oblige a distribution to fork the
90
- * packaged template. Ship a `KB_TEMPLATE_DIR` of your own when those folders
91
- * should arrive carrying READMEs.
92
- */
93
- kbExtraRootDirs?: readonly string[];
94
- }
95
-
96
- /**
97
- * Core default recovery agent: does nothing. The worker's retry ladder still
98
- * works — a stuck row burns its recovery budget on these no-op runs and then
99
- * escalates to the `systemNotice` sink, which is exactly the "no recovery
100
- * agent available" behavior a core-only deployment wants.
101
- */
102
- export const noopRecoveryAgent: RecoveryAgentRunner = {
103
- async run(): Promise<void> {
104
- // Intentionally empty — see doc comment.
105
- },
106
- };
1
+ import type { ISessionSink } from '../modules/workspace/session-sink.js';
2
+ import type {
3
+ ISystemNoticeSink,
4
+ RecoveryAgentRunner,
5
+ } from '../modules/workflow/pending-commits.worker.js';
6
+ import type { ILlmUsageMeter } from '../modules/tool-auth/llm-usage-meter.js';
7
+ import type { AuthProviderPlugin } from '../modules/auth/auth.routes.js';
8
+ import type { IErasureParticipant } from '../modules/auth/account-erasure.service.js';
9
+ import type { OnServerStart } from '../modules/workspace/startup/on-server-start.js';
10
+
11
+ /**
12
+ * Every seam the enterprise overlay can fill in the CORE composition
13
+ * (`createCoreServices`). All fields are optional; each has a safe core-only
14
+ * default, so `createCoreServices(config)` with no ports yields a fully
15
+ * working core deployment.
16
+ *
17
+ * Two consumption patterns exist, and they matter for wiring order:
18
+ *
19
+ * - CONSTRUCTION-TIME ports (`recoveryAgent`, `systemNotice`,
20
+ * `erasureParticipants`): dereferenced while core services are being
21
+ * constructed. Enterprise implementations of these need core services that
22
+ * don't exist yet at that point (the background-agent factory, the thread
23
+ * service, …), so the enterprise root passes FORWARDING DELEGATORS / a
24
+ * mutable array here and assigns the real targets right after
25
+ * `createCoreServices` returns. That is safe because core only *calls* these
26
+ * ports at request/commit/erasure time, long after boot — the same
27
+ * late-binding pattern the composition root already uses for e.g. the MCP
28
+ * OAuth revoke closure.
29
+ *
30
+ * - SERVER-TIME seams (`sessionSink`, `usageMeter`, `authProviders`): only
31
+ * read when `createCoreServer` mounts routes / registers tools. Core seeds
32
+ * them onto `CoreServices` from these ports (with the defaults below); the
33
+ * enterprise root overwrites the `CoreServices` fields (or pushes into the
34
+ * `authProviders` array) after construction, before the server is built.
35
+ *
36
+ * (Commit-time KB validation and the ontology write block are NOT ports:
37
+ * they are workflow lifecycle HOOKS the enterprise root registers on
38
+ * `workflowService.hooks` after construction — see
39
+ * `modules/workflow/workflow-hooks.ts`.)
40
+ */
41
+ export interface CorePorts {
42
+ /**
43
+ * Backs the `start_session` tool. Core default: {@link UuidSessionSink}
44
+ * (a bare random id). Enterprise substitutes a sink that mints a real chat
45
+ * thread so the same id works end to end with `ask`.
46
+ */
47
+ sessionSink?: ISessionSink;
48
+ /**
49
+ * Recovery-agent dispatcher for the pending-commits worker. The worker
50
+ * requires one, so the core default is {@link noopRecoveryAgent} — a run
51
+ * that just returns, meaning the row stays pending until the recovery
52
+ * budget is exhausted and the worker escalates via `systemNotice`.
53
+ */
54
+ recoveryAgent?: RecoveryAgentRunner;
55
+ /**
56
+ * Where the pending-commits worker escalates terminal failures. Core
57
+ * default: {@link consoleSystemNoticeSink} (stderr, no dashboard).
58
+ * Enterprise passes its feedback service.
59
+ */
60
+ systemNotice?: ISystemNoticeSink;
61
+ /**
62
+ * Per-connection-key LLM usage metering shown on the connection-key
63
+ * management routes. Core default: {@link unmeteredLlmUsage} (no proxy,
64
+ * nothing to meter). Enterprise passes the LLM proxy's usage service.
65
+ */
66
+ usageMeter?: ILlmUsageMeter;
67
+ /**
68
+ * SSO login plugins the auth router mounts. Core default: `[]` (password
69
+ * login only). The array instance is kept on `CoreServices.authProviders`,
70
+ * so an enterprise root may pass an array it fills after construction.
71
+ */
72
+ authProviders?: AuthProviderPlugin[];
73
+ /**
74
+ * Module-owned GDPR-erasure slices run by `AccountErasureService`. Core
75
+ * default: `[]` (core erases only the rows it owns). The array reference is
76
+ * held — not copied — so an enterprise root may pass an array it fills after
77
+ * construction (participants are only iterated at erasure time).
78
+ */
79
+ erasureParticipants?: IErasureParticipant[];
80
+ /**
81
+ * Root folders THIS distribution reserves in the knowledge base, on top of
82
+ * core's `KnowledgeBase/` + `Plugins/`. Core default: `[]`.
83
+ *
84
+ * A name here does two things: the seeder guarantees the folder exists on
85
+ * every branch it tops up, and — because the names are already reserved in
86
+ * `kb-layout.ts` — the file tree keeps rendering it as its own root instead
87
+ * of folding it into Knowledge as stray content.
88
+ *
89
+ * The folder is created as an empty `<dir>/.gitkeep`, written rather than
90
+ * copied, so reserving a root does not oblige a distribution to fork the
91
+ * packaged template. Ship a `KB_TEMPLATE_DIR` of your own when those folders
92
+ * should arrive carrying READMEs.
93
+ */
94
+ kbExtraRootDirs?: readonly string[];
95
+ /**
96
+ * Steps THIS distribution appends to the KB startup phase, run after core's
97
+ * own steps in array order (see `startup/on-server-start.ts` for the
98
+ * contract each step signs up to). Core default: `[]`.
99
+ */
100
+ kbStartupSteps?: readonly OnServerStart[];
101
+ }
102
+
103
+ /**
104
+ * Core default recovery agent: does nothing. The worker's retry ladder still
105
+ * works — a stuck row burns its recovery budget on these no-op runs and then
106
+ * escalates to the `systemNotice` sink, which is exactly the "no recovery
107
+ * agent available" behavior a core-only deployment wants.
108
+ */
109
+ export const noopRecoveryAgent: RecoveryAgentRunner = {
110
+ async run(): Promise<void> {
111
+ // Intentionally empty — see doc comment.
112
+ },
113
+ };
@@ -21,7 +21,7 @@ import { registerWorkflowTools } from '../modules/workflow/agent-tools/workflow.
21
21
  import { registerWorkspaceTools } from '../modules/workspace/workspace.tools.js';
22
22
  import { RECOVERY_BOT_EMAIL } from '../modules/workflow/recovery-bot.js';
23
23
  import { registerSkillsTools, createSkillsRoutes } from '../modules/skills/index.js';
24
- import { createGroupsRoutes } from '../modules/groups/index.js';
24
+ import { createPluginsRoutes } from '../modules/plugins/index.js';
25
25
  import type { SessionOntologyGate } from '../modules/workspace/session-ontology.gate.js';
26
26
  import {
27
27
  createSecretsVaultRoutes,
@@ -30,7 +30,7 @@ import {
30
30
  import { createAdminAccessRoutes } from '../modules/admin/admin-access.routes.js';
31
31
  import { createAccountRoutes } from '../modules/auth/account.routes.js';
32
32
  import { createSetupRoutes } from '../modules/settings/setup.routes.js';
33
- import { DEFAULT_BRANCH, PROTECTED_BRANCHES } from '@bevel-software/platform-shared';
33
+ import { DEFAULT_BRANCH, PROTECTED_BRANCHES, type AuthUser } from '@bevel-software/platform-shared';
34
34
  import { GIT_SHA } from '../version.js';
35
35
  import type { CoreServices } from './create-core-services.js';
36
36
 
@@ -150,6 +150,30 @@ export async function createCoreServer(
150
150
  res.json({ status: 'ok', sha: GIT_SHA, timestamp: Date.now() });
151
151
  });
152
152
 
153
+ /**
154
+ * This deployment's MCP endpoint, derived ONCE.
155
+ *
156
+ * Two consumers must agree on it: `/api/config` below, which is where the
157
+ * frontend learns what address to show people, and the OAuth
158
+ * `resourceServerUrl` further down, which is the resource identifier the
159
+ * protected-resource metadata publishes and therefore the one that decides
160
+ * whether a connection actually works.
161
+ *
162
+ * A constant rather than the same expression written twice. The frontend
163
+ * carried the two-places version of this bug for a long time — six inline
164
+ * sites each rebuilding the address, held together by a docstring asserting
165
+ * they could not diverge — and a comment is not a mechanism.
166
+ *
167
+ * Userinfo is STRIPPED: a `PUBLIC_BACKEND_URL` spelled with `user:pass@`
168
+ * (a basic-auth proxy in front of the deployment, say) would otherwise be
169
+ * republished verbatim by the unauthenticated `/api/config` below — a
170
+ * credential handed to any caller. The address is ours to publish; the
171
+ * credential never was.
172
+ */
173
+ const mcpResourceUrl = new URL('/api/mcp', core.config.publicBackendUrl);
174
+ mcpResourceUrl.username = '';
175
+ mcpResourceUrl.password = '';
176
+
153
177
  /**
154
178
  * The handful of facts the browser needs BEFORE it can render anything, and
155
179
  * therefore before it can authenticate: the branch model.
@@ -170,15 +194,46 @@ export async function createCoreServer(
170
194
  defaultBranch: DEFAULT_BRANCH,
171
195
  protectedBranches: [...PROTECTED_BRANCHES],
172
196
  },
197
+ /**
198
+ * The same value the OAuth metadata publishes (see `mcpResourceUrl`).
199
+ *
200
+ * The frontend used to build this from `window.location.origin`, which
201
+ * is the browser's idea of our address rather than ours. The two agree
202
+ * on a simple deployment and disagree behind a proxy, on a second
203
+ * domain, or on an internal hostname — and the one that decides whether
204
+ * a connection works is this one.
205
+ *
206
+ * That was survivable while every surface was copy-paste: a human sees
207
+ * the host before pasting it. It stops being survivable the moment we
208
+ * hand the URL to a third party (a connector install link), where
209
+ * nobody reads it and the failure surfaces inside someone else's UI.
210
+ */
211
+ mcpUrl: mcpResourceUrl.toString(),
173
212
  });
174
213
  });
175
214
 
176
- // Close change requests whose source branch has been deleted. Not awaited:
177
- // it fetches from origin, and a slow or unreachable remote must not hold up
178
- // the server — nothing downstream depends on the result, and the requests it
179
- // closes have been unusable since the branch went away, so landing a few
180
- // seconds into uptime is soon enough. Errors are swallowed inside the sweep,
181
- // which fails safe by closing nothing.
215
+ // Overlay boot-time side effects (startup reconciles, periodic sweeps).
216
+ await ext.onBoot?.(core);
217
+
218
+ // The KB startup phase — AFTER the distribution's onBoot, because a FATAL
219
+ // template finding raised there must stop the boot before anything seeds
220
+ // from that template; the runner then brings every branch up to this build
221
+ // before any route can serve KB content. Throws to stop the boot (the
222
+ // container's restart policy is the retry) — see kb-startup-runner.ts.
223
+ await core.kbStartupRunner.runAll();
224
+
225
+ // Close change requests whose source branch has been deleted. SEQUENCED
226
+ // AFTER the startup phase above, for two reasons: the sweep's fresh fetch
227
+ // lazily bootstraps and fetches the same default-branch clone the runner
228
+ // maintains (kicking it off earlier races the runner's clone/fetch of that
229
+ // very directory), and on a brand-new deployment it would run before the
230
+ // empty remote is seeded, fail its clone, swallow the error, and leave
231
+ // deleted-branch CRs open for the whole process. Still not awaited from
232
+ // here on: a slow or unreachable remote must not hold up the server —
233
+ // nothing downstream depends on the result, and the requests it closes
234
+ // have been unusable since the branch went away, so landing a few seconds
235
+ // into uptime is soon enough. Errors are swallowed inside the sweep, which
236
+ // fails safe by closing nothing.
182
237
  void core.workflowService
183
238
  .closeChangeRequestsWithDeletedBranches()
184
239
  .then((n) => {
@@ -188,9 +243,6 @@ export async function createCoreServer(
188
243
  })
189
244
  .catch((err) => console.warn('[cr] deleted-branch sweep failed:', err));
190
245
 
191
- // Overlay boot-time side effects (startup reconciles, periodic sweeps).
192
- await ext.onBoot?.(core);
193
-
194
246
  // Auth routes (unprotected — login endpoint must be accessible)
195
247
  app.use(
196
248
  '/api',
@@ -225,7 +277,7 @@ export async function createCoreServer(
225
277
  app.use(mcpAuthRouter({
226
278
  provider: core.mcpOAuthProvider,
227
279
  issuerUrl: new URL(core.config.publicBackendUrl),
228
- resourceServerUrl: new URL('/api/mcp', core.config.publicBackendUrl),
280
+ resourceServerUrl: mcpResourceUrl,
229
281
  scopesSupported: ['mcp'],
230
282
  resourceName: 'Bevel MCP',
231
283
  }));
@@ -300,6 +352,7 @@ export async function createCoreServer(
300
352
  core.toolManualService,
301
353
  core.manualAuthMiddleware,
302
354
  async (userId) => (await core.authService.getUserById(userId))?.email,
355
+ { workspaceService: core.workspaceService, accessControl: core.accessControl, kbDirName: core.kbDirName },
303
356
  ));
304
357
  app.use('/api', toolsRouter);
305
358
 
@@ -349,23 +402,24 @@ export async function createCoreServer(
349
402
  core.eventBus,
350
403
  core.db,
351
404
  core.kbDirName,
405
+ [core.config.adminEmail],
352
406
  ));
353
407
  app.use(
354
408
  '/api',
355
409
  core.authMiddleware,
356
410
  createSkillsRoutes(core.skillService, core.pendingSkillsService),
357
411
  );
358
- // Group enumeration + join requests. Browser-only (JWT), and fail-closed
359
- // like every other read surface: groups the caller cannot access (member,
412
+ // Plugin enumeration + join requests. Browser-only (JWT), and fail-closed
413
+ // like every other read surface: plugins the caller cannot access (member,
360
414
  // manager, or discoverable via the access.md file's own read grant) are
361
415
  // absent from the list. A join request is a plain change request.
362
- app.use('/api', core.authMiddleware, createGroupsRoutes(
363
- core.groupIndexService,
416
+ app.use('/api', core.authMiddleware, createPluginsRoutes(
417
+ core.pluginIndexService,
364
418
  core.accessControl,
365
419
  core.workflowService,
366
420
  core.workspaceService,
367
421
  core.joinRequestsService,
368
- core.groupProvisionService,
422
+ core.pluginProvisionService,
369
423
  core.kbDirName,
370
424
  async (req) => (req.userId ? ((await core.authService.getUserById(req.userId)) ?? null) : null),
371
425
  ));
@@ -381,9 +435,20 @@ export async function createCoreServer(
381
435
  ));
382
436
  // First-run setup. Mounted with the other authed routes but touching NO
383
437
  // workspace — it has to work on a deployment that has no knowledge base yet,
384
- // which is the whole reason it exists.
385
- app.use('/api', core.authMiddleware, createSetupRoutes(core.settings, core.adminAccess));
386
- app.use('/api', core.authMiddleware, createToolManualsBrowserRoutes(core.toolManualService));
438
+ // which is the whole reason it exists. The startup runner rides along for
439
+ // the phase's SECOND quiet moment: the save that completes setup.
440
+ app.use(
441
+ '/api',
442
+ core.authMiddleware,
443
+ createSetupRoutes(core.settings, core.adminAccess, core.kbStartupRunner),
444
+ );
445
+ app.use('/api', core.authMiddleware, createToolManualsBrowserRoutes(core.toolManualService, {
446
+ service: core.mcpServerEditService,
447
+ getUser: async (userId) => {
448
+ const u = await core.authService.getUserById(userId);
449
+ return u ? ({ id: u.id, email: u.email, name: u.name } as AuthUser) : undefined;
450
+ },
451
+ }));
387
452
  app.use('/api', core.authMiddleware, createSecretsVaultRoutes(secretsVaultRoutesDeps));
388
453
  // The authed tail of the MCP OAuth flow: /connect calls these to describe
389
454
  // the pending authorization and, on Finish, to mint the one-time code. The