@bevel-software/platform-core-backend 0.25.2 → 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 (733) hide show
  1. package/agent-guide/access-control.md +251 -0
  2. package/agent-guide/conventions.md +35 -0
  3. package/agent-guide/directory-structure.md +145 -0
  4. package/agent-guide/finding-things.md +7 -0
  5. package/agent-guide/html-views.md +83 -0
  6. package/agent-guide/introduction.md +27 -0
  7. package/agent-guide/new-knowledge-base.md +24 -0
  8. package/agent-guide/skills.md +47 -0
  9. package/agent-guide/tool-manuals.md +227 -0
  10. package/agent-guide/where-a-new-file-goes.md +36 -0
  11. package/dist/assets.d.ts +26 -0
  12. package/dist/assets.d.ts.map +1 -1
  13. package/dist/assets.js +35 -2
  14. package/dist/assets.js.map +1 -1
  15. package/dist/core/catalog-revision.d.ts +19 -1
  16. package/dist/core/catalog-revision.d.ts.map +1 -1
  17. package/dist/core/catalog-revision.js +14 -3
  18. package/dist/core/catalog-revision.js.map +1 -1
  19. package/dist/core/core-ports.d.ts +11 -0
  20. package/dist/core/core-ports.d.ts.map +1 -1
  21. package/dist/core/core-ports.js.map +1 -1
  22. package/dist/core/create-core-server.d.ts +5 -0
  23. package/dist/core/create-core-server.d.ts.map +1 -1
  24. package/dist/core/create-core-server.js +65 -3
  25. package/dist/core/create-core-server.js.map +1 -1
  26. package/dist/core/create-core-services.d.ts +35 -0
  27. package/dist/core/create-core-services.d.ts.map +1 -1
  28. package/dist/core/create-core-services.js +114 -12
  29. package/dist/core/create-core-services.js.map +1 -1
  30. package/dist/core/lifecycle.d.ts +16 -1
  31. package/dist/core/lifecycle.d.ts.map +1 -1
  32. package/dist/core/lifecycle.js +18 -1
  33. package/dist/core/lifecycle.js.map +1 -1
  34. package/dist/core-config.d.ts +21 -0
  35. package/dist/core-config.d.ts.map +1 -1
  36. package/dist/core-config.js +22 -1
  37. package/dist/core-config.js.map +1 -1
  38. package/dist/index.d.ts +1 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +2 -2
  41. package/dist/index.js.map +1 -1
  42. package/dist/modules/access/access-control.interface.d.ts +17 -0
  43. package/dist/modules/access/access-control.interface.d.ts.map +1 -1
  44. package/dist/modules/access/access-control.service.d.ts +2 -0
  45. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  46. package/dist/modules/access/access-control.service.js +27 -0
  47. package/dist/modules/access/access-control.service.js.map +1 -1
  48. package/dist/modules/access/directory-sync-bot.js +1 -1
  49. package/dist/modules/access/directory-sync-bot.js.map +1 -1
  50. package/dist/modules/agent-guide/agent-guide.d.ts +145 -0
  51. package/dist/modules/agent-guide/agent-guide.d.ts.map +1 -0
  52. package/dist/modules/agent-guide/agent-guide.js +199 -0
  53. package/dist/modules/agent-guide/agent-guide.js.map +1 -0
  54. package/dist/modules/agent-guide/agent-guide.tools.d.ts +24 -0
  55. package/dist/modules/agent-guide/agent-guide.tools.d.ts.map +1 -0
  56. package/dist/modules/agent-guide/agent-guide.tools.js +100 -0
  57. package/dist/modules/agent-guide/agent-guide.tools.js.map +1 -0
  58. package/dist/modules/agent-guide/index.d.ts +4 -0
  59. package/dist/modules/agent-guide/index.d.ts.map +1 -0
  60. package/dist/modules/agent-guide/index.js +4 -0
  61. package/dist/modules/agent-guide/index.js.map +1 -0
  62. package/dist/modules/agent-instructions/agent-instructions.routes.d.ts +3 -2
  63. package/dist/modules/agent-instructions/agent-instructions.routes.d.ts.map +1 -1
  64. package/dist/modules/agent-instructions/agent-instructions.routes.js +3 -2
  65. package/dist/modules/agent-instructions/agent-instructions.routes.js.map +1 -1
  66. package/dist/modules/agent-instructions/compose.d.ts +14 -6
  67. package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
  68. package/dist/modules/agent-instructions/compose.js +28 -8
  69. package/dist/modules/agent-instructions/compose.js.map +1 -1
  70. package/dist/modules/agent-instructions/index.d.ts +1 -1
  71. package/dist/modules/agent-instructions/index.d.ts.map +1 -1
  72. package/dist/modules/agent-instructions/index.js +1 -1
  73. package/dist/modules/agent-instructions/index.js.map +1 -1
  74. package/dist/modules/agent-instructions/shared-file-rules.d.ts +10 -50
  75. package/dist/modules/agent-instructions/shared-file-rules.d.ts.map +1 -1
  76. package/dist/modules/agent-instructions/shared-file-rules.js +51 -104
  77. package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -1
  78. package/dist/modules/audit/agent-audit.service.d.ts +21 -2
  79. package/dist/modules/audit/agent-audit.service.d.ts.map +1 -1
  80. package/dist/modules/audit/agent-audit.service.js +43 -2
  81. package/dist/modules/audit/agent-audit.service.js.map +1 -1
  82. package/dist/modules/audit/agent-connection.routes.d.ts +34 -0
  83. package/dist/modules/audit/agent-connection.routes.d.ts.map +1 -0
  84. package/dist/modules/audit/agent-connection.routes.js +38 -0
  85. package/dist/modules/audit/agent-connection.routes.js.map +1 -0
  86. package/dist/modules/audit/audit.contract.d.ts +24 -0
  87. package/dist/modules/audit/audit.contract.d.ts.map +1 -1
  88. package/dist/modules/audit/audit.contract.js.map +1 -1
  89. package/dist/modules/audit/index.d.ts +1 -0
  90. package/dist/modules/audit/index.d.ts.map +1 -1
  91. package/dist/modules/audit/index.js +1 -0
  92. package/dist/modules/audit/index.js.map +1 -1
  93. package/dist/modules/auth/account.routes.d.ts.map +1 -1
  94. package/dist/modules/auth/account.routes.js +10 -3
  95. package/dist/modules/auth/account.routes.js.map +1 -1
  96. package/dist/modules/auth/auth.middleware.d.ts +7 -0
  97. package/dist/modules/auth/auth.middleware.d.ts.map +1 -1
  98. package/dist/modules/auth/auth.middleware.js +1 -1
  99. package/dist/modules/auth/auth.middleware.js.map +1 -1
  100. package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -1
  101. package/dist/modules/code-mode/code-mode.tool.js +11 -3
  102. package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
  103. package/dist/modules/database/core-schema.d.ts +96 -0
  104. package/dist/modules/database/core-schema.d.ts.map +1 -1
  105. package/dist/modules/database/core-schema.js +32 -3
  106. package/dist/modules/database/core-schema.js.map +1 -1
  107. package/dist/modules/embed/account-link.service.d.ts +42 -0
  108. package/dist/modules/embed/account-link.service.d.ts.map +1 -0
  109. package/dist/modules/embed/account-link.service.js +50 -0
  110. package/dist/modules/embed/account-link.service.js.map +1 -0
  111. package/dist/modules/embed/embed-link.d.ts +58 -0
  112. package/dist/modules/embed/embed-link.d.ts.map +1 -0
  113. package/dist/modules/embed/embed-link.js +160 -0
  114. package/dist/modules/embed/embed-link.js.map +1 -0
  115. package/dist/modules/embed/embed.errors.d.ts +30 -0
  116. package/dist/modules/embed/embed.errors.d.ts.map +1 -0
  117. package/dist/modules/embed/embed.errors.js +42 -0
  118. package/dist/modules/embed/embed.errors.js.map +1 -0
  119. package/dist/modules/embed/embed.interface.d.ts +204 -0
  120. package/dist/modules/embed/embed.interface.d.ts.map +1 -0
  121. package/dist/modules/embed/embed.interface.js +2 -0
  122. package/dist/modules/embed/embed.interface.js.map +1 -0
  123. package/dist/modules/embed/embed.routes.d.ts +59 -0
  124. package/dist/modules/embed/embed.routes.d.ts.map +1 -0
  125. package/dist/modules/embed/embed.routes.js +343 -0
  126. package/dist/modules/embed/embed.routes.js.map +1 -0
  127. package/dist/modules/embed/embed.service.d.ts +169 -0
  128. package/dist/modules/embed/embed.service.d.ts.map +1 -0
  129. package/dist/modules/embed/embed.service.js +627 -0
  130. package/dist/modules/embed/embed.service.js.map +1 -0
  131. package/dist/modules/embed/embed.tools.d.ts +51 -0
  132. package/dist/modules/embed/embed.tools.d.ts.map +1 -0
  133. package/dist/modules/embed/embed.tools.js +170 -0
  134. package/dist/modules/embed/embed.tools.js.map +1 -0
  135. package/dist/modules/embed/mcp-app.d.ts +64 -0
  136. package/dist/modules/embed/mcp-app.d.ts.map +1 -0
  137. package/dist/modules/embed/mcp-app.js +147 -0
  138. package/dist/modules/embed/mcp-app.js.map +1 -0
  139. package/dist/modules/embed/mcp-app.routes.d.ts +21 -0
  140. package/dist/modules/embed/mcp-app.routes.d.ts.map +1 -0
  141. package/dist/modules/embed/mcp-app.routes.js +36 -0
  142. package/dist/modules/embed/mcp-app.routes.js.map +1 -0
  143. package/dist/modules/github-app/github-app.connection.d.ts +15 -0
  144. package/dist/modules/github-app/github-app.connection.d.ts.map +1 -1
  145. package/dist/modules/github-app/github-app.connection.js +34 -3
  146. package/dist/modules/github-app/github-app.connection.js.map +1 -1
  147. package/dist/modules/kb-fs/locking-filesystem.d.ts +65 -0
  148. package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
  149. package/dist/modules/kb-fs/locking-filesystem.js +300 -0
  150. package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
  151. package/dist/modules/kb-sync/kb-sync.interface.d.ts +5 -0
  152. package/dist/modules/kb-sync/kb-sync.interface.d.ts.map +1 -1
  153. package/dist/modules/kb-sync/kb-sync.service.d.ts.map +1 -1
  154. package/dist/modules/kb-sync/kb-sync.service.js +6 -0
  155. package/dist/modules/kb-sync/kb-sync.service.js.map +1 -1
  156. package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
  157. package/dist/modules/mcp/mcp-auth.middleware.js +2 -1
  158. package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
  159. package/dist/modules/mcp/mcp.service.d.ts +57 -3
  160. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  161. package/dist/modules/mcp/mcp.service.js +177 -24
  162. package/dist/modules/mcp/mcp.service.js.map +1 -1
  163. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +24 -0
  164. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
  165. package/dist/modules/mcp/oauth/bevel-oauth-provider.js +32 -4
  166. package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
  167. package/dist/modules/mcp/tool-schema-guard.d.ts +105 -0
  168. package/dist/modules/mcp/tool-schema-guard.d.ts.map +1 -0
  169. package/dist/modules/mcp/tool-schema-guard.js +171 -0
  170. package/dist/modules/mcp/tool-schema-guard.js.map +1 -0
  171. package/dist/modules/onboarding/onboarding.contract.d.ts +80 -0
  172. package/dist/modules/onboarding/onboarding.contract.d.ts.map +1 -0
  173. package/dist/modules/onboarding/onboarding.contract.js +7 -0
  174. package/dist/modules/onboarding/onboarding.contract.js.map +1 -0
  175. package/dist/modules/onboarding/onboarding.routes.d.ts +18 -0
  176. package/dist/modules/onboarding/onboarding.routes.d.ts.map +1 -0
  177. package/dist/modules/onboarding/onboarding.routes.js +81 -0
  178. package/dist/modules/onboarding/onboarding.routes.js.map +1 -0
  179. package/dist/modules/onboarding/starter-pack.service.d.ts +213 -0
  180. package/dist/modules/onboarding/starter-pack.service.d.ts.map +1 -0
  181. package/dist/modules/onboarding/starter-pack.service.js +492 -0
  182. package/dist/modules/onboarding/starter-pack.service.js.map +1 -0
  183. package/dist/modules/onboarding/starter-packs.d.ts +78 -0
  184. package/dist/modules/onboarding/starter-packs.d.ts.map +1 -0
  185. package/dist/modules/onboarding/starter-packs.js +156 -0
  186. package/dist/modules/onboarding/starter-packs.js.map +1 -0
  187. package/dist/modules/plugins/index.d.ts +1 -1
  188. package/dist/modules/plugins/index.d.ts.map +1 -1
  189. package/dist/modules/plugins/index.js +1 -1
  190. package/dist/modules/plugins/index.js.map +1 -1
  191. package/dist/modules/plugins/plugin-provision.service.d.ts +19 -0
  192. package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
  193. package/dist/modules/plugins/plugin-provision.service.js +18 -1
  194. package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
  195. package/dist/modules/plugins/plugins.routes.d.ts +0 -36
  196. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  197. package/dist/modules/plugins/plugins.routes.js +31 -0
  198. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  199. package/dist/modules/plugins/plugins.tools.d.ts +36 -2
  200. package/dist/modules/plugins/plugins.tools.d.ts.map +1 -1
  201. package/dist/modules/plugins/plugins.tools.js +71 -14
  202. package/dist/modules/plugins/plugins.tools.js.map +1 -1
  203. package/dist/modules/settings/deployment-settings.service.d.ts +34 -7
  204. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  205. package/dist/modules/settings/deployment-settings.service.js +148 -54
  206. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  207. package/dist/modules/settings/repository-source.d.ts +1 -0
  208. package/dist/modules/settings/repository-source.d.ts.map +1 -1
  209. package/dist/modules/settings/repository-source.js +3 -3
  210. package/dist/modules/settings/repository-source.js.map +1 -1
  211. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  212. package/dist/modules/settings/setup.routes.js +3 -6
  213. package/dist/modules/settings/setup.routes.js.map +1 -1
  214. package/dist/modules/skills/skills.tools.d.ts.map +1 -1
  215. package/dist/modules/skills/skills.tools.js +103 -43
  216. package/dist/modules/skills/skills.tools.js.map +1 -1
  217. package/dist/modules/tool-auth/connection-key-rejection.d.ts +10 -1
  218. package/dist/modules/tool-auth/connection-key-rejection.d.ts.map +1 -1
  219. package/dist/modules/tool-auth/connection-key-rejection.js +11 -3
  220. package/dist/modules/tool-auth/connection-key-rejection.js.map +1 -1
  221. package/dist/modules/tool-auth/external-api-key.interface.d.ts +8 -0
  222. package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
  223. package/dist/modules/tool-auth/external-api-key.service.d.ts +24 -2
  224. package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
  225. package/dist/modules/tool-auth/external-api-key.service.js +59 -2
  226. package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
  227. package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
  228. package/dist/modules/tool-auth/tool-auth.middleware.js +9 -4
  229. package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
  230. package/dist/modules/tool-helpers/index.d.ts +28 -1
  231. package/dist/modules/tool-helpers/index.d.ts.map +1 -1
  232. package/dist/modules/tool-helpers/index.js +28 -1
  233. package/dist/modules/tool-helpers/index.js.map +1 -1
  234. package/dist/modules/tool-helpers/route-argument-check.d.ts +10 -0
  235. package/dist/modules/tool-helpers/route-argument-check.d.ts.map +1 -0
  236. package/dist/modules/tool-helpers/route-argument-check.js +132 -0
  237. package/dist/modules/tool-helpers/route-argument-check.js.map +1 -0
  238. package/dist/modules/tool-helpers/route-tool-schemas.d.ts +89 -0
  239. package/dist/modules/tool-helpers/route-tool-schemas.d.ts.map +1 -0
  240. package/dist/modules/tool-helpers/route-tool-schemas.js +113 -0
  241. package/dist/modules/tool-helpers/route-tool-schemas.js.map +1 -0
  242. package/dist/modules/tool-helpers/tool-def.d.ts +71 -0
  243. package/dist/modules/tool-helpers/tool-def.d.ts.map +1 -1
  244. package/dist/modules/tool-helpers/tool-def.js +70 -6
  245. package/dist/modules/tool-helpers/tool-def.js.map +1 -1
  246. package/dist/modules/tool-helpers/tool-handler.d.ts +46 -6
  247. package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
  248. package/dist/modules/tool-helpers/tool-handler.js +157 -8
  249. package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
  250. package/dist/modules/tool-helpers/tool.contract.d.ts +9 -0
  251. package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
  252. package/dist/modules/tool-helpers/tool.contract.js.map +1 -1
  253. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +23 -4
  254. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
  255. package/dist/modules/tool-manuals/tool-manuals.contract.js.map +1 -1
  256. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +4 -0
  257. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  258. package/dist/modules/tool-manuals/tool-manuals.service.js +14 -0
  259. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  260. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +7 -0
  261. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  262. package/dist/modules/tool-manuals/tool-manuals.tools.js +77 -38
  263. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  264. package/dist/modules/tool-registry/description-length.d.ts +20 -16
  265. package/dist/modules/tool-registry/description-length.d.ts.map +1 -1
  266. package/dist/modules/tool-registry/description-length.js +50 -30
  267. package/dist/modules/tool-registry/description-length.js.map +1 -1
  268. package/dist/modules/tool-registry/guide-first.d.ts +27 -0
  269. package/dist/modules/tool-registry/guide-first.d.ts.map +1 -0
  270. package/dist/modules/tool-registry/guide-first.js +40 -0
  271. package/dist/modules/tool-registry/guide-first.js.map +1 -0
  272. package/dist/modules/tool-registry/tool-registry.d.ts +6 -0
  273. package/dist/modules/tool-registry/tool-registry.d.ts.map +1 -1
  274. package/dist/modules/tool-registry/tool-registry.js +9 -2
  275. package/dist/modules/tool-registry/tool-registry.js.map +1 -1
  276. package/dist/modules/workflow/agent-tools/change-request-read-shape.d.ts +449 -0
  277. package/dist/modules/workflow/agent-tools/change-request-read-shape.d.ts.map +1 -0
  278. package/dist/modules/workflow/agent-tools/change-request-read-shape.js +481 -0
  279. package/dist/modules/workflow/agent-tools/change-request-read-shape.js.map +1 -0
  280. package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts +126 -0
  281. package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts.map +1 -0
  282. package/dist/modules/workflow/agent-tools/change-request-read.tools.js +611 -0
  283. package/dist/modules/workflow/agent-tools/change-request-read.tools.js.map +1 -0
  284. package/dist/modules/workflow/agent-tools/change-request-summary.d.ts +12 -1
  285. package/dist/modules/workflow/agent-tools/change-request-summary.d.ts.map +1 -1
  286. package/dist/modules/workflow/agent-tools/change-request-summary.js +5 -1
  287. package/dist/modules/workflow/agent-tools/change-request-summary.js.map +1 -1
  288. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +8 -1
  289. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  290. package/dist/modules/workflow/agent-tools/workflow.tools.js +133 -37
  291. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  292. package/dist/modules/workflow/file-lock.service.d.ts +29 -5
  293. package/dist/modules/workflow/file-lock.service.d.ts.map +1 -1
  294. package/dist/modules/workflow/file-lock.service.js +62 -5
  295. package/dist/modules/workflow/file-lock.service.js.map +1 -1
  296. package/dist/modules/workflow/git/git.service.d.ts +282 -14
  297. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  298. package/dist/modules/workflow/git/git.service.js +627 -126
  299. package/dist/modules/workflow/git/git.service.js.map +1 -1
  300. package/dist/modules/workflow/git/merge-commit.d.ts +73 -0
  301. package/dist/modules/workflow/git/merge-commit.d.ts.map +1 -0
  302. package/dist/modules/workflow/git/merge-commit.js +89 -0
  303. package/dist/modules/workflow/git/merge-commit.js.map +1 -0
  304. package/dist/modules/workflow/git/node-git-runner.d.ts +15 -0
  305. package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -1
  306. package/dist/modules/workflow/git/node-git-runner.js +78 -6
  307. package/dist/modules/workflow/git/node-git-runner.js.map +1 -1
  308. package/dist/modules/workflow/git/pull-request.service.d.ts +94 -1
  309. package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
  310. package/dist/modules/workflow/git/pull-request.service.js +332 -37
  311. package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
  312. package/dist/modules/workflow/pending-commits.service.d.ts +15 -0
  313. package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -1
  314. package/dist/modules/workflow/pending-commits.service.js +25 -1
  315. package/dist/modules/workflow/pending-commits.service.js.map +1 -1
  316. package/dist/modules/workflow/pending-commits.worker.d.ts +6 -1
  317. package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -1
  318. package/dist/modules/workflow/pending-commits.worker.js +23 -6
  319. package/dist/modules/workflow/pending-commits.worker.js.map +1 -1
  320. package/dist/modules/workflow/recovery-bot.js +1 -1
  321. package/dist/modules/workflow/recovery-bot.js.map +1 -1
  322. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts +35 -0
  323. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
  324. package/dist/modules/workflow/review-workflow/review-workflow.service.js +180 -13
  325. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
  326. package/dist/modules/workflow/sanitize-error.d.ts +16 -0
  327. package/dist/modules/workflow/sanitize-error.d.ts.map +1 -1
  328. package/dist/modules/workflow/sanitize-error.js +45 -0
  329. package/dist/modules/workflow/sanitize-error.js.map +1 -1
  330. package/dist/modules/workflow/workflow.routes.d.ts +6 -2
  331. package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
  332. package/dist/modules/workflow/workflow.routes.js +7 -2
  333. package/dist/modules/workflow/workflow.routes.js.map +1 -1
  334. package/dist/modules/workflow/workflow.service.d.ts +187 -15
  335. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  336. package/dist/modules/workflow/workflow.service.js +808 -106
  337. package/dist/modules/workflow/workflow.service.js.map +1 -1
  338. package/dist/modules/workspace/agent-download.builder.d.ts +105 -0
  339. package/dist/modules/workspace/agent-download.builder.d.ts.map +1 -0
  340. package/dist/modules/workspace/agent-download.builder.js +238 -0
  341. package/dist/modules/workspace/agent-download.builder.js.map +1 -0
  342. package/dist/modules/workspace/agent-download.routes.d.ts +77 -0
  343. package/dist/modules/workspace/agent-download.routes.d.ts.map +1 -0
  344. package/dist/modules/workspace/agent-download.routes.js +156 -0
  345. package/dist/modules/workspace/agent-download.routes.js.map +1 -0
  346. package/dist/modules/workspace/agent-download.store.d.ts +225 -0
  347. package/dist/modules/workspace/agent-download.store.d.ts.map +1 -0
  348. package/dist/modules/workspace/agent-download.store.js +423 -0
  349. package/dist/modules/workspace/agent-download.store.js.map +1 -0
  350. package/dist/modules/workspace/agent-upload.store.d.ts +10 -1
  351. package/dist/modules/workspace/agent-upload.store.d.ts.map +1 -1
  352. package/dist/modules/workspace/agent-upload.store.js +16 -6
  353. package/dist/modules/workspace/agent-upload.store.js.map +1 -1
  354. package/dist/modules/workspace/file-readers/raw-mime.d.ts +6 -0
  355. package/dist/modules/workspace/file-readers/raw-mime.d.ts.map +1 -0
  356. package/dist/modules/workspace/file-readers/raw-mime.js +38 -0
  357. package/dist/modules/workspace/file-readers/raw-mime.js.map +1 -0
  358. package/dist/modules/workspace/file-readers/text-reader.d.ts +5 -5
  359. package/dist/modules/workspace/file-readers/text-reader.d.ts.map +1 -1
  360. package/dist/modules/workspace/file-readers/text-reader.js +5 -8
  361. package/dist/modules/workspace/file-readers/text-reader.js.map +1 -1
  362. package/dist/modules/workspace/first-run.d.ts +111 -0
  363. package/dist/modules/workspace/first-run.d.ts.map +1 -0
  364. package/dist/modules/workspace/first-run.js +181 -0
  365. package/dist/modules/workspace/first-run.js.map +1 -0
  366. package/dist/modules/workspace/move-links.d.ts +92 -0
  367. package/dist/modules/workspace/move-links.d.ts.map +1 -0
  368. package/dist/modules/workspace/move-links.js +173 -0
  369. package/dist/modules/workspace/move-links.js.map +1 -0
  370. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  371. package/dist/modules/workspace/startup/steps/seed-tree.js +24 -39
  372. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  373. package/dist/modules/workspace/startup/steps/template-files.step.d.ts +58 -52
  374. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
  375. package/dist/modules/workspace/startup/steps/template-files.step.js +209 -223
  376. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
  377. package/dist/modules/workspace/startup/steps/template-source.d.ts +5 -3
  378. package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
  379. package/dist/modules/workspace/startup/steps/template-source.js +5 -3
  380. package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
  381. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  382. package/dist/modules/workspace/workspace.routes.js +63 -22
  383. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  384. package/dist/modules/workspace/workspace.service.d.ts +75 -2
  385. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  386. package/dist/modules/workspace/workspace.service.js +197 -24
  387. package/dist/modules/workspace/workspace.service.js.map +1 -1
  388. package/dist/modules/workspace/workspace.tools.d.ts +68 -1
  389. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  390. package/dist/modules/workspace/workspace.tools.js +642 -71
  391. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  392. package/dist/modules/write-access/write-access.d.ts.map +1 -1
  393. package/dist/modules/write-access/write-access.js +9 -0
  394. package/dist/modules/write-access/write-access.js.map +1 -1
  395. package/dist/shared/domain-errors.d.ts +84 -1
  396. package/dist/shared/domain-errors.d.ts.map +1 -1
  397. package/dist/shared/domain-errors.js +100 -12
  398. package/dist/shared/domain-errors.js.map +1 -1
  399. package/dist/shared/git.contract.d.ts +10 -1
  400. package/dist/shared/git.contract.d.ts.map +1 -1
  401. package/dist/shared/git.contract.js.map +1 -1
  402. package/dist/shared/hidden-tools.d.ts +44 -0
  403. package/dist/shared/hidden-tools.d.ts.map +1 -0
  404. package/dist/shared/hidden-tools.js +13 -0
  405. package/dist/shared/hidden-tools.js.map +1 -0
  406. package/dist/shared/utf8-text.d.ts +15 -0
  407. package/dist/shared/utf8-text.d.ts.map +1 -0
  408. package/dist/shared/utf8-text.js +20 -0
  409. package/dist/shared/utf8-text.js.map +1 -0
  410. package/dist/tenancy/static-tenant-source.d.ts +2 -1
  411. package/dist/tenancy/static-tenant-source.d.ts.map +1 -1
  412. package/dist/tenancy/static-tenant-source.js +9 -2
  413. package/dist/tenancy/static-tenant-source.js.map +1 -1
  414. package/kb-template/.bevelignore +0 -5
  415. package/mcp-app/page.html +349 -0
  416. package/migrations/0017_atlassian_account_links.sql +37 -0
  417. package/migrations/meta/0017_snapshot.json +2396 -0
  418. package/migrations/meta/_journal.json +8 -1
  419. package/package.json +6 -3
  420. package/src/__tests__/kb-layout-config.test.ts +10 -100
  421. package/src/__tests__/packaged-assets-ship.test.ts +66 -0
  422. package/src/assets.ts +38 -2
  423. package/src/core/__tests__/catalog-revision.test.ts +40 -0
  424. package/src/core/__tests__/gated-boot.test.ts +1 -0
  425. package/src/core/__tests__/lifecycle.test.ts +14 -0
  426. package/src/core/catalog-revision.ts +15 -2
  427. package/src/core/core-ports.ts +11 -0
  428. package/src/core/create-core-server.ts +78 -3
  429. package/src/core/create-core-services.ts +168 -10
  430. package/src/core/lifecycle.ts +28 -2
  431. package/src/core-config.ts +24 -1
  432. package/src/index.ts +2 -2
  433. package/src/modules/access/__tests__/access-control.atref-batch.test.ts +58 -0
  434. package/src/modules/access/__tests__/access-control.platform-restore.test.ts +8 -7
  435. package/src/modules/access/__tests__/access-control.service.test.ts +19 -0
  436. package/src/modules/access/__tests__/access-personal-plugin.test.ts +1 -18
  437. package/src/modules/access/access-control.interface.ts +28 -0
  438. package/src/modules/access/access-control.service.ts +37 -0
  439. package/src/modules/access/directory-sync-bot.ts +1 -1
  440. package/src/modules/agent-guide/__tests__/agent-guide.test.ts +386 -0
  441. package/src/modules/agent-guide/__tests__/agent-guide.tools.test.ts +207 -0
  442. package/src/modules/agent-guide/agent-guide.tools.ts +122 -0
  443. package/src/modules/agent-guide/agent-guide.ts +300 -0
  444. package/src/modules/agent-guide/index.ts +22 -0
  445. package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +39 -118
  446. package/src/modules/agent-instructions/agent-instructions.routes.ts +3 -2
  447. package/src/modules/agent-instructions/compose.ts +26 -8
  448. package/src/modules/agent-instructions/index.ts +0 -3
  449. package/src/modules/agent-instructions/shared-file-rules.ts +50 -112
  450. package/src/modules/audit/__tests__/agent-audit.service.test.ts +64 -4
  451. package/src/modules/audit/__tests__/agent-connection.routes.test.ts +102 -0
  452. package/src/modules/audit/agent-audit.service.ts +58 -3
  453. package/src/modules/audit/agent-connection.routes.ts +56 -0
  454. package/src/modules/audit/audit.contract.ts +26 -0
  455. package/src/modules/audit/index.ts +1 -0
  456. package/src/modules/auth/__tests__/account.routes.test.ts +5 -3
  457. package/src/modules/auth/account.routes.ts +10 -3
  458. package/src/modules/auth/auth.middleware.ts +1 -1
  459. package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +18 -2
  460. package/src/modules/code-mode/code-mode.tool.ts +13 -2
  461. package/src/modules/database/core-schema.ts +33 -3
  462. package/src/modules/embed/__tests__/account-links.migration.test.ts +98 -0
  463. package/src/modules/embed/__tests__/embed-link.test.ts +122 -0
  464. package/src/modules/embed/__tests__/embed.routes.test.ts +362 -0
  465. package/src/modules/embed/__tests__/embed.service.lock.test.ts +193 -0
  466. package/src/modules/embed/__tests__/embed.service.test.ts +805 -0
  467. package/src/modules/embed/__tests__/embed.tools.test.ts +304 -0
  468. package/src/modules/embed/__tests__/mcp-app.test.ts +207 -0
  469. package/src/modules/embed/account-link.service.ts +76 -0
  470. package/src/modules/embed/embed-link.ts +180 -0
  471. package/src/modules/embed/embed.errors.ts +43 -0
  472. package/src/modules/embed/embed.interface.ts +203 -0
  473. package/src/modules/embed/embed.routes.ts +363 -0
  474. package/src/modules/embed/embed.service.ts +705 -0
  475. package/src/modules/embed/embed.tools.ts +206 -0
  476. package/src/modules/embed/mcp-app.routes.ts +41 -0
  477. package/src/modules/embed/mcp-app.ts +173 -0
  478. package/src/modules/github-app/__tests__/github-app.test.ts +76 -0
  479. package/src/modules/github-app/github-app.connection.ts +38 -4
  480. package/src/modules/kb-fs/__tests__/move-with-edits.test.ts +304 -0
  481. package/src/modules/kb-fs/locking-filesystem.ts +287 -0
  482. package/src/modules/kb-sync/__tests__/kb-sync.service.test.ts +35 -0
  483. package/src/modules/kb-sync/kb-sync.interface.ts +2 -0
  484. package/src/modules/kb-sync/kb-sync.service.ts +6 -0
  485. package/src/modules/mcp/__tests__/bevel-oauth-provider.test.ts +68 -11
  486. package/src/modules/mcp/__tests__/fake-downstream-mcp-server.ts +14 -3
  487. package/src/modules/mcp/__tests__/mcp-proxy-helpers.test.ts +37 -2
  488. package/src/modules/mcp/__tests__/mcp.app.e2e.test.ts +200 -0
  489. package/src/modules/mcp/__tests__/mcp.e2e.test.ts +252 -0
  490. package/src/modules/mcp/__tests__/mcp.service.test.ts +42 -24
  491. package/src/modules/mcp/__tests__/tool-call-interface.e2e.test.ts +499 -0
  492. package/src/modules/mcp/__tests__/tool-schema-guard.test.ts +266 -0
  493. package/src/modules/mcp/mcp-auth.middleware.ts +2 -1
  494. package/src/modules/mcp/mcp.service.ts +218 -31
  495. package/src/modules/mcp/oauth/bevel-oauth-provider.ts +42 -4
  496. package/src/modules/mcp/tool-schema-guard.ts +196 -0
  497. package/src/modules/onboarding/__tests__/onboarding.routes.test.ts +163 -0
  498. package/src/modules/onboarding/__tests__/starter-pack.service.test.ts +635 -0
  499. package/src/modules/onboarding/__tests__/starter-packs.test.ts +169 -0
  500. package/src/modules/onboarding/onboarding.contract.ts +85 -0
  501. package/src/modules/onboarding/onboarding.routes.ts +85 -0
  502. package/src/modules/onboarding/starter-pack.service.ts +580 -0
  503. package/src/modules/onboarding/starter-packs.ts +182 -0
  504. package/src/modules/plugins/__tests__/plugins.tools.test.ts +177 -4
  505. package/src/modules/plugins/index.ts +1 -0
  506. package/src/modules/plugins/plugin-provision.service.ts +22 -1
  507. package/src/modules/plugins/plugins.routes.ts +29 -0
  508. package/src/modules/plugins/plugins.tools.ts +75 -15
  509. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +176 -56
  510. package/src/modules/settings/__tests__/repository-source.test.ts +9 -0
  511. package/src/modules/settings/deployment-settings.service.ts +144 -55
  512. package/src/modules/settings/repository-source.ts +4 -4
  513. package/src/modules/settings/setup.routes.ts +3 -6
  514. package/src/modules/skills/__tests__/skills.tools.description.test.ts +95 -0
  515. package/src/modules/skills/skills.tools.ts +112 -46
  516. package/src/modules/tool-auth/__tests__/connection-key-rejection.test.ts +32 -0
  517. package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +65 -0
  518. package/src/modules/tool-auth/connection-key-rejection.ts +13 -3
  519. package/src/modules/tool-auth/external-api-key.interface.ts +9 -0
  520. package/src/modules/tool-auth/external-api-key.service.ts +61 -4
  521. package/src/modules/tool-auth/tool-auth.middleware.ts +13 -4
  522. package/src/modules/tool-helpers/__tests__/branch-declaration.test.ts +502 -0
  523. package/src/modules/tool-helpers/__tests__/route-argument-check.test.ts +337 -0
  524. package/src/modules/tool-helpers/index.ts +34 -1
  525. package/src/modules/tool-helpers/route-argument-check.ts +149 -0
  526. package/src/modules/tool-helpers/route-tool-schemas.ts +171 -0
  527. package/src/modules/tool-helpers/tool-def.ts +132 -7
  528. package/src/modules/tool-helpers/tool-handler.ts +196 -8
  529. package/src/modules/tool-helpers/tool.contract.ts +9 -0
  530. package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +57 -0
  531. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +73 -4
  532. package/src/modules/tool-manuals/tool-manuals.contract.ts +24 -4
  533. package/src/modules/tool-manuals/tool-manuals.service.ts +17 -0
  534. package/src/modules/tool-manuals/tool-manuals.tools.ts +86 -38
  535. package/src/modules/tool-registry/__tests__/own-tool-schemas.test.ts +173 -0
  536. package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +81 -66
  537. package/src/modules/tool-registry/description-length.ts +57 -32
  538. package/src/modules/tool-registry/guide-first.ts +41 -0
  539. package/src/modules/tool-registry/tool-registry.ts +9 -2
  540. package/src/modules/workflow/__tests__/apply-failure.test.ts +6 -1
  541. package/src/modules/workflow/__tests__/file-lock.service.deletion-gate.test.ts +104 -0
  542. package/src/modules/workflow/__tests__/pending-commits.repository-replaced.test.ts +66 -0
  543. package/src/modules/workflow/__tests__/pending-commits.worker.test.ts +31 -2
  544. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +110 -6
  545. package/src/modules/workflow/__tests__/sanitize-error.test.ts +89 -1
  546. package/src/modules/workflow/__tests__/workflow.routes.push-refused.test.ts +202 -0
  547. package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +6 -6
  548. package/src/modules/workflow/__tests__/workflow.service.delete-branch.test.ts +1026 -0
  549. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +468 -10
  550. package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +4 -0
  551. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +5 -4
  552. package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +54 -2
  553. package/src/modules/workflow/agent-tools/__tests__/change-request-read-shape.test.ts +705 -0
  554. package/src/modules/workflow/agent-tools/__tests__/change-request-read.tools.test.ts +1554 -0
  555. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +150 -4
  556. package/src/modules/workflow/agent-tools/change-request-read-shape.ts +712 -0
  557. package/src/modules/workflow/agent-tools/change-request-read.tools.ts +759 -0
  558. package/src/modules/workflow/agent-tools/change-request-summary.ts +5 -1
  559. package/src/modules/workflow/agent-tools/workflow.tools.ts +137 -35
  560. package/src/modules/workflow/file-lock.service.ts +67 -5
  561. package/src/modules/workflow/git/__tests__/git.service.appliedChange.test.ts +285 -0
  562. package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +124 -0
  563. package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +164 -0
  564. package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +334 -0
  565. package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +48 -1
  566. package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +231 -2
  567. package/src/modules/workflow/git/__tests__/pull-request.service.list-fetch.test.ts +72 -2
  568. package/src/modules/workflow/git/__tests__/pull-request.service.placeholder.test.ts +24 -2
  569. package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +620 -1
  570. package/src/modules/workflow/git/git.service.ts +714 -133
  571. package/src/modules/workflow/git/merge-commit.ts +88 -0
  572. package/src/modules/workflow/git/node-git-runner.ts +82 -7
  573. package/src/modules/workflow/git/pull-request.service.ts +380 -54
  574. package/src/modules/workflow/pending-commits.service.ts +29 -1
  575. package/src/modules/workflow/pending-commits.worker.ts +24 -6
  576. package/src/modules/workflow/recovery-bot.ts +1 -1
  577. package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +7 -1
  578. package/src/modules/workflow/review-workflow/__tests__/merge-records-own-commit.test.ts +407 -0
  579. package/src/modules/workflow/review-workflow/review-workflow.service.ts +191 -12
  580. package/src/modules/workflow/sanitize-error.ts +50 -0
  581. package/src/modules/workflow/workflow.routes.ts +7 -2
  582. package/src/modules/workflow/workflow.service.ts +886 -112
  583. package/src/modules/workspace/__tests__/agent-downloads.test.ts +823 -0
  584. package/src/modules/workspace/__tests__/escape-sequences.routes.test.ts +4 -3
  585. package/src/modules/workspace/__tests__/first-run.test.ts +234 -0
  586. package/src/modules/workspace/__tests__/git-internals.security.test.ts +5 -2
  587. package/src/modules/workspace/__tests__/md-links.test.ts +353 -0
  588. package/src/modules/workspace/__tests__/move-links.test.ts +261 -0
  589. package/src/modules/workspace/__tests__/rest-tool-arguments.test.ts +219 -0
  590. package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +3 -0
  591. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +102 -0
  592. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +52 -5
  593. package/src/modules/workspace/__tests__/workspace.routes.folder-zip-access.test.ts +190 -0
  594. package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +21 -10
  595. package/src/modules/workspace/__tests__/workspace.service.forget-clone-races.test.ts +8 -4
  596. package/src/modules/workspace/__tests__/workspace.service.test.ts +50 -8
  597. package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +33 -55
  598. package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +44 -1
  599. package/src/modules/workspace/__tests__/workspace.tools.test.ts +664 -34
  600. package/src/modules/workspace/agent-download.builder.ts +308 -0
  601. package/src/modules/workspace/agent-download.routes.ts +183 -0
  602. package/src/modules/workspace/agent-download.store.ts +533 -0
  603. package/src/modules/workspace/agent-upload.store.ts +23 -7
  604. package/src/modules/workspace/file-readers/raw-mime.ts +40 -0
  605. package/src/modules/workspace/file-readers/text-reader.ts +5 -8
  606. package/src/modules/workspace/first-run.ts +222 -0
  607. package/src/modules/workspace/move-links.ts +237 -0
  608. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +191 -489
  609. package/src/modules/workspace/startup/steps/seed-tree.ts +23 -38
  610. package/src/modules/workspace/startup/steps/template-files.step.ts +217 -249
  611. package/src/modules/workspace/startup/steps/template-source.ts +5 -3
  612. package/src/modules/workspace/workspace.routes.ts +64 -22
  613. package/src/modules/workspace/workspace.service.ts +202 -25
  614. package/src/modules/workspace/workspace.tools.ts +707 -68
  615. package/src/modules/write-access/__tests__/write-access.test.ts +13 -0
  616. package/src/modules/write-access/write-access.ts +9 -0
  617. package/src/shared/domain-errors.ts +123 -11
  618. package/src/shared/git.contract.ts +8 -1
  619. package/src/shared/hidden-tools.ts +45 -0
  620. package/src/shared/utf8-text.ts +21 -0
  621. package/src/tenancy/__tests__/static-tenant-source.test.ts +1 -0
  622. package/src/tenancy/static-tenant-source.ts +10 -2
  623. package/starter-packs/README.md +103 -0
  624. package/starter-packs/engineering/KnowledgeBase/About us.md +9 -0
  625. package/starter-packs/engineering/KnowledgeBase/Architecture.md +9 -0
  626. package/starter-packs/engineering/KnowledgeBase/Glossary.md +9 -0
  627. package/starter-packs/engineering/KnowledgeBase/How we ship.md +9 -0
  628. package/starter-packs/engineering/Plugins/engineering-starter/LICENSE +21 -0
  629. package/starter-packs/engineering/Plugins/engineering-starter/SOURCE.md +20 -0
  630. package/starter-packs/engineering/Plugins/engineering-starter/access.md +19 -0
  631. package/starter-packs/engineering/Plugins/engineering-starter/plugin.json +10 -0
  632. package/starter-packs/engineering/Plugins/engineering-starter/skills/office-hours/SKILL.md +171 -0
  633. package/starter-packs/engineering/Plugins/engineering-starter/skills/office-hours/sections/phase-2a-startup-diagnostic.md +157 -0
  634. package/starter-packs/engineering/Plugins/engineering-starter/skills/office-hours/sections/phase-2b-builder-brainstorm.md +39 -0
  635. package/starter-packs/engineering/Plugins/engineering-starter/skills/plan-ceo-review/SKILL.md +144 -0
  636. package/starter-packs/engineering/Plugins/engineering-starter/skills/plan-eng-review/SKILL.md +144 -0
  637. package/starter-packs/engineering/Plugins/engineering-starter/skills/review/SKILL.md +80 -0
  638. package/starter-packs/engineering/Plugins/engineering-starter/skills/review/checklist.md +184 -0
  639. package/starter-packs/engineering/pack.yaml +11 -0
  640. package/starter-packs/general/KnowledgeBase/About us.md +9 -0
  641. package/starter-packs/general/KnowledgeBase/Glossary.md +9 -0
  642. package/starter-packs/general/KnowledgeBase/How we work.md +9 -0
  643. package/starter-packs/general/Plugins/general-starter/LICENSE +202 -0
  644. package/starter-packs/general/Plugins/general-starter/SOURCE.md +10 -0
  645. package/starter-packs/general/Plugins/general-starter/access.md +19 -0
  646. package/starter-packs/general/Plugins/general-starter/plugin.json +10 -0
  647. package/starter-packs/general/Plugins/general-starter/skills/memory-management/SKILL.md +332 -0
  648. package/starter-packs/general/Plugins/general-starter/skills/productivity-start/SKILL.md +163 -0
  649. package/starter-packs/general/Plugins/general-starter/skills/productivity-update/SKILL.md +167 -0
  650. package/starter-packs/general/Plugins/general-starter/skills/task-management/SKILL.md +83 -0
  651. package/starter-packs/general/pack.yaml +10 -0
  652. package/starter-packs/operations/KnowledgeBase/Glossary.md +9 -0
  653. package/starter-packs/operations/KnowledgeBase/How we work.md +9 -0
  654. package/starter-packs/operations/KnowledgeBase/Processes.md +9 -0
  655. package/starter-packs/operations/KnowledgeBase/Tools we use.md +9 -0
  656. package/starter-packs/operations/KnowledgeBase/Vendors.md +9 -0
  657. package/starter-packs/operations/Plugins/operations-starter/LICENSE +202 -0
  658. package/starter-packs/operations/Plugins/operations-starter/SOURCE.md +10 -0
  659. package/starter-packs/operations/Plugins/operations-starter/access.md +19 -0
  660. package/starter-packs/operations/Plugins/operations-starter/plugin.json +10 -0
  661. package/starter-packs/operations/Plugins/operations-starter/skills/capacity-plan/SKILL.md +111 -0
  662. package/starter-packs/operations/Plugins/operations-starter/skills/change-request/SKILL.md +119 -0
  663. package/starter-packs/operations/Plugins/operations-starter/skills/compliance-tracking/SKILL.md +44 -0
  664. package/starter-packs/operations/Plugins/operations-starter/skills/process-doc/SKILL.md +80 -0
  665. package/starter-packs/operations/Plugins/operations-starter/skills/process-optimization/SKILL.md +39 -0
  666. package/starter-packs/operations/Plugins/operations-starter/skills/risk-assessment/SKILL.md +40 -0
  667. package/starter-packs/operations/Plugins/operations-starter/skills/runbook/SKILL.md +85 -0
  668. package/starter-packs/operations/Plugins/operations-starter/skills/status-report/SKILL.md +75 -0
  669. package/starter-packs/operations/Plugins/operations-starter/skills/vendor-review/SKILL.md +102 -0
  670. package/starter-packs/operations/pack.yaml +12 -0
  671. package/starter-packs/sales/KnowledgeBase/About us.md +9 -0
  672. package/starter-packs/sales/KnowledgeBase/Customers.md +9 -0
  673. package/starter-packs/sales/KnowledgeBase/Glossary.md +9 -0
  674. package/starter-packs/sales/KnowledgeBase/How we sell.md +9 -0
  675. package/starter-packs/sales/KnowledgeBase/Objections.md +9 -0
  676. package/starter-packs/sales/KnowledgeBase/Pricing.md +9 -0
  677. package/starter-packs/sales/Plugins/sales-starter/LICENSE +202 -0
  678. package/starter-packs/sales/Plugins/sales-starter/SOURCE.md +10 -0
  679. package/starter-packs/sales/Plugins/sales-starter/access.md +19 -0
  680. package/starter-packs/sales/Plugins/sales-starter/plugin.json +10 -0
  681. package/starter-packs/sales/Plugins/sales-starter/skills/account-context/SKILL.md +94 -0
  682. package/starter-packs/sales/Plugins/sales-starter/skills/account-plan/SKILL.md +95 -0
  683. package/starter-packs/sales/Plugins/sales-starter/skills/account-research/SKILL.md +99 -0
  684. package/starter-packs/sales/Plugins/sales-starter/skills/account-tiering/SKILL.md +101 -0
  685. package/starter-packs/sales/Plugins/sales-starter/skills/call-prep/SKILL.md +111 -0
  686. package/starter-packs/sales/Plugins/sales-starter/skills/call-summary/SKILL.md +111 -0
  687. package/starter-packs/sales/Plugins/sales-starter/skills/close-plan/SKILL.md +106 -0
  688. package/starter-packs/sales/Plugins/sales-starter/skills/competitive-intelligence/SKILL.md +102 -0
  689. package/starter-packs/sales/Plugins/sales-starter/skills/create-an-asset/SKILL.md +105 -0
  690. package/starter-packs/sales/Plugins/sales-starter/skills/crm-hygiene-check/SKILL.md +103 -0
  691. package/starter-packs/sales/Plugins/sales-starter/skills/customer-health/SKILL.md +108 -0
  692. package/starter-packs/sales/Plugins/sales-starter/skills/customer-voice/SKILL.md +94 -0
  693. package/starter-packs/sales/Plugins/sales-starter/skills/daily-briefing/SKILL.md +61 -0
  694. package/starter-packs/sales/Plugins/sales-starter/skills/deal-advance-gap/SKILL.md +102 -0
  695. package/starter-packs/sales/Plugins/sales-starter/skills/deal-review/SKILL.md +105 -0
  696. package/starter-packs/sales/Plugins/sales-starter/skills/deal-signals/SKILL.md +96 -0
  697. package/starter-packs/sales/Plugins/sales-starter/skills/deal-slip-scenario/SKILL.md +104 -0
  698. package/starter-packs/sales/Plugins/sales-starter/skills/draft-outreach/SKILL.md +116 -0
  699. package/starter-packs/sales/Plugins/sales-starter/skills/end-of-day/SKILL.md +114 -0
  700. package/starter-packs/sales/Plugins/sales-starter/skills/expansion-whitespace/SKILL.md +97 -0
  701. package/starter-packs/sales/Plugins/sales-starter/skills/forecast/SKILL.md +100 -0
  702. package/starter-packs/sales/Plugins/sales-starter/skills/handle-objection/SKILL.md +93 -0
  703. package/starter-packs/sales/Plugins/sales-starter/skills/inbox-sweep/SKILL.md +114 -0
  704. package/starter-packs/sales/Plugins/sales-starter/skills/lead-triage/SKILL.md +106 -0
  705. package/starter-packs/sales/Plugins/sales-starter/skills/log-activity/SKILL.md +111 -0
  706. package/starter-packs/sales/Plugins/sales-starter/skills/pipeline-review/SKILL.md +97 -0
  707. package/starter-packs/sales/Plugins/sales-starter/skills/renewal-radar/SKILL.md +95 -0
  708. package/starter-packs/sales/Plugins/sales-starter/skills/rep-context/SKILL.md +90 -0
  709. package/starter-packs/sales/Plugins/sales-starter/skills/route-lead/SKILL.md +111 -0
  710. package/starter-packs/sales/Plugins/sales-starter/skills/sales-setup/SKILL.md +200 -0
  711. package/starter-packs/sales/Plugins/sales-starter/skills/schedule-meeting/SKILL.md +99 -0
  712. package/starter-packs/sales/Plugins/sales-starter/skills/stakeholder-map/SKILL.md +107 -0
  713. package/starter-packs/sales/Plugins/sales-starter/skills/team-pipeline/SKILL.md +105 -0
  714. package/starter-packs/sales/Plugins/sales-starter/skills/update-opportunity/SKILL.md +112 -0
  715. package/starter-packs/sales/Plugins/sales-starter/skills/weekly-wrap/SKILL.md +90 -0
  716. package/starter-packs/sales/Plugins/sales-starter/skills/win-loss-review/SKILL.md +88 -0
  717. package/starter-packs/sales/pack.yaml +13 -0
  718. package/starter-packs/support/KnowledgeBase/Escalations.md +9 -0
  719. package/starter-packs/support/KnowledgeBase/Glossary.md +9 -0
  720. package/starter-packs/support/KnowledgeBase/Known issues.md +9 -0
  721. package/starter-packs/support/KnowledgeBase/Products.md +9 -0
  722. package/starter-packs/support/KnowledgeBase/Tone of voice.md +9 -0
  723. package/starter-packs/support/Plugins/support-starter/LICENSE +202 -0
  724. package/starter-packs/support/Plugins/support-starter/SOURCE.md +10 -0
  725. package/starter-packs/support/Plugins/support-starter/access.md +19 -0
  726. package/starter-packs/support/Plugins/support-starter/plugin.json +10 -0
  727. package/starter-packs/support/Plugins/support-starter/skills/customer-escalation/SKILL.md +246 -0
  728. package/starter-packs/support/Plugins/support-starter/skills/customer-research/SKILL.md +250 -0
  729. package/starter-packs/support/Plugins/support-starter/skills/draft-response/SKILL.md +416 -0
  730. package/starter-packs/support/Plugins/support-starter/skills/kb-article/SKILL.md +350 -0
  731. package/starter-packs/support/Plugins/support-starter/skills/ticket-triage/SKILL.md +273 -0
  732. package/starter-packs/support/pack.yaml +12 -0
  733. package/kb-template/AGENTS.md +0 -730
@@ -103,8 +103,12 @@ export interface ChangeRequestSummary {
103
103
  * does with either is look at where the text came from — so both read `moved`.
104
104
  * `unchanged` is a file the request lists without changing (git reports it on
105
105
  * a mode-only change); `changed` is the honest word for it among these four.
106
+ *
107
+ * Exported because `list_change_request_files` answers `change` under this same
108
+ * name: an agent that opens a request and reads its files back must not be told
109
+ * `moved` by one tool and `renamed` by the other.
106
110
  */
107
- function changeKindOf(status: PrFileStatus | undefined): ChangeKind {
111
+ export function changeKindOf(status: PrFileStatus | undefined): ChangeKind {
108
112
  switch (status) {
109
113
  case 'added':
110
114
  return 'added';
@@ -1,11 +1,10 @@
1
1
  import type { Router, RequestHandler } from 'express';
2
2
  import type { IToolRegistry, JsonSchema } from '../../tool-registry/tool.contract.js';
3
3
  import { ToolError, type ToolContext, type ToolHandler } from '../../tool-helpers/tool.contract.js';
4
- import { toolDef, withBranchInput } from '../../tool-helpers/tool-def.js';
4
+ import { toolDef } from '../../tool-helpers/tool-def.js';
5
5
  import type { ToolHandlerFactory } from '../../tool-helpers/tool-handler.js';
6
6
  import { requireInternalSource } from '../../tool-auth/tool-auth.middleware.js';
7
7
  import type { KbContext } from '../../../shared/kb-context.js';
8
- import { assertBranchProvided } from '../../../shared/domain-errors.js';
9
8
  import { workspaceIdForBranch } from '../../../shared/workspace-id.js';
10
9
  import { assertInsideRepo, normalizePathArgs } from '../../kb-fs/repo-path.js';
11
10
  import { RETIRED_TOOL_MESSAGES } from '@bevel-software/platform-mcp-core';
@@ -171,6 +170,12 @@ export function registerWorkflowTools(
171
170
  toolHandler: ToolHandlerFactory,
172
171
  /** The clone folder at the workspace root (`save_file` refuses a path outside it) and the branch model. */
173
172
  kb: Pick<KbContext, 'kbDirName' | 'defaultBranch' | 'defaultWorkspaceId' | 'protectedBranches'>,
173
+ /**
174
+ * Whether the caller may see change request `number` — `get_change_request`'s
175
+ * own gate (`changeRequestScope(...).maySee`). `delete_branch` neither names
176
+ * nor links a request it answers no for.
177
+ */
178
+ maySeeChangeRequest: (ctx: ToolContext, number: number) => Promise<boolean>,
174
179
  ): void {
175
180
  const { kbDirName } = kb;
176
181
  const mount = (spec: {
@@ -191,21 +196,24 @@ export function registerWorkflowTools(
191
196
  * out of the check while still demanding the input.
192
197
  */
193
198
  skipBranch?: boolean;
199
+ /** Arguments this tool's handler refuses by name itself (see `ToolDefSpec`). */
200
+ refusesItself?: string[];
194
201
  handler: ToolHandler;
195
202
  }): void => {
196
203
  const path = `/api/agent/tools/${spec.name}`;
197
- const inputs = spec.skipBranch ? spec.inputs : withBranchInput(spec.inputs);
198
- // The tool's OWN declaration is the only honest answer to "must this call
199
- // name a branch": the injected input and a hand-declared one (the fork
200
- // base, the draft to switch to) are equally required, and a tool that adds
201
- // or drops the input later moves this with it.
202
- const requiresBranch = ((inputs as { required?: string[] }).required ?? []).includes('branch');
204
+ // Every workflow tool that takes a branch REQUIRES it — the injected input
205
+ // and a hand-declared one (the fork base, the draft to switch to) alike.
206
+ // A hand-declared one is required by its own schema, which `toolDef`
207
+ // reads as `required` too; the tool handler refuses a call without it.
203
208
  const def = toolDef({
204
209
  name: spec.name,
205
210
  description: spec.description,
206
211
  path,
207
- inputs,
212
+ inputs: spec.inputs,
213
+ branch: spec.skipBranch ? undefined : 'required',
214
+ write: spec.write,
208
215
  outputs: spec.outputs,
216
+ refusesItself: spec.refusesItself,
209
217
  tags: spec.write ? ['workflow', 'write'] : ['workflow'],
210
218
  });
211
219
  registry.registerInternalTool(def);
@@ -223,24 +231,12 @@ export function registerWorkflowTools(
223
231
  // workspace path, and a path with no prefix is placed under
224
232
  // `<kbDirName>/` rather than refused.
225
233
  toolHandler(
226
- (args, ctx) => {
227
- // These tools hand `branch` STRAIGHT to `workspaceIdForBranch` —
228
- // they address a workspace by id rather than going through
229
- // `getFilesystem`, so the choke point that guards the file tools
230
- // never sees them. Without this, a branch-less `commit_change`
231
- // commits to a workspace id literally named "undefined", and a
232
- // branch-less `create_branch` forks from one: it clones a branch of
233
- // that name, fails, and answers `There is no branch named undefined.`
234
- //
235
- // Keyed on whether the SCHEMA requires `branch`, not on whether the
236
- // input was injected. `create_branch` and `switch_branch` declare
237
- // their own required `branch`; a check keyed on the injection skipped
238
- // exactly those two, which is how the reported bug survived on
239
- // `create_branch` — the one tool whose `branch` is a branch the
240
- // caller must already have.
241
- if (requiresBranch) assertBranchProvided(args.branch);
242
- return spec.handler(normalizePathArgs(args, kbDirName), ctx);
243
- },
234
+ // These tools hand `branch` STRAIGHT to `workspaceIdForBranch` —
235
+ // they address a workspace by id rather than going through
236
+ // `getFilesystem` — so the branch-less call the tool handler refuses
237
+ // before this runs would otherwise commit to, or fork from, a
238
+ // workspace literally named "undefined".
239
+ (args, ctx) => spec.handler(normalizePathArgs(args, kbDirName), ctx),
244
240
  { write: spec.write },
245
241
  ),
246
242
  );
@@ -383,6 +379,9 @@ export function registerWorkflowTools(
383
379
  // workspace-`branch` injection ("the branch you are currently working on"),
384
380
  // whose wording invites filling in the draft being created instead.
385
381
  skipBranch: true,
382
+ // The handler refuses a missing `name` with a message that says what the
383
+ // name is for (`name-required`); the generic check leaves it to that.
384
+ refusesItself: ['name'],
386
385
  inputs: {
387
386
  type: 'object',
388
387
  properties: {
@@ -528,6 +527,14 @@ export function registerWorkflowTools(
528
527
  });
529
528
  if (!detail) { throw new ToolError(`Change request #${number} not found.`, 404);
530
529
  }
530
+ // A comment anchors to a commit, and a DECLINED request has none to anchor
531
+ // to: nothing durable records what it proposed, so its detail carries no
532
+ // head (see `changeSourceFor`). Say that, rather than letting the service's
533
+ // `head sha is required` surface as a 400 about an argument the caller
534
+ // never passed. An APPLIED request still takes comments — its head is the
535
+ // source tip its merge commit recorded.
536
+ if (!detail.headSha) { throw new ToolError(`Change request #${number} is ${detail.state} and has no commit to anchor a comment to.`, 409);
537
+ }
531
538
  const comment = await ctx.workflowService.postComment(
532
539
  number,
533
540
  ctx.user,
@@ -542,13 +549,16 @@ export function registerWorkflowTools(
542
549
  name: 'merge_branch',
543
550
  description:
544
551
  'Merge branch `source` into branch `target` as you, and publish `target`. An agent proposes and syncs; ' +
545
- 'a person merges: this tool never lands a change request. It refuses when a change request from `source` ' +
546
- 'into `target` is open (naming it) — ask the user to review that request in the app instead. It refuses ' +
552
+ 'a person merges: this tool never lands a change request. It refuses while a change request from `source` ' +
553
+ 'into `target` is open (naming it): ask the user to review it in the app. It refuses ' +
547
554
  'when `target` is a protected branch unless you could commit every changed file directly to it. ' +
548
555
  'SYNC: merging the target into your draft (`source` = the change request\'s target, `target` = your draft) ' +
549
- 'is always allowed, even with that draft\'s request open — use it to bring a draft up to date. ' +
550
- 'Returns `merged` with the merge commit, or `conflicts-need-resolution` with the conflicting paths ' +
551
- '(nothing is written; resolve them on `source` and merge again).',
556
+ 'is always allowed, even with the draft\'s request open. ' +
557
+ 'Writes are committed asynchronously; the merge first waits up to 20s for those on `source`. ' +
558
+ 'Returns `merged` with the merge commit; `nothing-to-merge` with `target`\'s tip when it already holds ' +
559
+ 'all of `source`; `pending-commits` (nothing merged) when writes are still committing — retry shortly — ' +
560
+ 'or one failed (`needsAttention`: tell the user); or `conflicts-need-resolution` with the conflicting ' +
561
+ 'paths (nothing is written; resolve them on `source` and merge again).',
552
562
  // Names both branches itself; the merge runs in `target`'s workspace.
553
563
  skipBranch: true,
554
564
  inputs: {
@@ -565,11 +575,28 @@ export function registerWorkflowTools(
565
575
  properties: {
566
576
  outcome: {
567
577
  type: 'object',
568
- description: 'Either a completed merge or a signal that conflicts must be resolved first.',
578
+ description:
579
+ 'A completed merge, a merge with nothing to do, writes on `source` not committed yet ' +
580
+ '(writes are committed asynchronously and the merge waits up to 20 seconds for them), ' +
581
+ 'or a signal that conflicts must be resolved first.',
569
582
  properties: {
570
- kind: { type: 'string', enum: ['merged', 'conflicts-need-resolution'] },
571
- sha: { type: 'string', description: 'Present when `kind` is `merged` — the tip of `target` after the merge.' },
583
+ kind: { type: 'string', enum: ['merged', 'nothing-to-merge', 'pending-commits', 'conflicts-need-resolution'] },
584
+ sha: {
585
+ type: 'string',
586
+ description:
587
+ 'Present when `kind` is `merged` (the merge commit, now the tip of `target`) or `nothing-to-merge` ' +
588
+ '(the unchanged tip of `target`, which already held everything on `source`).',
589
+ },
572
590
  conflictedPaths: { type: 'array', items: { type: 'string' }, description: 'Present when `kind` is `conflicts-need-resolution`.' },
591
+ branch: { type: 'string', description: 'Present when `kind` is `pending-commits` — the branch whose writes are not committed yet.' },
592
+ pending: { type: 'integer', description: 'Present when `kind` is `pending-commits` — how many commits on that branch are still queued, plus those that failed when `needsAttention` is present.' },
593
+ needsAttention: {
594
+ type: 'string',
595
+ description:
596
+ 'Present when `kind` is `pending-commits` and a queued commit failed: the worker\'s message. ' +
597
+ 'Waiting will not help; tell the user.',
598
+ },
599
+ message: { type: 'string', description: 'Present when `kind` is `pending-commits` — what to do next.' },
573
600
  },
574
601
  required: ['kind'],
575
602
  },
@@ -587,6 +614,81 @@ export function registerWorkflowTools(
587
614
  },
588
615
  });
589
616
 
617
+ mount({
618
+ name: 'delete_branch',
619
+ description:
620
+ 'Delete branch `name` from the shared repository and the server. Allowed for the ' +
621
+ 'branch\'s author (`<email-localpart>/…`, or your own `suggestions/…` bundle) or an Admin. Refuses a ' +
622
+ 'protected branch, a name that is not a branch, a branch with saves still landing or a file held ' +
623
+ '(retry once they land). An open change request from or into it that proposes nothing is closed and the ' +
624
+ 'delete goes ahead; one that still proposes something refuses it, naming and linking it: its author ' +
625
+ 'withdraws it or an Admin declines it, in the app (one you cannot see is not named, nor in a preview). ' +
626
+ 'Refuses a branch holding commits that are not on the ' +
627
+ 'default branch, saying how many; `discardUnmerged: true` deletes it anyway and reports them as ' +
628
+ '`discardedCommits`. Refuses if the shared repository is unreachable. Preview with ' +
629
+ '`dryRun: true`: it changes nothing and answers `exists`, `canDelete`, `refusals`, `unmergedCommits`, ' +
630
+ '`openChangeRequests` and `lastCommit`. A preview grants nothing; checks rerun on delete. ' +
631
+ 'Answers the deleted branch\'s `lastCommit`.',
632
+ // Names its branch itself; the deletion runs in the default branch's workspace.
633
+ skipBranch: true,
634
+ refusesItself: ['name'],
635
+ inputs: {
636
+ type: 'object',
637
+ properties: {
638
+ name: { type: 'string', minLength: 1, description: 'The branch to delete.' },
639
+ dryRun: { type: 'boolean', description: 'Report what deleting would do, and change nothing.' },
640
+ discardUnmerged: {
641
+ type: 'boolean',
642
+ description: 'Delete even though the branch holds commits that are not on the default branch. They are lost.',
643
+ },
644
+ },
645
+ required: ['name'],
646
+ additionalProperties: false,
647
+ },
648
+ outputs: {
649
+ type: 'object',
650
+ properties: {
651
+ kind: { type: 'string', enum: ['preview', 'deleted'] },
652
+ branch: { type: 'string' },
653
+ lastCommit: { type: ['string', 'null'], description: 'The branch\'s tip — what a restore starts from. Null in a preview of a branch that does not exist.' },
654
+ discardedCommits: { type: 'integer', description: 'When `kind` is `deleted`: commits not on the default branch that went with it.' },
655
+ exists: { type: 'boolean', description: 'When `kind` is `preview`.' },
656
+ canDelete: { type: 'boolean', description: 'When `kind` is `preview`: whether a delete asked for now would go through.' },
657
+ refusals: { type: 'array', items: { type: 'string' }, description: 'When `kind` is `preview`: why it would not.' },
658
+ unmergedCommits: { type: 'integer', description: 'When `kind` is `preview`: commits not on the default branch.' },
659
+ openChangeRequests: {
660
+ type: 'array',
661
+ description: 'When `kind` is `preview`: open change requests from (`source`) or into (`target`) the branch that you can see.',
662
+ items: {
663
+ type: 'object',
664
+ properties: {
665
+ number: { type: 'integer' },
666
+ end: { type: 'string', enum: ['source', 'target'] },
667
+ url: { type: 'string', description: 'Link to the request in the app.' },
668
+ proposesNothing: { type: 'boolean', description: 'True when the delete would close it rather than be refused by it.' },
669
+ },
670
+ required: ['number', 'end', 'url', 'proposesNothing'],
671
+ },
672
+ },
673
+ },
674
+ required: ['kind', 'branch', 'lastCommit'],
675
+ },
676
+ write: true,
677
+ handler: async (args, ctx: ToolContext) => {
678
+ const name = args.name;
679
+ if (typeof name !== 'string' || name.length === 0) {
680
+ throw new ToolError('`name` is required: pass the name of the branch to delete.', 400, {
681
+ kind: 'name-required',
682
+ });
683
+ }
684
+ return ctx.workflowService.deleteBranchChecked(ctx.user, name, {
685
+ dryRun: args.dryRun === true,
686
+ discardUnmerged: args.discardUnmerged === true,
687
+ maySee: (number) => maySeeChangeRequest(ctx, number),
688
+ });
689
+ },
690
+ });
691
+
590
692
  // `merge_change_request` is retired: a change request is merged by a person
591
693
  // in the app. It is in no catalog, but a caller holding an old manual still
592
694
  // posts to its path — answer with who merges now, not a bare 404.
@@ -69,17 +69,52 @@ function rowToFileLock(row: typeof fileLocks.$inferSelect): FileLock {
69
69
  export class FileLockService {
70
70
  constructor(private readonly db: Database) {}
71
71
 
72
+ /**
73
+ * Branches being deleted right now, with how many deletions hold each. No
74
+ * lock is granted on them: a deletion checks that no save is landing and
75
+ * then removes the branch, and a save that took its lock in between would
76
+ * be lost with the checkout. See `whileNoneAcquired`.
77
+ */
78
+ private readonly closing = new Map<string, number>();
79
+
80
+ /**
81
+ * Acquires on each branch that passed the `closing` check and have not
82
+ * settled yet. `whileNoneAcquired` waits for them: one whose row is still
83
+ * being written when a deletion starts would otherwise land after the
84
+ * deletion's last check.
85
+ */
86
+ private readonly acquiring = new Map<string, Set<Promise<unknown>>>();
87
+
88
+ /**
89
+ * Run `fn` while no lock can be acquired on `branch`, once every acquire
90
+ * already under way on it has settled. The deletion paths re-check for
91
+ * saves landing inside it, so that check sees every lock granted before it,
92
+ * and the deletion meets no save that started in between.
93
+ */
94
+ async whileNoneAcquired<T>(branch: string, fn: () => Promise<T>): Promise<T> {
95
+ this.closing.set(branch, (this.closing.get(branch) ?? 0) + 1);
96
+ try {
97
+ await Promise.allSettled([...(this.acquiring.get(branch) ?? [])]);
98
+ return await fn();
99
+ } finally {
100
+ const n = (this.closing.get(branch) ?? 1) - 1;
101
+ if (n > 0) this.closing.set(branch, n);
102
+ else this.closing.delete(branch);
103
+ }
104
+ }
105
+
72
106
  /**
73
107
  * Acquire a lock for `(workspaceId, branch, path)` on behalf of `user`.
74
108
  *
75
109
  * Three outcomes folded into the same return shape:
76
110
  * - No existing row: insert + return `{ acquired: true, lock }`.
77
111
  * - Existing row, expired: take it over (update) + `{ acquired: true }`.
78
- * - Existing row, live, different user: return `{ acquired: false }`
79
- * with the current holder's lock state so the UI can render
80
- * "Locked by X" without a follow-up call.
81
- * - Existing row, live, same user: refresh TTL + `{ acquired: true }`
82
- * so re-acquiring your own lock is idempotent.
112
+ * - Existing row, live — ANY user, the holder included: return
113
+ * `{ acquired: false }` with the current holder's lock state so the UI
114
+ * can render "Locked by X" without a follow-up call. Re-acquiring your
115
+ * own live lock is refused on purpose (see the comment in the body):
116
+ * refresh a held lock with `heartbeat()`, and ask "do I already hold
117
+ * it?" with `get()`.
83
118
  *
84
119
  * `opts.coordination` stamps the row's `mode` as `'coordination'` — a
85
120
  * pure-mutex hold that grants no write authority (see
@@ -97,6 +132,33 @@ export class FileLockService {
97
132
  opts?: { coordination?: boolean },
98
133
  ): Promise<AcquireLockResult> {
99
134
  const targetPath = canonicalFileIdentity(rawPath);
135
+ if (this.closing.has(branch)) {
136
+ throw new WorkflowValidationError(`"${branch}" is being deleted, so "${targetPath}" cannot be held for editing.`, {
137
+ kind: 'branch-being-deleted',
138
+ branch,
139
+ path: targetPath,
140
+ });
141
+ }
142
+ const pending = this.acquireUnchecked(workspaceId, branch, targetPath, user, opts);
143
+ const inFlight = this.acquiring.get(branch) ?? new Set<Promise<unknown>>();
144
+ inFlight.add(pending);
145
+ this.acquiring.set(branch, inFlight);
146
+ try {
147
+ return await pending;
148
+ } finally {
149
+ inFlight.delete(pending);
150
+ if (inFlight.size === 0 && this.acquiring.get(branch) === inFlight) this.acquiring.delete(branch);
151
+ }
152
+ }
153
+
154
+ /** `acquire` past the deletion gate. */
155
+ private async acquireUnchecked(
156
+ workspaceId: string,
157
+ branch: string,
158
+ targetPath: string,
159
+ user: AuthUser,
160
+ opts?: { coordination?: boolean },
161
+ ): Promise<AcquireLockResult> {
100
162
  const now = new Date();
101
163
  const expiresAt = new Date(now.getTime() + LOCK_TTL_MS);
102
164
 
@@ -0,0 +1,285 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import os from 'node:os';
5
+ import { testKbContext } from '../../../../__tests__/kb-context.js';
6
+ import { WorkflowHooks } from '../../workflow-hooks.js';
7
+ import { GitService } from '../git.service.js';
8
+ import { WorkflowValidationError } from '../../../../shared/domain-errors.js';
9
+ import { mergeCommitSubject } from '../merge-commit.js';
10
+ import { runGit, gitOut, stubWorkspaceService } from './git-test-helpers.js';
11
+
12
+ /**
13
+ * Reading an APPLIED change request back from its merge commit — the three
14
+ * methods behind Razvan's 2026-10-02 decision, against a real git.
15
+ *
16
+ * Why they exist at all: merging a change request retires its source branch, so
17
+ * the branch pair every other diff method takes no longer resolves. Before this,
18
+ * a merged request answered no files — and since an empty file set proves no read
19
+ * access, that left every applied request readable by its author alone. The merge
20
+ * commit is what is left of the change, it is local, and it cannot move.
21
+ *
22
+ * The fixture is the merge `mergeChangeRequest` makes: `--no-ff`, on the target,
23
+ * so the commit has the target as its first parent and the source tip as its
24
+ * second.
25
+ */
26
+ describe('GitService reading an applied change from its merge commit', () => {
27
+ const workspaceId = 'ws-applied';
28
+ /** The change request the fixture's merge commit belongs to. */
29
+ const CR = 42;
30
+ let root: string;
31
+ let repo: string;
32
+ let git: GitService;
33
+
34
+ /** One clone with a merge commit on `main`, and the shas that went into it. */
35
+ async function seedMerged(): Promise<{
36
+ mergeSha: string;
37
+ targetBefore: string;
38
+ sourceTip: string;
39
+ }> {
40
+ repo = path.join(root, workspaceId, 'knowledge-base');
41
+ await fs.mkdir(repo, { recursive: true });
42
+ await runGit(path.dirname(repo), ['init', '-b', 'main', 'knowledge-base']);
43
+ await runGit(repo, ['config', 'user.email', 'test@bevel.local']);
44
+ await runGit(repo, ['config', 'user.name', 'Test Runner']);
45
+
46
+ await fs.writeFile(path.join(repo, 'base.md'), 'base\n');
47
+ await fs.mkdir(path.join(repo, 'Payroll'), { recursive: true });
48
+ await fs.writeFile(path.join(repo, 'Payroll', 'Rates.md'), 'bands\n');
49
+ await runGit(repo, ['add', '-A']);
50
+ await runGit(repo, ['commit', '-m', 'init']);
51
+
52
+ // The proposal: an add, an edit, a delete and a move out of Payroll.
53
+ await runGit(repo, ['checkout', '-b', 'juan/proposal']);
54
+ await fs.writeFile(path.join(repo, 'Added.md'), 'new\n');
55
+ await fs.writeFile(path.join(repo, 'base.md'), 'base\nmore\n');
56
+ await fs.mkdir(path.join(repo, 'Knowledge'), { recursive: true });
57
+ await fs.rename(path.join(repo, 'Payroll', 'Rates.md'), path.join(repo, 'Knowledge', 'Open.md'));
58
+ await runGit(repo, ['add', '-A']);
59
+ await runGit(repo, ['commit', '-m', 'the proposal']);
60
+ const sourceTip = await gitOut(repo, ['rev-parse', 'HEAD']);
61
+
62
+ // The target moves on while the proposal waits, so a three-dot read of the
63
+ // merge commit would report this commit's file too — and must not.
64
+ await runGit(repo, ['checkout', 'main']);
65
+ await fs.writeFile(path.join(repo, 'OnTarget.md'), 'meanwhile\n');
66
+ await runGit(repo, ['add', '-A']);
67
+ await runGit(repo, ['commit', '-m', 'unrelated work on the target']);
68
+ const targetBefore = await gitOut(repo, ['rev-parse', 'HEAD']);
69
+
70
+ // The subject `mergePr` writes — the reader verifies it, so the fixture must
71
+ // produce it the same way rather than spelling it out.
72
+ await runGit(repo, [
73
+ 'merge', '--no-ff', '-m', mergeCommitSubject('Rework the onboarding note', CR), 'juan/proposal',
74
+ ]);
75
+ const mergeSha = await gitOut(repo, ['rev-parse', 'HEAD']);
76
+ // Applied: the source branch goes, as `mergeChangeRequest` retires it.
77
+ await runGit(repo, ['branch', '-D', 'juan/proposal']);
78
+
79
+ git = new GitService(
80
+ stubWorkspaceService({ [workspaceId]: path.dirname(repo) }),
81
+ new WorkflowHooks(),
82
+ testKbContext(),
83
+ );
84
+ return { mergeSha, targetBefore, sourceTip };
85
+ }
86
+
87
+ /** The row's pointer at its merge commit: the sha AND the number that proves it. */
88
+ const ref = (mergeSha: string, number = CR) => ({ number, mergeSha });
89
+
90
+ beforeEach(async () => {
91
+ root = await fs.mkdtemp(path.join(os.tmpdir(), 'bevel-applied-'));
92
+ });
93
+ afterEach(async () => {
94
+ await fs.rm(root, { recursive: true, force: true }).catch(() => {});
95
+ });
96
+
97
+ it('answers the files the request applied, with their statuses and counts', async () => {
98
+ const { mergeSha } = await seedMerged();
99
+ const files = await git.changedFilesOfAppliedChange(workspaceId, ref(mergeSha));
100
+ const byPath = Object.fromEntries(files.map((f) => [f.path, f]));
101
+ expect(Object.keys(byPath).sort()).toEqual(['Added.md', 'Knowledge/Open.md', 'base.md']);
102
+ expect(byPath['Added.md'].status).toBe('added');
103
+ expect(byPath['base.md'].status).toBe('modified');
104
+ expect(byPath['base.md'].additions).toBe(1);
105
+ // The move is reported as one file with both of its names — which is what
106
+ // the read gate needs to judge it on the folder it LEFT as well.
107
+ expect(byPath['Knowledge/Open.md'].status).toBe('renamed');
108
+ expect(byPath['Knowledge/Open.md'].previousPath).toBe('Payroll/Rates.md');
109
+ });
110
+
111
+ // The reason the range is two-dot from the FIRST parent. A three-dot diff
112
+ // would be read from the merge base of the two parents, so it would re-report
113
+ // everything that landed on the target while the proposal waited.
114
+ it('reports nothing the target did on its own while the request waited', async () => {
115
+ const { mergeSha } = await seedMerged();
116
+ const files = await git.changedFilesOfAppliedChange(workspaceId, ref(mergeSha));
117
+ expect(files.map((f) => f.path)).not.toContain('OnTarget.md');
118
+ });
119
+
120
+ it('generates the patches, and skips them entirely at patchCap 0', async () => {
121
+ const { mergeSha } = await seedMerged();
122
+ const withPatches = await git.changedFilesOfAppliedChange(workspaceId, ref(mergeSha));
123
+ expect(withPatches.find((f) => f.path === 'base.md')?.patch).toContain('+more');
124
+ const without = await git.changedFilesOfAppliedChange(workspaceId, ref(mergeSha), { patchCap: 0 });
125
+ expect(without.every((f) => f.patch === undefined)).toBe(true);
126
+ });
127
+
128
+ it('answers the same change as the two path views a summary needs', async () => {
129
+ const { mergeSha } = await seedMerged();
130
+ const { paths, pairs } = await git.changedPathsAndPairsOfAppliedChange(workspaceId, ref(mergeSha));
131
+ // The flat list offers both sides of the move for an access lookup; the pairs
132
+ // say which old name belongs to which file. The file list above and these
133
+ // pairs must agree, or the list of requests and the detail of one would
134
+ // disagree about what is readable.
135
+ expect(paths.sort()).toEqual(['Added.md', 'Knowledge/Open.md', 'base.md']);
136
+ expect(pairs).toEqual(
137
+ expect.arrayContaining([
138
+ { path: 'Knowledge/Open.md', previousPath: 'Payroll/Rates.md' },
139
+ { path: 'Added.md' },
140
+ { path: 'base.md' },
141
+ ]),
142
+ );
143
+ const files = await git.changedFilesOfAppliedChange(workspaceId, ref(mergeSha), { patchCap: 0 });
144
+ expect(pairs.map((p) => p.path).sort()).toEqual(files.map((f) => f.path).sort());
145
+ });
146
+
147
+ it("answers the merge commit's two parents as the request's base and head", async () => {
148
+ const { mergeSha, targetBefore, sourceTip } = await seedMerged();
149
+ expect(await git.appliedChangeShas(workspaceId, ref(mergeSha))).toEqual({
150
+ baseSha: targetBefore,
151
+ headSha: sourceTip,
152
+ });
153
+ });
154
+
155
+ // cubic P1 on #347, and the case that makes the whole verification necessary.
156
+ // When the target already contains the source there is nothing to merge, so the
157
+ // merge writes NO commit and reports the target tip. A row that recorded that
158
+ // tip points at an ordinary commit — whatever landed on the target last — and
159
+ // reading its own change would answer with THAT change's files under this
160
+ // request's number. Refused, so the request falls back to author-only.
161
+ it('refuses a commit with no second parent, which no merge of this request wrote', async () => {
162
+ await seedMerged();
163
+ await fs.writeFile(path.join(repo, 'SomebodyElse.md'), 'unrelated work\n');
164
+ await runGit(repo, ['add', '-A']);
165
+ await runGit(repo, ['commit', '-m', 'unrelated work on the target']);
166
+ const tip = await gitOut(repo, ['rev-parse', 'HEAD']);
167
+ for (const call of [
168
+ () => git.appliedChangeShas(workspaceId, ref(tip)),
169
+ () => git.changedFilesOfAppliedChange(workspaceId, ref(tip)),
170
+ () => git.changedPathsAndPairsOfAppliedChange(workspaceId, ref(tip)),
171
+ ]) {
172
+ await expect(call()).rejects.toThrow(/is not a merge commit/);
173
+ }
174
+ });
175
+
176
+ it('tells a commit the clone does not hold apart from one that is not a merge: the first may arrive, the second never will', async () => {
177
+ await seedMerged();
178
+ const unknown = 'f'.repeat(40);
179
+ await expect(git.appliedChangeShas(workspaceId, ref(unknown))).rejects.toThrow(/is not in this clone/);
180
+ await expect(git.appliedChangeShas(workspaceId, ref(unknown))).rejects.not.toThrow(/is not a merge commit/);
181
+ });
182
+
183
+ // The residual of the same P1, and the reason the NUMBER travels with the sha.
184
+ // An empty request merged while the target tip was ANOTHER request's merge
185
+ // commit recorded a sha that is a merge commit — just not this request's. Two
186
+ // parents alone would accept it and publish the other request's files.
187
+ it('refuses a merge commit whose subject names a different request', async () => {
188
+ const { mergeSha } = await seedMerged();
189
+ for (const call of [
190
+ () => git.appliedChangeShas(workspaceId, ref(mergeSha, CR + 1)),
191
+ () => git.changedFilesOfAppliedChange(workspaceId, ref(mergeSha, CR + 1)),
192
+ () => git.changedPathsAndPairsOfAppliedChange(workspaceId, ref(mergeSha, CR + 1)),
193
+ ]) {
194
+ await expect(call()).rejects.toThrow(/is not the merge commit of change request #43/);
195
+ }
196
+ // The same commit under its OWN number still reads, so what guards is the
197
+ // number and not a blanket refusal.
198
+ expect(
199
+ (await git.changedFilesOfAppliedChange(workspaceId, ref(mergeSha), { patchCap: 0 })).length,
200
+ ).toBe(3);
201
+ });
202
+
203
+ // The number is matched at the END of the subject, where `mergeCommitSubject`
204
+ // puts it, so a title that happens to contain another request's number is not
205
+ // mistaken for that request's merge commit.
206
+ it('matches the number at the end, not anywhere in the title', async () => {
207
+ await seedMerged();
208
+ await runGit(repo, ['checkout', '-b', 'juan/third']);
209
+ await fs.writeFile(path.join(repo, 'Third.md'), 'x\n');
210
+ await runGit(repo, ['add', '-A']);
211
+ await runGit(repo, ['commit', '-m', 'third']);
212
+ await runGit(repo, ['checkout', 'main']);
213
+ await runGit(repo, [
214
+ 'merge', '--no-ff', '-m', mergeCommitSubject('Follow-up to (#99)', 7), 'juan/third',
215
+ ]);
216
+ const sha = await gitOut(repo, ['rev-parse', 'HEAD']);
217
+ await expect(git.appliedChangeShas(workspaceId, ref(sha, 99))).rejects.toThrow(
218
+ /is not the merge commit of change request #99/,
219
+ );
220
+ expect(await git.appliedChangeShas(workspaceId, ref(sha, 7))).toMatchObject({
221
+ baseSha: expect.any(String),
222
+ });
223
+ });
224
+
225
+ // Fail-closed, and this is the case it protects: a clone that has not fetched
226
+ // the merge yet must answer no files, never somebody else's. Every caller reads
227
+ // the rejection as "the file set could not be resolved" and leaves the request
228
+ // to its author.
229
+ it('refuses a commit this clone does not hold, rather than reaching for it', async () => {
230
+ await seedMerged();
231
+ const absent = 'f'.repeat(40);
232
+ for (const call of [
233
+ () => git.changedFilesOfAppliedChange(workspaceId, ref(absent)),
234
+ () => git.changedPathsAndPairsOfAppliedChange(workspaceId, ref(absent)),
235
+ () => git.appliedChangeShas(workspaceId, ref(absent)),
236
+ ]) {
237
+ await expect(call()).rejects.toThrow(WorkflowValidationError);
238
+ }
239
+ });
240
+
241
+ it('refuses anything that is not a sha, so no ref name can be smuggled in', async () => {
242
+ await seedMerged();
243
+ for (const bad of ['main', 'HEAD', '', 'main; rm -rf /', '../../etc/passwd', 'abc']) {
244
+ await expect(
245
+ git.changedFilesOfAppliedChange(workspaceId, ref(bad)),
246
+ ).rejects.toThrow(/invalid commit sha/);
247
+ }
248
+ });
249
+
250
+ it('refuses a root commit, which has no parent to read the change against', async () => {
251
+ await seedMerged();
252
+ const rootCommit = await gitOut(repo, ['rev-list', '--max-parents=0', 'HEAD']);
253
+ await expect(
254
+ git.changedFilesOfAppliedChange(workspaceId, ref(rootCommit)),
255
+ ).rejects.toThrow(/is not a merge commit/);
256
+ });
257
+
258
+ it('filters roles.yaml and the folder placeholder, as the branch-pair diff does', async () => {
259
+ await seedMerged();
260
+ // A request that touches roles.yaml and creates an empty folder: neither is
261
+ // content to review, and a merged request must not start listing them when an
262
+ // open one does not.
263
+ await runGit(repo, ['checkout', '-b', 'juan/second']);
264
+ await fs.writeFile(path.join(repo, 'roles.yaml'), 'Admin: [a@b.c]\n');
265
+ await fs.mkdir(path.join(repo, 'Empty'), { recursive: true });
266
+ await fs.writeFile(path.join(repo, 'Empty', '.gitkeep'), '');
267
+ await fs.writeFile(path.join(repo, 'Real.md'), 'content\n');
268
+ await runGit(repo, ['add', '-A']);
269
+ await runGit(repo, ['commit', '-m', 'second proposal']);
270
+ await runGit(repo, ['checkout', 'main']);
271
+ await runGit(repo, [
272
+ 'merge', '--no-ff', '-m', mergeCommitSubject('The second proposal', 43), 'juan/second',
273
+ ]);
274
+ const sha = await gitOut(repo, ['rev-parse', 'HEAD']);
275
+
276
+ const files = await git.changedFilesOfAppliedChange(workspaceId, ref(sha, 43), { patchCap: 0 });
277
+ expect(files.map((f) => f.path)).toEqual(['Real.md']);
278
+ // The paths view keeps the placeholder (a folder-only request must still
279
+ // reach the folder's owners) and drops roles.yaml, exactly as the
280
+ // branch-pair diff does.
281
+ const { paths, pairs } = await git.changedPathsAndPairsOfAppliedChange(workspaceId, ref(sha, 43));
282
+ expect(paths.sort()).toEqual(['Empty/.gitkeep', 'Real.md']);
283
+ expect(pairs.map((p) => p.path)).toEqual(['Real.md']);
284
+ });
285
+ });