@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
@@ -1,8 +1,10 @@
1
- import { desc, eq } from 'drizzle-orm';
1
+ import { desc, eq, inArray } from 'drizzle-orm';
2
2
  import { logger } from '../../../shared/logging.js';
3
3
 
4
4
  const log = logger('cr');
5
5
  import type {
6
+ AppliedChangeRef,
7
+ ChangedPathPair,
6
8
  FileApprovalState,
7
9
  IPullRequestService,
8
10
  PrReviewComment,
@@ -18,15 +20,127 @@ import { changeRequests } from '../../database/schema.js';
18
20
  import type { WorkspaceService } from '../../workspace/workspace.service.js';
19
21
  import type { IAccessControl } from '../../access/access-control.interface.js';
20
22
  import { AccessUnreadableError } from '../../access-model/access-errors.js';
21
- import { WorkflowValidationError } from '../../../shared/domain-errors.js';
23
+ import { AppliedChangeMismatchError, WorkflowValidationError } from '../../../shared/domain-errors.js';
22
24
  import { canonicalEmail, hashEmail } from '../../../shared/email-identity.js';
23
25
  import { changeRequestLink, changeRequestLinkBase } from './change-request-link.js';
24
26
 
27
+ /**
28
+ * The latest moment a change-request row records — its close time when it has
29
+ * one, else its creation time, with `updated_at` folded in for the day
30
+ * something writes it. Deliberately derived from the ROW alone: a time taken
31
+ * from the newest comment or approval would make the same request report
32
+ * different "last changed" moments to a list (which reads no comments) and a
33
+ * detail (which does).
34
+ */
35
+ function latestRowMoment(row: {
36
+ createdAt: Date;
37
+ updatedAt: Date | null;
38
+ closedAt: Date | null;
39
+ }): string {
40
+ const times = [row.createdAt, row.updatedAt, row.closedAt]
41
+ .filter((d): d is Date => d instanceof Date)
42
+ .map((d) => d.getTime());
43
+ return new Date(Math.max(...times)).toISOString();
44
+ }
45
+
25
46
  const LIST_PR_CACHE_TTL_MS = 30_000;
47
+ /**
48
+ * How many applied requests' file lists are remembered at once. Each is a
49
+ * short path list, so this is about a deployment that applies requests for
50
+ * years never growing the map without bound. Past it, what is remembered
51
+ * stays and new answers are not kept — see `touchedPathsFor` for why nothing
52
+ * is evicted.
53
+ */
54
+ const MAX_REMEMBERED_APPLIED_CHANGES = 20_000;
55
+ /** How many mismatched applied rows to remember — see `touchedPathsFor`. */
56
+ const MAX_MISMATCHED_APPLIED_CHANGES = 5_000;
57
+ /** How many rows a listing reads from git at once. */
58
+ const SUMMARY_CONCURRENCY = 8;
59
+
60
+ /** `fn` over `items`, at most `limit` in flight, results in order. */
61
+ async function mapWithLimit<T, R>(items: readonly T[], limit: number, fn: (item: T) => Promise<R>): Promise<R[]> {
62
+ const results: R[] = new Array(items.length);
63
+ let next = 0;
64
+ const worker = async (): Promise<void> => {
65
+ while (next < items.length) {
66
+ const index = next;
67
+ next += 1;
68
+ results[index] = await fn(items[index]!);
69
+ }
70
+ };
71
+ await Promise.all(Array.from({ length: Math.min(limit, items.length) }, () => worker()));
72
+ return results;
73
+ }
26
74
  const DETAIL_CACHE_TTL_MS = 30_000;
27
75
 
28
76
  type ChangeRequestRow = typeof changeRequests.$inferSelect;
29
77
 
78
+ /**
79
+ * Where a change request's files are read from.
80
+ *
81
+ * - `branches` — the source/target pair, as a live proposal is read.
82
+ * - `commit` — the merge commit the row records, as an applied one is.
83
+ * - `none` — nothing: there is no durable record of what this request
84
+ * proposed, so it has no file list to show.
85
+ */
86
+ export type ChangeSource =
87
+ | { kind: 'branches' }
88
+ | { kind: 'commit'; applied: AppliedChangeRef }
89
+ | { kind: 'none' };
90
+
91
+ /**
92
+ * Which diff a change-request row is read from — asked ONCE, here, by both the
93
+ * list (`touchedPathsFor`) and the by-number detail (`getPrDetail`). The two
94
+ * surfaces answered this question separately before, and so answered it
95
+ * differently: the list gave a declined request no paths while the detail
96
+ * resolved its branch pair, which left `list_change_requests` and the four
97
+ * by-number tools contradicting each other about the same request for the same
98
+ * caller. One function, one answer.
99
+ *
100
+ * An OPEN request is its two branch tips, which is what a proposal IS.
101
+ *
102
+ * An APPLIED one is the merge commit its row records: the branch is retired, and
103
+ * the commit is local, immutable, and holds exactly what landed.
104
+ *
105
+ * A DECLINED one is read from NOTHING, and that is not a degradation:
106
+ *
107
+ * - The row records no sha, so nothing durable says what the request
108
+ * proposed. Declining retires the source branch as merging does
109
+ * (`deleteChangeRequest` ends in `retireMergedSourceBranch`) — unless
110
+ * another open request still needs that branch, which keeps it alive and
111
+ * moving. Where the branch pair still resolves it would answer with what
112
+ * that branch differs by NOW, work committed since for the request that
113
+ * kept it included; reading the declined request would then present later
114
+ * work as the proposal that was turned down.
115
+ * - An empty file set proves no read access downstream, so a declined request
116
+ * is readable by its author alone — the owner's criterion of 2026-10-02.
117
+ * - And it asks git nothing, so neither a listing nor a by-number read of a
118
+ * declined request costs a network round trip.
119
+ *
120
+ * A merged row that records no merge commit (or whose commit this clone has not
121
+ * fetched) lands on `none` too, and fails closed the same way until it can be
122
+ * read in full.
123
+ */
124
+ export function changeSourceFor(row: {
125
+ number: number;
126
+ state: string;
127
+ /** The stored title, handed along so a merge commit in the old message format is still recognised. */
128
+ title?: string;
129
+ mergedSha?: string | null;
130
+ }): ChangeSource {
131
+ if (row.state === 'open') return { kind: 'branches' };
132
+ // The NUMBER travels with the sha, because reading the commit's own change is
133
+ // only sound if the commit is this request's merge commit — and the number is
134
+ // what proves it (the subject ends with `(#<number>)`). A row whose
135
+ // `merged_sha` was written by a merge that made no commit points at the target
136
+ // tip, which is usually another request's merge commit; the git layer rejects
137
+ // that rather than answering with its files. See `merge-commit.ts`.
138
+ if (row.state === 'merged' && row.mergedSha) {
139
+ return { kind: 'commit', applied: { number: row.number, mergeSha: row.mergedSha, title: row.title } };
140
+ }
141
+ return { kind: 'none' };
142
+ }
143
+
30
144
  /**
31
145
  * The slice of the review-workflow service this module needs to compose detail
32
146
  * responses. Kept narrow (just what `getPrDetail` stitches in) so the PR
@@ -90,6 +204,14 @@ export class PullRequestService implements IPullRequestService {
90
204
  * list cache stores, so it lives and dies with them.
91
205
  */
92
206
  private routingPaths = new WeakMap<PullRequestSummary, string[]>();
207
+ /**
208
+ * The files an APPLIED request landed, per clone and merge commit. A merge
209
+ * commit is immutable, so its answer is good for the life of the process;
210
+ * nothing invalidates this, and nothing needs to. See {@link touchedPathsFor}.
211
+ */
212
+ private readonly appliedChanges = new Map<string, { paths: string[]; pairs: ChangedPathPair[] }>();
213
+ /** Applied rows whose recorded commit is not their own, by the same key — never asked again. */
214
+ private readonly mismatchedAppliedChanges = new Set<string>();
93
215
  /**
94
216
  * Per-CR detail cache, keyed by `${workspaceId ?? 'global'}:${viewer}:${number}`.
95
217
  * The payload includes per-file approvals resolved against the caller's
@@ -145,7 +267,11 @@ export class PullRequestService implements IPullRequestService {
145
267
  return this.workspaceService.findAnyWorkspaceId();
146
268
  }
147
269
 
148
- private rowToSummary(row: ChangeRequestRow, touchedNodePaths: string[]): PullRequestSummary {
270
+ private rowToSummary(
271
+ row: ChangeRequestRow,
272
+ touchedNodePaths: string[],
273
+ touchedNodeFiles: ChangedPathPair[],
274
+ ): PullRequestSummary {
149
275
  return {
150
276
  number: row.number,
151
277
  title: row.title,
@@ -160,7 +286,14 @@ export class PullRequestService implements IPullRequestService {
160
286
  base: row.targetBranch,
161
287
  state: row.state as PullRequestState,
162
288
  createdAt: row.createdAt.toISOString(),
289
+ // The latest moment the ROW records. Nothing stamps `updated_at` on a
290
+ // change request today, so in practice this is the close time of a
291
+ // closed request and the creation time of an open one — the honest
292
+ // answer from the row, with the column folded in for the day something
293
+ // does write it.
294
+ updatedAt: latestRowMoment(row),
163
295
  touchedNodePaths,
296
+ touchedNodeFiles,
164
297
  // Provider reviews are gone; the real approval state lives in the detail
165
298
  // view (per-file, DB-backed). The summary badge is derived there.
166
299
  review: { approvals: 0, changesRequested: 0, pendingLogins: [] },
@@ -183,25 +316,86 @@ export class PullRequestService implements IPullRequestService {
183
316
  /**
184
317
  * Cheap touched-paths for a CR row (empty when no workspace exists yet),
185
318
  * placeholders included — see {@link summaryOf} for what a summary shows.
319
+ *
320
+ * WHICH DIFF is {@link changeSourceFor}'s answer — the same one `getPrDetail`
321
+ * takes, so a list and a by-number read never disagree about which files a
322
+ * request has. No state reaches the network per request: an open row is
323
+ * diffed from two branch tips a single whole-clone refresh has already brought
324
+ * up to date (`fetch: false`), an applied one from a local immutable commit,
325
+ * and a declined one from nothing at all.
326
+ *
327
+ * The merge commit also undid the flood finding 1 of Razvan's review named:
328
+ * `publishedPrCommits` answers null for a retired branch, which sent
329
+ * `changedPathsAndPairsForPr` to `fetch` two refs — one of them gone — once PER
330
+ * REQUEST and then logged a warning for each, so a list of a few hundred
331
+ * applied requests opened a few hundred concurrent fetches to answer nothing.
186
332
  */
187
333
  private async touchedPathsFor(
188
334
  row: ChangeRequestRow,
189
335
  workspaceId: string | null,
190
336
  opts: { fetch?: boolean } = {},
191
- ): Promise<string[]> {
192
- if (!workspaceId) return [];
337
+ ): Promise<{ paths: string[]; pairs: ChangedPathPair[] }> {
338
+ const empty = { paths: [] as string[], pairs: [] as ChangedPathPair[] };
339
+ if (!workspaceId) return empty;
340
+ // Best-effort, but logged: an empty result silently hides a CR from the
341
+ // owner-routing match in `listPrsForOwnerEmail`, so a swallowed failure
342
+ // shouldn't be invisible.
343
+ const degrade = (what: string) => (err: unknown) => {
344
+ const where = `#${row.number} (${row.sourceBranch} → ${row.targetBranch}) in ${workspaceId}`;
345
+ // A clone that simply does not hold the merge commit yet is not a failure
346
+ // to shout about — it is this row's turn to be fetched, and the next list
347
+ // read answers it. Warning per request on that would be the log flood the
348
+ // network flood came with.
349
+ if (err instanceof WorkflowValidationError) {
350
+ log.debug(`${what} could not resolve ${where}; answering no touched paths:`, { err });
351
+ } else {
352
+ log.warn(`${what} failed for ${where}:`, { err });
353
+ }
354
+ return empty;
355
+ };
356
+ const source = changeSourceFor(row);
357
+ if (source.kind === 'none') return empty;
358
+ if (source.kind === 'commit') {
359
+ // Remembered once read: a merge commit never changes, so neither does
360
+ // its diff, and a list of a few hundred applied requests would otherwise
361
+ // run four git processes per row on every call. Only an ANSWER is kept.
362
+ // A commit this clone does not hold yet rejects, and that is this row's
363
+ // turn to be fetched, so the next read asks again.
364
+ const key = `${workspaceId}\u0000${source.applied.mergeSha}\u0000${source.applied.number}`;
365
+ const known = this.appliedChanges.get(key);
366
+ if (known) return known;
367
+ // A row whose commit the clone holds but which is NOT this request's
368
+ // own (a `merged_sha` written before merges recorded their own commit)
369
+ // never becomes it, and is remembered as such, bounded in count:
370
+ // without this, every list re-ran its git calls for every such row,
371
+ // serialized under the workspace mutex, on every poll, and a deployment
372
+ // with hundreds of pre-fix rows paid seconds of git per poll
373
+ // indefinitely. A commit the clone does not HOLD is not remembered —
374
+ // the next fetch may bring it, and the next list asks again.
375
+ if (this.mismatchedAppliedChanges.has(key)) return empty;
376
+ return this.gitService
377
+ .changedPathsAndPairsOfAppliedChange(workspaceId, source.applied)
378
+ .then((answer) => {
379
+ // Full: what is remembered stays, and this answer is simply not
380
+ // kept. A list scans every applied row in one pass, so clearing or
381
+ // evicting here would throw out entries the SAME pass is about to
382
+ // ask for again, and a deployment past the cap would recompute
383
+ // every row on every list. Kept, the rows past the cap are the only
384
+ // ones that cost git anything.
385
+ if (this.appliedChanges.size < MAX_REMEMBERED_APPLIED_CHANGES) this.appliedChanges.set(key, answer);
386
+ return answer;
387
+ })
388
+ .catch((err: unknown) => {
389
+ if (err instanceof AppliedChangeMismatchError) {
390
+ if (this.mismatchedAppliedChanges.size >= MAX_MISMATCHED_APPLIED_CHANGES) this.mismatchedAppliedChanges.clear();
391
+ this.mismatchedAppliedChanges.add(key);
392
+ }
393
+ return degrade('changedPathsAndPairsOfAppliedChange')(err);
394
+ });
395
+ }
193
396
  return this.gitService
194
- .changedPathsForPr(workspaceId, row.targetBranch, row.sourceBranch, opts)
195
- .catch((err) => {
196
- // Best-effort, but log it: an empty result silently hides a CR from the
197
- // owner-routing match in `listPrsForOwnerEmail`, so a swallowed failure
198
- // shouldn't be invisible.
199
- log.warn(
200
- `changedPathsForPr failed for #${row.number} (${row.sourceBranch} → ${row.targetBranch}) in ${workspaceId}:`,
201
- { err },
202
- );
203
- return [] as string[];
204
- });
397
+ .changedPathsAndPairsForPr(workspaceId, row.targetBranch, row.sourceBranch, opts)
398
+ .catch(degrade('changedPathsAndPairsForPr'));
205
399
  }
206
400
 
207
401
  /**
@@ -216,8 +410,14 @@ export class PullRequestService implements IPullRequestService {
216
410
  opts: { fetch?: boolean } = {},
217
411
  ): Promise<PullRequestSummary> {
218
412
  const touched = await this.touchedPathsFor(row, workspaceId, opts);
219
- const summary = this.rowToSummary(row, touched.filter((p) => !isFolderPlaceholder(p)));
220
- this.routingPaths.set(summary, touched);
413
+ const summary = this.rowToSummary(
414
+ row,
415
+ touched.paths.filter((p) => !isFolderPlaceholder(p)),
416
+ // Already placeholder-free and roles.yaml-free (see `changedPathPairs`),
417
+ // so the pairs need no filtering of their own here.
418
+ touched.pairs,
419
+ );
420
+ this.routingPaths.set(summary, touched.paths);
221
421
  return summary;
222
422
  }
223
423
 
@@ -274,6 +474,50 @@ export class PullRequestService implements IPullRequestService {
274
474
  return summaries;
275
475
  }
276
476
 
477
+ /**
478
+ * Every request in `states`, newest first. `['open']` is delegated so the
479
+ * list the app polls keeps its cache; any other set is read straight from
480
+ * the table, because a closed-request read is rare and a second cache keyed
481
+ * on a state set would mostly hold misses.
482
+ *
483
+ * Touched paths are best-effort exactly as on the open list, and no row costs
484
+ * a network call of its own: a MERGED row is diffed from the merge commit it
485
+ * records (local and immutable), and a DECLINED one is not diffed at all —
486
+ * see {@link touchedPathsFor}. A caller that gates on those paths must still
487
+ * treat an empty set as "cannot prove", never as "nothing to protect".
488
+ */
489
+ async listPrsByState(
490
+ states: PullRequestState[],
491
+ opts: { fresh?: boolean; workspaceId?: string } = {},
492
+ ): Promise<PullRequestSummary[]> {
493
+ const wanted = [...new Set(states)];
494
+ if (wanted.length === 0) return [];
495
+ if (wanted.length === 1 && wanted[0] === 'open') return this.listOpenPrs(opts);
496
+ const workspaceId = await this.resolveWorkspaceId(opts.workspaceId);
497
+ const rows = await this.db
498
+ .select()
499
+ .from(changeRequests)
500
+ .where(inArray(changeRequests.state, wanted))
501
+ .orderBy(desc(changeRequests.createdAt));
502
+ // ONE fetch for the whole list, for the reason spelled out on listOpenPrs —
503
+ // never one per row — and only when a row in scope reads from git at all.
504
+ // An open request is diffed from two branch refs, which are as current as
505
+ // the last fetch; a MERGED one from its merge commit, which cannot change
506
+ // but which a clone that has not fetched since the merge does not hold —
507
+ // without this fetch such a clone would read every applied request as
508
+ // author-only for good. A declined one reads from nothing, so a listing
509
+ // of declined requests alone reaches the network not once.
510
+ if (workspaceId && rows.some((row) => row.state === 'open' || row.state === 'merged')) {
511
+ await this.workspaceService
512
+ .ensureRemotesFetched(workspaceId, { force: opts.fresh === true })
513
+ .catch(() => undefined);
514
+ }
515
+ // Bounded fan-out: an applied row's read takes the workspace mutex for
516
+ // its git calls, so a hundred rows launched at once would only queue on
517
+ // it while holding a hundred pending promises.
518
+ return mapWithLimit(rows, SUMMARY_CONCURRENCY, (row) => this.summaryOf(row, workspaceId, { fetch: false }));
519
+ }
520
+
277
521
  async listPrsAuthoredBy(
278
522
  loginOrEmail: string,
279
523
  opts: { fresh?: boolean } = {},
@@ -448,42 +692,114 @@ export class PullRequestService implements IPullRequestService {
448
692
  };
449
693
  /** Did the target change, since the fork point, a file this request changes? */
450
694
  let targetChangedShared = false;
451
- if (workspaceId) {
452
- const shas = await this.gitService.resolvePrShas(
453
- workspaceId,
454
- row.targetBranch,
455
- row.sourceBranch,
456
- );
457
- baseSha = shas.baseSha;
458
- headSha = shas.headSha;
459
- // The file list is pinned to the SHAs just resolved (`at`), so it and
460
- // the `headSha` approvals pin against describe the same commits even if
461
- // another fetch lands on this workspace in between, and the second
462
- // fetch of the same two refs is gone. `patches: false` is for the
463
- // internal detail an approve / withdraw / revert fetches to pin its
464
- // work: those never read `files[].patch`, and generating it cost one git
465
- // subprocess per changed file per click. The detail served to clients
466
- // keeps its patches, so the published payload is unchanged.
467
- files = await this.gitService.changedFilesForPr(
468
- workspaceId,
469
- row.targetBranch,
470
- row.sourceBranch,
471
- { at: { baseSha, headSha }, ...(opts.patches === false ? { patchCap: 0 } : {}) },
472
- );
473
- // Pinned to the same two commits as the file list, so "needs updating"
474
- // and the diff it qualifies can never describe different heads.
475
- forkPoint = await this.gitService.forkPointForPr(workspaceId, { baseSha, headSha });
476
- // Only a target that moved in a file THIS request also changes makes the
477
- // proposal's diff describe text that has moved. One extra
478
- // `diff --name-only` (and only when the branches have diverged at all)
479
- // buys the difference between opening instantly and paying for a merge,
480
- // a push and a second detail read.
481
- targetChangedShared = await this.targetTouchesRequestFiles(
482
- workspaceId,
483
- forkPoint,
484
- baseSha,
485
- files,
695
+ // The SAME routing the list takes, from the same function, so the two
696
+ // surfaces cannot disagree about which files a request has — see
697
+ // {@link changeSourceFor} for why each state reads from what it does.
698
+ const source = workspaceId ? changeSourceFor(row) : ({ kind: 'none' } as ChangeSource);
699
+ try {
700
+ if (workspaceId && source.kind === 'commit') {
701
+ // An APPLIED request is read from its merge commit, not from its
702
+ // branches: the source branch is retired, so there is nothing to resolve
703
+ // and nothing to fetch. The commit's first parent is the target as it
704
+ // stood before the merge and its second is the source tip that landed,
705
+ // so the file list is exactly what was applied, and the `headSha` the
706
+ // approvals are judged stale against is the head they were given on.
707
+ //
708
+ // Before the 2026-10-02 decision this fell into the catch below and
709
+ // answered no files — which, since an empty file set proves no read
710
+ // access, made every applied request readable by its author alone.
711
+ // Reading back what happened is what the ticket exists for.
712
+ //
713
+ // One refresh first: the commit cannot change, but a clone that has
714
+ // not fetched since the merge does not hold it yet, and reading it as
715
+ // missing would make the request author-only on that clone for good.
716
+ await this.workspaceService
717
+ .ensureRemotesFetched(workspaceId, { force: opts.fresh === true })
718
+ .catch(() => undefined);
719
+ const ends = await this.gitService.appliedChangeShas(workspaceId, source.applied);
720
+ baseSha = ends.baseSha;
721
+ headSha = ends.headSha;
722
+ files = await this.gitService.changedFilesOfAppliedChange(workspaceId, source.applied, {
723
+ ...(opts.patches === false ? { patchCap: 0 } : {}),
724
+ });
725
+ // `forkPoint` and `targetChangedShared` stay at their defaults. "Is this
726
+ // behind its target, and does the divergence reach its files" is a
727
+ // question about a proposal that could still be updated; an applied one
728
+ // has no answer to give and reports none (`behind` and `needsUpdate` are
729
+ // gated on `state === 'open'` downstream anyway).
730
+ } else if (workspaceId && source.kind === 'branches') {
731
+ const shas = await this.gitService.resolvePrShas(
732
+ workspaceId,
733
+ row.targetBranch,
734
+ row.sourceBranch,
735
+ );
736
+ baseSha = shas.baseSha;
737
+ headSha = shas.headSha;
738
+ // The file list is pinned to the SHAs just resolved (`at`), so it and
739
+ // the `headSha` approvals pin against describe the same commits even if
740
+ // another fetch lands on this workspace in between, and the second
741
+ // fetch of the same two refs is gone. `patches: false` is for the
742
+ // internal detail an approve / withdraw / revert fetches to pin its
743
+ // work: those never read `files[].patch`, and generating it cost one git
744
+ // subprocess per changed file per click. The detail served to clients
745
+ // keeps its patches, so the published payload is unchanged.
746
+ files = await this.gitService.changedFilesForPr(
747
+ workspaceId,
748
+ row.targetBranch,
749
+ row.sourceBranch,
750
+ { at: { baseSha, headSha }, ...(opts.patches === false ? { patchCap: 0 } : {}) },
751
+ );
752
+ // Pinned to the same two commits as the file list, so "needs updating"
753
+ // and the diff it qualifies can never describe different heads.
754
+ forkPoint = await this.gitService.forkPointForPr(workspaceId, { baseSha, headSha });
755
+ // Only a target that moved in a file THIS request also changes makes the
756
+ // proposal's diff describe text that has moved. One extra
757
+ // `diff --name-only` (and only when the branches have diverged at all)
758
+ // buys the difference between opening instantly and paying for a merge,
759
+ // a push and a second detail read.
760
+ targetChangedShared = await this.targetTouchesRequestFiles(
761
+ workspaceId,
762
+ forkPoint,
763
+ baseSha,
764
+ files,
765
+ );
766
+ }
767
+ // `source.kind === 'none'` — a DECLINED request, a merged row recording no
768
+ // merge commit, or no workspace at all — asks git NOTHING and is answered
769
+ // from the ROW ALONE: no shas, no files. The row's STATE decides that, not
770
+ // whether git happens to fail, which is the fix for the contradiction
771
+ // Local Testing found: declining does not retire the source branch (only
772
+ // merging deletes it), so the branch pair below resolved a declined
773
+ // request perfectly well and published its files to anyone who could read
774
+ // one of them — while the list, which gives a declined row no paths at
775
+ // all, hid the same request from the same caller.
776
+ } catch (err) {
777
+ // What reaches this is a MERGED request whose merge commit this clone
778
+ // cannot resolve — not fetched yet, or a sha the row records that the
779
+ // object store does not hold. A DECLINED request never gets here at all
780
+ // any more: it asks git nothing (see above), so it cannot fail.
781
+ //
782
+ // Everything the ROW records — title, body, state, author, times — is
783
+ // still true, and this is the degradation the no-workspace case above
784
+ // already takes: no shas and no files, rather than no answer at all. Since
785
+ // an empty file set proves no read access, such a row fails CLOSED to its
786
+ // author, and the next read, once the commit is in the clone, answers in
787
+ // full.
788
+ //
789
+ // An OPEN request still fails loudly. There, an unresolvable branch means
790
+ // a branch not yet published or a clone not yet caught up, and presenting
791
+ // a live proposal as one that changes nothing would tell a reviewer the
792
+ // opposite of the truth.
793
+ if (!(err instanceof WorkflowValidationError) || row.state === 'open') throw err;
794
+ log.warn(
795
+ `change request #${prNumber} is ${row.state} and can no longer be diffed; answering from its row alone:`,
796
+ { err },
486
797
  );
798
+ baseSha = '';
799
+ headSha = '';
800
+ files = [];
801
+ forkPoint = { mergeBaseSha: null, behind: false };
802
+ targetChangedShared = false;
487
803
  }
488
804
 
489
805
  // Validated cache hit: TTL fresh AND head SHA unchanged since we cached.
@@ -499,7 +815,17 @@ export class PullRequestService implements IPullRequestService {
499
815
  return cached.value;
500
816
  }
501
817
 
502
- const summary = this.rowToSummary(row, files.map((f) => f.path));
818
+ // The detail has the real file list, so its pairs come straight off it —
819
+ // the same shape the list builds from its own diff, so a reader gating on
820
+ // `touchedNodeFiles` gets the same verdict from a summary and a detail.
821
+ const summary = this.rowToSummary(
822
+ row,
823
+ files.map((f) => f.path),
824
+ files.map((f) => ({
825
+ path: f.path,
826
+ ...(f.previousPath ? { previousPath: f.previousPath } : {}),
827
+ })),
828
+ );
503
829
 
504
830
  // Comments + approvals come from our own DB via the review-workflow service.
505
831
  // The enricher is optional — if it isn't wired yet (startup ordering,
@@ -34,7 +34,7 @@
34
34
  * (status='needs_attention')
35
35
  */
36
36
 
37
- import { and, eq, inArray, isNull, min, or, sql, type SQL } from 'drizzle-orm';
37
+ import { and, asc, eq, inArray, isNull, min, or, sql, type SQL } from 'drizzle-orm';
38
38
  import { logger } from '../../shared/logging.js';
39
39
 
40
40
  const log = logger('pending-commits');
@@ -495,6 +495,34 @@ export class PendingCommitsService {
495
495
  return rows[0]?.count ?? 0;
496
496
  }
497
497
 
498
+ /**
499
+ * What still stands between `branch`'s saved files and its remote: how many
500
+ * commits are queued (`pending` or `running` — a row the worker holds is not
501
+ * pushed yet either), how many were escalated to `needs_attention`, and the
502
+ * message of the oldest of those, or null when none was.
503
+ *
504
+ * Keyed on the branch the row was written for, not a workspace id: the
505
+ * question is asked by `mergeBranch`, which merges what the REMOTE holds of
506
+ * that branch, whichever clone the bytes are waiting in.
507
+ */
508
+ async queuedOnBranch(
509
+ branch: string,
510
+ ): Promise<{ queued: number; stuck: number; needsAttention: string | null }> {
511
+ const rows = await this.db
512
+ .select({ status: pendingCommits.status, lastError: pendingCommits.lastError })
513
+ .from(pendingCommits)
514
+ .where(eq(pendingCommits.branch, branch))
515
+ // Oldest first, so the message reported is the same on every call.
516
+ .orderBy(asc(pendingCommits.queuedAt), asc(pendingCommits.id));
517
+ const stuck = rows.filter((r) => r.status === 'needs_attention');
518
+ return {
519
+ queued: rows.filter((r) => r.status === 'pending' || r.status === 'running').length,
520
+ stuck: stuck.length,
521
+ needsAttention:
522
+ stuck.length === 0 ? null : (stuck[0]?.lastError || 'A queued commit on this branch failed and needs a person.'),
523
+ };
524
+ }
525
+
498
526
  /**
499
527
  * Is a LIVE row — `pending` or `running`, the statuses the worker will
500
528
  * still drive — queued for `(workspaceId, branch, path)`? A
@@ -23,10 +23,20 @@
23
23
  * stalled push parked every other user's save behind it.
24
24
  */
25
25
 
26
+ import { createHash } from 'node:crypto';
26
27
  import type { AuthUser } from '@bevel-software/platform-shared';
27
28
  import { logger } from '../../shared/logging.js';
28
29
 
29
30
  const log = logger('pending-commits');
31
+
32
+ /**
33
+ * The commit author's synthetic user id: a digest of the address, so the id
34
+ * is stable for one person and carries nothing a reader can turn back into
35
+ * the address. It stands in log lines (`user=<id>`) where a real id would.
36
+ */
37
+ function authorIdOf(email: string): string {
38
+ return createHash('sha256').update(email.trim().toLowerCase()).digest('hex').slice(0, 24);
39
+ }
30
40
  import type {
31
41
  PendingCommit,
32
42
  PendingCommitsService,
@@ -56,10 +66,15 @@ export interface ISystemNoticeSink {
56
66
  }): Promise<void>;
57
67
  }
58
68
 
59
- /** Core default: terminal-failure notices go to stderr (no dashboard). */
69
+ /**
70
+ * Core default: terminal-failure notices go to stderr (no dashboard).
71
+ *
72
+ * Keyed by the user's id, never the email or the name: log lines carry no
73
+ * personal identifiers, and an operator can look the id up.
74
+ */
60
75
  export const consoleSystemNoticeSink: ISystemNoticeSink = {
61
76
  async send(notice) {
62
- logger('system-notice').error(`${notice.user.email}: ${notice.message}`);
77
+ logger('system-notice').error(`user ${notice.user.id}: ${notice.message}`);
63
78
  },
64
79
  };
65
80
 
@@ -337,8 +352,11 @@ export class PendingCommitsWorker {
337
352
  // The worker doesn't have a real `users.id` for the commit author —
338
353
  // commit attribution flows through `git commit --author="Name <email>"`,
339
354
  // not through any FK. Drop a synthetic id so the AuthUser shape is
340
- // satisfied without hitting the users table.
341
- id: `pending-commit-author:${row.authorEmail}`,
355
+ // satisfied without hitting the users table. OPAQUE, like a real id:
356
+ // the push path logs `user=<id>` when a push or its recovery fails,
357
+ // and log lines carry no email addresses — so the id is a digest of
358
+ // the address, stable per person and nothing a reader can turn back.
359
+ id: `pending-commit-author:${authorIdOf(row.authorEmail)}`,
342
360
  email: row.authorEmail,
343
361
  name: row.authorName,
344
362
  };
@@ -462,7 +480,7 @@ function strayPathNotice(row: PendingCommit, error: string, corrected: string):
462
480
  `Branch: ${row.branch}`,
463
481
  `Path: ${row.path}`,
464
482
  `Use instead: ${corrected}`,
465
- `Original author: ${row.authorEmail}`,
483
+ `Queue row: ${row.id} (names the author; log lines carry no email addresses)`,
466
484
  `Queued at: ${row.queuedAt.toISOString()}`,
467
485
  `Error: ${error}`,
468
486
  '',
@@ -486,7 +504,7 @@ function terminalFailureNotice(row: PendingCommit, error: string): string {
486
504
  `Workspace: ${row.workspaceId}`,
487
505
  `Branch: ${row.branch}`,
488
506
  `Path: ${row.path}`,
489
- `Original author: ${row.authorEmail}`,
507
+ `Queue row: ${row.id} (names the author; log lines carry no email addresses)`,
490
508
  `Queued at: ${row.queuedAt.toISOString()} (${elapsed} ago)`,
491
509
  `Last error: ${error}`,
492
510
  '',
@@ -50,7 +50,7 @@ export async function ensureRecoveryBotUser(db: Database): Promise<AuthUser> {
50
50
  .returning();
51
51
  if (inserted.length > 0) {
52
52
  const row = inserted[0];
53
- log.info(`created recovery-bot user id=${row.id} email=${row.email}`);
53
+ log.info(`created recovery-bot user id=${row.id}`);
54
54
  return {
55
55
  id: row.id,
56
56
  email: row.email,
@@ -4,7 +4,13 @@ import type { PullRequestFile } from '@bevel-software/platform-shared';
4
4
  // mergePr merges locally through GitService now (no `gh`), so we stub the git
5
5
  // seam and spy on it. `mergeChangeRequestMock` stands in for the real
6
6
  // merge+push; asserting whether it was called replaces the old `gh`-call checks.
7
- const mergeChangeRequestMock = vi.fn(async () => ({ kind: 'merged' as const, sha: 'merged-sha' }));
7
+ const mergeChangeRequestMock = vi.fn(async () => ({
8
+ kind: 'merged' as const,
9
+ sha: 'merged-sha',
10
+ // The commit the request owns — `sha` and `mergeCommit` coincide whenever the
11
+ // merge wrote one, which is the ordinary case these tests exercise.
12
+ mergeCommit: 'merged-sha',
13
+ }));
8
14
 
9
15
  import { ReviewWorkflowService } from '../review-workflow.service.js';
10
16
  import { changeRequests } from '../../../database/schema.js';