@bevel-software/platform-core-backend 0.26.0 → 0.28.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 (681) hide show
  1. package/agent-guide/access-control.md +17 -0
  2. package/agent-guide/conventions.md +8 -0
  3. package/agent-guide/html-views.md +83 -0
  4. package/agent-guide/new-knowledge-base.md +24 -0
  5. package/agent-guide/tool-manuals.md +10 -0
  6. package/dist/assets.d.ts +19 -0
  7. package/dist/assets.d.ts.map +1 -1
  8. package/dist/assets.js +26 -2
  9. package/dist/assets.js.map +1 -1
  10. package/dist/core/catalog-revision.d.ts +19 -1
  11. package/dist/core/catalog-revision.d.ts.map +1 -1
  12. package/dist/core/catalog-revision.js +14 -3
  13. package/dist/core/catalog-revision.js.map +1 -1
  14. package/dist/core/create-core-server.d.ts +5 -0
  15. package/dist/core/create-core-server.d.ts.map +1 -1
  16. package/dist/core/create-core-server.js +56 -5
  17. package/dist/core/create-core-server.js.map +1 -1
  18. package/dist/core/create-core-services.d.ts +33 -0
  19. package/dist/core/create-core-services.d.ts.map +1 -1
  20. package/dist/core/create-core-services.js +105 -8
  21. package/dist/core/create-core-services.js.map +1 -1
  22. package/dist/core/lifecycle.d.ts +16 -1
  23. package/dist/core/lifecycle.d.ts.map +1 -1
  24. package/dist/core/lifecycle.js +18 -1
  25. package/dist/core/lifecycle.js.map +1 -1
  26. package/dist/core-config.d.ts +21 -0
  27. package/dist/core-config.d.ts.map +1 -1
  28. package/dist/core-config.js +22 -1
  29. package/dist/core-config.js.map +1 -1
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +2 -2
  33. package/dist/index.js.map +1 -1
  34. package/dist/modules/access/access-control.interface.d.ts +17 -0
  35. package/dist/modules/access/access-control.interface.d.ts.map +1 -1
  36. package/dist/modules/access/access-control.service.d.ts +2 -0
  37. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  38. package/dist/modules/access/access-control.service.js +31 -0
  39. package/dist/modules/access/access-control.service.js.map +1 -1
  40. package/dist/modules/access/access.routes.d.ts +4 -1
  41. package/dist/modules/access/access.routes.d.ts.map +1 -1
  42. package/dist/modules/access/access.routes.js +66 -7
  43. package/dist/modules/access/access.routes.js.map +1 -1
  44. package/dist/modules/access/directory-sync-bot.js +1 -1
  45. package/dist/modules/access/directory-sync-bot.js.map +1 -1
  46. package/dist/modules/access/roles-admin.service.d.ts +35 -6
  47. package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
  48. package/dist/modules/access/roles-admin.service.js +36 -9
  49. package/dist/modules/access/roles-admin.service.js.map +1 -1
  50. package/dist/modules/access/user-access-removal.service.js +1 -1
  51. package/dist/modules/access/user-access-removal.service.js.map +1 -1
  52. package/dist/modules/agent-guide/agent-guide.d.ts +6 -0
  53. package/dist/modules/agent-guide/agent-guide.d.ts.map +1 -1
  54. package/dist/modules/agent-guide/agent-guide.js +8 -0
  55. package/dist/modules/agent-guide/agent-guide.js.map +1 -1
  56. package/dist/modules/agent-guide/index.d.ts +1 -1
  57. package/dist/modules/agent-guide/index.d.ts.map +1 -1
  58. package/dist/modules/agent-guide/index.js +1 -1
  59. package/dist/modules/agent-guide/index.js.map +1 -1
  60. package/dist/modules/agent-instructions/compose.d.ts +5 -0
  61. package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
  62. package/dist/modules/agent-instructions/compose.js +19 -2
  63. package/dist/modules/agent-instructions/compose.js.map +1 -1
  64. package/dist/modules/agent-instructions/shared-file-rules.js +19 -19
  65. package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -1
  66. package/dist/modules/audit/agent-audit.service.d.ts +21 -2
  67. package/dist/modules/audit/agent-audit.service.d.ts.map +1 -1
  68. package/dist/modules/audit/agent-audit.service.js +43 -2
  69. package/dist/modules/audit/agent-audit.service.js.map +1 -1
  70. package/dist/modules/audit/agent-connection.routes.d.ts +34 -0
  71. package/dist/modules/audit/agent-connection.routes.d.ts.map +1 -0
  72. package/dist/modules/audit/agent-connection.routes.js +38 -0
  73. package/dist/modules/audit/agent-connection.routes.js.map +1 -0
  74. package/dist/modules/audit/audit.contract.d.ts +24 -0
  75. package/dist/modules/audit/audit.contract.d.ts.map +1 -1
  76. package/dist/modules/audit/audit.contract.js.map +1 -1
  77. package/dist/modules/audit/index.d.ts +1 -0
  78. package/dist/modules/audit/index.d.ts.map +1 -1
  79. package/dist/modules/audit/index.js +1 -0
  80. package/dist/modules/audit/index.js.map +1 -1
  81. package/dist/modules/auth/account-hooks.d.ts +46 -0
  82. package/dist/modules/auth/account-hooks.d.ts.map +1 -0
  83. package/dist/modules/auth/account-hooks.js +25 -0
  84. package/dist/modules/auth/account-hooks.js.map +1 -0
  85. package/dist/modules/auth/account-switch-guard.d.ts +15 -0
  86. package/dist/modules/auth/account-switch-guard.d.ts.map +1 -0
  87. package/dist/modules/auth/account-switch-guard.js +2 -0
  88. package/dist/modules/auth/account-switch-guard.js.map +1 -0
  89. package/dist/modules/auth/account-switch-lock.d.ts +34 -0
  90. package/dist/modules/auth/account-switch-lock.d.ts.map +1 -0
  91. package/dist/modules/auth/account-switch-lock.js +48 -0
  92. package/dist/modules/auth/account-switch-lock.js.map +1 -0
  93. package/dist/modules/auth/account.routes.d.ts +4 -1
  94. package/dist/modules/auth/account.routes.d.ts.map +1 -1
  95. package/dist/modules/auth/account.routes.js +110 -13
  96. package/dist/modules/auth/account.routes.js.map +1 -1
  97. package/dist/modules/auth/auth.middleware.d.ts +7 -0
  98. package/dist/modules/auth/auth.middleware.d.ts.map +1 -1
  99. package/dist/modules/auth/auth.middleware.js +1 -1
  100. package/dist/modules/auth/auth.middleware.js.map +1 -1
  101. package/dist/modules/auth/auth.service.d.ts +101 -6
  102. package/dist/modules/auth/auth.service.d.ts.map +1 -1
  103. package/dist/modules/auth/auth.service.js +246 -51
  104. package/dist/modules/auth/auth.service.js.map +1 -1
  105. package/dist/modules/auth/password-hash.d.ts +5 -2
  106. package/dist/modules/auth/password-hash.d.ts.map +1 -1
  107. package/dist/modules/auth/password-hash.js +5 -2
  108. package/dist/modules/auth/password-hash.js.map +1 -1
  109. package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -1
  110. package/dist/modules/code-mode/code-mode.tool.js +11 -3
  111. package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
  112. package/dist/modules/database/core-schema.d.ts +96 -0
  113. package/dist/modules/database/core-schema.d.ts.map +1 -1
  114. package/dist/modules/database/core-schema.js +32 -3
  115. package/dist/modules/database/core-schema.js.map +1 -1
  116. package/dist/modules/database/pg-error.d.ts +9 -0
  117. package/dist/modules/database/pg-error.d.ts.map +1 -0
  118. package/dist/modules/database/pg-error.js +17 -0
  119. package/dist/modules/database/pg-error.js.map +1 -0
  120. package/dist/modules/embed/account-link.service.d.ts +42 -0
  121. package/dist/modules/embed/account-link.service.d.ts.map +1 -0
  122. package/dist/modules/embed/account-link.service.js +50 -0
  123. package/dist/modules/embed/account-link.service.js.map +1 -0
  124. package/dist/modules/embed/embed-link.d.ts +58 -0
  125. package/dist/modules/embed/embed-link.d.ts.map +1 -0
  126. package/dist/modules/embed/embed-link.js +160 -0
  127. package/dist/modules/embed/embed-link.js.map +1 -0
  128. package/dist/modules/embed/embed.errors.d.ts +30 -0
  129. package/dist/modules/embed/embed.errors.d.ts.map +1 -0
  130. package/dist/modules/embed/embed.errors.js +42 -0
  131. package/dist/modules/embed/embed.errors.js.map +1 -0
  132. package/dist/modules/embed/embed.interface.d.ts +204 -0
  133. package/dist/modules/embed/embed.interface.d.ts.map +1 -0
  134. package/dist/modules/embed/embed.interface.js +2 -0
  135. package/dist/modules/embed/embed.interface.js.map +1 -0
  136. package/dist/modules/embed/embed.routes.d.ts +59 -0
  137. package/dist/modules/embed/embed.routes.d.ts.map +1 -0
  138. package/dist/modules/embed/embed.routes.js +343 -0
  139. package/dist/modules/embed/embed.routes.js.map +1 -0
  140. package/dist/modules/embed/embed.service.d.ts +169 -0
  141. package/dist/modules/embed/embed.service.d.ts.map +1 -0
  142. package/dist/modules/embed/embed.service.js +627 -0
  143. package/dist/modules/embed/embed.service.js.map +1 -0
  144. package/dist/modules/embed/embed.tools.d.ts +51 -0
  145. package/dist/modules/embed/embed.tools.d.ts.map +1 -0
  146. package/dist/modules/embed/embed.tools.js +170 -0
  147. package/dist/modules/embed/embed.tools.js.map +1 -0
  148. package/dist/modules/embed/mcp-app.d.ts +64 -0
  149. package/dist/modules/embed/mcp-app.d.ts.map +1 -0
  150. package/dist/modules/embed/mcp-app.js +147 -0
  151. package/dist/modules/embed/mcp-app.js.map +1 -0
  152. package/dist/modules/embed/mcp-app.routes.d.ts +21 -0
  153. package/dist/modules/embed/mcp-app.routes.d.ts.map +1 -0
  154. package/dist/modules/embed/mcp-app.routes.js +36 -0
  155. package/dist/modules/embed/mcp-app.routes.js.map +1 -0
  156. package/dist/modules/github-app/github-app.connection.d.ts +15 -0
  157. package/dist/modules/github-app/github-app.connection.d.ts.map +1 -1
  158. package/dist/modules/github-app/github-app.connection.js +34 -3
  159. package/dist/modules/github-app/github-app.connection.js.map +1 -1
  160. package/dist/modules/kb-fs/locking-filesystem.d.ts +65 -0
  161. package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
  162. package/dist/modules/kb-fs/locking-filesystem.js +300 -0
  163. package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
  164. package/dist/modules/kb-sync/kb-sync.interface.d.ts +5 -0
  165. package/dist/modules/kb-sync/kb-sync.interface.d.ts.map +1 -1
  166. package/dist/modules/kb-sync/kb-sync.service.d.ts.map +1 -1
  167. package/dist/modules/kb-sync/kb-sync.service.js +6 -0
  168. package/dist/modules/kb-sync/kb-sync.service.js.map +1 -1
  169. package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
  170. package/dist/modules/mcp/mcp-auth.middleware.js +2 -1
  171. package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
  172. package/dist/modules/mcp/mcp.service.d.ts +28 -1
  173. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  174. package/dist/modules/mcp/mcp.service.js +64 -8
  175. package/dist/modules/mcp/mcp.service.js.map +1 -1
  176. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +24 -0
  177. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
  178. package/dist/modules/mcp/oauth/bevel-oauth-provider.js +32 -4
  179. package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
  180. package/dist/modules/onboarding/onboarding.contract.d.ts +80 -0
  181. package/dist/modules/onboarding/onboarding.contract.d.ts.map +1 -0
  182. package/dist/modules/onboarding/onboarding.contract.js +7 -0
  183. package/dist/modules/onboarding/onboarding.contract.js.map +1 -0
  184. package/dist/modules/onboarding/onboarding.routes.d.ts +18 -0
  185. package/dist/modules/onboarding/onboarding.routes.d.ts.map +1 -0
  186. package/dist/modules/onboarding/onboarding.routes.js +81 -0
  187. package/dist/modules/onboarding/onboarding.routes.js.map +1 -0
  188. package/dist/modules/onboarding/starter-pack.service.d.ts +213 -0
  189. package/dist/modules/onboarding/starter-pack.service.d.ts.map +1 -0
  190. package/dist/modules/onboarding/starter-pack.service.js +492 -0
  191. package/dist/modules/onboarding/starter-pack.service.js.map +1 -0
  192. package/dist/modules/onboarding/starter-packs.d.ts +78 -0
  193. package/dist/modules/onboarding/starter-packs.d.ts.map +1 -0
  194. package/dist/modules/onboarding/starter-packs.js +156 -0
  195. package/dist/modules/onboarding/starter-packs.js.map +1 -0
  196. package/dist/modules/plugins/index.d.ts +1 -1
  197. package/dist/modules/plugins/index.d.ts.map +1 -1
  198. package/dist/modules/plugins/index.js +1 -1
  199. package/dist/modules/plugins/index.js.map +1 -1
  200. package/dist/modules/plugins/plugin-provision.service.d.ts +19 -0
  201. package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
  202. package/dist/modules/plugins/plugin-provision.service.js +18 -1
  203. package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
  204. package/dist/modules/plugins/plugins.routes.d.ts +0 -36
  205. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  206. package/dist/modules/plugins/plugins.routes.js +31 -0
  207. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  208. package/dist/modules/settings/deployment-settings.service.d.ts +34 -0
  209. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  210. package/dist/modules/settings/deployment-settings.service.js +134 -1
  211. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  212. package/dist/modules/settings/repository-source.d.ts +1 -0
  213. package/dist/modules/settings/repository-source.d.ts.map +1 -1
  214. package/dist/modules/settings/repository-source.js +3 -3
  215. package/dist/modules/settings/repository-source.js.map +1 -1
  216. package/dist/modules/skills/skills.tools.d.ts.map +1 -1
  217. package/dist/modules/skills/skills.tools.js +50 -32
  218. package/dist/modules/skills/skills.tools.js.map +1 -1
  219. package/dist/modules/tool-auth/connection-key-rejection.d.ts +10 -1
  220. package/dist/modules/tool-auth/connection-key-rejection.d.ts.map +1 -1
  221. package/dist/modules/tool-auth/connection-key-rejection.js +11 -3
  222. package/dist/modules/tool-auth/connection-key-rejection.js.map +1 -1
  223. package/dist/modules/tool-auth/external-api-key.interface.d.ts +8 -0
  224. package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
  225. package/dist/modules/tool-auth/external-api-key.service.d.ts +24 -2
  226. package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
  227. package/dist/modules/tool-auth/external-api-key.service.js +59 -2
  228. package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
  229. package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
  230. package/dist/modules/tool-auth/tool-auth.middleware.js +9 -4
  231. package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
  232. package/dist/modules/tool-helpers/index.d.ts +28 -1
  233. package/dist/modules/tool-helpers/index.d.ts.map +1 -1
  234. package/dist/modules/tool-helpers/index.js +28 -1
  235. package/dist/modules/tool-helpers/index.js.map +1 -1
  236. package/dist/modules/tool-helpers/route-argument-check.d.ts +10 -0
  237. package/dist/modules/tool-helpers/route-argument-check.d.ts.map +1 -0
  238. package/dist/modules/tool-helpers/route-argument-check.js +132 -0
  239. package/dist/modules/tool-helpers/route-argument-check.js.map +1 -0
  240. package/dist/modules/tool-helpers/route-tool-schemas.d.ts +89 -0
  241. package/dist/modules/tool-helpers/route-tool-schemas.d.ts.map +1 -0
  242. package/dist/modules/tool-helpers/route-tool-schemas.js +113 -0
  243. package/dist/modules/tool-helpers/route-tool-schemas.js.map +1 -0
  244. package/dist/modules/tool-helpers/tool-def.d.ts +71 -0
  245. package/dist/modules/tool-helpers/tool-def.d.ts.map +1 -1
  246. package/dist/modules/tool-helpers/tool-def.js +70 -6
  247. package/dist/modules/tool-helpers/tool-def.js.map +1 -1
  248. package/dist/modules/tool-helpers/tool-handler.d.ts +46 -6
  249. package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
  250. package/dist/modules/tool-helpers/tool-handler.js +157 -8
  251. package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
  252. package/dist/modules/tool-helpers/tool.contract.d.ts +9 -0
  253. package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
  254. package/dist/modules/tool-helpers/tool.contract.js.map +1 -1
  255. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  256. package/dist/modules/tool-manuals/tool-manuals.tools.js +14 -5
  257. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  258. package/dist/modules/tool-registry/description-length.d.ts +6 -2
  259. package/dist/modules/tool-registry/description-length.d.ts.map +1 -1
  260. package/dist/modules/tool-registry/description-length.js +27 -5
  261. package/dist/modules/tool-registry/description-length.js.map +1 -1
  262. package/dist/modules/tool-registry/guide-first.d.ts +4 -0
  263. package/dist/modules/tool-registry/guide-first.d.ts.map +1 -1
  264. package/dist/modules/tool-registry/guide-first.js +9 -1
  265. package/dist/modules/tool-registry/guide-first.js.map +1 -1
  266. package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts +53 -0
  267. package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts.map +1 -1
  268. package/dist/modules/workflow/agent-tools/change-request-read.tools.js +97 -68
  269. package/dist/modules/workflow/agent-tools/change-request-read.tools.js.map +1 -1
  270. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +8 -1
  271. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  272. package/dist/modules/workflow/agent-tools/workflow.tools.js +124 -37
  273. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  274. package/dist/modules/workflow/file-lock.service.d.ts +29 -5
  275. package/dist/modules/workflow/file-lock.service.d.ts.map +1 -1
  276. package/dist/modules/workflow/file-lock.service.js +62 -5
  277. package/dist/modules/workflow/file-lock.service.js.map +1 -1
  278. package/dist/modules/workflow/git/git.service.d.ts +72 -1
  279. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  280. package/dist/modules/workflow/git/git.service.js +172 -36
  281. package/dist/modules/workflow/git/git.service.js.map +1 -1
  282. package/dist/modules/workflow/git/node-git-runner.d.ts +15 -0
  283. package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -1
  284. package/dist/modules/workflow/git/node-git-runner.js +78 -6
  285. package/dist/modules/workflow/git/node-git-runner.js.map +1 -1
  286. package/dist/modules/workflow/pending-commits.service.d.ts +15 -0
  287. package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -1
  288. package/dist/modules/workflow/pending-commits.service.js +25 -1
  289. package/dist/modules/workflow/pending-commits.service.js.map +1 -1
  290. package/dist/modules/workflow/pending-commits.worker.d.ts +6 -1
  291. package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -1
  292. package/dist/modules/workflow/pending-commits.worker.js +23 -6
  293. package/dist/modules/workflow/pending-commits.worker.js.map +1 -1
  294. package/dist/modules/workflow/recovery-bot.js +1 -1
  295. package/dist/modules/workflow/recovery-bot.js.map +1 -1
  296. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
  297. package/dist/modules/workflow/review-workflow/review-workflow.service.js +2 -1
  298. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
  299. package/dist/modules/workflow/sanitize-error.d.ts +16 -0
  300. package/dist/modules/workflow/sanitize-error.d.ts.map +1 -1
  301. package/dist/modules/workflow/sanitize-error.js +45 -0
  302. package/dist/modules/workflow/sanitize-error.js.map +1 -1
  303. package/dist/modules/workflow/workflow.service.d.ts +183 -15
  304. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  305. package/dist/modules/workflow/workflow.service.js +807 -107
  306. package/dist/modules/workflow/workflow.service.js.map +1 -1
  307. package/dist/modules/workspace/agent-download.builder.d.ts +105 -0
  308. package/dist/modules/workspace/agent-download.builder.d.ts.map +1 -0
  309. package/dist/modules/workspace/agent-download.builder.js +238 -0
  310. package/dist/modules/workspace/agent-download.builder.js.map +1 -0
  311. package/dist/modules/workspace/agent-download.routes.d.ts +77 -0
  312. package/dist/modules/workspace/agent-download.routes.d.ts.map +1 -0
  313. package/dist/modules/workspace/agent-download.routes.js +156 -0
  314. package/dist/modules/workspace/agent-download.routes.js.map +1 -0
  315. package/dist/modules/workspace/agent-download.store.d.ts +225 -0
  316. package/dist/modules/workspace/agent-download.store.d.ts.map +1 -0
  317. package/dist/modules/workspace/agent-download.store.js +423 -0
  318. package/dist/modules/workspace/agent-download.store.js.map +1 -0
  319. package/dist/modules/workspace/agent-upload.store.d.ts +10 -1
  320. package/dist/modules/workspace/agent-upload.store.d.ts.map +1 -1
  321. package/dist/modules/workspace/agent-upload.store.js +16 -6
  322. package/dist/modules/workspace/agent-upload.store.js.map +1 -1
  323. package/dist/modules/workspace/file-readers/raw-mime.d.ts +6 -0
  324. package/dist/modules/workspace/file-readers/raw-mime.d.ts.map +1 -0
  325. package/dist/modules/workspace/file-readers/raw-mime.js +38 -0
  326. package/dist/modules/workspace/file-readers/raw-mime.js.map +1 -0
  327. package/dist/modules/workspace/file-readers/text-reader.d.ts +5 -5
  328. package/dist/modules/workspace/file-readers/text-reader.d.ts.map +1 -1
  329. package/dist/modules/workspace/file-readers/text-reader.js +5 -8
  330. package/dist/modules/workspace/file-readers/text-reader.js.map +1 -1
  331. package/dist/modules/workspace/first-run.d.ts +111 -0
  332. package/dist/modules/workspace/first-run.d.ts.map +1 -0
  333. package/dist/modules/workspace/first-run.js +181 -0
  334. package/dist/modules/workspace/first-run.js.map +1 -0
  335. package/dist/modules/workspace/move-links.d.ts +92 -0
  336. package/dist/modules/workspace/move-links.d.ts.map +1 -0
  337. package/dist/modules/workspace/move-links.js +173 -0
  338. package/dist/modules/workspace/move-links.js.map +1 -0
  339. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  340. package/dist/modules/workspace/startup/steps/seed-tree.js +3 -13
  341. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  342. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  343. package/dist/modules/workspace/workspace.routes.js +63 -22
  344. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  345. package/dist/modules/workspace/workspace.service.d.ts +75 -2
  346. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  347. package/dist/modules/workspace/workspace.service.js +197 -24
  348. package/dist/modules/workspace/workspace.service.js.map +1 -1
  349. package/dist/modules/workspace/workspace.tools.d.ts +59 -1
  350. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  351. package/dist/modules/workspace/workspace.tools.js +443 -65
  352. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  353. package/dist/modules/write-access/write-access.d.ts.map +1 -1
  354. package/dist/modules/write-access/write-access.js +9 -0
  355. package/dist/modules/write-access/write-access.js.map +1 -1
  356. package/dist/shared/domain-errors.d.ts +73 -1
  357. package/dist/shared/domain-errors.d.ts.map +1 -1
  358. package/dist/shared/domain-errors.js +86 -12
  359. package/dist/shared/domain-errors.js.map +1 -1
  360. package/dist/shared/git.contract.d.ts +10 -1
  361. package/dist/shared/git.contract.d.ts.map +1 -1
  362. package/dist/shared/git.contract.js.map +1 -1
  363. package/dist/shared/utf8-text.d.ts +15 -0
  364. package/dist/shared/utf8-text.d.ts.map +1 -0
  365. package/dist/shared/utf8-text.js +20 -0
  366. package/dist/shared/utf8-text.js.map +1 -0
  367. package/dist/tenancy/static-tenant-source.d.ts +2 -1
  368. package/dist/tenancy/static-tenant-source.d.ts.map +1 -1
  369. package/dist/tenancy/static-tenant-source.js +9 -2
  370. package/dist/tenancy/static-tenant-source.js.map +1 -1
  371. package/mcp-app/page.html +349 -0
  372. package/migrations/0017_atlassian_account_links.sql +37 -0
  373. package/migrations/meta/0017_snapshot.json +2396 -0
  374. package/migrations/meta/_journal.json +8 -1
  375. package/package.json +5 -3
  376. package/src/__tests__/packaged-assets-ship.test.ts +16 -4
  377. package/src/__tests__/pg-scratch.ts +48 -0
  378. package/src/assets.ts +28 -2
  379. package/src/core/__tests__/catalog-revision.test.ts +40 -0
  380. package/src/core/__tests__/gated-boot.test.ts +1 -0
  381. package/src/core/__tests__/lifecycle.test.ts +14 -0
  382. package/src/core/catalog-revision.ts +15 -2
  383. package/src/core/create-core-server.ts +69 -3
  384. package/src/core/create-core-services.ts +151 -6
  385. package/src/core/lifecycle.ts +28 -2
  386. package/src/core-config.ts +24 -1
  387. package/src/index.ts +2 -2
  388. package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +1 -0
  389. package/src/modules/access/__tests__/access-control.service.test.ts +19 -0
  390. package/src/modules/access/__tests__/access.routes.admins.test.ts +203 -0
  391. package/src/modules/access/__tests__/access.routes.batch.test.ts +25 -5
  392. package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +1 -0
  393. package/src/modules/access/__tests__/access.routes.group-grant.test.ts +1 -1
  394. package/src/modules/access/__tests__/access.routes.overrides.test.ts +1 -1
  395. package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +1 -0
  396. package/src/modules/access/__tests__/access.routes.prospective.test.ts +1 -0
  397. package/src/modules/access/__tests__/access.routes.revoke.test.ts +1 -1
  398. package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +1 -0
  399. package/src/modules/access/__tests__/roles-admin.security.test.ts +1 -1
  400. package/src/modules/access/__tests__/roles-admin.service.test.ts +15 -2
  401. package/src/modules/access/__tests__/roles.routes.test.ts +132 -7
  402. package/src/modules/access/__tests__/user-access-removal.service.test.ts +2 -2
  403. package/src/modules/access/__tests__/users-db-double.ts +12 -3
  404. package/src/modules/access/access-control.interface.ts +23 -0
  405. package/src/modules/access/access-control.service.ts +35 -0
  406. package/src/modules/access/access.routes.ts +67 -6
  407. package/src/modules/access/directory-sync-bot.ts +1 -1
  408. package/src/modules/access/roles-admin.service.ts +51 -11
  409. package/src/modules/access/user-access-removal.service.ts +1 -1
  410. package/src/modules/agent-guide/__tests__/agent-guide.test.ts +58 -0
  411. package/src/modules/agent-guide/__tests__/agent-guide.tools.test.ts +19 -1
  412. package/src/modules/agent-guide/agent-guide.ts +9 -0
  413. package/src/modules/agent-guide/index.ts +1 -0
  414. package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +14 -0
  415. package/src/modules/agent-instructions/compose.ts +17 -2
  416. package/src/modules/agent-instructions/shared-file-rules.ts +19 -19
  417. package/src/modules/audit/__tests__/agent-audit.service.test.ts +64 -4
  418. package/src/modules/audit/__tests__/agent-connection.routes.test.ts +102 -0
  419. package/src/modules/audit/agent-audit.service.ts +58 -3
  420. package/src/modules/audit/agent-connection.routes.ts +56 -0
  421. package/src/modules/audit/audit.contract.ts +26 -0
  422. package/src/modules/audit/index.ts +1 -0
  423. package/src/modules/auth/__tests__/account-deactivation.test.ts +145 -16
  424. package/src/modules/auth/__tests__/account-hooks.test.ts +57 -0
  425. package/src/modules/auth/__tests__/account-switch-lock.pg.test.ts +78 -0
  426. package/src/modules/auth/__tests__/account-switch-lock.test.ts +43 -0
  427. package/src/modules/auth/__tests__/account.routes.test.ts +387 -9
  428. package/src/modules/auth/__tests__/auth.service.created.pg.test.ts +69 -0
  429. package/src/modules/auth/__tests__/auth.service.test.ts +159 -1
  430. package/src/modules/auth/account-hooks.ts +69 -0
  431. package/src/modules/auth/account-switch-guard.ts +14 -0
  432. package/src/modules/auth/account-switch-lock.ts +58 -0
  433. package/src/modules/auth/account.routes.ts +122 -13
  434. package/src/modules/auth/auth.middleware.ts +1 -1
  435. package/src/modules/auth/auth.service.ts +268 -52
  436. package/src/modules/auth/password-hash.ts +5 -2
  437. package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +18 -2
  438. package/src/modules/code-mode/code-mode.tool.ts +13 -2
  439. package/src/modules/database/__tests__/pg-error.test.ts +21 -0
  440. package/src/modules/database/__tests__/pii-backfill.pg.test.ts +6 -27
  441. package/src/modules/database/core-schema.ts +33 -3
  442. package/src/modules/database/pg-error.ts +15 -0
  443. package/src/modules/embed/__tests__/account-links.migration.test.ts +98 -0
  444. package/src/modules/embed/__tests__/embed-link.test.ts +122 -0
  445. package/src/modules/embed/__tests__/embed.routes.test.ts +362 -0
  446. package/src/modules/embed/__tests__/embed.service.lock.test.ts +193 -0
  447. package/src/modules/embed/__tests__/embed.service.test.ts +805 -0
  448. package/src/modules/embed/__tests__/embed.tools.test.ts +304 -0
  449. package/src/modules/embed/__tests__/mcp-app.test.ts +207 -0
  450. package/src/modules/embed/account-link.service.ts +76 -0
  451. package/src/modules/embed/embed-link.ts +180 -0
  452. package/src/modules/embed/embed.errors.ts +43 -0
  453. package/src/modules/embed/embed.interface.ts +203 -0
  454. package/src/modules/embed/embed.routes.ts +363 -0
  455. package/src/modules/embed/embed.service.ts +705 -0
  456. package/src/modules/embed/embed.tools.ts +206 -0
  457. package/src/modules/embed/mcp-app.routes.ts +41 -0
  458. package/src/modules/embed/mcp-app.ts +173 -0
  459. package/src/modules/github-app/__tests__/github-app.test.ts +76 -0
  460. package/src/modules/github-app/github-app.connection.ts +38 -4
  461. package/src/modules/kb-fs/__tests__/move-with-edits.test.ts +304 -0
  462. package/src/modules/kb-fs/locking-filesystem.ts +287 -0
  463. package/src/modules/kb-sync/__tests__/kb-sync.service.test.ts +35 -0
  464. package/src/modules/kb-sync/kb-sync.interface.ts +2 -0
  465. package/src/modules/kb-sync/kb-sync.service.ts +6 -0
  466. package/src/modules/mcp/__tests__/bevel-oauth-provider.test.ts +68 -11
  467. package/src/modules/mcp/__tests__/mcp-proxy-helpers.test.ts +37 -2
  468. package/src/modules/mcp/__tests__/mcp.app.e2e.test.ts +200 -0
  469. package/src/modules/mcp/__tests__/mcp.e2e.test.ts +3 -1
  470. package/src/modules/mcp/__tests__/mcp.service.test.ts +23 -13
  471. package/src/modules/mcp/__tests__/tool-call-interface.e2e.test.ts +499 -0
  472. package/src/modules/mcp/mcp-auth.middleware.ts +2 -1
  473. package/src/modules/mcp/mcp.service.ts +81 -12
  474. package/src/modules/mcp/oauth/bevel-oauth-provider.ts +42 -4
  475. package/src/modules/onboarding/__tests__/onboarding.routes.test.ts +163 -0
  476. package/src/modules/onboarding/__tests__/starter-pack.service.test.ts +635 -0
  477. package/src/modules/onboarding/__tests__/starter-packs.test.ts +169 -0
  478. package/src/modules/onboarding/onboarding.contract.ts +85 -0
  479. package/src/modules/onboarding/onboarding.routes.ts +85 -0
  480. package/src/modules/onboarding/starter-pack.service.ts +580 -0
  481. package/src/modules/onboarding/starter-packs.ts +182 -0
  482. package/src/modules/plugins/__tests__/plugins.tools.test.ts +25 -2
  483. package/src/modules/plugins/index.ts +1 -0
  484. package/src/modules/plugins/plugin-provision.service.ts +22 -1
  485. package/src/modules/plugins/plugins.routes.ts +29 -0
  486. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +150 -1
  487. package/src/modules/settings/__tests__/repository-source.test.ts +9 -0
  488. package/src/modules/settings/deployment-settings.service.ts +131 -1
  489. package/src/modules/settings/repository-source.ts +4 -4
  490. package/src/modules/skills/__tests__/skills.tools.description.test.ts +5 -1
  491. package/src/modules/skills/skills.tools.ts +55 -35
  492. package/src/modules/tool-auth/__tests__/connection-key-rejection.test.ts +32 -0
  493. package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +65 -0
  494. package/src/modules/tool-auth/connection-key-rejection.ts +13 -3
  495. package/src/modules/tool-auth/external-api-key.interface.ts +9 -0
  496. package/src/modules/tool-auth/external-api-key.service.ts +61 -4
  497. package/src/modules/tool-auth/tool-auth.middleware.ts +13 -4
  498. package/src/modules/tool-helpers/__tests__/branch-declaration.test.ts +502 -0
  499. package/src/modules/tool-helpers/__tests__/route-argument-check.test.ts +337 -0
  500. package/src/modules/tool-helpers/index.ts +34 -1
  501. package/src/modules/tool-helpers/route-argument-check.ts +149 -0
  502. package/src/modules/tool-helpers/route-tool-schemas.ts +171 -0
  503. package/src/modules/tool-helpers/tool-def.ts +132 -7
  504. package/src/modules/tool-helpers/tool-handler.ts +196 -8
  505. package/src/modules/tool-helpers/tool.contract.ts +9 -0
  506. package/src/modules/tool-manuals/tool-manuals.tools.ts +15 -5
  507. package/src/modules/tool-registry/__tests__/own-tool-schemas.test.ts +14 -1
  508. package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +23 -10
  509. package/src/modules/tool-registry/description-length.ts +34 -7
  510. package/src/modules/tool-registry/guide-first.ts +8 -1
  511. package/src/modules/workflow/__tests__/file-lock.service.deletion-gate.test.ts +104 -0
  512. package/src/modules/workflow/__tests__/pending-commits.repository-replaced.test.ts +66 -0
  513. package/src/modules/workflow/__tests__/pending-commits.worker.test.ts +31 -2
  514. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +110 -6
  515. package/src/modules/workflow/__tests__/sanitize-error.test.ts +89 -1
  516. package/src/modules/workflow/__tests__/workflow.routes.push-refused.test.ts +202 -0
  517. package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +6 -6
  518. package/src/modules/workflow/__tests__/workflow.service.delete-branch.test.ts +1026 -0
  519. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +468 -10
  520. package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +4 -0
  521. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +5 -4
  522. package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +54 -2
  523. package/src/modules/workflow/agent-tools/__tests__/change-request-read.tools.test.ts +41 -5
  524. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +127 -2
  525. package/src/modules/workflow/agent-tools/change-request-read.tools.ts +157 -122
  526. package/src/modules/workflow/agent-tools/workflow.tools.ts +129 -35
  527. package/src/modules/workflow/file-lock.service.ts +67 -5
  528. package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +164 -0
  529. package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +48 -1
  530. package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +231 -2
  531. package/src/modules/workflow/git/git.service.ts +176 -38
  532. package/src/modules/workflow/git/node-git-runner.ts +82 -7
  533. package/src/modules/workflow/pending-commits.service.ts +29 -1
  534. package/src/modules/workflow/pending-commits.worker.ts +24 -6
  535. package/src/modules/workflow/recovery-bot.ts +1 -1
  536. package/src/modules/workflow/review-workflow/review-workflow.service.ts +2 -1
  537. package/src/modules/workflow/sanitize-error.ts +50 -0
  538. package/src/modules/workflow/workflow.service.ts +881 -113
  539. package/src/modules/workspace/__tests__/agent-downloads.test.ts +823 -0
  540. package/src/modules/workspace/__tests__/first-run.test.ts +234 -0
  541. package/src/modules/workspace/__tests__/git-internals.security.test.ts +5 -2
  542. package/src/modules/workspace/__tests__/md-links.test.ts +353 -0
  543. package/src/modules/workspace/__tests__/move-links.test.ts +261 -0
  544. package/src/modules/workspace/__tests__/rest-tool-arguments.test.ts +219 -0
  545. package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +3 -0
  546. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +102 -0
  547. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +52 -5
  548. package/src/modules/workspace/__tests__/workspace.routes.folder-zip-access.test.ts +190 -0
  549. package/src/modules/workspace/__tests__/workspace.service.forget-clone-races.test.ts +8 -4
  550. package/src/modules/workspace/__tests__/workspace.service.test.ts +50 -8
  551. package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +44 -1
  552. package/src/modules/workspace/__tests__/workspace.tools.test.ts +409 -12
  553. package/src/modules/workspace/agent-download.builder.ts +308 -0
  554. package/src/modules/workspace/agent-download.routes.ts +183 -0
  555. package/src/modules/workspace/agent-download.store.ts +533 -0
  556. package/src/modules/workspace/agent-upload.store.ts +23 -7
  557. package/src/modules/workspace/file-readers/raw-mime.ts +40 -0
  558. package/src/modules/workspace/file-readers/text-reader.ts +5 -8
  559. package/src/modules/workspace/first-run.ts +222 -0
  560. package/src/modules/workspace/move-links.ts +237 -0
  561. package/src/modules/workspace/startup/steps/seed-tree.ts +3 -12
  562. package/src/modules/workspace/workspace.routes.ts +64 -22
  563. package/src/modules/workspace/workspace.service.ts +202 -25
  564. package/src/modules/workspace/workspace.tools.ts +492 -63
  565. package/src/modules/write-access/__tests__/write-access.test.ts +13 -0
  566. package/src/modules/write-access/write-access.ts +9 -0
  567. package/src/shared/domain-errors.ts +108 -11
  568. package/src/shared/git.contract.ts +8 -1
  569. package/src/shared/utf8-text.ts +21 -0
  570. package/src/tenancy/__tests__/static-tenant-source.test.ts +1 -0
  571. package/src/tenancy/static-tenant-source.ts +10 -2
  572. package/starter-packs/README.md +103 -0
  573. package/starter-packs/engineering/KnowledgeBase/About us.md +9 -0
  574. package/starter-packs/engineering/KnowledgeBase/Architecture.md +9 -0
  575. package/starter-packs/engineering/KnowledgeBase/Glossary.md +9 -0
  576. package/starter-packs/engineering/KnowledgeBase/How we ship.md +9 -0
  577. package/starter-packs/engineering/Plugins/engineering-starter/LICENSE +21 -0
  578. package/starter-packs/engineering/Plugins/engineering-starter/SOURCE.md +20 -0
  579. package/starter-packs/engineering/Plugins/engineering-starter/access.md +19 -0
  580. package/starter-packs/engineering/Plugins/engineering-starter/plugin.json +10 -0
  581. package/starter-packs/engineering/Plugins/engineering-starter/skills/office-hours/SKILL.md +171 -0
  582. package/starter-packs/engineering/Plugins/engineering-starter/skills/office-hours/sections/phase-2a-startup-diagnostic.md +157 -0
  583. package/starter-packs/engineering/Plugins/engineering-starter/skills/office-hours/sections/phase-2b-builder-brainstorm.md +39 -0
  584. package/starter-packs/engineering/Plugins/engineering-starter/skills/plan-ceo-review/SKILL.md +144 -0
  585. package/starter-packs/engineering/Plugins/engineering-starter/skills/plan-eng-review/SKILL.md +144 -0
  586. package/starter-packs/engineering/Plugins/engineering-starter/skills/review/SKILL.md +80 -0
  587. package/starter-packs/engineering/Plugins/engineering-starter/skills/review/checklist.md +184 -0
  588. package/starter-packs/engineering/pack.yaml +11 -0
  589. package/starter-packs/general/KnowledgeBase/About us.md +9 -0
  590. package/starter-packs/general/KnowledgeBase/Glossary.md +9 -0
  591. package/starter-packs/general/KnowledgeBase/How we work.md +9 -0
  592. package/starter-packs/general/Plugins/general-starter/LICENSE +202 -0
  593. package/starter-packs/general/Plugins/general-starter/SOURCE.md +10 -0
  594. package/starter-packs/general/Plugins/general-starter/access.md +19 -0
  595. package/starter-packs/general/Plugins/general-starter/plugin.json +10 -0
  596. package/starter-packs/general/Plugins/general-starter/skills/memory-management/SKILL.md +332 -0
  597. package/starter-packs/general/Plugins/general-starter/skills/productivity-start/SKILL.md +163 -0
  598. package/starter-packs/general/Plugins/general-starter/skills/productivity-update/SKILL.md +167 -0
  599. package/starter-packs/general/Plugins/general-starter/skills/task-management/SKILL.md +83 -0
  600. package/starter-packs/general/pack.yaml +10 -0
  601. package/starter-packs/operations/KnowledgeBase/Glossary.md +9 -0
  602. package/starter-packs/operations/KnowledgeBase/How we work.md +9 -0
  603. package/starter-packs/operations/KnowledgeBase/Processes.md +9 -0
  604. package/starter-packs/operations/KnowledgeBase/Tools we use.md +9 -0
  605. package/starter-packs/operations/KnowledgeBase/Vendors.md +9 -0
  606. package/starter-packs/operations/Plugins/operations-starter/LICENSE +202 -0
  607. package/starter-packs/operations/Plugins/operations-starter/SOURCE.md +10 -0
  608. package/starter-packs/operations/Plugins/operations-starter/access.md +19 -0
  609. package/starter-packs/operations/Plugins/operations-starter/plugin.json +10 -0
  610. package/starter-packs/operations/Plugins/operations-starter/skills/capacity-plan/SKILL.md +111 -0
  611. package/starter-packs/operations/Plugins/operations-starter/skills/change-request/SKILL.md +119 -0
  612. package/starter-packs/operations/Plugins/operations-starter/skills/compliance-tracking/SKILL.md +44 -0
  613. package/starter-packs/operations/Plugins/operations-starter/skills/process-doc/SKILL.md +80 -0
  614. package/starter-packs/operations/Plugins/operations-starter/skills/process-optimization/SKILL.md +39 -0
  615. package/starter-packs/operations/Plugins/operations-starter/skills/risk-assessment/SKILL.md +40 -0
  616. package/starter-packs/operations/Plugins/operations-starter/skills/runbook/SKILL.md +85 -0
  617. package/starter-packs/operations/Plugins/operations-starter/skills/status-report/SKILL.md +75 -0
  618. package/starter-packs/operations/Plugins/operations-starter/skills/vendor-review/SKILL.md +102 -0
  619. package/starter-packs/operations/pack.yaml +12 -0
  620. package/starter-packs/sales/KnowledgeBase/About us.md +9 -0
  621. package/starter-packs/sales/KnowledgeBase/Customers.md +9 -0
  622. package/starter-packs/sales/KnowledgeBase/Glossary.md +9 -0
  623. package/starter-packs/sales/KnowledgeBase/How we sell.md +9 -0
  624. package/starter-packs/sales/KnowledgeBase/Objections.md +9 -0
  625. package/starter-packs/sales/KnowledgeBase/Pricing.md +9 -0
  626. package/starter-packs/sales/Plugins/sales-starter/LICENSE +202 -0
  627. package/starter-packs/sales/Plugins/sales-starter/SOURCE.md +10 -0
  628. package/starter-packs/sales/Plugins/sales-starter/access.md +19 -0
  629. package/starter-packs/sales/Plugins/sales-starter/plugin.json +10 -0
  630. package/starter-packs/sales/Plugins/sales-starter/skills/account-context/SKILL.md +94 -0
  631. package/starter-packs/sales/Plugins/sales-starter/skills/account-plan/SKILL.md +95 -0
  632. package/starter-packs/sales/Plugins/sales-starter/skills/account-research/SKILL.md +99 -0
  633. package/starter-packs/sales/Plugins/sales-starter/skills/account-tiering/SKILL.md +101 -0
  634. package/starter-packs/sales/Plugins/sales-starter/skills/call-prep/SKILL.md +111 -0
  635. package/starter-packs/sales/Plugins/sales-starter/skills/call-summary/SKILL.md +111 -0
  636. package/starter-packs/sales/Plugins/sales-starter/skills/close-plan/SKILL.md +106 -0
  637. package/starter-packs/sales/Plugins/sales-starter/skills/competitive-intelligence/SKILL.md +102 -0
  638. package/starter-packs/sales/Plugins/sales-starter/skills/create-an-asset/SKILL.md +105 -0
  639. package/starter-packs/sales/Plugins/sales-starter/skills/crm-hygiene-check/SKILL.md +103 -0
  640. package/starter-packs/sales/Plugins/sales-starter/skills/customer-health/SKILL.md +108 -0
  641. package/starter-packs/sales/Plugins/sales-starter/skills/customer-voice/SKILL.md +94 -0
  642. package/starter-packs/sales/Plugins/sales-starter/skills/daily-briefing/SKILL.md +61 -0
  643. package/starter-packs/sales/Plugins/sales-starter/skills/deal-advance-gap/SKILL.md +102 -0
  644. package/starter-packs/sales/Plugins/sales-starter/skills/deal-review/SKILL.md +105 -0
  645. package/starter-packs/sales/Plugins/sales-starter/skills/deal-signals/SKILL.md +96 -0
  646. package/starter-packs/sales/Plugins/sales-starter/skills/deal-slip-scenario/SKILL.md +104 -0
  647. package/starter-packs/sales/Plugins/sales-starter/skills/draft-outreach/SKILL.md +116 -0
  648. package/starter-packs/sales/Plugins/sales-starter/skills/end-of-day/SKILL.md +114 -0
  649. package/starter-packs/sales/Plugins/sales-starter/skills/expansion-whitespace/SKILL.md +97 -0
  650. package/starter-packs/sales/Plugins/sales-starter/skills/forecast/SKILL.md +100 -0
  651. package/starter-packs/sales/Plugins/sales-starter/skills/handle-objection/SKILL.md +93 -0
  652. package/starter-packs/sales/Plugins/sales-starter/skills/inbox-sweep/SKILL.md +114 -0
  653. package/starter-packs/sales/Plugins/sales-starter/skills/lead-triage/SKILL.md +106 -0
  654. package/starter-packs/sales/Plugins/sales-starter/skills/log-activity/SKILL.md +111 -0
  655. package/starter-packs/sales/Plugins/sales-starter/skills/pipeline-review/SKILL.md +97 -0
  656. package/starter-packs/sales/Plugins/sales-starter/skills/renewal-radar/SKILL.md +95 -0
  657. package/starter-packs/sales/Plugins/sales-starter/skills/rep-context/SKILL.md +90 -0
  658. package/starter-packs/sales/Plugins/sales-starter/skills/route-lead/SKILL.md +111 -0
  659. package/starter-packs/sales/Plugins/sales-starter/skills/sales-setup/SKILL.md +200 -0
  660. package/starter-packs/sales/Plugins/sales-starter/skills/schedule-meeting/SKILL.md +99 -0
  661. package/starter-packs/sales/Plugins/sales-starter/skills/stakeholder-map/SKILL.md +107 -0
  662. package/starter-packs/sales/Plugins/sales-starter/skills/team-pipeline/SKILL.md +105 -0
  663. package/starter-packs/sales/Plugins/sales-starter/skills/update-opportunity/SKILL.md +112 -0
  664. package/starter-packs/sales/Plugins/sales-starter/skills/weekly-wrap/SKILL.md +90 -0
  665. package/starter-packs/sales/Plugins/sales-starter/skills/win-loss-review/SKILL.md +88 -0
  666. package/starter-packs/sales/pack.yaml +13 -0
  667. package/starter-packs/support/KnowledgeBase/Escalations.md +9 -0
  668. package/starter-packs/support/KnowledgeBase/Glossary.md +9 -0
  669. package/starter-packs/support/KnowledgeBase/Known issues.md +9 -0
  670. package/starter-packs/support/KnowledgeBase/Products.md +9 -0
  671. package/starter-packs/support/KnowledgeBase/Tone of voice.md +9 -0
  672. package/starter-packs/support/Plugins/support-starter/LICENSE +202 -0
  673. package/starter-packs/support/Plugins/support-starter/SOURCE.md +10 -0
  674. package/starter-packs/support/Plugins/support-starter/access.md +19 -0
  675. package/starter-packs/support/Plugins/support-starter/plugin.json +10 -0
  676. package/starter-packs/support/Plugins/support-starter/skills/customer-escalation/SKILL.md +246 -0
  677. package/starter-packs/support/Plugins/support-starter/skills/customer-research/SKILL.md +250 -0
  678. package/starter-packs/support/Plugins/support-starter/skills/draft-response/SKILL.md +416 -0
  679. package/starter-packs/support/Plugins/support-starter/skills/kb-article/SKILL.md +350 -0
  680. package/starter-packs/support/Plugins/support-starter/skills/ticket-triage/SKILL.md +273 -0
  681. package/starter-packs/support/pack.yaml +12 -0
@@ -263,6 +263,19 @@ export interface IAccessControl {
263
263
  relativePath: string,
264
264
  ): Promise<boolean>;
265
265
 
266
+ /**
267
+ * Batched `canDownload` — one config load per call, the same resolution
268
+ * as the single form, each path's own frontmatter `download:` rules
269
+ * included. A folder download judges every file it would pack through
270
+ * this, so a folder of a thousand files costs one model load, not a
271
+ * thousand.
272
+ */
273
+ canDownloadBatch(
274
+ workspaceId: string,
275
+ userEmail: string,
276
+ relativePaths: string[],
277
+ ): Promise<Map<string, boolean>>;
278
+
266
279
  /**
267
280
  * True iff `userEmail` is an `owner` of `relativePath` per the current
268
281
  * access tree, resolved from the `owner:` lists alone (the `write` /
@@ -665,6 +678,16 @@ export interface IAccessControl {
665
678
  */
666
679
  holdsAdminRootWrite(workspaceId: string, userEmail: string): Promise<boolean>;
667
680
 
681
+ /**
682
+ * Every address the resolver treats as an Admin in the working-tree model,
683
+ * each once: the Admin role's members — through a group too — and the
684
+ * deployment owners. The same membership answer {@link holdsAdminRootWrite}
685
+ * gives one address at a time, enumerated. When the model cannot be loaded
686
+ * (a `roles.yaml` that does not parse makes nobody an Admin), the
687
+ * deployment owners alone.
688
+ */
689
+ adminEmails(workspaceId: string): Promise<string[]>;
690
+
668
691
  /**
669
692
  * Whether `userEmail` may put a misplaced platform file back at
670
693
  * `destinationRelativePath` — the ONE write that is allowed to land on a
@@ -1581,6 +1581,22 @@ export class AccessControlService implements IAccessControl {
1581
1581
  return hasPermissionResolved(model, 'download', userEmail, relativePath, own);
1582
1582
  }
1583
1583
 
1584
+ async canDownloadBatch(
1585
+ workspaceId: string,
1586
+ userEmail: string,
1587
+ relativePaths: string[],
1588
+ ): Promise<Map<string, boolean>> {
1589
+ const model = await this.loadModel(workspaceId);
1590
+ const repoDir = await this.repoDir(workspaceId);
1591
+ // Parallel own-entries reads, memoized — same shape as `canWriteBatch`.
1592
+ const owns = await Promise.all(relativePaths.map((p) => this.cachedOwnEntries(workspaceId, repoDir, p)));
1593
+ const result = new Map<string, boolean>();
1594
+ relativePaths.forEach((p, i) => {
1595
+ result.set(p, hasPermissionResolved(model, 'download', userEmail, p, owns[i]));
1596
+ });
1597
+ return result;
1598
+ }
1599
+
1584
1600
  async canOwnerBatch(
1585
1601
  workspaceId: string,
1586
1602
  userEmail: string,
@@ -2148,6 +2164,25 @@ export class AccessControlService implements IAccessControl {
2148
2164
  return isAdminEmail(model, canonicalEmail(userEmail));
2149
2165
  }
2150
2166
 
2167
+ async adminEmails(workspaceId: string): Promise<string[]> {
2168
+ let model: AccessModel;
2169
+ try {
2170
+ model = await this.loadModel(workspaceId);
2171
+ } catch (err) {
2172
+ // As canRestorePlatformFile: with no model to ask, the deployment owners
2173
+ // are the only admins left. A `roles.yaml` that does not parse is that
2174
+ // by design; anything else (a clone being read, the disk) is said, so a
2175
+ // list that names fewer admins than there are is diagnosable.
2176
+ if (!(err instanceof AccessConfigError)) {
2177
+ log.warn('the access model could not be loaded; the admins list names the deployment owners only:', { err });
2178
+ }
2179
+ return [...this.deploymentOwners];
2180
+ }
2181
+ const candidates = new Set<string>(model.deploymentOwners);
2182
+ for (const email of model.roles.byEmail.keys()) candidates.add(email);
2183
+ return [...candidates].filter((email) => isAdminEmail(model, email));
2184
+ }
2185
+
2151
2186
  async canRestorePlatformFile(
2152
2187
  workspaceId: string,
2153
2188
  userEmail: string,
@@ -21,6 +21,7 @@ import type { WorkspaceService } from '../workspace/workspace.service.js';
21
21
  import type { KbContext } from '../../shared/kb-context.js';
22
22
  import { branchForWorkspaceId } from '../../shared/workspace-id.js';
23
23
  import type { AuthService } from '../auth/auth.service.js';
24
+ import type { IAccountSwitchGuard } from '../auth/account-switch-guard.js';
24
25
  import type { WorkflowService } from '../workflow/workflow.service.js';
25
26
  import type { WorkflowEventBus } from '../workflow/event-bus.js';
26
27
  import { WorkflowDomainError } from '../../shared/domain-errors.js';
@@ -51,6 +52,7 @@ import { RolesAdminService } from './roles-admin.service.js';
51
52
  import type { Principal } from '../access-model/access-splice.js';
52
53
  import type { Database } from '../database/connection.js';
53
54
  import { users } from '../database/schema.js';
55
+ import { canonicalEmail } from '../../shared/email-identity.js';
54
56
  import '../auth/auth.middleware.js';
55
57
 
56
58
  /** Verbs the share UI may grant. Verbs are independent — `download` is grantable on its own. */
@@ -85,6 +87,8 @@ export function createAccessRoutes(
85
87
  accessControl: IAccessControl,
86
88
  workspaceService: WorkspaceService,
87
89
  authService: AuthService,
90
+ /** Auth's switch-off coordination, for the invite's promotion (`ifActive`). */
91
+ switchGuard: IAccountSwitchGuard,
88
92
  workflowService: WorkflowService,
89
93
  eventBus: WorkflowEventBus,
90
94
  db: Database,
@@ -431,12 +435,15 @@ export function createAccessRoutes(
431
435
 
432
436
  /**
433
437
  * POST /api/workspace/:id/access/batch
434
- * Body: `{ paths: string[], verb?: 'write' | 'owner' }`. Returns
438
+ * Body: `{ paths: string[], verb?: 'write' | 'owner' | 'read' }`. Returns
435
439
  * `{ results: { [path]: boolean } }`.
436
440
  *
437
441
  * `verb` defaults to `write`, the question every existing caller asks.
438
442
  * `owner` answers from the `owner:` lists alone — no admin rescue, and a
439
- * writer is not an owner — which is what an Owner pill has to mean.
443
+ * writer is not an owner — which is what an Owner pill has to mean. `read`
444
+ * is the verdict the single lookup's `canRead` gives, for many paths at
445
+ * once: what New page asks on a draft branch, where a page may go wherever
446
+ * its author may read, of every Knowledge folder in one request.
440
447
  */
441
448
  router.post('/workspace/:id/access/batch', async (req, res) => {
442
449
  const user = await requireUser(req, res);
@@ -451,13 +458,18 @@ export function createAccessRoutes(
451
458
  res.status(400).json({ error: 'paths cannot exceed 500 entries per request' });
452
459
  return;
453
460
  }
454
- if (verb !== 'write' && verb !== 'owner') {
455
- res.status(400).json({ error: 'verb must be "write" or "owner"' });
461
+ if (verb !== 'write' && verb !== 'owner' && verb !== 'read') {
462
+ res.status(400).json({ error: 'verb must be "write", "owner" or "read"' });
456
463
  return;
457
464
  }
458
465
 
459
466
  try {
460
- const batch = verb === 'owner' ? accessControl.canOwnerBatch : accessControl.canWriteBatch;
467
+ const batch =
468
+ verb === 'owner'
469
+ ? accessControl.canOwnerBatch
470
+ : verb === 'read'
471
+ ? accessControl.canReadBatch
472
+ : accessControl.canWriteBatch;
461
473
  const result = await batch.call(
462
474
  accessControl,
463
475
  req.params.id,
@@ -1228,6 +1240,39 @@ export function createAccessRoutes(
1228
1240
  }
1229
1241
  });
1230
1242
 
1243
+ // Who the admins are, for anyone signed in: the top bar tells someone who
1244
+ // is not an admin to ask one, and names them. Names and emails ONLY — the
1245
+ // roster above (every role, its members, groups and references) stays
1246
+ // admin-only. Names come from the accounts table; an admin with no account
1247
+ // yet (a deployment admin before first sign-in, say) is named by address.
1248
+ // A role member whose account is switched off cannot sign in to invite
1249
+ // anyone, so is left out; a deployment admin is not (it signs in with the
1250
+ // environment's password regardless).
1251
+ router.get('/access/admins', async (req, res) => {
1252
+ const user = await requireUser(req, res);
1253
+ if (!user) return;
1254
+ try {
1255
+ const emails = await rolesAdmin.getAdminEmails();
1256
+ const rows =
1257
+ emails.length === 0
1258
+ ? []
1259
+ : await db
1260
+ .select({ email: users.email, name: users.name, deactivatedAt: users.deactivatedAt })
1261
+ .from(users)
1262
+ .where(inArray(users.emailBidx, emails));
1263
+ const names = new Map(rows.map((r) => [canonicalEmail(r.email), r.name?.trim() ?? '']));
1264
+ const off = new Set(rows.filter((r) => r.deactivatedAt).map((r) => canonicalEmail(r.email)));
1265
+ const admins = emails
1266
+ .filter((email) => !off.has(email) || rolesAdmin.isFixedAdmin(email))
1267
+ .map((email) => ({ name: names.get(email) || email, email }))
1268
+ .sort((a, b) => a.name.localeCompare(b.name) || a.email.localeCompare(b.email));
1269
+ res.json({ admins });
1270
+ } catch (err) {
1271
+ const { status, body } = toHttpError(err);
1272
+ res.status(status).json(body);
1273
+ }
1274
+ });
1275
+
1231
1276
  // NOTE: POST /access/roles (create), PATCH /access/roles/:canonical
1232
1277
  // (rename), and DELETE /access/roles/:canonical are GONE — roles are
1233
1278
  // app-defined capabilities, not user-editable objects.
@@ -1239,7 +1284,23 @@ export function createAccessRoutes(
1239
1284
  await assertRolesAdmin(user.email);
1240
1285
  const canonical = canonicalRoleName(req.params.canonical);
1241
1286
  const email = requireNonEmptyString((req.body ?? {}).email, 'email');
1242
- res.json({ roles: await rolesAdmin.addMember(user, canonical, email) });
1287
+ // `ifActive`: the invite's promotion, which leaves a switched-off
1288
+ // account unchanged. Inside the roles file's lock, auth reads the
1289
+ // account under the address's switch lock and keeps that transaction
1290
+ // open until roles.yaml is written and committed
1291
+ // (`IAccountSwitchGuard.whileSwitchedOn`). So a switch-off either committed
1292
+ // before the read (the promotion is refused) or waits until the
1293
+ // promotion is written (it lands after, as for any Admin switched off
1294
+ // later: the place in roles stays, the credentials stop being honoured).
1295
+ const ifActive = (req.body ?? {}).ifActive;
1296
+ if (ifActive !== undefined && typeof ifActive !== 'boolean') {
1297
+ res.status(400).json({ error: 'ifActive must be a boolean' });
1298
+ return;
1299
+ }
1300
+ const whileSwitchedOn = (write: () => Promise<void>): Promise<void> => switchGuard.whileSwitchedOn(email, write);
1301
+ res.json({
1302
+ roles: await rolesAdmin.addMember(user, canonical, email, ifActive ? { aroundWrite: whileSwitchedOn } : undefined),
1303
+ });
1243
1304
  } catch (err) {
1244
1305
  const { status, body } = toHttpError(err);
1245
1306
  res.status(status).json(body);
@@ -35,7 +35,7 @@ export async function ensureDirectorySyncBot(db: Database): Promise<AuthUser> {
35
35
  .returning();
36
36
  if (inserted.length > 0) {
37
37
  const row = inserted[0];
38
- log.info(`created sync-bot user id=${row.id} email=${row.email}`);
38
+ log.info(`created sync-bot user id=${row.id}`);
39
39
  return { id: row.id, email: row.email, name: row.name, avatarUrl: row.avatarUrl ?? undefined };
40
40
  }
41
41
  const [row] = await db
@@ -103,6 +103,13 @@ export interface RoleRosterEntry {
103
103
  * email once, as fixed.
104
104
  */
105
105
  fixedMembers: string[];
106
+ /**
107
+ * The note the page prints beside {@link fixedMembers}, and the sentence
108
+ * both Admin-membership refusals lead with. Sent with the roster so the
109
+ * page keeps no copy of the wording. Null when the role has no fixed
110
+ * members.
111
+ */
112
+ fixedMembersNote: string | null;
106
113
  /** Canonical names of groups this role is assigned to (`group:` members). */
107
114
  groups: string[];
108
115
  isAdmin: boolean;
@@ -165,11 +172,12 @@ export class RolesAdminService {
165
172
  private readonly fixedAdminEmails: readonly string[];
166
173
  /**
167
174
  * The one explanation both Admin-role refusals carry, verbatim: the note the
168
- * page prints beside a fixed member. Kept as a named constant so the refusal
169
- * an API caller reads and the note a UI reader sees cannot drift apart.
175
+ * page prints beside a fixed member, which it reads from the roster's
176
+ * `fixedMembersNote`. One constant, so the refusal an API caller reads and
177
+ * the note a UI reader sees cannot drift apart.
170
178
  */
171
179
  private static readonly FIXED_ADMIN_NOTE =
172
- 'Deployment admin, set in the server configuration; cannot be removed here';
180
+ 'Owner; cannot be removed here';
173
181
 
174
182
  constructor(
175
183
  private readonly workspaceService: IWorkspaceService,
@@ -227,9 +235,10 @@ export class RolesAdminService {
227
235
  /**
228
236
  * Is `email` a deployment admin — an address the server configuration makes
229
237
  * an Admin, ahead of `roles.yaml`? Drives both the fixed member rows and
230
- * the add/remove refusals on the Admin role.
238
+ * the add/remove refusals on the Admin role, and keeps a switched-off
239
+ * deployment admin among the admins people are told to ask.
231
240
  */
232
- private isFixedAdmin(email: string): boolean {
241
+ isFixedAdmin(email: string): boolean {
233
242
  return this.fixedAdminEmails.includes(canonicalEmail(email));
234
243
  }
235
244
 
@@ -326,6 +335,8 @@ export class RolesAdminService {
326
335
  // Only Admin has fixed members: `deploymentOwners` is an Admin rescue
327
336
  // in the resolver, never a general grant, so no other role gains one.
328
337
  fixedMembers: isAdmin ? [...this.fixedAdminEmails] : [],
338
+ fixedMembersNote:
339
+ isAdmin && this.fixedAdminEmails.length > 0 ? RolesAdminService.FIXED_ADMIN_NOTE : null,
329
340
  groups: role.members
330
341
  .filter(isGroupRefMember)
331
342
  .map((m) => canonicalRoleName(m.slice(GROUP_REF_PREFIX.length))),
@@ -342,6 +353,18 @@ export class RolesAdminService {
342
353
  return out;
343
354
  }
344
355
 
356
+ /**
357
+ * The addresses the app treats as an Admin, each once — the resolver's own
358
+ * membership answer ({@link IAccessControl.adminEmails}), so who this names
359
+ * and who the admin gates admit cannot drift apart. Nothing else about
360
+ * roles: this backs a read any signed-in person may make (who to ask for an
361
+ * invite), unlike the roster.
362
+ */
363
+ async getAdminEmails(): Promise<string[]> {
364
+ const workspaceId = await this.ensureWorkspace();
365
+ return this.accessControl.adminEmails(workspaceId);
366
+ }
367
+
345
368
  /**
346
369
  * Whether the default-branch roles.yaml parses. Drives the "roles file
347
370
  * corrupted" banner. Auth-only (never admin-gated): a corrupted file resolves
@@ -446,10 +469,24 @@ export class RolesAdminService {
446
469
  * admits it ahead of `roles.yaml` — so the write would add a row that means
447
470
  * nothing, next to the fixed row the page already shows. Other roles are
448
471
  * unaffected: a deployment admin is an ordinary member of "Sales".
472
+ *
473
+ * `aroundWrite`, when given, runs once the roles file's lock is held and
474
+ * is handed the edit itself (read, check, write, commit) to run. What it
475
+ * does around that call brackets the whole write: the invite holds the
476
+ * address's account-switch lock (a transaction-scoped advisory lock keyed
477
+ * on the canonical email, see `AuthService.whileSwitchedOn`) across it, so
478
+ * a switch-off cannot commit in between, whether or not the account exists
479
+ * yet (see the members route). It may throw instead of calling `write`;
480
+ * nothing is written then.
449
481
  */
450
- async addMember(actor: AuthUser, canonical: string, email: string): Promise<RoleRosterEntry[]> {
482
+ async addMember(
483
+ actor: AuthUser,
484
+ canonical: string,
485
+ email: string,
486
+ opts?: { aroundWrite?: (write: () => Promise<void>) => Promise<void> },
487
+ ): Promise<RoleRosterEntry[]> {
451
488
  this.assertNotFixedAdmin(canonical, email);
452
- await this.runEdit(actor, (text) => editAddMember(text, canonical, email));
489
+ await this.runEdit(actor, (text) => editAddMember(text, canonical, email), opts?.aroundWrite);
453
490
  return this.getRoster();
454
491
  }
455
492
 
@@ -682,17 +719,20 @@ export class RolesAdminService {
682
719
  * `pre` produces the candidate (and may throw RolesAdminError for invariant
683
720
  * violations before any write). Skips on a no-op. Every candidate passes
684
721
  * the resolver's own parser (assertLoadable) plus the pre-disk validator
685
- * before a byte lands.
722
+ * before a byte lands. `aroundWrite` wraps the locked edit (see
723
+ * {@link addMember}).
686
724
  */
687
725
  private async runEdit(
688
726
  actor: AuthUser,
689
727
  pre: (currentText: string) => EditResult,
728
+ aroundWrite?: (write: () => Promise<void>) => Promise<void>,
690
729
  ): Promise<void> {
691
730
  const workspaceId = await this.ensureWorkspace();
692
731
  await this.assertRolesUnlocked(workspaceId, actor);
693
- return this.locked.withFileLocks(workspaceId, actor, [ROLES_YAML], () =>
694
- this.runEditLocked(workspaceId, actor, pre),
695
- );
732
+ return this.locked.withFileLocks(workspaceId, actor, [ROLES_YAML], () => {
733
+ const write = () => this.runEditLocked(workspaceId, actor, pre);
734
+ return aroundWrite ? aroundWrite(write) : write();
735
+ });
696
736
  }
697
737
 
698
738
  private async runEditLocked(
@@ -492,7 +492,7 @@ export class UserAccessRemovalService {
492
492
  /** Why `email` may not be removed from access files, or null when it may. */
493
493
  private blockedReason(rolesText: string | undefined, email: string): string | null {
494
494
  if (this.deploymentOwners.some((o) => canonicalEmail(o) === email)) {
495
- return 'This is the deployment owner (ADMIN_EMAIL); their access cannot be removed here.';
495
+ return 'The owner stays in roles and access rules.';
496
496
  }
497
497
  const admin = rolesText
498
498
  ? (() => {
@@ -299,6 +299,18 @@ describe('what the guide tells an agent', () => {
299
299
  expect(prose).toContain('add people to existing roles, and use a GROUP for a task- or team-scoped set of people');
300
300
  });
301
301
 
302
+ it('describes delete_branch where it says what an agent does with branches', async () => {
303
+ const text = section(await composeAgentGuide(DEFAULT_KB_LAYOUT), '### An agent proposes and syncs; a person merges');
304
+ const prose = text.replace(/\s+/g, ' ');
305
+ expect(prose).toContain('`delete_branch`');
306
+ expect(prose).toContain('Only its author');
307
+ expect(prose).toContain('`dryRun: true`');
308
+ expect(prose).toContain('`discardUnmerged: true`');
309
+ expect(prose).toContain('that proposes nothing is closed by the delete');
310
+ expect(prose).toContain('its author can withdraw it, or an Admin can decline it, in the app');
311
+ expect(prose).toContain('`lastCommit`');
312
+ });
313
+
302
314
  it('documents giving a role to a group, with an example that parses as a valid roles.yaml', async () => {
303
315
  const text = section(await composeAgentGuide(DEFAULT_KB_LAYOUT), '### Giving a role to a group');
304
316
  const prose = text.replace(/\s+/g, ' ');
@@ -326,3 +338,49 @@ describe('what the guide tells an agent', () => {
326
338
  expect(parsed.index.byEmail.get('pat@example.com')?.has('role/admin')).toBe(false);
327
339
  });
328
340
  });
341
+
342
+ /**
343
+ * The HTML views section: what an agent writing a live page is told about the
344
+ * frame. Its link rules are pinned against the renderer by core-frontend's
345
+ * `htmlViewsGuide.test.ts`, which reads the same file; what is pinned here is
346
+ * that it is served like every other section and that a distribution may
347
+ * reshape it.
348
+ */
349
+ describe('the HTML views section', () => {
350
+ it('is served on its own, inside the whole guide, titled "HTML views"', async () => {
351
+ const sections = await agentGuideSections(DEFAULT_KB_LAYOUT);
352
+ const html = sections.find((s) => s.id === 'html-views')!;
353
+ expect(html.title).toBe('HTML views');
354
+ expect(html.body).not.toContain('{{');
355
+ expect(await composeAgentGuide(DEFAULT_KB_LAYOUT)).toContain(html.body);
356
+ // After the tool manuals, before the conventions.
357
+ const ids = sections.map((s) => s.id);
358
+ expect(ids.indexOf('html-views')).toBe(ids.indexOf('tool-manuals') + 1);
359
+ });
360
+
361
+ it('describes the frame, the two members core puts on window.bevel, and a fragment that scrolls the page', async () => {
362
+ const text = section(await composeAgentGuide(DEFAULT_KB_LAYOUT), '## HTML views').replace(/\s+/g, ' ');
363
+ expect(text).toContain('**No network.**');
364
+ expect(text).toContain('**Inline scripts and styles only.**');
365
+ expect(text).toContain('**Scripts run as ES modules**');
366
+ expect(text).toContain('**No browser storage.**');
367
+ expect(text).toContain('**No host navigation.**');
368
+ expect(text).toContain('`window.bevel.openNode(href)`');
369
+ expect(text).toContain('`window.bevel.navigate(href)`');
370
+ expect(text).toContain('A distribution may add data members of its own to `window.bevel`');
371
+ expect(text).toContain('**A bare fragment scrolls the page.**');
372
+ // Rendered for the deployment's layout like every other section.
373
+ const docs = section(await composeAgentGuide({ ...DEFAULT_KB_LAYOUT, knowledgeBaseDir: 'Docs' }), '## HTML views');
374
+ expect(docs).toContain('/workspace/main/Docs/Alice.md');
375
+ });
376
+
377
+ it('lets a distribution replace the section or drop it', async () => {
378
+ const replaced = await composeAgentGuide(DEFAULT_KB_LAYOUT, (sections) =>
379
+ sections.map((s) => (s.id === 'html-views' ? { id: s.id, body: '## HTML views\n\nOurs, graph-aware.\n' } : s)),
380
+ );
381
+ expect(section(replaced, '## HTML views').trim()).toBe('Ours, graph-aware.');
382
+ const dropped = await agentGuideSections(DEFAULT_KB_LAYOUT, (sections) => sections.filter((s) => s.id !== 'html-views'));
383
+ expect(dropped.map((s) => s.id)).not.toContain('html-views');
384
+ expect(joinGuideSections(dropped)).not.toContain('## HTML views');
385
+ });
386
+ });
@@ -9,7 +9,8 @@ import { createToolHandlerFactory } from '../../tool-helpers/tool-handler.js';
9
9
  import type { ToolContext } from '../../tool-helpers/tool.contract.js';
10
10
  import { toolDef } from '../../tool-helpers/tool-def.js';
11
11
  import { GET_AGENT_GUIDE_TOOL, registerAgentGuideTool } from '../agent-guide.tools.js';
12
- import type { RenderedGuideSection } from '../agent-guide.js';
12
+ import { DEFAULT_KB_LAYOUT } from '@bevel-software/platform-shared';
13
+ import { agentGuideSections, joinGuideSections, type RenderedGuideSection } from '../agent-guide.js';
13
14
 
14
15
  let server: Server | null = null;
15
16
 
@@ -186,4 +187,21 @@ describe('get_agent_guide', () => {
186
187
  sectionsNow(SECTIONS);
187
188
  expect(await describedAs()).toContain('`introduction` (Knowledge base)');
188
189
  });
190
+
191
+ it('returns the platform\'s HTML views section on its own, and inside the whole guide', async () => {
192
+ const { call, registry, sectionsNow } = await serve();
193
+ const platform = await agentGuideSections(DEFAULT_KB_LAYOUT);
194
+ sectionsNow([...platform]);
195
+ const html = platform.find((s) => s.id === 'html-views')!;
196
+ expect(await call({ section: 'html-views' })).toEqual({
197
+ status: 200,
198
+ body: { guide: html.body, section: 'html-views', title: 'HTML views' },
199
+ });
200
+ const whole = await call();
201
+ expect(whole.body.guide).toBe(joinGuideSections(platform));
202
+ expect(String(whole.body.guide)).toContain('## HTML views');
203
+ // The description lists it, so an agent knows it can ask for it.
204
+ const def = (await registry.listExternal()).find((t) => t.name === GET_AGENT_GUIDE_TOOL)!;
205
+ expect(def.description).toContain('`html-views`');
206
+ });
189
207
  });
@@ -79,6 +79,13 @@ export type AgentGuideReader = () => Promise<string>;
79
79
  /** The computed section: the rules every file tool shares. */
80
80
  export const WORKING_WITH_FILES_SECTION_ID = 'working-with-files';
81
81
 
82
+ /**
83
+ * What to do on a knowledge base nobody has written in yet: the section the
84
+ * `firstRun` note `start_session` answers with points at (see
85
+ * workspace/first-run.ts, which names it by this constant).
86
+ */
87
+ export const NEW_KNOWLEDGE_BASE_SECTION_ID = 'new-knowledge-base';
88
+
82
89
  /**
83
90
  * Core's sections, in reading order. Every id but the shared-rules one names
84
91
  * a file in the package's `agent-guide/` folder.
@@ -91,8 +98,10 @@ export const CORE_SECTION_IDS: readonly string[] = Object.freeze([
91
98
  'access-control',
92
99
  'skills',
93
100
  'tool-manuals',
101
+ 'html-views',
94
102
  'conventions',
95
103
  'finding-things',
104
+ NEW_KNOWLEDGE_BASE_SECTION_ID,
96
105
  ]);
97
106
 
98
107
  /**
@@ -1,6 +1,7 @@
1
1
  export {
2
2
  AGENT_GUIDE_FILE,
3
3
  CORE_SECTION_IDS,
4
+ NEW_KNOWLEDGE_BASE_SECTION_ID,
4
5
  PLATFORM_GUIDE_SEPARATOR,
5
6
  WORKING_WITH_FILES_SECTION_ID,
6
7
  agentGuideSections,
@@ -114,6 +114,20 @@ describe('the shared file rules are one text, in two places', () => {
114
114
 
115
115
  });
116
116
 
117
+ describe('the delete rule for platform files', () => {
118
+ const managedItems = (): string => sharedFileRules(DEFAULT_KB_LAYOUT).find((r) => r.id === 'managed-items')!.body;
119
+
120
+ it('says a nested access.md is deleted by whoever may write it, and the root\'s platform files by nobody', async () => {
121
+ const body = managedItems();
122
+ expect(body).toContain('delete_file deletes a nested `access.md` for whoever may write it');
123
+ expect(body).toContain("its folder then follows its parent's rules");
124
+ expect(body).toContain("the repository root's `access.md` and `roles.yaml` are deleted by nobody");
125
+ // The sentence the refusal actually carries, as the tools and the app say it.
126
+ expect(body).toContain("\"<name> is the repository's own file and cannot be deleted.\"");
127
+ expect(await composeAgentGuide(DEFAULT_KB_LAYOUT)).toContain(body);
128
+ });
129
+ });
130
+
117
131
  describe('the handshake text stays inside the length it pins', () => {
118
132
  it('holds the shared section under its own cap', () => {
119
133
  const section = sharedFileRulesSection(DEFAULT_KB_LAYOUT);
@@ -30,6 +30,7 @@ import {
30
30
  stripHtmlComments,
31
31
  type KbLayout,
32
32
  } from '@bevel-software/platform-shared';
33
+ import { splitCallLine } from '@bevel-software/platform-mcp-core';
33
34
  import { sharedFileRulesSection } from './shared-file-rules.js';
34
35
 
35
36
  export { PREAMBLE_CAP, PREAMBLE_FILE, TOOL_PREFIX_CAP };
@@ -48,7 +49,13 @@ export const PLATFORM_HEADER =
48
49
  'Before answering a question about the organisation, its people, customers, products, processes, projects or internal terms, ' +
49
50
  'search the knowledge base: call `start_session` once, then `grep` for the key terms, `list_files` to orient, and `read_file` what matches. ' +
50
51
  'Prefer what you find there over memory or the web, and say so when the knowledge base is silent on something the organisation should have documented. ' +
51
- 'Skills are available as prompts and through `list_skills` and `get_skill`.';
52
+ 'Skills are available as prompts and through `list_skills` and `get_skill`. ' +
53
+ // There is no one calling shape to state: the knowledge-base tools take
54
+ // their arguments under `body`, a tool that calls another service takes them
55
+ // flat, and an agent told one rule for all of them sends a GET with a body.
56
+ // The per-tool `Call:` line is generated from each tool's own input schema,
57
+ // so pointing at it is both shorter and always right.
58
+ 'Tools do not share one calling shape: call each tool exactly as the `Call:` line at the top of its description shows.';
52
59
 
53
60
  /**
54
61
  * The fixed first line of the tool prefix. It always leads, so an admin's
@@ -167,9 +174,17 @@ export function composeAgentInstructions(
167
174
  * A tool description with the prefix ahead of it: the prefix, a blank line,
168
175
  * then the original. Purpose line first, because claude.ai cuts descriptions
169
176
  * near 500 characters.
177
+ *
178
+ * Except for the `Call:` line, which stays the very first line whatever else
179
+ * is prepended: it is how an agent learns the shape this tool's arguments take,
180
+ * and a description that opens with the purpose prefix instead would bury the
181
+ * one line the refusal for a wrong call points back to.
170
182
  */
171
183
  export function prefixToolDescription(toolPrefix: string, description: string | undefined): string {
172
- return description ? `${toolPrefix}\n\n${description}` : toolPrefix;
184
+ if (!description) return toolPrefix;
185
+ const { call, rest } = splitCallLine(description);
186
+ if (call === null) return `${toolPrefix}\n\n${description}`;
187
+ return rest === '' ? `${call}\n\n${toolPrefix}` : `${call}\n\n${toolPrefix}\n\n${rest}`;
173
188
  }
174
189
 
175
190
  /** An ATX heading line: `#` to `######`, then a space or the end. */
@@ -145,15 +145,15 @@ export function sharedFileRules(layout: KbLayout): readonly SharedFileRule[] {
145
145
  // that take content as a JSON string names the route in one sentence of
146
146
  // its own; WHY a file should go that way, and how, is here.
147
147
  id: 'upload-route',
148
- heading: 'Large, escape-heavy and binary content goes by upload',
148
+ heading: 'Large, escape-heavy and binary content: upload in, download out',
149
149
  body:
150
- 'write_file, write_files and edit_file take content as a JSON string you have to type out in full, so a long ' +
151
- 'file is cut off mid-answer, a file full of backslashes or `\\u` escapes fails to parse as a parameter, and ' +
152
- 'an image, a PDF or a zip cannot be sent at all. For any of those: call `request_file_upload`, POST the file — ' +
153
- 'or one zip holding many files — to the address it answers with any HTTP client ' +
154
- '(`curl -X POST --data-binary @<file> "<uploadUrl>?filename=<name>"`), then `apply_file_upload` to land it on ' +
155
- 'a branch in one commit. The bytes never pass through the conversation, so nothing is cut or mangled on the ' +
156
- 'way. A person can also use Upload in the app.',
150
+ 'write_file, write_files and edit_file take content as a JSON string you type out in full, so a long file ' +
151
+ 'is cut off mid-answer, a file full of backslashes or `\\u` escapes fails to parse as a parameter, and an ' +
152
+ 'image, a PDF or a zip cannot be sent at all. For those, call `request_file_upload`, POST the file (or one ' +
153
+ 'zip of many) with any HTTP client (`curl -X POST --data-binary @<file> ' +
154
+ '"<uploadUrl>?filename=<name>"`), then `apply_file_upload` lands it in one commit. To take copies OUT, ' +
155
+ '`request_file_download` answers a one-time link per file and a zip per folder (`curl -o <name> ' +
156
+ '"<downloadUrl>"`). Either way no bytes pass through the conversation.',
157
157
  },
158
158
  {
159
159
  id: 'dry-run-confirm',
@@ -163,22 +163,22 @@ export function sharedFileRules(layout: KbLayout): readonly SharedFileRule[] {
163
163
  'what the call would touch, `allowed`, and `reason` when it may not run. A non-empty folder is deleted, and a ' +
164
164
  'move that changes your access runs, only with `confirm: true`; without it the call changes nothing and ' +
165
165
  'returns the same impact with `confirmationRequired: true`. Do NOT set `confirm: true` on your first call — ' +
166
- 'dry-run, check the impact, then confirm. delete_file takes neither: it removes the one file you named, so ' +
167
- 'check it first with file_stat (`deletable`) if you are unsure.',
166
+ 'dry-run, check the impact, then confirm. delete_file takes neither: check it first with file_stat ' +
167
+ '(`deletable`) if you are unsure. delete_branch has its own `dryRun`.',
168
168
  },
169
169
  {
170
170
  id: 'managed-items',
171
171
  heading: 'What these tools never move or delete',
172
172
  body:
173
- `A platform file (${platformFileList(layout)}) is refused with ` +
174
- '"<name> is a platform file and stays in its folder." — a folder that moves ' +
175
- 'takes its own platform files along, still in their folder, and a folder that is deleted takes them with it in ' +
176
- 'the same one change, so its files are never left ungoverned part-way. A platform folder (the repository root ' +
177
- `or a reserved root folder such as \`${layout.knowledgeBaseDir}/\`) and git metadata are refused, and so is creating a ` +
178
- 'platform file or folder at a destination (renaming a note to `access.md` is refused). A path that is, or goes ' +
179
- 'through, a symbolic link is refused: links are never followed or removed. On a protected branch you must be ' +
180
- 'able to write everything the call touches — for a folder, every file under it, at its old and its new path. ' +
181
- 'file_stat reports `managed`, `movable` and `deletable` so you can tell before the call.',
173
+ `A platform file (${platformFileList(layout)}) is never moved: "<name> is a platform file and stays in its folder." ` +
174
+ 'A folder moved or deleted takes its own along, in one change. delete_file deletes a nested `access.md` for ' +
175
+ "whoever may write it (its folder then follows its parent's rules) and refuses `.bevelignore`; the repository " +
176
+ "root's `access.md` and `roles.yaml` are deleted by nobody: \"<name> is the repository's own file and cannot be " +
177
+ 'deleted." A platform folder (the root, or a reserved one like ' +
178
+ `\`${layout.knowledgeBaseDir}/\`), git metadata, and making a platform file or folder at a destination are ` +
179
+ 'refused; so is a path that is or crosses a symlink: links are never followed or removed. On a protected ' +
180
+ 'branch you must be able to write all a call touches — for a folder, every file under it, at its old and new ' +
181
+ 'path. file_stat reports `managed`, `movable` and `deletable` up front.',
182
182
  },
183
183
  {
184
184
  id: 'refused-for-permissions',