@bevel-software/platform-core-backend 0.1.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 (720) hide show
  1. package/LICENSE +202 -0
  2. package/dist/assets.d.ts +5 -0
  3. package/dist/assets.d.ts.map +1 -0
  4. package/dist/assets.js +23 -0
  5. package/dist/assets.js.map +1 -0
  6. package/dist/core/core-ports.d.ts +83 -0
  7. package/dist/core/core-ports.d.ts.map +1 -0
  8. package/dist/core/core-ports.js +12 -0
  9. package/dist/core/core-ports.js.map +1 -0
  10. package/dist/core/create-core-server.d.ts +62 -0
  11. package/dist/core/create-core-server.d.ts.map +1 -0
  12. package/dist/core/create-core-server.js +204 -0
  13. package/dist/core/create-core-server.js.map +1 -0
  14. package/dist/core/create-core-services.d.ts +95 -0
  15. package/dist/core/create-core-services.d.ts.map +1 -0
  16. package/dist/core/create-core-services.js +352 -0
  17. package/dist/core/create-core-services.js.map +1 -0
  18. package/dist/core-config.d.ts +119 -0
  19. package/dist/core-config.d.ts.map +1 -0
  20. package/dist/core-config.js +240 -0
  21. package/dist/core-config.js.map +1 -0
  22. package/dist/index.d.ts +36 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +36 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/modules/access/access-control.interface.d.ts +348 -0
  27. package/dist/modules/access/access-control.interface.d.ts.map +1 -0
  28. package/dist/modules/access/access-control.interface.js +2 -0
  29. package/dist/modules/access/access-control.interface.js.map +1 -0
  30. package/dist/modules/access/access-control.service.d.ts +323 -0
  31. package/dist/modules/access/access-control.service.d.ts.map +1 -0
  32. package/dist/modules/access/access-control.service.js +1431 -0
  33. package/dist/modules/access/access-control.service.js.map +1 -0
  34. package/dist/modules/access/access-errors.d.ts +34 -0
  35. package/dist/modules/access/access-errors.d.ts.map +1 -0
  36. package/dist/modules/access/access-errors.js +40 -0
  37. package/dist/modules/access/access-errors.js.map +1 -0
  38. package/dist/modules/access/access-mutation.service.d.ts +176 -0
  39. package/dist/modules/access/access-mutation.service.d.ts.map +1 -0
  40. package/dist/modules/access/access-mutation.service.js +307 -0
  41. package/dist/modules/access/access-mutation.service.js.map +1 -0
  42. package/dist/modules/access/access-splice.d.ts +98 -0
  43. package/dist/modules/access/access-splice.d.ts.map +1 -0
  44. package/dist/modules/access/access-splice.js +346 -0
  45. package/dist/modules/access/access-splice.js.map +1 -0
  46. package/dist/modules/access/access.routes.d.ts +10 -0
  47. package/dist/modules/access/access.routes.d.ts.map +1 -0
  48. package/dist/modules/access/access.routes.js +757 -0
  49. package/dist/modules/access/access.routes.js.map +1 -0
  50. package/dist/modules/access/creator-access.d.ts +113 -0
  51. package/dist/modules/access/creator-access.d.ts.map +1 -0
  52. package/dist/modules/access/creator-access.js +212 -0
  53. package/dist/modules/access/creator-access.js.map +1 -0
  54. package/dist/modules/access/kb-read-filter.d.ts +41 -0
  55. package/dist/modules/access/kb-read-filter.d.ts.map +1 -0
  56. package/dist/modules/access/kb-read-filter.js +60 -0
  57. package/dist/modules/access/kb-read-filter.js.map +1 -0
  58. package/dist/modules/access/roles-admin.service.d.ts +240 -0
  59. package/dist/modules/access/roles-admin.service.d.ts.map +1 -0
  60. package/dist/modules/access/roles-admin.service.js +630 -0
  61. package/dist/modules/access/roles-admin.service.js.map +1 -0
  62. package/dist/modules/access/roles-edit.d.ts +91 -0
  63. package/dist/modules/access/roles-edit.d.ts.map +1 -0
  64. package/dist/modules/access/roles-edit.js +232 -0
  65. package/dist/modules/access/roles-edit.js.map +1 -0
  66. package/dist/modules/access/roles-yaml-guard.d.ts +56 -0
  67. package/dist/modules/access/roles-yaml-guard.d.ts.map +1 -0
  68. package/dist/modules/access/roles-yaml-guard.js +79 -0
  69. package/dist/modules/access/roles-yaml-guard.js.map +1 -0
  70. package/dist/modules/admin/admin-access.routes.d.ts +18 -0
  71. package/dist/modules/admin/admin-access.routes.d.ts.map +1 -0
  72. package/dist/modules/admin/admin-access.routes.js +26 -0
  73. package/dist/modules/admin/admin-access.routes.js.map +1 -0
  74. package/dist/modules/admin/admin-access.service.d.ts +24 -0
  75. package/dist/modules/admin/admin-access.service.d.ts.map +1 -0
  76. package/dist/modules/admin/admin-access.service.js +41 -0
  77. package/dist/modules/admin/admin-access.service.js.map +1 -0
  78. package/dist/modules/admin/admin.interface.d.ts +11 -0
  79. package/dist/modules/admin/admin.interface.d.ts.map +1 -0
  80. package/dist/modules/admin/admin.interface.js +2 -0
  81. package/dist/modules/admin/admin.interface.js.map +1 -0
  82. package/dist/modules/auth/account-erasure.service.d.ts +80 -0
  83. package/dist/modules/auth/account-erasure.service.d.ts.map +1 -0
  84. package/dist/modules/auth/account-erasure.service.js +91 -0
  85. package/dist/modules/auth/account-erasure.service.js.map +1 -0
  86. package/dist/modules/auth/auth.middleware.d.ts +23 -0
  87. package/dist/modules/auth/auth.middleware.d.ts.map +1 -0
  88. package/dist/modules/auth/auth.middleware.js +68 -0
  89. package/dist/modules/auth/auth.middleware.js.map +1 -0
  90. package/dist/modules/auth/auth.routes.d.ts +25 -0
  91. package/dist/modules/auth/auth.routes.d.ts.map +1 -0
  92. package/dist/modules/auth/auth.routes.js +72 -0
  93. package/dist/modules/auth/auth.routes.js.map +1 -0
  94. package/dist/modules/auth/auth.service.d.ts +76 -0
  95. package/dist/modules/auth/auth.service.d.ts.map +1 -0
  96. package/dist/modules/auth/auth.service.js +168 -0
  97. package/dist/modules/auth/auth.service.js.map +1 -0
  98. package/dist/modules/code-mode/code-mode-names.d.ts +16 -0
  99. package/dist/modules/code-mode/code-mode-names.d.ts.map +1 -0
  100. package/dist/modules/code-mode/code-mode-names.js +30 -0
  101. package/dist/modules/code-mode/code-mode-names.js.map +1 -0
  102. package/dist/modules/code-mode/code-mode.tool.d.ts +13 -0
  103. package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -0
  104. package/dist/modules/code-mode/code-mode.tool.js +112 -0
  105. package/dist/modules/code-mode/code-mode.tool.js.map +1 -0
  106. package/dist/modules/code-mode/index.d.ts +3 -0
  107. package/dist/modules/code-mode/index.d.ts.map +1 -0
  108. package/dist/modules/code-mode/index.js +3 -0
  109. package/dist/modules/code-mode/index.js.map +1 -0
  110. package/dist/modules/database/connection.d.ts +6 -0
  111. package/dist/modules/database/connection.d.ts.map +1 -0
  112. package/dist/modules/database/connection.js +12 -0
  113. package/dist/modules/database/connection.js.map +1 -0
  114. package/dist/modules/database/core-schema.d.ts +2273 -0
  115. package/dist/modules/database/core-schema.d.ts.map +1 -0
  116. package/dist/modules/database/core-schema.js +413 -0
  117. package/dist/modules/database/core-schema.js.map +1 -0
  118. package/dist/modules/database/migrate.d.ts +10 -0
  119. package/dist/modules/database/migrate.d.ts.map +1 -0
  120. package/dist/modules/database/migrate.js +40 -0
  121. package/dist/modules/database/migrate.js.map +1 -0
  122. package/dist/modules/database/schema.d.ts +12 -0
  123. package/dist/modules/database/schema.d.ts.map +1 -0
  124. package/dist/modules/database/schema.js +12 -0
  125. package/dist/modules/database/schema.js.map +1 -0
  126. package/dist/modules/diff/diff-paths.d.ts +2 -0
  127. package/dist/modules/diff/diff-paths.d.ts.map +1 -0
  128. package/dist/modules/diff/diff-paths.js +9 -0
  129. package/dist/modules/diff/diff-paths.js.map +1 -0
  130. package/dist/modules/diff/diff.config.d.ts +8 -0
  131. package/dist/modules/diff/diff.config.d.ts.map +1 -0
  132. package/dist/modules/diff/diff.config.js +13 -0
  133. package/dist/modules/diff/diff.config.js.map +1 -0
  134. package/dist/modules/diff/diff.interface.d.ts +73 -0
  135. package/dist/modules/diff/diff.interface.d.ts.map +1 -0
  136. package/dist/modules/diff/diff.interface.js +2 -0
  137. package/dist/modules/diff/diff.interface.js.map +1 -0
  138. package/dist/modules/diff/diff.routes.d.ts +35 -0
  139. package/dist/modules/diff/diff.routes.d.ts.map +1 -0
  140. package/dist/modules/diff/diff.routes.js +228 -0
  141. package/dist/modules/diff/diff.routes.js.map +1 -0
  142. package/dist/modules/diff/diff.service.d.ts +51 -0
  143. package/dist/modules/diff/diff.service.d.ts.map +1 -0
  144. package/dist/modules/diff/diff.service.js +489 -0
  145. package/dist/modules/diff/diff.service.js.map +1 -0
  146. package/dist/modules/diff/line-diff.d.ts +16 -0
  147. package/dist/modules/diff/line-diff.d.ts.map +1 -0
  148. package/dist/modules/diff/line-diff.js +67 -0
  149. package/dist/modules/diff/line-diff.js.map +1 -0
  150. package/dist/modules/mcp/mcp-auth.middleware.d.ts +27 -0
  151. package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -0
  152. package/dist/modules/mcp/mcp-auth.middleware.js +116 -0
  153. package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -0
  154. package/dist/modules/mcp/mcp-session-store.d.ts +74 -0
  155. package/dist/modules/mcp/mcp-session-store.d.ts.map +1 -0
  156. package/dist/modules/mcp/mcp-session-store.js +131 -0
  157. package/dist/modules/mcp/mcp-session-store.js.map +1 -0
  158. package/dist/modules/mcp/mcp.routes.d.ts +24 -0
  159. package/dist/modules/mcp/mcp.routes.d.ts.map +1 -0
  160. package/dist/modules/mcp/mcp.routes.js +229 -0
  161. package/dist/modules/mcp/mcp.routes.js.map +1 -0
  162. package/dist/modules/mcp/mcp.service.d.ts +198 -0
  163. package/dist/modules/mcp/mcp.service.d.ts.map +1 -0
  164. package/dist/modules/mcp/mcp.service.js +840 -0
  165. package/dist/modules/mcp/mcp.service.js.map +1 -0
  166. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +76 -0
  167. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -0
  168. package/dist/modules/mcp/oauth/bevel-oauth-provider.js +291 -0
  169. package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -0
  170. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts +18 -0
  171. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -0
  172. package/dist/modules/mcp/oauth/oauth-consent.routes.js +52 -0
  173. package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -0
  174. package/dist/modules/mcp/oauth/oauth-state.d.ts +32 -0
  175. package/dist/modules/mcp/oauth/oauth-state.d.ts.map +1 -0
  176. package/dist/modules/mcp/oauth/oauth-state.js +34 -0
  177. package/dist/modules/mcp/oauth/oauth-state.js.map +1 -0
  178. package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +92 -0
  179. package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -0
  180. package/dist/modules/secrets-vault/db-secrets-vault.service.js +728 -0
  181. package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -0
  182. package/dist/modules/secrets-vault/index.d.ts +7 -0
  183. package/dist/modules/secrets-vault/index.d.ts.map +1 -0
  184. package/dist/modules/secrets-vault/index.js +6 -0
  185. package/dist/modules/secrets-vault/index.js.map +1 -0
  186. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts +63 -0
  187. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts.map +1 -0
  188. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js +269 -0
  189. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js.map +1 -0
  190. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts +46 -0
  191. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -0
  192. package/dist/modules/secrets-vault/secrets-variable-loader.js +87 -0
  193. package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -0
  194. package/dist/modules/secrets-vault/secrets-vault.contract.d.ts +210 -0
  195. package/dist/modules/secrets-vault/secrets-vault.contract.d.ts.map +1 -0
  196. package/dist/modules/secrets-vault/secrets-vault.contract.js +90 -0
  197. package/dist/modules/secrets-vault/secrets-vault.contract.js.map +1 -0
  198. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +30 -0
  199. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -0
  200. package/dist/modules/secrets-vault/secrets-vault.routes.js +490 -0
  201. package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -0
  202. package/dist/modules/skills/index.d.ts +5 -0
  203. package/dist/modules/skills/index.d.ts.map +1 -0
  204. package/dist/modules/skills/index.js +4 -0
  205. package/dist/modules/skills/index.js.map +1 -0
  206. package/dist/modules/skills/skills.contract.d.ts +58 -0
  207. package/dist/modules/skills/skills.contract.d.ts.map +1 -0
  208. package/dist/modules/skills/skills.contract.js +10 -0
  209. package/dist/modules/skills/skills.contract.js.map +1 -0
  210. package/dist/modules/skills/skills.routes.d.ts +15 -0
  211. package/dist/modules/skills/skills.routes.d.ts.map +1 -0
  212. package/dist/modules/skills/skills.routes.js +34 -0
  213. package/dist/modules/skills/skills.routes.js.map +1 -0
  214. package/dist/modules/skills/skills.service.d.ts +21 -0
  215. package/dist/modules/skills/skills.service.d.ts.map +1 -0
  216. package/dist/modules/skills/skills.service.js +202 -0
  217. package/dist/modules/skills/skills.service.js.map +1 -0
  218. package/dist/modules/skills/skills.tools.d.ts +15 -0
  219. package/dist/modules/skills/skills.tools.d.ts.map +1 -0
  220. package/dist/modules/skills/skills.tools.js +96 -0
  221. package/dist/modules/skills/skills.tools.js.map +1 -0
  222. package/dist/modules/tool-auth/external-api-key.errors.d.ts +14 -0
  223. package/dist/modules/tool-auth/external-api-key.errors.d.ts.map +1 -0
  224. package/dist/modules/tool-auth/external-api-key.errors.js +23 -0
  225. package/dist/modules/tool-auth/external-api-key.errors.js.map +1 -0
  226. package/dist/modules/tool-auth/external-api-key.interface.d.ts +90 -0
  227. package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -0
  228. package/dist/modules/tool-auth/external-api-key.interface.js +2 -0
  229. package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -0
  230. package/dist/modules/tool-auth/external-api-key.service.d.ts +25 -0
  231. package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -0
  232. package/dist/modules/tool-auth/external-api-key.service.js +164 -0
  233. package/dist/modules/tool-auth/external-api-key.service.js.map +1 -0
  234. package/dist/modules/tool-auth/internal-token.service.d.ts +62 -0
  235. package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -0
  236. package/dist/modules/tool-auth/internal-token.service.js +85 -0
  237. package/dist/modules/tool-auth/internal-token.service.js.map +1 -0
  238. package/dist/modules/tool-auth/llm-usage-meter.d.ts +16 -0
  239. package/dist/modules/tool-auth/llm-usage-meter.d.ts.map +1 -0
  240. package/dist/modules/tool-auth/llm-usage-meter.js +6 -0
  241. package/dist/modules/tool-auth/llm-usage-meter.js.map +1 -0
  242. package/dist/modules/tool-auth/tool-auth.middleware.d.ts +101 -0
  243. package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -0
  244. package/dist/modules/tool-auth/tool-auth.middleware.js +166 -0
  245. package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -0
  246. package/dist/modules/tool-helpers/index.d.ts +19 -0
  247. package/dist/modules/tool-helpers/index.d.ts.map +1 -0
  248. package/dist/modules/tool-helpers/index.js +18 -0
  249. package/dist/modules/tool-helpers/index.js.map +1 -0
  250. package/dist/modules/tool-helpers/tool-context.d.ts +35 -0
  251. package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -0
  252. package/dist/modules/tool-helpers/tool-context.js +66 -0
  253. package/dist/modules/tool-helpers/tool-context.js.map +1 -0
  254. package/dist/modules/tool-helpers/tool-def.d.ts +33 -0
  255. package/dist/modules/tool-helpers/tool-def.d.ts.map +1 -0
  256. package/dist/modules/tool-helpers/tool-def.js +57 -0
  257. package/dist/modules/tool-helpers/tool-def.js.map +1 -0
  258. package/dist/modules/tool-helpers/tool-handler.d.ts +19 -0
  259. package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -0
  260. package/dist/modules/tool-helpers/tool-handler.js +84 -0
  261. package/dist/modules/tool-helpers/tool-handler.js.map +1 -0
  262. package/dist/modules/tool-helpers/tool.contract.d.ts +64 -0
  263. package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -0
  264. package/dist/modules/tool-helpers/tool.contract.js +24 -0
  265. package/dist/modules/tool-helpers/tool.contract.js.map +1 -0
  266. package/dist/modules/tool-helpers/validate-token.d.ts +31 -0
  267. package/dist/modules/tool-helpers/validate-token.d.ts.map +1 -0
  268. package/dist/modules/tool-helpers/validate-token.js +20 -0
  269. package/dist/modules/tool-helpers/validate-token.js.map +1 -0
  270. package/dist/modules/tool-manuals/index.d.ts +5 -0
  271. package/dist/modules/tool-manuals/index.d.ts.map +1 -0
  272. package/dist/modules/tool-manuals/index.js +5 -0
  273. package/dist/modules/tool-manuals/index.js.map +1 -0
  274. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +182 -0
  275. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -0
  276. package/dist/modules/tool-manuals/tool-manuals.contract.js +19 -0
  277. package/dist/modules/tool-manuals/tool-manuals.contract.js.map +1 -0
  278. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +24 -0
  279. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -0
  280. package/dist/modules/tool-manuals/tool-manuals.routes.js +102 -0
  281. package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -0
  282. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +108 -0
  283. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -0
  284. package/dist/modules/tool-manuals/tool-manuals.service.js +710 -0
  285. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -0
  286. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +35 -0
  287. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -0
  288. package/dist/modules/tool-manuals/tool-manuals.tools.js +157 -0
  289. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -0
  290. package/dist/modules/tool-registry/manual.routes.d.ts +6 -0
  291. package/dist/modules/tool-registry/manual.routes.d.ts.map +1 -0
  292. package/dist/modules/tool-registry/manual.routes.js +76 -0
  293. package/dist/modules/tool-registry/manual.routes.js.map +1 -0
  294. package/dist/modules/tool-registry/tool-registry.d.ts +23 -0
  295. package/dist/modules/tool-registry/tool-registry.d.ts.map +1 -0
  296. package/dist/modules/tool-registry/tool-registry.js +46 -0
  297. package/dist/modules/tool-registry/tool-registry.js.map +1 -0
  298. package/dist/modules/tool-registry/tool.contract.d.ts +48 -0
  299. package/dist/modules/tool-registry/tool.contract.d.ts.map +1 -0
  300. package/dist/modules/tool-registry/tool.contract.js +2 -0
  301. package/dist/modules/tool-registry/tool.contract.js.map +1 -0
  302. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +14 -0
  303. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -0
  304. package/dist/modules/workflow/agent-tools/workflow.tools.js +437 -0
  305. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -0
  306. package/dist/modules/workflow/event-bus.d.ts +107 -0
  307. package/dist/modules/workflow/event-bus.d.ts.map +1 -0
  308. package/dist/modules/workflow/event-bus.js +224 -0
  309. package/dist/modules/workflow/event-bus.js.map +1 -0
  310. package/dist/modules/workflow/events.routes.d.ts +80 -0
  311. package/dist/modules/workflow/events.routes.d.ts.map +1 -0
  312. package/dist/modules/workflow/events.routes.js +216 -0
  313. package/dist/modules/workflow/events.routes.js.map +1 -0
  314. package/dist/modules/workflow/file-change-notifier.d.ts +38 -0
  315. package/dist/modules/workflow/file-change-notifier.d.ts.map +1 -0
  316. package/dist/modules/workflow/file-change-notifier.js +22 -0
  317. package/dist/modules/workflow/file-change-notifier.js.map +1 -0
  318. package/dist/modules/workflow/file-lock.service.d.ts +57 -0
  319. package/dist/modules/workflow/file-lock.service.d.ts.map +1 -0
  320. package/dist/modules/workflow/file-lock.service.js +202 -0
  321. package/dist/modules/workflow/file-lock.service.js.map +1 -0
  322. package/dist/modules/workflow/git/branch-name.d.ts +10 -0
  323. package/dist/modules/workflow/git/branch-name.d.ts.map +1 -0
  324. package/dist/modules/workflow/git/branch-name.js +76 -0
  325. package/dist/modules/workflow/git/branch-name.js.map +1 -0
  326. package/dist/modules/workflow/git/clone-config.d.ts +61 -0
  327. package/dist/modules/workflow/git/clone-config.d.ts.map +1 -0
  328. package/dist/modules/workflow/git/clone-config.js +69 -0
  329. package/dist/modules/workflow/git/clone-config.js.map +1 -0
  330. package/dist/modules/workflow/git/git-version.d.ts +34 -0
  331. package/dist/modules/workflow/git/git-version.d.ts.map +1 -0
  332. package/dist/modules/workflow/git/git-version.js +63 -0
  333. package/dist/modules/workflow/git/git-version.js.map +1 -0
  334. package/dist/modules/workflow/git/git.service.d.ts +427 -0
  335. package/dist/modules/workflow/git/git.service.d.ts.map +1 -0
  336. package/dist/modules/workflow/git/git.service.js +1987 -0
  337. package/dist/modules/workflow/git/git.service.js.map +1 -0
  338. package/dist/modules/workflow/git/mutex.d.ts +11 -0
  339. package/dist/modules/workflow/git/mutex.d.ts.map +1 -0
  340. package/dist/modules/workflow/git/mutex.js +23 -0
  341. package/dist/modules/workflow/git/mutex.js.map +1 -0
  342. package/dist/modules/workflow/git/pull-request.service.d.ts +124 -0
  343. package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -0
  344. package/dist/modules/workflow/git/pull-request.service.js +328 -0
  345. package/dist/modules/workflow/git/pull-request.service.js.map +1 -0
  346. package/dist/modules/workflow/locking-filesystem.d.ts +133 -0
  347. package/dist/modules/workflow/locking-filesystem.d.ts.map +1 -0
  348. package/dist/modules/workflow/locking-filesystem.js +400 -0
  349. package/dist/modules/workflow/locking-filesystem.js.map +1 -0
  350. package/dist/modules/workflow/pending-commits.service.d.ts +221 -0
  351. package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -0
  352. package/dist/modules/workflow/pending-commits.service.js +364 -0
  353. package/dist/modules/workflow/pending-commits.service.js.map +1 -0
  354. package/dist/modules/workflow/pending-commits.worker.d.ts +148 -0
  355. package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -0
  356. package/dist/modules/workflow/pending-commits.worker.js +245 -0
  357. package/dist/modules/workflow/pending-commits.worker.js.map +1 -0
  358. package/dist/modules/workflow/read-only-filesystem.d.ts +24 -0
  359. package/dist/modules/workflow/read-only-filesystem.d.ts.map +1 -0
  360. package/dist/modules/workflow/read-only-filesystem.js +39 -0
  361. package/dist/modules/workflow/read-only-filesystem.js.map +1 -0
  362. package/dist/modules/workflow/recovery-bot.d.ts +31 -0
  363. package/dist/modules/workflow/recovery-bot.d.ts.map +1 -0
  364. package/dist/modules/workflow/recovery-bot.js +64 -0
  365. package/dist/modules/workflow/recovery-bot.js.map +1 -0
  366. package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts +137 -0
  367. package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts.map +1 -0
  368. package/dist/modules/workflow/review-workflow/review-workflow.interface.js +2 -0
  369. package/dist/modules/workflow/review-workflow/review-workflow.interface.js.map +1 -0
  370. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts +26 -0
  371. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -0
  372. package/dist/modules/workflow/review-workflow/review-workflow.service.js +636 -0
  373. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -0
  374. package/dist/modules/workflow/sanitize-error.d.ts +29 -0
  375. package/dist/modules/workflow/sanitize-error.d.ts.map +1 -0
  376. package/dist/modules/workflow/sanitize-error.js +60 -0
  377. package/dist/modules/workflow/sanitize-error.js.map +1 -0
  378. package/dist/modules/workflow/session-ontology.policy.d.ts +52 -0
  379. package/dist/modules/workflow/session-ontology.policy.d.ts.map +1 -0
  380. package/dist/modules/workflow/session-ontology.policy.js +62 -0
  381. package/dist/modules/workflow/session-ontology.policy.js.map +1 -0
  382. package/dist/modules/workflow/session-ontology.service.d.ts +100 -0
  383. package/dist/modules/workflow/session-ontology.service.d.ts.map +1 -0
  384. package/dist/modules/workflow/session-ontology.service.js +143 -0
  385. package/dist/modules/workflow/session-ontology.service.js.map +1 -0
  386. package/dist/modules/workflow/workflow-hooks.d.ts +87 -0
  387. package/dist/modules/workflow/workflow-hooks.d.ts.map +1 -0
  388. package/dist/modules/workflow/workflow-hooks.js +35 -0
  389. package/dist/modules/workflow/workflow-hooks.js.map +1 -0
  390. package/dist/modules/workflow/workflow.errors.d.ts +171 -0
  391. package/dist/modules/workflow/workflow.errors.d.ts.map +1 -0
  392. package/dist/modules/workflow/workflow.errors.js +260 -0
  393. package/dist/modules/workflow/workflow.errors.js.map +1 -0
  394. package/dist/modules/workflow/workflow.routes.d.ts +26 -0
  395. package/dist/modules/workflow/workflow.routes.d.ts.map +1 -0
  396. package/dist/modules/workflow/workflow.routes.js +804 -0
  397. package/dist/modules/workflow/workflow.routes.js.map +1 -0
  398. package/dist/modules/workflow/workflow.service.d.ts +385 -0
  399. package/dist/modules/workflow/workflow.service.d.ts.map +1 -0
  400. package/dist/modules/workflow/workflow.service.js +1155 -0
  401. package/dist/modules/workflow/workflow.service.js.map +1 -0
  402. package/dist/modules/workspace/bevel-ignore.d.ts +25 -0
  403. package/dist/modules/workspace/bevel-ignore.d.ts.map +1 -0
  404. package/dist/modules/workspace/bevel-ignore.js +57 -0
  405. package/dist/modules/workspace/bevel-ignore.js.map +1 -0
  406. package/dist/modules/workspace/kb-seed.interface.d.ts +36 -0
  407. package/dist/modules/workspace/kb-seed.interface.d.ts.map +1 -0
  408. package/dist/modules/workspace/kb-seed.interface.js +2 -0
  409. package/dist/modules/workspace/kb-seed.interface.js.map +1 -0
  410. package/dist/modules/workspace/kb-seed.service.d.ts +70 -0
  411. package/dist/modules/workspace/kb-seed.service.d.ts.map +1 -0
  412. package/dist/modules/workspace/kb-seed.service.js +325 -0
  413. package/dist/modules/workspace/kb-seed.service.js.map +1 -0
  414. package/dist/modules/workspace/routine-write-policy.d.ts +49 -0
  415. package/dist/modules/workspace/routine-write-policy.d.ts.map +1 -0
  416. package/dist/modules/workspace/routine-write-policy.js +46 -0
  417. package/dist/modules/workspace/routine-write-policy.js.map +1 -0
  418. package/dist/modules/workspace/session-ontology.gate.d.ts +112 -0
  419. package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -0
  420. package/dist/modules/workspace/session-ontology.gate.js +161 -0
  421. package/dist/modules/workspace/session-ontology.gate.js.map +1 -0
  422. package/dist/modules/workspace/session-sink.d.ts +25 -0
  423. package/dist/modules/workspace/session-sink.d.ts.map +1 -0
  424. package/dist/modules/workspace/session-sink.js +8 -0
  425. package/dist/modules/workspace/session-sink.js.map +1 -0
  426. package/dist/modules/workspace/spill-store.d.ts +24 -0
  427. package/dist/modules/workspace/spill-store.d.ts.map +1 -0
  428. package/dist/modules/workspace/spill-store.js +87 -0
  429. package/dist/modules/workspace/spill-store.js.map +1 -0
  430. package/dist/modules/workspace/workspace.routes.d.ts +25 -0
  431. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -0
  432. package/dist/modules/workspace/workspace.routes.js +1046 -0
  433. package/dist/modules/workspace/workspace.routes.js.map +1 -0
  434. package/dist/modules/workspace/workspace.service.d.ts +339 -0
  435. package/dist/modules/workspace/workspace.service.d.ts.map +1 -0
  436. package/dist/modules/workspace/workspace.service.js +1221 -0
  437. package/dist/modules/workspace/workspace.service.js.map +1 -0
  438. package/dist/modules/workspace/workspace.tools.d.ts +19 -0
  439. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -0
  440. package/dist/modules/workspace/workspace.tools.js +767 -0
  441. package/dist/modules/workspace/workspace.tools.js.map +1 -0
  442. package/dist/shared/frontmatter-id.d.ts +35 -0
  443. package/dist/shared/frontmatter-id.d.ts.map +1 -0
  444. package/dist/shared/frontmatter-id.js +68 -0
  445. package/dist/shared/frontmatter-id.js.map +1 -0
  446. package/dist/shared/fs-walk.d.ts +9 -0
  447. package/dist/shared/fs-walk.d.ts.map +1 -0
  448. package/dist/shared/fs-walk.js +34 -0
  449. package/dist/shared/fs-walk.js.map +1 -0
  450. package/dist/shared/hash-email.d.ts +11 -0
  451. package/dist/shared/hash-email.d.ts.map +1 -0
  452. package/dist/shared/hash-email.js +14 -0
  453. package/dist/shared/hash-email.js.map +1 -0
  454. package/dist/shared/kb-layout.d.ts +38 -0
  455. package/dist/shared/kb-layout.d.ts.map +1 -0
  456. package/dist/shared/kb-layout.js +102 -0
  457. package/dist/shared/kb-layout.js.map +1 -0
  458. package/dist/shared/kb-layout.test.d.ts +2 -0
  459. package/dist/shared/kb-layout.test.d.ts.map +1 -0
  460. package/dist/shared/kb-layout.test.js +67 -0
  461. package/dist/shared/kb-layout.test.js.map +1 -0
  462. package/dist/shared/ssrf.d.ts +20 -0
  463. package/dist/shared/ssrf.d.ts.map +1 -0
  464. package/dist/shared/ssrf.js +89 -0
  465. package/dist/shared/ssrf.js.map +1 -0
  466. package/dist/shared/token-crypto.d.ts +16 -0
  467. package/dist/shared/token-crypto.d.ts.map +1 -0
  468. package/dist/shared/token-crypto.js +49 -0
  469. package/dist/shared/token-crypto.js.map +1 -0
  470. package/dist/shared/ttl-cache.d.ts +16 -0
  471. package/dist/shared/ttl-cache.d.ts.map +1 -0
  472. package/dist/shared/ttl-cache.js +27 -0
  473. package/dist/shared/ttl-cache.js.map +1 -0
  474. package/dist/shared/utcp-namespace.d.ts +46 -0
  475. package/dist/shared/utcp-namespace.d.ts.map +1 -0
  476. package/dist/shared/utcp-namespace.js +82 -0
  477. package/dist/shared/utcp-namespace.js.map +1 -0
  478. package/dist/version.d.ts +17 -0
  479. package/dist/version.d.ts.map +1 -0
  480. package/dist/version.js +19 -0
  481. package/dist/version.js.map +1 -0
  482. package/kb-template/.bevelignore +21 -0
  483. package/kb-template/Agents/.gitkeep +0 -0
  484. package/kb-template/Agents/README.md +38 -0
  485. package/kb-template/CLAUDE.md +419 -0
  486. package/kb-template/Data/.gitkeep +0 -0
  487. package/kb-template/Data/README.md +39 -0
  488. package/kb-template/KnowledgeBase/.gitkeep +0 -0
  489. package/kb-template/KnowledgeBase/README.md +37 -0
  490. package/kb-template/Pipelines/.gitkeep +0 -0
  491. package/kb-template/Pipelines/README.md +38 -0
  492. package/kb-template/Skills/.gitkeep +0 -0
  493. package/kb-template/Skills/README.md +32 -0
  494. package/kb-template/Tools/.gitkeep +0 -0
  495. package/kb-template/Tools/README.md +42 -0
  496. package/kb-template/access.md +36 -0
  497. package/migrations/0000_core_init.sql +243 -0
  498. package/migrations/meta/0000_snapshot.json +1480 -0
  499. package/migrations/meta/_journal.json +13 -0
  500. package/package.json +80 -0
  501. package/src/assets.ts +25 -0
  502. package/src/core/core-ports.ts +91 -0
  503. package/src/core/create-core-server.ts +338 -0
  504. package/src/core/create-core-services.ts +501 -0
  505. package/src/core-config.ts +257 -0
  506. package/src/index.ts +69 -0
  507. package/src/modules/access/__tests__/access-control.atref-batch.test.ts +98 -0
  508. package/src/modules/access/__tests__/access-control.read-batch.test.ts +132 -0
  509. package/src/modules/access/__tests__/access-control.service.test.ts +1011 -0
  510. package/src/modules/access/__tests__/access-mutation.service.test.ts +439 -0
  511. package/src/modules/access/__tests__/access-splice.test.ts +247 -0
  512. package/src/modules/access/__tests__/access.routes.revoke.test.ts +407 -0
  513. package/src/modules/access/__tests__/creator-access.test.ts +217 -0
  514. package/src/modules/access/__tests__/grant-sources.test.ts +204 -0
  515. package/src/modules/access/__tests__/kb-read-filter.test.ts +70 -0
  516. package/src/modules/access/__tests__/roles-admin.service.test.ts +469 -0
  517. package/src/modules/access/__tests__/roles-edit.test.ts +138 -0
  518. package/src/modules/access/__tests__/roles-yaml-guard.test.ts +70 -0
  519. package/src/modules/access/__tests__/roles.routes.test.ts +234 -0
  520. package/src/modules/access/access-control.interface.ts +383 -0
  521. package/src/modules/access/access-control.service.ts +1794 -0
  522. package/src/modules/access/access-errors.ts +60 -0
  523. package/src/modules/access/access-mutation.service.ts +369 -0
  524. package/src/modules/access/access-splice.ts +413 -0
  525. package/src/modules/access/access.routes.ts +894 -0
  526. package/src/modules/access/creator-access.ts +270 -0
  527. package/src/modules/access/kb-read-filter.ts +76 -0
  528. package/src/modules/access/roles-admin.service.ts +741 -0
  529. package/src/modules/access/roles-edit.ts +248 -0
  530. package/src/modules/access/roles-yaml-guard.ts +89 -0
  531. package/src/modules/admin/admin-access.routes.ts +29 -0
  532. package/src/modules/admin/admin-access.service.ts +38 -0
  533. package/src/modules/admin/admin.interface.ts +10 -0
  534. package/src/modules/auth/account-erasure.service.ts +183 -0
  535. package/src/modules/auth/auth.middleware.ts +78 -0
  536. package/src/modules/auth/auth.routes.ts +97 -0
  537. package/src/modules/auth/auth.service.ts +199 -0
  538. package/src/modules/code-mode/code-mode-names.ts +38 -0
  539. package/src/modules/code-mode/code-mode.tool.ts +117 -0
  540. package/src/modules/code-mode/index.ts +6 -0
  541. package/src/modules/database/connection.ts +15 -0
  542. package/src/modules/database/core-schema.ts +431 -0
  543. package/src/modules/database/migrate.ts +43 -0
  544. package/src/modules/database/schema.ts +11 -0
  545. package/src/modules/diff/__tests__/diff.routes.read-gate.test.ts +87 -0
  546. package/src/modules/diff/__tests__/diff.routes.rejectPathsLocked.test.ts +150 -0
  547. package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +184 -0
  548. package/src/modules/diff/__tests__/diff.service.test.ts +202 -0
  549. package/src/modules/diff/diff-paths.ts +9 -0
  550. package/src/modules/diff/diff.config.ts +12 -0
  551. package/src/modules/diff/diff.interface.ts +78 -0
  552. package/src/modules/diff/diff.routes.ts +277 -0
  553. package/src/modules/diff/diff.service.ts +508 -0
  554. package/src/modules/diff/line-diff.ts +79 -0
  555. package/src/modules/mcp/__tests__/bevel-oauth-provider.test.ts +287 -0
  556. package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +249 -0
  557. package/src/modules/mcp/__tests__/mcp-proxy-helpers.test.ts +253 -0
  558. package/src/modules/mcp/__tests__/mcp-session-store.test.ts +151 -0
  559. package/src/modules/mcp/__tests__/mcp.e2e.test.ts +150 -0
  560. package/src/modules/mcp/__tests__/mcp.routes.delete.test.ts +92 -0
  561. package/src/modules/mcp/__tests__/mcp.service.test.ts +414 -0
  562. package/src/modules/mcp/mcp-auth.middleware.ts +126 -0
  563. package/src/modules/mcp/mcp-session-store.ts +162 -0
  564. package/src/modules/mcp/mcp.routes.ts +263 -0
  565. package/src/modules/mcp/mcp.service.ts +973 -0
  566. package/src/modules/mcp/oauth/bevel-oauth-provider.ts +401 -0
  567. package/src/modules/mcp/oauth/oauth-consent.routes.ts +60 -0
  568. package/src/modules/mcp/oauth/oauth-state.ts +61 -0
  569. package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +277 -0
  570. package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +206 -0
  571. package/src/modules/secrets-vault/__tests__/mcp-oauth-discovery.service.test.ts +178 -0
  572. package/src/modules/secrets-vault/__tests__/scopes-covered.test.ts +101 -0
  573. package/src/modules/secrets-vault/__tests__/secrets-variable-loader.test.ts +54 -0
  574. package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +143 -0
  575. package/src/modules/secrets-vault/db-secrets-vault.service.ts +792 -0
  576. package/src/modules/secrets-vault/index.ts +25 -0
  577. package/src/modules/secrets-vault/mcp-oauth-discovery.service.ts +289 -0
  578. package/src/modules/secrets-vault/secrets-variable-loader.ts +104 -0
  579. package/src/modules/secrets-vault/secrets-vault.contract.ts +270 -0
  580. package/src/modules/secrets-vault/secrets-vault.routes.ts +526 -0
  581. package/src/modules/skills/__tests__/skills.service.test.ts +176 -0
  582. package/src/modules/skills/index.ts +10 -0
  583. package/src/modules/skills/skills.contract.ts +54 -0
  584. package/src/modules/skills/skills.routes.ts +38 -0
  585. package/src/modules/skills/skills.service.ts +245 -0
  586. package/src/modules/skills/skills.tools.ts +121 -0
  587. package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +358 -0
  588. package/src/modules/tool-auth/__tests__/internal-token.service.test.ts +79 -0
  589. package/src/modules/tool-auth/__tests__/manual-auth.middleware.test.ts +88 -0
  590. package/src/modules/tool-auth/external-api-key.errors.ts +25 -0
  591. package/src/modules/tool-auth/external-api-key.interface.ts +99 -0
  592. package/src/modules/tool-auth/external-api-key.service.ts +209 -0
  593. package/src/modules/tool-auth/internal-token.service.ts +124 -0
  594. package/src/modules/tool-auth/llm-usage-meter.ts +19 -0
  595. package/src/modules/tool-auth/tool-auth.middleware.ts +220 -0
  596. package/src/modules/tool-helpers/__tests__/phase0-loopback-spike.test.ts +129 -0
  597. package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +95 -0
  598. package/src/modules/tool-helpers/__tests__/tools-surface.test.ts +146 -0
  599. package/src/modules/tool-helpers/__tests__/validate-token.test.ts +75 -0
  600. package/src/modules/tool-helpers/index.ts +18 -0
  601. package/src/modules/tool-helpers/tool-context.ts +98 -0
  602. package/src/modules/tool-helpers/tool-def.ts +73 -0
  603. package/src/modules/tool-helpers/tool-handler.ts +91 -0
  604. package/src/modules/tool-helpers/tool.contract.ts +85 -0
  605. package/src/modules/tool-helpers/validate-token.ts +50 -0
  606. package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +200 -0
  607. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +499 -0
  608. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +156 -0
  609. package/src/modules/tool-manuals/index.ts +12 -0
  610. package/src/modules/tool-manuals/tool-manuals.contract.ts +183 -0
  611. package/src/modules/tool-manuals/tool-manuals.routes.ts +110 -0
  612. package/src/modules/tool-manuals/tool-manuals.service.ts +781 -0
  613. package/src/modules/tool-manuals/tool-manuals.tools.ts +202 -0
  614. package/src/modules/tool-registry/__tests__/tool-registry.test.ts +64 -0
  615. package/src/modules/tool-registry/manual.routes.ts +87 -0
  616. package/src/modules/tool-registry/tool-registry.ts +55 -0
  617. package/src/modules/tool-registry/tool.contract.ts +52 -0
  618. package/src/modules/workflow/__tests__/event-bus.test.ts +322 -0
  619. package/src/modules/workflow/__tests__/file-change-notifier.test.ts +51 -0
  620. package/src/modules/workflow/__tests__/format-affected-owners.test.ts +67 -0
  621. package/src/modules/workflow/__tests__/locking-filesystem.test.ts +445 -0
  622. package/src/modules/workflow/__tests__/pending-commits.canonical.test.ts +36 -0
  623. package/src/modules/workflow/__tests__/pending-commits.worker.test.ts +243 -0
  624. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +308 -0
  625. package/src/modules/workflow/__tests__/sanitize-error.test.ts +67 -0
  626. package/src/modules/workflow/__tests__/session-ontology.policy.test.ts +62 -0
  627. package/src/modules/workflow/__tests__/session-ontology.service.test.ts +200 -0
  628. package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +232 -0
  629. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +380 -0
  630. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +340 -0
  631. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +192 -0
  632. package/src/modules/workflow/agent-tools/workflow.tools.ts +502 -0
  633. package/src/modules/workflow/event-bus.ts +262 -0
  634. package/src/modules/workflow/events.routes.ts +266 -0
  635. package/src/modules/workflow/file-change-notifier.ts +54 -0
  636. package/src/modules/workflow/file-lock.service.ts +269 -0
  637. package/src/modules/workflow/git/__tests__/branch-name.test.ts +86 -0
  638. package/src/modules/workflow/git/__tests__/branchAuthor.test.ts +80 -0
  639. package/src/modules/workflow/git/__tests__/clone-config.test.ts +15 -0
  640. package/src/modules/workflow/git/__tests__/git-test-helpers.ts +47 -0
  641. package/src/modules/workflow/git/__tests__/git-version.failure.test.ts +24 -0
  642. package/src/modules/workflow/git/__tests__/git-version.test.ts +49 -0
  643. package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +389 -0
  644. package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +124 -0
  645. package/src/modules/workflow/git/__tests__/git.service.commitChanges.test.ts +105 -0
  646. package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +211 -0
  647. package/src/modules/workflow/git/__tests__/git.service.createBranch.test.ts +154 -0
  648. package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +320 -0
  649. package/src/modules/workflow/git/__tests__/git.service.diffFileAtCommit.test.ts +202 -0
  650. package/src/modules/workflow/git/__tests__/git.service.diffFileBetweenBranches.test.ts +453 -0
  651. package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +198 -0
  652. package/src/modules/workflow/git/__tests__/git.service.listTrackedFiles.test.ts +125 -0
  653. package/src/modules/workflow/git/__tests__/git.service.logForFile.test.ts +219 -0
  654. package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +145 -0
  655. package/src/modules/workflow/git/__tests__/git.service.pendingChanges.test.ts +240 -0
  656. package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +272 -0
  657. package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +232 -0
  658. package/src/modules/workflow/git/__tests__/git.service.readFileAtRef.test.ts +101 -0
  659. package/src/modules/workflow/git/__tests__/git.service.status.test.ts +127 -0
  660. package/src/modules/workflow/git/__tests__/mutex.test.ts +78 -0
  661. package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +225 -0
  662. package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-cancel.test.ts +101 -0
  663. package/src/modules/workflow/git/branch-name.ts +70 -0
  664. package/src/modules/workflow/git/clone-config.ts +71 -0
  665. package/src/modules/workflow/git/git-version.ts +70 -0
  666. package/src/modules/workflow/git/git.service.ts +2248 -0
  667. package/src/modules/workflow/git/mutex.ts +22 -0
  668. package/src/modules/workflow/git/pull-request.service.ts +447 -0
  669. package/src/modules/workflow/locking-filesystem.ts +489 -0
  670. package/src/modules/workflow/pending-commits.service.ts +444 -0
  671. package/src/modules/workflow/pending-commits.worker.ts +361 -0
  672. package/src/modules/workflow/read-only-filesystem.ts +54 -0
  673. package/src/modules/workflow/recovery-bot.ts +73 -0
  674. package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +560 -0
  675. package/src/modules/workflow/review-workflow/__tests__/cancel-pr.test.ts +176 -0
  676. package/src/modules/workflow/review-workflow/__tests__/merge-gate.test.ts +258 -0
  677. package/src/modules/workflow/review-workflow/review-workflow.interface.ts +199 -0
  678. package/src/modules/workflow/review-workflow/review-workflow.service.ts +806 -0
  679. package/src/modules/workflow/sanitize-error.ts +62 -0
  680. package/src/modules/workflow/session-ontology.policy.ts +70 -0
  681. package/src/modules/workflow/session-ontology.service.ts +178 -0
  682. package/src/modules/workflow/workflow-hooks.ts +101 -0
  683. package/src/modules/workflow/workflow.errors.ts +285 -0
  684. package/src/modules/workflow/workflow.routes.ts +858 -0
  685. package/src/modules/workflow/workflow.service.ts +1555 -0
  686. package/src/modules/workspace/__tests__/kb-seed.service.test.ts +213 -0
  687. package/src/modules/workspace/__tests__/routine-write-policy.test.ts +68 -0
  688. package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +237 -0
  689. package/src/modules/workspace/__tests__/spill-store.test.ts +43 -0
  690. package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +233 -0
  691. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +176 -0
  692. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +303 -0
  693. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +276 -0
  694. package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +120 -0
  695. package/src/modules/workspace/__tests__/workspace.service.test.ts +565 -0
  696. package/src/modules/workspace/__tests__/workspace.tools.test.ts +504 -0
  697. package/src/modules/workspace/bevel-ignore.ts +62 -0
  698. package/src/modules/workspace/kb-seed.interface.ts +36 -0
  699. package/src/modules/workspace/kb-seed.service.ts +361 -0
  700. package/src/modules/workspace/routine-write-policy.ts +79 -0
  701. package/src/modules/workspace/session-ontology.gate.ts +189 -0
  702. package/src/modules/workspace/session-sink.ts +25 -0
  703. package/src/modules/workspace/spill-store.ts +87 -0
  704. package/src/modules/workspace/workspace.routes.ts +1114 -0
  705. package/src/modules/workspace/workspace.service.ts +1343 -0
  706. package/src/modules/workspace/workspace.tools.ts +885 -0
  707. package/src/shared/__tests__/frontmatter-id.test.ts +88 -0
  708. package/src/shared/__tests__/fs-walk.test.ts +42 -0
  709. package/src/shared/__tests__/ssrf.test.ts +53 -0
  710. package/src/shared/__tests__/utcp-namespace.test.ts +19 -0
  711. package/src/shared/frontmatter-id.ts +72 -0
  712. package/src/shared/fs-walk.ts +30 -0
  713. package/src/shared/hash-email.ts +14 -0
  714. package/src/shared/kb-layout.test.ts +88 -0
  715. package/src/shared/kb-layout.ts +101 -0
  716. package/src/shared/ssrf.ts +78 -0
  717. package/src/shared/token-crypto.ts +54 -0
  718. package/src/shared/ttl-cache.ts +27 -0
  719. package/src/shared/utcp-namespace.ts +88 -0
  720. package/src/version.ts +19 -0
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Per-(workspace, branch, path) edit lock store. The spec calls for
3
+ * file-scoped locks acquired on first edit and released either explicitly
4
+ * (with an autosave commit) or implicitly by TTL expiry — preventing a
5
+ * disconnected client from holding a file hostage.
6
+ *
7
+ * Lock state lives in Postgres because workspaces share state across
8
+ * backend instances eventually. The hot read path (does someone hold this
9
+ * lock?) is one indexed lookup; the hot write path (heartbeat) is a single
10
+ * row update. We don't bother caching in process memory — the lock table
11
+ * is the source of truth and any cache would lose its purpose the moment
12
+ * a different replica takes over.
13
+ *
14
+ * Stale-lock semantics: `get`, `acquire`, and `heartbeat` all treat a row
15
+ * with `expires_at <= now()` as if the lock didn't exist. We purge it
16
+ * lazily on next access rather than running a sweeper — the row count is
17
+ * bounded by concurrent editors, not history, so lazy GC is fine.
18
+ */
19
+
20
+ import { and, eq, gt, lte } from 'drizzle-orm';
21
+ import type { Database } from '../database/connection.js';
22
+ import { fileLocks } from '../database/schema.js';
23
+ import type { AcquireLockResult, AuthUser, FileLock } from '@bevel-software/platform-shared';
24
+ import { WorkflowValidationError } from './workflow.errors.js';
25
+
26
+ /**
27
+ * Lock lifetime without a heartbeat. The client is expected to heartbeat
28
+ * every ~half this interval so a single missed ping doesn't release the
29
+ * lock out from under them. Bumping the TTL trades off "how long does a
30
+ * crashed client hold a file" against "how forgiving are we of network
31
+ * blips" — 60s is a balance.
32
+ */
33
+ const LOCK_TTL_MS = 60_000;
34
+
35
+ function rowToFileLock(row: typeof fileLocks.$inferSelect): FileLock {
36
+ return {
37
+ branch: row.branch,
38
+ path: row.path,
39
+ holderUserId: row.holderUserId,
40
+ holderName: row.holderName,
41
+ acquiredAt: row.acquiredAt.toISOString(),
42
+ lastHeartbeatAt: row.lastHeartbeatAt.toISOString(),
43
+ expiresAt: row.expiresAt.toISOString(),
44
+ };
45
+ }
46
+
47
+ export class FileLockService {
48
+ constructor(private readonly db: Database) {}
49
+
50
+ /**
51
+ * Acquire a lock for `(workspaceId, branch, path)` on behalf of `user`.
52
+ *
53
+ * Three outcomes folded into the same return shape:
54
+ * - No existing row: insert + return `{ acquired: true, lock }`.
55
+ * - Existing row, expired: take it over (update) + `{ acquired: true }`.
56
+ * - Existing row, live, different user: return `{ acquired: false }`
57
+ * with the current holder's lock state so the UI can render
58
+ * "Locked by X" without a follow-up call.
59
+ * - Existing row, live, same user: refresh TTL + `{ acquired: true }`
60
+ * so re-acquiring your own lock is idempotent.
61
+ */
62
+ async acquire(
63
+ workspaceId: string,
64
+ branch: string,
65
+ targetPath: string,
66
+ user: AuthUser,
67
+ ): Promise<AcquireLockResult> {
68
+ const now = new Date();
69
+ const expiresAt = new Date(now.getTime() + LOCK_TTL_MS);
70
+
71
+ // Atomic acquire-or-takeover, in a single statement. Two callers
72
+ // racing on the same `(workspace, branch, path)` would otherwise
73
+ // both SELECT no row → both INSERT (one PK-fails) or both SELECT a
74
+ // stale row → both UPDATE (one silently overwrites the other's
75
+ // takeover). PostgreSQL's INSERT ... ON CONFLICT DO UPDATE WHERE
76
+ // collapses both paths into one atomic statement:
77
+ //
78
+ // - No existing row → INSERT succeeds, RETURNING our new row.
79
+ // - Existing row, WHERE matches (stale OR same user) → UPDATE
80
+ // fires, RETURNING the updated row.
81
+ // - Existing row, WHERE doesn't match (live + different user) →
82
+ // the conflict is silently absorbed (PG's documented behavior),
83
+ // RETURNING is empty. We then read the live holder for the
84
+ // "Locked by X" payload.
85
+ //
86
+ // **Only expired rows can be taken over.** The same-user clause used
87
+ // to be here as an "idempotent refresh" shortcut, but it had a nasty
88
+ // side effect: the AGENT and the HUMAN EDITOR share the same `user.id`
89
+ // (agent edits attribute to the human), so the agent's
90
+ // `LockingFilesystem.withLock` would silently steal a lock the human
91
+ // had taken via the Edit button — overwriting their in-flight edits
92
+ // and dropping their lock on agent-release. Removing same-user from
93
+ // setWhere makes acquire strict: a non-expired lock is contended even
94
+ // by yourself, so the agent's retry/skip path kicks in and the human
95
+ // keeps editing. Real refresh-while-holding goes through
96
+ // `heartbeat()` (which has its own same-user UPDATE), and the
97
+ // editor's save flow detects "I already hold it" via `getLock` in
98
+ // `workspace.routes.withLock` rather than re-acquiring.
99
+ const upsertResult = await this.db
100
+ .insert(fileLocks)
101
+ .values({
102
+ workspaceId,
103
+ branch,
104
+ path: targetPath,
105
+ holderUserId: user.id,
106
+ holderName: user.name,
107
+ acquiredAt: now,
108
+ lastHeartbeatAt: now,
109
+ expiresAt,
110
+ })
111
+ .onConflictDoUpdate({
112
+ target: [fileLocks.workspaceId, fileLocks.branch, fileLocks.path],
113
+ set: {
114
+ holderUserId: user.id,
115
+ holderName: user.name,
116
+ acquiredAt: now,
117
+ lastHeartbeatAt: now,
118
+ expiresAt,
119
+ },
120
+ setWhere: lte(fileLocks.expiresAt, now),
121
+ })
122
+ .returning();
123
+
124
+ if (upsertResult.length > 0) {
125
+ return { acquired: true, lock: rowToFileLock(upsertResult[0]) };
126
+ }
127
+
128
+ // Live lock held by another user. Fetch it for the "Locked by X" UI
129
+ // payload. We don't filter on `expiresAt > now` here because the
130
+ // upsert above already proved an unreclaimable row exists; the only
131
+ // way this read returns null is a tight race where the holder
132
+ // released between the upsert and this select — rare enough to
133
+ // surface as a retryable error rather than complicate the happy path.
134
+ const [holder] = await this.db
135
+ .select()
136
+ .from(fileLocks)
137
+ .where(
138
+ and(
139
+ eq(fileLocks.workspaceId, workspaceId),
140
+ eq(fileLocks.branch, branch),
141
+ eq(fileLocks.path, targetPath),
142
+ ),
143
+ )
144
+ .limit(1);
145
+ if (!holder) {
146
+ throw new WorkflowValidationError(
147
+ `Lock contention race on "${targetPath}" — please retry.`,
148
+ { kind: 'lock-contention-race', branch, path: targetPath },
149
+ );
150
+ }
151
+ return { acquired: false, lock: rowToFileLock(holder) };
152
+ }
153
+
154
+ /**
155
+ * Extend the lock's TTL. Refuses if the lock is held by someone else or
156
+ * doesn't exist — the client is then expected to re-call `acquire`,
157
+ * which will either succeed (taking over a stale lock) or surface the
158
+ * current holder.
159
+ */
160
+ async heartbeat(
161
+ workspaceId: string,
162
+ branch: string,
163
+ targetPath: string,
164
+ user: AuthUser,
165
+ ): Promise<FileLock> {
166
+ const now = new Date();
167
+ const expiresAt = new Date(now.getTime() + LOCK_TTL_MS);
168
+ // The expiry guard (`expiresAt > now`) matters because an expired
169
+ // lock is conceptually released, even if its row hasn't been swept
170
+ // and no other user has taken it yet. Without it, a client whose
171
+ // tab was suspended past the TTL would silently extend a lock that
172
+ // the rest of the system considers "free for the next acquire" —
173
+ // any subsequent `acquire()` by another user could already have
174
+ // taken it (the upsert's `lte(expiresAt, now)` predicate matches),
175
+ // and the heartbeat would race with that takeover. Failing here
176
+ // forces the client to re-acquire (which goes through the proper
177
+ // takeover path) and surfaces the "your session went stale" state
178
+ // honestly.
179
+ const [updated] = await this.db
180
+ .update(fileLocks)
181
+ .set({ lastHeartbeatAt: now, expiresAt })
182
+ .where(
183
+ and(
184
+ eq(fileLocks.workspaceId, workspaceId),
185
+ eq(fileLocks.branch, branch),
186
+ eq(fileLocks.path, targetPath),
187
+ eq(fileLocks.holderUserId, user.id),
188
+ gt(fileLocks.expiresAt, now),
189
+ ),
190
+ )
191
+ .returning();
192
+ if (!updated) {
193
+ throw new WorkflowValidationError(
194
+ `Cannot heartbeat lock on "${targetPath}": not held by you (or no longer exists).`,
195
+ { kind: 'lock-not-held', branch, path: targetPath },
196
+ );
197
+ }
198
+ return rowToFileLock(updated);
199
+ }
200
+
201
+ /**
202
+ * Idempotent release. Deletes the lock row when the caller holds it;
203
+ * silently no-ops otherwise (the lock may have expired and been taken
204
+ * over by someone else — that's not an error from the caller's POV).
205
+ */
206
+ async release(
207
+ workspaceId: string,
208
+ branch: string,
209
+ targetPath: string,
210
+ user: AuthUser,
211
+ ): Promise<void> {
212
+ await this.db
213
+ .delete(fileLocks)
214
+ .where(
215
+ and(
216
+ eq(fileLocks.workspaceId, workspaceId),
217
+ eq(fileLocks.branch, branch),
218
+ eq(fileLocks.path, targetPath),
219
+ eq(fileLocks.holderUserId, user.id),
220
+ ),
221
+ );
222
+ }
223
+
224
+ /**
225
+ * Read the current lock for `(workspace, branch, path)`. Returns null when
226
+ * no one holds it, OR when the existing row is expired — expired locks
227
+ * are purged here lazily.
228
+ */
229
+ async get(
230
+ workspaceId: string,
231
+ branch: string,
232
+ targetPath: string,
233
+ ): Promise<FileLock | null> {
234
+ const rows = await this.db
235
+ .select()
236
+ .from(fileLocks)
237
+ .where(
238
+ and(
239
+ eq(fileLocks.workspaceId, workspaceId),
240
+ eq(fileLocks.branch, branch),
241
+ eq(fileLocks.path, targetPath),
242
+ ),
243
+ )
244
+ .limit(1);
245
+ if (rows.length === 0) return null;
246
+ const row = rows[0];
247
+ if (row.expiresAt.getTime() <= Date.now()) {
248
+ // Lazy GC — drop the stale row so the next `acquire` doesn't have
249
+ // to bypass it. Bind the delete to this exact row's `expiresAt` so
250
+ // a concurrent acquire that wrote a fresh row in the gap between
251
+ // our SELECT and DELETE doesn't get clobbered. Primary key
252
+ // `(workspaceId, branch, path)` alone isn't enough — a new acquire
253
+ // for the same triple updates that row in place with a future
254
+ // expiry, and a path-only delete here would silently nuke it.
255
+ await this.db
256
+ .delete(fileLocks)
257
+ .where(
258
+ and(
259
+ eq(fileLocks.workspaceId, workspaceId),
260
+ eq(fileLocks.branch, branch),
261
+ eq(fileLocks.path, targetPath),
262
+ eq(fileLocks.expiresAt, row.expiresAt),
263
+ ),
264
+ );
265
+ return null;
266
+ }
267
+ return rowToFileLock(row);
268
+ }
269
+ }
@@ -0,0 +1,86 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ assertValidBranchName,
4
+ assertValidRelativePath,
5
+ isProtectedBranch,
6
+ } from '../branch-name.js';
7
+ import { BranchNameError, WorkflowValidationError } from '../../workflow.errors.js';
8
+
9
+ describe('assertValidBranchName', () => {
10
+ it.each([
11
+ 'ali-raza/add-owner',
12
+ 'feature/x',
13
+ 'fix_123',
14
+ 'v1.2.3',
15
+ 'main',
16
+ 'release-2026.04',
17
+ ])('accepts %s', (name) => {
18
+ expect(() => assertValidBranchName(name)).not.toThrow();
19
+ });
20
+
21
+ it.each([
22
+ ['empty', ''],
23
+ ['leading dash', '-dangerous'],
24
+ ['semicolon', 'foo;rm -rf /'],
25
+ ['backtick', 'foo`whoami`'],
26
+ ['space', 'foo bar'],
27
+ ['double dot', 'foo..bar'],
28
+ ['trailing slash', 'foo/'],
29
+ ['trailing dot', 'foo.'],
30
+ ['trailing .lock', 'foo.lock'],
31
+ ['double slash', 'foo//bar'],
32
+ ['ref expansion', 'HEAD@{0}'],
33
+ ['null byte', 'foo\x00bar'],
34
+ ['newline', 'foo\nbar'],
35
+ ['path traversal', '../../etc/passwd'],
36
+ ])('rejects %s (%s)', (_label, name) => {
37
+ expect(() => assertValidBranchName(name)).toThrow(BranchNameError);
38
+ });
39
+ });
40
+
41
+ describe('assertValidRelativePath', () => {
42
+ it.each([
43
+ 'Knowledge/Foo.md',
44
+ 'NodeTypes/Process.md',
45
+ 'scripts/generate-mermaid.js',
46
+ 'a/b/c/d.md',
47
+ 'file-with-dash.md',
48
+ // Pathspec glob characters used to be rejected here, but `GitService.git()`
49
+ // now sets `GIT_LITERAL_PATHSPECS=1` on every git subprocess, so KB files
50
+ // arriving with bracketed prefixes (`[Approved]`, `[New]`, `[Updated …]`)
51
+ // or other glob metacharacters round-trip through commit cleanly.
52
+ '[Approved] Purchasing_Order archive.docx',
53
+ 'Purchasing/[New] Purchasing_E-Invoicing DE.docx',
54
+ 'Purchasing/[Updated 03.09.2025] Purchasing_How to search_Product detail page.docx',
55
+ 'docs/wildcard*name.md',
56
+ 'docs/question?name.md',
57
+ 'docs/bang!name.md',
58
+ ])('accepts %s', (p) => {
59
+ expect(() => assertValidRelativePath(p)).not.toThrow();
60
+ });
61
+
62
+ it.each([
63
+ ['empty', ''],
64
+ ['absolute unix', '/etc/passwd'],
65
+ ['windows drive', 'C:/Users/a'],
66
+ ['parent segment', '../etc/passwd'],
67
+ ['nested parent', 'a/../b'],
68
+ ['current segment', 'a/./b'],
69
+ ['null byte', 'a\x00b'],
70
+ ['leading dash', '-afile'],
71
+ ])('rejects %s (%s)', (_label, p) => {
72
+ expect(() => assertValidRelativePath(p)).toThrow(WorkflowValidationError);
73
+ });
74
+ });
75
+
76
+ describe('isProtectedBranch', () => {
77
+ it('protects current-company-state and target-company-state', () => {
78
+ expect(isProtectedBranch('current-company-state')).toBe(true);
79
+ expect(isProtectedBranch('target-company-state')).toBe(true);
80
+ });
81
+ it('does not protect user branches', () => {
82
+ expect(isProtectedBranch('ali-raza/add-owner')).toBe(false);
83
+ expect(isProtectedBranch('main')).toBe(false);
84
+ expect(isProtectedBranch('develop')).toBe(false);
85
+ });
86
+ });
@@ -0,0 +1,80 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ branchAuthorLocalpart,
4
+ isBranchAuthoredBy,
5
+ } from '@bevel-software/platform-shared';
6
+
7
+ describe('branchAuthorLocalpart', () => {
8
+ it('extracts and lowercases the localpart', () => {
9
+ expect(branchAuthorLocalpart('Alice@example.com')).toBe('alice');
10
+ });
11
+
12
+ it('sanitizes dotted localparts to match slugifyDraftName', () => {
13
+ // The frontend slugifies "john.doe" → "john-doe" when creating drafts,
14
+ // so authorship has to recognise the same shape on lookup.
15
+ expect(branchAuthorLocalpart('john.doe@example.com')).toBe('john-doe');
16
+ });
17
+
18
+ it('sanitizes plus-addressed localparts the same way', () => {
19
+ expect(branchAuthorLocalpart('alice+test@example.com')).toBe('alice-test');
20
+ });
21
+
22
+ it('returns null for empty / missing email', () => {
23
+ expect(branchAuthorLocalpart('')).toBeNull();
24
+ expect(branchAuthorLocalpart(null)).toBeNull();
25
+ expect(branchAuthorLocalpart(undefined)).toBeNull();
26
+ });
27
+
28
+ it('returns null when the localpart sanitizes to nothing (no auth identity)', () => {
29
+ // Email with only non-alphanumeric chars before @ — refuse to derive an
30
+ // identity rather than silently mapping to a default like "user", which
31
+ // would let any malformed-email user delete any "user/..." branch.
32
+ expect(branchAuthorLocalpart('___@example.com')).toBeNull();
33
+ });
34
+
35
+ it('handles emails with no @ by treating the whole string as localpart', () => {
36
+ // Internal identity systems occasionally use bare usernames; sanitizing
37
+ // them through the same pipeline keeps the comparison consistent.
38
+ expect(branchAuthorLocalpart('alice')).toBe('alice');
39
+ });
40
+ });
41
+
42
+ describe('isBranchAuthoredBy', () => {
43
+ it('matches when the branch name starts with <localpart>/', () => {
44
+ expect(isBranchAuthoredBy('alice/my-draft', 'alice@example.com')).toBe(true);
45
+ });
46
+
47
+ it('rejects when prefix is a different user', () => {
48
+ expect(isBranchAuthoredBy('bob/my-draft', 'alice@example.com')).toBe(false);
49
+ });
50
+
51
+ it('rejects when the branch has no slash (no recognisable prefix)', () => {
52
+ expect(isBranchAuthoredBy('alice', 'alice@example.com')).toBe(false);
53
+ });
54
+
55
+ it('rejects conventional non-author prefixes (fix/, polish/)', () => {
56
+ // `fix/...` is a common CLI-created prefix in this repo. It has no author
57
+ // claim, so the authored-by check must NOT grant ownership to anyone.
58
+ expect(isBranchAuthoredBy('fix/some-bug', 'alice@example.com')).toBe(false);
59
+ expect(isBranchAuthoredBy('polish/foo', 'alice@example.com')).toBe(false);
60
+ });
61
+
62
+ it('returns false when email is null / undefined / empty', () => {
63
+ expect(isBranchAuthoredBy('alice/my-draft', null)).toBe(false);
64
+ expect(isBranchAuthoredBy('alice/my-draft', undefined)).toBe(false);
65
+ expect(isBranchAuthoredBy('alice/my-draft', '')).toBe(false);
66
+ });
67
+
68
+ it('matches case-insensitively on the email side (branch is already lowercase by convention)', () => {
69
+ // slugifyDraftName lowercases the email at create time, so a user with
70
+ // capitals in their email still ends up owning a lowercase prefix.
71
+ expect(isBranchAuthoredBy('alice/draft', 'ALICE@example.com')).toBe(true);
72
+ });
73
+
74
+ it('requires the slash boundary — does not treat substring as prefix', () => {
75
+ // "alice-extra/foo" must not look authored by "alice" — otherwise users
76
+ // could delete other people's branches whose prefix happens to start
77
+ // with their own localpart.
78
+ expect(isBranchAuthoredBy('alice-extra/foo', 'alice@example.com')).toBe(false);
79
+ });
80
+ });
@@ -0,0 +1,15 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cloneTrackingConfigArgs, ORIGIN_FETCH_REFSPEC } from '../clone-config.js';
3
+
4
+ describe('cloneTrackingConfigArgs', () => {
5
+ // A slashed draft name is the everyday case (`<email-localpart>/<slug>`), and
6
+ // the branch lands verbatim inside the config KEY — pin the exact tuples so a
7
+ // future quoting/encoding change can't silently re-point tracking.
8
+ it('emits the three --replace-all tuples for a slashed branch', () => {
9
+ expect(cloneTrackingConfigArgs('feature/x')).toEqual([
10
+ ['config', '--replace-all', 'remote.origin.fetch', ORIGIN_FETCH_REFSPEC],
11
+ ['config', '--replace-all', 'branch.feature/x.remote', 'origin'],
12
+ ['config', '--replace-all', 'branch.feature/x.merge', 'refs/heads/feature/x'],
13
+ ]);
14
+ });
15
+ });
@@ -0,0 +1,47 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import type { WorkspaceService } from '../../../workspace/workspace.service.js';
4
+ import { WorkflowHooks } from '../../workflow-hooks.js';
5
+
6
+ /**
7
+ * Helpers shared by the GitService integration suites that drive a real git
8
+ * against temp repos (`git.service.pull.test.ts`,
9
+ * `git.service.postMergePull.test.ts`). Not a test file itself — vitest only
10
+ * picks up `*.test.ts`.
11
+ */
12
+
13
+ const execFileAsync = promisify(execFile);
14
+
15
+ /** Run git with a pinned test committer identity, discarding output. */
16
+ export async function runGit(cwd: string, args: string[]): Promise<void> {
17
+ await execFileAsync('git', args, {
18
+ cwd,
19
+ env: {
20
+ ...process.env,
21
+ GIT_AUTHOR_NAME: 'Test', GIT_AUTHOR_EMAIL: 't@x.com',
22
+ GIT_COMMITTER_NAME: 'Test', GIT_COMMITTER_EMAIL: 't@x.com',
23
+ },
24
+ });
25
+ }
26
+
27
+ /** Run git and return its trimmed stdout. */
28
+ export async function gitOut(cwd: string, args: string[]): Promise<string> {
29
+ const { stdout } = await execFileAsync('git', args, { cwd });
30
+ return stdout.toString().trim();
31
+ }
32
+
33
+ /** An empty hooks registry — no commit-time validation, so pulls/merges never block. */
34
+ export function stubWorkflowHooks(): WorkflowHooks {
35
+ return new WorkflowHooks();
36
+ }
37
+
38
+ /** Resolves each workspace id to its directory, like the real service does. */
39
+ export function stubWorkspaceService(dirs: Record<string, string>): WorkspaceService {
40
+ return {
41
+ getWorkspacePath: async (id: string) => {
42
+ const dir = dirs[id];
43
+ if (!dir) throw new Error(`unexpected workspace ${id}`);
44
+ return dir;
45
+ },
46
+ } as unknown as WorkspaceService;
47
+ }
@@ -0,0 +1,24 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { assertGitVersion } from '../git-version.js';
3
+
4
+ // Lives in its own file (not git-version.test.ts) because `git-version.ts`
5
+ // binds `promisify(execFile)` at module load: the spawn failure must be mocked
6
+ // module-wide before that import, which would also break the sibling test that
7
+ // runs against the real git binary.
8
+ vi.mock('node:child_process', () => ({
9
+ execFile: (
10
+ _cmd: string,
11
+ _args: readonly string[],
12
+ cb: (err: Error) => void,
13
+ ) => {
14
+ cb(Object.assign(new Error('spawn git ENOENT'), { code: 'ENOENT' }));
15
+ },
16
+ }));
17
+
18
+ describe('assertGitVersion — git binary missing', () => {
19
+ it('wraps the spawn failure in the "git is required" boot error', async () => {
20
+ await expect(assertGitVersion()).rejects.toThrow(
21
+ /git is required but could not be run: .*ENOENT/,
22
+ );
23
+ });
24
+ });
@@ -0,0 +1,49 @@
1
+ import { describe, it, expect, vi, afterEach } from 'vitest';
2
+ import {
3
+ MIN_GIT_VERSION,
4
+ parseGitVersion,
5
+ assertSupportedGitVersion,
6
+ assertGitVersion,
7
+ } from '../git-version.js';
8
+
9
+ describe('the git version floor', () => {
10
+ afterEach(() => {
11
+ vi.restoreAllMocks();
12
+ });
13
+
14
+ it('reads the major/minor out of the shapes git actually prints', () => {
15
+ expect(parseGitVersion('git version 2.39.5\n')).toEqual([2, 39]);
16
+ expect(parseGitVersion('git version 2.39.5 (Apple Git-154)\n')).toEqual([2, 39]);
17
+ expect(parseGitVersion('git version 2.45.1.windows.1\n')).toEqual([2, 45]);
18
+ expect(parseGitVersion('git version 3.0\n')).toEqual([3, 0]);
19
+ expect(parseGitVersion('not git at all')).toBeNull();
20
+ });
21
+
22
+ it('rejects a git too old for --no-write-fetch-head', () => {
23
+ const [major, minor] = MIN_GIT_VERSION;
24
+ expect(() => assertSupportedGitVersion(`git version ${major}.${minor - 1}.0`))
25
+ .toThrow(/git 2\.29 or newer is required, found 2\.28/);
26
+ expect(() => assertSupportedGitVersion('git version 1.9.5')).toThrow(/required/);
27
+ });
28
+
29
+ it('accepts the floor itself and anything newer', () => {
30
+ const [major, minor] = MIN_GIT_VERSION;
31
+ expect(() => assertSupportedGitVersion(`git version ${major}.${minor}.0`)).not.toThrow();
32
+ expect(() => assertSupportedGitVersion('git version 2.39.5')).not.toThrow();
33
+ expect(() => assertSupportedGitVersion('git version 3.0.0')).not.toThrow();
34
+ });
35
+
36
+ // A git build with an unusual version banner is far more likely than one
37
+ // older than 2.29, so an unreadable string must not take down the boot.
38
+ it('warns but does not block boot on an unreadable version string', () => {
39
+ const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
40
+ expect(() => assertSupportedGitVersion('some vendored git\n')).not.toThrow();
41
+ expect(warn).toHaveBeenCalled();
42
+ });
43
+
44
+ // The real binary on any machine that can run this suite is well past the
45
+ // floor; this pins the wiring (spawn + parse) rather than the version.
46
+ it('passes against the git installed on this machine', async () => {
47
+ await expect(assertGitVersion()).resolves.toBeUndefined();
48
+ });
49
+ });