@bevel-software/platform-core-backend 0.1.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 (720) hide show
  1. package/LICENSE +202 -0
  2. package/dist/assets.d.ts +5 -0
  3. package/dist/assets.d.ts.map +1 -0
  4. package/dist/assets.js +23 -0
  5. package/dist/assets.js.map +1 -0
  6. package/dist/core/core-ports.d.ts +83 -0
  7. package/dist/core/core-ports.d.ts.map +1 -0
  8. package/dist/core/core-ports.js +12 -0
  9. package/dist/core/core-ports.js.map +1 -0
  10. package/dist/core/create-core-server.d.ts +62 -0
  11. package/dist/core/create-core-server.d.ts.map +1 -0
  12. package/dist/core/create-core-server.js +204 -0
  13. package/dist/core/create-core-server.js.map +1 -0
  14. package/dist/core/create-core-services.d.ts +95 -0
  15. package/dist/core/create-core-services.d.ts.map +1 -0
  16. package/dist/core/create-core-services.js +352 -0
  17. package/dist/core/create-core-services.js.map +1 -0
  18. package/dist/core-config.d.ts +119 -0
  19. package/dist/core-config.d.ts.map +1 -0
  20. package/dist/core-config.js +240 -0
  21. package/dist/core-config.js.map +1 -0
  22. package/dist/index.d.ts +36 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +36 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/modules/access/access-control.interface.d.ts +348 -0
  27. package/dist/modules/access/access-control.interface.d.ts.map +1 -0
  28. package/dist/modules/access/access-control.interface.js +2 -0
  29. package/dist/modules/access/access-control.interface.js.map +1 -0
  30. package/dist/modules/access/access-control.service.d.ts +323 -0
  31. package/dist/modules/access/access-control.service.d.ts.map +1 -0
  32. package/dist/modules/access/access-control.service.js +1431 -0
  33. package/dist/modules/access/access-control.service.js.map +1 -0
  34. package/dist/modules/access/access-errors.d.ts +34 -0
  35. package/dist/modules/access/access-errors.d.ts.map +1 -0
  36. package/dist/modules/access/access-errors.js +40 -0
  37. package/dist/modules/access/access-errors.js.map +1 -0
  38. package/dist/modules/access/access-mutation.service.d.ts +176 -0
  39. package/dist/modules/access/access-mutation.service.d.ts.map +1 -0
  40. package/dist/modules/access/access-mutation.service.js +307 -0
  41. package/dist/modules/access/access-mutation.service.js.map +1 -0
  42. package/dist/modules/access/access-splice.d.ts +98 -0
  43. package/dist/modules/access/access-splice.d.ts.map +1 -0
  44. package/dist/modules/access/access-splice.js +346 -0
  45. package/dist/modules/access/access-splice.js.map +1 -0
  46. package/dist/modules/access/access.routes.d.ts +10 -0
  47. package/dist/modules/access/access.routes.d.ts.map +1 -0
  48. package/dist/modules/access/access.routes.js +757 -0
  49. package/dist/modules/access/access.routes.js.map +1 -0
  50. package/dist/modules/access/creator-access.d.ts +113 -0
  51. package/dist/modules/access/creator-access.d.ts.map +1 -0
  52. package/dist/modules/access/creator-access.js +212 -0
  53. package/dist/modules/access/creator-access.js.map +1 -0
  54. package/dist/modules/access/kb-read-filter.d.ts +41 -0
  55. package/dist/modules/access/kb-read-filter.d.ts.map +1 -0
  56. package/dist/modules/access/kb-read-filter.js +60 -0
  57. package/dist/modules/access/kb-read-filter.js.map +1 -0
  58. package/dist/modules/access/roles-admin.service.d.ts +240 -0
  59. package/dist/modules/access/roles-admin.service.d.ts.map +1 -0
  60. package/dist/modules/access/roles-admin.service.js +630 -0
  61. package/dist/modules/access/roles-admin.service.js.map +1 -0
  62. package/dist/modules/access/roles-edit.d.ts +91 -0
  63. package/dist/modules/access/roles-edit.d.ts.map +1 -0
  64. package/dist/modules/access/roles-edit.js +232 -0
  65. package/dist/modules/access/roles-edit.js.map +1 -0
  66. package/dist/modules/access/roles-yaml-guard.d.ts +56 -0
  67. package/dist/modules/access/roles-yaml-guard.d.ts.map +1 -0
  68. package/dist/modules/access/roles-yaml-guard.js +79 -0
  69. package/dist/modules/access/roles-yaml-guard.js.map +1 -0
  70. package/dist/modules/admin/admin-access.routes.d.ts +18 -0
  71. package/dist/modules/admin/admin-access.routes.d.ts.map +1 -0
  72. package/dist/modules/admin/admin-access.routes.js +26 -0
  73. package/dist/modules/admin/admin-access.routes.js.map +1 -0
  74. package/dist/modules/admin/admin-access.service.d.ts +24 -0
  75. package/dist/modules/admin/admin-access.service.d.ts.map +1 -0
  76. package/dist/modules/admin/admin-access.service.js +41 -0
  77. package/dist/modules/admin/admin-access.service.js.map +1 -0
  78. package/dist/modules/admin/admin.interface.d.ts +11 -0
  79. package/dist/modules/admin/admin.interface.d.ts.map +1 -0
  80. package/dist/modules/admin/admin.interface.js +2 -0
  81. package/dist/modules/admin/admin.interface.js.map +1 -0
  82. package/dist/modules/auth/account-erasure.service.d.ts +80 -0
  83. package/dist/modules/auth/account-erasure.service.d.ts.map +1 -0
  84. package/dist/modules/auth/account-erasure.service.js +91 -0
  85. package/dist/modules/auth/account-erasure.service.js.map +1 -0
  86. package/dist/modules/auth/auth.middleware.d.ts +23 -0
  87. package/dist/modules/auth/auth.middleware.d.ts.map +1 -0
  88. package/dist/modules/auth/auth.middleware.js +68 -0
  89. package/dist/modules/auth/auth.middleware.js.map +1 -0
  90. package/dist/modules/auth/auth.routes.d.ts +25 -0
  91. package/dist/modules/auth/auth.routes.d.ts.map +1 -0
  92. package/dist/modules/auth/auth.routes.js +72 -0
  93. package/dist/modules/auth/auth.routes.js.map +1 -0
  94. package/dist/modules/auth/auth.service.d.ts +76 -0
  95. package/dist/modules/auth/auth.service.d.ts.map +1 -0
  96. package/dist/modules/auth/auth.service.js +168 -0
  97. package/dist/modules/auth/auth.service.js.map +1 -0
  98. package/dist/modules/code-mode/code-mode-names.d.ts +16 -0
  99. package/dist/modules/code-mode/code-mode-names.d.ts.map +1 -0
  100. package/dist/modules/code-mode/code-mode-names.js +30 -0
  101. package/dist/modules/code-mode/code-mode-names.js.map +1 -0
  102. package/dist/modules/code-mode/code-mode.tool.d.ts +13 -0
  103. package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -0
  104. package/dist/modules/code-mode/code-mode.tool.js +112 -0
  105. package/dist/modules/code-mode/code-mode.tool.js.map +1 -0
  106. package/dist/modules/code-mode/index.d.ts +3 -0
  107. package/dist/modules/code-mode/index.d.ts.map +1 -0
  108. package/dist/modules/code-mode/index.js +3 -0
  109. package/dist/modules/code-mode/index.js.map +1 -0
  110. package/dist/modules/database/connection.d.ts +6 -0
  111. package/dist/modules/database/connection.d.ts.map +1 -0
  112. package/dist/modules/database/connection.js +12 -0
  113. package/dist/modules/database/connection.js.map +1 -0
  114. package/dist/modules/database/core-schema.d.ts +2273 -0
  115. package/dist/modules/database/core-schema.d.ts.map +1 -0
  116. package/dist/modules/database/core-schema.js +413 -0
  117. package/dist/modules/database/core-schema.js.map +1 -0
  118. package/dist/modules/database/migrate.d.ts +10 -0
  119. package/dist/modules/database/migrate.d.ts.map +1 -0
  120. package/dist/modules/database/migrate.js +40 -0
  121. package/dist/modules/database/migrate.js.map +1 -0
  122. package/dist/modules/database/schema.d.ts +12 -0
  123. package/dist/modules/database/schema.d.ts.map +1 -0
  124. package/dist/modules/database/schema.js +12 -0
  125. package/dist/modules/database/schema.js.map +1 -0
  126. package/dist/modules/diff/diff-paths.d.ts +2 -0
  127. package/dist/modules/diff/diff-paths.d.ts.map +1 -0
  128. package/dist/modules/diff/diff-paths.js +9 -0
  129. package/dist/modules/diff/diff-paths.js.map +1 -0
  130. package/dist/modules/diff/diff.config.d.ts +8 -0
  131. package/dist/modules/diff/diff.config.d.ts.map +1 -0
  132. package/dist/modules/diff/diff.config.js +13 -0
  133. package/dist/modules/diff/diff.config.js.map +1 -0
  134. package/dist/modules/diff/diff.interface.d.ts +73 -0
  135. package/dist/modules/diff/diff.interface.d.ts.map +1 -0
  136. package/dist/modules/diff/diff.interface.js +2 -0
  137. package/dist/modules/diff/diff.interface.js.map +1 -0
  138. package/dist/modules/diff/diff.routes.d.ts +35 -0
  139. package/dist/modules/diff/diff.routes.d.ts.map +1 -0
  140. package/dist/modules/diff/diff.routes.js +228 -0
  141. package/dist/modules/diff/diff.routes.js.map +1 -0
  142. package/dist/modules/diff/diff.service.d.ts +51 -0
  143. package/dist/modules/diff/diff.service.d.ts.map +1 -0
  144. package/dist/modules/diff/diff.service.js +489 -0
  145. package/dist/modules/diff/diff.service.js.map +1 -0
  146. package/dist/modules/diff/line-diff.d.ts +16 -0
  147. package/dist/modules/diff/line-diff.d.ts.map +1 -0
  148. package/dist/modules/diff/line-diff.js +67 -0
  149. package/dist/modules/diff/line-diff.js.map +1 -0
  150. package/dist/modules/mcp/mcp-auth.middleware.d.ts +27 -0
  151. package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -0
  152. package/dist/modules/mcp/mcp-auth.middleware.js +116 -0
  153. package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -0
  154. package/dist/modules/mcp/mcp-session-store.d.ts +74 -0
  155. package/dist/modules/mcp/mcp-session-store.d.ts.map +1 -0
  156. package/dist/modules/mcp/mcp-session-store.js +131 -0
  157. package/dist/modules/mcp/mcp-session-store.js.map +1 -0
  158. package/dist/modules/mcp/mcp.routes.d.ts +24 -0
  159. package/dist/modules/mcp/mcp.routes.d.ts.map +1 -0
  160. package/dist/modules/mcp/mcp.routes.js +229 -0
  161. package/dist/modules/mcp/mcp.routes.js.map +1 -0
  162. package/dist/modules/mcp/mcp.service.d.ts +198 -0
  163. package/dist/modules/mcp/mcp.service.d.ts.map +1 -0
  164. package/dist/modules/mcp/mcp.service.js +840 -0
  165. package/dist/modules/mcp/mcp.service.js.map +1 -0
  166. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +76 -0
  167. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -0
  168. package/dist/modules/mcp/oauth/bevel-oauth-provider.js +291 -0
  169. package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -0
  170. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts +18 -0
  171. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -0
  172. package/dist/modules/mcp/oauth/oauth-consent.routes.js +52 -0
  173. package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -0
  174. package/dist/modules/mcp/oauth/oauth-state.d.ts +32 -0
  175. package/dist/modules/mcp/oauth/oauth-state.d.ts.map +1 -0
  176. package/dist/modules/mcp/oauth/oauth-state.js +34 -0
  177. package/dist/modules/mcp/oauth/oauth-state.js.map +1 -0
  178. package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +92 -0
  179. package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -0
  180. package/dist/modules/secrets-vault/db-secrets-vault.service.js +728 -0
  181. package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -0
  182. package/dist/modules/secrets-vault/index.d.ts +7 -0
  183. package/dist/modules/secrets-vault/index.d.ts.map +1 -0
  184. package/dist/modules/secrets-vault/index.js +6 -0
  185. package/dist/modules/secrets-vault/index.js.map +1 -0
  186. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts +63 -0
  187. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts.map +1 -0
  188. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js +269 -0
  189. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js.map +1 -0
  190. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts +46 -0
  191. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -0
  192. package/dist/modules/secrets-vault/secrets-variable-loader.js +87 -0
  193. package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -0
  194. package/dist/modules/secrets-vault/secrets-vault.contract.d.ts +210 -0
  195. package/dist/modules/secrets-vault/secrets-vault.contract.d.ts.map +1 -0
  196. package/dist/modules/secrets-vault/secrets-vault.contract.js +90 -0
  197. package/dist/modules/secrets-vault/secrets-vault.contract.js.map +1 -0
  198. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +30 -0
  199. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -0
  200. package/dist/modules/secrets-vault/secrets-vault.routes.js +490 -0
  201. package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -0
  202. package/dist/modules/skills/index.d.ts +5 -0
  203. package/dist/modules/skills/index.d.ts.map +1 -0
  204. package/dist/modules/skills/index.js +4 -0
  205. package/dist/modules/skills/index.js.map +1 -0
  206. package/dist/modules/skills/skills.contract.d.ts +58 -0
  207. package/dist/modules/skills/skills.contract.d.ts.map +1 -0
  208. package/dist/modules/skills/skills.contract.js +10 -0
  209. package/dist/modules/skills/skills.contract.js.map +1 -0
  210. package/dist/modules/skills/skills.routes.d.ts +15 -0
  211. package/dist/modules/skills/skills.routes.d.ts.map +1 -0
  212. package/dist/modules/skills/skills.routes.js +34 -0
  213. package/dist/modules/skills/skills.routes.js.map +1 -0
  214. package/dist/modules/skills/skills.service.d.ts +21 -0
  215. package/dist/modules/skills/skills.service.d.ts.map +1 -0
  216. package/dist/modules/skills/skills.service.js +202 -0
  217. package/dist/modules/skills/skills.service.js.map +1 -0
  218. package/dist/modules/skills/skills.tools.d.ts +15 -0
  219. package/dist/modules/skills/skills.tools.d.ts.map +1 -0
  220. package/dist/modules/skills/skills.tools.js +96 -0
  221. package/dist/modules/skills/skills.tools.js.map +1 -0
  222. package/dist/modules/tool-auth/external-api-key.errors.d.ts +14 -0
  223. package/dist/modules/tool-auth/external-api-key.errors.d.ts.map +1 -0
  224. package/dist/modules/tool-auth/external-api-key.errors.js +23 -0
  225. package/dist/modules/tool-auth/external-api-key.errors.js.map +1 -0
  226. package/dist/modules/tool-auth/external-api-key.interface.d.ts +90 -0
  227. package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -0
  228. package/dist/modules/tool-auth/external-api-key.interface.js +2 -0
  229. package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -0
  230. package/dist/modules/tool-auth/external-api-key.service.d.ts +25 -0
  231. package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -0
  232. package/dist/modules/tool-auth/external-api-key.service.js +164 -0
  233. package/dist/modules/tool-auth/external-api-key.service.js.map +1 -0
  234. package/dist/modules/tool-auth/internal-token.service.d.ts +62 -0
  235. package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -0
  236. package/dist/modules/tool-auth/internal-token.service.js +85 -0
  237. package/dist/modules/tool-auth/internal-token.service.js.map +1 -0
  238. package/dist/modules/tool-auth/llm-usage-meter.d.ts +16 -0
  239. package/dist/modules/tool-auth/llm-usage-meter.d.ts.map +1 -0
  240. package/dist/modules/tool-auth/llm-usage-meter.js +6 -0
  241. package/dist/modules/tool-auth/llm-usage-meter.js.map +1 -0
  242. package/dist/modules/tool-auth/tool-auth.middleware.d.ts +101 -0
  243. package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -0
  244. package/dist/modules/tool-auth/tool-auth.middleware.js +166 -0
  245. package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -0
  246. package/dist/modules/tool-helpers/index.d.ts +19 -0
  247. package/dist/modules/tool-helpers/index.d.ts.map +1 -0
  248. package/dist/modules/tool-helpers/index.js +18 -0
  249. package/dist/modules/tool-helpers/index.js.map +1 -0
  250. package/dist/modules/tool-helpers/tool-context.d.ts +35 -0
  251. package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -0
  252. package/dist/modules/tool-helpers/tool-context.js +66 -0
  253. package/dist/modules/tool-helpers/tool-context.js.map +1 -0
  254. package/dist/modules/tool-helpers/tool-def.d.ts +33 -0
  255. package/dist/modules/tool-helpers/tool-def.d.ts.map +1 -0
  256. package/dist/modules/tool-helpers/tool-def.js +57 -0
  257. package/dist/modules/tool-helpers/tool-def.js.map +1 -0
  258. package/dist/modules/tool-helpers/tool-handler.d.ts +19 -0
  259. package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -0
  260. package/dist/modules/tool-helpers/tool-handler.js +84 -0
  261. package/dist/modules/tool-helpers/tool-handler.js.map +1 -0
  262. package/dist/modules/tool-helpers/tool.contract.d.ts +64 -0
  263. package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -0
  264. package/dist/modules/tool-helpers/tool.contract.js +24 -0
  265. package/dist/modules/tool-helpers/tool.contract.js.map +1 -0
  266. package/dist/modules/tool-helpers/validate-token.d.ts +31 -0
  267. package/dist/modules/tool-helpers/validate-token.d.ts.map +1 -0
  268. package/dist/modules/tool-helpers/validate-token.js +20 -0
  269. package/dist/modules/tool-helpers/validate-token.js.map +1 -0
  270. package/dist/modules/tool-manuals/index.d.ts +5 -0
  271. package/dist/modules/tool-manuals/index.d.ts.map +1 -0
  272. package/dist/modules/tool-manuals/index.js +5 -0
  273. package/dist/modules/tool-manuals/index.js.map +1 -0
  274. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +182 -0
  275. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -0
  276. package/dist/modules/tool-manuals/tool-manuals.contract.js +19 -0
  277. package/dist/modules/tool-manuals/tool-manuals.contract.js.map +1 -0
  278. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +24 -0
  279. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -0
  280. package/dist/modules/tool-manuals/tool-manuals.routes.js +102 -0
  281. package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -0
  282. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +108 -0
  283. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -0
  284. package/dist/modules/tool-manuals/tool-manuals.service.js +710 -0
  285. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -0
  286. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +35 -0
  287. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -0
  288. package/dist/modules/tool-manuals/tool-manuals.tools.js +157 -0
  289. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -0
  290. package/dist/modules/tool-registry/manual.routes.d.ts +6 -0
  291. package/dist/modules/tool-registry/manual.routes.d.ts.map +1 -0
  292. package/dist/modules/tool-registry/manual.routes.js +76 -0
  293. package/dist/modules/tool-registry/manual.routes.js.map +1 -0
  294. package/dist/modules/tool-registry/tool-registry.d.ts +23 -0
  295. package/dist/modules/tool-registry/tool-registry.d.ts.map +1 -0
  296. package/dist/modules/tool-registry/tool-registry.js +46 -0
  297. package/dist/modules/tool-registry/tool-registry.js.map +1 -0
  298. package/dist/modules/tool-registry/tool.contract.d.ts +48 -0
  299. package/dist/modules/tool-registry/tool.contract.d.ts.map +1 -0
  300. package/dist/modules/tool-registry/tool.contract.js +2 -0
  301. package/dist/modules/tool-registry/tool.contract.js.map +1 -0
  302. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +14 -0
  303. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -0
  304. package/dist/modules/workflow/agent-tools/workflow.tools.js +437 -0
  305. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -0
  306. package/dist/modules/workflow/event-bus.d.ts +107 -0
  307. package/dist/modules/workflow/event-bus.d.ts.map +1 -0
  308. package/dist/modules/workflow/event-bus.js +224 -0
  309. package/dist/modules/workflow/event-bus.js.map +1 -0
  310. package/dist/modules/workflow/events.routes.d.ts +80 -0
  311. package/dist/modules/workflow/events.routes.d.ts.map +1 -0
  312. package/dist/modules/workflow/events.routes.js +216 -0
  313. package/dist/modules/workflow/events.routes.js.map +1 -0
  314. package/dist/modules/workflow/file-change-notifier.d.ts +38 -0
  315. package/dist/modules/workflow/file-change-notifier.d.ts.map +1 -0
  316. package/dist/modules/workflow/file-change-notifier.js +22 -0
  317. package/dist/modules/workflow/file-change-notifier.js.map +1 -0
  318. package/dist/modules/workflow/file-lock.service.d.ts +57 -0
  319. package/dist/modules/workflow/file-lock.service.d.ts.map +1 -0
  320. package/dist/modules/workflow/file-lock.service.js +202 -0
  321. package/dist/modules/workflow/file-lock.service.js.map +1 -0
  322. package/dist/modules/workflow/git/branch-name.d.ts +10 -0
  323. package/dist/modules/workflow/git/branch-name.d.ts.map +1 -0
  324. package/dist/modules/workflow/git/branch-name.js +76 -0
  325. package/dist/modules/workflow/git/branch-name.js.map +1 -0
  326. package/dist/modules/workflow/git/clone-config.d.ts +61 -0
  327. package/dist/modules/workflow/git/clone-config.d.ts.map +1 -0
  328. package/dist/modules/workflow/git/clone-config.js +69 -0
  329. package/dist/modules/workflow/git/clone-config.js.map +1 -0
  330. package/dist/modules/workflow/git/git-version.d.ts +34 -0
  331. package/dist/modules/workflow/git/git-version.d.ts.map +1 -0
  332. package/dist/modules/workflow/git/git-version.js +63 -0
  333. package/dist/modules/workflow/git/git-version.js.map +1 -0
  334. package/dist/modules/workflow/git/git.service.d.ts +427 -0
  335. package/dist/modules/workflow/git/git.service.d.ts.map +1 -0
  336. package/dist/modules/workflow/git/git.service.js +1987 -0
  337. package/dist/modules/workflow/git/git.service.js.map +1 -0
  338. package/dist/modules/workflow/git/mutex.d.ts +11 -0
  339. package/dist/modules/workflow/git/mutex.d.ts.map +1 -0
  340. package/dist/modules/workflow/git/mutex.js +23 -0
  341. package/dist/modules/workflow/git/mutex.js.map +1 -0
  342. package/dist/modules/workflow/git/pull-request.service.d.ts +124 -0
  343. package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -0
  344. package/dist/modules/workflow/git/pull-request.service.js +328 -0
  345. package/dist/modules/workflow/git/pull-request.service.js.map +1 -0
  346. package/dist/modules/workflow/locking-filesystem.d.ts +133 -0
  347. package/dist/modules/workflow/locking-filesystem.d.ts.map +1 -0
  348. package/dist/modules/workflow/locking-filesystem.js +400 -0
  349. package/dist/modules/workflow/locking-filesystem.js.map +1 -0
  350. package/dist/modules/workflow/pending-commits.service.d.ts +221 -0
  351. package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -0
  352. package/dist/modules/workflow/pending-commits.service.js +364 -0
  353. package/dist/modules/workflow/pending-commits.service.js.map +1 -0
  354. package/dist/modules/workflow/pending-commits.worker.d.ts +148 -0
  355. package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -0
  356. package/dist/modules/workflow/pending-commits.worker.js +245 -0
  357. package/dist/modules/workflow/pending-commits.worker.js.map +1 -0
  358. package/dist/modules/workflow/read-only-filesystem.d.ts +24 -0
  359. package/dist/modules/workflow/read-only-filesystem.d.ts.map +1 -0
  360. package/dist/modules/workflow/read-only-filesystem.js +39 -0
  361. package/dist/modules/workflow/read-only-filesystem.js.map +1 -0
  362. package/dist/modules/workflow/recovery-bot.d.ts +31 -0
  363. package/dist/modules/workflow/recovery-bot.d.ts.map +1 -0
  364. package/dist/modules/workflow/recovery-bot.js +64 -0
  365. package/dist/modules/workflow/recovery-bot.js.map +1 -0
  366. package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts +137 -0
  367. package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts.map +1 -0
  368. package/dist/modules/workflow/review-workflow/review-workflow.interface.js +2 -0
  369. package/dist/modules/workflow/review-workflow/review-workflow.interface.js.map +1 -0
  370. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts +26 -0
  371. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -0
  372. package/dist/modules/workflow/review-workflow/review-workflow.service.js +636 -0
  373. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -0
  374. package/dist/modules/workflow/sanitize-error.d.ts +29 -0
  375. package/dist/modules/workflow/sanitize-error.d.ts.map +1 -0
  376. package/dist/modules/workflow/sanitize-error.js +60 -0
  377. package/dist/modules/workflow/sanitize-error.js.map +1 -0
  378. package/dist/modules/workflow/session-ontology.policy.d.ts +52 -0
  379. package/dist/modules/workflow/session-ontology.policy.d.ts.map +1 -0
  380. package/dist/modules/workflow/session-ontology.policy.js +62 -0
  381. package/dist/modules/workflow/session-ontology.policy.js.map +1 -0
  382. package/dist/modules/workflow/session-ontology.service.d.ts +100 -0
  383. package/dist/modules/workflow/session-ontology.service.d.ts.map +1 -0
  384. package/dist/modules/workflow/session-ontology.service.js +143 -0
  385. package/dist/modules/workflow/session-ontology.service.js.map +1 -0
  386. package/dist/modules/workflow/workflow-hooks.d.ts +87 -0
  387. package/dist/modules/workflow/workflow-hooks.d.ts.map +1 -0
  388. package/dist/modules/workflow/workflow-hooks.js +35 -0
  389. package/dist/modules/workflow/workflow-hooks.js.map +1 -0
  390. package/dist/modules/workflow/workflow.errors.d.ts +171 -0
  391. package/dist/modules/workflow/workflow.errors.d.ts.map +1 -0
  392. package/dist/modules/workflow/workflow.errors.js +260 -0
  393. package/dist/modules/workflow/workflow.errors.js.map +1 -0
  394. package/dist/modules/workflow/workflow.routes.d.ts +26 -0
  395. package/dist/modules/workflow/workflow.routes.d.ts.map +1 -0
  396. package/dist/modules/workflow/workflow.routes.js +804 -0
  397. package/dist/modules/workflow/workflow.routes.js.map +1 -0
  398. package/dist/modules/workflow/workflow.service.d.ts +385 -0
  399. package/dist/modules/workflow/workflow.service.d.ts.map +1 -0
  400. package/dist/modules/workflow/workflow.service.js +1155 -0
  401. package/dist/modules/workflow/workflow.service.js.map +1 -0
  402. package/dist/modules/workspace/bevel-ignore.d.ts +25 -0
  403. package/dist/modules/workspace/bevel-ignore.d.ts.map +1 -0
  404. package/dist/modules/workspace/bevel-ignore.js +57 -0
  405. package/dist/modules/workspace/bevel-ignore.js.map +1 -0
  406. package/dist/modules/workspace/kb-seed.interface.d.ts +36 -0
  407. package/dist/modules/workspace/kb-seed.interface.d.ts.map +1 -0
  408. package/dist/modules/workspace/kb-seed.interface.js +2 -0
  409. package/dist/modules/workspace/kb-seed.interface.js.map +1 -0
  410. package/dist/modules/workspace/kb-seed.service.d.ts +70 -0
  411. package/dist/modules/workspace/kb-seed.service.d.ts.map +1 -0
  412. package/dist/modules/workspace/kb-seed.service.js +325 -0
  413. package/dist/modules/workspace/kb-seed.service.js.map +1 -0
  414. package/dist/modules/workspace/routine-write-policy.d.ts +49 -0
  415. package/dist/modules/workspace/routine-write-policy.d.ts.map +1 -0
  416. package/dist/modules/workspace/routine-write-policy.js +46 -0
  417. package/dist/modules/workspace/routine-write-policy.js.map +1 -0
  418. package/dist/modules/workspace/session-ontology.gate.d.ts +112 -0
  419. package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -0
  420. package/dist/modules/workspace/session-ontology.gate.js +161 -0
  421. package/dist/modules/workspace/session-ontology.gate.js.map +1 -0
  422. package/dist/modules/workspace/session-sink.d.ts +25 -0
  423. package/dist/modules/workspace/session-sink.d.ts.map +1 -0
  424. package/dist/modules/workspace/session-sink.js +8 -0
  425. package/dist/modules/workspace/session-sink.js.map +1 -0
  426. package/dist/modules/workspace/spill-store.d.ts +24 -0
  427. package/dist/modules/workspace/spill-store.d.ts.map +1 -0
  428. package/dist/modules/workspace/spill-store.js +87 -0
  429. package/dist/modules/workspace/spill-store.js.map +1 -0
  430. package/dist/modules/workspace/workspace.routes.d.ts +25 -0
  431. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -0
  432. package/dist/modules/workspace/workspace.routes.js +1046 -0
  433. package/dist/modules/workspace/workspace.routes.js.map +1 -0
  434. package/dist/modules/workspace/workspace.service.d.ts +339 -0
  435. package/dist/modules/workspace/workspace.service.d.ts.map +1 -0
  436. package/dist/modules/workspace/workspace.service.js +1221 -0
  437. package/dist/modules/workspace/workspace.service.js.map +1 -0
  438. package/dist/modules/workspace/workspace.tools.d.ts +19 -0
  439. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -0
  440. package/dist/modules/workspace/workspace.tools.js +767 -0
  441. package/dist/modules/workspace/workspace.tools.js.map +1 -0
  442. package/dist/shared/frontmatter-id.d.ts +35 -0
  443. package/dist/shared/frontmatter-id.d.ts.map +1 -0
  444. package/dist/shared/frontmatter-id.js +68 -0
  445. package/dist/shared/frontmatter-id.js.map +1 -0
  446. package/dist/shared/fs-walk.d.ts +9 -0
  447. package/dist/shared/fs-walk.d.ts.map +1 -0
  448. package/dist/shared/fs-walk.js +34 -0
  449. package/dist/shared/fs-walk.js.map +1 -0
  450. package/dist/shared/hash-email.d.ts +11 -0
  451. package/dist/shared/hash-email.d.ts.map +1 -0
  452. package/dist/shared/hash-email.js +14 -0
  453. package/dist/shared/hash-email.js.map +1 -0
  454. package/dist/shared/kb-layout.d.ts +38 -0
  455. package/dist/shared/kb-layout.d.ts.map +1 -0
  456. package/dist/shared/kb-layout.js +102 -0
  457. package/dist/shared/kb-layout.js.map +1 -0
  458. package/dist/shared/kb-layout.test.d.ts +2 -0
  459. package/dist/shared/kb-layout.test.d.ts.map +1 -0
  460. package/dist/shared/kb-layout.test.js +67 -0
  461. package/dist/shared/kb-layout.test.js.map +1 -0
  462. package/dist/shared/ssrf.d.ts +20 -0
  463. package/dist/shared/ssrf.d.ts.map +1 -0
  464. package/dist/shared/ssrf.js +89 -0
  465. package/dist/shared/ssrf.js.map +1 -0
  466. package/dist/shared/token-crypto.d.ts +16 -0
  467. package/dist/shared/token-crypto.d.ts.map +1 -0
  468. package/dist/shared/token-crypto.js +49 -0
  469. package/dist/shared/token-crypto.js.map +1 -0
  470. package/dist/shared/ttl-cache.d.ts +16 -0
  471. package/dist/shared/ttl-cache.d.ts.map +1 -0
  472. package/dist/shared/ttl-cache.js +27 -0
  473. package/dist/shared/ttl-cache.js.map +1 -0
  474. package/dist/shared/utcp-namespace.d.ts +46 -0
  475. package/dist/shared/utcp-namespace.d.ts.map +1 -0
  476. package/dist/shared/utcp-namespace.js +82 -0
  477. package/dist/shared/utcp-namespace.js.map +1 -0
  478. package/dist/version.d.ts +17 -0
  479. package/dist/version.d.ts.map +1 -0
  480. package/dist/version.js +19 -0
  481. package/dist/version.js.map +1 -0
  482. package/kb-template/.bevelignore +21 -0
  483. package/kb-template/Agents/.gitkeep +0 -0
  484. package/kb-template/Agents/README.md +38 -0
  485. package/kb-template/CLAUDE.md +419 -0
  486. package/kb-template/Data/.gitkeep +0 -0
  487. package/kb-template/Data/README.md +39 -0
  488. package/kb-template/KnowledgeBase/.gitkeep +0 -0
  489. package/kb-template/KnowledgeBase/README.md +37 -0
  490. package/kb-template/Pipelines/.gitkeep +0 -0
  491. package/kb-template/Pipelines/README.md +38 -0
  492. package/kb-template/Skills/.gitkeep +0 -0
  493. package/kb-template/Skills/README.md +32 -0
  494. package/kb-template/Tools/.gitkeep +0 -0
  495. package/kb-template/Tools/README.md +42 -0
  496. package/kb-template/access.md +36 -0
  497. package/migrations/0000_core_init.sql +243 -0
  498. package/migrations/meta/0000_snapshot.json +1480 -0
  499. package/migrations/meta/_journal.json +13 -0
  500. package/package.json +80 -0
  501. package/src/assets.ts +25 -0
  502. package/src/core/core-ports.ts +91 -0
  503. package/src/core/create-core-server.ts +338 -0
  504. package/src/core/create-core-services.ts +501 -0
  505. package/src/core-config.ts +257 -0
  506. package/src/index.ts +69 -0
  507. package/src/modules/access/__tests__/access-control.atref-batch.test.ts +98 -0
  508. package/src/modules/access/__tests__/access-control.read-batch.test.ts +132 -0
  509. package/src/modules/access/__tests__/access-control.service.test.ts +1011 -0
  510. package/src/modules/access/__tests__/access-mutation.service.test.ts +439 -0
  511. package/src/modules/access/__tests__/access-splice.test.ts +247 -0
  512. package/src/modules/access/__tests__/access.routes.revoke.test.ts +407 -0
  513. package/src/modules/access/__tests__/creator-access.test.ts +217 -0
  514. package/src/modules/access/__tests__/grant-sources.test.ts +204 -0
  515. package/src/modules/access/__tests__/kb-read-filter.test.ts +70 -0
  516. package/src/modules/access/__tests__/roles-admin.service.test.ts +469 -0
  517. package/src/modules/access/__tests__/roles-edit.test.ts +138 -0
  518. package/src/modules/access/__tests__/roles-yaml-guard.test.ts +70 -0
  519. package/src/modules/access/__tests__/roles.routes.test.ts +234 -0
  520. package/src/modules/access/access-control.interface.ts +383 -0
  521. package/src/modules/access/access-control.service.ts +1794 -0
  522. package/src/modules/access/access-errors.ts +60 -0
  523. package/src/modules/access/access-mutation.service.ts +369 -0
  524. package/src/modules/access/access-splice.ts +413 -0
  525. package/src/modules/access/access.routes.ts +894 -0
  526. package/src/modules/access/creator-access.ts +270 -0
  527. package/src/modules/access/kb-read-filter.ts +76 -0
  528. package/src/modules/access/roles-admin.service.ts +741 -0
  529. package/src/modules/access/roles-edit.ts +248 -0
  530. package/src/modules/access/roles-yaml-guard.ts +89 -0
  531. package/src/modules/admin/admin-access.routes.ts +29 -0
  532. package/src/modules/admin/admin-access.service.ts +38 -0
  533. package/src/modules/admin/admin.interface.ts +10 -0
  534. package/src/modules/auth/account-erasure.service.ts +183 -0
  535. package/src/modules/auth/auth.middleware.ts +78 -0
  536. package/src/modules/auth/auth.routes.ts +97 -0
  537. package/src/modules/auth/auth.service.ts +199 -0
  538. package/src/modules/code-mode/code-mode-names.ts +38 -0
  539. package/src/modules/code-mode/code-mode.tool.ts +117 -0
  540. package/src/modules/code-mode/index.ts +6 -0
  541. package/src/modules/database/connection.ts +15 -0
  542. package/src/modules/database/core-schema.ts +431 -0
  543. package/src/modules/database/migrate.ts +43 -0
  544. package/src/modules/database/schema.ts +11 -0
  545. package/src/modules/diff/__tests__/diff.routes.read-gate.test.ts +87 -0
  546. package/src/modules/diff/__tests__/diff.routes.rejectPathsLocked.test.ts +150 -0
  547. package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +184 -0
  548. package/src/modules/diff/__tests__/diff.service.test.ts +202 -0
  549. package/src/modules/diff/diff-paths.ts +9 -0
  550. package/src/modules/diff/diff.config.ts +12 -0
  551. package/src/modules/diff/diff.interface.ts +78 -0
  552. package/src/modules/diff/diff.routes.ts +277 -0
  553. package/src/modules/diff/diff.service.ts +508 -0
  554. package/src/modules/diff/line-diff.ts +79 -0
  555. package/src/modules/mcp/__tests__/bevel-oauth-provider.test.ts +287 -0
  556. package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +249 -0
  557. package/src/modules/mcp/__tests__/mcp-proxy-helpers.test.ts +253 -0
  558. package/src/modules/mcp/__tests__/mcp-session-store.test.ts +151 -0
  559. package/src/modules/mcp/__tests__/mcp.e2e.test.ts +150 -0
  560. package/src/modules/mcp/__tests__/mcp.routes.delete.test.ts +92 -0
  561. package/src/modules/mcp/__tests__/mcp.service.test.ts +414 -0
  562. package/src/modules/mcp/mcp-auth.middleware.ts +126 -0
  563. package/src/modules/mcp/mcp-session-store.ts +162 -0
  564. package/src/modules/mcp/mcp.routes.ts +263 -0
  565. package/src/modules/mcp/mcp.service.ts +973 -0
  566. package/src/modules/mcp/oauth/bevel-oauth-provider.ts +401 -0
  567. package/src/modules/mcp/oauth/oauth-consent.routes.ts +60 -0
  568. package/src/modules/mcp/oauth/oauth-state.ts +61 -0
  569. package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +277 -0
  570. package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +206 -0
  571. package/src/modules/secrets-vault/__tests__/mcp-oauth-discovery.service.test.ts +178 -0
  572. package/src/modules/secrets-vault/__tests__/scopes-covered.test.ts +101 -0
  573. package/src/modules/secrets-vault/__tests__/secrets-variable-loader.test.ts +54 -0
  574. package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +143 -0
  575. package/src/modules/secrets-vault/db-secrets-vault.service.ts +792 -0
  576. package/src/modules/secrets-vault/index.ts +25 -0
  577. package/src/modules/secrets-vault/mcp-oauth-discovery.service.ts +289 -0
  578. package/src/modules/secrets-vault/secrets-variable-loader.ts +104 -0
  579. package/src/modules/secrets-vault/secrets-vault.contract.ts +270 -0
  580. package/src/modules/secrets-vault/secrets-vault.routes.ts +526 -0
  581. package/src/modules/skills/__tests__/skills.service.test.ts +176 -0
  582. package/src/modules/skills/index.ts +10 -0
  583. package/src/modules/skills/skills.contract.ts +54 -0
  584. package/src/modules/skills/skills.routes.ts +38 -0
  585. package/src/modules/skills/skills.service.ts +245 -0
  586. package/src/modules/skills/skills.tools.ts +121 -0
  587. package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +358 -0
  588. package/src/modules/tool-auth/__tests__/internal-token.service.test.ts +79 -0
  589. package/src/modules/tool-auth/__tests__/manual-auth.middleware.test.ts +88 -0
  590. package/src/modules/tool-auth/external-api-key.errors.ts +25 -0
  591. package/src/modules/tool-auth/external-api-key.interface.ts +99 -0
  592. package/src/modules/tool-auth/external-api-key.service.ts +209 -0
  593. package/src/modules/tool-auth/internal-token.service.ts +124 -0
  594. package/src/modules/tool-auth/llm-usage-meter.ts +19 -0
  595. package/src/modules/tool-auth/tool-auth.middleware.ts +220 -0
  596. package/src/modules/tool-helpers/__tests__/phase0-loopback-spike.test.ts +129 -0
  597. package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +95 -0
  598. package/src/modules/tool-helpers/__tests__/tools-surface.test.ts +146 -0
  599. package/src/modules/tool-helpers/__tests__/validate-token.test.ts +75 -0
  600. package/src/modules/tool-helpers/index.ts +18 -0
  601. package/src/modules/tool-helpers/tool-context.ts +98 -0
  602. package/src/modules/tool-helpers/tool-def.ts +73 -0
  603. package/src/modules/tool-helpers/tool-handler.ts +91 -0
  604. package/src/modules/tool-helpers/tool.contract.ts +85 -0
  605. package/src/modules/tool-helpers/validate-token.ts +50 -0
  606. package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +200 -0
  607. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +499 -0
  608. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +156 -0
  609. package/src/modules/tool-manuals/index.ts +12 -0
  610. package/src/modules/tool-manuals/tool-manuals.contract.ts +183 -0
  611. package/src/modules/tool-manuals/tool-manuals.routes.ts +110 -0
  612. package/src/modules/tool-manuals/tool-manuals.service.ts +781 -0
  613. package/src/modules/tool-manuals/tool-manuals.tools.ts +202 -0
  614. package/src/modules/tool-registry/__tests__/tool-registry.test.ts +64 -0
  615. package/src/modules/tool-registry/manual.routes.ts +87 -0
  616. package/src/modules/tool-registry/tool-registry.ts +55 -0
  617. package/src/modules/tool-registry/tool.contract.ts +52 -0
  618. package/src/modules/workflow/__tests__/event-bus.test.ts +322 -0
  619. package/src/modules/workflow/__tests__/file-change-notifier.test.ts +51 -0
  620. package/src/modules/workflow/__tests__/format-affected-owners.test.ts +67 -0
  621. package/src/modules/workflow/__tests__/locking-filesystem.test.ts +445 -0
  622. package/src/modules/workflow/__tests__/pending-commits.canonical.test.ts +36 -0
  623. package/src/modules/workflow/__tests__/pending-commits.worker.test.ts +243 -0
  624. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +308 -0
  625. package/src/modules/workflow/__tests__/sanitize-error.test.ts +67 -0
  626. package/src/modules/workflow/__tests__/session-ontology.policy.test.ts +62 -0
  627. package/src/modules/workflow/__tests__/session-ontology.service.test.ts +200 -0
  628. package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +232 -0
  629. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +380 -0
  630. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +340 -0
  631. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +192 -0
  632. package/src/modules/workflow/agent-tools/workflow.tools.ts +502 -0
  633. package/src/modules/workflow/event-bus.ts +262 -0
  634. package/src/modules/workflow/events.routes.ts +266 -0
  635. package/src/modules/workflow/file-change-notifier.ts +54 -0
  636. package/src/modules/workflow/file-lock.service.ts +269 -0
  637. package/src/modules/workflow/git/__tests__/branch-name.test.ts +86 -0
  638. package/src/modules/workflow/git/__tests__/branchAuthor.test.ts +80 -0
  639. package/src/modules/workflow/git/__tests__/clone-config.test.ts +15 -0
  640. package/src/modules/workflow/git/__tests__/git-test-helpers.ts +47 -0
  641. package/src/modules/workflow/git/__tests__/git-version.failure.test.ts +24 -0
  642. package/src/modules/workflow/git/__tests__/git-version.test.ts +49 -0
  643. package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +389 -0
  644. package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +124 -0
  645. package/src/modules/workflow/git/__tests__/git.service.commitChanges.test.ts +105 -0
  646. package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +211 -0
  647. package/src/modules/workflow/git/__tests__/git.service.createBranch.test.ts +154 -0
  648. package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +320 -0
  649. package/src/modules/workflow/git/__tests__/git.service.diffFileAtCommit.test.ts +202 -0
  650. package/src/modules/workflow/git/__tests__/git.service.diffFileBetweenBranches.test.ts +453 -0
  651. package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +198 -0
  652. package/src/modules/workflow/git/__tests__/git.service.listTrackedFiles.test.ts +125 -0
  653. package/src/modules/workflow/git/__tests__/git.service.logForFile.test.ts +219 -0
  654. package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +145 -0
  655. package/src/modules/workflow/git/__tests__/git.service.pendingChanges.test.ts +240 -0
  656. package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +272 -0
  657. package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +232 -0
  658. package/src/modules/workflow/git/__tests__/git.service.readFileAtRef.test.ts +101 -0
  659. package/src/modules/workflow/git/__tests__/git.service.status.test.ts +127 -0
  660. package/src/modules/workflow/git/__tests__/mutex.test.ts +78 -0
  661. package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +225 -0
  662. package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-cancel.test.ts +101 -0
  663. package/src/modules/workflow/git/branch-name.ts +70 -0
  664. package/src/modules/workflow/git/clone-config.ts +71 -0
  665. package/src/modules/workflow/git/git-version.ts +70 -0
  666. package/src/modules/workflow/git/git.service.ts +2248 -0
  667. package/src/modules/workflow/git/mutex.ts +22 -0
  668. package/src/modules/workflow/git/pull-request.service.ts +447 -0
  669. package/src/modules/workflow/locking-filesystem.ts +489 -0
  670. package/src/modules/workflow/pending-commits.service.ts +444 -0
  671. package/src/modules/workflow/pending-commits.worker.ts +361 -0
  672. package/src/modules/workflow/read-only-filesystem.ts +54 -0
  673. package/src/modules/workflow/recovery-bot.ts +73 -0
  674. package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +560 -0
  675. package/src/modules/workflow/review-workflow/__tests__/cancel-pr.test.ts +176 -0
  676. package/src/modules/workflow/review-workflow/__tests__/merge-gate.test.ts +258 -0
  677. package/src/modules/workflow/review-workflow/review-workflow.interface.ts +199 -0
  678. package/src/modules/workflow/review-workflow/review-workflow.service.ts +806 -0
  679. package/src/modules/workflow/sanitize-error.ts +62 -0
  680. package/src/modules/workflow/session-ontology.policy.ts +70 -0
  681. package/src/modules/workflow/session-ontology.service.ts +178 -0
  682. package/src/modules/workflow/workflow-hooks.ts +101 -0
  683. package/src/modules/workflow/workflow.errors.ts +285 -0
  684. package/src/modules/workflow/workflow.routes.ts +858 -0
  685. package/src/modules/workflow/workflow.service.ts +1555 -0
  686. package/src/modules/workspace/__tests__/kb-seed.service.test.ts +213 -0
  687. package/src/modules/workspace/__tests__/routine-write-policy.test.ts +68 -0
  688. package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +237 -0
  689. package/src/modules/workspace/__tests__/spill-store.test.ts +43 -0
  690. package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +233 -0
  691. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +176 -0
  692. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +303 -0
  693. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +276 -0
  694. package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +120 -0
  695. package/src/modules/workspace/__tests__/workspace.service.test.ts +565 -0
  696. package/src/modules/workspace/__tests__/workspace.tools.test.ts +504 -0
  697. package/src/modules/workspace/bevel-ignore.ts +62 -0
  698. package/src/modules/workspace/kb-seed.interface.ts +36 -0
  699. package/src/modules/workspace/kb-seed.service.ts +361 -0
  700. package/src/modules/workspace/routine-write-policy.ts +79 -0
  701. package/src/modules/workspace/session-ontology.gate.ts +189 -0
  702. package/src/modules/workspace/session-sink.ts +25 -0
  703. package/src/modules/workspace/spill-store.ts +87 -0
  704. package/src/modules/workspace/workspace.routes.ts +1114 -0
  705. package/src/modules/workspace/workspace.service.ts +1343 -0
  706. package/src/modules/workspace/workspace.tools.ts +885 -0
  707. package/src/shared/__tests__/frontmatter-id.test.ts +88 -0
  708. package/src/shared/__tests__/fs-walk.test.ts +42 -0
  709. package/src/shared/__tests__/ssrf.test.ts +53 -0
  710. package/src/shared/__tests__/utcp-namespace.test.ts +19 -0
  711. package/src/shared/frontmatter-id.ts +72 -0
  712. package/src/shared/fs-walk.ts +30 -0
  713. package/src/shared/hash-email.ts +14 -0
  714. package/src/shared/kb-layout.test.ts +88 -0
  715. package/src/shared/kb-layout.ts +101 -0
  716. package/src/shared/ssrf.ts +78 -0
  717. package/src/shared/token-crypto.ts +54 -0
  718. package/src/shared/ttl-cache.ts +27 -0
  719. package/src/shared/utcp-namespace.ts +88 -0
  720. package/src/version.ts +19 -0
@@ -0,0 +1,176 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import type { AuthUser } from '@bevel-software/platform-shared';
3
+ import { ReviewWorkflowService } from '../review-workflow.service.js';
4
+ import type { Database } from '../../../database/connection.js';
5
+ import type { WorkspaceService } from '../../../workspace/workspace.service.js';
6
+ import type { GitService } from '../../git/git.service.js';
7
+ import type { IAccessControl } from '../../../access/access-control.interface.js';
8
+ import { hashEmail } from '../../../../shared/hash-email.js';
9
+ import { WorkflowValidationError } from '../../workflow.errors.js';
10
+
11
+ // Cancel is now a DB state flip (no `gh`): `update(change_requests) … WHERE
12
+ // number = ? AND state = 'open'`. This spy stands in for the update's
13
+ // `.returning()` — a non-empty array means the row was open and got closed.
14
+ const updateReturning = vi.fn(async () => [{ id: 'cr-1' }] as { id: string }[]);
15
+ // The re-read used only when the update matched zero rows (a race). Default to
16
+ // a merged row so that path yields already-applied.
17
+ const reReadState = { current: 'merged' as 'merged' | 'closed' };
18
+
19
+ function makeDb(): Database {
20
+ return {
21
+ update: () => ({ set: () => ({ where: () => ({ returning: updateReturning }) }) }),
22
+ select: () => ({
23
+ from: () => ({ where: () => ({ limit: async () => [{ state: reReadState.current }] }) }),
24
+ }),
25
+ } as unknown as Database;
26
+ }
27
+
28
+ const USER: AuthUser = { id: 'u1', email: 'juan@bevel.software', name: 'Juan' };
29
+ const OTHER_AUTHOR_HASH = hashEmail('someone-else@bevel.software');
30
+
31
+ function makeAccessControl(adminEmails: string[] = []): IAccessControl {
32
+ const set = new Set(adminEmails.map((e) => e.toLowerCase()));
33
+ return {
34
+ canWrite: async () => false,
35
+ canWriteBatch: async () => new Map(),
36
+ canRead: async () => true,
37
+ canReadBatch: async () => new Map(),
38
+ eligibleReaders: async () => ({ restricted: false, roles: [], users: [] }),
39
+ canReadAtRef: async () => null,
40
+ canDownload: async () => false,
41
+ canOwner: async () => false,
42
+ eligibleOwners: async () => ({ roles: [], users: [] }),
43
+ eligibleDownloaders: async () => ({ roles: [], users: [] }),
44
+ eligibleWriters: async () => ({ roles: [], users: [] }),
45
+ eligibleWriterEmails: async () => new Map(),
46
+ eligibleOwnerEmails: async () => new Map(),
47
+ grantSources: async () => ({}),
48
+ invalidate: () => {},
49
+ canWriteAtRef: async (_ws, _ref, email) => {
50
+ return set.has(email.trim().toLowerCase());
51
+ },
52
+ canWriteBatchAtRef: async () => null,
53
+ eligibleWritersAtRef: async () => null,
54
+ eligibleWritersForPathsAtRef: async () => null,
55
+ findEmailByHash: async () => null,
56
+ kbPrincipals: async () => ({ groups: [], people: [] }),
57
+ validateRolesYaml: () => ({ ok: true }),
58
+ referencesToRole: async () => [],
59
+ };
60
+ }
61
+
62
+ function makeService(accessControl: IAccessControl): ReviewWorkflowService {
63
+ // `ensureRemotesFetched` is best-effort (catches errors); the DB stub above
64
+ // stands in for the state-flip update + the race re-read.
65
+ const workspace = { ensureRemotesFetched: async () => undefined } as unknown as WorkspaceService;
66
+ return new ReviewWorkflowService(makeDb(), accessControl, workspace, {} as unknown as GitService);
67
+ }
68
+
69
+ describe('ReviewWorkflowService.cancelPr', () => {
70
+ beforeEach(() => {
71
+ updateReturning.mockClear();
72
+ updateReturning.mockResolvedValue([{ id: 'cr-1' }]);
73
+ reReadState.current = 'merged';
74
+ });
75
+
76
+ it('lets the PR author cancel (admin check skipped)', async () => {
77
+ const svc = makeService(makeAccessControl([]));
78
+ const result = await svc.cancelPr(
79
+ 42, USER, 'open', hashEmail(USER.email), 'current-company-state', 'ws-1',
80
+ );
81
+ expect(result.prNumber).toBe(42);
82
+ expect(typeof result.cancelledAt).toBe('string');
83
+ expect(new Date(result.cancelledAt).toString()).not.toBe('Invalid Date');
84
+ // The row was flipped via the guarded update (state='open' precondition).
85
+ expect(updateReturning).toHaveBeenCalledTimes(1);
86
+ });
87
+
88
+ it('lets a base-branch admin cancel someone else’s PR', async () => {
89
+ const svc = makeService(makeAccessControl([USER.email]));
90
+ const result = await svc.cancelPr(
91
+ 7, USER, 'open', OTHER_AUTHOR_HASH, 'current-company-state', 'ws-1',
92
+ );
93
+ expect(result.prNumber).toBe(7);
94
+ });
95
+
96
+ it('refuses when caller is neither author nor admin (403)', async () => {
97
+ const svc = makeService(makeAccessControl([])); // no admins
98
+ await expect(
99
+ svc.cancelPr(7, USER, 'open', OTHER_AUTHOR_HASH, 'current-company-state', 'ws-1'),
100
+ ).rejects.toMatchObject({
101
+ name: 'CancelAuthError',
102
+ status: 403,
103
+ message: expect.stringMatching(/only the author or an admin/i),
104
+ });
105
+ expect(updateReturning).not.toHaveBeenCalled();
106
+ });
107
+
108
+ it('refuses a merged PR with 422 already-applied — no state change', async () => {
109
+ const svc = makeService(makeAccessControl([USER.email]));
110
+ await expect(
111
+ svc.cancelPr(7, USER, 'merged', hashEmail(USER.email), 'current-company-state', 'ws-1'),
112
+ ).rejects.toMatchObject({
113
+ name: 'CancelStateError',
114
+ status: 422,
115
+ message: 'This change request was already applied.',
116
+ });
117
+ expect(updateReturning).not.toHaveBeenCalled();
118
+ });
119
+
120
+ it('refuses an already-closed PR with 422 already-cancelled', async () => {
121
+ const svc = makeService(makeAccessControl([USER.email]));
122
+ await expect(
123
+ svc.cancelPr(7, USER, 'closed', hashEmail(USER.email), 'current-company-state', 'ws-1'),
124
+ ).rejects.toMatchObject({
125
+ name: 'CancelStateError',
126
+ status: 422,
127
+ message: 'This change request is already cancelled.',
128
+ });
129
+ expect(updateReturning).not.toHaveBeenCalled();
130
+ });
131
+
132
+ it('maps a lost race (update matched 0 rows, row now merged) to already-applied', async () => {
133
+ updateReturning.mockResolvedValue([]); // the guarded update caught nothing
134
+ reReadState.current = 'merged';
135
+ const svc = makeService(makeAccessControl([USER.email]));
136
+ await expect(
137
+ svc.cancelPr(42, USER, 'open', hashEmail(USER.email), 'current-company-state', 'ws-1'),
138
+ ).rejects.toMatchObject({ name: 'CancelStateError', message: 'This change request was already applied.' });
139
+ });
140
+
141
+ it('rejects invalid PR numbers', async () => {
142
+ const svc = makeService(makeAccessControl([USER.email]));
143
+ for (const bad of [0, -1, 1.5, Number.NaN]) {
144
+ await expect(
145
+ svc.cancelPr(bad, USER, 'open', null, 'current-company-state', 'ws-1'),
146
+ ).rejects.toBeInstanceOf(WorkflowValidationError);
147
+ }
148
+ });
149
+
150
+ it('rejects empty workspaceId / baseBranch', async () => {
151
+ const svc = makeService(makeAccessControl([USER.email]));
152
+ await expect(
153
+ svc.cancelPr(42, USER, 'open', null, '', 'ws-1'),
154
+ ).rejects.toBeInstanceOf(WorkflowValidationError);
155
+ await expect(
156
+ svc.cancelPr(42, USER, 'open', null, 'current-company-state', ''),
157
+ ).rejects.toBeInstanceOf(WorkflowValidationError);
158
+ });
159
+
160
+ it('skips the admin lookup when the author check matches', async () => {
161
+ // canWriteAtRef would throw — if the service calls it for a matching author,
162
+ // the test fails. Guards against an authz-check ordering regression.
163
+ const throwingAccess: IAccessControl = {
164
+ ...makeAccessControl([]),
165
+ canWriteAtRef: async () => {
166
+ throw new Error('admin check should not run for matching author');
167
+ },
168
+ };
169
+ const svc = makeService(throwingAccess);
170
+ await expect(
171
+ svc.cancelPr(
172
+ 42, USER, 'open', hashEmail(USER.email), 'current-company-state', 'ws-1',
173
+ ),
174
+ ).resolves.toMatchObject({ prNumber: 42 });
175
+ });
176
+ });
@@ -0,0 +1,258 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import type { FileApprovalEntry, FileApprovalState, PullRequestState } from '@bevel-software/platform-shared';
3
+ import { ReviewWorkflowService } from '../review-workflow.service.js';
4
+
5
+ function makeService(): ReviewWorkflowService {
6
+ // evaluateMergeGate is pure — it never touches the DB, access service, or
7
+ // workspace. Constructing with `undefined as any` for unused deps keeps the
8
+ // test focused on the gate logic and avoids pulling in fixture scaffolding.
9
+ return new ReviewWorkflowService(undefined as any, undefined as any, undefined as any, undefined as any);
10
+ }
11
+
12
+ const ADMIN_ELIGIBLE = {
13
+ roles: ['Admin'],
14
+ users: [] as { name: string; email: string }[],
15
+ };
16
+ const EMPTY_ELIGIBLE = {
17
+ roles: [] as string[],
18
+ users: [] as { name: string; email: string }[],
19
+ };
20
+
21
+ // Spread-after-defaults so explicit empty eligibility (e.g. ownerless legacy
22
+ // file) passes through instead of being overwritten by the default.
23
+ function approval(overrides: Partial<FileApprovalState>): FileApprovalState {
24
+ return {
25
+ path: 'Knowledge/Foo.md',
26
+ eligibleApprovers: ADMIN_ELIGIBLE,
27
+ approvedBy: [],
28
+ isApproved: false,
29
+ viewerCanApprove: false,
30
+ ...overrides,
31
+ };
32
+ }
33
+
34
+ function entry(overrides: Partial<FileApprovalEntry>): FileApprovalEntry {
35
+ return {
36
+ email: 'alice@bevel.software',
37
+ name: 'Alice',
38
+ approvedAt: '2026-04-20T12:00:00Z',
39
+ isStale: false,
40
+ isSelfApproval: false,
41
+ ...overrides,
42
+ };
43
+ }
44
+
45
+ describe('evaluateMergeGate', () => {
46
+ const svc = makeService();
47
+
48
+ it('passes cleanly when every gate-relevant file has a non-stale approval', () => {
49
+ const result = svc.evaluateMergeGate({
50
+ prNumber: 1,
51
+ state: 'open',
52
+ approvals: [
53
+ approval({ path: 'A.md', isApproved: true, approvedBy: [entry({})] }),
54
+ approval({ path: 'B.md', isApproved: true, approvedBy: [entry({})] }),
55
+ ],
56
+ });
57
+ expect(result).toEqual({ mergeable: true, reasons: [], warnings: [] });
58
+ });
59
+
60
+ it('rejects merged PRs as a hard block', () => {
61
+ const result = svc.evaluateMergeGate({
62
+ prNumber: 1,
63
+ state: 'merged' as PullRequestState,
64
+ approvals: [approval({ isApproved: true })],
65
+ });
66
+ expect(result.mergeable).toBe(false);
67
+ expect(result.reasons[0]).toMatch(/already been merged/i);
68
+ });
69
+
70
+ it('rejects closed PRs as a hard block', () => {
71
+ const result = svc.evaluateMergeGate({
72
+ prNumber: 1,
73
+ state: 'closed',
74
+ approvals: [approval({ isApproved: true })],
75
+ });
76
+ expect(result.mergeable).toBe(false);
77
+ expect(result.reasons[0]).toMatch(/closed/i);
78
+ });
79
+
80
+ it('rejects PRs with no files to approve as a hard block', () => {
81
+ const result = svc.evaluateMergeGate({
82
+ prNumber: 1,
83
+ state: 'open',
84
+ approvals: [],
85
+ });
86
+ expect(result.mergeable).toBe(false);
87
+ expect(result.reasons[0]).toMatch(/no file changes/i);
88
+ });
89
+
90
+ it('ignores md files with no eligible approvers — no warning, no block', () => {
91
+ // Files outside the access-controlled surface (no roles/users grant
92
+ // write) are not part of the gate.
93
+ const result = svc.evaluateMergeGate({
94
+ prNumber: 1,
95
+ state: 'open',
96
+ approvals: [
97
+ approval({ path: 'A.md', isApproved: true, approvedBy: [entry({})] }),
98
+ approval({ path: 'Legacy.md', eligibleApprovers: EMPTY_ELIGIBLE }),
99
+ ],
100
+ });
101
+ expect(result.mergeable).toBe(true);
102
+ expect(result.reasons).toEqual([]);
103
+ expect(result.warnings).toEqual([]);
104
+ });
105
+
106
+ it('ignores non-md files regardless of eligibility', () => {
107
+ // TypeScript sources, JSON, images etc. don't participate in the gate.
108
+ const result = svc.evaluateMergeGate({
109
+ prNumber: 1,
110
+ state: 'open',
111
+ approvals: [
112
+ approval({ path: 'src/foo.ts', eligibleApprovers: ADMIN_ELIGIBLE }),
113
+ approval({ path: 'assets/logo.png', eligibleApprovers: EMPTY_ELIGIBLE }),
114
+ ],
115
+ });
116
+ expect(result.mergeable).toBe(true);
117
+ expect(result.reasons).toEqual([]);
118
+ expect(result.warnings).toEqual([]);
119
+ });
120
+
121
+ it('treats unapproved md-with-eligible-approvers as a warning, not a hard block', () => {
122
+ const result = svc.evaluateMergeGate({
123
+ prNumber: 1,
124
+ state: 'open',
125
+ approvals: [
126
+ approval({
127
+ path: 'B.md',
128
+ eligibleApprovers: {
129
+ roles: ['Product Manager'],
130
+ users: [{ name: 'Bob', email: 'bob@bevel.software' }],
131
+ },
132
+ approvedBy: [],
133
+ }),
134
+ ],
135
+ });
136
+ expect(result.mergeable).toBe(true);
137
+ expect(result.reasons).toEqual([]);
138
+ expect(result.warnings).toEqual([
139
+ 'Waiting on approval for B.md from Product Manager; Bob <bob@bevel.software>.',
140
+ ]);
141
+ });
142
+
143
+ it('distinguishes stale approvals from never-approved in warnings', () => {
144
+ const result = svc.evaluateMergeGate({
145
+ prNumber: 1,
146
+ state: 'open',
147
+ approvals: [
148
+ approval({
149
+ path: 'A.md',
150
+ eligibleApprovers: ADMIN_ELIGIBLE,
151
+ approvedBy: [entry({ email: 'alice@bevel.software', isStale: true })],
152
+ }),
153
+ approval({
154
+ path: 'B.md',
155
+ eligibleApprovers: ADMIN_ELIGIBLE,
156
+ approvedBy: [],
157
+ }),
158
+ ],
159
+ });
160
+ expect(result.mergeable).toBe(true);
161
+ expect(result.warnings).toContain('Admin need to re-approve A.md after the latest push.');
162
+ expect(result.warnings).toContain('Waiting on approval for B.md from Admin.');
163
+ });
164
+
165
+ it('surfaces only the hard block when the PR is closed, not soft warnings', () => {
166
+ const result = svc.evaluateMergeGate({
167
+ prNumber: 1,
168
+ state: 'closed',
169
+ approvals: [
170
+ approval({ path: 'A.md', eligibleApprovers: EMPTY_ELIGIBLE }),
171
+ approval({ path: 'B.md' }),
172
+ ],
173
+ });
174
+ expect(result.mergeable).toBe(false);
175
+ expect(result.reasons[0]).toMatch(/closed/i);
176
+ });
177
+
178
+ it('is case-insensitive on the .md extension check', () => {
179
+ const result = svc.evaluateMergeGate({
180
+ prNumber: 1,
181
+ state: 'open',
182
+ approvals: [
183
+ approval({
184
+ path: 'Knowledge/FOO.MD',
185
+ eligibleApprovers: ADMIN_ELIGIBLE,
186
+ approvedBy: [],
187
+ }),
188
+ ],
189
+ });
190
+ expect(result.warnings).toContain('Waiting on approval for Knowledge/FOO.MD from Admin.');
191
+ });
192
+
193
+ // Regression: roles.yaml is the file that decides Admin membership, but it
194
+ // isn't a `.md` KB node — so before this gate it slipped through with zero
195
+ // warnings, and a roles.yaml-only change request could merge into a protected
196
+ // branch with no approval and no admin check, letting its author self-promote
197
+ // to Admin. The gate must bind roles.yaml (and access.md) like an md node.
198
+ it('treats an unapproved roles.yaml change as a warning (privilege-escalation guard)', () => {
199
+ const result = svc.evaluateMergeGate({
200
+ prNumber: 1,
201
+ state: 'open',
202
+ approvals: [
203
+ approval({ path: 'roles.yaml', eligibleApprovers: ADMIN_ELIGIBLE, approvedBy: [] }),
204
+ ],
205
+ });
206
+ // mergeable stays true (it's a soft warning, bypassable only by an admin in
207
+ // mergePr) — the point is that the warning EXISTS, so a non-admin merge of a
208
+ // roles.yaml-only PR is no longer silently waved through.
209
+ expect(result.warnings).toContain('Waiting on approval for roles.yaml from Admin.');
210
+ // Pin the non-blocking contract: this PR's guarantee is "warn, don't block".
211
+ // If evaluateMergeGate ever starts adding blocking reasons or flipping
212
+ // mergeable to false for an access-config file, these must fail.
213
+ expect(result.mergeable).toBe(true);
214
+ expect(result.reasons).toEqual([]);
215
+ });
216
+
217
+ it('treats an unapproved access.md change as a warning, at root and nested', () => {
218
+ const result = svc.evaluateMergeGate({
219
+ prNumber: 1,
220
+ state: 'open',
221
+ approvals: [
222
+ approval({ path: 'access.md', eligibleApprovers: ADMIN_ELIGIBLE, approvedBy: [] }),
223
+ approval({ path: 'Knowledge/Sales/access.md', eligibleApprovers: ADMIN_ELIGIBLE, approvedBy: [] }),
224
+ ],
225
+ });
226
+ expect(result.warnings).toContain('Waiting on approval for access.md from Admin.');
227
+ expect(result.warnings).toContain('Waiting on approval for Knowledge/Sales/access.md from Admin.');
228
+ // Same non-blocking contract as roles.yaml: warn, never block.
229
+ expect(result.mergeable).toBe(true);
230
+ expect(result.reasons).toEqual([]);
231
+ });
232
+
233
+ it('a roles.yaml change WITH a non-stale eligible approval passes cleanly', () => {
234
+ const result = svc.evaluateMergeGate({
235
+ prNumber: 1,
236
+ state: 'open',
237
+ approvals: [
238
+ approval({ path: 'roles.yaml', isApproved: true, approvedBy: [entry({})] }),
239
+ ],
240
+ });
241
+ expect(result).toEqual({ mergeable: true, reasons: [], warnings: [] });
242
+ });
243
+
244
+ it('does not gate roles.yaml when no one is eligible to approve it', () => {
245
+ // Mirrors the md path: a config file with no eligible approver can't be
246
+ // approved, so it neither warns nor blocks (the merge-gate would otherwise
247
+ // deadlock on an un-approvable file).
248
+ const result = svc.evaluateMergeGate({
249
+ prNumber: 1,
250
+ state: 'open',
251
+ approvals: [
252
+ approval({ path: 'roles.yaml', eligibleApprovers: EMPTY_ELIGIBLE }),
253
+ ],
254
+ });
255
+ expect(result.mergeable).toBe(true);
256
+ expect(result.warnings).toEqual([]);
257
+ });
258
+ });
@@ -0,0 +1,199 @@
1
+ import type {
2
+ AuthUser,
3
+ CancelPrResult,
4
+ FileApprovalState,
5
+ MergePrResult,
6
+ PostPrCommentInput,
7
+ PrReviewComment,
8
+ PullRequestFile,
9
+ PullRequestState,
10
+ } from '@bevel-software/platform-shared';
11
+
12
+ export interface MergeGateInput {
13
+ prNumber: number;
14
+ state: PullRequestState;
15
+ approvals: FileApprovalState[];
16
+ }
17
+
18
+ export interface MergeGateResult {
19
+ /** False only on hard blocks (PR closed/merged, zero files). Warnings do NOT flip this false. */
20
+ mergeable: boolean;
21
+ /** Hard-block reasons — merge cannot proceed until these resolve. */
22
+ reasons: string[];
23
+ /**
24
+ * Soft warnings — md files with an owner who hasn't approved (or whose
25
+ * approval is stale). Merge proceeds only when the caller explicitly opts
26
+ * into bypass; the frontend surfaces these in a confirm dialog.
27
+ */
28
+ warnings: string[];
29
+ }
30
+
31
+ /**
32
+ * Owns the Bevel-side review state for a PR: comments (phase 2), per-file
33
+ * approvals (phase 3), and the merge gate (phase 4). GitHub stays authoritative
34
+ * for the diff + eventual merge; everything in this interface is in-app state
35
+ * the team uses to decide whether the merge should fire.
36
+ */
37
+ export interface IReviewWorkflowService {
38
+ /** List all comments for a PR, oldest first. */
39
+ listComments(prNumber: number): Promise<PrReviewComment[]>;
40
+
41
+ /** Post a new comment. Shape of `input` decides whether it's general, file-level, or inline. */
42
+ postComment(
43
+ prNumber: number,
44
+ user: AuthUser,
45
+ input: PostPrCommentInput,
46
+ headSha: string,
47
+ ): Promise<PrReviewComment>;
48
+
49
+ /**
50
+ * Edit an existing comment. Only the original author may edit — 403 otherwise.
51
+ * `prNumber` scopes the lookup so a caller can't touch a comment from a
52
+ * different PR via a guessed id; the comment must belong to this PR.
53
+ */
54
+ editComment(
55
+ commentId: string,
56
+ prNumber: number,
57
+ user: AuthUser,
58
+ body: string,
59
+ ): Promise<PrReviewComment>;
60
+
61
+ /**
62
+ * Delete a comment. Only the original author may delete — 403 otherwise.
63
+ * Replies are preserved (orphaned to the thread root). `prNumber` scopes the
64
+ * lookup so a caller can't cross PRs via a guessed id.
65
+ */
66
+ deleteComment(commentId: string, prNumber: number, user: AuthUser): Promise<void>;
67
+
68
+ /**
69
+ * Compose the per-file approval state for a PR detail response. Resolves
70
+ * the eligible approver set against **the PR's base branch on origin**
71
+ * (e.g. `origin/current-company-state`), then joins approval rows from
72
+ * the DB, marking stale approvals and flagging self-approvals.
73
+ *
74
+ * Why base, not head: the PR's head can carry arbitrary edits to
75
+ * `roles.yaml` or `access.md`, so resolving against head would let a PR
76
+ * author grant themselves approval rights by editing access config in
77
+ * their own branch. The base is fast-forward-only (protected branches
78
+ * are gated by their own PR review), so it's the authoritative source
79
+ * for "who has write access to this path right now."
80
+ *
81
+ * `workspaceId` is optional. When omitted (or when the access lookup
82
+ * fails — e.g. the workspace hasn't fetched `origin/<base>` yet), the
83
+ * result is still one `FileApprovalState` per input file but with empty
84
+ * eligibility. Downstream the merge gate treats empty-eligibility entries
85
+ * as silent (outside the gate), so a missing workspace degrades to
86
+ * "PR detail renders, approval gating unavailable" rather than a hard
87
+ * failure.
88
+ */
89
+ getApprovalStates(
90
+ prNumber: number,
91
+ files: PullRequestFile[],
92
+ headSha: string,
93
+ baseBranch: string,
94
+ prAuthorIdHash: string | null,
95
+ workspaceId?: string,
96
+ /**
97
+ * Email of the user viewing the PR. When provided, each returned state
98
+ * carries `viewerCanApprove` populated from the access tree at
99
+ * `origin/<baseBranch>`. Omitted (or absent workspace) → `viewerCanApprove`
100
+ * defaults to `false` everywhere.
101
+ */
102
+ viewerEmail?: string,
103
+ ): Promise<FileApprovalState[]>;
104
+
105
+ /**
106
+ * Approve one file. Requires the caller to hold `write` on the path per
107
+ * the access tree on `origin/<baseBranch>` (403 otherwise). Idempotent —
108
+ * approving twice on the same headSha is a no-op. Returns the fresh
109
+ * composite state for all files.
110
+ */
111
+ approveFile(
112
+ prNumber: number,
113
+ path: string,
114
+ user: AuthUser,
115
+ files: PullRequestFile[],
116
+ headSha: string,
117
+ baseBranch: string,
118
+ prAuthorIdHash: string | null,
119
+ workspaceId: string,
120
+ ): Promise<FileApprovalState[]>;
121
+
122
+ /**
123
+ * Revoke the caller's own approval on one file. Non-author users cannot
124
+ * revoke someone else's approval (403). Idempotent when no matching
125
+ * approval exists.
126
+ */
127
+ unapproveFile(
128
+ prNumber: number,
129
+ path: string,
130
+ user: AuthUser,
131
+ files: PullRequestFile[],
132
+ headSha: string,
133
+ baseBranch: string,
134
+ prAuthorIdHash: string | null,
135
+ workspaceId: string,
136
+ ): Promise<FileApprovalState[]>;
137
+
138
+ /**
139
+ * Pure derivation of the merge gate from PR state + per-file approvals.
140
+ * Exposed as a method (not a free function) so the HTTP response and the
141
+ * merge route re-validate via the same code path.
142
+ */
143
+ evaluateMergeGate(input: MergeGateInput): MergeGateResult;
144
+
145
+ /**
146
+ * Execute the merge via a local `git merge --no-ff` on the base branch's
147
+ * workspace, pushed to origin (provider-agnostic — no PR API). Re-validates
148
+ * the gate server-side first (don't trust the caller's cached
149
+ * `mergeableInBevel`), writes a row to `pr_merge_log` bracketing the attempt,
150
+ * flips the `change_requests` row to `merged`, and tags the merge commit with
151
+ * the real triggerer so the audit trail lives on the commit. Conflicts throw
152
+ * `ChangeRequestConflictsError` (409) with the conflicting paths.
153
+ *
154
+ * **Merge authority invariant**: this method is the *only* backend code path
155
+ * that lands a change request on a protected branch.
156
+ */
157
+ mergePr(
158
+ prNumber: number,
159
+ user: AuthUser,
160
+ /** Fresh detail fetched within the request — used for the gate and the head SHA. */
161
+ headSha: string,
162
+ approvals: FileApprovalState[],
163
+ state: PullRequestState,
164
+ prTitle: string,
165
+ /** The PR's base branch — used to resolve admin status at `origin/<base>` for bypass. */
166
+ baseBranch: string,
167
+ /** Workspace clone — used for the access-tree lookup that gates bypass. */
168
+ workspaceId: string,
169
+ /**
170
+ * When true, proceed even if soft warnings (unapproved md-with-owner files)
171
+ * exist. Hard blocks are refused regardless. The bypassed warnings are
172
+ * recorded in the merge commit body for audit. Bypass requires admin
173
+ * write access at `origin/<baseBranch>` (i.e. write on `roles.yaml`) —
174
+ * non-admins get a 403 even when warnings would otherwise be skippable.
175
+ */
176
+ opts?: { bypass?: boolean },
177
+ ): Promise<MergePrResult>;
178
+
179
+ /**
180
+ * Close a change request without merging — flips the `change_requests` row to
181
+ * `closed` (guarded on `state = 'open'`). Authorized when the caller is the PR
182
+ * author (hash-matched against `authorIdHash`) OR an admin on the base branch
183
+ * (write on `roles.yaml` at `origin/<baseBranch>` — the same predicate
184
+ * `mergePr`'s bypass uses). Refused with 422 when the CR is already merged or
185
+ * closed. The source branch is left intact.
186
+ */
187
+ cancelPr(
188
+ prNumber: number,
189
+ user: AuthUser,
190
+ /** The PR's current state per a fresh `getPrDetail` fetch. */
191
+ state: PullRequestState,
192
+ /** Hash of the PR-author email from the body marker — null when absent. */
193
+ authorIdHash: string | null,
194
+ /** The PR's base branch — used to resolve admin authority at `origin/<base>`. */
195
+ baseBranch: string,
196
+ /** Workspace clone — used for the access-tree lookup that gates admin authority. */
197
+ workspaceId: string,
198
+ ): Promise<CancelPrResult>;
199
+ }