@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,95 @@
1
+ import { callLine } from '@bevel-software/platform-mcp-core';
2
+ import express from 'express';
3
+ import { describe, expect, it } from 'vitest';
4
+ import { ToolRegistry } from '../../tool-registry/tool-registry.js';
5
+ import { TOOL_DESCRIPTION_CAP, clientVisibleLength } from '../../tool-registry/description-length.js';
6
+ import { GUIDE_FIRST_SENTENCE } from '../../tool-registry/guide-first.js';
7
+ import { createToolHandlerFactory } from '../../tool-helpers/tool-handler.js';
8
+ import type { ToolAuth } from '../../tool-auth/tool-auth.middleware.js';
9
+ import { registerSkillsTools } from '../skills.tools.js';
10
+ import type { ISkillService, Skill } from '../skills.contract.js';
11
+
12
+ /**
13
+ * The two skill tools name the skills the caller may read in their
14
+ * descriptions. The catalog is the organisation's to grow, and a client cuts
15
+ * a long description from the END — so the names are the part that gives way,
16
+ * never the tool's own text, and never an id cut in half.
17
+ */
18
+ describe('the skill tools name the available skills within the description cap', () => {
19
+ const unused = () => new Proxy({}, { get: () => undefined }) as never;
20
+
21
+ async function served(skills: readonly Skill[]) {
22
+ const registry = new ToolRegistry();
23
+ const skillService = { listSkills: async () => skills } as unknown as ISkillService;
24
+ registerSkillsTools(registry, express.Router(), ((_req, _res, next) => next()) as unknown as ToolAuth, createToolHandlerFactory(unused()), skillService);
25
+ const tools = await registry.listExternal();
26
+ return {
27
+ list: tools.find((t) => t.name === 'list_skills')!,
28
+ get: tools.find((t) => t.name === 'get_skill')!,
29
+ };
30
+ }
31
+
32
+ const skill = (name: string): Skill => ({ name, description: '', path: `Skills/${name}` }) as unknown as Skill;
33
+
34
+ it('names every skill when they fit, and says so plainly when there are none', async () => {
35
+ const few = await served(['rfi', 'deck-review'].map(skill));
36
+ for (const tool of [few.list, few.get]) {
37
+ expect(tool.description).toContain('Currently available skills: `rfi`, `deck-review`.');
38
+ expect(tool.description).not.toContain(' more');
39
+ }
40
+ const none = await served([]);
41
+ expect(none.list.description).toContain('No skills are currently available.');
42
+ });
43
+
44
+ it('lists every skill when the complete line fits, even where a shorter list plus its count would not', async () => {
45
+ // The budget is what the tool's fixed text leaves under the cap once the
46
+ // guide-first sentence is counted — read off a served description rather
47
+ // than guessed, so the names below are sized to fill it EXACTLY.
48
+ const probe = await served([skill('x')]);
49
+ const fixed = probe.list.description!.slice(GUIDE_FIRST_SENTENCE.length + 1, probe.list.description!.indexOf('Currently available skills: '));
50
+ // And the `Call:` line a client is handed ahead of all of it, with the
51
+ // blank line after it: the example counts toward the cap too.
52
+ const call = callLine(`KNOWLEDGE_BASE.list_skills`, probe.list.inputs).length + 2;
53
+ const budget = TOOL_DESCRIPTION_CAP - call - GUIDE_FIRST_SENTENCE.length - 1 - fixed.length;
54
+ const head = 'Currently available skills: '.length;
55
+ // Twenty-one names, the LAST one short — shorter than the ", and 1 more…"
56
+ // tail a cut before it would carry — and the first one sized so the
57
+ // complete line is the budget to the character. A cut-then-count loop
58
+ // stops short of the complete list here (a prefix plus its count tail is
59
+ // over budget well before the last name) though the complete line fits.
60
+ const count = 21;
61
+ const base = Math.floor((budget - head - 1 - (count - 1) * 2 - count * 2) / count); // chars inside the backticks
62
+ const names = Array.from({ length: count }, (_, i) => `n${i}`.padEnd(base, 'x'));
63
+ names[count - 1] = 'z';
64
+ const slack = budget - (head + names.reduce((n, name) => n + name.length + 2, 0) + (count - 1) * 2 + 1);
65
+ names[0] = names[0] + 'y'.repeat(slack);
66
+ const { list } = await served(names.map(skill));
67
+ const line = list.description!.slice(list.description!.indexOf('Currently available skills: '));
68
+ expect(line.length).toBe(budget);
69
+ expect(line.endsWith('.')).toBe(true);
70
+ expect(line).not.toContain(' more');
71
+ for (const name of names) expect(line).toContain(`\`${name}\``);
72
+ });
73
+
74
+ it('cuts the list to what fits under the cap with the guide-first sentence counted, and counts the rest', async () => {
75
+ const many = Array.from({ length: 300 }, (_, i) => skill(`a-skill-with-a-long-name-number-${i}`));
76
+ const { list, get } = await served(many);
77
+ for (const tool of [list, get]) {
78
+ // Measured as the registry serves it: the opener in front.
79
+ expect(clientVisibleLength(tool), tool.name).toBeLessThanOrEqual(TOOL_DESCRIPTION_CAP);
80
+ expect(tool.description!.startsWith(GUIDE_FIRST_SENTENCE), tool.name).toBe(true);
81
+ // The tool's own text is whole; the names are what gave way.
82
+ expect(tool.description, tool.name).toContain('Currently available skills: `a-skill-with-a-long-name-number-0`');
83
+ const counted = /, and (\d+) more that list_skills names\.$/.exec(tool.description!);
84
+ expect(counted, tool.name).not.toBeNull();
85
+ const shown = (tool.description!.match(/`a-skill-with-a-long-name-number-\d+`/g) ?? []).length;
86
+ expect(shown + Number(counted![1]), tool.name).toBe(300);
87
+ // No name is cut in half: every one listed is a real one, closing
88
+ // backtick included — a dangling name (no closing backtick) is caught
89
+ // because the scan does not require one.
90
+ for (const name of tool.description!.match(/`a-skill-with-a-long-name-number-[^`,.]*`?/g) ?? []) {
91
+ expect(name, tool.name).toMatch(/^`a-skill-with-a-long-name-number-\d+`$/);
92
+ }
93
+ }
94
+ });
95
+ });
@@ -1,9 +1,14 @@
1
1
  import type { Router, RequestHandler } from 'express';
2
- import type { IToolRegistry, UtcpTool } from '../tool-registry/tool.contract.js';
2
+ import { callLine } from '@bevel-software/platform-mcp-core';
3
+ import type { IToolRegistry, JsonSchema, UtcpTool } from '../tool-registry/tool.contract.js';
4
+ import { TOOL_DESCRIPTION_CAP } from '../tool-registry/description-length.js';
5
+ import { GUIDE_FIRST_SENTENCE } from '../tool-registry/guide-first.js';
3
6
  import { ToolError, type ToolContext } from '../tool-helpers/tool.contract.js';
4
7
  import { toolDef } from '../tool-helpers/tool-def.js';
8
+ import { bodyEnvelope, declareRouteTool } from '../tool-helpers/route-tool-schemas.js';
5
9
  import type { ToolHandlerFactory } from '../tool-helpers/tool-handler.js';
6
10
  import type { ISkillService } from './skills.contract.js';
11
+ import { EXTERNAL_KB_MANUAL_NAME } from '../tool-manuals/tool-manuals.contract.js';
7
12
  import type { IAllowedToolsChecker } from './allowed-tools-check.js';
8
13
 
9
14
  /**
@@ -20,6 +25,39 @@ const BRANCH_SKILLS_INPUT = {
20
25
  'a branch that does not exist answers 404 naming it. Omit it for the approved skills.',
21
26
  };
22
27
 
28
+ /** What `list_skills` takes. A const so the route's check and the def share one declaration. */
29
+ const LIST_SKILLS_INPUTS = {
30
+ type: 'object' as const,
31
+ properties: { branch: BRANCH_SKILLS_INPUT },
32
+ additionalProperties: false,
33
+ };
34
+
35
+ /** What `get_skill` takes. A const for the same reason as {@link LIST_SKILLS_INPUTS}. */
36
+ const GET_SKILL_INPUTS = {
37
+ type: 'object' as const,
38
+ properties: {
39
+ name: { type: 'string' as const, minLength: 1, description: 'Skill name (its folder name, e.g. `rfi`).' },
40
+ file: {
41
+ type: 'string' as const,
42
+ description:
43
+ 'Optional bundled file path relative to the skill folder (e.g. `scripts/build_xlsx.py`) — ' +
44
+ 'fetch its content instead of the body.',
45
+ },
46
+ version: {
47
+ type: 'string' as const,
48
+ description:
49
+ 'Optional: the declared version to load (e.g. `1.4.0` — the `version` that `list_skills` ' +
50
+ 'reports: `metadata.version`, else `version`, else `lifecycle.version`). Omitted, the skill is loaded as it ' +
51
+ 'is now, which is the latest. Given, the skill — or the `file` — is served as it was at the most ' +
52
+ 'recent commit that declared that version; a version the skill never declared answers ' +
53
+ '`version_not_found` with the versions it did declare.',
54
+ },
55
+ branch: BRANCH_SKILLS_INPUT,
56
+ },
57
+ required: ['name'],
58
+ additionalProperties: false,
59
+ };
60
+
23
61
  /**
24
62
  * Registers the two skill tools (both surfaces) and hosts their endpoints.
25
63
  *
@@ -49,6 +87,11 @@ export function registerSkillsTools(
49
87
  registry.registerInternalTool((ctx) => buildListSkillsDef(skillService, ctx.userEmail));
50
88
  registry.registerExternalTool((ctx) => buildGetSkillDef(skillService, ctx.userEmail));
51
89
  registry.registerInternalTool((ctx) => buildGetSkillDef(skillService, ctx.userEmail));
90
+ // Both defs are built per catalog listing (their descriptions name the skills
91
+ // THIS caller may read), so declare the arguments here as well: a direct REST
92
+ // call that lands before the first listing must be checked against them too.
93
+ declareRouteTool('list_skills', LIST_SKILLS_INPUTS);
94
+ declareRouteTool('get_skill', GET_SKILL_INPUTS);
52
95
 
53
96
  router.post(
54
97
  '/agent/tools/list_skills',
@@ -97,31 +140,74 @@ function branchArg(args: Record<string, unknown>): string | undefined {
97
140
  return typeof branch === 'string' && branch.trim().length > 0 ? branch : undefined;
98
141
  }
99
142
 
100
- /** "Currently available skills: `a`, `b`." (or a no-skills note), filtered to what the caller may read. */
101
- async function availableSkillsLine(skillService: ISkillService, userEmail?: string): Promise<string> {
143
+ /**
144
+ * "Currently available skills: `a`, `b`." (or a no-skills note), filtered to
145
+ * what the caller may read, and cut to `budget` characters: as many names as
146
+ * fit, then a count of the rest. The names are a convenience — `list_skills`
147
+ * is the complete answer — and a description a client cuts from the end
148
+ * would lose the tool's own tail to a catalog that grew; the budget is what
149
+ * the tool's fixed text leaves under {@link TOOL_DESCRIPTION_CAP} once the
150
+ * guide-first sentence the registry puts in front is counted.
151
+ */
152
+ async function availableSkillsLine(skillService: ISkillService, userEmail: string | undefined, budget: number): Promise<string> {
102
153
  const skills = await skillService.listSkills(userEmail);
103
154
  if (skills.length === 0) return 'No skills are currently available.';
104
- return `Currently available skills: ${skills.map((s) => `\`${s.name}\``).join(', ')}.`;
155
+ const names = skills.map((s) => `\`${s.name}\``);
156
+ const rest = (shown: number): string =>
157
+ shown < names.length ? `, and ${names.length - shown} more that list_skills names.` : '.';
158
+ const head = 'Currently available skills: ';
159
+ // The complete line first: it ends in a full stop, not in a count, so it
160
+ // can fit where a shorter list plus its "and N more" tail would not.
161
+ const complete = `${head}${names.join(', ')}.`;
162
+ if (complete.length <= budget) return complete;
163
+ // Otherwise one pass, accumulating: the cut is where the next name — with
164
+ // the separator before it and the tail that would follow it — no longer
165
+ // fits. (Rebuilding the joined prefix per candidate made this quadratic in
166
+ // the catalog's size, on every catalog listing.)
167
+ let shown = 0;
168
+ let length = head.length;
169
+ for (const name of names) {
170
+ const added = (shown > 0 ? 2 : 0) + name.length;
171
+ if (length + added + rest(shown + 1).length > budget) break;
172
+ length += added;
173
+ shown += 1;
174
+ }
175
+ if (shown === 0) {
176
+ return names.length === 1
177
+ ? '1 skill is currently available; list_skills names it.'
178
+ : `${names.length} skills are currently available; list_skills names them.`;
179
+ }
180
+ return `${head}${names.slice(0, shown).join(', ')}${rest(shown)}`;
105
181
  }
106
182
 
183
+ /**
184
+ * What the fixed part of a description leaves the skills line, with the
185
+ * `Call:` line ahead of everything (and the blank line after it) and the
186
+ * guide-first sentence counted. The call line is generated from the schema
187
+ * the tool advertises: its flat `inputs` inside the `body` envelope.
188
+ */
189
+ function skillsLineBudget(name: string, inputs: JsonSchema, fixed: string): number {
190
+ const call = callLine(`${EXTERNAL_KB_MANUAL_NAME}.${name}`, bodyEnvelope(inputs)).length + 2;
191
+ return TOOL_DESCRIPTION_CAP - call - GUIDE_FIRST_SENTENCE.length - 1 - fixed.length;
192
+ }
193
+
194
+ const LIST_SKILLS_DESCRIPTION =
195
+ 'List the available skills (reusable specialist instructions) with their names, descriptions and, ' +
196
+ 'for a skill that declares one, its current `version` (its SKILL.md `metadata.version`, else a ' +
197
+ 'top-level `version`, else `lifecycle.version`). ' +
198
+ 'Discover what skills exist before specialist work, then `get_skill` to load one. ' +
199
+ 'Pass `branch` to list the skills as they are on a draft branch instead of the released set — ' +
200
+ 'what you need to try a skill you just wrote there; each skill that differs from the released ' +
201
+ 'one comes back with `unmerged: true` and that branch, meaning nobody has approved it. ';
202
+
107
203
  async function buildListSkillsDef(skillService: ISkillService, userEmail?: string): Promise<UtcpTool> {
108
204
  return toolDef({
109
205
  name: 'list_skills',
110
206
  description:
111
- 'List the available skills (reusable specialist instructions) with their names, descriptions and, ' +
112
- 'for a skill that declares one, its current `version` (its SKILL.md `metadata.version`, else a ' +
113
- 'top-level `version`, else `lifecycle.version`). ' +
114
- 'Discover what skills exist before specialist work, then `get_skill` to load one. ' +
115
- 'Pass `branch` to list the skills as they are on a draft branch instead of the released set — ' +
116
- 'what you need to try a skill you just wrote there; each skill that differs from the released ' +
117
- 'one comes back with `unmerged: true` and that branch, meaning nobody has approved it. ' +
118
- (await availableSkillsLine(skillService, userEmail)),
207
+ LIST_SKILLS_DESCRIPTION +
208
+ (await availableSkillsLine(skillService, userEmail, skillsLineBudget('list_skills', LIST_SKILLS_INPUTS, LIST_SKILLS_DESCRIPTION))),
119
209
  path: '/api/agent/tools/list_skills',
120
- inputs: {
121
- type: 'object',
122
- properties: { branch: BRANCH_SKILLS_INPUT },
123
- additionalProperties: false,
124
- },
210
+ inputs: LIST_SKILLS_INPUTS,
125
211
  outputs: {
126
212
  type: 'object',
127
213
  properties: {
@@ -156,40 +242,20 @@ async function buildListSkillsDef(skillService: ISkillService, userEmail?: strin
156
242
  });
157
243
  }
158
244
 
245
+ const GET_SKILL_DESCRIPTION =
246
+ 'Load a skill by name: returns its full instructions (SKILL.md body) to follow, plus the skill ' +
247
+ 'folder path and the list of bundled files. Pass `file` to fetch a bundled file’s content ' +
248
+ '(e.g. a script) instead of the body. Loads the latest copy unless `version` names an earlier ' +
249
+ 'one the skill declared, or `branch` names a draft to load it from. ';
250
+
159
251
  async function buildGetSkillDef(skillService: ISkillService, userEmail?: string): Promise<UtcpTool> {
160
252
  return toolDef({
161
253
  name: 'get_skill',
162
254
  description:
163
- 'Load a skill by name: returns its full instructions (SKILL.md body) to follow, plus the skill ' +
164
- 'folder path and the list of bundled files. Pass `file` to fetch a bundled file’s content ' +
165
- '(e.g. a script) instead of the body. Loads the latest copy unless `version` names an earlier ' +
166
- 'one the skill declared, or `branch` names a draft to load it from. ' +
167
- (await availableSkillsLine(skillService, userEmail)),
255
+ GET_SKILL_DESCRIPTION +
256
+ (await availableSkillsLine(skillService, userEmail, skillsLineBudget('get_skill', GET_SKILL_INPUTS, GET_SKILL_DESCRIPTION))),
168
257
  path: '/api/agent/tools/get_skill',
169
- inputs: {
170
- type: 'object',
171
- properties: {
172
- name: { type: 'string', minLength: 1, description: 'Skill name (its folder name, e.g. `rfi`).' },
173
- file: {
174
- type: 'string',
175
- description:
176
- 'Optional bundled file path relative to the skill folder (e.g. `scripts/build_xlsx.py`) — ' +
177
- 'fetch its content instead of the body.',
178
- },
179
- version: {
180
- type: 'string',
181
- description:
182
- 'Optional: the declared version to load (e.g. `1.4.0` — the `version` that `list_skills` ' +
183
- 'reports: `metadata.version`, else `version`, else `lifecycle.version`). Omitted, the skill is loaded as it ' +
184
- 'is now, which is the latest. Given, the skill — or the `file` — is served as it was at the most ' +
185
- 'recent commit that declared that version; a version the skill never declared answers ' +
186
- '`version_not_found` with the versions it did declare.',
187
- },
188
- branch: BRANCH_SKILLS_INPUT,
189
- },
190
- required: ['name'],
191
- additionalProperties: false,
192
- },
258
+ inputs: GET_SKILL_INPUTS,
193
259
  outputs: {
194
260
  type: 'object',
195
261
  description: 'On success carries `skill` (or `file` when `file` was passed); on failure carries `error`.',
@@ -11,6 +11,7 @@ import type { AuthService } from '../../auth/auth.service.js';
11
11
  import { InternalTokenService } from '../internal-token.service.js';
12
12
  import { createManualAuthMiddleware, createToolAuthMiddleware } from '../tool-auth.middleware.js';
13
13
  import type { IExternalApiKeyService } from '../external-api-key.interface.js';
14
+ import { ACCOUNT_DEACTIVATED_MESSAGE } from '../../auth/account-admission.js';
14
15
 
15
16
  /**
16
17
  * A bearer shaped like a connection key that does not verify is answered with
@@ -24,6 +25,8 @@ import type { IExternalApiKeyService } from '../external-api-key.interface.js';
24
25
  * server requests, with the same gate `create-core-server.ts` puts on each.
25
26
  */
26
27
  const BAD_KEY = 'bevel_revokedKeyThatMustNeverBeEchoed';
28
+ /** A second refused key: on the switched-off service it is not one of a switched-off account. */
29
+ const OTHER_BAD_KEY = 'bevel_unknownKeyThatMustNeverBeEchoed';
27
30
  const RESOURCE_METADATA_URL = 'https://hexis.example/.well-known/oauth-protected-resource/api/mcp';
28
31
  const DISCOVERY_CHALLENGE = `Bearer realm="bevel-mcp", resource_metadata="${RESOURCE_METADATA_URL}"`;
29
32
  const KEY_CHALLENGE = 'Bearer error="invalid_token", error_description="Invalid or revoked connection key"';
@@ -190,3 +193,32 @@ describe('the REST agent surface keeps its challenge for everything but a key',
190
193
  }
191
194
  });
192
195
  });
196
+
197
+ describe('a live connection key whose account is switched off is told so', () => {
198
+ const switchedOffKeys = {
199
+ ...externalApiKeys,
200
+ isKeyOfSwitchedOffAccount: async (t: string) => t === BAD_KEY,
201
+ } as unknown as IExternalApiKeyService;
202
+
203
+ for (const endpoint of KEY_ENDPOINTS) {
204
+ it(`${endpoint.name}: 401 with the switched-off reason, not an invitation to mint a new key`, async () => {
205
+ const base = await start(switchedOffKeys);
206
+ const res = await call(base, endpoint.method, endpoint.path, BAD_KEY);
207
+ expect(res.status).toBe(401);
208
+ expect(res.headers.get('www-authenticate')).toBe(
209
+ 'Bearer error="invalid_token", error_description="The account of this connection key is switched off"',
210
+ );
211
+ expect(await res.json()).toEqual({ error: ACCOUNT_DEACTIVATED_MESSAGE });
212
+ expect(logged.join('\n')).not.toContain(BAD_KEY);
213
+ });
214
+
215
+ it(`${endpoint.name}: any other refused key on the same service is still told it is invalid`, async () => {
216
+ const base = await start(switchedOffKeys);
217
+ const res = await call(base, endpoint.method, endpoint.path, OTHER_BAD_KEY);
218
+ expect(res.status).toBe(401);
219
+ expect(res.headers.get('www-authenticate')).toBe(KEY_CHALLENGE);
220
+ expect(await res.json()).toEqual(KEY_BODY);
221
+ expect(logged.join('\n')).not.toContain(OTHER_BAD_KEY);
222
+ });
223
+ }
224
+ });
@@ -276,6 +276,71 @@ describe('ExternalApiKeyService', () => {
276
276
  expect(warn).toHaveBeenCalled();
277
277
  warn.mockRestore();
278
278
  });
279
+
280
+ /**
281
+ * A key's FIRST use is an agent arriving — what the onboarding waits for
282
+ * — so the owner is told once the stamp has landed, and once only. The
283
+ * first stamp is a CLAIM (`… where last_used_at is null … returning`):
284
+ * the request the database hands the row to announces, a racing one
285
+ * loses the claim, stamps the ordinary way and says nothing, and a key
286
+ * stamped before is touched without a word.
287
+ */
288
+ it("announces a key's first use to its owner once the claim has landed, and never otherwise", async () => {
289
+ const row = { tokenId: 'tok-1', label: 'Laptop', lastUsedAt: null, userId: 'user-7', email: 'a@x.io', name: 'Alice', avatarUrl: null };
290
+ const events = { emit: vi.fn() };
291
+ // The claim's answer is held back, to pin that the announcement waits for it.
292
+ let claimed!: (rows: { id: string }[]) => void;
293
+ const claim = new Promise<{ id: string }[]>((resolve) => (claimed = resolve));
294
+ const first = makeFakeDb([[row], claim]);
295
+ await new ExternalApiKeyService(first.db, 'bevel_', {}, events).verifyAndLoadUser('bevel_abc');
296
+ await flushMicrotasks();
297
+ expect(first.calls.update).toHaveLength(1);
298
+ expect(first.calls.set[0][0]).toHaveProperty('lastUsedAt');
299
+ expect(renderSql(first.calls.where[1][0]).sql).toMatch(/"api_tokens"."id" = \$1 and "api_tokens"."last_used_at" is null/);
300
+ expect(events.emit).not.toHaveBeenCalled();
301
+ claimed([{ id: 'tok-1' }]);
302
+ await flushMicrotasks();
303
+ expect(events.emit).toHaveBeenCalledTimes(1);
304
+ expect(events.emit).toHaveBeenCalledWith({
305
+ kind: 'agent-connected',
306
+ forUserId: 'user-7',
307
+ client: 'Laptop',
308
+ agentKind: 'key',
309
+ at: expect.stringMatching(/^\d{4}-\d{2}-\d{2}T/),
310
+ });
311
+
312
+ // A racing request lost the claim: the ordinary stamp, and no announcement.
313
+ const lost = makeFakeDb([[row], [], undefined]);
314
+ const lostEvents = { emit: vi.fn() };
315
+ await new ExternalApiKeyService(lost.db, 'bevel_', {}, lostEvents).verifyAndLoadUser('bevel_abc');
316
+ await flushMicrotasks();
317
+ expect(lost.calls.update).toHaveLength(2);
318
+ expect(lostEvents.emit).not.toHaveBeenCalled();
319
+
320
+ // A key stamped before: touched, and nobody is told.
321
+ const again = makeFakeDb([[{ ...row, lastUsedAt: new Date('2026-10-07T12:00:00Z') }], undefined]);
322
+ const laterEvents = { emit: vi.fn() };
323
+ await new ExternalApiKeyService(again.db, 'bevel_', {}, laterEvents).verifyAndLoadUser('bevel_abc');
324
+ await flushMicrotasks();
325
+ expect(again.calls.update).toHaveLength(1);
326
+ expect(laterEvents.emit).not.toHaveBeenCalled();
327
+ });
328
+
329
+ it('announces nothing when the first stamp could not be written', async () => {
330
+ const row = { tokenId: 'tok-1', label: 'Laptop', lastUsedAt: null, userId: 'user-7', email: 'a@x.io', name: 'Alice', avatarUrl: null };
331
+ let fail!: (err: Error) => void;
332
+ const claim = new Promise<{ id: string }[]>((_resolve, reject) => (fail = reject));
333
+ const { db } = makeFakeDb([[row], claim]);
334
+ const events = { emit: vi.fn() };
335
+ const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
336
+ const user = await new ExternalApiKeyService(db, 'bevel_', {}, events).verifyAndLoadUser('bevel_abc');
337
+ expect(user?.id).toBe('user-7');
338
+ fail(new Error('connection lost'));
339
+ await flushMicrotasks();
340
+ expect(events.emit).not.toHaveBeenCalled();
341
+ expect(warn).toHaveBeenCalled();
342
+ warn.mockRestore();
343
+ });
279
344
  });
280
345
 
281
346
  describe('listForUser', () => {
@@ -1,4 +1,5 @@
1
1
  import type { Response } from 'express';
2
+ import { ACCOUNT_DEACTIVATED_MESSAGE } from '../auth/account-admission.js';
2
3
 
3
4
  /**
4
5
  * How every key-authenticated endpoint answers a bearer that LOOKS like a
@@ -19,7 +20,16 @@ export const INVALID_CONNECTION_KEY_CHALLENGE =
19
20
  export const INVALID_CONNECTION_KEY_MESSAGE =
20
21
  'Invalid or revoked connection key. Mint a new one in External agent access.';
21
22
 
22
- export function rejectConnectionKey(res: Response): void {
23
- res.setHeader('WWW-Authenticate', INVALID_CONNECTION_KEY_CHALLENGE);
24
- res.status(401).json({ error: INVALID_CONNECTION_KEY_MESSAGE });
23
+ /**
24
+ * A live key whose account an admin switched off: still a plain
25
+ * `invalid_token` (no sign-in invitation, see above), but told the real
26
+ * reason — telling them to mint a new key would send them to something
27
+ * they cannot do.
28
+ */
29
+ export const SWITCHED_OFF_CONNECTION_KEY_CHALLENGE =
30
+ 'Bearer error="invalid_token", error_description="The account of this connection key is switched off"';
31
+
32
+ export function rejectConnectionKey(res: Response, opts: { switchedOff?: boolean } = {}): void {
33
+ res.setHeader('WWW-Authenticate', opts.switchedOff ? SWITCHED_OFF_CONNECTION_KEY_CHALLENGE : INVALID_CONNECTION_KEY_CHALLENGE);
34
+ res.status(401).json({ error: opts.switchedOff ? ACCOUNT_DEACTIVATED_MESSAGE : INVALID_CONNECTION_KEY_MESSAGE });
25
35
  }
@@ -140,6 +140,15 @@ export interface IExternalApiKeyService {
140
140
  plaintext: string,
141
141
  ): Promise<{ tokenId: string; user: AuthUser } | null>;
142
142
 
143
+ /**
144
+ * For a key {@link verifyAndLoadToken} refused: whether it is a live key
145
+ * whose account an admin switched off — the one refusal its holder must
146
+ * not be told to mint a new key over (they cannot; the account is off).
147
+ * Asked only on the refusal path, so a working key costs nothing more.
148
+ * Optional: without it every refused key is reported as invalid.
149
+ */
150
+ isKeyOfSwitchedOffAccount?(plaintext: string): Promise<boolean>;
151
+
143
152
  /** Active + revoked tokens for the user, newest-first. */
144
153
  listForUser(userId: string): Promise<ExternalApiKeySummary[]>;
145
154
 
@@ -3,7 +3,7 @@ import { logger } from '../../shared/logging.js';
3
3
 
4
4
  const log = logger('external-api-key');
5
5
  import { and, desc, eq, isNotNull, isNull, type SQL } from 'drizzle-orm';
6
- import type { AuthUser } from '@bevel-software/platform-shared';
6
+ import type { AgentConnectedEvent, AuthUser } from '@bevel-software/platform-shared';
7
7
  import type { Database } from '../database/connection.js';
8
8
  import { externalApiKeys, users } from '../database/schema.js';
9
9
  import {
@@ -51,6 +51,12 @@ export class ExternalApiKeyService implements IExternalApiKeyService {
51
51
  private readonly db: Database,
52
52
  private readonly keyPrefix: string,
53
53
  private readonly kinds: Readonly<Record<string, KeyKindSpec>> = {},
54
+ /**
55
+ * Where a key's FIRST use is announced to its owner (`agent-connected`,
56
+ * see `verifyAndLoadToken`). Optional: without it the stamp is written
57
+ * and nobody is told.
58
+ */
59
+ private readonly events?: { emit(event: AgentConnectedEvent): void },
54
60
  ) {
55
61
  this.prefixes = [keyPrefix, ...Object.values(kinds).map((k) => k.prefix)];
56
62
  }
@@ -97,6 +103,19 @@ export class ExternalApiKeyService implements IExternalApiKeyService {
97
103
  return resolved ? resolved.user : null;
98
104
  }
99
105
 
106
+ async isKeyOfSwitchedOffAccount(plaintext: string): Promise<boolean> {
107
+ if (!this.looksLikeExternalApiKey(plaintext)) return false;
108
+ // The same key `verifyAndLoadToken` would accept (known, not revoked),
109
+ // but on an account that is off.
110
+ const [row] = await this.db
111
+ .select({ id: externalApiKeys.id })
112
+ .from(externalApiKeys)
113
+ .innerJoin(users, eq(externalApiKeys.userId, users.id))
114
+ .where(and(eq(externalApiKeys.tokenHash, hashToken(plaintext)), isNull(externalApiKeys.revokedAt), isNotNull(users.deactivatedAt)))
115
+ .limit(1);
116
+ return row !== undefined;
117
+ }
118
+
100
119
  async verifyAndLoadToken(
101
120
  plaintext: string,
102
121
  ): Promise<{ tokenId: string; user: AuthUser } | null> {
@@ -114,6 +133,8 @@ export class ExternalApiKeyService implements IExternalApiKeyService {
114
133
  const [row] = await this.db
115
134
  .select({
116
135
  tokenId: externalApiKeys.id,
136
+ label: externalApiKeys.label,
137
+ lastUsedAt: externalApiKeys.lastUsedAt,
117
138
  userId: users.id,
118
139
  email: users.email,
119
140
  name: users.name,
@@ -130,9 +151,28 @@ export class ExternalApiKeyService implements IExternalApiKeyService {
130
151
  // the UPDATE. A failed touch is logged but never blocks the caller —
131
152
  // the worst case is a slightly stale `last_used_at`, which is fine for
132
153
  // a "when was this key last used" audit view.
133
- this.touchLastUsed(row.tokenId).catch((err) => {
134
- log.warn('touchLastUsed failed:', { err });
135
- });
154
+ //
155
+ // A key's FIRST use is an agent that has just reached the platform —
156
+ // what the onboarding waits for — so its owner is told once the stamp
157
+ // has landed. A key never stamped is CLAIMED (`claimFirstUse`), so of
158
+ // two requests racing its first use exactly one announces it; a key
159
+ // stamped before is touched and nobody is told.
160
+ const stamped = row.lastUsedAt === null ? this.claimFirstUse(row.tokenId) : this.touchLastUsed(row.tokenId).then(() => false);
161
+ stamped.then(
162
+ (first) => {
163
+ if (!first) return;
164
+ this.events?.emit({
165
+ kind: 'agent-connected',
166
+ forUserId: row.userId,
167
+ client: row.label,
168
+ agentKind: 'key',
169
+ at: new Date().toISOString(),
170
+ });
171
+ },
172
+ (err) => {
173
+ log.warn('touchLastUsed failed:', { err });
174
+ },
175
+ );
136
176
 
137
177
  return {
138
178
  tokenId: row.tokenId,
@@ -280,6 +320,23 @@ export class ExternalApiKeyService implements IExternalApiKeyService {
280
320
  .set({ lastUsedAt: new Date() })
281
321
  .where(eq(externalApiKeys.id, tokenId));
282
322
  }
323
+
324
+ /**
325
+ * The first stamp as ONE statement: the row is taken only while
326
+ * `last_used_at` is still null, so of two requests (or two replicas)
327
+ * racing a key's first use the database hands it to exactly one, which
328
+ * answers true. The loser stamps the ordinary way and answers false.
329
+ */
330
+ private async claimFirstUse(tokenId: string): Promise<boolean> {
331
+ const won = await this.db
332
+ .update(externalApiKeys)
333
+ .set({ lastUsedAt: new Date() })
334
+ .where(and(eq(externalApiKeys.id, tokenId), isNull(externalApiKeys.lastUsedAt)))
335
+ .returning({ id: externalApiKeys.id });
336
+ if (won.length > 0) return true;
337
+ await this.touchLastUsed(tokenId);
338
+ return false;
339
+ }
283
340
  }
284
341
 
285
342
  function hashToken(plaintext: string): string {
@@ -6,7 +6,11 @@ import type { IExternalApiKeyService } from './external-api-key.interface.js';
6
6
  import type { AuthService } from '../auth/auth.service.js';
7
7
  import { ACCOUNT_DEACTIVATED_MESSAGE, AuthBackendError } from '../auth/account-admission.js';
8
8
  import { InternalTokenService } from './internal-token.service.js';
9
- import { INVALID_CONNECTION_KEY_CHALLENGE, INVALID_CONNECTION_KEY_MESSAGE } from './connection-key-rejection.js';
9
+ import {
10
+ INVALID_CONNECTION_KEY_CHALLENGE,
11
+ INVALID_CONNECTION_KEY_MESSAGE,
12
+ SWITCHED_OFF_CONNECTION_KEY_CHALLENGE,
13
+ } from './connection-key-rejection.js';
10
14
 
11
15
  /**
12
16
  * What the `toolAuth` middleware resolves a bearer to, before the per-call
@@ -165,9 +169,14 @@ export function createTokenVerifier(
165
169
  // External API key → external caller. (verifyAndLoadToken may throw → propagates → caller maps to 500.)
166
170
  if (externalApiKeyService.looksLikeExternalApiKey(token)) {
167
171
  const resolved = await externalApiKeyService.verifyAndLoadToken(token);
168
- return resolved
169
- ? { ok: true, auth: { source: 'external', userId: resolved.user.id, tokenId: resolved.tokenId, scope: 'write' } }
170
- : { ok: false, status: 401, message: INVALID_CONNECTION_KEY_MESSAGE, challenge: INVALID_CONNECTION_KEY_CHALLENGE };
172
+ if (resolved) {
173
+ return { ok: true, auth: { source: 'external', userId: resolved.user.id, tokenId: resolved.tokenId, scope: 'write' } };
174
+ }
175
+ // A live key of a switched-off account is told so, not sent to mint another.
176
+ if (await externalApiKeyService.isKeyOfSwitchedOffAccount?.(token)) {
177
+ return { ok: false, status: 401, message: ACCOUNT_DEACTIVATED_MESSAGE, challenge: SWITCHED_OFF_CONNECTION_KEY_CHALLENGE };
178
+ }
179
+ return { ok: false, status: 401, message: INVALID_CONNECTION_KEY_MESSAGE, challenge: INVALID_CONNECTION_KEY_CHALLENGE };
171
180
  }
172
181
 
173
182
  return missing;