@bevel-software/platform-core-backend 0.26.0 → 0.27.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 (613) hide show
  1. package/agent-guide/access-control.md +17 -0
  2. package/agent-guide/conventions.md +8 -0
  3. package/agent-guide/html-views.md +83 -0
  4. package/agent-guide/new-knowledge-base.md +24 -0
  5. package/agent-guide/tool-manuals.md +10 -0
  6. package/dist/assets.d.ts +19 -0
  7. package/dist/assets.d.ts.map +1 -1
  8. package/dist/assets.js +26 -2
  9. package/dist/assets.js.map +1 -1
  10. package/dist/core/catalog-revision.d.ts +19 -1
  11. package/dist/core/catalog-revision.d.ts.map +1 -1
  12. package/dist/core/catalog-revision.js +14 -3
  13. package/dist/core/catalog-revision.js.map +1 -1
  14. package/dist/core/create-core-server.d.ts +5 -0
  15. package/dist/core/create-core-server.d.ts.map +1 -1
  16. package/dist/core/create-core-server.js +54 -3
  17. package/dist/core/create-core-server.js.map +1 -1
  18. package/dist/core/create-core-services.d.ts +26 -0
  19. package/dist/core/create-core-services.d.ts.map +1 -1
  20. package/dist/core/create-core-services.js +100 -8
  21. package/dist/core/create-core-services.js.map +1 -1
  22. package/dist/core/lifecycle.d.ts +16 -1
  23. package/dist/core/lifecycle.d.ts.map +1 -1
  24. package/dist/core/lifecycle.js +18 -1
  25. package/dist/core/lifecycle.js.map +1 -1
  26. package/dist/core-config.d.ts +21 -0
  27. package/dist/core-config.d.ts.map +1 -1
  28. package/dist/core-config.js +22 -1
  29. package/dist/core-config.js.map +1 -1
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +2 -2
  33. package/dist/index.js.map +1 -1
  34. package/dist/modules/access/access-control.interface.d.ts +8 -0
  35. package/dist/modules/access/access-control.interface.d.ts.map +1 -1
  36. package/dist/modules/access/access-control.service.d.ts +1 -0
  37. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  38. package/dist/modules/access/access-control.service.js +11 -0
  39. package/dist/modules/access/access-control.service.js.map +1 -1
  40. package/dist/modules/access/directory-sync-bot.js +1 -1
  41. package/dist/modules/access/directory-sync-bot.js.map +1 -1
  42. package/dist/modules/agent-guide/agent-guide.d.ts +6 -0
  43. package/dist/modules/agent-guide/agent-guide.d.ts.map +1 -1
  44. package/dist/modules/agent-guide/agent-guide.js +8 -0
  45. package/dist/modules/agent-guide/agent-guide.js.map +1 -1
  46. package/dist/modules/agent-guide/index.d.ts +1 -1
  47. package/dist/modules/agent-guide/index.d.ts.map +1 -1
  48. package/dist/modules/agent-guide/index.js +1 -1
  49. package/dist/modules/agent-guide/index.js.map +1 -1
  50. package/dist/modules/agent-instructions/compose.d.ts +5 -0
  51. package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
  52. package/dist/modules/agent-instructions/compose.js +19 -2
  53. package/dist/modules/agent-instructions/compose.js.map +1 -1
  54. package/dist/modules/agent-instructions/shared-file-rules.js +19 -19
  55. package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -1
  56. package/dist/modules/audit/agent-audit.service.d.ts +21 -2
  57. package/dist/modules/audit/agent-audit.service.d.ts.map +1 -1
  58. package/dist/modules/audit/agent-audit.service.js +43 -2
  59. package/dist/modules/audit/agent-audit.service.js.map +1 -1
  60. package/dist/modules/audit/agent-connection.routes.d.ts +34 -0
  61. package/dist/modules/audit/agent-connection.routes.d.ts.map +1 -0
  62. package/dist/modules/audit/agent-connection.routes.js +38 -0
  63. package/dist/modules/audit/agent-connection.routes.js.map +1 -0
  64. package/dist/modules/audit/audit.contract.d.ts +24 -0
  65. package/dist/modules/audit/audit.contract.d.ts.map +1 -1
  66. package/dist/modules/audit/audit.contract.js.map +1 -1
  67. package/dist/modules/audit/index.d.ts +1 -0
  68. package/dist/modules/audit/index.d.ts.map +1 -1
  69. package/dist/modules/audit/index.js +1 -0
  70. package/dist/modules/audit/index.js.map +1 -1
  71. package/dist/modules/auth/account.routes.d.ts.map +1 -1
  72. package/dist/modules/auth/account.routes.js +10 -3
  73. package/dist/modules/auth/account.routes.js.map +1 -1
  74. package/dist/modules/auth/auth.middleware.d.ts +7 -0
  75. package/dist/modules/auth/auth.middleware.d.ts.map +1 -1
  76. package/dist/modules/auth/auth.middleware.js +1 -1
  77. package/dist/modules/auth/auth.middleware.js.map +1 -1
  78. package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -1
  79. package/dist/modules/code-mode/code-mode.tool.js +11 -3
  80. package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
  81. package/dist/modules/database/core-schema.d.ts +96 -0
  82. package/dist/modules/database/core-schema.d.ts.map +1 -1
  83. package/dist/modules/database/core-schema.js +32 -3
  84. package/dist/modules/database/core-schema.js.map +1 -1
  85. package/dist/modules/embed/account-link.service.d.ts +42 -0
  86. package/dist/modules/embed/account-link.service.d.ts.map +1 -0
  87. package/dist/modules/embed/account-link.service.js +50 -0
  88. package/dist/modules/embed/account-link.service.js.map +1 -0
  89. package/dist/modules/embed/embed-link.d.ts +58 -0
  90. package/dist/modules/embed/embed-link.d.ts.map +1 -0
  91. package/dist/modules/embed/embed-link.js +160 -0
  92. package/dist/modules/embed/embed-link.js.map +1 -0
  93. package/dist/modules/embed/embed.errors.d.ts +30 -0
  94. package/dist/modules/embed/embed.errors.d.ts.map +1 -0
  95. package/dist/modules/embed/embed.errors.js +42 -0
  96. package/dist/modules/embed/embed.errors.js.map +1 -0
  97. package/dist/modules/embed/embed.interface.d.ts +204 -0
  98. package/dist/modules/embed/embed.interface.d.ts.map +1 -0
  99. package/dist/modules/embed/embed.interface.js +2 -0
  100. package/dist/modules/embed/embed.interface.js.map +1 -0
  101. package/dist/modules/embed/embed.routes.d.ts +59 -0
  102. package/dist/modules/embed/embed.routes.d.ts.map +1 -0
  103. package/dist/modules/embed/embed.routes.js +343 -0
  104. package/dist/modules/embed/embed.routes.js.map +1 -0
  105. package/dist/modules/embed/embed.service.d.ts +169 -0
  106. package/dist/modules/embed/embed.service.d.ts.map +1 -0
  107. package/dist/modules/embed/embed.service.js +627 -0
  108. package/dist/modules/embed/embed.service.js.map +1 -0
  109. package/dist/modules/embed/embed.tools.d.ts +51 -0
  110. package/dist/modules/embed/embed.tools.d.ts.map +1 -0
  111. package/dist/modules/embed/embed.tools.js +170 -0
  112. package/dist/modules/embed/embed.tools.js.map +1 -0
  113. package/dist/modules/embed/mcp-app.d.ts +64 -0
  114. package/dist/modules/embed/mcp-app.d.ts.map +1 -0
  115. package/dist/modules/embed/mcp-app.js +147 -0
  116. package/dist/modules/embed/mcp-app.js.map +1 -0
  117. package/dist/modules/embed/mcp-app.routes.d.ts +21 -0
  118. package/dist/modules/embed/mcp-app.routes.d.ts.map +1 -0
  119. package/dist/modules/embed/mcp-app.routes.js +36 -0
  120. package/dist/modules/embed/mcp-app.routes.js.map +1 -0
  121. package/dist/modules/github-app/github-app.connection.d.ts +15 -0
  122. package/dist/modules/github-app/github-app.connection.d.ts.map +1 -1
  123. package/dist/modules/github-app/github-app.connection.js +34 -3
  124. package/dist/modules/github-app/github-app.connection.js.map +1 -1
  125. package/dist/modules/kb-fs/locking-filesystem.d.ts +65 -0
  126. package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
  127. package/dist/modules/kb-fs/locking-filesystem.js +300 -0
  128. package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
  129. package/dist/modules/kb-sync/kb-sync.interface.d.ts +5 -0
  130. package/dist/modules/kb-sync/kb-sync.interface.d.ts.map +1 -1
  131. package/dist/modules/kb-sync/kb-sync.service.d.ts.map +1 -1
  132. package/dist/modules/kb-sync/kb-sync.service.js +6 -0
  133. package/dist/modules/kb-sync/kb-sync.service.js.map +1 -1
  134. package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
  135. package/dist/modules/mcp/mcp-auth.middleware.js +2 -1
  136. package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
  137. package/dist/modules/mcp/mcp.service.d.ts +28 -1
  138. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  139. package/dist/modules/mcp/mcp.service.js +64 -8
  140. package/dist/modules/mcp/mcp.service.js.map +1 -1
  141. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +24 -0
  142. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
  143. package/dist/modules/mcp/oauth/bevel-oauth-provider.js +32 -4
  144. package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
  145. package/dist/modules/onboarding/onboarding.contract.d.ts +80 -0
  146. package/dist/modules/onboarding/onboarding.contract.d.ts.map +1 -0
  147. package/dist/modules/onboarding/onboarding.contract.js +7 -0
  148. package/dist/modules/onboarding/onboarding.contract.js.map +1 -0
  149. package/dist/modules/onboarding/onboarding.routes.d.ts +18 -0
  150. package/dist/modules/onboarding/onboarding.routes.d.ts.map +1 -0
  151. package/dist/modules/onboarding/onboarding.routes.js +81 -0
  152. package/dist/modules/onboarding/onboarding.routes.js.map +1 -0
  153. package/dist/modules/onboarding/starter-pack.service.d.ts +213 -0
  154. package/dist/modules/onboarding/starter-pack.service.d.ts.map +1 -0
  155. package/dist/modules/onboarding/starter-pack.service.js +492 -0
  156. package/dist/modules/onboarding/starter-pack.service.js.map +1 -0
  157. package/dist/modules/onboarding/starter-packs.d.ts +78 -0
  158. package/dist/modules/onboarding/starter-packs.d.ts.map +1 -0
  159. package/dist/modules/onboarding/starter-packs.js +156 -0
  160. package/dist/modules/onboarding/starter-packs.js.map +1 -0
  161. package/dist/modules/plugins/index.d.ts +1 -1
  162. package/dist/modules/plugins/index.d.ts.map +1 -1
  163. package/dist/modules/plugins/index.js +1 -1
  164. package/dist/modules/plugins/index.js.map +1 -1
  165. package/dist/modules/plugins/plugin-provision.service.d.ts +19 -0
  166. package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
  167. package/dist/modules/plugins/plugin-provision.service.js +18 -1
  168. package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
  169. package/dist/modules/plugins/plugins.routes.d.ts +0 -36
  170. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  171. package/dist/modules/plugins/plugins.routes.js +31 -0
  172. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  173. package/dist/modules/settings/deployment-settings.service.d.ts +34 -0
  174. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  175. package/dist/modules/settings/deployment-settings.service.js +134 -1
  176. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  177. package/dist/modules/settings/repository-source.d.ts +1 -0
  178. package/dist/modules/settings/repository-source.d.ts.map +1 -1
  179. package/dist/modules/settings/repository-source.js +3 -3
  180. package/dist/modules/settings/repository-source.js.map +1 -1
  181. package/dist/modules/skills/skills.tools.d.ts.map +1 -1
  182. package/dist/modules/skills/skills.tools.js +50 -32
  183. package/dist/modules/skills/skills.tools.js.map +1 -1
  184. package/dist/modules/tool-auth/connection-key-rejection.d.ts +10 -1
  185. package/dist/modules/tool-auth/connection-key-rejection.d.ts.map +1 -1
  186. package/dist/modules/tool-auth/connection-key-rejection.js +11 -3
  187. package/dist/modules/tool-auth/connection-key-rejection.js.map +1 -1
  188. package/dist/modules/tool-auth/external-api-key.interface.d.ts +8 -0
  189. package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
  190. package/dist/modules/tool-auth/external-api-key.service.d.ts +24 -2
  191. package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
  192. package/dist/modules/tool-auth/external-api-key.service.js +59 -2
  193. package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
  194. package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
  195. package/dist/modules/tool-auth/tool-auth.middleware.js +9 -4
  196. package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
  197. package/dist/modules/tool-helpers/index.d.ts +28 -1
  198. package/dist/modules/tool-helpers/index.d.ts.map +1 -1
  199. package/dist/modules/tool-helpers/index.js +28 -1
  200. package/dist/modules/tool-helpers/index.js.map +1 -1
  201. package/dist/modules/tool-helpers/route-argument-check.d.ts +10 -0
  202. package/dist/modules/tool-helpers/route-argument-check.d.ts.map +1 -0
  203. package/dist/modules/tool-helpers/route-argument-check.js +132 -0
  204. package/dist/modules/tool-helpers/route-argument-check.js.map +1 -0
  205. package/dist/modules/tool-helpers/route-tool-schemas.d.ts +89 -0
  206. package/dist/modules/tool-helpers/route-tool-schemas.d.ts.map +1 -0
  207. package/dist/modules/tool-helpers/route-tool-schemas.js +113 -0
  208. package/dist/modules/tool-helpers/route-tool-schemas.js.map +1 -0
  209. package/dist/modules/tool-helpers/tool-def.d.ts +71 -0
  210. package/dist/modules/tool-helpers/tool-def.d.ts.map +1 -1
  211. package/dist/modules/tool-helpers/tool-def.js +70 -6
  212. package/dist/modules/tool-helpers/tool-def.js.map +1 -1
  213. package/dist/modules/tool-helpers/tool-handler.d.ts +46 -6
  214. package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
  215. package/dist/modules/tool-helpers/tool-handler.js +157 -8
  216. package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
  217. package/dist/modules/tool-helpers/tool.contract.d.ts +9 -0
  218. package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
  219. package/dist/modules/tool-helpers/tool.contract.js.map +1 -1
  220. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  221. package/dist/modules/tool-manuals/tool-manuals.tools.js +14 -5
  222. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  223. package/dist/modules/tool-registry/description-length.d.ts +6 -2
  224. package/dist/modules/tool-registry/description-length.d.ts.map +1 -1
  225. package/dist/modules/tool-registry/description-length.js +27 -5
  226. package/dist/modules/tool-registry/description-length.js.map +1 -1
  227. package/dist/modules/tool-registry/guide-first.d.ts +4 -0
  228. package/dist/modules/tool-registry/guide-first.d.ts.map +1 -1
  229. package/dist/modules/tool-registry/guide-first.js +9 -1
  230. package/dist/modules/tool-registry/guide-first.js.map +1 -1
  231. package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts +53 -0
  232. package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts.map +1 -1
  233. package/dist/modules/workflow/agent-tools/change-request-read.tools.js +97 -68
  234. package/dist/modules/workflow/agent-tools/change-request-read.tools.js.map +1 -1
  235. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +8 -1
  236. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  237. package/dist/modules/workflow/agent-tools/workflow.tools.js +124 -37
  238. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  239. package/dist/modules/workflow/file-lock.service.d.ts +29 -5
  240. package/dist/modules/workflow/file-lock.service.d.ts.map +1 -1
  241. package/dist/modules/workflow/file-lock.service.js +62 -5
  242. package/dist/modules/workflow/file-lock.service.js.map +1 -1
  243. package/dist/modules/workflow/git/git.service.d.ts +72 -1
  244. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  245. package/dist/modules/workflow/git/git.service.js +172 -36
  246. package/dist/modules/workflow/git/git.service.js.map +1 -1
  247. package/dist/modules/workflow/git/node-git-runner.d.ts +15 -0
  248. package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -1
  249. package/dist/modules/workflow/git/node-git-runner.js +78 -6
  250. package/dist/modules/workflow/git/node-git-runner.js.map +1 -1
  251. package/dist/modules/workflow/pending-commits.service.d.ts +15 -0
  252. package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -1
  253. package/dist/modules/workflow/pending-commits.service.js +25 -1
  254. package/dist/modules/workflow/pending-commits.service.js.map +1 -1
  255. package/dist/modules/workflow/pending-commits.worker.d.ts +6 -1
  256. package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -1
  257. package/dist/modules/workflow/pending-commits.worker.js +23 -6
  258. package/dist/modules/workflow/pending-commits.worker.js.map +1 -1
  259. package/dist/modules/workflow/recovery-bot.js +1 -1
  260. package/dist/modules/workflow/recovery-bot.js.map +1 -1
  261. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
  262. package/dist/modules/workflow/review-workflow/review-workflow.service.js +2 -1
  263. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
  264. package/dist/modules/workflow/sanitize-error.d.ts +16 -0
  265. package/dist/modules/workflow/sanitize-error.d.ts.map +1 -1
  266. package/dist/modules/workflow/sanitize-error.js +45 -0
  267. package/dist/modules/workflow/sanitize-error.js.map +1 -1
  268. package/dist/modules/workflow/workflow.service.d.ts +183 -15
  269. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  270. package/dist/modules/workflow/workflow.service.js +805 -106
  271. package/dist/modules/workflow/workflow.service.js.map +1 -1
  272. package/dist/modules/workspace/agent-download.builder.d.ts +105 -0
  273. package/dist/modules/workspace/agent-download.builder.d.ts.map +1 -0
  274. package/dist/modules/workspace/agent-download.builder.js +238 -0
  275. package/dist/modules/workspace/agent-download.builder.js.map +1 -0
  276. package/dist/modules/workspace/agent-download.routes.d.ts +77 -0
  277. package/dist/modules/workspace/agent-download.routes.d.ts.map +1 -0
  278. package/dist/modules/workspace/agent-download.routes.js +156 -0
  279. package/dist/modules/workspace/agent-download.routes.js.map +1 -0
  280. package/dist/modules/workspace/agent-download.store.d.ts +225 -0
  281. package/dist/modules/workspace/agent-download.store.d.ts.map +1 -0
  282. package/dist/modules/workspace/agent-download.store.js +423 -0
  283. package/dist/modules/workspace/agent-download.store.js.map +1 -0
  284. package/dist/modules/workspace/agent-upload.store.d.ts +10 -1
  285. package/dist/modules/workspace/agent-upload.store.d.ts.map +1 -1
  286. package/dist/modules/workspace/agent-upload.store.js +16 -6
  287. package/dist/modules/workspace/agent-upload.store.js.map +1 -1
  288. package/dist/modules/workspace/file-readers/raw-mime.d.ts +6 -0
  289. package/dist/modules/workspace/file-readers/raw-mime.d.ts.map +1 -0
  290. package/dist/modules/workspace/file-readers/raw-mime.js +38 -0
  291. package/dist/modules/workspace/file-readers/raw-mime.js.map +1 -0
  292. package/dist/modules/workspace/file-readers/text-reader.d.ts +5 -5
  293. package/dist/modules/workspace/file-readers/text-reader.d.ts.map +1 -1
  294. package/dist/modules/workspace/file-readers/text-reader.js +5 -8
  295. package/dist/modules/workspace/file-readers/text-reader.js.map +1 -1
  296. package/dist/modules/workspace/first-run.d.ts +111 -0
  297. package/dist/modules/workspace/first-run.d.ts.map +1 -0
  298. package/dist/modules/workspace/first-run.js +181 -0
  299. package/dist/modules/workspace/first-run.js.map +1 -0
  300. package/dist/modules/workspace/move-links.d.ts +92 -0
  301. package/dist/modules/workspace/move-links.d.ts.map +1 -0
  302. package/dist/modules/workspace/move-links.js +173 -0
  303. package/dist/modules/workspace/move-links.js.map +1 -0
  304. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  305. package/dist/modules/workspace/startup/steps/seed-tree.js +3 -13
  306. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  307. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  308. package/dist/modules/workspace/workspace.routes.js +63 -22
  309. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  310. package/dist/modules/workspace/workspace.service.d.ts +75 -2
  311. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  312. package/dist/modules/workspace/workspace.service.js +197 -24
  313. package/dist/modules/workspace/workspace.service.js.map +1 -1
  314. package/dist/modules/workspace/workspace.tools.d.ts +59 -1
  315. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  316. package/dist/modules/workspace/workspace.tools.js +443 -65
  317. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  318. package/dist/modules/write-access/write-access.d.ts.map +1 -1
  319. package/dist/modules/write-access/write-access.js +9 -0
  320. package/dist/modules/write-access/write-access.js.map +1 -1
  321. package/dist/shared/domain-errors.d.ts +73 -1
  322. package/dist/shared/domain-errors.d.ts.map +1 -1
  323. package/dist/shared/domain-errors.js +86 -12
  324. package/dist/shared/domain-errors.js.map +1 -1
  325. package/dist/shared/git.contract.d.ts +10 -1
  326. package/dist/shared/git.contract.d.ts.map +1 -1
  327. package/dist/shared/git.contract.js.map +1 -1
  328. package/dist/shared/utf8-text.d.ts +15 -0
  329. package/dist/shared/utf8-text.d.ts.map +1 -0
  330. package/dist/shared/utf8-text.js +20 -0
  331. package/dist/shared/utf8-text.js.map +1 -0
  332. package/dist/tenancy/static-tenant-source.d.ts +2 -1
  333. package/dist/tenancy/static-tenant-source.d.ts.map +1 -1
  334. package/dist/tenancy/static-tenant-source.js +9 -2
  335. package/dist/tenancy/static-tenant-source.js.map +1 -1
  336. package/mcp-app/page.html +349 -0
  337. package/migrations/0017_atlassian_account_links.sql +37 -0
  338. package/migrations/meta/0017_snapshot.json +2396 -0
  339. package/migrations/meta/_journal.json +8 -1
  340. package/package.json +5 -3
  341. package/src/__tests__/packaged-assets-ship.test.ts +16 -4
  342. package/src/assets.ts +28 -2
  343. package/src/core/__tests__/catalog-revision.test.ts +40 -0
  344. package/src/core/__tests__/gated-boot.test.ts +1 -0
  345. package/src/core/__tests__/lifecycle.test.ts +14 -0
  346. package/src/core/catalog-revision.ts +15 -2
  347. package/src/core/create-core-server.ts +67 -3
  348. package/src/core/create-core-services.ts +140 -6
  349. package/src/core/lifecycle.ts +28 -2
  350. package/src/core-config.ts +24 -1
  351. package/src/index.ts +2 -2
  352. package/src/modules/access/__tests__/access-control.service.test.ts +19 -0
  353. package/src/modules/access/access-control.interface.ts +13 -0
  354. package/src/modules/access/access-control.service.ts +16 -0
  355. package/src/modules/access/directory-sync-bot.ts +1 -1
  356. package/src/modules/agent-guide/__tests__/agent-guide.test.ts +58 -0
  357. package/src/modules/agent-guide/__tests__/agent-guide.tools.test.ts +19 -1
  358. package/src/modules/agent-guide/agent-guide.ts +9 -0
  359. package/src/modules/agent-guide/index.ts +1 -0
  360. package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +14 -0
  361. package/src/modules/agent-instructions/compose.ts +17 -2
  362. package/src/modules/agent-instructions/shared-file-rules.ts +19 -19
  363. package/src/modules/audit/__tests__/agent-audit.service.test.ts +64 -4
  364. package/src/modules/audit/__tests__/agent-connection.routes.test.ts +102 -0
  365. package/src/modules/audit/agent-audit.service.ts +58 -3
  366. package/src/modules/audit/agent-connection.routes.ts +56 -0
  367. package/src/modules/audit/audit.contract.ts +26 -0
  368. package/src/modules/audit/index.ts +1 -0
  369. package/src/modules/auth/__tests__/account.routes.test.ts +5 -3
  370. package/src/modules/auth/account.routes.ts +10 -3
  371. package/src/modules/auth/auth.middleware.ts +1 -1
  372. package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +18 -2
  373. package/src/modules/code-mode/code-mode.tool.ts +13 -2
  374. package/src/modules/database/core-schema.ts +33 -3
  375. package/src/modules/embed/__tests__/account-links.migration.test.ts +98 -0
  376. package/src/modules/embed/__tests__/embed-link.test.ts +122 -0
  377. package/src/modules/embed/__tests__/embed.routes.test.ts +362 -0
  378. package/src/modules/embed/__tests__/embed.service.lock.test.ts +193 -0
  379. package/src/modules/embed/__tests__/embed.service.test.ts +805 -0
  380. package/src/modules/embed/__tests__/embed.tools.test.ts +304 -0
  381. package/src/modules/embed/__tests__/mcp-app.test.ts +207 -0
  382. package/src/modules/embed/account-link.service.ts +76 -0
  383. package/src/modules/embed/embed-link.ts +180 -0
  384. package/src/modules/embed/embed.errors.ts +43 -0
  385. package/src/modules/embed/embed.interface.ts +203 -0
  386. package/src/modules/embed/embed.routes.ts +363 -0
  387. package/src/modules/embed/embed.service.ts +705 -0
  388. package/src/modules/embed/embed.tools.ts +206 -0
  389. package/src/modules/embed/mcp-app.routes.ts +41 -0
  390. package/src/modules/embed/mcp-app.ts +173 -0
  391. package/src/modules/github-app/__tests__/github-app.test.ts +76 -0
  392. package/src/modules/github-app/github-app.connection.ts +38 -4
  393. package/src/modules/kb-fs/__tests__/move-with-edits.test.ts +304 -0
  394. package/src/modules/kb-fs/locking-filesystem.ts +287 -0
  395. package/src/modules/kb-sync/__tests__/kb-sync.service.test.ts +35 -0
  396. package/src/modules/kb-sync/kb-sync.interface.ts +2 -0
  397. package/src/modules/kb-sync/kb-sync.service.ts +6 -0
  398. package/src/modules/mcp/__tests__/bevel-oauth-provider.test.ts +68 -11
  399. package/src/modules/mcp/__tests__/mcp-proxy-helpers.test.ts +37 -2
  400. package/src/modules/mcp/__tests__/mcp.app.e2e.test.ts +200 -0
  401. package/src/modules/mcp/__tests__/mcp.e2e.test.ts +3 -1
  402. package/src/modules/mcp/__tests__/mcp.service.test.ts +23 -13
  403. package/src/modules/mcp/__tests__/tool-call-interface.e2e.test.ts +499 -0
  404. package/src/modules/mcp/mcp-auth.middleware.ts +2 -1
  405. package/src/modules/mcp/mcp.service.ts +81 -12
  406. package/src/modules/mcp/oauth/bevel-oauth-provider.ts +42 -4
  407. package/src/modules/onboarding/__tests__/onboarding.routes.test.ts +163 -0
  408. package/src/modules/onboarding/__tests__/starter-pack.service.test.ts +635 -0
  409. package/src/modules/onboarding/__tests__/starter-packs.test.ts +169 -0
  410. package/src/modules/onboarding/onboarding.contract.ts +85 -0
  411. package/src/modules/onboarding/onboarding.routes.ts +85 -0
  412. package/src/modules/onboarding/starter-pack.service.ts +580 -0
  413. package/src/modules/onboarding/starter-packs.ts +182 -0
  414. package/src/modules/plugins/__tests__/plugins.tools.test.ts +25 -2
  415. package/src/modules/plugins/index.ts +1 -0
  416. package/src/modules/plugins/plugin-provision.service.ts +22 -1
  417. package/src/modules/plugins/plugins.routes.ts +29 -0
  418. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +150 -1
  419. package/src/modules/settings/__tests__/repository-source.test.ts +9 -0
  420. package/src/modules/settings/deployment-settings.service.ts +131 -1
  421. package/src/modules/settings/repository-source.ts +4 -4
  422. package/src/modules/skills/__tests__/skills.tools.description.test.ts +5 -1
  423. package/src/modules/skills/skills.tools.ts +55 -35
  424. package/src/modules/tool-auth/__tests__/connection-key-rejection.test.ts +32 -0
  425. package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +65 -0
  426. package/src/modules/tool-auth/connection-key-rejection.ts +13 -3
  427. package/src/modules/tool-auth/external-api-key.interface.ts +9 -0
  428. package/src/modules/tool-auth/external-api-key.service.ts +61 -4
  429. package/src/modules/tool-auth/tool-auth.middleware.ts +13 -4
  430. package/src/modules/tool-helpers/__tests__/branch-declaration.test.ts +502 -0
  431. package/src/modules/tool-helpers/__tests__/route-argument-check.test.ts +337 -0
  432. package/src/modules/tool-helpers/index.ts +34 -1
  433. package/src/modules/tool-helpers/route-argument-check.ts +149 -0
  434. package/src/modules/tool-helpers/route-tool-schemas.ts +171 -0
  435. package/src/modules/tool-helpers/tool-def.ts +132 -7
  436. package/src/modules/tool-helpers/tool-handler.ts +196 -8
  437. package/src/modules/tool-helpers/tool.contract.ts +9 -0
  438. package/src/modules/tool-manuals/tool-manuals.tools.ts +15 -5
  439. package/src/modules/tool-registry/__tests__/own-tool-schemas.test.ts +14 -1
  440. package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +23 -10
  441. package/src/modules/tool-registry/description-length.ts +34 -7
  442. package/src/modules/tool-registry/guide-first.ts +8 -1
  443. package/src/modules/workflow/__tests__/file-lock.service.deletion-gate.test.ts +104 -0
  444. package/src/modules/workflow/__tests__/pending-commits.repository-replaced.test.ts +66 -0
  445. package/src/modules/workflow/__tests__/pending-commits.worker.test.ts +31 -2
  446. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +110 -6
  447. package/src/modules/workflow/__tests__/sanitize-error.test.ts +89 -1
  448. package/src/modules/workflow/__tests__/workflow.routes.push-refused.test.ts +202 -0
  449. package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +6 -6
  450. package/src/modules/workflow/__tests__/workflow.service.delete-branch.test.ts +1026 -0
  451. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +468 -10
  452. package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +4 -0
  453. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +5 -4
  454. package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +54 -2
  455. package/src/modules/workflow/agent-tools/__tests__/change-request-read.tools.test.ts +41 -5
  456. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +127 -2
  457. package/src/modules/workflow/agent-tools/change-request-read.tools.ts +157 -122
  458. package/src/modules/workflow/agent-tools/workflow.tools.ts +129 -35
  459. package/src/modules/workflow/file-lock.service.ts +67 -5
  460. package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +164 -0
  461. package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +48 -1
  462. package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +231 -2
  463. package/src/modules/workflow/git/git.service.ts +176 -38
  464. package/src/modules/workflow/git/node-git-runner.ts +82 -7
  465. package/src/modules/workflow/pending-commits.service.ts +29 -1
  466. package/src/modules/workflow/pending-commits.worker.ts +24 -6
  467. package/src/modules/workflow/recovery-bot.ts +1 -1
  468. package/src/modules/workflow/review-workflow/review-workflow.service.ts +2 -1
  469. package/src/modules/workflow/sanitize-error.ts +50 -0
  470. package/src/modules/workflow/workflow.service.ts +879 -112
  471. package/src/modules/workspace/__tests__/agent-downloads.test.ts +823 -0
  472. package/src/modules/workspace/__tests__/first-run.test.ts +234 -0
  473. package/src/modules/workspace/__tests__/git-internals.security.test.ts +5 -2
  474. package/src/modules/workspace/__tests__/md-links.test.ts +353 -0
  475. package/src/modules/workspace/__tests__/move-links.test.ts +261 -0
  476. package/src/modules/workspace/__tests__/rest-tool-arguments.test.ts +219 -0
  477. package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +3 -0
  478. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +102 -0
  479. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +52 -5
  480. package/src/modules/workspace/__tests__/workspace.routes.folder-zip-access.test.ts +190 -0
  481. package/src/modules/workspace/__tests__/workspace.service.forget-clone-races.test.ts +8 -4
  482. package/src/modules/workspace/__tests__/workspace.service.test.ts +50 -8
  483. package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +44 -1
  484. package/src/modules/workspace/__tests__/workspace.tools.test.ts +409 -12
  485. package/src/modules/workspace/agent-download.builder.ts +308 -0
  486. package/src/modules/workspace/agent-download.routes.ts +183 -0
  487. package/src/modules/workspace/agent-download.store.ts +533 -0
  488. package/src/modules/workspace/agent-upload.store.ts +23 -7
  489. package/src/modules/workspace/file-readers/raw-mime.ts +40 -0
  490. package/src/modules/workspace/file-readers/text-reader.ts +5 -8
  491. package/src/modules/workspace/first-run.ts +222 -0
  492. package/src/modules/workspace/move-links.ts +237 -0
  493. package/src/modules/workspace/startup/steps/seed-tree.ts +3 -12
  494. package/src/modules/workspace/workspace.routes.ts +64 -22
  495. package/src/modules/workspace/workspace.service.ts +202 -25
  496. package/src/modules/workspace/workspace.tools.ts +492 -63
  497. package/src/modules/write-access/__tests__/write-access.test.ts +13 -0
  498. package/src/modules/write-access/write-access.ts +9 -0
  499. package/src/shared/domain-errors.ts +108 -11
  500. package/src/shared/git.contract.ts +8 -1
  501. package/src/shared/utf8-text.ts +21 -0
  502. package/src/tenancy/__tests__/static-tenant-source.test.ts +1 -0
  503. package/src/tenancy/static-tenant-source.ts +10 -2
  504. package/starter-packs/README.md +103 -0
  505. package/starter-packs/engineering/KnowledgeBase/About us.md +9 -0
  506. package/starter-packs/engineering/KnowledgeBase/Architecture.md +9 -0
  507. package/starter-packs/engineering/KnowledgeBase/Glossary.md +9 -0
  508. package/starter-packs/engineering/KnowledgeBase/How we ship.md +9 -0
  509. package/starter-packs/engineering/Plugins/engineering-starter/LICENSE +21 -0
  510. package/starter-packs/engineering/Plugins/engineering-starter/SOURCE.md +20 -0
  511. package/starter-packs/engineering/Plugins/engineering-starter/access.md +19 -0
  512. package/starter-packs/engineering/Plugins/engineering-starter/plugin.json +10 -0
  513. package/starter-packs/engineering/Plugins/engineering-starter/skills/office-hours/SKILL.md +171 -0
  514. package/starter-packs/engineering/Plugins/engineering-starter/skills/office-hours/sections/phase-2a-startup-diagnostic.md +157 -0
  515. package/starter-packs/engineering/Plugins/engineering-starter/skills/office-hours/sections/phase-2b-builder-brainstorm.md +39 -0
  516. package/starter-packs/engineering/Plugins/engineering-starter/skills/plan-ceo-review/SKILL.md +144 -0
  517. package/starter-packs/engineering/Plugins/engineering-starter/skills/plan-eng-review/SKILL.md +144 -0
  518. package/starter-packs/engineering/Plugins/engineering-starter/skills/review/SKILL.md +80 -0
  519. package/starter-packs/engineering/Plugins/engineering-starter/skills/review/checklist.md +184 -0
  520. package/starter-packs/engineering/pack.yaml +11 -0
  521. package/starter-packs/general/KnowledgeBase/About us.md +9 -0
  522. package/starter-packs/general/KnowledgeBase/Glossary.md +9 -0
  523. package/starter-packs/general/KnowledgeBase/How we work.md +9 -0
  524. package/starter-packs/general/Plugins/general-starter/LICENSE +202 -0
  525. package/starter-packs/general/Plugins/general-starter/SOURCE.md +10 -0
  526. package/starter-packs/general/Plugins/general-starter/access.md +19 -0
  527. package/starter-packs/general/Plugins/general-starter/plugin.json +10 -0
  528. package/starter-packs/general/Plugins/general-starter/skills/memory-management/SKILL.md +332 -0
  529. package/starter-packs/general/Plugins/general-starter/skills/productivity-start/SKILL.md +163 -0
  530. package/starter-packs/general/Plugins/general-starter/skills/productivity-update/SKILL.md +167 -0
  531. package/starter-packs/general/Plugins/general-starter/skills/task-management/SKILL.md +83 -0
  532. package/starter-packs/general/pack.yaml +10 -0
  533. package/starter-packs/operations/KnowledgeBase/Glossary.md +9 -0
  534. package/starter-packs/operations/KnowledgeBase/How we work.md +9 -0
  535. package/starter-packs/operations/KnowledgeBase/Processes.md +9 -0
  536. package/starter-packs/operations/KnowledgeBase/Tools we use.md +9 -0
  537. package/starter-packs/operations/KnowledgeBase/Vendors.md +9 -0
  538. package/starter-packs/operations/Plugins/operations-starter/LICENSE +202 -0
  539. package/starter-packs/operations/Plugins/operations-starter/SOURCE.md +10 -0
  540. package/starter-packs/operations/Plugins/operations-starter/access.md +19 -0
  541. package/starter-packs/operations/Plugins/operations-starter/plugin.json +10 -0
  542. package/starter-packs/operations/Plugins/operations-starter/skills/capacity-plan/SKILL.md +111 -0
  543. package/starter-packs/operations/Plugins/operations-starter/skills/change-request/SKILL.md +119 -0
  544. package/starter-packs/operations/Plugins/operations-starter/skills/compliance-tracking/SKILL.md +44 -0
  545. package/starter-packs/operations/Plugins/operations-starter/skills/process-doc/SKILL.md +80 -0
  546. package/starter-packs/operations/Plugins/operations-starter/skills/process-optimization/SKILL.md +39 -0
  547. package/starter-packs/operations/Plugins/operations-starter/skills/risk-assessment/SKILL.md +40 -0
  548. package/starter-packs/operations/Plugins/operations-starter/skills/runbook/SKILL.md +85 -0
  549. package/starter-packs/operations/Plugins/operations-starter/skills/status-report/SKILL.md +75 -0
  550. package/starter-packs/operations/Plugins/operations-starter/skills/vendor-review/SKILL.md +102 -0
  551. package/starter-packs/operations/pack.yaml +12 -0
  552. package/starter-packs/sales/KnowledgeBase/About us.md +9 -0
  553. package/starter-packs/sales/KnowledgeBase/Customers.md +9 -0
  554. package/starter-packs/sales/KnowledgeBase/Glossary.md +9 -0
  555. package/starter-packs/sales/KnowledgeBase/How we sell.md +9 -0
  556. package/starter-packs/sales/KnowledgeBase/Objections.md +9 -0
  557. package/starter-packs/sales/KnowledgeBase/Pricing.md +9 -0
  558. package/starter-packs/sales/Plugins/sales-starter/LICENSE +202 -0
  559. package/starter-packs/sales/Plugins/sales-starter/SOURCE.md +10 -0
  560. package/starter-packs/sales/Plugins/sales-starter/access.md +19 -0
  561. package/starter-packs/sales/Plugins/sales-starter/plugin.json +10 -0
  562. package/starter-packs/sales/Plugins/sales-starter/skills/account-context/SKILL.md +94 -0
  563. package/starter-packs/sales/Plugins/sales-starter/skills/account-plan/SKILL.md +95 -0
  564. package/starter-packs/sales/Plugins/sales-starter/skills/account-research/SKILL.md +99 -0
  565. package/starter-packs/sales/Plugins/sales-starter/skills/account-tiering/SKILL.md +101 -0
  566. package/starter-packs/sales/Plugins/sales-starter/skills/call-prep/SKILL.md +111 -0
  567. package/starter-packs/sales/Plugins/sales-starter/skills/call-summary/SKILL.md +111 -0
  568. package/starter-packs/sales/Plugins/sales-starter/skills/close-plan/SKILL.md +106 -0
  569. package/starter-packs/sales/Plugins/sales-starter/skills/competitive-intelligence/SKILL.md +102 -0
  570. package/starter-packs/sales/Plugins/sales-starter/skills/create-an-asset/SKILL.md +105 -0
  571. package/starter-packs/sales/Plugins/sales-starter/skills/crm-hygiene-check/SKILL.md +103 -0
  572. package/starter-packs/sales/Plugins/sales-starter/skills/customer-health/SKILL.md +108 -0
  573. package/starter-packs/sales/Plugins/sales-starter/skills/customer-voice/SKILL.md +94 -0
  574. package/starter-packs/sales/Plugins/sales-starter/skills/daily-briefing/SKILL.md +61 -0
  575. package/starter-packs/sales/Plugins/sales-starter/skills/deal-advance-gap/SKILL.md +102 -0
  576. package/starter-packs/sales/Plugins/sales-starter/skills/deal-review/SKILL.md +105 -0
  577. package/starter-packs/sales/Plugins/sales-starter/skills/deal-signals/SKILL.md +96 -0
  578. package/starter-packs/sales/Plugins/sales-starter/skills/deal-slip-scenario/SKILL.md +104 -0
  579. package/starter-packs/sales/Plugins/sales-starter/skills/draft-outreach/SKILL.md +116 -0
  580. package/starter-packs/sales/Plugins/sales-starter/skills/end-of-day/SKILL.md +114 -0
  581. package/starter-packs/sales/Plugins/sales-starter/skills/expansion-whitespace/SKILL.md +97 -0
  582. package/starter-packs/sales/Plugins/sales-starter/skills/forecast/SKILL.md +100 -0
  583. package/starter-packs/sales/Plugins/sales-starter/skills/handle-objection/SKILL.md +93 -0
  584. package/starter-packs/sales/Plugins/sales-starter/skills/inbox-sweep/SKILL.md +114 -0
  585. package/starter-packs/sales/Plugins/sales-starter/skills/lead-triage/SKILL.md +106 -0
  586. package/starter-packs/sales/Plugins/sales-starter/skills/log-activity/SKILL.md +111 -0
  587. package/starter-packs/sales/Plugins/sales-starter/skills/pipeline-review/SKILL.md +97 -0
  588. package/starter-packs/sales/Plugins/sales-starter/skills/renewal-radar/SKILL.md +95 -0
  589. package/starter-packs/sales/Plugins/sales-starter/skills/rep-context/SKILL.md +90 -0
  590. package/starter-packs/sales/Plugins/sales-starter/skills/route-lead/SKILL.md +111 -0
  591. package/starter-packs/sales/Plugins/sales-starter/skills/sales-setup/SKILL.md +200 -0
  592. package/starter-packs/sales/Plugins/sales-starter/skills/schedule-meeting/SKILL.md +99 -0
  593. package/starter-packs/sales/Plugins/sales-starter/skills/stakeholder-map/SKILL.md +107 -0
  594. package/starter-packs/sales/Plugins/sales-starter/skills/team-pipeline/SKILL.md +105 -0
  595. package/starter-packs/sales/Plugins/sales-starter/skills/update-opportunity/SKILL.md +112 -0
  596. package/starter-packs/sales/Plugins/sales-starter/skills/weekly-wrap/SKILL.md +90 -0
  597. package/starter-packs/sales/Plugins/sales-starter/skills/win-loss-review/SKILL.md +88 -0
  598. package/starter-packs/sales/pack.yaml +13 -0
  599. package/starter-packs/support/KnowledgeBase/Escalations.md +9 -0
  600. package/starter-packs/support/KnowledgeBase/Glossary.md +9 -0
  601. package/starter-packs/support/KnowledgeBase/Known issues.md +9 -0
  602. package/starter-packs/support/KnowledgeBase/Products.md +9 -0
  603. package/starter-packs/support/KnowledgeBase/Tone of voice.md +9 -0
  604. package/starter-packs/support/Plugins/support-starter/LICENSE +202 -0
  605. package/starter-packs/support/Plugins/support-starter/SOURCE.md +10 -0
  606. package/starter-packs/support/Plugins/support-starter/access.md +19 -0
  607. package/starter-packs/support/Plugins/support-starter/plugin.json +10 -0
  608. package/starter-packs/support/Plugins/support-starter/skills/customer-escalation/SKILL.md +246 -0
  609. package/starter-packs/support/Plugins/support-starter/skills/customer-research/SKILL.md +250 -0
  610. package/starter-packs/support/Plugins/support-starter/skills/draft-response/SKILL.md +416 -0
  611. package/starter-packs/support/Plugins/support-starter/skills/kb-article/SKILL.md +350 -0
  612. package/starter-packs/support/Plugins/support-starter/skills/ticket-triage/SKILL.md +273 -0
  613. package/starter-packs/support/pack.yaml +12 -0
@@ -13,7 +13,11 @@ import { FileLockService } from '../file-lock.service.js';
13
13
  import { PendingCommitsService } from '../pending-commits.service.js';
14
14
  import { WorkflowService } from '../workflow.service.js';
15
15
  import type { Database } from '../../database/connection.js';
16
- import { RolesYamlPreservationError } from '../../../shared/domain-errors.js';
16
+ import {
17
+ PushNeedsAgentResolutionError,
18
+ RolesYamlPreservationError,
19
+ } from '../../../shared/domain-errors.js';
20
+ import type { WorkflowEventBus } from '../event-bus.js';
17
21
  import { openChangeGate } from '../../../__tests__/open-change-gate.js';
18
22
 
19
23
  /**
@@ -63,12 +67,18 @@ describe('mergeChangeRequest — roles.yaml preservation guard', () => {
63
67
  headRoles: string | null;
64
68
  baseRoles: string | null;
65
69
  commitFileResult?: unknown;
70
+ /**
71
+ * What the clone answers when asked whether its HEAD already holds all of
72
+ * origin/<head>; an Error makes the probe throw instead.
73
+ */
74
+ headContainsOrigin?: boolean | Error;
66
75
  pushImpl?: () => Promise<void>;
67
76
  getPrResult?: { branch: string; base: string } | null;
68
77
  getPrDetailResult?: unknown;
69
78
  // Simulate a concurrent editor already holding the roles.yaml lock. When set,
70
79
  // acquire returns { acquired: false } and the restore must fail-closed.
71
80
  lockHeldBy?: string;
81
+ events?: WorkflowEventBus;
72
82
  }) {
73
83
  const ac = noopAccessControl();
74
84
  const reviewWorkflow = {
@@ -91,6 +101,11 @@ describe('mergeChangeRequest — roles.yaml preservation guard', () => {
91
101
  'commitFileResult' in opts ? opts.commitFileResult : { sha: 'preserve-sha' },
92
102
  ),
93
103
  push: vi.fn(opts.pushImpl ?? (async () => undefined)),
104
+ headContainsOrigin: vi.fn(async () => {
105
+ const answer = opts.headContainsOrigin ?? false;
106
+ if (answer instanceof Error) throw answer;
107
+ return answer;
108
+ }),
94
109
  } as unknown as GitService;
95
110
 
96
111
  const prs = {
@@ -123,6 +138,7 @@ describe('mergeChangeRequest — roles.yaml preservation guard', () => {
123
138
  fileLocks, {} as unknown as PendingCommitsService,
124
139
  testKbContext({ kbDirName: KB_DIR }),
125
140
  openChangeGate(),
141
+ opts.events,
126
142
  );
127
143
  // Conflicts are now surfaced by the local merge inside `reviewWorkflow.mergePr`
128
144
  // (mocked to resolve here), so there's no provider "mergeable" pre-check to stub.
@@ -221,17 +237,55 @@ describe('mergeChangeRequest — roles.yaml preservation guard', () => {
221
237
  expect(git.push).toHaveBeenCalled();
222
238
  });
223
239
 
224
- it('ABORTS the merge (RolesYamlPreservationError) if the restore push fails', async () => {
240
+ it('ABORTS the merge when the host refuses the restore push, keeping the restore locally (409, saved-locally, banner)', async () => {
225
241
  await fs.writeFile(path.join(headRepoDir, 'roles.yaml'), ATTACKER_ROLES);
226
- const { svc, reviewWorkflow } = makeSvc({
242
+ const emit = vi.fn();
243
+ const { svc, git, reviewWorkflow, fileLocks } = makeSvc({
227
244
  headRoles: ATTACKER_ROLES,
228
245
  baseRoles: BASE_ROLES,
229
- pushImpl: async () => { throw new Error('push rejected: non-fast-forward'); },
246
+ pushImpl: async () => {
247
+ throw new Error('git push failed: remote: Internal Server Error');
248
+ },
249
+ events: { emit } as unknown as WorkflowEventBus,
230
250
  });
231
251
 
232
- await expect(merge(svc)).rejects.toBeInstanceOf(RolesYamlPreservationError);
233
- // Fail-closed: the merge must NOT have run.
252
+ const err = await merge(svc).catch((e: unknown) => e);
253
+ // Answered like every refused push — not the 502 preservation error, and
254
+ // never a raw 500.
255
+ expect(err).toBeInstanceOf(PushNeedsAgentResolutionError);
256
+ expect((err as PushNeedsAgentResolutionError).status).toBe(409);
257
+ expect((err as Error).message).toContain(`Saved locally on "${HEAD}"`);
258
+ expect(JSON.stringify((err as PushNeedsAgentResolutionError).payload)).not.toContain('Internal Server Error');
259
+ // Fail-closed: the merge must NOT have run — origin still carries the
260
+ // divergent roles.yaml.
234
261
  expect(reviewWorkflow.mergePr).not.toHaveBeenCalled();
262
+ // The local result stays: base version on disk, committed, lock dropped.
263
+ expect(await fs.readFile(path.join(headRepoDir, 'roles.yaml'), 'utf-8')).toBe(BASE_ROLES);
264
+ expect(git.commitFile).toHaveBeenCalled();
265
+ expect(fileLocks.release).toHaveBeenCalled();
266
+ // A refusal is not a divergence: no cooperative pull-rebase, no retry.
267
+ expect(git.push).toHaveBeenCalledTimes(1);
268
+ expect(git.pull).not.toHaveBeenCalledWith(expect.anything(), { preserveMerges: true });
269
+ expect(emit).toHaveBeenCalledWith(
270
+ expect.objectContaining({ kind: 'git-sync-failed', workspaceId: HEAD, branch: HEAD }),
271
+ );
272
+ });
273
+
274
+ it('a non-fast-forward restore push takes the cooperative pull-rebase, then the merge proceeds', async () => {
275
+ await fs.writeFile(path.join(headRepoDir, 'roles.yaml'), ATTACKER_ROLES);
276
+ let pushes = 0;
277
+ const { svc, git, reviewWorkflow } = makeSvc({
278
+ headRoles: ATTACKER_ROLES,
279
+ baseRoles: BASE_ROLES,
280
+ pushImpl: async () => {
281
+ if (pushes++ === 0) throw new Error('push rejected: non-fast-forward');
282
+ },
283
+ });
284
+
285
+ await merge(svc);
286
+ expect(git.pull).toHaveBeenCalled();
287
+ expect(git.push).toHaveBeenCalledTimes(2);
288
+ expect(reviewWorkflow.mergePr).toHaveBeenCalledTimes(1);
235
289
  });
236
290
 
237
291
  it('ABORTS the merge if the CR (PR) cannot be resolved', async () => {
@@ -283,6 +337,56 @@ describe('mergeChangeRequest — roles.yaml preservation guard', () => {
283
337
  expect(reviewWorkflow.mergePr).not.toHaveBeenCalled();
284
338
  });
285
339
 
340
+ it('a merge retried after a refused restore push pushes the restore that is already committed, then merges', async () => {
341
+ // The earlier attempt restored and committed roles.yaml on the source,
342
+ // and the host refused the push (the 409 above). origin/head therefore
343
+ // still diverges, the working tree already matches base, and commitFile
344
+ // has nothing new — but the clone's HEAD holds the restore commit on top
345
+ // of everything origin has. The retry must push it and merge, not refuse
346
+ // "out of sync" forever.
347
+ await fs.writeFile(path.join(headRepoDir, 'roles.yaml'), BASE_ROLES);
348
+ const { svc, git, reviewWorkflow } = makeSvc({
349
+ headRoles: ATTACKER_ROLES,
350
+ baseRoles: BASE_ROLES,
351
+ commitFileResult: null,
352
+ headContainsOrigin: true,
353
+ });
354
+ await expect(merge(svc)).resolves.toMatchObject({ kind: 'merged' });
355
+ expect(git.push).toHaveBeenCalledTimes(1);
356
+ expect(reviewWorkflow.mergePr).toHaveBeenCalled();
357
+ });
358
+
359
+ it('still ABORTS when the base version is on disk but the clone is BEHIND origin/head (fail-closed)', async () => {
360
+ // The unsafe shape: HEAD never saw origin's divergent roles.yaml commit,
361
+ // the working tree matches base, and the clone carries some unpushed
362
+ // save. Pushing would rebase origin's divergent copy INTO HEAD first and
363
+ // the merge would land it — so holding unpushed work is not the question,
364
+ // holding all of origin is.
365
+ await fs.writeFile(path.join(headRepoDir, 'roles.yaml'), BASE_ROLES);
366
+ const { svc, git, reviewWorkflow } = makeSvc({
367
+ headRoles: ATTACKER_ROLES,
368
+ baseRoles: BASE_ROLES,
369
+ commitFileResult: null,
370
+ headContainsOrigin: false,
371
+ });
372
+ await expect(merge(svc)).rejects.toBeInstanceOf(RolesYamlPreservationError);
373
+ expect(git.push).not.toHaveBeenCalled();
374
+ expect(reviewWorkflow.mergePr).not.toHaveBeenCalled();
375
+ });
376
+
377
+ it('ABORTS when the probe for "does HEAD hold origin/head" itself fails (fail-closed, not open)', async () => {
378
+ await fs.writeFile(path.join(headRepoDir, 'roles.yaml'), BASE_ROLES);
379
+ const { svc, git, reviewWorkflow } = makeSvc({
380
+ headRoles: ATTACKER_ROLES,
381
+ baseRoles: BASE_ROLES,
382
+ commitFileResult: null,
383
+ headContainsOrigin: new Error("fatal: Not a valid object name refs/remotes/origin/mallory/escalate"),
384
+ });
385
+ await expect(merge(svc)).rejects.toBeInstanceOf(RolesYamlPreservationError);
386
+ expect(git.push).not.toHaveBeenCalled();
387
+ expect(reviewWorkflow.mergePr).not.toHaveBeenCalled();
388
+ });
389
+
286
390
  it('ABORTS the merge when the post-preservation CR detail cannot be reloaded (fail-closed)', async () => {
287
391
  // After a preservation commit advances the head, the gate inputs must be
288
392
  // re-resolved. If the fresh detail is unavailable, abort — never fall back to
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { sanitizeError } from '../sanitize-error.js';
2
+ import { describeSyncFailure, sanitizeError } from '../sanitize-error.js';
3
3
 
4
4
  describe('sanitizeError', () => {
5
5
  it('returns String(err) for non-Error throws', () => {
@@ -75,3 +75,91 @@ describe('sanitizeError', () => {
75
75
  expect(twice).toBe(once);
76
76
  });
77
77
  });
78
+
79
+ describe('describeSyncFailure', () => {
80
+ // What a person reads about a failed push: the kind of failure, never a
81
+ // line of git's own output (the server log keeps that).
82
+ const cases: Array<[string, string]> = [
83
+ [
84
+ "fatal: Authentication failed for 'https://x-access-token:ghp_abc@github.com/acme/kb.git/'",
85
+ "The repository host did not accept this server's credentials.",
86
+ ],
87
+ [
88
+ "fatal: unable to access 'https://github.com/acme/kb.git/': The requested URL returned error: 401",
89
+ "The repository host did not accept this server's credentials.",
90
+ ],
91
+ [
92
+ "fatal: unable to access 'https://github.com/acme/kb.git/': The requested URL returned error: 403",
93
+ "The repository host did not give this server's credentials permission to push here.",
94
+ ],
95
+ [
96
+ 'remote: Permission to acme/kb.git denied to kb-bot.',
97
+ "The repository host did not give this server's credentials permission to push here.",
98
+ ],
99
+ [
100
+ 'git@github.com: Permission denied (publickey).\nfatal: Could not read from remote repository.',
101
+ "The repository host did not accept this server's credentials.",
102
+ ],
103
+ [
104
+ "error: cannot open .git/FETCH_HEAD: Permission denied",
105
+ "This server could not write to its own copy of the repository.",
106
+ ],
107
+ [
108
+ 'error: insufficient permission for adding an object to repository database .git/objects',
109
+ "This server could not write to its own copy of the repository.",
110
+ ],
111
+ [
112
+ "fatal: unable to access 'https://127.0.0.1:9/none.git/': Failed to connect to 127.0.0.1 port 9: Connection refused",
113
+ 'The repository host could not be reached.',
114
+ ],
115
+ [
116
+ '! [rejected] main -> main (non-fast-forward)',
117
+ 'The branch changed on the repository host and could not be reconciled automatically.',
118
+ ],
119
+ [
120
+ 'remote: Internal Server Error\n ! [remote rejected] ali/x -> ali/x (Internal Server Error)',
121
+ 'The repository host refused the request.',
122
+ ],
123
+ // A timeout in git's own standalone wording, and Node's code for one.
124
+ [
125
+ "fatal: unable to access 'https://github.com/acme/kb.git/': Operation timed out after 30001 milliseconds",
126
+ 'The repository host could not be reached.',
127
+ ],
128
+ ["fatal: unable to access 'https://github.com/acme/kb.git/': timed out", 'The repository host could not be reached.'],
129
+ ['connect ETIMEDOUT 140.82.121.3:443', 'The repository host could not be reached.'],
130
+ ['HTTP 401 Unauthorized', "The repository host did not accept this server's credentials."],
131
+ // A host's "token" wording is a rejected credential, as its "password" wording is.
132
+ ["remote: Invalid username or token. Password authentication is not supported", "The repository host did not accept this server's credentials."],
133
+ // "repository … not found" with git's quoted URL between the words.
134
+ ["remote: Repository 'https://github.com/acme/kb.git/' not found", "The repository host did not give this server's credentials permission to push here."],
135
+ ];
136
+
137
+ it.each(cases)('describes %j without quoting it', (raw, expected) => {
138
+ const said = describeSyncFailure(new Error(raw));
139
+ expect(said).toBe(expected);
140
+ expect(said).not.toMatch(/fatal|remote:|github\.com|ghp_|127\.0\.0\.1/);
141
+ });
142
+
143
+ it('says "access to this repository", not "push", when the PULL was refused', () => {
144
+ for (const raw of [
145
+ "fatal: unable to access 'https://github.com/acme/kb.git/': The requested URL returned error: 403",
146
+ 'remote: Repository not found.\nfatal: repository \'https://github.com/acme/kb.git/\' not found',
147
+ 'remote: Permission to acme/kb.git denied to kb-bot.',
148
+ ]) {
149
+ expect(describeSyncFailure(new Error(raw), 'pull')).toBe(
150
+ "The repository host did not give this server's credentials access to this repository.",
151
+ );
152
+ expect(describeSyncFailure(new Error(raw), 'push')).toBe(
153
+ "The repository host did not give this server's credentials permission to push here.",
154
+ );
155
+ }
156
+ // A rejected credential is the same fix whichever side met it.
157
+ expect(describeSyncFailure(new Error('fatal: Authentication failed'), 'pull')).toBe(
158
+ "The repository host did not accept this server's credentials.",
159
+ );
160
+ });
161
+
162
+ it('accepts a non-Error throw', () => {
163
+ expect(describeSyncFailure('something odd')).toBe('The repository host refused the request.');
164
+ });
165
+ });
@@ -0,0 +1,202 @@
1
+ import type { Server } from 'node:http';
2
+ import type { AddressInfo } from 'node:net';
3
+ import express from 'express';
4
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
5
+ import { testKbContext } from '../../../__tests__/kb-context.js';
6
+ import type { AuthUser, IWorkflowService } from '@bevel-software/platform-shared';
7
+ import type { Database } from '../../database/connection.js';
8
+ import type { IAccessControl } from '../../access/access-control.interface.js';
9
+ import type { AuthService } from '../../auth/auth.service.js';
10
+ import type { WorkspaceService } from '../../workspace/workspace.service.js';
11
+ import type { GitService } from '../git/git.service.js';
12
+ import type { PullRequestService } from '../git/pull-request.service.js';
13
+ import type { IReviewWorkflowService } from '../review-workflow/review-workflow.interface.js';
14
+ import type { FileLockService } from '../file-lock.service.js';
15
+ import type { PendingCommitsService } from '../pending-commits.service.js';
16
+ import { WorkflowEventBus } from '../event-bus.js';
17
+ import { WorkflowService } from '../workflow.service.js';
18
+ import { createWorkflowRoutes } from '../workflow.routes.js';
19
+ import { openChangeGate } from '../../../__tests__/open-change-gate.js';
20
+ import {
21
+ BranchDeleteRefusedError,
22
+ PushNeedsAgentResolutionError,
23
+ } from '../../../shared/domain-errors.js';
24
+
25
+ /**
26
+ * Every route whose operation pushes answers a push the repository host
27
+ * refused the same way: 409, the saved-locally sentence naming the branch —
28
+ * or, for a branch deletion, the host-refused sentence — and never
29
+ * "Internal server error" or a line of git output.
30
+ *
31
+ * The services' own tests prove each operation THROWS the refusal; these
32
+ * prove the routes answer it. The share route runs over the real service,
33
+ * because it is the one that answered 500 for a raw push error before.
34
+ */
35
+
36
+ const ALICE: AuthUser = { id: '11111111-1111-4111-8111-111111111111', email: 'alice@example.com', name: 'Alice' };
37
+ const BRANCH = 'alice/deal';
38
+ const WS = encodeURIComponent(BRANCH);
39
+ /** What GitHub answered during its incident — none of it may reach the body. */
40
+ const GIT_OUTPUT =
41
+ 'git push failed: remote: Internal Server Error\nTo https://x-access-token:ghp_abc@github.com/acme/kb.git\n ! [remote rejected] alice/deal -> alice/deal (Internal Server Error)';
42
+
43
+ function refused(path: string, branch = BRANCH): PushNeedsAgentResolutionError {
44
+ return new PushNeedsAgentResolutionError(branch, path, GIT_OUTPUT, '(cooperative path not attempted)', 'refused');
45
+ }
46
+
47
+ /**
48
+ * Each operation's refusal names its own branch, so a route that answered
49
+ * with a fixed name — or another operation's — fails its case.
50
+ */
51
+ const REVERT_BRANCH = 'alice/revert-src';
52
+ const OPEN_BRANCH = 'alice/open-src';
53
+ const UPDATE_BRANCH = 'alice/update-src';
54
+
55
+ async function serve(workflow: Partial<IWorkflowService>): Promise<{ server: Server; baseUrl: string }> {
56
+ const authService = { getUserById: vi.fn(async () => ALICE) } as unknown as AuthService;
57
+ const workspaceService = {
58
+ getOrCreateForBranch: vi.fn(async (branch: string) => ({ id: encodeURIComponent(branch) })),
59
+ } as unknown as WorkspaceService;
60
+ const app = express();
61
+ app.use(express.json());
62
+ app.use('/api', (req, _res, next) => {
63
+ (req as unknown as { userId: string }).userId = ALICE.id;
64
+ next();
65
+ });
66
+ app.use(
67
+ '/api',
68
+ createWorkflowRoutes(
69
+ workflow as IWorkflowService,
70
+ workspaceService,
71
+ authService,
72
+ new WorkflowEventBus(),
73
+ {} as unknown as IAccessControl,
74
+ 'knowledge-base',
75
+ ),
76
+ );
77
+ const server = await new Promise<Server>((resolve) => {
78
+ const s = app.listen(0, () => resolve(s));
79
+ });
80
+ return { server, baseUrl: `http://127.0.0.1:${(server.address() as AddressInfo).port}` };
81
+ }
82
+
83
+ function close(s: Server): Promise<void> {
84
+ return new Promise((resolve, reject) => s.close((e) => (e ? reject(e) : resolve())));
85
+ }
86
+
87
+ async function call(baseUrl: string, method: string, path: string, body?: unknown) {
88
+ const res = await fetch(`${baseUrl}/api${path}`, {
89
+ method,
90
+ headers: { 'content-type': 'application/json' },
91
+ body: body === undefined ? undefined : JSON.stringify(body),
92
+ });
93
+ const text = await res.text();
94
+ return { status: res.status, text, json: JSON.parse(text) as Record<string, unknown> };
95
+ }
96
+
97
+ function expectNoGitOutput(text: string): void {
98
+ expect(text).not.toMatch(/Internal (server )?error|remote rejected|remote:|ghp_|github\.com/i);
99
+ }
100
+
101
+ describe('routes answer a push the host refused with 409 and the saved-locally sentence', () => {
102
+ let server: Server;
103
+ let baseUrl: string;
104
+
105
+ const workflow: Partial<IWorkflowService> = {
106
+ revertChangeRequestFile: vi.fn(async () => {
107
+ throw refused('Sales/Deal.md', REVERT_BRANCH);
108
+ }),
109
+ openChangeRequest: vi.fn(async () => {
110
+ throw refused('(opening a change request)', OPEN_BRANCH);
111
+ }),
112
+ getChangeRequest: vi.fn(async () => ({ number: 7, branch: BRANCH, base: 'main' }) as never),
113
+ updateFromTarget: vi.fn(async () => {
114
+ throw refused('(update from main)', UPDATE_BRANCH);
115
+ }),
116
+ deleteBranch: vi.fn(async () => {
117
+ throw new BranchDeleteRefusedError(BRANCH, GIT_OUTPUT);
118
+ }),
119
+ };
120
+
121
+ beforeEach(async () => {
122
+ ({ server, baseUrl } = await serve(workflow));
123
+ });
124
+ afterEach(async () => {
125
+ await close(server);
126
+ });
127
+
128
+ it.each([
129
+ ['reverting a file of a change request', REVERT_BRANCH, 'POST', '/workflow/change-requests/7/files/revert', { path: 'Sales/Deal.md' }],
130
+ ['opening a change request', OPEN_BRANCH, 'POST', '/workflow/change-requests', { sourceBranch: OPEN_BRANCH, targetBranch: 'main', title: 'Deal' }],
131
+ ['updating a change request from its target', UPDATE_BRANCH, 'POST', '/workflow/change-requests/7/update-from-target', undefined],
132
+ ])('%s', async (_what, branch, method, path, body) => {
133
+ const res = await call(baseUrl, method, path, body);
134
+ expect(res.status).toBe(409);
135
+ expect(res.json.error).toBe(
136
+ `Saved locally on "${branch}" but couldn't share with the team automatically — ` +
137
+ 'the repository host refused the push; the next save on this branch will try sharing it again.',
138
+ );
139
+ expect(res.json).toMatchObject({ kind: 'push-needs-resolution', branch });
140
+ expect(res.json).not.toHaveProperty('originalDetail');
141
+ expect(res.json).not.toHaveProperty('recoveryDetail');
142
+ expectNoGitOutput(res.text);
143
+ });
144
+
145
+ it('deleting a branch: 409, the host refused, the branch is still there', async () => {
146
+ const res = await call(baseUrl, 'DELETE', `/workspace/main/workflow/branches/${WS}`);
147
+ expect(res.status).toBe(409);
148
+ expect(res.json).toEqual({
149
+ kind: 'branch-delete-refused',
150
+ branchName: BRANCH,
151
+ error: `The repository host refused to delete "${BRANCH}"; it is still there. Try again later.`,
152
+ });
153
+ expectNoGitOutput(res.text);
154
+ });
155
+ });
156
+
157
+ describe('the share route over the real service', () => {
158
+ let server: Server;
159
+ let baseUrl: string;
160
+ let push: ReturnType<typeof vi.fn>;
161
+
162
+ beforeEach(async () => {
163
+ // Twice: `[remote rejected]` reads like a divergence, so the cooperative
164
+ // pull-and-retry runs too — and is refused again.
165
+ push = vi
166
+ .fn()
167
+ .mockRejectedValueOnce(new Error(GIT_OUTPUT))
168
+ .mockRejectedValueOnce(new Error(GIT_OUTPUT))
169
+ .mockResolvedValue(undefined);
170
+ const git = {
171
+ push,
172
+ pull: vi.fn().mockResolvedValue({ treeChanged: false }),
173
+ } as unknown as GitService;
174
+ const workflow = new WorkflowService(
175
+ {} as unknown as Database,
176
+ git,
177
+ {} as PullRequestService,
178
+ {} as IReviewWorkflowService,
179
+ {} as WorkspaceService,
180
+ {} as IAccessControl,
181
+ {} as FileLockService,
182
+ {} as PendingCommitsService,
183
+ testKbContext(),
184
+ openChangeGate(),
185
+ );
186
+ ({ server, baseUrl } = await serve(workflow as unknown as IWorkflowService));
187
+ });
188
+ afterEach(async () => {
189
+ await close(server);
190
+ });
191
+
192
+ it('answers 409 with the sentence instead of 500, then shares once the host accepts', async () => {
193
+ const first = await call(baseUrl, 'POST', `/workspace/${WS}/workflow/share`);
194
+ expect(first.status).toBe(409);
195
+ expect(first.json.error).toContain(`Saved locally on "${BRANCH}"`);
196
+ expectNoGitOutput(first.text);
197
+
198
+ const second = await call(baseUrl, 'POST', `/workspace/${WS}/workflow/share`);
199
+ expect(second.status).toBe(200);
200
+ expect(second.json).toEqual({ status: 'shared' });
201
+ });
202
+ });
@@ -137,7 +137,7 @@ describe('post-merge branch retirement', () => {
137
137
  const deleted: string[] = [];
138
138
  const { db, statements } = fakeDb([MERGED_23, OPEN_24_INTO_RFI]);
139
139
  const svc = makeService(db, {
140
- deleteBranch: vi.fn(async (_ws: string, name: string) => void deleted.push(name)),
140
+ deleteBranch: vi.fn(async (_ws: string, name: string) => (deleted.push(name), { lastCommit: null })),
141
141
  });
142
142
 
143
143
  await retire(svc, 23, 'target-company-state');
@@ -153,7 +153,7 @@ describe('post-merge branch retirement', () => {
153
153
  // #24 is gone; only the merged request remains, so nothing needs the branch.
154
154
  const { db } = fakeDb([MERGED_23]);
155
155
  const svc = makeService(db, {
156
- deleteBranch: vi.fn(async (_ws: string, name: string) => void deleted.push(name)),
156
+ deleteBranch: vi.fn(async (_ws: string, name: string) => (deleted.push(name), { lastCommit: null })),
157
157
  });
158
158
 
159
159
  await retire(svc, 23, 'target-company-state');
@@ -168,7 +168,7 @@ describe('post-merge branch retirement', () => {
168
168
  { number: 25, source_branch: 'juan/rfi', target_branch: 'other', state: 'open' },
169
169
  ]);
170
170
  const svc = makeService(db, {
171
- deleteBranch: vi.fn(async (_ws: string, name: string) => void deleted.push(name)),
171
+ deleteBranch: vi.fn(async (_ws: string, name: string) => (deleted.push(name), { lastCommit: null })),
172
172
  });
173
173
 
174
174
  await retire(svc, 23, 'target-company-state');
@@ -180,7 +180,7 @@ describe('post-merge branch retirement', () => {
180
180
  describe('deleteBranch', () => {
181
181
  it('refuses a branch an open request proposes INTO, naming who can act', async () => {
182
182
  const { db } = fakeDb([OPEN_24_INTO_RFI]);
183
- const svc = makeService(db, { deleteBranch: vi.fn() });
183
+ const svc = makeService(db, { deleteBranch: vi.fn(async () => ({ lastCommit: null })) });
184
184
 
185
185
  // Not "withdraw or decline it": the request belongs to someone else, and
186
186
  // the branch owner may be authorized to do neither. The message has to
@@ -194,7 +194,7 @@ describe('deleteBranch', () => {
194
194
  const { db } = fakeDb([
195
195
  { number: 26, source_branch: 'juan/rfi', target_branch: 'target-company-state', state: 'open' },
196
196
  ]);
197
- const svc = makeService(db, { deleteBranch: vi.fn() });
197
+ const svc = makeService(db, { deleteBranch: vi.fn(async () => ({ lastCommit: null })) });
198
198
 
199
199
  await expect(svc.deleteBranch('ws', 'juan/rfi', USER)).rejects.toThrow(
200
200
  /open change request \(#26\)\. Withdraw or decline it/,
@@ -205,7 +205,7 @@ describe('deleteBranch', () => {
205
205
  const deleted: string[] = [];
206
206
  const { db } = fakeDb([OPEN_24_INTO_RFI]);
207
207
  const svc = makeService(db, {
208
- deleteBranch: vi.fn(async (_ws: string, name: string) => void deleted.push(name)),
208
+ deleteBranch: vi.fn(async (_ws: string, name: string) => (deleted.push(name), { lastCommit: null })),
209
209
  });
210
210
 
211
211
  await svc.deleteBranch('ws', 'juan/unrelated', USER);