@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,304 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { execFile } from 'node:child_process';
3
+ import { promisify } from 'node:util';
4
+ import fs from 'node:fs/promises';
5
+ import path from 'node:path';
6
+ import os from 'node:os';
7
+ import type { AuthUser, IWorkflowService } from '@bevel-software/platform-shared';
8
+ import { testKbContext } from '../../../__tests__/kb-context.js';
9
+ import { GitService } from '../../workflow/git/git.service.js';
10
+ import { WorkflowHooks } from '../../workflow/workflow-hooks.js';
11
+ import type { WorkspaceService } from '../../workspace/workspace.service.js';
12
+ import { LockingFilesystem, MoveLockedError, MoveRacedError, MoveUndoError } from '../locking-filesystem.js';
13
+ import { PushNeedsAgentResolutionError } from '../../../shared/domain-errors.js';
14
+
15
+ /**
16
+ * `LockingFilesystem.moveWithEdits` — `move_file` with link rewriting: the
17
+ * move and every link edit in ONE commit, which git reads as a rename; and,
18
+ * when any lock is out of reach, nothing changed at all. Committed through the
19
+ * real `GitService.commitChanges` on a real repository.
20
+ */
21
+
22
+ const exec = promisify(execFile);
23
+ const KB = 'knowledge-base';
24
+ const WS = 'ws-move';
25
+ const USER: AuthUser = { id: 'u-alice', name: 'Alice', email: 'alice@bevel.software' };
26
+
27
+ async function git(cwd: string, args: string[]): Promise<string> {
28
+ const { stdout } = await exec('git', args, {
29
+ cwd,
30
+ env: { ...process.env, GIT_AUTHOR_NAME: 'T', GIT_AUTHOR_EMAIL: 't@x.com', GIT_COMMITTER_NAME: 'T', GIT_COMMITTER_EMAIL: 't@x.com' },
31
+ });
32
+ return stdout;
33
+ }
34
+
35
+ let root: string;
36
+ let repo: string;
37
+ let workflow: IWorkflowService;
38
+ let lockedPaths: Set<string>;
39
+
40
+ async function put(rel: string, content: string | Buffer): Promise<void> {
41
+ await fs.mkdir(path.dirname(path.join(repo, rel)), { recursive: true });
42
+ await fs.writeFile(path.join(repo, rel), content);
43
+ }
44
+
45
+ const read = (rel: string) => fs.readFile(path.join(repo, rel), 'utf8');
46
+
47
+ beforeEach(async () => {
48
+ root = await fs.mkdtemp(path.join(os.tmpdir(), 'bevel-move-edits-'));
49
+ repo = path.join(root, KB);
50
+ await fs.mkdir(repo, { recursive: true });
51
+ await git(repo, ['init', '-b', 'feature-test']);
52
+ await git(repo, ['config', 'user.email', 'test@bevel.local']);
53
+ await git(repo, ['config', 'user.name', 'Test Runner']);
54
+ await put('Projects/A/One.md', '---\nnodeType: "[Task](../../NodeTypes/Task.md)"\nid: one\n---\n\n# One\nSee [two](Two.md).\n' + 'body line\n'.repeat(20));
55
+ await put('Projects/A/Two.md', '# Two\n' + 'two line\n'.repeat(20));
56
+ await put('Projects/A/pic.png', Buffer.from([0x89, 0x50, 0x4e, 0x47, 0, 1, 2, 3]));
57
+ await put('Index.md', '[one](Projects/A/One.md)\n');
58
+ await put('NodeTypes/Task.md', '# Task\n');
59
+ await git(repo, ['add', '-A']);
60
+ await git(repo, ['commit', '-m', 'seed']);
61
+
62
+ const svc = new GitService(
63
+ { getWorkspacePath: async () => root } as unknown as WorkspaceService,
64
+ (() => {
65
+ const hooks = new WorkflowHooks();
66
+ hooks.onCommitValidation(vi.fn(async () => ({ ok: true, mustFix: [], warnings: [], rawOutput: '' })));
67
+ return hooks;
68
+ })(),
69
+ testKbContext({ kbDirName: KB }),
70
+ );
71
+ lockedPaths = new Set();
72
+ workflow = {
73
+ acquireLock: vi.fn(async (_w: string, _b: string, p: string) =>
74
+ lockedPaths.has(p)
75
+ ? { acquired: false, lock: { holderName: 'Bob' } }
76
+ : { acquired: true, lock: { holderName: 'Alice' } }),
77
+ releaseLock: vi.fn(async () => null),
78
+ releaseLockNoCommit: vi.fn(async () => undefined),
79
+ releaseLockUntouched: vi.fn(async () => undefined),
80
+ commitChanges: vi.fn((w: string, u: AuthUser, s: string, paths?: string[]) => svc.commitChanges(w, u, s, paths)),
81
+ } as unknown as IWorkflowService;
82
+ });
83
+
84
+ afterEach(async () => {
85
+ await fs.rm(root, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
86
+ });
87
+
88
+ const fsLayer = (validateWrite?: (p: string, content: unknown) => Promise<void>) =>
89
+ new LockingFilesystem(
90
+ { basePath: root, contained: true },
91
+ { workflow, workspaceId: WS, branch: 'feature-test', user: USER, kbDirName: KB, ...(validateWrite ? { validateWrite } : {}) },
92
+ );
93
+
94
+ /** The paths each release kind was called with. */
95
+ const released = (fn: unknown) => (fn as ReturnType<typeof vi.fn>).mock.calls.map((c) => c[2] as string).sort();
96
+
97
+ const edits = () => [
98
+ {
99
+ path: `${KB}/Topics/Deep/A/One.md`,
100
+ lockAt: `${KB}/Projects/A/One.md`,
101
+ content: '---\nnodeType: "[Task](../../../NodeTypes/Task.md)"\nid: one\n---\n\n# One\nSee [two](Two.md).\n' + 'body line\n'.repeat(20),
102
+ },
103
+ { path: `${KB}/Index.md`, lockAt: `${KB}/Index.md`, content: '[one](Topics/Deep/A/One.md)\n' },
104
+ ];
105
+
106
+ describe('LockingFilesystem.moveWithEdits', () => {
107
+ it('lands the folder move and every edit as ONE commit that git reads as renames', async () => {
108
+ const before = (await git(repo, ['rev-list', '--count', 'HEAD'])).trim();
109
+ await fsLayer().moveWithEdits(`${KB}/Projects/A`, `${KB}/Topics/Deep/A`, edits(), 'Move A');
110
+
111
+ expect((await git(repo, ['rev-list', '--count', 'HEAD'])).trim()).toBe(String(Number(before) + 1));
112
+ expect((await git(repo, ['status', '--porcelain'])).trim()).toBe('');
113
+ const stat = (await git(repo, ['show', '-M', '--name-status', '--format=%s', 'HEAD'])).trim().split('\n');
114
+ expect(stat[0]).toBe('Move A');
115
+ const rows = stat.slice(1).filter(Boolean).map((l) => l.split('\t'));
116
+ expect(rows.map((r) => [r[0].replace(/\d+$/, ''), ...r.slice(1)]).sort()).toEqual([
117
+ ['M', 'Index.md'],
118
+ ['R', 'Projects/A/One.md', 'Topics/Deep/A/One.md'],
119
+ ['R', 'Projects/A/Two.md', 'Topics/Deep/A/Two.md'],
120
+ ['R', 'Projects/A/pic.png', 'Topics/Deep/A/pic.png'],
121
+ ]);
122
+ expect(await read('Index.md')).toBe('[one](Topics/Deep/A/One.md)\n');
123
+ expect(await read('Topics/Deep/A/One.md')).toContain('../../../NodeTypes/Task.md');
124
+ // The binary moved byte for byte.
125
+ expect([...(await fs.readFile(path.join(repo, 'Topics/Deep/A/pic.png')))]).toEqual([0x89, 0x50, 0x4e, 0x47, 0, 1, 2, 3]);
126
+ });
127
+
128
+ it('a single file moved with edits is one commit with a rename', async () => {
129
+ const body = 'index line\n'.repeat(20);
130
+ await put('Index.md', `[one](Projects/A/One.md)\n${body}`);
131
+ await git(repo, ['commit', '-am', 'longer index']);
132
+ await fsLayer().moveWithEdits(`${KB}/Index.md`, `${KB}/Home/Index.md`, [
133
+ { path: `${KB}/Home/Index.md`, lockAt: `${KB}/Index.md`, content: `[one](../Projects/A/One.md)\n${body}` },
134
+ ], 'Move Index');
135
+ const stat = (await git(repo, ['show', '-M', '--name-status', '--format=', 'HEAD'])).trim();
136
+ expect(stat).toMatch(/^R\d+\tIndex\.md\tHome\/Index\.md$/);
137
+ });
138
+
139
+ it('a lock held past the retries changes nothing and names the busy file', async () => {
140
+ // A file inside the moved folder, locked in the middle of the sorted
141
+ // order: the locks taken before it must all be given back.
142
+ lockedPaths.add(`${KB}/Projects/A/Two.md`);
143
+ const head = await git(repo, ['rev-parse', 'HEAD']);
144
+ // The real retry window: three attempts, two seconds apart.
145
+ const err = await fsLayer().moveWithEdits(`${KB}/Projects/A`, `${KB}/Topics/Deep/A`, edits(), 'Move A').catch((e: unknown) => e);
146
+ expect(err).toBeInstanceOf(MoveLockedError);
147
+ expect((err as Error).message).toContain(`"${KB}/Projects/A/Two.md" is being edited by Bob`);
148
+ expect(await git(repo, ['rev-parse', 'HEAD'])).toBe(head);
149
+ expect((await git(repo, ['status', '--porcelain'])).trim()).toBe('');
150
+ expect(workflow.commitChanges).not.toHaveBeenCalled();
151
+ // Every lock taken was given back untouched.
152
+ expect(released(workflow.releaseLockUntouched)).toEqual([`${KB}/Index.md`, `${KB}/Projects/A`, `${KB}/Projects/A/One.md`]);
153
+ expect(workflow.releaseLockNoCommit).not.toHaveBeenCalled();
154
+ expect(workflow.releaseLock).not.toHaveBeenCalled();
155
+ expect(await read('Index.md')).toBe('[one](Projects/A/One.md)\n');
156
+ }, 20_000);
157
+
158
+ it('a file saved into the folder while the locks were being taken refuses the move, nothing moved', async () => {
159
+ const acquire = workflow.acquireLock as ReturnType<typeof vi.fn>;
160
+ let arrived = false;
161
+ acquire.mockImplementation(async () => {
162
+ // The first lock is the moment somebody else's save lands in the folder.
163
+ if (!arrived) {
164
+ arrived = true;
165
+ await put('Projects/A/Late.md', 'late\n');
166
+ }
167
+ return { acquired: true, lock: { holderName: 'Alice' } };
168
+ });
169
+ const head = await git(repo, ['rev-parse', 'HEAD']);
170
+ const err = await fsLayer().moveWithEdits(`${KB}/Projects/A`, `${KB}/Topics/Deep/A`, edits(), 'Move A').catch((e: unknown) => e);
171
+ expect(err).toBeInstanceOf(MoveRacedError);
172
+ expect((err as Error).message).toContain(`"${KB}/Projects/A/Late.md" was added`);
173
+ expect(await git(repo, ['rev-parse', 'HEAD'])).toBe(head);
174
+ expect(workflow.commitChanges).not.toHaveBeenCalled();
175
+ expect(await read('Projects/A/Late.md')).toBe('late\n');
176
+ expect(await read('Index.md')).toBe('[one](Projects/A/One.md)\n');
177
+ expect(workflow.releaseLockNoCommit).not.toHaveBeenCalled();
178
+ expect(released(workflow.releaseLockUntouched).length).toBeGreaterThan(0);
179
+ });
180
+
181
+ it('a move that fails and cannot be undone releases every lock with the discard, and says both', async () => {
182
+ (workflow.commitChanges as ReturnType<typeof vi.fn>).mockImplementation(async () => {
183
+ // Something takes the old place while the move is in flight, so the
184
+ // undo's rename finds its destination occupied.
185
+ await put('Projects/A/Taken.md', 'x\n');
186
+ throw new Error('commit exploded');
187
+ });
188
+ const err = await fsLayer().moveWithEdits(`${KB}/Projects/A`, `${KB}/Topics/Deep/A`, edits(), 'Move A').catch((e: unknown) => e);
189
+ expect(err).toBeInstanceOf(MoveUndoError);
190
+ expect((err as Error).message).toContain('commit exploded');
191
+ expect((err as Error).message).toContain('could not be undone');
192
+ // Nothing is handed back as untouched: every path goes with the discard.
193
+ expect(workflow.releaseLockUntouched).not.toHaveBeenCalled();
194
+ const discarded = released(workflow.releaseLockNoCommit);
195
+ expect(discarded).toContain(`${KB}/Projects/A`);
196
+ expect(discarded).toContain(`${KB}/Topics/Deep/A/One.md`);
197
+ expect(discarded).toContain(`${KB}/Index.md`);
198
+ });
199
+
200
+ it('a commit that landed but could not be pushed enqueues the committed paths only; the folder locks go back untouched', async () => {
201
+ // The real commit lands; only its push is refused.
202
+ const commit = (workflow.commitChanges as ReturnType<typeof vi.fn>).getMockImplementation()!;
203
+ (workflow.commitChanges as ReturnType<typeof vi.fn>).mockImplementation(async (...args: unknown[]) => {
204
+ await commit(...args);
205
+ throw new PushNeedsAgentResolutionError('feature-test', `${KB}/Index.md`, 'refused', '(not attempted)', 'refused');
206
+ });
207
+ const commitsBefore = await git(repo, ['rev-list', '--count', 'HEAD']);
208
+ await expect(
209
+ fsLayer().moveWithEdits(`${KB}/Projects/A`, `${KB}/Topics/Deep/A`, edits(), 'Move A'),
210
+ ).rejects.toBeInstanceOf(PushNeedsAgentResolutionError);
211
+ // The commit stands — the tree is as committed, nothing rolled back —
212
+ // and only its push is owed.
213
+ expect(Number(await git(repo, ['rev-list', '--count', 'HEAD']))).toBe(Number(commitsBefore) + 1);
214
+ expect((await git(repo, ['status', '--porcelain'])).trim()).toBe('');
215
+ expect(await read('Topics/Deep/A/One.md')).toContain('../../../NodeTypes/Task.md');
216
+ const enqueued = released(workflow.releaseLock);
217
+ const untouched = released(workflow.releaseLockUntouched);
218
+ // Every file the commit named is enqueued…
219
+ for (const p of [`${KB}/Index.md`, `${KB}/Projects/A/One.md`, `${KB}/Topics/Deep/A/One.md`, `${KB}/Topics/Deep/A/pic.png`]) {
220
+ expect(enqueued).toContain(p);
221
+ }
222
+ // …and the folder locks, which name nothing committed, are not.
223
+ expect(enqueued).not.toContain(`${KB}/Projects/A`);
224
+ expect(enqueued).not.toContain(`${KB}/Topics/Deep/A`);
225
+ expect(untouched).toEqual([`${KB}/Projects/A`, `${KB}/Topics/Deep/A`]);
226
+ });
227
+
228
+ it('locks every file of a moved folder at its old and its new path', async () => {
229
+ await fsLayer().moveWithEdits(`${KB}/Projects/A`, `${KB}/Topics/Deep/A`, edits(), 'Move A');
230
+ const locked = (workflow.acquireLock as ReturnType<typeof vi.fn>).mock.calls.map((c) => c[2] as string);
231
+ for (const name of ['One.md', 'Two.md', 'pic.png']) {
232
+ expect(locked).toContain(`${KB}/Projects/A/${name}`);
233
+ expect(locked).toContain(`${KB}/Topics/Deep/A/${name}`);
234
+ }
235
+ expect(locked).toEqual([...locked].sort());
236
+ });
237
+
238
+ it('a lock store that throws gives back the locks already held, and changes nothing', async () => {
239
+ (workflow.acquireLock as ReturnType<typeof vi.fn>).mockImplementation(async (_w: string, _b: string, p: string) => {
240
+ if (p === `${KB}/Projects/A/One.md`) throw new Error('lock store down');
241
+ return { acquired: true, lock: { holderName: 'Alice' } };
242
+ });
243
+ await expect(
244
+ fsLayer().moveWithEdits(`${KB}/Projects/A`, `${KB}/Topics/Deep/A`, edits(), 'Move A'),
245
+ ).rejects.toThrow('lock store down');
246
+ expect(released(workflow.releaseLockUntouched)).toEqual([`${KB}/Index.md`, `${KB}/Projects/A`]);
247
+ expect((await git(repo, ['status', '--porcelain'])).trim()).toBe('');
248
+ });
249
+
250
+ it('every edit is judged again once the locks are held, and a refusal there changes nothing', async () => {
251
+ const acquire = workflow.acquireLock as ReturnType<typeof vi.fn>;
252
+ // A validator whose verdict depends on the state under the locks.
253
+ const validateWrite = vi.fn(async (p: string) => {
254
+ if (acquire.mock.calls.length > 0 && p.endsWith('Index.md')) throw new Error('refused under lock');
255
+ });
256
+ const head = await git(repo, ['rev-parse', 'HEAD']);
257
+ await expect(
258
+ fsLayer(validateWrite).moveWithEdits(`${KB}/Projects/A`, `${KB}/Topics/Deep/A`, edits(), 'Move A'),
259
+ ).rejects.toThrow('refused under lock');
260
+ expect(validateWrite.mock.calls.filter((c) => c[0] === `${KB}/Index.md`)).toHaveLength(2);
261
+ expect(await git(repo, ['rev-parse', 'HEAD'])).toBe(head);
262
+ expect((await git(repo, ['status', '--porcelain'])).trim()).toBe('');
263
+ expect(workflow.releaseLockNoCommit).not.toHaveBeenCalled();
264
+ expect(released(workflow.releaseLockUntouched)).toContain(`${KB}/Index.md`);
265
+ });
266
+
267
+ it('an edit whose bytes cannot be put back is released with the discard, not untouched', async () => {
268
+ (workflow.commitChanges as ReturnType<typeof vi.fn>).mockImplementationOnce(async () => {
269
+ // The restore of Index.md will fail: a folder now sits at its path.
270
+ await fs.rm(path.join(repo, 'Index.md'));
271
+ await fs.mkdir(path.join(repo, 'Index.md'));
272
+ throw new Error('commit exploded');
273
+ });
274
+ await expect(
275
+ fsLayer().moveWithEdits(`${KB}/Projects/A`, `${KB}/Topics/Deep/A`, edits(), 'Move A'),
276
+ ).rejects.toThrow('commit exploded');
277
+ expect(released(workflow.releaseLockNoCommit)).toEqual([`${KB}/Index.md`]);
278
+ expect(released(workflow.releaseLockUntouched)).not.toContain(`${KB}/Index.md`);
279
+ // The moved file's edit was put back, and its lock released untouched.
280
+ expect(await read('Projects/A/One.md')).toContain('../../NodeTypes/Task.md');
281
+ expect(released(workflow.releaseLockUntouched)).toContain(`${KB}/Projects/A/One.md`);
282
+ });
283
+
284
+ it('a check refusal under the locks changes nothing', async () => {
285
+ const head = await git(repo, ['rev-parse', 'HEAD']);
286
+ await expect(
287
+ fsLayer().moveWithEdits(`${KB}/Projects/A`, `${KB}/Topics/Deep/A`, edits(), 'Move A', async () => {
288
+ throw new Error('changed meanwhile');
289
+ }),
290
+ ).rejects.toThrow('changed meanwhile');
291
+ expect(await git(repo, ['rev-parse', 'HEAD'])).toBe(head);
292
+ expect((await git(repo, ['status', '--porcelain'])).trim()).toBe('');
293
+ });
294
+
295
+ it('a failing commit puts every byte back and undoes the move', async () => {
296
+ (workflow.commitChanges as ReturnType<typeof vi.fn>).mockRejectedValueOnce(new Error('commit exploded'));
297
+ await expect(
298
+ fsLayer().moveWithEdits(`${KB}/Projects/A`, `${KB}/Topics/Deep/A`, edits(), 'Move A'),
299
+ ).rejects.toThrow('commit exploded');
300
+ expect((await git(repo, ['status', '--porcelain', '--untracked-files=all'])).trim()).toBe('');
301
+ expect(await read('Index.md')).toBe('[one](Projects/A/One.md)\n');
302
+ expect(await read('Projects/A/One.md')).toContain('../../NodeTypes/Task.md');
303
+ });
304
+ });
@@ -70,6 +70,57 @@ class CheckRefusal {
70
70
  constructor(readonly reason: unknown) {}
71
71
  }
72
72
 
73
+ /**
74
+ * `moveWithEdits` could not take a lock: another writer held `path` past the
75
+ * retries. Nothing was moved or written.
76
+ */
77
+ export class MoveLockedError extends Error {
78
+ constructor(
79
+ readonly path: string,
80
+ readonly holderName: string | null,
81
+ ) {
82
+ super(
83
+ `"${path}" is being edited by ${holderName ?? 'another user'}, so nothing was moved and no link was changed. ` +
84
+ 'Try the move again later.',
85
+ );
86
+ this.name = 'MoveLockedError';
87
+ }
88
+ }
89
+
90
+ /**
91
+ * `moveWithEdits` found a file in the folder that was not there when the
92
+ * locks were planned: somebody saved into the folder meanwhile. Nothing was
93
+ * moved; the caller plans again against the folder as it is now.
94
+ */
95
+ export class MoveRacedError extends Error {
96
+ constructor(readonly path: string) {
97
+ super(`"${path}" was added to the folder while the move was being prepared, so nothing was moved. Run the move again.`);
98
+ this.name = 'MoveRacedError';
99
+ }
100
+ }
101
+
102
+ /**
103
+ * `moveWithEdits` failed after the rename and could not put the folder back.
104
+ * The locks were released with the discard, so the working tree is reset to
105
+ * the last commit rather than left half-moved; the error carries both
106
+ * failures for the log.
107
+ */
108
+ export class MoveUndoError extends Error {
109
+ constructor(
110
+ readonly src: string,
111
+ readonly dest: string,
112
+ readonly cause: unknown,
113
+ readonly undoFailure: unknown,
114
+ ) {
115
+ super(
116
+ `Moving "${src}" to "${dest}" failed (${cause instanceof Error ? cause.message : String(cause)}), and the move ` +
117
+ `could not be undone (${undoFailure instanceof Error ? undoFailure.message : String(undoFailure)}). ` +
118
+ 'The working copy has been reset to the last commit; check the folder before trying again.',
119
+ );
120
+ this.name = 'MoveUndoError';
121
+ }
122
+ }
123
+
73
124
  /**
74
125
  * A pre-disk write validator: called with the (workspace-relative path, full
75
126
  * candidate content) of a write; throw (or reject) to refuse it. `appliesTo`
@@ -389,6 +440,242 @@ export class LockingFilesystem extends GitGuardedFilesystem {
389
440
  }
390
441
  }
391
442
 
443
+ /**
444
+ * A move and the link edits it brings, as ONE change: `move_file` with link
445
+ * rewriting on. Where `moveFile` lands a move as two queued single-path
446
+ * commits (a delete, a create), this takes every lock first — both ends of
447
+ * the move, every file a moved folder holds at its old and its new path, and
448
+ * every file it edits — in deterministic order, renames,
449
+ * writes the edits, and commits the whole set synchronously in one commit,
450
+ * so git sees the move as a rename beside the edits.
451
+ *
452
+ * `edits[].path` is where each file sits AFTER the move (a moved file's
453
+ * edit lands at its new path); `edits[].lockAt` is where it sits now, and is
454
+ * the path locked. `check` runs once every lock is held and before anything
455
+ * changes — the caller confirms there that the bytes its edits were computed
456
+ * from are still the bytes on disk.
457
+ *
458
+ * Fail-closed: a lock still held by another writer after the retries throws
459
+ * {@link MoveLockedError} naming that path, with nothing moved and nothing
460
+ * written; a failure after the rename puts every edited file's bytes back and
461
+ * the move undone before the error leaves. Only edited text passes through
462
+ * memory: a folder's other files, binaries among them, are renamed on disk.
463
+ */
464
+ async moveWithEdits(
465
+ src: string,
466
+ dest: string,
467
+ edits: { path: string; lockAt: string; content: string }[],
468
+ summary: string,
469
+ check?: () => Promise<void>,
470
+ ): Promise<Change | null> {
471
+ const { workflow, workspaceId, branch, user } = this.lockContext;
472
+ await this.assertNotGitInternals(src);
473
+ await this.assertNotGitInternals(dest);
474
+ this.assertInsideRepo(dest);
475
+ for (const e of edits) {
476
+ await this.assertNotGitInternals(e.path);
477
+ this.assertInsideRepo(e.path);
478
+ }
479
+ await this.validateResultingWrite(dest, () => this.readFile(src));
480
+ if (this.lockContext.validateWrite) {
481
+ for (const e of edits) await this.lockContext.validateWrite(e.path, e.content);
482
+ }
483
+ // A folder's files are locked one by one at both ends: a save to one of
484
+ // them mid-move would otherwise recreate the old path, or ride this
485
+ // move's commit, whose scope names every one of them.
486
+ const movedNow = src === dest ? [] : await this.filesBelow(src);
487
+ const paths = [
488
+ ...new Set([
489
+ src,
490
+ dest,
491
+ ...movedNow.flatMap((f) => [f, dest + f.slice(src.length)]),
492
+ ...edits.map((e) => e.lockAt),
493
+ ]),
494
+ ].sort();
495
+ const acquired: string[] = [];
496
+ // Locked paths left holding bytes this move wrote and could not put back:
497
+ // released with the discard (reset to HEAD), so those bytes cannot ride
498
+ // the next save's commit as if they were this move's result.
499
+ const dirtyLeft = new Set<string>();
500
+ // The paths the commit names (set once it is built): the only ones a
501
+ // release with a commit may enqueue. The folder locks at either end
502
+ // coordinate and name nothing committed, so they go back untouched —
503
+ // enqueued, a later write under those folders would be this move's.
504
+ let scope: string[] = [];
505
+ const release = async (mode: 'untouched' | 'enqueue'): Promise<void> => {
506
+ for (const p of acquired) {
507
+ try {
508
+ if (mode === 'enqueue' && scope.includes(p)) await workflow.releaseLock(workspaceId, branch, p, user);
509
+ else if (mode === 'enqueue') await workflow.releaseLockUntouched(workspaceId, branch, p, user);
510
+ else if (dirtyLeft.has(p)) await workflow.releaseLockNoCommit(workspaceId, branch, p, user);
511
+ else await workflow.releaseLockUntouched(workspaceId, branch, p, user);
512
+ } catch (releaseErr) {
513
+ log.warn(`lock release failed for "${p}" during moveWithEdits:`, { err: releaseErr });
514
+ }
515
+ }
516
+ };
517
+ for (const p of paths) {
518
+ let holderName: string | null = null;
519
+ let ok = false;
520
+ try {
521
+ for (let attempt = 0; attempt < ACQUIRE_RETRY_ATTEMPTS; attempt++) {
522
+ const result = await workflow.acquireLock(workspaceId, branch, p, user);
523
+ if (result.acquired) {
524
+ ok = true;
525
+ break;
526
+ }
527
+ holderName = result.lock.holderName;
528
+ if (attempt < ACQUIRE_RETRY_ATTEMPTS - 1) await sleep(ACQUIRE_RETRY_DELAY_MS);
529
+ }
530
+ } catch (err) {
531
+ // The lock store failing is no reason to keep the locks already held
532
+ // until their TTL runs out.
533
+ await release('untouched');
534
+ throw err;
535
+ }
536
+ if (!ok) {
537
+ await release('untouched');
538
+ throw new MoveLockedError(p, holderName);
539
+ }
540
+ acquired.push(p);
541
+ }
542
+ // Judged again under the locks, on the bytes that land: a validator that
543
+ // reads the current file must see the state each edit replaces.
544
+ try {
545
+ // The folder's files, listed again now that every lock is held: a file
546
+ // saved into it between the listing above and the locks would ride
547
+ // this move's commit without its lock — refused, and the caller tries
548
+ // again against the folder as it is now.
549
+ if (src !== dest) {
550
+ const locked = new Set(paths);
551
+ const arrived = (await this.filesBelow(src)).find((f) => !locked.has(f));
552
+ if (arrived !== undefined) throw new MoveRacedError(arrived);
553
+ }
554
+ // Placement, re-judged where the rename happens: a link introduced on
555
+ // the way to either end since the caller's preflight would carry the
556
+ // rename outside the repository.
557
+ // The entries themselves included: an edit destination replaced by a
558
+ // link since planning would have the write follow it.
559
+ await this.assertNoLinkBelowBase(src);
560
+ await this.assertNoLinkBelowBase(dest);
561
+ for (const e of edits) await this.assertNoLinkBelowBase(e.path);
562
+ await this.validateResultingWrite(dest, () => this.readFile(src));
563
+ if (this.lockContext.validateWrite) {
564
+ for (const e of edits) await this.lockContext.validateWrite(e.path, e.content);
565
+ }
566
+ await check?.();
567
+ } catch (err) {
568
+ await release('untouched');
569
+ throw err;
570
+ }
571
+
572
+ // Done in this order, and undone in the reverse one.
573
+ let moved = false;
574
+ const written: { path: string; lockAt: string; before: Buffer | null }[] = [];
575
+ try {
576
+ await this.moveNoReplace(src, dest);
577
+ moved = true;
578
+ for (const e of edits) {
579
+ const before = await this.readIfExists(e.path);
580
+ written.push({ path: e.path, lockAt: e.lockAt, before });
581
+ await super.writeFile(e.path, e.content);
582
+ }
583
+ // The commit names every file at both ends: a folder's files one by one,
584
+ // because the scope matches files, not the folders holding them. From
585
+ // the files LOCKED, not the destination as it is now: a file saved into
586
+ // the new place since the rename is somebody else's, under no lock of
587
+ // this move, and stays out of its commit.
588
+ const movedFiles = src === dest ? [] : movedNow.map((f) => dest + f.slice(src.length));
589
+ scope = [
590
+ ...new Set([
591
+ ...movedFiles.flatMap((f) => [f, src + f.slice(dest.length)]),
592
+ ...edits.map((e) => e.path),
593
+ ]),
594
+ ].sort();
595
+ const change = await workflow.commitChanges(workspaceId, user, summary, scope);
596
+ await release('untouched');
597
+ if (change) this.lockContext.fileChanges?.emit({ workspaceId, branch, paths: scope, byUser: user });
598
+ return change;
599
+ } catch (err) {
600
+ if (err instanceof PushNeedsAgentResolutionError) {
601
+ // The commit landed; only its push needs help. Releasing with a commit
602
+ // arms the pending-commits worker's push retry (see `writeFiles`).
603
+ await release('enqueue');
604
+ throw err;
605
+ }
606
+ for (const w of written.reverse()) {
607
+ try {
608
+ if (w.before === null) {
609
+ const absolute = this.resolveAbsolutePath(w.path);
610
+ if (absolute) await fs.rm(absolute, { force: true });
611
+ } else {
612
+ await super.writeFile(w.path, w.before);
613
+ }
614
+ } catch (restoreErr) {
615
+ log.warn(`could not restore "${w.path}" after a failed move:`, { err: restoreErr });
616
+ dirtyLeft.add(w.path);
617
+ dirtyLeft.add(w.lockAt);
618
+ }
619
+ }
620
+ if (moved) {
621
+ try {
622
+ await this.moveNoReplace(dest, src);
623
+ } catch (undoErr) {
624
+ // The folder is still at its new place, holding bytes this move
625
+ // wrote. Nothing may release that as "untouched": every locked path
626
+ // is let go with the discard, so the half-done move is reset rather
627
+ // than left for a later writer to publish, and the failure says so.
628
+ log.warn(`could not undo the move of "${src}" after a failure:`, { err: undoErr });
629
+ for (const p of acquired) dirtyLeft.add(p);
630
+ await release('untouched');
631
+ throw new MoveUndoError(src, dest, err, undoErr);
632
+ }
633
+ }
634
+ await release('untouched');
635
+ throw err;
636
+ }
637
+ }
638
+
639
+ /**
640
+ * Refuse a path when any folder between this filesystem's root and it is a
641
+ * link — judged by `lstat` on each ancestor, under the locks, right before
642
+ * the rename that would otherwise follow the link out of the repository.
643
+ */
644
+ private async assertNoLinkBelowBase(inputPath: string): Promise<void> {
645
+ const absolute = this.resolveAbsolutePath(inputPath);
646
+ if (!absolute) return;
647
+ const base = path.resolve(this.basePath);
648
+ let current = path.resolve(absolute);
649
+ const ancestors: string[] = [];
650
+ while (current.startsWith(base) && current !== base) {
651
+ ancestors.push(current);
652
+ current = path.dirname(current);
653
+ }
654
+ for (const ancestor of ancestors) {
655
+ const stat = await lstatOrNull(ancestor);
656
+ if (stat?.isSymbolicLink()) {
657
+ throw new Error(`"${inputPath}" is reached through a link, so nothing was moved.`);
658
+ }
659
+ }
660
+ }
661
+
662
+ /** Every file at or under `inputPath` (workspace-relative), the path itself when it is a file. */
663
+ private async filesBelow(inputPath: string): Promise<string[]> {
664
+ const absolute = this.resolveAbsolutePath(inputPath);
665
+ if (!absolute) return [inputPath];
666
+ const stat = await lstatOrNull(absolute);
667
+ if (!stat?.isDirectory()) return [inputPath];
668
+ const out: string[] = [];
669
+ const walk = async (abs: string, rel: string): Promise<void> => {
670
+ for (const e of await fs.readdir(abs, { withFileTypes: true })) {
671
+ if (e.isDirectory()) await walk(path.join(abs, e.name), `${rel}/${e.name}`);
672
+ else out.push(`${rel}/${e.name}`);
673
+ }
674
+ };
675
+ await walk(absolute, inputPath);
676
+ return out;
677
+ }
678
+
392
679
  /**
393
680
  * Write several files and commit them as ONE atomic change — the multi-file
394
681
  * counterpart to `writeFile`, for the rare case where a set of files must