@bevel-software/platform-core-backend 0.14.0 → 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 (385) 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 +99 -8
  8. package/dist/core/create-core-server.js.map +1 -1
  9. package/dist/core/create-core-services.d.ts +18 -1
  10. package/dist/core/create-core-services.d.ts.map +1 -1
  11. package/dist/core/create-core-services.js +96 -43
  12. package/dist/core/create-core-services.js.map +1 -1
  13. package/dist/modules/access/access-control.interface.d.ts +18 -6
  14. package/dist/modules/access/access-control.interface.d.ts.map +1 -1
  15. package/dist/modules/access/access-control.service.d.ts +26 -1
  16. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  17. package/dist/modules/access/access-control.service.js +213 -71
  18. package/dist/modules/access/access-control.service.js.map +1 -1
  19. package/dist/modules/access/access.routes.d.ts.map +1 -1
  20. package/dist/modules/access/access.routes.js +59 -7
  21. package/dist/modules/access/access.routes.js.map +1 -1
  22. package/dist/modules/access-model/access-grammar.d.ts +51 -1
  23. package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
  24. package/dist/modules/access-model/access-grammar.js +95 -1
  25. package/dist/modules/access-model/access-grammar.js.map +1 -1
  26. package/dist/modules/access-model/group-files.d.ts.map +1 -1
  27. package/dist/modules/access-model/group-files.js +4 -1
  28. package/dist/modules/access-model/group-files.js.map +1 -1
  29. package/dist/modules/access-model/plugin-principals.d.ts +49 -0
  30. package/dist/modules/access-model/plugin-principals.d.ts.map +1 -0
  31. package/dist/modules/access-model/plugin-principals.js +125 -0
  32. package/dist/modules/access-model/plugin-principals.js.map +1 -0
  33. package/dist/modules/database/core-schema.d.ts +326 -0
  34. package/dist/modules/database/core-schema.d.ts.map +1 -1
  35. package/dist/modules/database/core-schema.js +52 -0
  36. package/dist/modules/database/core-schema.js.map +1 -1
  37. package/dist/modules/kb-sync/index.d.ts +6 -0
  38. package/dist/modules/kb-sync/index.d.ts.map +1 -0
  39. package/dist/modules/kb-sync/index.js +5 -0
  40. package/dist/modules/kb-sync/index.js.map +1 -0
  41. package/dist/modules/kb-sync/kb-sync.interface.d.ts +77 -0
  42. package/dist/modules/kb-sync/kb-sync.interface.d.ts.map +1 -0
  43. package/dist/modules/kb-sync/kb-sync.interface.js +2 -0
  44. package/dist/modules/kb-sync/kb-sync.interface.js.map +1 -0
  45. package/dist/modules/kb-sync/kb-sync.routes.d.ts +70 -0
  46. package/dist/modules/kb-sync/kb-sync.routes.d.ts.map +1 -0
  47. package/dist/modules/kb-sync/kb-sync.routes.js +135 -0
  48. package/dist/modules/kb-sync/kb-sync.routes.js.map +1 -0
  49. package/dist/modules/kb-sync/kb-sync.service.d.ts +45 -0
  50. package/dist/modules/kb-sync/kb-sync.service.d.ts.map +1 -0
  51. package/dist/modules/kb-sync/kb-sync.service.js +183 -0
  52. package/dist/modules/kb-sync/kb-sync.service.js.map +1 -0
  53. package/dist/modules/kb-sync/sync-auth.d.ts +59 -0
  54. package/dist/modules/kb-sync/sync-auth.d.ts.map +1 -0
  55. package/dist/modules/kb-sync/sync-auth.js +62 -0
  56. package/dist/modules/kb-sync/sync-auth.js.map +1 -0
  57. package/dist/modules/kb-sync/sync-payload.d.ts +32 -0
  58. package/dist/modules/kb-sync/sync-payload.d.ts.map +1 -0
  59. package/dist/modules/kb-sync/sync-payload.js +105 -0
  60. package/dist/modules/kb-sync/sync-payload.js.map +1 -0
  61. package/dist/modules/marketplace/git-http.routes.d.ts +42 -0
  62. package/dist/modules/marketplace/git-http.routes.d.ts.map +1 -0
  63. package/dist/modules/marketplace/git-http.routes.js +190 -0
  64. package/dist/modules/marketplace/git-http.routes.js.map +1 -0
  65. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts +23 -0
  66. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts.map +1 -0
  67. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js +59 -0
  68. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js.map +1 -0
  69. package/dist/modules/marketplace/github-facade/github-facade-codes.store.d.ts +59 -0
  70. package/dist/modules/marketplace/github-facade/github-facade-codes.store.d.ts.map +1 -0
  71. package/dist/modules/marketplace/github-facade/github-facade-codes.store.js +96 -0
  72. package/dist/modules/marketplace/github-facade/github-facade-codes.store.js.map +1 -0
  73. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts +99 -0
  74. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts.map +1 -0
  75. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js +147 -0
  76. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js.map +1 -0
  77. package/dist/modules/marketplace/github-facade/github-facade.routes.d.ts +47 -0
  78. package/dist/modules/marketplace/github-facade/github-facade.routes.d.ts.map +1 -0
  79. package/dist/modules/marketplace/github-facade/github-facade.routes.js +228 -0
  80. package/dist/modules/marketplace/github-facade/github-facade.routes.js.map +1 -0
  81. package/dist/modules/marketplace/github-facade/github-facade.service.d.ts +109 -0
  82. package/dist/modules/marketplace/github-facade/github-facade.service.d.ts.map +1 -0
  83. package/dist/modules/marketplace/github-facade/github-facade.service.js +172 -0
  84. package/dist/modules/marketplace/github-facade/github-facade.service.js.map +1 -0
  85. package/dist/modules/marketplace/github-facade/index.d.ts +6 -0
  86. package/dist/modules/marketplace/github-facade/index.d.ts.map +1 -0
  87. package/dist/modules/marketplace/github-facade/index.js +6 -0
  88. package/dist/modules/marketplace/github-facade/index.js.map +1 -0
  89. package/dist/modules/marketplace/index.d.ts +4 -0
  90. package/dist/modules/marketplace/index.d.ts.map +1 -0
  91. package/dist/modules/marketplace/index.js +4 -0
  92. package/dist/modules/marketplace/index.js.map +1 -0
  93. package/dist/modules/marketplace/marketplace-repo.service.d.ts +122 -0
  94. package/dist/modules/marketplace/marketplace-repo.service.d.ts.map +1 -0
  95. package/dist/modules/marketplace/marketplace-repo.service.js +300 -0
  96. package/dist/modules/marketplace/marketplace-repo.service.js.map +1 -0
  97. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
  98. package/dist/modules/mcp/oauth/bevel-oauth-provider.js +4 -0
  99. package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
  100. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts +14 -8
  101. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -1
  102. package/dist/modules/mcp/oauth/oauth-consent.routes.js +13 -1
  103. package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -1
  104. package/dist/modules/mcp/oauth/oauth-state.d.ts +13 -2
  105. package/dist/modules/mcp/oauth/oauth-state.d.ts.map +1 -1
  106. package/dist/modules/mcp/oauth/oauth-state.js +3 -1
  107. package/dist/modules/mcp/oauth/oauth-state.js.map +1 -1
  108. package/dist/modules/plugins/compile/compile-marketplace.d.ts +97 -0
  109. package/dist/modules/plugins/compile/compile-marketplace.d.ts.map +1 -0
  110. package/dist/modules/plugins/compile/compile-marketplace.js +240 -0
  111. package/dist/modules/plugins/compile/compile-marketplace.js.map +1 -0
  112. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +66 -0
  113. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -0
  114. package/dist/modules/plugins/compile/marketplace-compiler.service.js +132 -0
  115. package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -0
  116. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts +37 -0
  117. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -0
  118. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +135 -0
  119. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -0
  120. package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts +45 -0
  121. package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts.map +1 -0
  122. package/dist/modules/plugins/discovery/bundle-dialect/registry.js +147 -0
  123. package/dist/modules/plugins/discovery/bundle-dialect/registry.js.map +1 -0
  124. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +37 -0
  125. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -0
  126. package/dist/modules/plugins/discovery/kb-plugin-source.js +107 -0
  127. package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -0
  128. package/dist/modules/plugins/discovery/native.source.d.ts +15 -0
  129. package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -0
  130. package/dist/modules/plugins/discovery/native.source.js +102 -0
  131. package/dist/modules/plugins/discovery/native.source.js.map +1 -0
  132. package/dist/modules/plugins/discovery/plugin-source.d.ts +96 -0
  133. package/dist/modules/plugins/discovery/plugin-source.d.ts.map +1 -0
  134. package/dist/modules/plugins/discovery/plugin-source.js +2 -0
  135. package/dist/modules/plugins/discovery/plugin-source.js.map +1 -0
  136. package/dist/modules/plugins/index.d.ts +10 -1
  137. package/dist/modules/plugins/index.d.ts.map +1 -1
  138. package/dist/modules/plugins/index.js +8 -0
  139. package/dist/modules/plugins/index.js.map +1 -1
  140. package/dist/modules/plugins/plugin-links.d.ts +66 -0
  141. package/dist/modules/plugins/plugin-links.d.ts.map +1 -0
  142. package/dist/modules/plugins/plugin-links.js +160 -0
  143. package/dist/modules/plugins/plugin-links.js.map +1 -0
  144. package/dist/modules/plugins/plugin-links.service.d.ts +114 -0
  145. package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -0
  146. package/dist/modules/plugins/plugin-links.service.js +304 -0
  147. package/dist/modules/plugins/plugin-links.service.js.map +1 -0
  148. package/dist/modules/plugins/plugin-provision.service.d.ts +39 -3
  149. package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
  150. package/dist/modules/plugins/plugin-provision.service.js +152 -52
  151. package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
  152. package/dist/modules/plugins/plugin-rename.service.d.ts +69 -0
  153. package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -0
  154. package/dist/modules/plugins/plugin-rename.service.js +245 -0
  155. package/dist/modules/plugins/plugin-rename.service.js.map +1 -0
  156. package/dist/modules/plugins/plugins.contract.d.ts +27 -1
  157. package/dist/modules/plugins/plugins.contract.d.ts.map +1 -1
  158. package/dist/modules/plugins/plugins.routes.d.ts +7 -1
  159. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  160. package/dist/modules/plugins/plugins.routes.js +120 -12
  161. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  162. package/dist/modules/plugins/plugins.service.d.ts +50 -3
  163. package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
  164. package/dist/modules/plugins/plugins.service.js +108 -47
  165. package/dist/modules/plugins/plugins.service.js.map +1 -1
  166. package/dist/modules/settings/deployment-settings.service.d.ts +9 -0
  167. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  168. package/dist/modules/settings/deployment-settings.service.js +82 -2
  169. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  170. package/dist/modules/settings/setup.routes.d.ts +26 -0
  171. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  172. package/dist/modules/settings/setup.routes.js +9 -1
  173. package/dist/modules/settings/setup.routes.js.map +1 -1
  174. package/dist/modules/skills/index.d.ts +1 -0
  175. package/dist/modules/skills/index.d.ts.map +1 -1
  176. package/dist/modules/skills/index.js +1 -0
  177. package/dist/modules/skills/index.js.map +1 -1
  178. package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
  179. package/dist/modules/skills/pending-skills.service.js +9 -4
  180. package/dist/modules/skills/pending-skills.service.js.map +1 -1
  181. package/dist/modules/skills/skill-access-requests.routes.d.ts +38 -0
  182. package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -0
  183. package/dist/modules/skills/skill-access-requests.routes.js +168 -0
  184. package/dist/modules/skills/skill-access-requests.routes.js.map +1 -0
  185. package/dist/modules/skills/skills.contract.d.ts +31 -0
  186. package/dist/modules/skills/skills.contract.d.ts.map +1 -1
  187. package/dist/modules/skills/skills.routes.d.ts +28 -3
  188. package/dist/modules/skills/skills.routes.d.ts.map +1 -1
  189. package/dist/modules/skills/skills.routes.js +42 -3
  190. package/dist/modules/skills/skills.routes.js.map +1 -1
  191. package/dist/modules/skills/skills.service.d.ts +4 -0
  192. package/dist/modules/skills/skills.service.d.ts.map +1 -1
  193. package/dist/modules/skills/skills.service.js +83 -22
  194. package/dist/modules/skills/skills.service.js.map +1 -1
  195. package/dist/modules/tool-auth/external-api-key.interface.d.ts +18 -1
  196. package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
  197. package/dist/modules/tool-auth/external-api-key.interface.js +2 -1
  198. package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -1
  199. package/dist/modules/tool-auth/external-api-key.service.d.ts +13 -4
  200. package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
  201. package/dist/modules/tool-auth/external-api-key.service.js +26 -9
  202. package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
  203. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +36 -0
  204. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
  205. package/dist/modules/tool-manuals/mcp-json-discovery.js +130 -92
  206. package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
  207. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +6 -1
  208. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  209. package/dist/modules/tool-manuals/tool-manuals.service.js +18 -25
  210. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  211. package/dist/modules/workflow/git/git.service.d.ts +40 -2
  212. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  213. package/dist/modules/workflow/git/git.service.js +227 -54
  214. package/dist/modules/workflow/git/git.service.js.map +1 -1
  215. package/dist/modules/workflow/git/pull-request.service.d.ts +6 -0
  216. package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
  217. package/dist/modules/workflow/git/pull-request.service.js +8 -0
  218. package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
  219. package/dist/modules/workflow/workflow.service.d.ts +52 -1
  220. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  221. package/dist/modules/workflow/workflow.service.js +242 -9
  222. package/dist/modules/workflow/workflow.service.js.map +1 -1
  223. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +35 -0
  224. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -0
  225. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +121 -0
  226. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -0
  227. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  228. package/dist/modules/workspace/startup/steps/seed-tree.js +46 -2
  229. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  230. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
  231. package/dist/modules/workspace/startup/steps/template-files.step.js +112 -25
  232. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
  233. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  234. package/dist/modules/workspace/workspace.routes.js +9 -9
  235. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  236. package/dist/modules/workspace/workspace.service.d.ts +33 -0
  237. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  238. package/dist/modules/workspace/workspace.service.js +110 -16
  239. package/dist/modules/workspace/workspace.service.js.map +1 -1
  240. package/dist/shared/domain-errors.d.ts +20 -0
  241. package/dist/shared/domain-errors.d.ts.map +1 -1
  242. package/dist/shared/domain-errors.js +29 -0
  243. package/dist/shared/domain-errors.js.map +1 -1
  244. package/dist/shared/fs-errors.d.ts +8 -0
  245. package/dist/shared/fs-errors.d.ts.map +1 -0
  246. package/dist/shared/fs-errors.js +11 -0
  247. package/dist/shared/fs-errors.js.map +1 -0
  248. package/dist/shared/fs-walk.d.ts +20 -6
  249. package/dist/shared/fs-walk.d.ts.map +1 -1
  250. package/dist/shared/fs-walk.js +35 -27
  251. package/dist/shared/fs-walk.js.map +1 -1
  252. package/dist/shared/kb-walk.d.ts +52 -0
  253. package/dist/shared/kb-walk.d.ts.map +1 -0
  254. package/dist/shared/kb-walk.js +76 -0
  255. package/dist/shared/kb-walk.js.map +1 -0
  256. package/dist/shared/path-order.d.ts +18 -0
  257. package/dist/shared/path-order.d.ts.map +1 -0
  258. package/dist/shared/path-order.js +35 -0
  259. package/dist/shared/path-order.js.map +1 -0
  260. package/dist/shared/ttl-cache.d.ts +28 -1
  261. package/dist/shared/ttl-cache.d.ts.map +1 -1
  262. package/dist/shared/ttl-cache.js +33 -1
  263. package/dist/shared/ttl-cache.js.map +1 -1
  264. package/kb-template/.bevelignore +1 -1
  265. package/kb-template/AGENTS.md +95 -30
  266. package/kb-template/Skills/.gitkeep +0 -0
  267. package/migrations/0005_github_facade.sql +25 -0
  268. package/migrations/meta/0005_snapshot.json +1717 -0
  269. package/migrations/meta/_journal.json +7 -0
  270. package/package.json +6 -6
  271. package/src/__tests__/kb-layout-config.test.ts +110 -0
  272. package/src/core/__tests__/catalog-cache-invalidation.test.ts +146 -0
  273. package/src/core/catalog-cache-invalidation.ts +92 -0
  274. package/src/core/create-core-server.ts +123 -7
  275. package/src/core/create-core-services.ts +162 -41
  276. package/src/modules/access/__tests__/access-control.invalidate-race.test.ts +86 -0
  277. package/src/modules/access/__tests__/access-control.service.test.ts +19 -3
  278. package/src/modules/access/__tests__/access-plugin-principals.test.ts +368 -0
  279. package/src/modules/access/__tests__/groups-admin.service.test.ts +8 -0
  280. package/src/modules/access/access-control.interface.ts +20 -9
  281. package/src/modules/access/access-control.service.ts +240 -78
  282. package/src/modules/access/access.routes.ts +96 -14
  283. package/src/modules/access-model/__tests__/access-grammar.test.ts +18 -0
  284. package/src/modules/access-model/__tests__/plugin-token-canonical.test.ts +40 -0
  285. package/src/modules/access-model/access-grammar.ts +114 -2
  286. package/src/modules/access-model/group-files.ts +4 -0
  287. package/src/modules/access-model/plugin-principals.ts +137 -0
  288. package/src/modules/database/core-schema.ts +54 -0
  289. package/src/modules/kb-sync/__tests__/kb-sync.routes.test.ts +297 -0
  290. package/src/modules/kb-sync/__tests__/kb-sync.service.test.ts +295 -0
  291. package/src/modules/kb-sync/__tests__/sync-auth.test.ts +118 -0
  292. package/src/modules/kb-sync/__tests__/sync-payload.test.ts +148 -0
  293. package/src/modules/kb-sync/index.ts +19 -0
  294. package/src/modules/kb-sync/kb-sync.interface.ts +79 -0
  295. package/src/modules/kb-sync/kb-sync.routes.ts +197 -0
  296. package/src/modules/kb-sync/kb-sync.service.ts +201 -0
  297. package/src/modules/kb-sync/sync-auth.ts +118 -0
  298. package/src/modules/kb-sync/sync-payload.ts +143 -0
  299. package/src/modules/marketplace/__tests__/github-facade.test.ts +443 -0
  300. package/src/modules/marketplace/__tests__/marketplace-git.test.ts +179 -0
  301. package/src/modules/marketplace/git-http.routes.ts +193 -0
  302. package/src/modules/marketplace/github-facade/github-facade-admin.routes.ts +78 -0
  303. package/src/modules/marketplace/github-facade/github-facade-codes.store.ts +145 -0
  304. package/src/modules/marketplace/github-facade/github-facade-credentials.service.ts +208 -0
  305. package/src/modules/marketplace/github-facade/github-facade.routes.ts +268 -0
  306. package/src/modules/marketplace/github-facade/github-facade.service.ts +221 -0
  307. package/src/modules/marketplace/github-facade/index.ts +25 -0
  308. package/src/modules/marketplace/index.ts +3 -0
  309. package/src/modules/marketplace/marketplace-repo.service.ts +337 -0
  310. package/src/modules/mcp/oauth/bevel-oauth-provider.ts +3 -0
  311. package/src/modules/mcp/oauth/oauth-consent.routes.ts +24 -2
  312. package/src/modules/mcp/oauth/oauth-state.ts +15 -3
  313. package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +163 -0
  314. package/src/modules/plugins/__tests__/compile-marketplace.test.ts +294 -0
  315. package/src/modules/plugins/__tests__/plugin-index.service.test.ts +56 -12
  316. package/src/modules/plugins/__tests__/plugin-links.service.test.ts +287 -0
  317. package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +205 -5
  318. package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +394 -0
  319. package/src/modules/plugins/__tests__/plugins.routes.test.ts +80 -33
  320. package/src/modules/plugins/compile/compile-marketplace.ts +403 -0
  321. package/src/modules/plugins/compile/marketplace-compiler.service.ts +150 -0
  322. package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +329 -0
  323. package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +140 -0
  324. package/src/modules/plugins/discovery/bundle-dialect/registry.ts +175 -0
  325. package/src/modules/plugins/discovery/kb-plugin-source.ts +114 -0
  326. package/src/modules/plugins/discovery/native.source.ts +122 -0
  327. package/src/modules/plugins/discovery/plugin-source.ts +99 -0
  328. package/src/modules/plugins/index.ts +10 -0
  329. package/src/modules/plugins/plugin-links.service.ts +363 -0
  330. package/src/modules/plugins/plugin-links.ts +184 -0
  331. package/src/modules/plugins/plugin-provision.service.ts +160 -54
  332. package/src/modules/plugins/plugin-rename.service.ts +298 -0
  333. package/src/modules/plugins/plugins.contract.ts +28 -1
  334. package/src/modules/plugins/plugins.routes.ts +128 -11
  335. package/src/modules/plugins/plugins.service.ts +106 -53
  336. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +57 -0
  337. package/src/modules/settings/__tests__/setup.routes.sync-status.test.ts +77 -0
  338. package/src/modules/settings/deployment-settings.service.ts +95 -2
  339. package/src/modules/settings/setup.routes.ts +24 -0
  340. package/src/modules/skills/__tests__/skill-access-requests.routes.test.ts +128 -0
  341. package/src/modules/skills/__tests__/skills.service.test.ts +85 -0
  342. package/src/modules/skills/index.ts +1 -0
  343. package/src/modules/skills/pending-skills.service.ts +7 -5
  344. package/src/modules/skills/skill-access-requests.routes.ts +199 -0
  345. package/src/modules/skills/skills.contract.ts +32 -0
  346. package/src/modules/skills/skills.routes.ts +59 -3
  347. package/src/modules/skills/skills.service.ts +84 -22
  348. package/src/modules/tool-auth/external-api-key.interface.ts +20 -1
  349. package/src/modules/tool-auth/external-api-key.service.ts +31 -13
  350. package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +24 -1
  351. package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +2 -0
  352. package/src/modules/tool-manuals/mcp-json-discovery.ts +154 -88
  353. package/src/modules/tool-manuals/tool-manuals.service.ts +14 -23
  354. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +1 -1
  355. package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +1 -0
  356. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +2 -2
  357. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +119 -2
  358. package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +437 -0
  359. package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +3 -3
  360. package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +47 -4
  361. package/src/modules/workflow/git/__tests__/git.service.syncFromRemote.test.ts +253 -0
  362. package/src/modules/workflow/git/git.service.ts +239 -56
  363. package/src/modules/workflow/git/pull-request.service.ts +9 -0
  364. package/src/modules/workflow/workflow.service.ts +260 -9
  365. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +6 -7
  366. package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +93 -0
  367. package/src/modules/workspace/__tests__/workspace.service.missing-branch.test.ts +28 -0
  368. package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +42 -12
  369. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +219 -4
  370. package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +129 -0
  371. package/src/modules/workspace/startup/steps/seed-tree.ts +44 -2
  372. package/src/modules/workspace/startup/steps/template-files.step.ts +131 -27
  373. package/src/modules/workspace/workspace.routes.ts +9 -17
  374. package/src/modules/workspace/workspace.service.ts +107 -16
  375. package/src/shared/__tests__/filename.test.ts +0 -0
  376. package/src/shared/__tests__/fs-walk.test.ts +22 -1
  377. package/src/shared/__tests__/kb-walk.test.ts +107 -0
  378. package/src/shared/__tests__/path-order.test.ts +24 -0
  379. package/src/shared/__tests__/ttl-cache.test.ts +55 -0
  380. package/src/shared/domain-errors.ts +29 -0
  381. package/src/shared/fs-errors.ts +10 -0
  382. package/src/shared/fs-walk.ts +38 -23
  383. package/src/shared/kb-walk.ts +95 -0
  384. package/src/shared/path-order.ts +33 -0
  385. package/src/shared/ttl-cache.ts +33 -1
@@ -0,0 +1,96 @@
1
+ import type { KbWalkListener } from '../../../shared/kb-walk.js';
2
+ /**
3
+ * Plugin DISCOVERY as an interface — the one seam between "what a plugin is
4
+ * on disk" and everything that consumes plugins (the plugin index, the link
5
+ * index, the tool-manual scanner, the compiler).
6
+ *
7
+ * Two providers implement it:
8
+ *
9
+ * - `native.source.ts` — the Agent Plugins layout this platform writes:
10
+ * `Plugins/<Name>/plugin.json` (+ `mcp.json`,
11
+ * `access.md`, the hexis extension block).
12
+ * - `bundle-dialect/` — a customer's source layout: `plugin.bundle.json`
13
+ * files at any depth, pointing at skill roots and at
14
+ * an MCP profile in a registry. Read-only, and
15
+ * deletable as a unit once that customer migrates.
16
+ *
17
+ * Consumers see only {@link DiscoveredPlugin}: parsed objects, never files.
18
+ * A provider that reads a different file shape changes nothing downstream.
19
+ */
20
+ export interface DiscoveredPlugin {
21
+ /**
22
+ * The plugin's IDENTITY everywhere a URL, a grant or a marketplace names
23
+ * it: the manifest's `name` — an Agent Plugins identifier — or the folder
24
+ * name folded into one when the manifest declares none it can be. A bundle
25
+ * plugin's is the bundle's `name`. Unique per source.
26
+ */
27
+ name: string;
28
+ /** What a person sees it called: the manifest's `displayName`, else the folder name. */
29
+ displayName: string;
30
+ /** Repo-relative folder holding the plugin, e.g. `Plugins/GTM`. */
31
+ folder: string;
32
+ /** The same folder relative to the plugins root, e.g. `GTM` or `functional/x/y`. */
33
+ relFolder: string;
34
+ /** A personal folder (`Plugins/personal-<id>`): a place, not a plugin. */
35
+ personal: boolean;
36
+ /**
37
+ * Whether the plugin EXISTS by the index's rule. Native: its folder carries
38
+ * an `access.md` (a bare directory is a ghost git left behind). Dialect:
39
+ * always — the bundle file is the existence.
40
+ */
41
+ exists: boolean;
42
+ /** The Agent Plugins manifest, parsed (a dialect synthesises one). Null when absent or unparsable. */
43
+ manifest: Record<string, unknown> | null;
44
+ /** The manifest's raw text, for readers that want the extension block verbatim (native only). */
45
+ manifestText: string | null;
46
+ /** Repo-relative roots the plugin LINKS skills from — a skill folder or a folder of skills. */
47
+ linkedRoots: string[];
48
+ /** The `mcpServers` map of the plugin's `mcp.json`, parsed; null when it has none. */
49
+ mcpServers: Record<string, unknown> | null;
50
+ /** The raw `mcp.json` text, when it exists on disk (native only). */
51
+ mcpJsonText: string | null;
52
+ /**
53
+ * Whether hexis manages this plugin's links — writes them, grants the
54
+ * plugin's principal on the skill, reports a missing grant as needing
55
+ * repair. False for a dialect, whose links are plain references and whose
56
+ * skills' own scopes decide readability.
57
+ */
58
+ linksAreManaged: boolean;
59
+ }
60
+ export interface Discovery {
61
+ plugins: DiscoveredPlugin[];
62
+ /** What was skipped and why — unparsable files, unknown profiles. */
63
+ warnings: string[];
64
+ /**
65
+ * HOLES: identity-bearing things that exist but could NOT be read
66
+ * (permissions, I/O), repo-relative — a folder that could not be listed,
67
+ * a manifest or bundle that could not be opened. Nothing behind a hole is
68
+ * in `plugins`: not absent, unseen, and never listed under a guessed name.
69
+ * A file that carries no identity (an `mcp.json`) is never a hole; its
70
+ * failure is a warning. A reader that only shows what it can carries on
71
+ * (the catalog does); a WRITER that keys a change on the set of plugins
72
+ * (a rename claiming a name) must refuse while this is not empty, or it
73
+ * may take an identity it could not see.
74
+ */
75
+ unreadable: string[];
76
+ }
77
+ /** What one walk yields when discovery shares it: the plugins, and every hole the walk met anywhere. */
78
+ export interface PluginSourceWalk {
79
+ discovery: Discovery;
80
+ /** Every folder the walk could not list, repo-relative — under the plugins root or anywhere else. */
81
+ holes: string[];
82
+ }
83
+ export interface PluginSource {
84
+ /** A short name for logs and the settings screen. */
85
+ readonly dialect: string;
86
+ /** Enumerate the plugins in a KB checkout. Never throws: a broken tree yields warnings. */
87
+ discover(kbRoot: string): Promise<Discovery>;
88
+ /**
89
+ * Discover while driving other listeners from the SAME walk — a writer
90
+ * that needs plugins and grant files alike reads the tree once, and sees
91
+ * one set of holes. Optional: a source that cannot share its walk is
92
+ * discovered on its own and the caller walks separately.
93
+ */
94
+ walkWith?(kbRoot: string, listeners: readonly KbWalkListener[]): Promise<PluginSourceWalk>;
95
+ }
96
+ //# sourceMappingURL=plugin-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-source.d.ts","sourceRoot":"","sources":["../../../../src/modules/plugins/discovery/plugin-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,wFAAwF;IACxF,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,oFAAoF;IACpF,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB,sGAAsG;IACtG,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzC,iGAAiG;IACjG,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,+FAA+F;IAC/F,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,sFAAsF;IACtF,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC3C,qEAAqE;IACrE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;;;OAKG;IACH,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;;;;;OAUG;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,wGAAwG;AACxG,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,SAAS,CAAC;IACrB,qGAAqG;IACrG,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,cAAc,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC5F"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plugin-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-source.js","sourceRoot":"","sources":["../../../../src/modules/plugins/discovery/plugin-source.ts"],"names":[],"mappings":""}
@@ -1,7 +1,16 @@
1
1
  export { PluginIndexService, pluginsWorkspaceId } from './plugins.service.js';
2
2
  export { PluginProvisionService, PluginProvisionError, pluginAccessMd, personalAccessMd, } from './plugin-provision.service.js';
3
3
  export { JoinRequestsService, type JoinRequest } from './join-requests.service.js';
4
+ export { PluginLinkIndex, type LinkMembership, type PluginLinks } from './plugin-links.js';
5
+ export { PluginLinksService, PluginLinkError } from './plugin-links.service.js';
6
+ export { PluginRenameService, PluginRenameError, renamePluginPrincipalInText } from './plugin-rename.service.js';
7
+ export { compileMarketplace, type VirtualTree, type CompileInput, type MarketplaceOptions } from './compile/compile-marketplace.js';
8
+ export { MarketplaceCompilerService, type CompileAudience } from './compile/marketplace-compiler.service.js';
9
+ export type { PluginSource, PluginSourceWalk, DiscoveredPlugin, Discovery } from './discovery/plugin-source.js';
10
+ export { walkKb, type KbWalkListener, type KbWalkResult } from '../../shared/kb-walk.js';
11
+ export { KbPluginSource } from './discovery/kb-plugin-source.js';
12
+ export { DEFAULT_REGISTRY_PATH } from './discovery/bundle-dialect/bundle.source.js';
4
13
  export { pendingProposals, type JoinProposal } from './join-proposals.js';
5
14
  export { createPluginsRoutes } from './plugins.routes.js';
6
- export type { IPluginIndexService, PluginCatalogEntry, PluginSummary, ResolvedPrincipals, ResolvedReaders, } from './plugins.contract.js';
15
+ export type { IPluginIndexService, PluginCatalogEntry, PluginMembership, PluginSummary, ResolvedPrincipals, ResolvedReaders, } from './plugins.contract.js';
7
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/plugins/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,cAAc,EACd,gBAAgB,GACjB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,KAAK,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,eAAe,GAChB,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/plugins/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,cAAc,EACd,gBAAgB,GACjB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,KAAK,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,KAAK,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACjH,OAAO,EAAE,kBAAkB,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACpI,OAAO,EAAE,0BAA0B,EAAE,KAAK,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAC7G,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAChH,OAAO,EAAE,MAAM,EAAE,KAAK,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACzF,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EAAE,gBAAgB,EAAE,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,eAAe,GAChB,MAAM,uBAAuB,CAAC"}
@@ -1,6 +1,14 @@
1
1
  export { PluginIndexService, pluginsWorkspaceId } from './plugins.service.js';
2
2
  export { PluginProvisionService, PluginProvisionError, pluginAccessMd, personalAccessMd, } from './plugin-provision.service.js';
3
3
  export { JoinRequestsService } from './join-requests.service.js';
4
+ export { PluginLinkIndex } from './plugin-links.js';
5
+ export { PluginLinksService, PluginLinkError } from './plugin-links.service.js';
6
+ export { PluginRenameService, PluginRenameError, renamePluginPrincipalInText } from './plugin-rename.service.js';
7
+ export { compileMarketplace } from './compile/compile-marketplace.js';
8
+ export { MarketplaceCompilerService } from './compile/marketplace-compiler.service.js';
9
+ export { walkKb } from '../../shared/kb-walk.js';
10
+ export { KbPluginSource } from './discovery/kb-plugin-source.js';
11
+ export { DEFAULT_REGISTRY_PATH } from './discovery/bundle-dialect/bundle.source.js';
4
12
  export { pendingProposals } from './join-proposals.js';
5
13
  export { createPluginsRoutes } from './plugins.routes.js';
6
14
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/modules/plugins/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,cAAc,EACd,gBAAgB,GACjB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAoB,MAAM,4BAA4B,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAqB,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/modules/plugins/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,cAAc,EACd,gBAAgB,GACjB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAoB,MAAM,4BAA4B,CAAC;AACnF,OAAO,EAAE,eAAe,EAAyC,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACjH,OAAO,EAAE,kBAAkB,EAAgE,MAAM,kCAAkC,CAAC;AACpI,OAAO,EAAE,0BAA0B,EAAwB,MAAM,2CAA2C,CAAC;AAE7G,OAAO,EAAE,MAAM,EAA0C,MAAM,yBAAyB,CAAC;AACzF,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EAAE,gBAAgB,EAAqB,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,66 @@
1
+ import type { WorkspaceService } from '../workspace/workspace.service.js';
2
+ import type { IAccessControl } from '../access/access-control.interface.js';
3
+ import type { ISkillService } from '../skills/skills.contract.js';
4
+ import type { PluginMembership } from './plugins.contract.js';
5
+ import type { PluginSource } from './discovery/plugin-source.js';
6
+ /** One plugin's links, resolved against the released catalog. */
7
+ export interface PluginLinks {
8
+ /** The plugin's name — its identity to people and URLs. */
9
+ name: string;
10
+ /** Repo-relative plugin folder. */
11
+ folder: string;
12
+ /** The roots the manifest declares, normalised. */
13
+ roots: string[];
14
+ /** Skill folders the roots resolve to (released catalog only). */
15
+ linkedSkills: string[];
16
+ /** Roots that resolve to no released skill — a typo, or a skill not yet merged. */
17
+ unresolvedRoots: string[];
18
+ /** Whether hexis writes these links and checks their grants — see `DiscoveredPlugin`. */
19
+ linksAreManaged: boolean;
20
+ }
21
+ export interface LinkMembership {
22
+ /** skill path → every plugin that holds it, inline or by link. */
23
+ bySkill: Map<string, PluginMembership[]>;
24
+ /** plugin folder → its links. Every plugin folder appears, linked or not. */
25
+ byPlugin: Map<string, PluginLinks>;
26
+ }
27
+ /**
28
+ * The link index: which shared skills each plugin links, and — the other way
29
+ * round — which plugins each skill belongs to, whether by sitting inside the
30
+ * plugin folder or by being linked from its manifest.
31
+ *
32
+ * Plugins come from the configured {@link PluginSource} (native manifests, or
33
+ * a customer dialect); resolution runs against the RELEASED catalog
34
+ * (`skillService.listSkills()`, unfiltered), never the file system: the
35
+ * catalog already applies the leaf-folder rule, the `.bevelignore` layers
36
+ * and the global-name dedup, and a second walk here would be a second
37
+ * opinion about what a skill is.
38
+ *
39
+ * `granted` is the consistency check the amber dot renders: a linked skill
40
+ * whose own access rules DO grant the plugin's `plugin/<Name>/read`
41
+ * principal (directly or from a scope above it). The link service writes
42
+ * that grant with the link; only a hand edit takes it away.
43
+ *
44
+ * Cached briefly, dropped by `invalidate()` from the same file-change
45
+ * subscriber that drops the plugin index, so a link committed on the default
46
+ * branch shows within one round-trip.
47
+ */
48
+ export declare class PluginLinkIndex {
49
+ private readonly workspaceService;
50
+ private readonly skillService;
51
+ private readonly accessControl;
52
+ private readonly kbDirName;
53
+ private readonly source;
54
+ private readonly cache;
55
+ constructor(workspaceService: WorkspaceService, skillService: ISkillService, accessControl: IAccessControl, kbDirName: string, now?: () => number, source?: PluginSource);
56
+ invalidate(): void;
57
+ membership(): Promise<LinkMembership>;
58
+ /** Convenience: the memberships of one skill (empty when it is in no plugin). */
59
+ pluginsOf(skillPath: string): Promise<PluginMembership[]>;
60
+ private build;
61
+ /** Whether the skill folder's effective readers include the plugin's read principal. */
62
+ private isGranted;
63
+ }
64
+ /** The default-branch workspace id every link resolution runs against. */
65
+ export declare function linksWorkspaceId(): string;
66
+ //# sourceMappingURL=plugin-links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-links.d.ts","sourceRoot":"","sources":["../../../src/modules/plugins/plugin-links.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAGlE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAKjE,iEAAiE;AACjE,MAAM,WAAW,WAAW;IAC1B,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,kEAAkE;IAClE,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mFAAmF;IACnF,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,yFAAyF;IACzF,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACzC,6EAA6E;IAC7E,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACpC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,eAAe;IAIxB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IARzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;gBAG9B,gBAAgB,EAAE,gBAAgB,EAClC,YAAY,EAAE,aAAa,EAC3B,aAAa,EAAE,cAAc,EAC7B,SAAS,EAAE,MAAM,EAClC,GAAG,GAAE,MAAM,MAAiB,EACX,MAAM,GAAE,YAAmC;IAK9D,UAAU,IAAI,IAAI;IAIZ,UAAU,IAAI,OAAO,CAAC,cAAc,CAAC;IAgB3C,iFAAiF;IAC3E,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;YAMjD,KAAK;IAoEnB,wFAAwF;YAC1E,SAAS;CAUxB;AAED,0EAA0E;AAC1E,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC"}
@@ -0,0 +1,160 @@
1
+ import path from 'node:path';
2
+ import { DEFAULT_BRANCH, pluginManifestName, skillUnderRoot } from '@bevel-software/platform-shared';
3
+ import { workspaceIdForBranch } from '../../shared/workspace-id.js';
4
+ import { TtlCache } from '../../shared/ttl-cache.js';
5
+ import { canonicalRoleName, pluginPrincipalKey } from '../access-model/access-grammar.js';
6
+ import { KbPluginSource } from './discovery/kb-plugin-source.js';
7
+ const CACHE_TTL_MS = 60_000;
8
+ /**
9
+ * The link index: which shared skills each plugin links, and — the other way
10
+ * round — which plugins each skill belongs to, whether by sitting inside the
11
+ * plugin folder or by being linked from its manifest.
12
+ *
13
+ * Plugins come from the configured {@link PluginSource} (native manifests, or
14
+ * a customer dialect); resolution runs against the RELEASED catalog
15
+ * (`skillService.listSkills()`, unfiltered), never the file system: the
16
+ * catalog already applies the leaf-folder rule, the `.bevelignore` layers
17
+ * and the global-name dedup, and a second walk here would be a second
18
+ * opinion about what a skill is.
19
+ *
20
+ * `granted` is the consistency check the amber dot renders: a linked skill
21
+ * whose own access rules DO grant the plugin's `plugin/<Name>/read`
22
+ * principal (directly or from a scope above it). The link service writes
23
+ * that grant with the link; only a hand edit takes it away.
24
+ *
25
+ * Cached briefly, dropped by `invalidate()` from the same file-change
26
+ * subscriber that drops the plugin index, so a link committed on the default
27
+ * branch shows within one round-trip.
28
+ */
29
+ export class PluginLinkIndex {
30
+ workspaceService;
31
+ skillService;
32
+ accessControl;
33
+ kbDirName;
34
+ source;
35
+ cache;
36
+ constructor(workspaceService, skillService, accessControl, kbDirName, now = Date.now, source = new KbPluginSource()) {
37
+ this.workspaceService = workspaceService;
38
+ this.skillService = skillService;
39
+ this.accessControl = accessControl;
40
+ this.kbDirName = kbDirName;
41
+ this.source = source;
42
+ this.cache = new TtlCache(CACHE_TTL_MS, now);
43
+ }
44
+ invalidate() {
45
+ this.cache.invalidate();
46
+ }
47
+ async membership() {
48
+ const cached = this.cache.get();
49
+ if (cached)
50
+ return cached;
51
+ // Token first, like the other catalogs: an `invalidate()` landing while
52
+ // the build reads the pre-change tree must not be undone by storing that
53
+ // read afterwards.
54
+ const token = this.cache.begin();
55
+ const built = await this.build();
56
+ // A degraded read (no workspace yet) is served but not stored — the same
57
+ // reasoning as the plugin index: caching a failure hides every link for
58
+ // a full TTL after its cause is gone.
59
+ if (built === null)
60
+ return { bySkill: new Map(), byPlugin: new Map() };
61
+ this.cache.set(built, token);
62
+ return built;
63
+ }
64
+ /** Convenience: the memberships of one skill (empty when it is in no plugin). */
65
+ async pluginsOf(skillPath) {
66
+ return (await this.membership()).bySkill.get(skillPath) ?? [];
67
+ }
68
+ // --- internal --------------------------------------------------------------
69
+ async build() {
70
+ let wsId;
71
+ let kbRoot;
72
+ try {
73
+ wsId = (await this.workspaceService.getOrCreateForBranch(DEFAULT_BRANCH)).id;
74
+ kbRoot = path.join(await this.workspaceService.getWorkspacePath(wsId), this.kbDirName);
75
+ }
76
+ catch {
77
+ return null;
78
+ }
79
+ const skills = await this.skillService.listSkills(undefined);
80
+ const bySkill = new Map();
81
+ const byPlugin = new Map();
82
+ const add = (skillPath, m) => {
83
+ const list = bySkill.get(skillPath) ?? [];
84
+ if (!list.some((x) => x.name === m.name))
85
+ list.push(m);
86
+ bySkill.set(skillPath, list);
87
+ };
88
+ const discovered = await this.source.discover(kbRoot);
89
+ for (const w of discovered.warnings)
90
+ console.warn(`[plugins] ${w}`);
91
+ // Inline skills: the ones sitting INSIDE a plugin's folder, matched by
92
+ // folder prefix (a plugin may sit at any depth, so the second path
93
+ // segment says nothing). Personal folders are places, not plugins —
94
+ // their skills belong to nobody's plugin.
95
+ const ownerOf = (skillPath) => discovered.plugins.find((p) => !p.personal && p.exists && skillPath.startsWith(`${p.folder}/`));
96
+ for (const s of skills) {
97
+ const owner = ownerOf(s.path);
98
+ if (owner)
99
+ add(s.path, { name: owner.name, linked: false, granted: true });
100
+ }
101
+ for (const plugin of discovered.plugins) {
102
+ // Personal folders are places, not plugins; a manifest without the
103
+ // access.md that makes a plugin EXIST is a ghost the index and the
104
+ // compiler omit, so it must not be linkable or hold grants either.
105
+ if (plugin.personal || !plugin.exists)
106
+ continue;
107
+ const roots = plugin.linkedRoots;
108
+ const linkedSkills = [];
109
+ const unresolvedRoots = [];
110
+ for (const root of roots) {
111
+ const hits = skills.filter((s) => skillUnderRoot(s.path, root)).map((s) => s.path);
112
+ if (hits.length === 0)
113
+ unresolvedRoots.push(root);
114
+ for (const hit of hits)
115
+ if (!linkedSkills.includes(hit))
116
+ linkedSkills.push(hit);
117
+ }
118
+ byPlugin.set(plugin.name, {
119
+ name: plugin.name,
120
+ folder: plugin.folder,
121
+ roots,
122
+ linkedSkills,
123
+ unresolvedRoots,
124
+ linksAreManaged: plugin.linksAreManaged,
125
+ });
126
+ if (linkedSkills.length === 0)
127
+ continue;
128
+ const token = pluginPrincipalKey(pluginManifestName(plugin.name), 'read');
129
+ for (const skillPath of linkedSkills) {
130
+ // A skill that also sits INSIDE this plugin folder is inline, and its
131
+ // inline membership already stands.
132
+ if (skillPath.startsWith(`${plugin.folder}/`))
133
+ continue;
134
+ // An unmanaged (dialect) link is a plain reference: nothing to grant,
135
+ // nothing to repair — the skill's own scope decides who reads it.
136
+ const granted = plugin.linksAreManaged ? await this.isGranted(wsId, skillPath, token) : true;
137
+ add(skillPath, { name: plugin.name, linked: true, granted });
138
+ }
139
+ }
140
+ return { bySkill, byPlugin };
141
+ }
142
+ /** Whether the skill folder's effective readers include the plugin's read principal. */
143
+ async isGranted(wsId, skillPath, token) {
144
+ try {
145
+ const readers = await this.accessControl.eligibleReaders(wsId, skillPath);
146
+ if (!readers.restricted)
147
+ return true; // readable by everyone — the plugin's members included
148
+ // The resolver reports display names; compare through the one canonicaliser.
149
+ return (readers.principals ?? []).some((p) => p.kind === 'plugin' && canonicalRoleName(p.name) === token);
150
+ }
151
+ catch {
152
+ return false; // fail closed: an unreadable tree reports the link as needing repair
153
+ }
154
+ }
155
+ }
156
+ /** The default-branch workspace id every link resolution runs against. */
157
+ export function linksWorkspaceId() {
158
+ return workspaceIdForBranch(DEFAULT_BRANCH);
159
+ }
160
+ //# sourceMappingURL=plugin-links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-links.js","sourceRoot":"","sources":["../../../src/modules/plugins/plugin-links.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ import { type AuthUser } from '@bevel-software/platform-shared';
2
+ import type { WorkspaceService } from '../workspace/workspace.service.js';
3
+ import type { IAccessControl } from '../access/access-control.interface.js';
4
+ import type { ISkillService } from '../skills/skills.contract.js';
5
+ import type { ProvisionCommitDriver } from './plugin-provision.service.js';
6
+ import { type PluginLinkIndex } from './plugin-links.js';
7
+ /** A refusal the route passes through: message + HTTP status + a machine-readable kind. */
8
+ export declare class PluginLinkError extends Error {
9
+ readonly status: number;
10
+ readonly payload: Record<string, unknown>;
11
+ constructor(message: string, status: number, payload?: Record<string, unknown>);
12
+ }
13
+ /**
14
+ * Linking shared skills into plugins — the writer behind "add an existing
15
+ * skill to this plugin".
16
+ *
17
+ * A link is TWO edits that only make sense together:
18
+ *
19
+ * 1. the skill's root goes into the plugin manifest's
20
+ * `extensions["software.bevel.hexis"].skills` list (see
21
+ * `HEXIS_LINKED_SKILLS_KEY`), which is what the catalog, the plugin page
22
+ * and the compiled distribution read;
23
+ * 2. the skill folder's own `access.md` grants `read` to
24
+ * `plugin/<Name>/read` and `write` to `plugin/<Name>/write`, which is
25
+ * what lets the plugin's members actually read it — ownership decides,
26
+ * the plugin is a view (see `plugin-principals.ts`).
27
+ *
28
+ * Which is why linking needs write on BOTH sides: on the plugin folder (to
29
+ * edit its manifest) and on the skill's root (to edit its access rules). A
30
+ * manager who lacks the second gets a 409 the UI turns into "request write
31
+ * access", not a link that silently shares nothing.
32
+ *
33
+ * Unlinking removes the manifest entry, and revokes the two tokens only when
34
+ * the actor may edit the skill's rules — otherwise the grant stays, and the
35
+ * skill page says so, for a skill editor to remove.
36
+ *
37
+ * Repair re-grants the tokens for a link that exists but whose grant was
38
+ * hand-removed: the amber dot's one action.
39
+ *
40
+ * Every operation is serialised on BOTH sides it writes — the plugin's
41
+ * manifest slug (the same key provisioning locks on) and the skill root whose
42
+ * access.md carries the grant — and lands as ordinary default-branch commits
43
+ * through the pending-commit driver, so the write gate and the per-user push
44
+ * gate apply exactly as they do to any edit.
45
+ */
46
+ export declare class PluginLinksService {
47
+ private readonly workspaceService;
48
+ private readonly commits;
49
+ private readonly accessControl;
50
+ private readonly skillService;
51
+ private readonly links;
52
+ private readonly kbDirName;
53
+ private readonly events?;
54
+ private readonly onChanged?;
55
+ private readonly locks;
56
+ private readonly mutation;
57
+ constructor(workspaceService: WorkspaceService, commits: ProvisionCommitDriver, accessControl: IAccessControl, skillService: ISkillService, links: PluginLinkIndex, kbDirName: string, events?: {
58
+ emit(event: {
59
+ kind: "fs-tree-changed";
60
+ workspaceId: string;
61
+ branch: string;
62
+ }): void;
63
+ } | undefined, onChanged?: (() => void) | undefined);
64
+ link(user: AuthUser, plugin: string, rawRoot: string): Promise<{
65
+ root: string;
66
+ skills: string[];
67
+ }>;
68
+ unlink(user: AuthUser, plugin: string, rawRoot: string): Promise<{
69
+ root: string;
70
+ revoked: boolean;
71
+ }>;
72
+ repair(user: AuthUser, plugin: string, rawRoot: string): Promise<{
73
+ root: string;
74
+ }>;
75
+ /**
76
+ * ONE reservation for both sides of a link: the plugin's manifest AND the
77
+ * skill root's access.md. Two plugins linking the same root write the same
78
+ * file, and serialising on the plugin alone let them interleave, one splice
79
+ * overwriting the other's grant. `runAll` takes both keys atomically, so
80
+ * nothing nests and no ordering discipline is needed.
81
+ */
82
+ private lockKeys;
83
+ /**
84
+ * The two grants a link carries: members read, managers write — written as
85
+ * the CANONICAL keys (slugged name), the spelling every comparison uses, so
86
+ * a repeated link finds its grant and an unlink finds what to revoke
87
+ * whatever the folder is called.
88
+ */
89
+ private tokens;
90
+ private grantTokens;
91
+ private rootOrThrow;
92
+ /**
93
+ * Released skills under the root — the catalog's answer, not the file
94
+ * system's. A RETIRED skill is kept for its owners and never shared onward:
95
+ * the grant lands on the ROOT folder, so a root that holds a retired skill
96
+ * anywhere beneath it cannot be linked at all — the grant would reach the
97
+ * retired one too. The refusal names them so the manager can link the
98
+ * active skills individually instead.
99
+ */
100
+ private resolvedSkills;
101
+ /**
102
+ * The exact on-disk plugin folder for `name`, or 404. Personal folders are
103
+ * not plugins, but that is the MEMBERSHIP's verdict (discovery marks the
104
+ * `personal-*` prefix personal only directly under the root), not a rule
105
+ * on the name — a nested plugin may be called anything.
106
+ */
107
+ private pluginFolder;
108
+ /** The repo-relative folder of a known plugin (any depth). */
109
+ private folderOf;
110
+ private requirePluginWrite;
111
+ private readManifest;
112
+ private changed;
113
+ }
114
+ //# sourceMappingURL=plugin-links.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-links.service.d.ts","sourceRoot":"","sources":["../../../src/modules/plugins/plugin-links.service.ts"],"names":[],"mappings":"AAEA,OAAO,EASL,KAAK,QAAQ,EACd,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAK5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE3E,2FAA2F;AAC3F,qBAAa,eAAgB,SAAQ,KAAK;IAGtC,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAFzC,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;CAKjD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,qBAAa,kBAAkB;IAK3B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAGxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IAb7B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwB;gBAG9B,gBAAgB,EAAE,gBAAgB,EAClC,OAAO,EAAE,qBAAqB,EAC9B,aAAa,EAAE,cAAc,EAC7B,YAAY,EAAE,aAAa,EAC3B,KAAK,EAAE,eAAe,EACtB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE;QACxB,IAAI,CAAC,KAAK,EAAE;YAAE,IAAI,EAAE,iBAAiB,CAAC;YAAC,WAAW,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;KACrF,YAAA,EACgB,SAAS,CAAC,GAAE,MAAM,IAAI,aAAA;IAKnC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IA+ClG,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAgDpG,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IA4BxF;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ;IAIhB;;;;;OAKG;IACH,OAAO,CAAC,MAAM;YAQA,WAAW;IASzB,OAAO,CAAC,WAAW;IAQnB;;;;;;;OAOG;YACW,cAAc;IAa5B;;;;;OAKG;YACW,YAAY;IAqB1B,8DAA8D;YAChD,QAAQ;YAMR,kBAAkB;YAOlB,YAAY;IA0C1B,OAAO,CAAC,OAAO;CAMhB"}