@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
@@ -0,0 +1,627 @@
1
+ import { createHmac } from 'node:crypto';
2
+ import { timingSafeStringEqual } from '../auth/password-hash.js';
3
+ import { ACCOUNT_DEACTIVATED_MESSAGE } from '../auth/account-admission.js';
4
+ import jwt from 'jsonwebtoken';
5
+ import { suggestionsBranchPrefixFor } from '@bevel-software/platform-shared';
6
+ import { logger } from '../../shared/logging.js';
7
+ import { workspaceIdForBranch } from '../../shared/workspace-id.js';
8
+ import { changeRequestLink, changeRequestLinkBase } from '../workflow/git/change-request-link.js';
9
+ import { EmbedAccessError, EmbedLockedError, EmbedNodeNotFoundError, EmbedTokenError, } from './embed.errors.js';
10
+ import { parseEmbedRef, EmbedRefParseError, isSafeRepoRelativeEmbedPath } from './embed-link.js';
11
+ const log = logger('embed');
12
+ /**
13
+ * Token lifetime — long enough for a view left open in a chat, short enough
14
+ * that a token copied out of a transcript stops working on its own. The
15
+ * token rides in `open_page`'s result, so it sits in the chat transcript, and
16
+ * whoever holds it reads and edits that one file as the token's user until
17
+ * it expires. One hour (Razvan, 2026-10-09; the embed used two before): a
18
+ * page left open in a chat is still covered, and the window is halved. A
19
+ * view older than that shows the expired sentence and the agent opens the
20
+ * page again.
21
+ */
22
+ export const EMBED_TOKEN_TTL_SECONDS = 60 * 60;
23
+ export class EmbedService {
24
+ config;
25
+ kb;
26
+ workspaceService;
27
+ accessControl;
28
+ authService;
29
+ workflowService;
30
+ gitService;
31
+ accountLinks;
32
+ readers;
33
+ validateWrite;
34
+ resolveNodeId;
35
+ /**
36
+ * Embed tokens are signed with a key DERIVED from the JWT secret (HMAC with
37
+ * a fixed label) rather than the secret itself — domain separation, so an
38
+ * embed token can never be replayed as a session JWT, nor the reverse. The
39
+ * label is part of the token format: changing it invalidates every live
40
+ * token, so it does not change.
41
+ */
42
+ signingKey;
43
+ constructor(config, kb, workspaceService, accessControl, authService, workflowService, gitService, accountLinks, readers,
44
+ /**
45
+ * The pre-disk write gate every other write surface runs — the file
46
+ * editor's and the agent tools' `roles.yaml` validity check. An embed
47
+ * save or proposal writes through `workspaceService.writeFile`, which
48
+ * puts bytes on disk without one, so the gate is asked here first.
49
+ */
50
+ validateWrite,
51
+ /** See {@link EmbedNodeIdResolver} — core has none, so core refuses an id reference. */
52
+ resolveNodeId = null) {
53
+ this.config = config;
54
+ this.kb = kb;
55
+ this.workspaceService = workspaceService;
56
+ this.accessControl = accessControl;
57
+ this.authService = authService;
58
+ this.workflowService = workflowService;
59
+ this.gitService = gitService;
60
+ this.accountLinks = accountLinks;
61
+ this.readers = readers;
62
+ this.validateWrite = validateWrite;
63
+ this.resolveNodeId = resolveNodeId;
64
+ this.signingKey = createHmac('sha256', config.jwtSecret)
65
+ .update('bevel-embed-token-v1')
66
+ .digest('hex');
67
+ }
68
+ // ── mint ───────────────────────────────────────────────────────────────────
69
+ sharedSecretConfigured() {
70
+ return this.config.embedSharedSecret.length > 0;
71
+ }
72
+ verifySharedSecret(secret) {
73
+ const expected = this.config.embedSharedSecret;
74
+ if (!expected || !secret)
75
+ return false;
76
+ // The one constant-time comparison the platform has (the password hash's).
77
+ return timingSafeStringEqual(secret, expected);
78
+ }
79
+ async mintForUser(input) {
80
+ if (!input.userId)
81
+ throw new EmbedAccessError('Missing user id');
82
+ return this.mint({ kind: 'user', userId: input.userId }, input.reference);
83
+ }
84
+ async mintToken(input) {
85
+ if (!input.accountId)
86
+ throw new EmbedAccessError('Missing Atlassian account id');
87
+ // The optional allowed-email-domains guard: a viewer whose domain may not
88
+ // reach the knowledge base must not receive a token either. With a guard
89
+ // configured and no email sent we fail CLOSED — we then cannot confirm the
90
+ // viewer is allowed. (Unchanged from the connector's contract.)
91
+ const email = input.email?.trim().toLowerCase() || undefined;
92
+ if (!this.authService.isEmailDomainAllowed(email ?? '')) {
93
+ throw new EmbedAccessError('Your email domain is not permitted to view this content');
94
+ }
95
+ return this.mint({ kind: 'atlassian', accountId: input.accountId }, input.reference);
96
+ }
97
+ /**
98
+ * The one mint. Resolves the reference to a path on the default branch,
99
+ * confirms the FILE EXISTS, and signs the claims.
100
+ *
101
+ * Access is NOT checked here and must not be: the two callers check it
102
+ * their own way — `open_page` has already answered the caller the way
103
+ * `read_file` would (refusal and all) before it asks for a token, and the
104
+ * connector's mint is for an account that may not be linked to anyone yet.
105
+ * The load path gates content on the resolved identity's read access, which
106
+ * is the gate that decides what anybody sees.
107
+ */
108
+ async mint(subject, reference) {
109
+ const ref = parseEmbedRef(reference, this.config.kbDirName);
110
+ let repoRelative;
111
+ if ('nodeId' in ref) {
112
+ // One dot-less segment is an id by the copy-link's shape — and ALSO a
113
+ // legal root-level file name (`readme`, `LICENSE`). A file that is
114
+ // actually there wins: it is what the caller named, and `open_page`
115
+ // has just read it by that very path.
116
+ if (isSafeRepoRelativeEmbedPath(ref.nodeId) && (await this.fileExists(ref.nodeId))) {
117
+ repoRelative = ref.nodeId;
118
+ }
119
+ else {
120
+ // A bare id is the app's copy-link form. Resolving it needs a node
121
+ // graph, which core does not have; a deployment that does registers a
122
+ // resolver (see `EmbedNodeIdResolver`).
123
+ const resolved = this.resolveNodeId ? await this.resolveNodeId(ref.nodeId) : null;
124
+ if (!resolved)
125
+ throw new EmbedRefParseError(`No file at the reference '${ref.nodeId}'`);
126
+ repoRelative = resolved;
127
+ }
128
+ }
129
+ else {
130
+ repoRelative = ref.repoRelative;
131
+ }
132
+ // Existence at mint time, so a dead reference fails where the caller can
133
+ // still say something about it rather than inside a rendered iframe. A
134
+ // stat, not a read: a deck or a workbook can be hundreds of megabytes,
135
+ // and the view fetches its bytes later, from `/raw`, if at all.
136
+ await this.assertExists(repoRelative);
137
+ const claims = {
138
+ scope: 'embed',
139
+ kind: subject.kind,
140
+ sub: subject.kind === 'user' ? subject.userId : subject.accountId,
141
+ repoRelative,
142
+ slug: ref.slug,
143
+ };
144
+ const token = jwt.sign(claims, this.signingKey, { expiresIn: EMBED_TOKEN_TTL_SECONDS });
145
+ return { token, embedUrl: this.embedUrlFor(token) };
146
+ }
147
+ /** The view's address — what a host frames. */
148
+ embedUrlFor(token) {
149
+ return `${this.config.publicFrontendUrl}/embed?token=${encodeURIComponent(token)}`;
150
+ }
151
+ /** A file's address in the app — what a link opens in a new tab. */
152
+ appUrlFor(repoRelative, slug) {
153
+ const wsPath = [this.config.kbDirName, ...repoRelative.split('/')]
154
+ .map(encodeURIComponent)
155
+ .join('/');
156
+ const branch = encodeURIComponent(this.kb.defaultBranch);
157
+ const anchor = slug ? `#${encodeURIComponent(slug)}` : '';
158
+ return `${this.config.publicFrontendUrl}/workspace/${branch}/${wsPath}${anchor}`;
159
+ }
160
+ // ── read ───────────────────────────────────────────────────────────────────
161
+ async loadFile(token) {
162
+ const claims = this.verifyToken(token);
163
+ const { linked, canRead, canWrite } = await this.resolveIdentity(claims);
164
+ const reader = this.readers.readerFor(claims.repoRelative);
165
+ const base = {
166
+ nodeName: nodeNameFor(claims.repoRelative),
167
+ repoRelative: claims.repoRelative,
168
+ workspacePath: this.wsPathFor(claims.repoRelative),
169
+ kbDirName: this.config.kbDirName,
170
+ branch: this.kb.defaultBranch,
171
+ appUrl: this.appUrlFor(claims.repoRelative, claims.slug),
172
+ ...(claims.slug ? { heading: claims.slug } : {}),
173
+ content: '',
174
+ contentIsText: reader.textEditable,
175
+ linked,
176
+ canRead,
177
+ canWrite,
178
+ linkUrl: `${this.config.publicFrontendUrl}/embed/link?token=${encodeURIComponent(token)}`,
179
+ };
180
+ // Default-deny, exactly as the app does: no content leaves the backend
181
+ // until the token's identity resolves AND may read this file. The gated
182
+ // view still carries the status so the page can show the right prompt.
183
+ if (!linked || !canRead)
184
+ return base;
185
+ // A renderer that reads BYTES is handed none here — it fetches them from
186
+ // `/api/embed/raw` under this same token, which keeps a document or an
187
+ // image out of a JSON payload and off the base64 round trip.
188
+ if (!reader.textEditable)
189
+ return base;
190
+ const bytes = await this.readFileBytes(claims.repoRelative);
191
+ const result = await reader.read(bytes, claims.repoRelative);
192
+ // A refusal IS the file's honest textual answer (unreadable binary under
193
+ // an extension the fallback reader took), and the app shows it as text —
194
+ // but it is not the file's text, so the view neither claims it is nor
195
+ // offers to save over the bytes it stands for. `save` holds the same line.
196
+ const isText = result.kind === 'text';
197
+ const content = isText ? result.text : result.kind === 'refusal' ? result.message : '';
198
+ return { ...base, content, contentIsText: isText, canWrite: canWrite && isText };
199
+ }
200
+ /**
201
+ * Refuse to write text over a file whose bytes are not text: the reader
202
+ * that would show it answers a refusal, not the content, and a save would
203
+ * replace a binary with the viewer's draft.
204
+ */
205
+ /** A file a page draws rather than a page: bytes no reader edits as text, or an SVG. */
206
+ isAsset(repoRelative) {
207
+ return !this.readers.readerFor(repoRelative).textEditable || /\.svg$/i.test(repoRelative);
208
+ }
209
+ async assertTextEditable(repoRelative) {
210
+ const reader = this.readers.readerFor(repoRelative);
211
+ if (!reader.textEditable)
212
+ throw new EmbedAccessError('This file is not editable as text');
213
+ const result = await reader.read(await this.readFileBytes(repoRelative), repoRelative);
214
+ if (result.kind !== 'text')
215
+ throw new EmbedAccessError('This file is not editable as text');
216
+ }
217
+ async readBytes(token, path) {
218
+ const claims = this.verifyToken(token);
219
+ const { linked, user } = await this.resolveIdentity(claims);
220
+ if (!linked || !user)
221
+ throw new EmbedAccessError('This view is not linked to an account');
222
+ // A path beside the embedded file — the pictures a markdown page shows.
223
+ // Resolved relative to the embedded file's own folder, then gated on the
224
+ // viewer's read access for THAT file: the token scopes the view to one
225
+ // page, never to one page's read permissions.
226
+ const target = path ? resolveBeside(claims.repoRelative, path) : claims.repoRelative;
227
+ if (target === null)
228
+ throw new EmbedAccessError('That path is not inside this knowledge base');
229
+ // ONE page, as the token promises: beside the page only an ASSET it draws
230
+ // is served — a file no reader edits as text, or an SVG, the one text
231
+ // format a page shows as a picture. Another page's text never comes
232
+ // through this token; that page opens in the app, under its own view.
233
+ if (target !== claims.repoRelative && !this.isAsset(target)) {
234
+ throw new EmbedAccessError('This view shows one page; another page opens in the app');
235
+ }
236
+ const workspaceId = this.defaultWorkspaceId();
237
+ if (!(await this.accessControl.canRead(workspaceId, user.email, target))) {
238
+ throw new EmbedAccessError(`You don't have permission to read "${target}".`);
239
+ }
240
+ return { bytes: await this.readFileBytes(target), path: target };
241
+ }
242
+ // ── write ──────────────────────────────────────────────────────────────────
243
+ async acquireLock(token) {
244
+ const { user, wsPath } = await this.requireEditor(token);
245
+ const result = await this.workflowService.acquireLock(this.defaultWorkspaceId(), this.kb.defaultBranch, wsPath, user);
246
+ return result.acquired
247
+ ? { acquired: true }
248
+ : { acquired: false, holderName: result.lock.holderName };
249
+ }
250
+ async heartbeat(token) {
251
+ const claims = this.verifyToken(token);
252
+ const { user, canWrite } = await this.resolveIdentity(claims);
253
+ if (!user)
254
+ return; // nothing held — nothing to keep alive
255
+ const workspaceId = this.defaultWorkspaceId();
256
+ const wsPath = this.wsPathFor(claims.repoRelative);
257
+ // Write access is asked again on every renewal: the token outlives the
258
+ // permission it was minted under, and a writer who lost it must not keep
259
+ // a lock alive that shuts out the people who still have it. The lock
260
+ // goes HERE, not only when the view hears the refusal: a frame that is
261
+ // gone, or a host that never delivers the 403, would otherwise leave the
262
+ // file shut to the writers who still have access until the TTL. Letting
263
+ // go takes no access — the workflow releases only a lock this user holds.
264
+ if (!canWrite) {
265
+ await this.workflowService.releaseLockNoCommit(workspaceId, this.kb.defaultBranch, wsPath, user);
266
+ throw new EmbedAccessError();
267
+ }
268
+ await this.workflowService.heartbeatLock(workspaceId, this.kb.defaultBranch, wsPath, user);
269
+ }
270
+ async cancel(token) {
271
+ const claims = this.verifyToken(token);
272
+ const { user } = await this.resolveIdentity(claims);
273
+ if (!user)
274
+ return;
275
+ await this.workflowService.releaseLockNoCommit(this.defaultWorkspaceId(), this.kb.defaultBranch, this.wsPathFor(claims.repoRelative), user);
276
+ }
277
+ async save(token, content) {
278
+ const { claims, user, wsPath } = await this.requireEditor(token);
279
+ await this.assertTextEditable(claims.repoRelative);
280
+ // The write gate before the lock: a text the gate refuses (a `roles.yaml`
281
+ // that would not parse) never takes a lock it has nothing to write under.
282
+ await this.validateWrite(wsPath, content);
283
+ const workspaceId = this.defaultWorkspaceId();
284
+ // Bytes reach the disk ONLY under a lock this viewer holds. ASK who holds
285
+ // it rather than acquiring again: `acquire` is strict and refuses a live
286
+ // lock even to its own holder (so an agent sharing the user id cannot
287
+ // steal a human's edit), which turned every Save into a 409 against the
288
+ // writer's own Edit lock. This is the check the app's file routes make
289
+ // (`workspace.routes` `withLock`). A viewer whose lock lapsed — a frame
290
+ // hidden past the TTL — takes it again if it is free, and is refused if
291
+ // somebody else took it: writing first and finding out at the release
292
+ // would leave their text on disk under the other editor's lock.
293
+ await this.ensureHoldsLock(workspaceId, wsPath, user);
294
+ try {
295
+ await this.workspaceService.writeFile(workspaceId, wsPath, content);
296
+ // Release commits + pushes the on-disk bytes through the background
297
+ // queue — the same path the app's file page takes out of edit mode.
298
+ await this.workflowService.releaseLock(workspaceId, this.kb.defaultBranch, wsPath, user);
299
+ }
300
+ catch (err) {
301
+ await this.workflowService
302
+ .releaseLockNoCommit(workspaceId, this.kb.defaultBranch, wsPath, user)
303
+ .catch((cleanupErr) => {
304
+ // Best-effort cleanup failed — say so, so a stuck lock is
305
+ // diagnosable, then rethrow the save's own error below.
306
+ log.error(`releaseLockNoCommit failed during save cleanup ` +
307
+ `(workspace=${workspaceId} path=${wsPath} user=${user.id})`, cleanupErr);
308
+ return undefined;
309
+ });
310
+ throw err;
311
+ }
312
+ }
313
+ /**
314
+ * File the edit as a change request authored by the viewer, on their own
315
+ * personal suggestions branch — the same branch and the same one-request
316
+ * bundle the app's "Propose changes" uses, so a reader who proposes from a
317
+ * chat and from the app lands in one place.
318
+ *
319
+ * No lock: nothing touches the default branch, and the suggestions branch
320
+ * is this person's own.
321
+ *
322
+ * The write is COMMITTED here, synchronously, before the request is opened.
323
+ * `workspaceService.writeFile` only puts bytes on disk — the app's file
324
+ * routes commit by releasing the lock they took, which enqueues the commit
325
+ * for the background worker. Neither is usable here: without a commit the
326
+ * branch head never moves, and the request opens against a tree identical
327
+ * to its base — `changedFiles: 0`, and a reviewer told "this pull request
328
+ * has no file changes to approve" about a proposal that is sitting
329
+ * uncommitted on disk. An ENQUEUED commit has the same problem with a race
330
+ * on top of it. `commitChanges` commits and pushes before returning, which
331
+ * is what the one other server-side propose flow (the plugin join request)
332
+ * does for exactly this reason.
333
+ */
334
+ async propose(token, content) {
335
+ const claims = this.verifyToken(token);
336
+ const { user, canRead } = await this.resolveIdentity(claims);
337
+ if (!user)
338
+ throw new EmbedAccessError('Link your account to propose a change');
339
+ // Read access is the floor for proposing: a change request quotes the
340
+ // file's new text beside its old, so proposing on a file you may not read
341
+ // would publish what you were not allowed to see.
342
+ if (!canRead)
343
+ throw new EmbedAccessError(`You don't have permission to read "${claims.repoRelative}".`);
344
+ // The guard a save runs: a proposal is text, so what it proposes over
345
+ // has to be text too — a PDF, an image or bytes under a markdown name
346
+ // are refused here as they are on Save, not committed as text.
347
+ await this.assertTextEditable(claims.repoRelative);
348
+ const wsPath = this.wsPathFor(claims.repoRelative);
349
+ // The same write gate as a save, before a branch is made for the text: a
350
+ // proposal is a commit, and a commit of an unparseable `roles.yaml` is
351
+ // exactly what the gate exists to keep out of the repository.
352
+ await this.validateWrite(wsPath, content);
353
+ const branch = `${suggestionsBranchPrefixFor({ email: user.email, id: user.id })}knowledge`;
354
+ // Create the branch when it is not there yet; an existing one is reused,
355
+ // which is what bundles a person's proposals into one request. Asked of
356
+ // ORIGIN first: a second proposal finds the branch already pushed, and
357
+ // creating it again would fail as a non-fast-forward push, not as
358
+ // "already exists" — the race between the two is still caught below.
359
+ // Created through the workflow service, under its branch-lifecycle lock,
360
+ // as every branch the app creates is: creating one is the one operation
361
+ // that can bring a "gone" branch back under a retirement's feet.
362
+ if (!(await this.gitService.remoteBranchExists(this.defaultWorkspaceId(), branch))) {
363
+ await this.workflowService
364
+ .createBranch(this.defaultWorkspaceId(), branch, this.kb.defaultBranch)
365
+ .catch((err) => {
366
+ if (err instanceof Error && /already exists|non-fast-forward|fetch first/i.test(err.message))
367
+ return;
368
+ throw err;
369
+ });
370
+ }
371
+ const workspace = await this.workspaceService.getOrCreateForBranch(branch);
372
+ // One proposal at a time per file on this branch: two from the same
373
+ // person landing together would otherwise write over each other before
374
+ // either commit staged the file, and one would commit the other's text.
375
+ // The workspace service's own per-path turn is that queue — the one the
376
+ // app's file routes take around a write whose decision spans more than
377
+ // one call — and the write inside takes the same turn, re-entrantly.
378
+ await this.workspaceService.withPathTurn(workspace.id, wsPath, async () => {
379
+ await this.workspaceService.writeFile(workspace.id, wsPath, content);
380
+ // Scoped to the one path this proposal is about: the suggestions branch
381
+ // is shared by everything this person has proposed, and a bare commit
382
+ // would sweep in another in-flight write of theirs under this message.
383
+ await this.workflowService.commitChanges(workspace.id, user, `Propose changes to ${claims.repoRelative}`, [wsPath]);
384
+ });
385
+ try {
386
+ const created = await this.workflowService.openChangeRequest(workspace.id, user, {
387
+ sourceBranch: branch,
388
+ targetBranch: this.kb.defaultBranch,
389
+ title: `Changes from ${user.name}. Knowledge`,
390
+ });
391
+ return {
392
+ branch,
393
+ ...(typeof created?.number === 'number'
394
+ ? { number: created.number, url: this.changeRequestUrl(created.number) }
395
+ : {}),
396
+ };
397
+ }
398
+ catch (err) {
399
+ // The person's one open Knowledge request already covers this branch —
400
+ // which is the state this method is trying to reach, not a failure. The
401
+ // refusal names it, so point at it.
402
+ const existing = duplicateRequestNumber(err);
403
+ if (existing === null)
404
+ throw err;
405
+ return { branch, number: existing, url: this.changeRequestUrl(existing) };
406
+ }
407
+ }
408
+ // ── account links ──────────────────────────────────────────────────────────
409
+ async linkAccount(token, userId) {
410
+ const claims = this.verifyToken(token);
411
+ // Only an outside account has anything to link; a token already minted
412
+ // for a Hexis user names its person and must not re-point at another.
413
+ if (claims.kind !== 'atlassian') {
414
+ throw new EmbedAccessError('This view is already signed in');
415
+ }
416
+ await this.accountLinks.link(claims.sub, userId);
417
+ }
418
+ async listLinkedAccounts(userId) {
419
+ const rows = await this.accountLinks.listForUser(userId);
420
+ return rows.map((r) => ({
421
+ atlassianAccountId: r.atlassianAccountId,
422
+ createdAt: r.createdAt.getTime(),
423
+ }));
424
+ }
425
+ async unlinkAccount(userId, accountId) {
426
+ return this.accountLinks.unlink(userId, accountId);
427
+ }
428
+ // ── internals ──────────────────────────────────────────────────────────────
429
+ /**
430
+ * Make sure `user` holds an EDIT lock on `wsPath` on the default branch:
431
+ * keep it when they already do, take it when nobody does (an expired row
432
+ * reads as none), refuse with the holder's name when somebody else does.
433
+ */
434
+ async ensureHoldsLock(workspaceId, wsPath, user) {
435
+ const branch = this.kb.defaultBranch;
436
+ const current = await this.workflowService.getLock(workspaceId, branch, wsPath);
437
+ if (current) {
438
+ // A coordination hold grants no write authority, so it is not "ours"
439
+ // for a save even when the id matches.
440
+ if (current.holderUserId === user.id && current.mode !== 'coordination')
441
+ return;
442
+ throw new EmbedLockedError(current.holderName);
443
+ }
444
+ const taken = await this.workflowService.acquireLock(workspaceId, branch, wsPath, user);
445
+ if (!taken.acquired)
446
+ throw new EmbedLockedError(taken.lock.holderName);
447
+ }
448
+ defaultWorkspaceId() {
449
+ return workspaceIdForBranch(this.kb.defaultBranch);
450
+ }
451
+ wsPathFor(repoRelative) {
452
+ return `${this.config.kbDirName}/${repoRelative}`;
453
+ }
454
+ /**
455
+ * A change request's address, through the same builder the workflow tools
456
+ * use — so a proposal made from a chat and one made by an agent point at
457
+ * the same place, path prefix of a proxied deployment included.
458
+ */
459
+ changeRequestUrl(number) {
460
+ return changeRequestLink(number, changeRequestLinkBase(this.config.publicFrontendUrl)).url;
461
+ }
462
+ /**
463
+ * Resolve, authorize and locate an edit. Throws `EmbedAccessError` when the
464
+ * identity does not resolve or may not write. Returns the user (for lock
465
+ * attribution) and the workspace-relative path.
466
+ */
467
+ async requireEditor(token) {
468
+ const claims = this.verifyToken(token);
469
+ const { user, canWrite } = await this.resolveIdentity(claims);
470
+ if (!user)
471
+ throw new EmbedAccessError('Link your account to edit');
472
+ if (!canWrite)
473
+ throw new EmbedAccessError();
474
+ await this.workspaceService.getOrCreateForBranch(this.kb.defaultBranch);
475
+ return { claims, user, wsPath: this.wsPathFor(claims.repoRelative) };
476
+ }
477
+ /** Resolve the token's identity to a user + read/write verdicts. */
478
+ async resolveIdentity(claims) {
479
+ const unresolved = { linked: false, user: null, canRead: false, canWrite: false };
480
+ const userId = claims.kind === 'user' ? claims.sub : await this.accountLinks.getUserId(claims.sub);
481
+ if (!userId)
482
+ return unresolved;
483
+ const user = await this.authService.getUserById(userId);
484
+ if (!user)
485
+ return unresolved;
486
+ // The gate every credential passes: a token minted for an account an
487
+ // admin has since switched off reads, saves and proposes nothing, and is
488
+ // told what every other door tells that person.
489
+ if (!(await this.authService.isActive(userId)))
490
+ throw new EmbedAccessError(ACCOUNT_DEACTIVATED_MESSAGE);
491
+ const workspaceId = this.defaultWorkspaceId();
492
+ const canRead = await this.accessControl.canRead(workspaceId, user.email, claims.repoRelative);
493
+ // Write implies read in the access resolver; the `canRead &&` guard pins
494
+ // that here, so no caller can see canWrite without canRead.
495
+ const canWrite = canRead && (await this.accessControl.canWrite(workspaceId, user.email, claims.repoRelative));
496
+ return { linked: true, user, canRead, canWrite };
497
+ }
498
+ /** Whether `repoRelative` is a file on the default branch — a stat, never a read. */
499
+ async fileExists(repoRelative) {
500
+ try {
501
+ await this.assertExists(repoRelative);
502
+ return true;
503
+ }
504
+ catch (err) {
505
+ if (err instanceof EmbedNodeNotFoundError)
506
+ return false;
507
+ throw err;
508
+ }
509
+ }
510
+ /** The typed 404 of {@link readFileBytes}, for a reference, without reading a byte. */
511
+ async assertExists(repoRelative) {
512
+ const workspaceId = this.defaultWorkspaceId();
513
+ await this.workspaceService.getOrCreateForBranch(this.kb.defaultBranch);
514
+ if (!(await this.workspaceService.isFile(workspaceId, this.wsPathFor(repoRelative)))) {
515
+ throw new EmbedNodeNotFoundError(`${repoRelative} doesn't exist on ${this.kb.defaultBranch}`);
516
+ }
517
+ }
518
+ async readFileBytes(repoRelative) {
519
+ const workspaceId = this.defaultWorkspaceId();
520
+ await this.workspaceService.getOrCreateForBranch(this.kb.defaultBranch);
521
+ try {
522
+ const read = await this.workspaceService.readFileBinary(workspaceId, this.wsPathFor(repoRelative));
523
+ return Buffer.isBuffer(read) ? read : Buffer.from(read);
524
+ }
525
+ catch (err) {
526
+ // A missing file is a bad or stale reference, not a server fault —
527
+ // surface it as a typed 404 so the view says what is wrong instead of
528
+ // showing a 500. Everything else (EACCES, EIO, …) stays unexpected.
529
+ const code = err?.code;
530
+ if (code === 'ENOENT' || code === 'ENOTDIR' || code === 'EISDIR') {
531
+ throw new EmbedNodeNotFoundError(`${repoRelative} doesn't exist on ${this.kb.defaultBranch}`);
532
+ }
533
+ throw err;
534
+ }
535
+ }
536
+ verifyToken(token) {
537
+ let decoded;
538
+ try {
539
+ decoded = jwt.verify(token, this.signingKey);
540
+ }
541
+ catch {
542
+ throw new EmbedTokenError();
543
+ }
544
+ const c = decoded;
545
+ if (c?.scope !== 'embed' || typeof c.repoRelative !== 'string' || !c.repoRelative) {
546
+ throw new EmbedTokenError();
547
+ }
548
+ // A token minted by the release BEFORE the subject was generalised keyed
549
+ // the identity on `accountId` alone. Those were minted for two hours, so an upgrade
550
+ // would otherwise expire every open Atlassian panel on the spot; reading
551
+ // the old spelling costs one branch and keeps them working.
552
+ if (typeof c.accountId === 'string' && c.accountId) {
553
+ return { scope: 'embed', kind: 'atlassian', sub: c.accountId, repoRelative: c.repoRelative, slug: c.slug };
554
+ }
555
+ if ((c.kind !== 'user' && c.kind !== 'atlassian') || typeof c.sub !== 'string' || !c.sub) {
556
+ throw new EmbedTokenError();
557
+ }
558
+ return { scope: 'embed', kind: c.kind, sub: c.sub, repoRelative: c.repoRelative, slug: c.slug };
559
+ }
560
+ }
561
+ /** Display name = file basename without its extension. */
562
+ function nodeNameFor(repoRelative) {
563
+ const base = repoRelative.split('/').pop() ?? repoRelative;
564
+ const dot = base.lastIndexOf('.');
565
+ return dot > 0 ? base.slice(0, dot) : base;
566
+ }
567
+ /**
568
+ * A path written relative to `from`'s folder, resolved to a repo-relative
569
+ * path — or null when it escapes the repository or is otherwise unsafe.
570
+ * A path with a leading slash (`/x`) is taken from the repository root:
571
+ * that is the form the embed view sends, translating the workspace path a
572
+ * renderer hands it.
573
+ */
574
+ export function resolveBeside(from, path) {
575
+ // eslint-disable-next-line no-control-regex
576
+ if (/[\x00-\x1f\x7f]/.test(path))
577
+ return null;
578
+ let decoded = path;
579
+ try {
580
+ decoded = decodeURIComponent(path);
581
+ }
582
+ catch {
583
+ return null;
584
+ }
585
+ // Judged again decoded: `%0a` is a newline once the escape is undone.
586
+ // eslint-disable-next-line no-control-regex
587
+ if (/[\x00-\x1f\x7f]/.test(decoded))
588
+ return null;
589
+ const absolute = decoded.startsWith('/');
590
+ const base = absolute ? [] : from.split('/').slice(0, -1);
591
+ const parts = [...base];
592
+ for (const seg of decoded.replace(/^\/+/, '').split('/')) {
593
+ if (seg === '' || seg === '.')
594
+ continue;
595
+ if (seg === '..') {
596
+ // Out of the repository — never a path this view may serve.
597
+ if (parts.length === 0)
598
+ return null;
599
+ parts.pop();
600
+ continue;
601
+ }
602
+ parts.push(seg);
603
+ }
604
+ return parts.length > 0 ? parts.join('/') : null;
605
+ }
606
+ /**
607
+ * The number of the open request the server says already covers this branch
608
+ * pair, or null when the failure was something else. The refusal carries the
609
+ * number precisely so a caller can point at the request instead of treating
610
+ * the state as broken.
611
+ */
612
+ function duplicateRequestNumber(err) {
613
+ const detail = err ?? null;
614
+ const candidate = detail?.details?.existingNumber ?? detail?.existingNumber;
615
+ if (typeof candidate === 'number')
616
+ return candidate;
617
+ if (err instanceof Error) {
618
+ // The refusal's own sentence ("An open change request already exists
619
+ // from … to … (#12)"), and only that shape: a count or a numeric token
620
+ // after some other "already" is not a request.
621
+ const match = /change request already exists[^#]*#(\d+)/i.exec(err.message);
622
+ if (match)
623
+ return Number(match[1]);
624
+ }
625
+ return null;
626
+ }
627
+ //# sourceMappingURL=embed.service.js.map