@bevel-software/platform-core-backend 0.13.6 → 0.15.1

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 (456) hide show
  1. package/THIRD-PARTY-NOTICES.md +6 -6
  2. package/dist/core/catalog-cache-invalidation.d.ts +29 -0
  3. package/dist/core/catalog-cache-invalidation.d.ts.map +1 -0
  4. package/dist/core/catalog-cache-invalidation.js +71 -0
  5. package/dist/core/catalog-cache-invalidation.js.map +1 -0
  6. package/dist/core/create-core-server.d.ts.map +1 -1
  7. package/dist/core/create-core-server.js +101 -9
  8. package/dist/core/create-core-server.js.map +1 -1
  9. package/dist/core/create-core-services.d.ts +20 -1
  10. package/dist/core/create-core-services.d.ts.map +1 -1
  11. package/dist/core/create-core-services.js +105 -43
  12. package/dist/core/create-core-services.js.map +1 -1
  13. package/dist/core-config.d.ts.map +1 -1
  14. package/dist/core-config.js +12 -5
  15. package/dist/core-config.js.map +1 -1
  16. package/dist/modules/access/access-control.interface.d.ts +18 -6
  17. package/dist/modules/access/access-control.interface.d.ts.map +1 -1
  18. package/dist/modules/access/access-control.service.d.ts +26 -1
  19. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  20. package/dist/modules/access/access-control.service.js +213 -71
  21. package/dist/modules/access/access-control.service.js.map +1 -1
  22. package/dist/modules/access/access.routes.d.ts.map +1 -1
  23. package/dist/modules/access/access.routes.js +59 -7
  24. package/dist/modules/access/access.routes.js.map +1 -1
  25. package/dist/modules/access-model/access-grammar.d.ts +51 -1
  26. package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
  27. package/dist/modules/access-model/access-grammar.js +95 -1
  28. package/dist/modules/access-model/access-grammar.js.map +1 -1
  29. package/dist/modules/access-model/group-files.d.ts.map +1 -1
  30. package/dist/modules/access-model/group-files.js +4 -1
  31. package/dist/modules/access-model/group-files.js.map +1 -1
  32. package/dist/modules/access-model/kb-read-filter.d.ts +12 -0
  33. package/dist/modules/access-model/kb-read-filter.d.ts.map +1 -1
  34. package/dist/modules/access-model/kb-read-filter.js +15 -0
  35. package/dist/modules/access-model/kb-read-filter.js.map +1 -1
  36. package/dist/modules/access-model/plugin-principals.d.ts +49 -0
  37. package/dist/modules/access-model/plugin-principals.d.ts.map +1 -0
  38. package/dist/modules/access-model/plugin-principals.js +125 -0
  39. package/dist/modules/access-model/plugin-principals.js.map +1 -0
  40. package/dist/modules/connection-probe/connection-probe.contract.d.ts +43 -0
  41. package/dist/modules/connection-probe/connection-probe.contract.d.ts.map +1 -0
  42. package/dist/modules/connection-probe/connection-probe.contract.js +2 -0
  43. package/dist/modules/connection-probe/connection-probe.contract.js.map +1 -0
  44. package/dist/modules/connection-probe/connection-probe.service.d.ts +94 -0
  45. package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -0
  46. package/dist/modules/connection-probe/connection-probe.service.js +684 -0
  47. package/dist/modules/connection-probe/connection-probe.service.js.map +1 -0
  48. package/dist/modules/connection-probe/index.d.ts +3 -0
  49. package/dist/modules/connection-probe/index.d.ts.map +1 -0
  50. package/dist/modules/connection-probe/index.js +3 -0
  51. package/dist/modules/connection-probe/index.js.map +1 -0
  52. package/dist/modules/database/core-schema.d.ts +326 -0
  53. package/dist/modules/database/core-schema.d.ts.map +1 -1
  54. package/dist/modules/database/core-schema.js +52 -0
  55. package/dist/modules/database/core-schema.js.map +1 -1
  56. package/dist/modules/diff/diff.routes.d.ts.map +1 -1
  57. package/dist/modules/diff/diff.routes.js +3 -5
  58. package/dist/modules/diff/diff.routes.js.map +1 -1
  59. package/dist/modules/kb-fs/mutex.d.ts +37 -0
  60. package/dist/modules/kb-fs/mutex.d.ts.map +1 -1
  61. package/dist/modules/kb-fs/mutex.js +48 -5
  62. package/dist/modules/kb-fs/mutex.js.map +1 -1
  63. package/dist/modules/kb-sync/index.d.ts +6 -0
  64. package/dist/modules/kb-sync/index.d.ts.map +1 -0
  65. package/dist/modules/kb-sync/index.js +5 -0
  66. package/dist/modules/kb-sync/index.js.map +1 -0
  67. package/dist/modules/kb-sync/kb-sync.interface.d.ts +77 -0
  68. package/dist/modules/kb-sync/kb-sync.interface.d.ts.map +1 -0
  69. package/dist/modules/kb-sync/kb-sync.interface.js +2 -0
  70. package/dist/modules/kb-sync/kb-sync.interface.js.map +1 -0
  71. package/dist/modules/kb-sync/kb-sync.routes.d.ts +70 -0
  72. package/dist/modules/kb-sync/kb-sync.routes.d.ts.map +1 -0
  73. package/dist/modules/kb-sync/kb-sync.routes.js +135 -0
  74. package/dist/modules/kb-sync/kb-sync.routes.js.map +1 -0
  75. package/dist/modules/kb-sync/kb-sync.service.d.ts +45 -0
  76. package/dist/modules/kb-sync/kb-sync.service.d.ts.map +1 -0
  77. package/dist/modules/kb-sync/kb-sync.service.js +183 -0
  78. package/dist/modules/kb-sync/kb-sync.service.js.map +1 -0
  79. package/dist/modules/kb-sync/sync-auth.d.ts +59 -0
  80. package/dist/modules/kb-sync/sync-auth.d.ts.map +1 -0
  81. package/dist/modules/kb-sync/sync-auth.js +62 -0
  82. package/dist/modules/kb-sync/sync-auth.js.map +1 -0
  83. package/dist/modules/kb-sync/sync-payload.d.ts +32 -0
  84. package/dist/modules/kb-sync/sync-payload.d.ts.map +1 -0
  85. package/dist/modules/kb-sync/sync-payload.js +105 -0
  86. package/dist/modules/kb-sync/sync-payload.js.map +1 -0
  87. package/dist/modules/marketplace/git-http.routes.d.ts +42 -0
  88. package/dist/modules/marketplace/git-http.routes.d.ts.map +1 -0
  89. package/dist/modules/marketplace/git-http.routes.js +190 -0
  90. package/dist/modules/marketplace/git-http.routes.js.map +1 -0
  91. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts +23 -0
  92. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts.map +1 -0
  93. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js +59 -0
  94. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js.map +1 -0
  95. package/dist/modules/marketplace/github-facade/github-facade-codes.store.d.ts +59 -0
  96. package/dist/modules/marketplace/github-facade/github-facade-codes.store.d.ts.map +1 -0
  97. package/dist/modules/marketplace/github-facade/github-facade-codes.store.js +96 -0
  98. package/dist/modules/marketplace/github-facade/github-facade-codes.store.js.map +1 -0
  99. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts +99 -0
  100. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts.map +1 -0
  101. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js +147 -0
  102. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js.map +1 -0
  103. package/dist/modules/marketplace/github-facade/github-facade.routes.d.ts +47 -0
  104. package/dist/modules/marketplace/github-facade/github-facade.routes.d.ts.map +1 -0
  105. package/dist/modules/marketplace/github-facade/github-facade.routes.js +228 -0
  106. package/dist/modules/marketplace/github-facade/github-facade.routes.js.map +1 -0
  107. package/dist/modules/marketplace/github-facade/github-facade.service.d.ts +109 -0
  108. package/dist/modules/marketplace/github-facade/github-facade.service.d.ts.map +1 -0
  109. package/dist/modules/marketplace/github-facade/github-facade.service.js +172 -0
  110. package/dist/modules/marketplace/github-facade/github-facade.service.js.map +1 -0
  111. package/dist/modules/marketplace/github-facade/index.d.ts +6 -0
  112. package/dist/modules/marketplace/github-facade/index.d.ts.map +1 -0
  113. package/dist/modules/marketplace/github-facade/index.js +6 -0
  114. package/dist/modules/marketplace/github-facade/index.js.map +1 -0
  115. package/dist/modules/marketplace/index.d.ts +4 -0
  116. package/dist/modules/marketplace/index.d.ts.map +1 -0
  117. package/dist/modules/marketplace/index.js +4 -0
  118. package/dist/modules/marketplace/index.js.map +1 -0
  119. package/dist/modules/marketplace/marketplace-repo.service.d.ts +122 -0
  120. package/dist/modules/marketplace/marketplace-repo.service.d.ts.map +1 -0
  121. package/dist/modules/marketplace/marketplace-repo.service.js +300 -0
  122. package/dist/modules/marketplace/marketplace-repo.service.js.map +1 -0
  123. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
  124. package/dist/modules/mcp/oauth/bevel-oauth-provider.js +4 -0
  125. package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
  126. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts +14 -8
  127. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -1
  128. package/dist/modules/mcp/oauth/oauth-consent.routes.js +13 -1
  129. package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -1
  130. package/dist/modules/mcp/oauth/oauth-state.d.ts +13 -2
  131. package/dist/modules/mcp/oauth/oauth-state.d.ts.map +1 -1
  132. package/dist/modules/mcp/oauth/oauth-state.js +3 -1
  133. package/dist/modules/mcp/oauth/oauth-state.js.map +1 -1
  134. package/dist/modules/plugins/compile/compile-marketplace.d.ts +97 -0
  135. package/dist/modules/plugins/compile/compile-marketplace.d.ts.map +1 -0
  136. package/dist/modules/plugins/compile/compile-marketplace.js +240 -0
  137. package/dist/modules/plugins/compile/compile-marketplace.js.map +1 -0
  138. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +66 -0
  139. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -0
  140. package/dist/modules/plugins/compile/marketplace-compiler.service.js +132 -0
  141. package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -0
  142. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts +37 -0
  143. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -0
  144. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +135 -0
  145. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -0
  146. package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts +45 -0
  147. package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts.map +1 -0
  148. package/dist/modules/plugins/discovery/bundle-dialect/registry.js +147 -0
  149. package/dist/modules/plugins/discovery/bundle-dialect/registry.js.map +1 -0
  150. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +37 -0
  151. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -0
  152. package/dist/modules/plugins/discovery/kb-plugin-source.js +107 -0
  153. package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -0
  154. package/dist/modules/plugins/discovery/native.source.d.ts +15 -0
  155. package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -0
  156. package/dist/modules/plugins/discovery/native.source.js +102 -0
  157. package/dist/modules/plugins/discovery/native.source.js.map +1 -0
  158. package/dist/modules/plugins/discovery/plugin-source.d.ts +96 -0
  159. package/dist/modules/plugins/discovery/plugin-source.d.ts.map +1 -0
  160. package/dist/modules/plugins/discovery/plugin-source.js +2 -0
  161. package/dist/modules/plugins/discovery/plugin-source.js.map +1 -0
  162. package/dist/modules/plugins/index.d.ts +10 -1
  163. package/dist/modules/plugins/index.d.ts.map +1 -1
  164. package/dist/modules/plugins/index.js +8 -0
  165. package/dist/modules/plugins/index.js.map +1 -1
  166. package/dist/modules/plugins/plugin-links.d.ts +66 -0
  167. package/dist/modules/plugins/plugin-links.d.ts.map +1 -0
  168. package/dist/modules/plugins/plugin-links.js +160 -0
  169. package/dist/modules/plugins/plugin-links.js.map +1 -0
  170. package/dist/modules/plugins/plugin-links.service.d.ts +114 -0
  171. package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -0
  172. package/dist/modules/plugins/plugin-links.service.js +304 -0
  173. package/dist/modules/plugins/plugin-links.service.js.map +1 -0
  174. package/dist/modules/plugins/plugin-provision.service.d.ts +39 -3
  175. package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
  176. package/dist/modules/plugins/plugin-provision.service.js +152 -52
  177. package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
  178. package/dist/modules/plugins/plugin-rename.service.d.ts +69 -0
  179. package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -0
  180. package/dist/modules/plugins/plugin-rename.service.js +245 -0
  181. package/dist/modules/plugins/plugin-rename.service.js.map +1 -0
  182. package/dist/modules/plugins/plugins.contract.d.ts +27 -1
  183. package/dist/modules/plugins/plugins.contract.d.ts.map +1 -1
  184. package/dist/modules/plugins/plugins.routes.d.ts +7 -1
  185. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  186. package/dist/modules/plugins/plugins.routes.js +120 -12
  187. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  188. package/dist/modules/plugins/plugins.service.d.ts +50 -3
  189. package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
  190. package/dist/modules/plugins/plugins.service.js +108 -47
  191. package/dist/modules/plugins/plugins.service.js.map +1 -1
  192. package/dist/modules/secrets-vault/db-secrets-vault.service.js +1 -1
  193. package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -1
  194. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +6 -0
  195. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
  196. package/dist/modules/secrets-vault/secrets-vault.routes.js +31 -1
  197. package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
  198. package/dist/modules/settings/deployment-settings.service.d.ts +9 -0
  199. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  200. package/dist/modules/settings/deployment-settings.service.js +82 -2
  201. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  202. package/dist/modules/settings/setup.routes.d.ts +26 -0
  203. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  204. package/dist/modules/settings/setup.routes.js +9 -1
  205. package/dist/modules/settings/setup.routes.js.map +1 -1
  206. package/dist/modules/skills/index.d.ts +1 -0
  207. package/dist/modules/skills/index.d.ts.map +1 -1
  208. package/dist/modules/skills/index.js +1 -0
  209. package/dist/modules/skills/index.js.map +1 -1
  210. package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
  211. package/dist/modules/skills/pending-skills.service.js +9 -4
  212. package/dist/modules/skills/pending-skills.service.js.map +1 -1
  213. package/dist/modules/skills/skill-access-requests.routes.d.ts +38 -0
  214. package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -0
  215. package/dist/modules/skills/skill-access-requests.routes.js +168 -0
  216. package/dist/modules/skills/skill-access-requests.routes.js.map +1 -0
  217. package/dist/modules/skills/skills.contract.d.ts +31 -0
  218. package/dist/modules/skills/skills.contract.d.ts.map +1 -1
  219. package/dist/modules/skills/skills.routes.d.ts +28 -3
  220. package/dist/modules/skills/skills.routes.d.ts.map +1 -1
  221. package/dist/modules/skills/skills.routes.js +42 -3
  222. package/dist/modules/skills/skills.routes.js.map +1 -1
  223. package/dist/modules/skills/skills.service.d.ts +4 -0
  224. package/dist/modules/skills/skills.service.d.ts.map +1 -1
  225. package/dist/modules/skills/skills.service.js +83 -22
  226. package/dist/modules/skills/skills.service.js.map +1 -1
  227. package/dist/modules/tool-auth/external-api-key.interface.d.ts +18 -1
  228. package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
  229. package/dist/modules/tool-auth/external-api-key.interface.js +2 -1
  230. package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -1
  231. package/dist/modules/tool-auth/external-api-key.service.d.ts +13 -4
  232. package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
  233. package/dist/modules/tool-auth/external-api-key.service.js +26 -9
  234. package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
  235. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +36 -0
  236. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
  237. package/dist/modules/tool-manuals/mcp-json-discovery.js +130 -83
  238. package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
  239. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -1
  240. package/dist/modules/tool-manuals/mcp-server-edit.service.js +10 -4
  241. package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
  242. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +83 -0
  243. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
  244. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +15 -2
  245. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  246. package/dist/modules/tool-manuals/tool-manuals.service.js +199 -38
  247. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  248. package/dist/modules/workflow/git/git.service.d.ts +58 -3
  249. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  250. package/dist/modules/workflow/git/git.service.js +325 -60
  251. package/dist/modules/workflow/git/git.service.js.map +1 -1
  252. package/dist/modules/workflow/git/pull-request.service.d.ts +6 -0
  253. package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
  254. package/dist/modules/workflow/git/pull-request.service.js +8 -0
  255. package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
  256. package/dist/modules/workflow/workflow.routes.d.ts +2 -1
  257. package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
  258. package/dist/modules/workflow/workflow.routes.js +98 -9
  259. package/dist/modules/workflow/workflow.routes.js.map +1 -1
  260. package/dist/modules/workflow/workflow.service.d.ts +133 -9
  261. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  262. package/dist/modules/workflow/workflow.service.js +462 -52
  263. package/dist/modules/workflow/workflow.service.js.map +1 -1
  264. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +35 -0
  265. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -0
  266. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +121 -0
  267. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -0
  268. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  269. package/dist/modules/workspace/startup/steps/seed-tree.js +46 -2
  270. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  271. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
  272. package/dist/modules/workspace/startup/steps/template-files.step.js +112 -25
  273. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
  274. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  275. package/dist/modules/workspace/workspace.routes.js +11 -14
  276. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  277. package/dist/modules/workspace/workspace.service.d.ts +38 -1
  278. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  279. package/dist/modules/workspace/workspace.service.js +131 -20
  280. package/dist/modules/workspace/workspace.service.js.map +1 -1
  281. package/dist/shared/domain-errors.d.ts +20 -0
  282. package/dist/shared/domain-errors.d.ts.map +1 -1
  283. package/dist/shared/domain-errors.js +29 -0
  284. package/dist/shared/domain-errors.js.map +1 -1
  285. package/dist/shared/fs-errors.d.ts +8 -0
  286. package/dist/shared/fs-errors.d.ts.map +1 -0
  287. package/dist/shared/fs-errors.js +11 -0
  288. package/dist/shared/fs-errors.js.map +1 -0
  289. package/dist/shared/fs-walk.d.ts +20 -6
  290. package/dist/shared/fs-walk.d.ts.map +1 -1
  291. package/dist/shared/fs-walk.js +35 -27
  292. package/dist/shared/fs-walk.js.map +1 -1
  293. package/dist/shared/kb-walk.d.ts +52 -0
  294. package/dist/shared/kb-walk.d.ts.map +1 -0
  295. package/dist/shared/kb-walk.js +76 -0
  296. package/dist/shared/kb-walk.js.map +1 -0
  297. package/dist/shared/path-order.d.ts +18 -0
  298. package/dist/shared/path-order.d.ts.map +1 -0
  299. package/dist/shared/path-order.js +35 -0
  300. package/dist/shared/path-order.js.map +1 -0
  301. package/dist/shared/token-crypto.d.ts +17 -2
  302. package/dist/shared/token-crypto.d.ts.map +1 -1
  303. package/dist/shared/token-crypto.js +25 -8
  304. package/dist/shared/token-crypto.js.map +1 -1
  305. package/dist/shared/ttl-cache.d.ts +28 -1
  306. package/dist/shared/ttl-cache.d.ts.map +1 -1
  307. package/dist/shared/ttl-cache.js +33 -1
  308. package/dist/shared/ttl-cache.js.map +1 -1
  309. package/kb-template/.bevelignore +1 -1
  310. package/kb-template/AGENTS.md +95 -30
  311. package/kb-template/Skills/.gitkeep +0 -0
  312. package/migrations/0005_github_facade.sql +25 -0
  313. package/migrations/meta/0005_snapshot.json +1717 -0
  314. package/migrations/meta/_journal.json +7 -0
  315. package/package.json +6 -6
  316. package/src/__tests__/core-config.admin.test.ts +21 -0
  317. package/src/__tests__/kb-layout-config.test.ts +110 -0
  318. package/src/core/__tests__/catalog-cache-invalidation.test.ts +146 -0
  319. package/src/core/catalog-cache-invalidation.ts +92 -0
  320. package/src/core/create-core-server.ts +126 -7
  321. package/src/core/create-core-services.ts +173 -41
  322. package/src/core-config.ts +14 -7
  323. package/src/modules/access/__tests__/access-control.invalidate-race.test.ts +86 -0
  324. package/src/modules/access/__tests__/access-control.service.test.ts +19 -3
  325. package/src/modules/access/__tests__/access-plugin-principals.test.ts +368 -0
  326. package/src/modules/access/__tests__/groups-admin.service.test.ts +8 -0
  327. package/src/modules/access/access-control.interface.ts +20 -9
  328. package/src/modules/access/access-control.service.ts +240 -78
  329. package/src/modules/access/access.routes.ts +96 -14
  330. package/src/modules/access-model/__tests__/access-grammar.test.ts +18 -0
  331. package/src/modules/access-model/__tests__/plugin-token-canonical.test.ts +40 -0
  332. package/src/modules/access-model/access-grammar.ts +114 -2
  333. package/src/modules/access-model/group-files.ts +4 -0
  334. package/src/modules/access-model/kb-read-filter.ts +22 -0
  335. package/src/modules/access-model/plugin-principals.ts +137 -0
  336. package/src/modules/connection-probe/__tests__/connection-probe.service.test.ts +685 -0
  337. package/src/modules/connection-probe/connection-probe.contract.ts +44 -0
  338. package/src/modules/connection-probe/connection-probe.service.ts +734 -0
  339. package/src/modules/connection-probe/index.ts +2 -0
  340. package/src/modules/database/core-schema.ts +54 -0
  341. package/src/modules/diff/diff.routes.ts +9 -5
  342. package/src/modules/kb-fs/__tests__/mutex.test.ts +107 -0
  343. package/src/modules/kb-fs/mutex.ts +50 -5
  344. package/src/modules/kb-sync/__tests__/kb-sync.routes.test.ts +297 -0
  345. package/src/modules/kb-sync/__tests__/kb-sync.service.test.ts +295 -0
  346. package/src/modules/kb-sync/__tests__/sync-auth.test.ts +118 -0
  347. package/src/modules/kb-sync/__tests__/sync-payload.test.ts +148 -0
  348. package/src/modules/kb-sync/index.ts +19 -0
  349. package/src/modules/kb-sync/kb-sync.interface.ts +79 -0
  350. package/src/modules/kb-sync/kb-sync.routes.ts +197 -0
  351. package/src/modules/kb-sync/kb-sync.service.ts +201 -0
  352. package/src/modules/kb-sync/sync-auth.ts +118 -0
  353. package/src/modules/kb-sync/sync-payload.ts +143 -0
  354. package/src/modules/marketplace/__tests__/github-facade.test.ts +443 -0
  355. package/src/modules/marketplace/__tests__/marketplace-git.test.ts +179 -0
  356. package/src/modules/marketplace/git-http.routes.ts +193 -0
  357. package/src/modules/marketplace/github-facade/github-facade-admin.routes.ts +78 -0
  358. package/src/modules/marketplace/github-facade/github-facade-codes.store.ts +145 -0
  359. package/src/modules/marketplace/github-facade/github-facade-credentials.service.ts +208 -0
  360. package/src/modules/marketplace/github-facade/github-facade.routes.ts +268 -0
  361. package/src/modules/marketplace/github-facade/github-facade.service.ts +221 -0
  362. package/src/modules/marketplace/github-facade/index.ts +25 -0
  363. package/src/modules/marketplace/index.ts +3 -0
  364. package/src/modules/marketplace/marketplace-repo.service.ts +337 -0
  365. package/src/modules/mcp/oauth/bevel-oauth-provider.ts +3 -0
  366. package/src/modules/mcp/oauth/oauth-consent.routes.ts +24 -2
  367. package/src/modules/mcp/oauth/oauth-state.ts +15 -3
  368. package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +163 -0
  369. package/src/modules/plugins/__tests__/compile-marketplace.test.ts +294 -0
  370. package/src/modules/plugins/__tests__/plugin-index.service.test.ts +56 -12
  371. package/src/modules/plugins/__tests__/plugin-links.service.test.ts +287 -0
  372. package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +205 -5
  373. package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +394 -0
  374. package/src/modules/plugins/__tests__/plugins.routes.test.ts +80 -33
  375. package/src/modules/plugins/compile/compile-marketplace.ts +403 -0
  376. package/src/modules/plugins/compile/marketplace-compiler.service.ts +150 -0
  377. package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +329 -0
  378. package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +140 -0
  379. package/src/modules/plugins/discovery/bundle-dialect/registry.ts +175 -0
  380. package/src/modules/plugins/discovery/kb-plugin-source.ts +114 -0
  381. package/src/modules/plugins/discovery/native.source.ts +122 -0
  382. package/src/modules/plugins/discovery/plugin-source.ts +99 -0
  383. package/src/modules/plugins/index.ts +10 -0
  384. package/src/modules/plugins/plugin-links.service.ts +363 -0
  385. package/src/modules/plugins/plugin-links.ts +184 -0
  386. package/src/modules/plugins/plugin-provision.service.ts +160 -54
  387. package/src/modules/plugins/plugin-rename.service.ts +298 -0
  388. package/src/modules/plugins/plugins.contract.ts +28 -1
  389. package/src/modules/plugins/plugins.routes.ts +128 -11
  390. package/src/modules/plugins/plugins.service.ts +106 -53
  391. package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +12 -0
  392. package/src/modules/secrets-vault/__tests__/oauth-return-to.route.test.ts +10 -3
  393. package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +26 -0
  394. package/src/modules/secrets-vault/db-secrets-vault.service.ts +1 -1
  395. package/src/modules/secrets-vault/secrets-vault.routes.ts +35 -1
  396. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +57 -0
  397. package/src/modules/settings/__tests__/setup.routes.sync-status.test.ts +77 -0
  398. package/src/modules/settings/deployment-settings.service.ts +95 -2
  399. package/src/modules/settings/setup.routes.ts +24 -0
  400. package/src/modules/skills/__tests__/skill-access-requests.routes.test.ts +128 -0
  401. package/src/modules/skills/__tests__/skills.service.test.ts +85 -0
  402. package/src/modules/skills/index.ts +1 -0
  403. package/src/modules/skills/pending-skills.service.ts +7 -5
  404. package/src/modules/skills/skill-access-requests.routes.ts +199 -0
  405. package/src/modules/skills/skills.contract.ts +32 -0
  406. package/src/modules/skills/skills.routes.ts +59 -3
  407. package/src/modules/skills/skills.service.ts +84 -22
  408. package/src/modules/tool-auth/external-api-key.interface.ts +20 -1
  409. package/src/modules/tool-auth/external-api-key.service.ts +31 -13
  410. package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +35 -1
  411. package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +2 -0
  412. package/src/modules/tool-manuals/__tests__/tool-manuals.health-check.test.ts +104 -0
  413. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +56 -0
  414. package/src/modules/tool-manuals/mcp-json-discovery.ts +154 -76
  415. package/src/modules/tool-manuals/mcp-server-edit.service.ts +13 -4
  416. package/src/modules/tool-manuals/tool-manuals.contract.ts +89 -0
  417. package/src/modules/tool-manuals/tool-manuals.service.ts +210 -37
  418. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +1 -1
  419. package/src/modules/workflow/__tests__/workflow.routes.history-read-gate.test.ts +139 -0
  420. package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +337 -0
  421. package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +1 -0
  422. package/src/modules/workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts +7 -1
  423. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +97 -10
  424. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +119 -2
  425. package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +437 -0
  426. package/src/modules/workflow/git/__tests__/git.service.history-guards.test.ts +86 -0
  427. package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +3 -3
  428. package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +47 -4
  429. package/src/modules/workflow/git/__tests__/git.service.syncFromRemote.test.ts +253 -0
  430. package/src/modules/workflow/git/git.service.ts +354 -63
  431. package/src/modules/workflow/git/pull-request.service.ts +9 -0
  432. package/src/modules/workflow/workflow.routes.ts +104 -4
  433. package/src/modules/workflow/workflow.service.ts +505 -64
  434. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +6 -7
  435. package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +93 -0
  436. package/src/modules/workspace/__tests__/workspace.service.missing-branch.test.ts +28 -0
  437. package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +42 -12
  438. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +219 -4
  439. package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +129 -0
  440. package/src/modules/workspace/startup/steps/seed-tree.ts +44 -2
  441. package/src/modules/workspace/startup/steps/template-files.step.ts +131 -27
  442. package/src/modules/workspace/workspace.routes.ts +17 -21
  443. package/src/modules/workspace/workspace.service.ts +128 -19
  444. package/src/shared/__tests__/filename.test.ts +0 -0
  445. package/src/shared/__tests__/fs-walk.test.ts +22 -1
  446. package/src/shared/__tests__/kb-walk.test.ts +107 -0
  447. package/src/shared/__tests__/path-order.test.ts +24 -0
  448. package/src/shared/__tests__/token-crypto.test.ts +34 -0
  449. package/src/shared/__tests__/ttl-cache.test.ts +55 -0
  450. package/src/shared/domain-errors.ts +29 -0
  451. package/src/shared/fs-errors.ts +10 -0
  452. package/src/shared/fs-walk.ts +38 -23
  453. package/src/shared/kb-walk.ts +95 -0
  454. package/src/shared/path-order.ts +33 -0
  455. package/src/shared/token-crypto.ts +28 -10
  456. package/src/shared/ttl-cache.ts +33 -1
@@ -0,0 +1,183 @@
1
+ import { sanitizeError } from '../workflow/sanitize-error.js';
2
+ /**
3
+ * Runs remote syncs one at a time and folds everything that arrives
4
+ * mid-run into ONE follow-up.
5
+ *
6
+ * Why coalesce: a git host fires several hooks for one event — Azure DevOps
7
+ * sends a push, a PR-updated and a PR-merged within a second of each other —
8
+ * and each would otherwise queue behind the workspace mutex to pull the same
9
+ * tree again. The follow-up pulls the union of every request that arrived
10
+ * during the run (an "all" absorbs the rest).
11
+ *
12
+ * But each caller is answered for the branches IT asked about. The endpoint
13
+ * promises to fail exactly when the caller's branch is not in sync; a hook
14
+ * for branch A answered with branch B's conflict would fail the wrong
15
+ * subscription — and a host that disables subscriptions after repeated
16
+ * failures would disable the wrong one.
17
+ *
18
+ * Branches are pulled sequentially. N is small (only cloned branches count),
19
+ * the per-clone mutex serialises them anyway, and one slow origin round-trip
20
+ * at a time keeps the process calm during a burst.
21
+ */
22
+ export class KbSyncService {
23
+ workflow;
24
+ workspaces;
25
+ now;
26
+ inFlight = null;
27
+ /** Everyone who arrived mid-run, each with what they asked for. */
28
+ waiters = [];
29
+ last = null;
30
+ constructor(workflow, workspaces, now = () => Date.now()) {
31
+ this.workflow = workflow;
32
+ this.workspaces = workspaces;
33
+ this.now = now;
34
+ }
35
+ lastSync() {
36
+ return this.last;
37
+ }
38
+ sync(request) {
39
+ if (!this.inFlight)
40
+ return this.start(request);
41
+ return new Promise((resolve, reject) => {
42
+ // Copied on entry: the caller keeps its array, and a caller that reuses
43
+ // or edits it before the follow-up runs must not change what is pulled
44
+ // or what it is answered for.
45
+ const branches = request.branches === 'all' ? 'all' : [...request.branches];
46
+ this.waiters.push({ branches, by: request.by, resolve, reject });
47
+ });
48
+ }
49
+ start(request) {
50
+ const run = this.run(request);
51
+ this.inFlight = run.catch(() => undefined).finally(() => {
52
+ this.inFlight = null;
53
+ this.drain();
54
+ });
55
+ return run;
56
+ }
57
+ /**
58
+ * Run ONE follow-up for everyone who arrived during the last run: the union
59
+ * of their branches, then each waiter answered from its own share of the
60
+ * result — never from another caller's branches.
61
+ */
62
+ drain() {
63
+ if (this.waiters.length === 0)
64
+ return;
65
+ const waiters = this.waiters;
66
+ this.waiters = [];
67
+ const union = new Set();
68
+ let all = false;
69
+ const by = new Set();
70
+ for (const w of waiters) {
71
+ if (w.branches === 'all')
72
+ all = true;
73
+ else
74
+ for (const b of w.branches)
75
+ union.add(b);
76
+ if (w.by)
77
+ by.add(w.by);
78
+ }
79
+ const request = {
80
+ branches: all ? 'all' : [...union],
81
+ by: by.size > 0 ? [...by].join(', ') : undefined,
82
+ };
83
+ this.start(request).then((result) => {
84
+ for (const w of waiters)
85
+ w.resolve(KbSyncService.subsetFor(result, w.branches));
86
+ }, (err) => {
87
+ for (const w of waiters)
88
+ w.reject(err);
89
+ });
90
+ }
91
+ /** The part of a union run that answers one caller: its branches, and its status over them. */
92
+ static subsetFor(result, branches) {
93
+ if (branches === 'all')
94
+ return result;
95
+ const wanted = new Set(branches);
96
+ const results = result.results.filter((r) => wanted.has(r.branch));
97
+ return {
98
+ status: KbSyncService.statusOf(results),
99
+ results,
100
+ changeRequests: result.changeRequests,
101
+ };
102
+ }
103
+ static statusOf(results) {
104
+ const clean = results.every((r) => r.outcome === 'updated' ||
105
+ r.outcome === 'up-to-date' ||
106
+ r.outcome === 'not-cloned' ||
107
+ r.outcome === 'remote-gone');
108
+ return clean ? 'synced' : 'partial';
109
+ }
110
+ async run(request) {
111
+ const known = await this.workspaces.listClonedWorkspaces();
112
+ const byBranch = new Map(known.map((w) => [w.branch, w.id]));
113
+ const targets = request.branches === 'all'
114
+ ? known.map((w) => ({ branch: w.branch, id: w.id }))
115
+ : request.branches.map((branch) => ({ branch, id: byBranch.get(branch) ?? null }));
116
+ const unreadable = new Map(known.filter((w) => w.unreadable).map((w) => [w.branch, w.unreadable]));
117
+ const results = [];
118
+ for (const { branch, id } of targets) {
119
+ if (id === null) {
120
+ results.push({ branch, outcome: 'not-cloned' });
121
+ continue;
122
+ }
123
+ const cannotRead = unreadable.get(branch);
124
+ if (cannotRead) {
125
+ results.push({ branch, outcome: 'error', error: cannotRead });
126
+ continue;
127
+ }
128
+ let outcome;
129
+ try {
130
+ outcome = await this.workflow.syncWorkspaceFromRemote(id);
131
+ }
132
+ catch (err) {
133
+ // The workflow step promises outcomes, not throws — but one broken
134
+ // clone must never take the other branches, the sweep, or every
135
+ // coalesced caller down with it, so the promise is enforced here too.
136
+ const message = sanitizeError(err);
137
+ console.error(`[sync] unexpected failure syncing "${branch}": ${message}`);
138
+ outcome = { branch, outcome: 'error', error: message };
139
+ }
140
+ results.push(outcome);
141
+ if (outcome.outcome === 'remote-gone') {
142
+ // The host deleted the branch. Left in place, the stale clone would
143
+ // fail its fetch on every following full sync — and a webhook host
144
+ // disables a subscription that keeps failing. The workflow retires it
145
+ // under the branch-lifecycle lock, after asking origin again, so a
146
+ // branch recreated since the pull keeps its clone. Best-effort.
147
+ try {
148
+ const removed = await this.workflow.retireRemoteGoneClone(id);
149
+ if (removed)
150
+ console.log(`[sync] removed the clone of "${branch}" — deleted on the host`);
151
+ else
152
+ console.log(`[sync] kept the clone of "${branch}" — it is back on the host, or already gone`);
153
+ }
154
+ catch (err) {
155
+ console.warn(`[sync] could not remove the clone of "${branch}":`, sanitizeError(err));
156
+ }
157
+ }
158
+ }
159
+ // The host may have deleted a branch (an ADO PR completed with "delete
160
+ // source branch"); the existing sweep closes the Hexis request that
161
+ // pointed at it. Best-effort — it fails safe by closing nothing.
162
+ let closedDeletedBranch = 0;
163
+ try {
164
+ closedDeletedBranch = await this.workflow.closeChangeRequestsWithDeletedBranches();
165
+ }
166
+ catch (err) {
167
+ console.warn('[sync] deleted-branch sweep failed:', err instanceof Error ? err.message : err);
168
+ }
169
+ const result = {
170
+ status: KbSyncService.statusOf(results),
171
+ results,
172
+ changeRequests: { closedDeletedBranch },
173
+ };
174
+ this.last = {
175
+ at: this.now(),
176
+ by: request.by ?? 'unknown',
177
+ status: result.status,
178
+ results: [...results],
179
+ };
180
+ return result;
181
+ }
182
+ }
183
+ //# sourceMappingURL=kb-sync.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kb-sync.service.js","sourceRoot":"","sources":["../../../src/modules/kb-sync/kb-sync.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Who may call `POST /api/sync`, decided from the request's credentials.
3
+ *
4
+ * Framework-agnostic on purpose (the route hands in plain strings and the
5
+ * raw body) so the rule is one function with one test, not something spread
6
+ * across middleware.
7
+ *
8
+ * Four credentials are accepted, because the callers cannot all speak the
9
+ * same one:
10
+ *
11
+ * bearer `Authorization: Bearer <secret>` — ADO Web Hooks and
12
+ * any pipeline can set a header.
13
+ * gitlab-token `X-Gitlab-Token: <secret>` — what GitLab sends.
14
+ * github-signature `X-Hub-Signature-256: sha256=<hmac of the raw body>` —
15
+ * GitHub and Gitea cannot set headers, only sign.
16
+ * admin-session a browser JWT whose user is an admin, so a "Sync now"
17
+ * button and a curl with your own session both work while
18
+ * the hook is being wired up.
19
+ *
20
+ * Every comparison is constant-time. The secret never travels in the URL.
21
+ */
22
+ export type SyncCredential = {
23
+ kind: 'bearer' | 'gitlab-token' | 'github-signature';
24
+ } | {
25
+ kind: 'admin-session';
26
+ email: string;
27
+ };
28
+ export type SyncAuthResult = {
29
+ ok: true;
30
+ credential: SyncCredential;
31
+ } | {
32
+ ok: false;
33
+ status: 401 | 503;
34
+ message: string;
35
+ };
36
+ export interface SyncAuthInput {
37
+ /** The configured secret, or empty when none is set. */
38
+ secret: string;
39
+ authorization?: string;
40
+ gitlabToken?: string;
41
+ hubSignature?: string;
42
+ /** The request body exactly as received — the HMAC is over these bytes. */
43
+ rawBody?: Buffer;
44
+ }
45
+ export interface SyncSessionVerifier {
46
+ /** Resolve a browser JWT to its email, or null when it is not one. */
47
+ verifyJwt(token: string): {
48
+ email: string;
49
+ } | null;
50
+ isAdmin(email: string): Promise<boolean>;
51
+ }
52
+ /**
53
+ * Shortest secret the endpoint will honour. The setup screen enforces the
54
+ * same floor on save; this is the boundary that also covers a secret set
55
+ * through the environment, which no validator ever sees.
56
+ */
57
+ export declare const MIN_SYNC_SECRET_LENGTH = 16;
58
+ export declare function verifySyncCredential(input: SyncAuthInput, session: SyncSessionVerifier): Promise<SyncAuthResult>;
59
+ //# sourceMappingURL=sync-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-auth.d.ts","sourceRoot":"","sources":["../../../src/modules/kb-sync/sync-auth.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,QAAQ,GAAG,cAAc,GAAG,kBAAkB,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7C,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,cAAc,CAAA;CAAE,GACxC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,sEAAsE;IACtE,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACnD,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1C;AAMD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAazC,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,CA4CzB"}
@@ -0,0 +1,62 @@
1
+ import { createHmac } from 'node:crypto';
2
+ import { timingSafeStringEqual } from '../auth/password-hash.js';
3
+ const NO_SECRET = 'No sync secret is configured. Set KB_SYNC_SECRET (or the setup screen’s sync secret), ' +
4
+ 'or call this endpoint with an administrator session.';
5
+ /**
6
+ * Shortest secret the endpoint will honour. The setup screen enforces the
7
+ * same floor on save; this is the boundary that also covers a secret set
8
+ * through the environment, which no validator ever sees.
9
+ */
10
+ export const MIN_SYNC_SECRET_LENGTH = 16;
11
+ const SECRET_TOO_SHORT = `The configured sync secret is shorter than ${MIN_SYNC_SECRET_LENGTH} characters and is not ` +
12
+ 'accepted. Set a longer KB_SYNC_SECRET, or call this endpoint with an administrator session.';
13
+ function signatureMatches(secret, rawBody, header) {
14
+ const [scheme, hex] = header.split('=', 2);
15
+ if (scheme !== 'sha256' || !hex)
16
+ return false;
17
+ const expected = createHmac('sha256', secret).update(rawBody).digest('hex');
18
+ return timingSafeStringEqual(expected, hex.toLowerCase());
19
+ }
20
+ export async function verifySyncCredential(input, session) {
21
+ const configured = input.secret.trim();
22
+ // A too-short secret is treated as absent for matching purposes and named
23
+ // as the problem below, so a one-character deployment secret can never be
24
+ // what lets a caller in.
25
+ const usable = configured.length >= MIN_SYNC_SECRET_LENGTH;
26
+ const secret = usable ? configured : '';
27
+ const bearer = input.authorization?.startsWith('Bearer ')
28
+ ? input.authorization.slice('Bearer '.length).trim()
29
+ : '';
30
+ // A shared secret presented in any of its three shapes.
31
+ if (secret) {
32
+ if (bearer && timingSafeStringEqual(bearer, secret)) {
33
+ return { ok: true, credential: { kind: 'bearer' } };
34
+ }
35
+ if (input.gitlabToken && timingSafeStringEqual(input.gitlabToken.trim(), secret)) {
36
+ return { ok: true, credential: { kind: 'gitlab-token' } };
37
+ }
38
+ if (input.hubSignature && input.rawBody && signatureMatches(secret, input.rawBody, input.hubSignature.trim())) {
39
+ return { ok: true, credential: { kind: 'github-signature' } };
40
+ }
41
+ }
42
+ // An admin's own session, carried as the bearer. Checked after the secret
43
+ // so a secret that happens to parse as a JWT is never mistaken for one.
44
+ if (bearer) {
45
+ const claim = session.verifyJwt(bearer);
46
+ if (claim && (await session.isAdmin(claim.email))) {
47
+ return { ok: true, credential: { kind: 'admin-session', email: claim.email } };
48
+ }
49
+ }
50
+ // Nothing matched. Say WHY when the reason is the deployment's, not the
51
+ // caller's: a hook pointed at an unconfigured endpoint should read "set
52
+ // the secret", not "wrong secret".
53
+ if (!secret && (bearer || input.gitlabToken || input.hubSignature)) {
54
+ return { ok: false, status: 503, message: configured ? SECRET_TOO_SHORT : NO_SECRET };
55
+ }
56
+ return {
57
+ ok: false,
58
+ status: 401,
59
+ message: 'A valid sync secret or an administrator session is required.',
60
+ };
61
+ }
62
+ //# sourceMappingURL=sync-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-auth.js","sourceRoot":"","sources":["../../../src/modules/kb-sync/sync-auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Turn whatever a caller POSTed to `/api/sync` into the branches to sync.
3
+ *
4
+ * Pure: no IO, no throwing on foreign shapes. The endpoint is meant to be
5
+ * pointed at by a webhook subscription whose payload the operator does not
6
+ * control, so an unrecognised body must degrade to "sync everything" — the
7
+ * safe answer, and the one an empty pipeline call gets too — never to a 400
8
+ * that makes the host disable the subscription.
9
+ *
10
+ * Recognised shapes:
11
+ *
12
+ * explicit `{ "branches": ["main", "ali/x"] }`
13
+ * azure-devops `eventType: git.push` → `resource.refUpdates[].name`
14
+ * `eventType: git.pullrequest.*` → `resource.targetRefName`
15
+ * and `resource.sourceRefName`
16
+ * github/gitea `{ "ref": "refs/heads/main" }` (push)
17
+ * gitlab `{ "object_kind": "push", "ref": "refs/heads/main" }`
18
+ *
19
+ * Only `refs/heads/*` refs count; a tag push names nothing to sync. A branch
20
+ * name git would refuse is dropped from a provider payload (the host
21
+ * produced it, nothing we can do) but reported for an explicit body, where
22
+ * it is the caller's mistake to fix.
23
+ */
24
+ export type SyncPayloadSource = 'explicit' | 'azure-devops' | 'github' | 'gitlab' | 'none';
25
+ export interface ParsedSyncPayload {
26
+ source: SyncPayloadSource;
27
+ branches: string[] | 'all';
28
+ /** Explicit-body names git would refuse. Empty for every other source. */
29
+ invalid: string[];
30
+ }
31
+ export declare function parseSyncPayload(body: unknown): ParsedSyncPayload;
32
+ //# sourceMappingURL=sync-payload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-payload.d.ts","sourceRoot":"","sources":["../../../src/modules/kb-sync/sync-payload.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,cAAc,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE3F,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAC3B,0EAA0E;IAC1E,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AA+CD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,iBAAiB,CA+DjE"}
@@ -0,0 +1,105 @@
1
+ import { assertValidBranchName } from '../kb-fs/branch-name.js';
2
+ const HEADS = 'refs/heads/';
3
+ function isRecord(v) {
4
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
5
+ }
6
+ function branchFromRef(ref) {
7
+ if (typeof ref !== 'string' || !ref.startsWith(HEADS))
8
+ return null;
9
+ const name = ref.slice(HEADS.length);
10
+ return isValidBranch(name) ? name : null;
11
+ }
12
+ function isValidBranch(name) {
13
+ try {
14
+ assertValidBranchName(name);
15
+ return true;
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ }
21
+ function unique(names) {
22
+ return [...new Set(names)];
23
+ }
24
+ /**
25
+ * How an invalid explicit entry is echoed back. Only primitives are
26
+ * stringified: `String(obj)` on a JSON object carrying `"toString": 1` throws
27
+ * ("Cannot convert object to primitive value"), which would turn a caller's
28
+ * bad body into our 500.
29
+ */
30
+ function describeInvalid(entry) {
31
+ if (entry === null)
32
+ return 'null';
33
+ switch (typeof entry) {
34
+ case 'string':
35
+ return entry.trim() === '' ? '(empty)' : entry;
36
+ case 'number':
37
+ case 'boolean':
38
+ case 'bigint':
39
+ return String(entry);
40
+ default:
41
+ return Array.isArray(entry) ? '(array)' : '(object)';
42
+ }
43
+ }
44
+ export function parseSyncPayload(body) {
45
+ if (!isRecord(body))
46
+ return { source: 'none', branches: 'all', invalid: [] };
47
+ if ('branches' in body) {
48
+ const raw = body.branches;
49
+ if (!Array.isArray(raw))
50
+ return { source: 'explicit', branches: 'all', invalid: [] };
51
+ const valid = [];
52
+ const invalid = [];
53
+ for (const entry of raw) {
54
+ if (typeof entry !== 'string' || !entry.trim()) {
55
+ invalid.push(describeInvalid(entry));
56
+ continue;
57
+ }
58
+ const name = entry.trim();
59
+ (isValidBranch(name) ? valid : invalid).push(name);
60
+ }
61
+ return { source: 'explicit', branches: unique(valid), invalid };
62
+ }
63
+ // Azure DevOps service hook. `eventType` names the event; the branches sit
64
+ // under `resource` in a per-event shape.
65
+ const eventType = body.eventType;
66
+ if (typeof eventType === 'string' && isRecord(body.resource)) {
67
+ const resource = body.resource;
68
+ if (eventType === 'git.push') {
69
+ const updates = Array.isArray(resource.refUpdates) ? resource.refUpdates : [];
70
+ // A DELETION (new object id all zeros) names its branch too: syncing it
71
+ // is what finds the branch gone and retires the stale clone, instead of
72
+ // leaving it to fail on some unrelated full sync later.
73
+ const branches = updates
74
+ .map((u) => (isRecord(u) ? branchFromRef(u.name) : null))
75
+ .filter((b) => b !== null);
76
+ return { source: 'azure-devops', branches: unique(branches), invalid: [] };
77
+ }
78
+ if (eventType.startsWith('git.pullrequest.')) {
79
+ const branches = [branchFromRef(resource.targetRefName), branchFromRef(resource.sourceRefName)]
80
+ .filter((b) => b !== null);
81
+ return { source: 'azure-devops', branches: unique(branches), invalid: [] };
82
+ }
83
+ }
84
+ // GitLab events all carry `object_kind`. Only a push (or a tag push, which
85
+ // names no branch) is a statement about a ref; anything else with a stray
86
+ // `ref` — a merge request, a pipeline — is not, and takes the "everything"
87
+ // fallback rather than being read as a push of that ref.
88
+ if (typeof body.object_kind === 'string') {
89
+ if (body.object_kind !== 'push' && body.object_kind !== 'tag_push') {
90
+ return { source: 'none', branches: 'all', invalid: [] };
91
+ }
92
+ // A deletion (a push to the null sha) names its branch like any push: the
93
+ // sync finds it gone and retires the clone.
94
+ const branch = branchFromRef(body.ref);
95
+ return { source: 'gitlab', branches: branch ? [branch] : [], invalid: [] };
96
+ }
97
+ // GitHub / Gitea push: `ref` at the top level, no `object_kind`. A deletion
98
+ // (`deleted: true`) names its branch like any push, for the same reason.
99
+ if (typeof body.ref === 'string') {
100
+ const branch = branchFromRef(body.ref);
101
+ return { source: 'github', branches: branch ? [branch] : [], invalid: [] };
102
+ }
103
+ return { source: 'none', branches: 'all', invalid: [] };
104
+ }
105
+ //# sourceMappingURL=sync-payload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-payload.js","sourceRoot":"","sources":["../../../src/modules/kb-sync/sync-payload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import express from 'express';
2
+ import type { AuthUser } from '@bevel-software/platform-shared';
3
+ import type { MarketplaceRepoService } from './marketplace-repo.service.js';
4
+ import '../tool-auth/external-api-key.interface.js';
5
+ /** How a bearer string resolves to a user — the connection-key service's shape. */
6
+ export interface MarketplaceKeyResolver {
7
+ looksLikeExternalApiKey(token: string): boolean;
8
+ verifyAndLoadToken(plaintext: string): Promise<{
9
+ tokenId: string;
10
+ user: AuthUser;
11
+ } | null>;
12
+ }
13
+ /**
14
+ * The per-user marketplace as a git remote:
15
+ *
16
+ * git clone https://key:<connection-key>@<host>/git/marketplace.git
17
+ *
18
+ * Anything that speaks git's smart HTTP protocol — Claude Code, Codex, `npx
19
+ * skills`, plain git — clones a repository whose `main` is the caller's
20
+ * compiled tree. The route authenticates, brings the caller's namespace up to
21
+ * date (`MarketplaceRepoService.ensureCompiled`), and hands the request to
22
+ * `git http-backend` with `GIT_NAMESPACE` set, so git itself serves the
23
+ * protocol and only that namespace's refs exist as far as the client can tell.
24
+ *
25
+ * AUTH: HTTP Basic with the connection key as the password (the username is
26
+ * anything — git sends whatever the URL carried), or the key as a Bearer
27
+ * token. The same keys the MCP endpoint takes, the same service resolving
28
+ * them, and the same metering stamp (`req.externalApiKeyId`), so a key's
29
+ * `lastUsedAt` moves when an agent refreshes its plugins. A 401 challenges
30
+ * with Basic so a client without credentials prompts for them.
31
+ *
32
+ * READ-ONLY: the receive-pack service is refused here by name, and the bare
33
+ * repository pins `http.receivepack=false` for good measure — a push would
34
+ * otherwise be enabled by http-backend the moment REMOTE_USER is set.
35
+ */
36
+ export declare function createMarketplaceGitRoutes(deps: {
37
+ repo: MarketplaceRepoService;
38
+ keys: MarketplaceKeyResolver;
39
+ /** The URL path the router is mounted at, e.g. `/git`. Used for PATH_INFO. */
40
+ mountPath: string;
41
+ }): express.Router;
42
+ //# sourceMappingURL=git-http.routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-http.routes.d.ts","sourceRoot":"","sources":["../../../src/modules/marketplace/git-http.routes.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,4CAA4C,CAAC;AAEpD,mFAAmF;AACnF,MAAM,WAAW,sBAAsB;IACrC,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAChD,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CAC5F;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE;IAC/C,IAAI,EAAE,sBAAsB,CAAC;IAC7B,IAAI,EAAE,sBAAsB,CAAC;IAC7B,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,CAwJjB"}