@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,88 @@
1
+ import { describe, test, expect, vi } from 'vitest';
2
+ import {
3
+ extractFrontmatter,
4
+ extractFrontmatterId,
5
+ resolveDeclaredId,
6
+ isValidId,
7
+ dedupeById,
8
+ } from '../frontmatter-id.js';
9
+ import { setFrontmatterField } from '@bevel-software/platform-shared';
10
+
11
+ describe('extractFrontmatter', () => {
12
+ test('splits a leading --- block from the body', () => {
13
+ const r = extractFrontmatter('---\nid: foo\n---\ntype: http\n');
14
+ expect(r).toEqual({ frontmatter: 'id: foo', body: 'type: http\n' });
15
+ });
16
+ test('null when there is no fence', () => {
17
+ expect(extractFrontmatter('type: http')).toBeNull();
18
+ });
19
+ });
20
+
21
+ describe('extractFrontmatterId', () => {
22
+ test('reads a legacy kebab id from frontmatter', () => {
23
+ expect(extractFrontmatterId('---\nid: foo-bar\n---\n# x')).toBe('foo-bar');
24
+ });
25
+ test('null with no fence or no id', () => {
26
+ expect(extractFrontmatterId('# heading')).toBeNull();
27
+ expect(extractFrontmatterId('---\nnodeType: "[T](T.md)"\n---\n# x')).toBeNull();
28
+ });
29
+ });
30
+
31
+ describe('resolveDeclaredId', () => {
32
+ test('id wins over name, name over fallback', () => {
33
+ expect(resolveDeclaredId({ id: 'the_id', name: 'The Name' }, 'file')).toBe('the_id');
34
+ expect(resolveDeclaredId({ name: 'the_name' }, 'file')).toBe('the_name');
35
+ expect(resolveDeclaredId({}, 'file')).toBe('file');
36
+ expect(resolveDeclaredId({ id: ' ' }, 'file')).toBe('file'); // blank id ignored
37
+ });
38
+ });
39
+
40
+ describe('isValidId', () => {
41
+ test('accepts lowercase snake_case, rejects hyphens/uppercase/leading underscore', () => {
42
+ for (const ok of ['a', 'my_tool', 'weather1', 'a_b_c']) expect(isValidId(ok)).toBe(true);
43
+ for (const bad of ['a-b', 'My_Tool', '_x', '', 'a b']) expect(isValidId(bad)).toBe(false);
44
+ });
45
+ });
46
+
47
+ describe('dedupeById', () => {
48
+ test('keeps the first, refuses later duplicates and reports them', () => {
49
+ const onDup = vi.fn();
50
+ const items = [
51
+ { id: 'a', at: 1 },
52
+ { id: 'b', at: 2 },
53
+ { id: 'a', at: 3 }, // duplicate
54
+ ];
55
+ const out = dedupeById(items, (x) => x.id, (x, id) => onDup(id, x.at));
56
+ expect(out.map((x) => x.at)).toEqual([1, 2]); // first `a` kept, second dropped
57
+ expect(onDup).toHaveBeenCalledWith('a', 3);
58
+ });
59
+ });
60
+
61
+ describe('setFrontmatterField (shared, line-based)', () => {
62
+ test('replaces an existing key, leaving every other line byte-identical', () => {
63
+ const node = '---\nnodeType: "[Thing](../NodeTypes/Thing.md)"\nid: "old-id"\nwrite:\n - Product Team\n---\n\n# Name\nFoo\n';
64
+ const out = setFrontmatterField(node, 'id', 'old-id2');
65
+ expect(out).toBe('---\nnodeType: "[Thing](../NodeTypes/Thing.md)"\nid: old-id2\nwrite:\n - Product Team\n---\n\n# Name\nFoo\n');
66
+ });
67
+
68
+ test('inserts a missing key at the top of an existing block', () => {
69
+ const out = setFrontmatterField('---\nname: weather\n---\n{"type":"http"}\n', 'id', 'weather2');
70
+ expect(out).toBe('---\nid: weather2\nname: weather\n---\n{"type":"http"}\n');
71
+ });
72
+
73
+ test('creates a frontmatter block when the file has none', () => {
74
+ const out = setFrontmatterField('{"type":"http","url":"https://x/m"}', 'id', 'tool_x');
75
+ expect(out).toBe('---\nid: tool_x\n---\n{"type":"http","url":"https://x/m"}');
76
+ });
77
+
78
+ test('does not touch a same-named key in the BODY', () => {
79
+ const out = setFrontmatterField('---\nid: a\n---\nid: body-line stays\n', 'id', 'b');
80
+ expect(out).toBe('---\nid: b\n---\nid: body-line stays\n');
81
+ });
82
+
83
+ test("preserves a CRLF file's line endings byte-for-byte", () => {
84
+ const crlf = '---\r\nid: a\r\nname: keep\r\n---\r\nbody line\r\n';
85
+ const out = setFrontmatterField(crlf, 'id', 'b');
86
+ expect(out).toBe('---\r\nid: b\r\nname: keep\r\n---\r\nbody line\r\n');
87
+ });
88
+ });
@@ -0,0 +1,42 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import os from 'node:os';
5
+ import { walkFiles } from '../fs-walk.js';
6
+
7
+ describe('walkFiles', () => {
8
+ let root: string;
9
+
10
+ beforeEach(async () => {
11
+ root = await fs.mkdtemp(path.join(os.tmpdir(), 'fs-walk-'));
12
+ });
13
+ afterEach(async () => {
14
+ await fs.rm(root, { recursive: true, force: true });
15
+ });
16
+
17
+ it('returns [] for a missing root', async () => {
18
+ expect(await walkFiles(path.join(root, 'nope'), () => true)).toEqual([]);
19
+ });
20
+
21
+ it('walks nested directories, filters by basename, and sorts the result', async () => {
22
+ await fs.mkdir(path.join(root, 'b/deep'), { recursive: true });
23
+ await fs.mkdir(path.join(root, 'a'), { recursive: true });
24
+ await fs.writeFile(path.join(root, 'b/deep/z.tool'), '');
25
+ await fs.writeFile(path.join(root, 'a/y.tool'), '');
26
+ await fs.writeFile(path.join(root, 'a/skip.md'), '');
27
+ await fs.writeFile(path.join(root, 'x.tool'), '');
28
+
29
+ const found = await walkFiles(root, (n) => n.endsWith('.tool'));
30
+ // Relative `/`-separated paths, sorted, only matching basenames.
31
+ expect(found).toEqual(['a/y.tool', 'b/deep/z.tool', 'x.tool']);
32
+ });
33
+
34
+ it('skips dot-prefixed entries — files AND whole directories (.git)', async () => {
35
+ await fs.mkdir(path.join(root, '.git/objects'), { recursive: true });
36
+ await fs.writeFile(path.join(root, '.git/objects/a.tool'), '');
37
+ await fs.writeFile(path.join(root, '.hidden.tool'), '');
38
+ await fs.writeFile(path.join(root, 'visible.tool'), '');
39
+
40
+ expect(await walkFiles(root, (n) => n.endsWith('.tool'))).toEqual(['visible.tool']);
41
+ });
42
+ });
@@ -0,0 +1,53 @@
1
+ import { describe, test, expect } from 'vitest';
2
+ import { isBlockedHost, assertSafeFetchUrl } from '../ssrf.js';
3
+
4
+ describe('isBlockedHost', () => {
5
+ test('blocks loopback / private / link-local / metadata', () => {
6
+ for (const h of [
7
+ 'localhost', 'app.localhost', 'localhost.', '127.0.0.1', '0.0.0.0', '10.1.2.3', '192.168.1.1',
8
+ '172.16.0.1', '169.254.169.254', '::1', '::', 'fe80::1', 'fe90::1', 'fc00::1', '::ffff:127.0.0.1',
9
+ // CGNAT 100.64.0.0/10 — includes Alibaba Cloud's metadata endpoint.
10
+ '100.64.0.1', '100.100.100.200', '100.127.255.255',
11
+ ]) {
12
+ expect(isBlockedHost(h)).toBe(true);
13
+ }
14
+ });
15
+
16
+ test('allows public hosts (incl. lookalikes)', () => {
17
+ for (const h of ['api.example.com', 'github.com', 'fc.example.org', '8.8.8.8', '172.15.0.1', '172.32.0.1', '100.63.255.255', '100.128.0.1']) {
18
+ expect(isBlockedHost(h)).toBe(false);
19
+ }
20
+ });
21
+
22
+ test('blocks IPv4-mapped IPv6 in the hex form new URL canonicalizes to', () => {
23
+ // `new URL('http://[::ffff:169.254.169.254]/').hostname` === '[::ffff:a9fe:a9fe]'
24
+ // — the mapped v4 is emitted as hex hextets, not dotted, so the guard must
25
+ // decode the hex mapping and not just match a dotted tail.
26
+ for (const h of ['[::ffff:a9fe:a9fe]', '::ffff:a9fe:a9fe', '::ffff:7f00:1', '::ffff:a00:1', '::ffff:c0a8:1']) {
27
+ expect(isBlockedHost(h)).toBe(true);
28
+ }
29
+ // A public address in the same mapped-hex form stays allowed (8.8.8.8 → 0808:0808).
30
+ expect(isBlockedHost('::ffff:808:808')).toBe(false);
31
+ });
32
+ });
33
+
34
+ describe('assertSafeFetchUrl', () => {
35
+ test('accepts a public https URL', () => {
36
+ expect(() => assertSafeFetchUrl('https://api.example.com/token', { requireHttps: true })).not.toThrow();
37
+ });
38
+
39
+ test('rejects http when https is required', () => {
40
+ expect(() => assertSafeFetchUrl('http://api.example.com/token', { requireHttps: true })).toThrow(/https/);
41
+ });
42
+
43
+ test('rejects internal/metadata hosts (SSRF)', () => {
44
+ expect(() => assertSafeFetchUrl('https://169.254.169.254/latest/meta-data/', { requireHttps: true })).toThrow(
45
+ /not allowed/,
46
+ );
47
+ expect(() => assertSafeFetchUrl('https://localhost:8080/token', { requireHttps: true })).toThrow(/not allowed/);
48
+ });
49
+
50
+ test('rejects a non-URL', () => {
51
+ expect(() => assertSafeFetchUrl('not a url')).toThrow(/valid URL/);
52
+ });
53
+ });
@@ -0,0 +1,19 @@
1
+ import { describe, test, expect } from 'vitest';
2
+ import { utcpNamespacedKey, utcpNamespacePrefix } from '../utcp-namespace.js';
3
+
4
+ describe('utcp-namespace', () => {
5
+ test('alphanumeric name → plain `<name>_<VAR>` (existing tools unaffected)', () => {
6
+ expect(utcpNamespacedKey('weather', 'API_KEY')).toBe('weather_API_KEY');
7
+ expect(utcpNamespacePrefix('weather')).toBe('weather_');
8
+ });
9
+ test('snake_case name → underscores doubled (UTCP convention)', () => {
10
+ expect(utcpNamespacedKey('my_tool', 'KEY')).toBe('my__tool_KEY');
11
+ expect(utcpNamespacePrefix('my_tool')).toBe('my__tool_');
12
+ expect(utcpNamespacedKey('a_b_c', 'X')).toBe('a__b__c_X');
13
+ });
14
+ test('non-word chars sanitized to `_` BEFORE doubling (mirrors `@utcp/sdk`\'s `name.replace(/[^\\w]/g,"_")`)', () => {
15
+ expect(utcpNamespacedKey('my-tool', 'KEY')).toBe('my__tool_KEY'); // same key as `my_tool`
16
+ expect(utcpNamespacePrefix('my-tool')).toBe('my__tool_');
17
+ expect(utcpNamespacedKey('acme.api', 'TOKEN')).toBe('acme__api_TOKEN');
18
+ });
19
+ });
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Shared identity helpers for the KB's `---`-frontmatter files, so tool manuals,
3
+ * skills, and node id-links all resolve identity the SAME way: a frontmatter `id`,
4
+ * then `name`, then a caller-supplied fallback (folder/filename). One grammar
5
+ * (lowercase `snake_case`) and one dedup rule (refuse duplicates) across all three.
6
+ * The `---` splitter itself lives in `@bevel-software/platform-shared` (used by the
7
+ * frontend too); re-exported here so backend callers keep one import site.
8
+ */
9
+ import { extractFrontmatter } from '@bevel-software/platform-shared';
10
+
11
+ export { extractFrontmatter };
12
+
13
+ /**
14
+ * Extract a node's stable frontmatter `id` — the short token nodes cross-reference
15
+ * with (`[text](<id>)`). Null when the file has no leading `---` block or no `id:`
16
+ * scalar in it. Keeps the lowercase-kebab grammar the renderer's id-link uses, so
17
+ * any id this returns round-trips as a citation link. (Node-specific; tools/skills
18
+ * read `id`/`name` from the PARSED frontmatter via {@link resolveDeclaredId}.)
19
+ */
20
+ export function extractFrontmatterId(markdown: string): string | null {
21
+ const fm = extractFrontmatter(markdown);
22
+ if (!fm) return null;
23
+ for (const line of fm.frontmatter.split(/\r?\n/)) {
24
+ const m = line.match(/^id:\s*["']?([a-z0-9][a-z0-9-]*)["']?\s*$/);
25
+ if (m) return m[1];
26
+ }
27
+ return null;
28
+ }
29
+
30
+ /** The ONE identity rule: frontmatter `id`, else `name`, else the caller's fallback. */
31
+ export function resolveDeclaredId(frontmatter: Record<string, unknown>, fallback: string): string {
32
+ const id = typeof frontmatter.id === 'string' ? frontmatter.id.trim() : '';
33
+ if (id) return id;
34
+ const name = typeof frontmatter.name === 'string' ? frontmatter.name.trim() : '';
35
+ if (name) return name;
36
+ return fallback;
37
+ }
38
+
39
+ /**
40
+ * The canonical id grammar: lowercase `snake_case`. Enforced for tool manual ids
41
+ * because the id is used VERBATIM as the UTCP variable namespace, whose grammar is
42
+ * `[a-zA-Z0-9_]+` (underscores ok, hyphens rejected). Skills/nodes don't carry this
43
+ * constraint, so they don't validate against it.
44
+ */
45
+ export function isValidId(id: string): boolean {
46
+ return /^[a-z0-9][a-z0-9_]*$/.test(id);
47
+ }
48
+
49
+ /**
50
+ * The ONE dedup rule: keep the first occurrence of each id, REFUSE later duplicates
51
+ * (skip + `onDuplicate`). Callers pass items in a deterministic order (e.g. sorted by
52
+ * path) so the winner is stable. Replaces tools' bespoke collision check and skills'
53
+ * auto-suffix with one shared behaviour.
54
+ */
55
+ export function dedupeById<T>(
56
+ items: T[],
57
+ keyOf: (item: T) => string,
58
+ onDuplicate?: (item: T, id: string) => void,
59
+ ): T[] {
60
+ const seen = new Set<string>();
61
+ const out: T[] = [];
62
+ for (const item of items) {
63
+ const id = keyOf(item);
64
+ if (seen.has(id)) {
65
+ onDuplicate?.(item, id);
66
+ continue;
67
+ }
68
+ seen.add(id);
69
+ out.push(item);
70
+ }
71
+ return out;
72
+ }
@@ -0,0 +1,30 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+
4
+ /**
5
+ * The ONE recursive file walk for catalog scanners: relative (`/`-separated,
6
+ * sorted) paths of files under `root` whose basename matches. A missing root
7
+ * yields `[]`; dot-entries (incl. `.git`) are skipped. Scanners with different
8
+ * semantics (the skills scanner's stop-at-skill-folder walk, the access
9
+ * resolver's dir chains) deliberately keep their own walks.
10
+ */
11
+ export async function walkFiles(root: string, match: (basename: string) => boolean): Promise<string[]> {
12
+ const out: string[] = [];
13
+ const walk = async (dir: string, rel: string): Promise<void> => {
14
+ let entries: import('node:fs').Dirent[];
15
+ try {
16
+ entries = await fs.readdir(dir, { withFileTypes: true });
17
+ } catch {
18
+ return;
19
+ }
20
+ for (const entry of entries) {
21
+ if (entry.name.startsWith('.')) continue;
22
+ const childRel = rel ? `${rel}/${entry.name}` : entry.name;
23
+ if (entry.isDirectory()) await walk(path.join(dir, entry.name), childRel);
24
+ else if (entry.isFile() && match(entry.name)) out.push(childRel);
25
+ }
26
+ };
27
+ await walk(root, '');
28
+ out.sort();
29
+ return out;
30
+ }
@@ -0,0 +1,14 @@
1
+ import { createHash } from 'node:crypto';
2
+
3
+ /**
4
+ * Canonical user-identity hash: SHA-256 over the trimmed, lowercased email,
5
+ * returned as hex. Used wherever Bevel needs a stable email-derived identifier
6
+ * without storing the raw email — PR author-id markers, self-approval
7
+ * detection, etc. All callers MUST use this single function; a drift in the
8
+ * normalization (case, whitespace) would silently de-attribute every PR the
9
+ * bot opens because the hash embedded in the PR body would no longer match
10
+ * the hash computed at lookup time.
11
+ */
12
+ export function hashEmail(email: string): string {
13
+ return createHash('sha256').update(email.trim().toLowerCase()).digest('hex');
14
+ }
@@ -0,0 +1,88 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { ontologyOf } from './kb-layout.js';
3
+
4
+ describe('ontologyOf', () => {
5
+ it('resolves a named ontology under Knowledge', () => {
6
+ expect(ontologyOf('KnowledgeBase/Product/Knowledge/Foo.md')).toBe('KnowledgeBase/Product');
7
+ });
8
+
9
+ it('resolves a named ontology under NodeTypes', () => {
10
+ expect(ontologyOf('KnowledgeBase/Product/NodeTypes/Process.md')).toBe('KnowledgeBase/Product');
11
+ });
12
+
13
+ it('is space-safe in the ontology name', () => {
14
+ expect(ontologyOf('KnowledgeBase/IT Architecture/NodeTypes/ServiceCommitment.md')).toBe(
15
+ 'KnowledgeBase/IT Architecture',
16
+ );
17
+ });
18
+
19
+ it('treats a nested ontology directory as the full prefix before the marker', () => {
20
+ expect(ontologyOf('KnowledgeBase/Group/Sub/Knowledge/x.md')).toBe('KnowledgeBase/Group/Sub');
21
+ });
22
+
23
+ it('returns null when the marker sits directly under KnowledgeBase/', () => {
24
+ expect(ontologyOf('KnowledgeBase/Knowledge/Foo.md')).toBeNull();
25
+ expect(ontologyOf('KnowledgeBase/NodeTypes/T.md')).toBeNull();
26
+ });
27
+
28
+ it('returns null for root-level Knowledge (not under KnowledgeBase/)', () => {
29
+ expect(ontologyOf('Knowledge/Foo.md')).toBeNull();
30
+ });
31
+
32
+ it('returns null for Data/ ontologies (deliberate session-ontology exemption)', () => {
33
+ // `Data/<X>` IS parsed into the graph (parser `ONTOLOGY_ROOTS`), but is
34
+ // intentionally NOT classified here so the session-ontology gate treats
35
+ // Data paths as neutral — pipeline agents read knowledge and write data
36
+ // in one session (owner decision 2026-07-27). See the `ontologyOf`
37
+ // docstring; this is not drift.
38
+ expect(ontologyOf('Data/Ops/Knowledge/x.md')).toBeNull();
39
+ expect(ontologyOf('Data/Ops/NodeTypes/Ticket.md')).toBeNull();
40
+ // KnowledgeBase paths still classify as before.
41
+ expect(ontologyOf('KnowledgeBase/Ops/Knowledge/x.md')).toBe('KnowledgeBase/Ops');
42
+ });
43
+
44
+ it('returns null for Skills and root config (neutral)', () => {
45
+ expect(ontologyOf('Skills/some-skill/SKILL.md')).toBeNull();
46
+ expect(ontologyOf('access.md')).toBeNull();
47
+ expect(ontologyOf('roles.yaml')).toBeNull();
48
+ });
49
+
50
+ it('returns null for an ontology path with no marker segment', () => {
51
+ expect(ontologyOf('KnowledgeBase/Product/Uploads/diagram.png')).toBeNull();
52
+ });
53
+
54
+ it('does not match substring lookalikes (segment equality)', () => {
55
+ expect(ontologyOf('KnowledgeBase/Product/Knowledge-notes.md')).toBeNull();
56
+ expect(ontologyOf('KnowledgeBase/Product/KnowledgeBase/x.md')).toBeNull();
57
+ });
58
+
59
+ it('strips a kbDirName prefix (normalized and un-normalized)', () => {
60
+ expect(ontologyOf('knowledge-base/KnowledgeBase/Product/Knowledge/Foo.md', 'knowledge-base')).toBe(
61
+ 'KnowledgeBase/Product',
62
+ );
63
+ expect(ontologyOf('./knowledge-base/KnowledgeBase/GTM/NodeTypes/T.md', 'knowledge-base/')).toBe(
64
+ 'KnowledgeBase/GTM',
65
+ );
66
+ });
67
+
68
+ it('normalizes backslashes and leading/trailing slashes', () => {
69
+ expect(ontologyOf('/KnowledgeBase/Product/Knowledge/Foo.md/')).toBe('KnowledgeBase/Product');
70
+ expect(ontologyOf('KnowledgeBase\\Product\\Knowledge\\Foo.md')).toBe('KnowledgeBase/Product');
71
+ });
72
+
73
+ it('canonicalizes inner . and .. segments to the same ontology', () => {
74
+ expect(ontologyOf('KnowledgeBase/Product/./Knowledge/Foo.md')).toBe('KnowledgeBase/Product');
75
+ expect(ontologyOf('KnowledgeBase/Product/Sub/../Knowledge/Foo.md')).toBe('KnowledgeBase/Product');
76
+ expect(ontologyOf('KnowledgeBase/Platform/../Product/Knowledge/Foo.md')).toBe('KnowledgeBase/Product');
77
+ // `..` also collapses inside the stripped kbDirName prefix.
78
+ expect(ontologyOf('knowledge-base/x/../KnowledgeBase/GTM/NodeTypes/T.md', 'knowledge-base')).toBe(
79
+ 'KnowledgeBase/GTM',
80
+ );
81
+ });
82
+
83
+ it('returns null for empty or root paths', () => {
84
+ expect(ontologyOf('')).toBeNull();
85
+ expect(ontologyOf('KnowledgeBase')).toBeNull();
86
+ expect(ontologyOf('KnowledgeBase/Product')).toBeNull();
87
+ });
88
+ });
@@ -0,0 +1,101 @@
1
+ import { KNOWLEDGE_BASE_DIR, ONTOLOGY_MARKERS, type Ontology } from '@bevel-software/platform-shared';
2
+
3
+ /**
4
+ * Resolve which named ontology a KB path belongs to — the backend-side
5
+ * implementation of the layout contract whose constants/types live in
6
+ * `@bevel-software/platform-shared` (`kb-layout.ts`). It is backend-only and consumed by
7
+ * more than one domain module (the `workspace` read gate and the `workflow`
8
+ * session-ontology service), so it lives in `backend/src/shared` rather than in
9
+ * any single module — importable by both modules without crossing a module's
10
+ * internal boundary. Note it does NOT mirror the kb-graph parser one-to-one:
11
+ * see the `ontologyOf` docstring for the deliberate `Data/` exemption.
12
+ *
13
+ * Pure string handling — no IO, no DB.
14
+ */
15
+
16
+ /**
17
+ * Split a path into repo-root-relative POSIX segments, dropping `./`,
18
+ * leading/trailing slashes, and an optional `kbDirName` prefix (the on-disk
19
+ * clone folder, e.g. `knowledge-base/`). Pure string handling — no IO.
20
+ */
21
+ function toSegments(path: string, kbDirName?: string): string[] {
22
+ // Collapse to canonical segments: backslashes → `/`, drop empty and `.`
23
+ // segments, resolve `..` against the accumulated prefix. Canonicalizing the
24
+ // inner segments (not just the ends) means equivalent paths like
25
+ // `KnowledgeBase/Product/../Product/Knowledge/x.md` and
26
+ // `KnowledgeBase/Product/Knowledge/x.md` resolve to the same ontology.
27
+ const collapse = (s: string): string[] => {
28
+ const out: string[] = [];
29
+ for (const seg of s.replace(/\\/g, '/').split('/')) {
30
+ if (seg === '' || seg === '.') continue;
31
+ if (seg === '..') {
32
+ // Pop a real segment; a leading `..` (nothing to pop) is kept so it can
33
+ // never alias into a sibling ontology.
34
+ if (out.length > 0 && out[out.length - 1] !== '..') out.pop();
35
+ else out.push('..');
36
+ continue;
37
+ }
38
+ out.push(seg);
39
+ }
40
+ return out;
41
+ };
42
+
43
+ let segs = collapse(path);
44
+ const prefixSegs = kbDirName ? collapse(kbDirName) : [];
45
+ if (prefixSegs.length > 0 && prefixSegs.every((s, i) => segs[i] === s)) {
46
+ segs = segs.slice(prefixSegs.length);
47
+ }
48
+ return segs;
49
+ }
50
+
51
+ /**
52
+ * Resolve the named ontology a KB path belongs to, or `null` (neutral) when it
53
+ * belongs to none.
54
+ *
55
+ * Classification is deliberately NARROWER than the kb-graph parser: the parser
56
+ * discovers ontologies under every `ONTOLOGY_ROOTS` entry (`KnowledgeBase/`
57
+ * AND `Data/`), but this function classifies ONLY `KnowledgeBase/` paths.
58
+ * `Data/` ontologies are parsed into the graph yet are intentionally NOT
59
+ * classified here, so the session-ontology gate treats `Data/` paths as
60
+ * neutral — pipeline agents read knowledge and write data records in one
61
+ * session (owner decision 2026-07-27; the cross-ontology boundary mechanism
62
+ * itself may be redesigned). This divergence is on purpose, not drift.
63
+ *
64
+ * Within `KnowledgeBase/`, the shape matches the parser (`parser.ts`
65
+ * `walkForOntologies`): an ontology is the directory that holds both a
66
+ * `Knowledge/` and a `NodeTypes/` subfolder. That directory can sit at ANY
67
+ * depth under `KnowledgeBase/`, so the ontology id is the path PREFIX up to
68
+ * (but excluding) the first `Knowledge/` or `NodeTypes/` marker segment — as
69
+ * long as that prefix is inside `KnowledgeBase/` and is not `KnowledgeBase/`
70
+ * itself.
71
+ *
72
+ * KnowledgeBase/Product/Knowledge/Foo.md → "KnowledgeBase/Product"
73
+ * KnowledgeBase/IT Architecture/NodeTypes/T.md → "KnowledgeBase/IT Architecture"
74
+ * KnowledgeBase/Group/Sub/Knowledge/x.md → "KnowledgeBase/Group/Sub"
75
+ * KnowledgeBase/Knowledge/Foo.md → null (marker directly under KB root)
76
+ * Knowledge/Foo.md, Skills/x.md, access.md → null (not under KnowledgeBase/)
77
+ * Data/Ops/Knowledge/x.md → null (Data/ is exempt — see above)
78
+ * KnowledgeBase/Product/Uploads/x.png → null (no marker segment)
79
+ *
80
+ * Uses exact segment equality (never substring), so `KnowledgeBase/` and
81
+ * `Knowledge-notes.md` are never treated as markers; space-safe; pure (no IO).
82
+ *
83
+ * @param path repo-root-relative POSIX path (may carry a `kbDirName` prefix)
84
+ * @param kbDirName optional on-disk clone folder prefix to strip first
85
+ */
86
+ export function ontologyOf(path: string, kbDirName?: string): Ontology {
87
+ const segs = toSegments(path, kbDirName);
88
+ // Must live under the dedicated KnowledgeBase/ container, with at least one
89
+ // ontology-name segment and a marker after it (so length >= 3).
90
+ if (segs.length < 3 || segs[0] !== KNOWLEDGE_BASE_DIR) return null;
91
+ // The ontology id is the prefix before the first marker segment. Require at
92
+ // least one name segment between `KnowledgeBase/` and the marker, so a marker
93
+ // sitting directly under `KnowledgeBase/` (`KnowledgeBase/Knowledge/...`) is
94
+ // neutral, matching the parser (it only discovers ontologies one level down).
95
+ for (let i = 1; i < segs.length; i++) {
96
+ if (ONTOLOGY_MARKERS.has(segs[i])) {
97
+ return i >= 2 ? segs.slice(0, i).join('/') : null;
98
+ }
99
+ }
100
+ return null;
101
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Minimal SSRF guard for user-supplied outbound URLs. Rejects obvious
3
+ * non-public targets (loopback, private, link-local, cloud-metadata) so an
4
+ * authenticated user can't point a server-side fetch at internal services.
5
+ *
6
+ * Only catches LITERAL hosts/IPs — DNS-rebinding (a public name that resolves to
7
+ * a private IP) is out of scope here; blunt that at fetch time / network layer.
8
+ */
9
+ export function isBlockedHost(hostname: string): boolean {
10
+ let host = hostname.replace(/^\[|\]$/g, '').toLowerCase();
11
+ // A trailing dot is the FQDN root and resolves identically: `localhost.` === `localhost`.
12
+ if (host.endsWith('.')) host = host.slice(0, -1);
13
+ if (host === 'localhost' || host.endsWith('.localhost')) return true;
14
+
15
+ // IPv6 literals only: they contain a colon, whereas a plain hostname never does
16
+ // — so domains like `fc.example.org` / `fd.example.com` are not matched.
17
+ if (host.includes(':')) {
18
+ // IPv4-mapped IPv6 connects to the embedded v4 — validate it. The textual
19
+ // form may be dotted (`::ffff:169.254.169.254`) OR two hex hextets
20
+ // (`::ffff:a9fe:a9fe`) — WHATWG `new URL` canonicalizes the mapped address
21
+ // to the HEX form, so the dotted regex alone would miss a normalized
22
+ // hostname. Handle both.
23
+ const mappedDotted = /:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/.exec(host);
24
+ if (mappedDotted && isBlockedV4(mappedDotted[1])) return true;
25
+ const mappedHex = /:ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(host);
26
+ if (mappedHex) {
27
+ const hi = parseInt(mappedHex[1], 16);
28
+ const lo = parseInt(mappedHex[2], 16);
29
+ const v4 = `${hi >> 8}.${hi & 0xff}.${lo >> 8}.${lo & 0xff}`;
30
+ if (isBlockedV4(v4)) return true;
31
+ }
32
+ if (host === '::1' || host === '::') return true; // loopback / unspecified
33
+ // link-local fe80::/10 (fe80–febf) and unique-local fc00::/7 (fc/fd).
34
+ if (/^fe[89ab]/.test(host) || host.startsWith('fc') || host.startsWith('fd')) return true;
35
+ return false;
36
+ }
37
+ return isBlockedV4(host);
38
+ }
39
+
40
+ /** True for an IPv4 literal in a private / loopback / link-local (incl. cloud IMDS) range. */
41
+ function isBlockedV4(host: string): boolean {
42
+ const m = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
43
+ if (!m) return false;
44
+ const a = Number(m[1]);
45
+ const b = Number(m[2]);
46
+ if (a === 0 || a === 127 || a === 10) return true;
47
+ if (a === 169 && b === 254) return true; // link-local (incl. cloud IMDS 169.254.169.254)
48
+ if (a === 192 && b === 168) return true;
49
+ if (a === 172 && b >= 16 && b <= 31) return true;
50
+ if (a === 100 && b >= 64 && b <= 127) return true; // CGNAT 100.64.0.0/10 (incl. Alibaba IMDS 100.100.100.200)
51
+ return false;
52
+ }
53
+
54
+ /**
55
+ * Parse + validate a user-supplied URL for a server-side fetch: must be http(s)
56
+ * (or https only when `requireHttps`), and its literal host must not be a
57
+ * blocked/internal target. Returns the parsed URL or throws a plain `Error`
58
+ * (callers wrap it in a domain error). `label` names the field in the message.
59
+ */
60
+ export function assertSafeFetchUrl(
61
+ raw: string,
62
+ opts: { requireHttps?: boolean; label?: string } = {},
63
+ ): URL {
64
+ const label = opts.label ?? 'URL';
65
+ let u: URL;
66
+ try {
67
+ u = new URL(raw);
68
+ } catch {
69
+ throw new Error(`${label} must be a valid URL`);
70
+ }
71
+ if (opts.requireHttps) {
72
+ if (u.protocol !== 'https:') throw new Error(`${label} must use https`);
73
+ } else if (u.protocol !== 'http:' && u.protocol !== 'https:') {
74
+ throw new Error(`${label} must be an http(s) URL`);
75
+ }
76
+ if (isBlockedHost(u.hostname)) throw new Error(`${label} host is not allowed`);
77
+ return u;
78
+ }
@@ -0,0 +1,54 @@
1
+ import { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';
2
+
3
+ /**
4
+ * AES-256-GCM encryption for at-rest secrets. Output format is
5
+ * `<ivB64>:<tagB64>:<ciphertextB64>` so all three parts travel together in one
6
+ * text column. A DB leak alone yields only ciphertext; the key lives in the
7
+ * app's env, not the database. Shared primitive with several consumers, each
8
+ * bringing its own key: the secrets vault + MCP OAuth store (core), and the
9
+ * SharePoint token cache / connector configs (enterprise).
10
+ */
11
+ export class TokenCrypto {
12
+ private readonly key: Buffer;
13
+
14
+ /** @param rawKey 32-byte key as hex (64 chars) or base64. */
15
+ constructor(rawKey: string) {
16
+ const key = decodeKey(rawKey);
17
+ if (key.length !== 32) {
18
+ throw new Error(
19
+ `SHAREPOINT_TOKEN_ENC_KEY must decode to 32 bytes (got ${key.length}). ` +
20
+ 'Generate one with: `node -e "console.log(require(\'crypto\').randomBytes(32).toString(\'base64\'))"`.',
21
+ );
22
+ }
23
+ this.key = key;
24
+ }
25
+
26
+ encrypt(plaintext: string): string {
27
+ const iv = randomBytes(12);
28
+ const cipher = createCipheriv('aes-256-gcm', this.key, iv);
29
+ const ct = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
30
+ const tag = cipher.getAuthTag();
31
+ return `${iv.toString('base64')}:${tag.toString('base64')}:${ct.toString('base64')}`;
32
+ }
33
+
34
+ decrypt(blob: string): string {
35
+ const parts = blob.split(':');
36
+ if (parts.length !== 3) {
37
+ throw new Error('TokenCrypto.decrypt: malformed ciphertext blob (expected iv:tag:ct)');
38
+ }
39
+ const [ivB64, tagB64, ctB64] = parts;
40
+ if (!ivB64 || !tagB64 || !ctB64) {
41
+ throw new Error('TokenCrypto.decrypt: malformed ciphertext blob');
42
+ }
43
+ const decipher = createDecipheriv('aes-256-gcm', this.key, Buffer.from(ivB64, 'base64'));
44
+ decipher.setAuthTag(Buffer.from(tagB64, 'base64'));
45
+ return Buffer.concat([decipher.update(Buffer.from(ctB64, 'base64')), decipher.final()]).toString('utf8');
46
+ }
47
+ }
48
+
49
+ function decodeKey(raw: string): Buffer {
50
+ // Accept hex (64 chars, hex alphabet) or base64. Hex first to avoid a 64-char
51
+ // hex string being misread as base64.
52
+ if (/^[0-9a-fA-F]{64}$/.test(raw)) return Buffer.from(raw, 'hex');
53
+ return Buffer.from(raw, 'base64');
54
+ }