@bevel-software/platform-core-backend 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (720) hide show
  1. package/LICENSE +202 -0
  2. package/dist/assets.d.ts +5 -0
  3. package/dist/assets.d.ts.map +1 -0
  4. package/dist/assets.js +23 -0
  5. package/dist/assets.js.map +1 -0
  6. package/dist/core/core-ports.d.ts +83 -0
  7. package/dist/core/core-ports.d.ts.map +1 -0
  8. package/dist/core/core-ports.js +12 -0
  9. package/dist/core/core-ports.js.map +1 -0
  10. package/dist/core/create-core-server.d.ts +62 -0
  11. package/dist/core/create-core-server.d.ts.map +1 -0
  12. package/dist/core/create-core-server.js +204 -0
  13. package/dist/core/create-core-server.js.map +1 -0
  14. package/dist/core/create-core-services.d.ts +95 -0
  15. package/dist/core/create-core-services.d.ts.map +1 -0
  16. package/dist/core/create-core-services.js +352 -0
  17. package/dist/core/create-core-services.js.map +1 -0
  18. package/dist/core-config.d.ts +119 -0
  19. package/dist/core-config.d.ts.map +1 -0
  20. package/dist/core-config.js +240 -0
  21. package/dist/core-config.js.map +1 -0
  22. package/dist/index.d.ts +36 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +36 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/modules/access/access-control.interface.d.ts +348 -0
  27. package/dist/modules/access/access-control.interface.d.ts.map +1 -0
  28. package/dist/modules/access/access-control.interface.js +2 -0
  29. package/dist/modules/access/access-control.interface.js.map +1 -0
  30. package/dist/modules/access/access-control.service.d.ts +323 -0
  31. package/dist/modules/access/access-control.service.d.ts.map +1 -0
  32. package/dist/modules/access/access-control.service.js +1431 -0
  33. package/dist/modules/access/access-control.service.js.map +1 -0
  34. package/dist/modules/access/access-errors.d.ts +34 -0
  35. package/dist/modules/access/access-errors.d.ts.map +1 -0
  36. package/dist/modules/access/access-errors.js +40 -0
  37. package/dist/modules/access/access-errors.js.map +1 -0
  38. package/dist/modules/access/access-mutation.service.d.ts +176 -0
  39. package/dist/modules/access/access-mutation.service.d.ts.map +1 -0
  40. package/dist/modules/access/access-mutation.service.js +307 -0
  41. package/dist/modules/access/access-mutation.service.js.map +1 -0
  42. package/dist/modules/access/access-splice.d.ts +98 -0
  43. package/dist/modules/access/access-splice.d.ts.map +1 -0
  44. package/dist/modules/access/access-splice.js +346 -0
  45. package/dist/modules/access/access-splice.js.map +1 -0
  46. package/dist/modules/access/access.routes.d.ts +10 -0
  47. package/dist/modules/access/access.routes.d.ts.map +1 -0
  48. package/dist/modules/access/access.routes.js +757 -0
  49. package/dist/modules/access/access.routes.js.map +1 -0
  50. package/dist/modules/access/creator-access.d.ts +113 -0
  51. package/dist/modules/access/creator-access.d.ts.map +1 -0
  52. package/dist/modules/access/creator-access.js +212 -0
  53. package/dist/modules/access/creator-access.js.map +1 -0
  54. package/dist/modules/access/kb-read-filter.d.ts +41 -0
  55. package/dist/modules/access/kb-read-filter.d.ts.map +1 -0
  56. package/dist/modules/access/kb-read-filter.js +60 -0
  57. package/dist/modules/access/kb-read-filter.js.map +1 -0
  58. package/dist/modules/access/roles-admin.service.d.ts +240 -0
  59. package/dist/modules/access/roles-admin.service.d.ts.map +1 -0
  60. package/dist/modules/access/roles-admin.service.js +630 -0
  61. package/dist/modules/access/roles-admin.service.js.map +1 -0
  62. package/dist/modules/access/roles-edit.d.ts +91 -0
  63. package/dist/modules/access/roles-edit.d.ts.map +1 -0
  64. package/dist/modules/access/roles-edit.js +232 -0
  65. package/dist/modules/access/roles-edit.js.map +1 -0
  66. package/dist/modules/access/roles-yaml-guard.d.ts +56 -0
  67. package/dist/modules/access/roles-yaml-guard.d.ts.map +1 -0
  68. package/dist/modules/access/roles-yaml-guard.js +79 -0
  69. package/dist/modules/access/roles-yaml-guard.js.map +1 -0
  70. package/dist/modules/admin/admin-access.routes.d.ts +18 -0
  71. package/dist/modules/admin/admin-access.routes.d.ts.map +1 -0
  72. package/dist/modules/admin/admin-access.routes.js +26 -0
  73. package/dist/modules/admin/admin-access.routes.js.map +1 -0
  74. package/dist/modules/admin/admin-access.service.d.ts +24 -0
  75. package/dist/modules/admin/admin-access.service.d.ts.map +1 -0
  76. package/dist/modules/admin/admin-access.service.js +41 -0
  77. package/dist/modules/admin/admin-access.service.js.map +1 -0
  78. package/dist/modules/admin/admin.interface.d.ts +11 -0
  79. package/dist/modules/admin/admin.interface.d.ts.map +1 -0
  80. package/dist/modules/admin/admin.interface.js +2 -0
  81. package/dist/modules/admin/admin.interface.js.map +1 -0
  82. package/dist/modules/auth/account-erasure.service.d.ts +80 -0
  83. package/dist/modules/auth/account-erasure.service.d.ts.map +1 -0
  84. package/dist/modules/auth/account-erasure.service.js +91 -0
  85. package/dist/modules/auth/account-erasure.service.js.map +1 -0
  86. package/dist/modules/auth/auth.middleware.d.ts +23 -0
  87. package/dist/modules/auth/auth.middleware.d.ts.map +1 -0
  88. package/dist/modules/auth/auth.middleware.js +68 -0
  89. package/dist/modules/auth/auth.middleware.js.map +1 -0
  90. package/dist/modules/auth/auth.routes.d.ts +25 -0
  91. package/dist/modules/auth/auth.routes.d.ts.map +1 -0
  92. package/dist/modules/auth/auth.routes.js +72 -0
  93. package/dist/modules/auth/auth.routes.js.map +1 -0
  94. package/dist/modules/auth/auth.service.d.ts +76 -0
  95. package/dist/modules/auth/auth.service.d.ts.map +1 -0
  96. package/dist/modules/auth/auth.service.js +168 -0
  97. package/dist/modules/auth/auth.service.js.map +1 -0
  98. package/dist/modules/code-mode/code-mode-names.d.ts +16 -0
  99. package/dist/modules/code-mode/code-mode-names.d.ts.map +1 -0
  100. package/dist/modules/code-mode/code-mode-names.js +30 -0
  101. package/dist/modules/code-mode/code-mode-names.js.map +1 -0
  102. package/dist/modules/code-mode/code-mode.tool.d.ts +13 -0
  103. package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -0
  104. package/dist/modules/code-mode/code-mode.tool.js +112 -0
  105. package/dist/modules/code-mode/code-mode.tool.js.map +1 -0
  106. package/dist/modules/code-mode/index.d.ts +3 -0
  107. package/dist/modules/code-mode/index.d.ts.map +1 -0
  108. package/dist/modules/code-mode/index.js +3 -0
  109. package/dist/modules/code-mode/index.js.map +1 -0
  110. package/dist/modules/database/connection.d.ts +6 -0
  111. package/dist/modules/database/connection.d.ts.map +1 -0
  112. package/dist/modules/database/connection.js +12 -0
  113. package/dist/modules/database/connection.js.map +1 -0
  114. package/dist/modules/database/core-schema.d.ts +2273 -0
  115. package/dist/modules/database/core-schema.d.ts.map +1 -0
  116. package/dist/modules/database/core-schema.js +413 -0
  117. package/dist/modules/database/core-schema.js.map +1 -0
  118. package/dist/modules/database/migrate.d.ts +10 -0
  119. package/dist/modules/database/migrate.d.ts.map +1 -0
  120. package/dist/modules/database/migrate.js +40 -0
  121. package/dist/modules/database/migrate.js.map +1 -0
  122. package/dist/modules/database/schema.d.ts +12 -0
  123. package/dist/modules/database/schema.d.ts.map +1 -0
  124. package/dist/modules/database/schema.js +12 -0
  125. package/dist/modules/database/schema.js.map +1 -0
  126. package/dist/modules/diff/diff-paths.d.ts +2 -0
  127. package/dist/modules/diff/diff-paths.d.ts.map +1 -0
  128. package/dist/modules/diff/diff-paths.js +9 -0
  129. package/dist/modules/diff/diff-paths.js.map +1 -0
  130. package/dist/modules/diff/diff.config.d.ts +8 -0
  131. package/dist/modules/diff/diff.config.d.ts.map +1 -0
  132. package/dist/modules/diff/diff.config.js +13 -0
  133. package/dist/modules/diff/diff.config.js.map +1 -0
  134. package/dist/modules/diff/diff.interface.d.ts +73 -0
  135. package/dist/modules/diff/diff.interface.d.ts.map +1 -0
  136. package/dist/modules/diff/diff.interface.js +2 -0
  137. package/dist/modules/diff/diff.interface.js.map +1 -0
  138. package/dist/modules/diff/diff.routes.d.ts +35 -0
  139. package/dist/modules/diff/diff.routes.d.ts.map +1 -0
  140. package/dist/modules/diff/diff.routes.js +228 -0
  141. package/dist/modules/diff/diff.routes.js.map +1 -0
  142. package/dist/modules/diff/diff.service.d.ts +51 -0
  143. package/dist/modules/diff/diff.service.d.ts.map +1 -0
  144. package/dist/modules/diff/diff.service.js +489 -0
  145. package/dist/modules/diff/diff.service.js.map +1 -0
  146. package/dist/modules/diff/line-diff.d.ts +16 -0
  147. package/dist/modules/diff/line-diff.d.ts.map +1 -0
  148. package/dist/modules/diff/line-diff.js +67 -0
  149. package/dist/modules/diff/line-diff.js.map +1 -0
  150. package/dist/modules/mcp/mcp-auth.middleware.d.ts +27 -0
  151. package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -0
  152. package/dist/modules/mcp/mcp-auth.middleware.js +116 -0
  153. package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -0
  154. package/dist/modules/mcp/mcp-session-store.d.ts +74 -0
  155. package/dist/modules/mcp/mcp-session-store.d.ts.map +1 -0
  156. package/dist/modules/mcp/mcp-session-store.js +131 -0
  157. package/dist/modules/mcp/mcp-session-store.js.map +1 -0
  158. package/dist/modules/mcp/mcp.routes.d.ts +24 -0
  159. package/dist/modules/mcp/mcp.routes.d.ts.map +1 -0
  160. package/dist/modules/mcp/mcp.routes.js +229 -0
  161. package/dist/modules/mcp/mcp.routes.js.map +1 -0
  162. package/dist/modules/mcp/mcp.service.d.ts +198 -0
  163. package/dist/modules/mcp/mcp.service.d.ts.map +1 -0
  164. package/dist/modules/mcp/mcp.service.js +840 -0
  165. package/dist/modules/mcp/mcp.service.js.map +1 -0
  166. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +76 -0
  167. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -0
  168. package/dist/modules/mcp/oauth/bevel-oauth-provider.js +291 -0
  169. package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -0
  170. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts +18 -0
  171. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -0
  172. package/dist/modules/mcp/oauth/oauth-consent.routes.js +52 -0
  173. package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -0
  174. package/dist/modules/mcp/oauth/oauth-state.d.ts +32 -0
  175. package/dist/modules/mcp/oauth/oauth-state.d.ts.map +1 -0
  176. package/dist/modules/mcp/oauth/oauth-state.js +34 -0
  177. package/dist/modules/mcp/oauth/oauth-state.js.map +1 -0
  178. package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +92 -0
  179. package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -0
  180. package/dist/modules/secrets-vault/db-secrets-vault.service.js +728 -0
  181. package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -0
  182. package/dist/modules/secrets-vault/index.d.ts +7 -0
  183. package/dist/modules/secrets-vault/index.d.ts.map +1 -0
  184. package/dist/modules/secrets-vault/index.js +6 -0
  185. package/dist/modules/secrets-vault/index.js.map +1 -0
  186. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts +63 -0
  187. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts.map +1 -0
  188. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js +269 -0
  189. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js.map +1 -0
  190. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts +46 -0
  191. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -0
  192. package/dist/modules/secrets-vault/secrets-variable-loader.js +87 -0
  193. package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -0
  194. package/dist/modules/secrets-vault/secrets-vault.contract.d.ts +210 -0
  195. package/dist/modules/secrets-vault/secrets-vault.contract.d.ts.map +1 -0
  196. package/dist/modules/secrets-vault/secrets-vault.contract.js +90 -0
  197. package/dist/modules/secrets-vault/secrets-vault.contract.js.map +1 -0
  198. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +30 -0
  199. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -0
  200. package/dist/modules/secrets-vault/secrets-vault.routes.js +490 -0
  201. package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -0
  202. package/dist/modules/skills/index.d.ts +5 -0
  203. package/dist/modules/skills/index.d.ts.map +1 -0
  204. package/dist/modules/skills/index.js +4 -0
  205. package/dist/modules/skills/index.js.map +1 -0
  206. package/dist/modules/skills/skills.contract.d.ts +58 -0
  207. package/dist/modules/skills/skills.contract.d.ts.map +1 -0
  208. package/dist/modules/skills/skills.contract.js +10 -0
  209. package/dist/modules/skills/skills.contract.js.map +1 -0
  210. package/dist/modules/skills/skills.routes.d.ts +15 -0
  211. package/dist/modules/skills/skills.routes.d.ts.map +1 -0
  212. package/dist/modules/skills/skills.routes.js +34 -0
  213. package/dist/modules/skills/skills.routes.js.map +1 -0
  214. package/dist/modules/skills/skills.service.d.ts +21 -0
  215. package/dist/modules/skills/skills.service.d.ts.map +1 -0
  216. package/dist/modules/skills/skills.service.js +202 -0
  217. package/dist/modules/skills/skills.service.js.map +1 -0
  218. package/dist/modules/skills/skills.tools.d.ts +15 -0
  219. package/dist/modules/skills/skills.tools.d.ts.map +1 -0
  220. package/dist/modules/skills/skills.tools.js +96 -0
  221. package/dist/modules/skills/skills.tools.js.map +1 -0
  222. package/dist/modules/tool-auth/external-api-key.errors.d.ts +14 -0
  223. package/dist/modules/tool-auth/external-api-key.errors.d.ts.map +1 -0
  224. package/dist/modules/tool-auth/external-api-key.errors.js +23 -0
  225. package/dist/modules/tool-auth/external-api-key.errors.js.map +1 -0
  226. package/dist/modules/tool-auth/external-api-key.interface.d.ts +90 -0
  227. package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -0
  228. package/dist/modules/tool-auth/external-api-key.interface.js +2 -0
  229. package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -0
  230. package/dist/modules/tool-auth/external-api-key.service.d.ts +25 -0
  231. package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -0
  232. package/dist/modules/tool-auth/external-api-key.service.js +164 -0
  233. package/dist/modules/tool-auth/external-api-key.service.js.map +1 -0
  234. package/dist/modules/tool-auth/internal-token.service.d.ts +62 -0
  235. package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -0
  236. package/dist/modules/tool-auth/internal-token.service.js +85 -0
  237. package/dist/modules/tool-auth/internal-token.service.js.map +1 -0
  238. package/dist/modules/tool-auth/llm-usage-meter.d.ts +16 -0
  239. package/dist/modules/tool-auth/llm-usage-meter.d.ts.map +1 -0
  240. package/dist/modules/tool-auth/llm-usage-meter.js +6 -0
  241. package/dist/modules/tool-auth/llm-usage-meter.js.map +1 -0
  242. package/dist/modules/tool-auth/tool-auth.middleware.d.ts +101 -0
  243. package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -0
  244. package/dist/modules/tool-auth/tool-auth.middleware.js +166 -0
  245. package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -0
  246. package/dist/modules/tool-helpers/index.d.ts +19 -0
  247. package/dist/modules/tool-helpers/index.d.ts.map +1 -0
  248. package/dist/modules/tool-helpers/index.js +18 -0
  249. package/dist/modules/tool-helpers/index.js.map +1 -0
  250. package/dist/modules/tool-helpers/tool-context.d.ts +35 -0
  251. package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -0
  252. package/dist/modules/tool-helpers/tool-context.js +66 -0
  253. package/dist/modules/tool-helpers/tool-context.js.map +1 -0
  254. package/dist/modules/tool-helpers/tool-def.d.ts +33 -0
  255. package/dist/modules/tool-helpers/tool-def.d.ts.map +1 -0
  256. package/dist/modules/tool-helpers/tool-def.js +57 -0
  257. package/dist/modules/tool-helpers/tool-def.js.map +1 -0
  258. package/dist/modules/tool-helpers/tool-handler.d.ts +19 -0
  259. package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -0
  260. package/dist/modules/tool-helpers/tool-handler.js +84 -0
  261. package/dist/modules/tool-helpers/tool-handler.js.map +1 -0
  262. package/dist/modules/tool-helpers/tool.contract.d.ts +64 -0
  263. package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -0
  264. package/dist/modules/tool-helpers/tool.contract.js +24 -0
  265. package/dist/modules/tool-helpers/tool.contract.js.map +1 -0
  266. package/dist/modules/tool-helpers/validate-token.d.ts +31 -0
  267. package/dist/modules/tool-helpers/validate-token.d.ts.map +1 -0
  268. package/dist/modules/tool-helpers/validate-token.js +20 -0
  269. package/dist/modules/tool-helpers/validate-token.js.map +1 -0
  270. package/dist/modules/tool-manuals/index.d.ts +5 -0
  271. package/dist/modules/tool-manuals/index.d.ts.map +1 -0
  272. package/dist/modules/tool-manuals/index.js +5 -0
  273. package/dist/modules/tool-manuals/index.js.map +1 -0
  274. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +182 -0
  275. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -0
  276. package/dist/modules/tool-manuals/tool-manuals.contract.js +19 -0
  277. package/dist/modules/tool-manuals/tool-manuals.contract.js.map +1 -0
  278. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +24 -0
  279. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -0
  280. package/dist/modules/tool-manuals/tool-manuals.routes.js +102 -0
  281. package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -0
  282. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +108 -0
  283. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -0
  284. package/dist/modules/tool-manuals/tool-manuals.service.js +710 -0
  285. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -0
  286. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +35 -0
  287. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -0
  288. package/dist/modules/tool-manuals/tool-manuals.tools.js +157 -0
  289. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -0
  290. package/dist/modules/tool-registry/manual.routes.d.ts +6 -0
  291. package/dist/modules/tool-registry/manual.routes.d.ts.map +1 -0
  292. package/dist/modules/tool-registry/manual.routes.js +76 -0
  293. package/dist/modules/tool-registry/manual.routes.js.map +1 -0
  294. package/dist/modules/tool-registry/tool-registry.d.ts +23 -0
  295. package/dist/modules/tool-registry/tool-registry.d.ts.map +1 -0
  296. package/dist/modules/tool-registry/tool-registry.js +46 -0
  297. package/dist/modules/tool-registry/tool-registry.js.map +1 -0
  298. package/dist/modules/tool-registry/tool.contract.d.ts +48 -0
  299. package/dist/modules/tool-registry/tool.contract.d.ts.map +1 -0
  300. package/dist/modules/tool-registry/tool.contract.js +2 -0
  301. package/dist/modules/tool-registry/tool.contract.js.map +1 -0
  302. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +14 -0
  303. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -0
  304. package/dist/modules/workflow/agent-tools/workflow.tools.js +437 -0
  305. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -0
  306. package/dist/modules/workflow/event-bus.d.ts +107 -0
  307. package/dist/modules/workflow/event-bus.d.ts.map +1 -0
  308. package/dist/modules/workflow/event-bus.js +224 -0
  309. package/dist/modules/workflow/event-bus.js.map +1 -0
  310. package/dist/modules/workflow/events.routes.d.ts +80 -0
  311. package/dist/modules/workflow/events.routes.d.ts.map +1 -0
  312. package/dist/modules/workflow/events.routes.js +216 -0
  313. package/dist/modules/workflow/events.routes.js.map +1 -0
  314. package/dist/modules/workflow/file-change-notifier.d.ts +38 -0
  315. package/dist/modules/workflow/file-change-notifier.d.ts.map +1 -0
  316. package/dist/modules/workflow/file-change-notifier.js +22 -0
  317. package/dist/modules/workflow/file-change-notifier.js.map +1 -0
  318. package/dist/modules/workflow/file-lock.service.d.ts +57 -0
  319. package/dist/modules/workflow/file-lock.service.d.ts.map +1 -0
  320. package/dist/modules/workflow/file-lock.service.js +202 -0
  321. package/dist/modules/workflow/file-lock.service.js.map +1 -0
  322. package/dist/modules/workflow/git/branch-name.d.ts +10 -0
  323. package/dist/modules/workflow/git/branch-name.d.ts.map +1 -0
  324. package/dist/modules/workflow/git/branch-name.js +76 -0
  325. package/dist/modules/workflow/git/branch-name.js.map +1 -0
  326. package/dist/modules/workflow/git/clone-config.d.ts +61 -0
  327. package/dist/modules/workflow/git/clone-config.d.ts.map +1 -0
  328. package/dist/modules/workflow/git/clone-config.js +69 -0
  329. package/dist/modules/workflow/git/clone-config.js.map +1 -0
  330. package/dist/modules/workflow/git/git-version.d.ts +34 -0
  331. package/dist/modules/workflow/git/git-version.d.ts.map +1 -0
  332. package/dist/modules/workflow/git/git-version.js +63 -0
  333. package/dist/modules/workflow/git/git-version.js.map +1 -0
  334. package/dist/modules/workflow/git/git.service.d.ts +427 -0
  335. package/dist/modules/workflow/git/git.service.d.ts.map +1 -0
  336. package/dist/modules/workflow/git/git.service.js +1987 -0
  337. package/dist/modules/workflow/git/git.service.js.map +1 -0
  338. package/dist/modules/workflow/git/mutex.d.ts +11 -0
  339. package/dist/modules/workflow/git/mutex.d.ts.map +1 -0
  340. package/dist/modules/workflow/git/mutex.js +23 -0
  341. package/dist/modules/workflow/git/mutex.js.map +1 -0
  342. package/dist/modules/workflow/git/pull-request.service.d.ts +124 -0
  343. package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -0
  344. package/dist/modules/workflow/git/pull-request.service.js +328 -0
  345. package/dist/modules/workflow/git/pull-request.service.js.map +1 -0
  346. package/dist/modules/workflow/locking-filesystem.d.ts +133 -0
  347. package/dist/modules/workflow/locking-filesystem.d.ts.map +1 -0
  348. package/dist/modules/workflow/locking-filesystem.js +400 -0
  349. package/dist/modules/workflow/locking-filesystem.js.map +1 -0
  350. package/dist/modules/workflow/pending-commits.service.d.ts +221 -0
  351. package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -0
  352. package/dist/modules/workflow/pending-commits.service.js +364 -0
  353. package/dist/modules/workflow/pending-commits.service.js.map +1 -0
  354. package/dist/modules/workflow/pending-commits.worker.d.ts +148 -0
  355. package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -0
  356. package/dist/modules/workflow/pending-commits.worker.js +245 -0
  357. package/dist/modules/workflow/pending-commits.worker.js.map +1 -0
  358. package/dist/modules/workflow/read-only-filesystem.d.ts +24 -0
  359. package/dist/modules/workflow/read-only-filesystem.d.ts.map +1 -0
  360. package/dist/modules/workflow/read-only-filesystem.js +39 -0
  361. package/dist/modules/workflow/read-only-filesystem.js.map +1 -0
  362. package/dist/modules/workflow/recovery-bot.d.ts +31 -0
  363. package/dist/modules/workflow/recovery-bot.d.ts.map +1 -0
  364. package/dist/modules/workflow/recovery-bot.js +64 -0
  365. package/dist/modules/workflow/recovery-bot.js.map +1 -0
  366. package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts +137 -0
  367. package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts.map +1 -0
  368. package/dist/modules/workflow/review-workflow/review-workflow.interface.js +2 -0
  369. package/dist/modules/workflow/review-workflow/review-workflow.interface.js.map +1 -0
  370. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts +26 -0
  371. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -0
  372. package/dist/modules/workflow/review-workflow/review-workflow.service.js +636 -0
  373. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -0
  374. package/dist/modules/workflow/sanitize-error.d.ts +29 -0
  375. package/dist/modules/workflow/sanitize-error.d.ts.map +1 -0
  376. package/dist/modules/workflow/sanitize-error.js +60 -0
  377. package/dist/modules/workflow/sanitize-error.js.map +1 -0
  378. package/dist/modules/workflow/session-ontology.policy.d.ts +52 -0
  379. package/dist/modules/workflow/session-ontology.policy.d.ts.map +1 -0
  380. package/dist/modules/workflow/session-ontology.policy.js +62 -0
  381. package/dist/modules/workflow/session-ontology.policy.js.map +1 -0
  382. package/dist/modules/workflow/session-ontology.service.d.ts +100 -0
  383. package/dist/modules/workflow/session-ontology.service.d.ts.map +1 -0
  384. package/dist/modules/workflow/session-ontology.service.js +143 -0
  385. package/dist/modules/workflow/session-ontology.service.js.map +1 -0
  386. package/dist/modules/workflow/workflow-hooks.d.ts +87 -0
  387. package/dist/modules/workflow/workflow-hooks.d.ts.map +1 -0
  388. package/dist/modules/workflow/workflow-hooks.js +35 -0
  389. package/dist/modules/workflow/workflow-hooks.js.map +1 -0
  390. package/dist/modules/workflow/workflow.errors.d.ts +171 -0
  391. package/dist/modules/workflow/workflow.errors.d.ts.map +1 -0
  392. package/dist/modules/workflow/workflow.errors.js +260 -0
  393. package/dist/modules/workflow/workflow.errors.js.map +1 -0
  394. package/dist/modules/workflow/workflow.routes.d.ts +26 -0
  395. package/dist/modules/workflow/workflow.routes.d.ts.map +1 -0
  396. package/dist/modules/workflow/workflow.routes.js +804 -0
  397. package/dist/modules/workflow/workflow.routes.js.map +1 -0
  398. package/dist/modules/workflow/workflow.service.d.ts +385 -0
  399. package/dist/modules/workflow/workflow.service.d.ts.map +1 -0
  400. package/dist/modules/workflow/workflow.service.js +1155 -0
  401. package/dist/modules/workflow/workflow.service.js.map +1 -0
  402. package/dist/modules/workspace/bevel-ignore.d.ts +25 -0
  403. package/dist/modules/workspace/bevel-ignore.d.ts.map +1 -0
  404. package/dist/modules/workspace/bevel-ignore.js +57 -0
  405. package/dist/modules/workspace/bevel-ignore.js.map +1 -0
  406. package/dist/modules/workspace/kb-seed.interface.d.ts +36 -0
  407. package/dist/modules/workspace/kb-seed.interface.d.ts.map +1 -0
  408. package/dist/modules/workspace/kb-seed.interface.js +2 -0
  409. package/dist/modules/workspace/kb-seed.interface.js.map +1 -0
  410. package/dist/modules/workspace/kb-seed.service.d.ts +70 -0
  411. package/dist/modules/workspace/kb-seed.service.d.ts.map +1 -0
  412. package/dist/modules/workspace/kb-seed.service.js +325 -0
  413. package/dist/modules/workspace/kb-seed.service.js.map +1 -0
  414. package/dist/modules/workspace/routine-write-policy.d.ts +49 -0
  415. package/dist/modules/workspace/routine-write-policy.d.ts.map +1 -0
  416. package/dist/modules/workspace/routine-write-policy.js +46 -0
  417. package/dist/modules/workspace/routine-write-policy.js.map +1 -0
  418. package/dist/modules/workspace/session-ontology.gate.d.ts +112 -0
  419. package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -0
  420. package/dist/modules/workspace/session-ontology.gate.js +161 -0
  421. package/dist/modules/workspace/session-ontology.gate.js.map +1 -0
  422. package/dist/modules/workspace/session-sink.d.ts +25 -0
  423. package/dist/modules/workspace/session-sink.d.ts.map +1 -0
  424. package/dist/modules/workspace/session-sink.js +8 -0
  425. package/dist/modules/workspace/session-sink.js.map +1 -0
  426. package/dist/modules/workspace/spill-store.d.ts +24 -0
  427. package/dist/modules/workspace/spill-store.d.ts.map +1 -0
  428. package/dist/modules/workspace/spill-store.js +87 -0
  429. package/dist/modules/workspace/spill-store.js.map +1 -0
  430. package/dist/modules/workspace/workspace.routes.d.ts +25 -0
  431. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -0
  432. package/dist/modules/workspace/workspace.routes.js +1046 -0
  433. package/dist/modules/workspace/workspace.routes.js.map +1 -0
  434. package/dist/modules/workspace/workspace.service.d.ts +339 -0
  435. package/dist/modules/workspace/workspace.service.d.ts.map +1 -0
  436. package/dist/modules/workspace/workspace.service.js +1221 -0
  437. package/dist/modules/workspace/workspace.service.js.map +1 -0
  438. package/dist/modules/workspace/workspace.tools.d.ts +19 -0
  439. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -0
  440. package/dist/modules/workspace/workspace.tools.js +767 -0
  441. package/dist/modules/workspace/workspace.tools.js.map +1 -0
  442. package/dist/shared/frontmatter-id.d.ts +35 -0
  443. package/dist/shared/frontmatter-id.d.ts.map +1 -0
  444. package/dist/shared/frontmatter-id.js +68 -0
  445. package/dist/shared/frontmatter-id.js.map +1 -0
  446. package/dist/shared/fs-walk.d.ts +9 -0
  447. package/dist/shared/fs-walk.d.ts.map +1 -0
  448. package/dist/shared/fs-walk.js +34 -0
  449. package/dist/shared/fs-walk.js.map +1 -0
  450. package/dist/shared/hash-email.d.ts +11 -0
  451. package/dist/shared/hash-email.d.ts.map +1 -0
  452. package/dist/shared/hash-email.js +14 -0
  453. package/dist/shared/hash-email.js.map +1 -0
  454. package/dist/shared/kb-layout.d.ts +38 -0
  455. package/dist/shared/kb-layout.d.ts.map +1 -0
  456. package/dist/shared/kb-layout.js +102 -0
  457. package/dist/shared/kb-layout.js.map +1 -0
  458. package/dist/shared/kb-layout.test.d.ts +2 -0
  459. package/dist/shared/kb-layout.test.d.ts.map +1 -0
  460. package/dist/shared/kb-layout.test.js +67 -0
  461. package/dist/shared/kb-layout.test.js.map +1 -0
  462. package/dist/shared/ssrf.d.ts +20 -0
  463. package/dist/shared/ssrf.d.ts.map +1 -0
  464. package/dist/shared/ssrf.js +89 -0
  465. package/dist/shared/ssrf.js.map +1 -0
  466. package/dist/shared/token-crypto.d.ts +16 -0
  467. package/dist/shared/token-crypto.d.ts.map +1 -0
  468. package/dist/shared/token-crypto.js +49 -0
  469. package/dist/shared/token-crypto.js.map +1 -0
  470. package/dist/shared/ttl-cache.d.ts +16 -0
  471. package/dist/shared/ttl-cache.d.ts.map +1 -0
  472. package/dist/shared/ttl-cache.js +27 -0
  473. package/dist/shared/ttl-cache.js.map +1 -0
  474. package/dist/shared/utcp-namespace.d.ts +46 -0
  475. package/dist/shared/utcp-namespace.d.ts.map +1 -0
  476. package/dist/shared/utcp-namespace.js +82 -0
  477. package/dist/shared/utcp-namespace.js.map +1 -0
  478. package/dist/version.d.ts +17 -0
  479. package/dist/version.d.ts.map +1 -0
  480. package/dist/version.js +19 -0
  481. package/dist/version.js.map +1 -0
  482. package/kb-template/.bevelignore +21 -0
  483. package/kb-template/Agents/.gitkeep +0 -0
  484. package/kb-template/Agents/README.md +38 -0
  485. package/kb-template/CLAUDE.md +419 -0
  486. package/kb-template/Data/.gitkeep +0 -0
  487. package/kb-template/Data/README.md +39 -0
  488. package/kb-template/KnowledgeBase/.gitkeep +0 -0
  489. package/kb-template/KnowledgeBase/README.md +37 -0
  490. package/kb-template/Pipelines/.gitkeep +0 -0
  491. package/kb-template/Pipelines/README.md +38 -0
  492. package/kb-template/Skills/.gitkeep +0 -0
  493. package/kb-template/Skills/README.md +32 -0
  494. package/kb-template/Tools/.gitkeep +0 -0
  495. package/kb-template/Tools/README.md +42 -0
  496. package/kb-template/access.md +36 -0
  497. package/migrations/0000_core_init.sql +243 -0
  498. package/migrations/meta/0000_snapshot.json +1480 -0
  499. package/migrations/meta/_journal.json +13 -0
  500. package/package.json +80 -0
  501. package/src/assets.ts +25 -0
  502. package/src/core/core-ports.ts +91 -0
  503. package/src/core/create-core-server.ts +338 -0
  504. package/src/core/create-core-services.ts +501 -0
  505. package/src/core-config.ts +257 -0
  506. package/src/index.ts +69 -0
  507. package/src/modules/access/__tests__/access-control.atref-batch.test.ts +98 -0
  508. package/src/modules/access/__tests__/access-control.read-batch.test.ts +132 -0
  509. package/src/modules/access/__tests__/access-control.service.test.ts +1011 -0
  510. package/src/modules/access/__tests__/access-mutation.service.test.ts +439 -0
  511. package/src/modules/access/__tests__/access-splice.test.ts +247 -0
  512. package/src/modules/access/__tests__/access.routes.revoke.test.ts +407 -0
  513. package/src/modules/access/__tests__/creator-access.test.ts +217 -0
  514. package/src/modules/access/__tests__/grant-sources.test.ts +204 -0
  515. package/src/modules/access/__tests__/kb-read-filter.test.ts +70 -0
  516. package/src/modules/access/__tests__/roles-admin.service.test.ts +469 -0
  517. package/src/modules/access/__tests__/roles-edit.test.ts +138 -0
  518. package/src/modules/access/__tests__/roles-yaml-guard.test.ts +70 -0
  519. package/src/modules/access/__tests__/roles.routes.test.ts +234 -0
  520. package/src/modules/access/access-control.interface.ts +383 -0
  521. package/src/modules/access/access-control.service.ts +1794 -0
  522. package/src/modules/access/access-errors.ts +60 -0
  523. package/src/modules/access/access-mutation.service.ts +369 -0
  524. package/src/modules/access/access-splice.ts +413 -0
  525. package/src/modules/access/access.routes.ts +894 -0
  526. package/src/modules/access/creator-access.ts +270 -0
  527. package/src/modules/access/kb-read-filter.ts +76 -0
  528. package/src/modules/access/roles-admin.service.ts +741 -0
  529. package/src/modules/access/roles-edit.ts +248 -0
  530. package/src/modules/access/roles-yaml-guard.ts +89 -0
  531. package/src/modules/admin/admin-access.routes.ts +29 -0
  532. package/src/modules/admin/admin-access.service.ts +38 -0
  533. package/src/modules/admin/admin.interface.ts +10 -0
  534. package/src/modules/auth/account-erasure.service.ts +183 -0
  535. package/src/modules/auth/auth.middleware.ts +78 -0
  536. package/src/modules/auth/auth.routes.ts +97 -0
  537. package/src/modules/auth/auth.service.ts +199 -0
  538. package/src/modules/code-mode/code-mode-names.ts +38 -0
  539. package/src/modules/code-mode/code-mode.tool.ts +117 -0
  540. package/src/modules/code-mode/index.ts +6 -0
  541. package/src/modules/database/connection.ts +15 -0
  542. package/src/modules/database/core-schema.ts +431 -0
  543. package/src/modules/database/migrate.ts +43 -0
  544. package/src/modules/database/schema.ts +11 -0
  545. package/src/modules/diff/__tests__/diff.routes.read-gate.test.ts +87 -0
  546. package/src/modules/diff/__tests__/diff.routes.rejectPathsLocked.test.ts +150 -0
  547. package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +184 -0
  548. package/src/modules/diff/__tests__/diff.service.test.ts +202 -0
  549. package/src/modules/diff/diff-paths.ts +9 -0
  550. package/src/modules/diff/diff.config.ts +12 -0
  551. package/src/modules/diff/diff.interface.ts +78 -0
  552. package/src/modules/diff/diff.routes.ts +277 -0
  553. package/src/modules/diff/diff.service.ts +508 -0
  554. package/src/modules/diff/line-diff.ts +79 -0
  555. package/src/modules/mcp/__tests__/bevel-oauth-provider.test.ts +287 -0
  556. package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +249 -0
  557. package/src/modules/mcp/__tests__/mcp-proxy-helpers.test.ts +253 -0
  558. package/src/modules/mcp/__tests__/mcp-session-store.test.ts +151 -0
  559. package/src/modules/mcp/__tests__/mcp.e2e.test.ts +150 -0
  560. package/src/modules/mcp/__tests__/mcp.routes.delete.test.ts +92 -0
  561. package/src/modules/mcp/__tests__/mcp.service.test.ts +414 -0
  562. package/src/modules/mcp/mcp-auth.middleware.ts +126 -0
  563. package/src/modules/mcp/mcp-session-store.ts +162 -0
  564. package/src/modules/mcp/mcp.routes.ts +263 -0
  565. package/src/modules/mcp/mcp.service.ts +973 -0
  566. package/src/modules/mcp/oauth/bevel-oauth-provider.ts +401 -0
  567. package/src/modules/mcp/oauth/oauth-consent.routes.ts +60 -0
  568. package/src/modules/mcp/oauth/oauth-state.ts +61 -0
  569. package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +277 -0
  570. package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +206 -0
  571. package/src/modules/secrets-vault/__tests__/mcp-oauth-discovery.service.test.ts +178 -0
  572. package/src/modules/secrets-vault/__tests__/scopes-covered.test.ts +101 -0
  573. package/src/modules/secrets-vault/__tests__/secrets-variable-loader.test.ts +54 -0
  574. package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +143 -0
  575. package/src/modules/secrets-vault/db-secrets-vault.service.ts +792 -0
  576. package/src/modules/secrets-vault/index.ts +25 -0
  577. package/src/modules/secrets-vault/mcp-oauth-discovery.service.ts +289 -0
  578. package/src/modules/secrets-vault/secrets-variable-loader.ts +104 -0
  579. package/src/modules/secrets-vault/secrets-vault.contract.ts +270 -0
  580. package/src/modules/secrets-vault/secrets-vault.routes.ts +526 -0
  581. package/src/modules/skills/__tests__/skills.service.test.ts +176 -0
  582. package/src/modules/skills/index.ts +10 -0
  583. package/src/modules/skills/skills.contract.ts +54 -0
  584. package/src/modules/skills/skills.routes.ts +38 -0
  585. package/src/modules/skills/skills.service.ts +245 -0
  586. package/src/modules/skills/skills.tools.ts +121 -0
  587. package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +358 -0
  588. package/src/modules/tool-auth/__tests__/internal-token.service.test.ts +79 -0
  589. package/src/modules/tool-auth/__tests__/manual-auth.middleware.test.ts +88 -0
  590. package/src/modules/tool-auth/external-api-key.errors.ts +25 -0
  591. package/src/modules/tool-auth/external-api-key.interface.ts +99 -0
  592. package/src/modules/tool-auth/external-api-key.service.ts +209 -0
  593. package/src/modules/tool-auth/internal-token.service.ts +124 -0
  594. package/src/modules/tool-auth/llm-usage-meter.ts +19 -0
  595. package/src/modules/tool-auth/tool-auth.middleware.ts +220 -0
  596. package/src/modules/tool-helpers/__tests__/phase0-loopback-spike.test.ts +129 -0
  597. package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +95 -0
  598. package/src/modules/tool-helpers/__tests__/tools-surface.test.ts +146 -0
  599. package/src/modules/tool-helpers/__tests__/validate-token.test.ts +75 -0
  600. package/src/modules/tool-helpers/index.ts +18 -0
  601. package/src/modules/tool-helpers/tool-context.ts +98 -0
  602. package/src/modules/tool-helpers/tool-def.ts +73 -0
  603. package/src/modules/tool-helpers/tool-handler.ts +91 -0
  604. package/src/modules/tool-helpers/tool.contract.ts +85 -0
  605. package/src/modules/tool-helpers/validate-token.ts +50 -0
  606. package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +200 -0
  607. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +499 -0
  608. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +156 -0
  609. package/src/modules/tool-manuals/index.ts +12 -0
  610. package/src/modules/tool-manuals/tool-manuals.contract.ts +183 -0
  611. package/src/modules/tool-manuals/tool-manuals.routes.ts +110 -0
  612. package/src/modules/tool-manuals/tool-manuals.service.ts +781 -0
  613. package/src/modules/tool-manuals/tool-manuals.tools.ts +202 -0
  614. package/src/modules/tool-registry/__tests__/tool-registry.test.ts +64 -0
  615. package/src/modules/tool-registry/manual.routes.ts +87 -0
  616. package/src/modules/tool-registry/tool-registry.ts +55 -0
  617. package/src/modules/tool-registry/tool.contract.ts +52 -0
  618. package/src/modules/workflow/__tests__/event-bus.test.ts +322 -0
  619. package/src/modules/workflow/__tests__/file-change-notifier.test.ts +51 -0
  620. package/src/modules/workflow/__tests__/format-affected-owners.test.ts +67 -0
  621. package/src/modules/workflow/__tests__/locking-filesystem.test.ts +445 -0
  622. package/src/modules/workflow/__tests__/pending-commits.canonical.test.ts +36 -0
  623. package/src/modules/workflow/__tests__/pending-commits.worker.test.ts +243 -0
  624. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +308 -0
  625. package/src/modules/workflow/__tests__/sanitize-error.test.ts +67 -0
  626. package/src/modules/workflow/__tests__/session-ontology.policy.test.ts +62 -0
  627. package/src/modules/workflow/__tests__/session-ontology.service.test.ts +200 -0
  628. package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +232 -0
  629. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +380 -0
  630. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +340 -0
  631. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +192 -0
  632. package/src/modules/workflow/agent-tools/workflow.tools.ts +502 -0
  633. package/src/modules/workflow/event-bus.ts +262 -0
  634. package/src/modules/workflow/events.routes.ts +266 -0
  635. package/src/modules/workflow/file-change-notifier.ts +54 -0
  636. package/src/modules/workflow/file-lock.service.ts +269 -0
  637. package/src/modules/workflow/git/__tests__/branch-name.test.ts +86 -0
  638. package/src/modules/workflow/git/__tests__/branchAuthor.test.ts +80 -0
  639. package/src/modules/workflow/git/__tests__/clone-config.test.ts +15 -0
  640. package/src/modules/workflow/git/__tests__/git-test-helpers.ts +47 -0
  641. package/src/modules/workflow/git/__tests__/git-version.failure.test.ts +24 -0
  642. package/src/modules/workflow/git/__tests__/git-version.test.ts +49 -0
  643. package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +389 -0
  644. package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +124 -0
  645. package/src/modules/workflow/git/__tests__/git.service.commitChanges.test.ts +105 -0
  646. package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +211 -0
  647. package/src/modules/workflow/git/__tests__/git.service.createBranch.test.ts +154 -0
  648. package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +320 -0
  649. package/src/modules/workflow/git/__tests__/git.service.diffFileAtCommit.test.ts +202 -0
  650. package/src/modules/workflow/git/__tests__/git.service.diffFileBetweenBranches.test.ts +453 -0
  651. package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +198 -0
  652. package/src/modules/workflow/git/__tests__/git.service.listTrackedFiles.test.ts +125 -0
  653. package/src/modules/workflow/git/__tests__/git.service.logForFile.test.ts +219 -0
  654. package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +145 -0
  655. package/src/modules/workflow/git/__tests__/git.service.pendingChanges.test.ts +240 -0
  656. package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +272 -0
  657. package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +232 -0
  658. package/src/modules/workflow/git/__tests__/git.service.readFileAtRef.test.ts +101 -0
  659. package/src/modules/workflow/git/__tests__/git.service.status.test.ts +127 -0
  660. package/src/modules/workflow/git/__tests__/mutex.test.ts +78 -0
  661. package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +225 -0
  662. package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-cancel.test.ts +101 -0
  663. package/src/modules/workflow/git/branch-name.ts +70 -0
  664. package/src/modules/workflow/git/clone-config.ts +71 -0
  665. package/src/modules/workflow/git/git-version.ts +70 -0
  666. package/src/modules/workflow/git/git.service.ts +2248 -0
  667. package/src/modules/workflow/git/mutex.ts +22 -0
  668. package/src/modules/workflow/git/pull-request.service.ts +447 -0
  669. package/src/modules/workflow/locking-filesystem.ts +489 -0
  670. package/src/modules/workflow/pending-commits.service.ts +444 -0
  671. package/src/modules/workflow/pending-commits.worker.ts +361 -0
  672. package/src/modules/workflow/read-only-filesystem.ts +54 -0
  673. package/src/modules/workflow/recovery-bot.ts +73 -0
  674. package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +560 -0
  675. package/src/modules/workflow/review-workflow/__tests__/cancel-pr.test.ts +176 -0
  676. package/src/modules/workflow/review-workflow/__tests__/merge-gate.test.ts +258 -0
  677. package/src/modules/workflow/review-workflow/review-workflow.interface.ts +199 -0
  678. package/src/modules/workflow/review-workflow/review-workflow.service.ts +806 -0
  679. package/src/modules/workflow/sanitize-error.ts +62 -0
  680. package/src/modules/workflow/session-ontology.policy.ts +70 -0
  681. package/src/modules/workflow/session-ontology.service.ts +178 -0
  682. package/src/modules/workflow/workflow-hooks.ts +101 -0
  683. package/src/modules/workflow/workflow.errors.ts +285 -0
  684. package/src/modules/workflow/workflow.routes.ts +858 -0
  685. package/src/modules/workflow/workflow.service.ts +1555 -0
  686. package/src/modules/workspace/__tests__/kb-seed.service.test.ts +213 -0
  687. package/src/modules/workspace/__tests__/routine-write-policy.test.ts +68 -0
  688. package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +237 -0
  689. package/src/modules/workspace/__tests__/spill-store.test.ts +43 -0
  690. package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +233 -0
  691. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +176 -0
  692. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +303 -0
  693. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +276 -0
  694. package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +120 -0
  695. package/src/modules/workspace/__tests__/workspace.service.test.ts +565 -0
  696. package/src/modules/workspace/__tests__/workspace.tools.test.ts +504 -0
  697. package/src/modules/workspace/bevel-ignore.ts +62 -0
  698. package/src/modules/workspace/kb-seed.interface.ts +36 -0
  699. package/src/modules/workspace/kb-seed.service.ts +361 -0
  700. package/src/modules/workspace/routine-write-policy.ts +79 -0
  701. package/src/modules/workspace/session-ontology.gate.ts +189 -0
  702. package/src/modules/workspace/session-sink.ts +25 -0
  703. package/src/modules/workspace/spill-store.ts +87 -0
  704. package/src/modules/workspace/workspace.routes.ts +1114 -0
  705. package/src/modules/workspace/workspace.service.ts +1343 -0
  706. package/src/modules/workspace/workspace.tools.ts +885 -0
  707. package/src/shared/__tests__/frontmatter-id.test.ts +88 -0
  708. package/src/shared/__tests__/fs-walk.test.ts +42 -0
  709. package/src/shared/__tests__/ssrf.test.ts +53 -0
  710. package/src/shared/__tests__/utcp-namespace.test.ts +19 -0
  711. package/src/shared/frontmatter-id.ts +72 -0
  712. package/src/shared/fs-walk.ts +30 -0
  713. package/src/shared/hash-email.ts +14 -0
  714. package/src/shared/kb-layout.test.ts +88 -0
  715. package/src/shared/kb-layout.ts +101 -0
  716. package/src/shared/ssrf.ts +78 -0
  717. package/src/shared/token-crypto.ts +54 -0
  718. package/src/shared/ttl-cache.ts +27 -0
  719. package/src/shared/utcp-namespace.ts +88 -0
  720. package/src/version.ts +19 -0
@@ -0,0 +1,176 @@
1
+ import { describe, test, expect, beforeEach, afterEach } from 'vitest';
2
+ import { mkdtemp, rm, mkdir, writeFile } from 'node:fs/promises';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { DEFAULT_BRANCH } from '@bevel-software/platform-shared';
6
+ import { SkillService } from '../skills.service.js';
7
+ import { workspaceIdForBranch } from '../../workspace/workspace.service.js';
8
+ import type { WorkspaceService } from '../../workspace/workspace.service.js';
9
+ import type { IAccessControl } from '../../access/access-control.interface.js';
10
+ import { readFile as fsReadFile } from 'node:fs/promises';
11
+
12
+ const KB_DIR = 'knowledge-base';
13
+ const wsId = workspaceIdForBranch(DEFAULT_BRANCH);
14
+
15
+ const RFI_SKILL = `---
16
+ name: rfi
17
+ version: 1.4.0
18
+ description: |
19
+ Specialist RFI responder. Runs KB-only: every answer is
20
+ grounded in a real knowledge-graph node.
21
+ allowed-tools:
22
+ - Bash
23
+ - Read
24
+ ---
25
+
26
+ # /rfi: Specialist RFI Responder
27
+
28
+ You answer RFIs.
29
+ `;
30
+
31
+ describe('SkillService', () => {
32
+ let root: string;
33
+
34
+ // WorkspaceService stub: default-branch workspace lives at <root>/<wsId>, the
35
+ // KB clone at <root>/<wsId>/<KB_DIR>.
36
+ const workspaceService = {
37
+ getOrCreateForBranch: async () => ({ id: wsId }),
38
+ getWorkspacePath: async (id: string) => join(root, id),
39
+ readFile: async (id: string, rel: string) => fsReadFile(join(root, id, rel), 'utf-8'),
40
+ } as unknown as WorkspaceService;
41
+
42
+ const allowAll: IAccessControl = {
43
+ canRead: async () => true,
44
+ canReadBatch: async (_w: string, _e: string, paths: string[]) =>
45
+ new Map(paths.map((p) => [p, true])),
46
+ } as unknown as IAccessControl;
47
+
48
+ const svc = (access: IAccessControl = allowAll) =>
49
+ new SkillService(workspaceService, access, KB_DIR);
50
+
51
+ beforeEach(async () => {
52
+ root = await mkdtemp(join(tmpdir(), 'skills-'));
53
+ const skills = join(root, wsId, KB_DIR, 'Skills');
54
+ await mkdir(join(skills, 'rfi', 'scripts'), { recursive: true });
55
+ await writeFile(join(skills, 'rfi', 'SKILL.md'), RFI_SKILL);
56
+ await writeFile(join(skills, 'rfi', 'scripts', 'build_xlsx.py'), 'print("xlsx")\n');
57
+ // A folder with no SKILL.md is not a skill.
58
+ await mkdir(join(skills, 'not-a-skill'), { recursive: true });
59
+ await writeFile(join(skills, 'not-a-skill', 'README.md'), '# nope\n');
60
+ // A skill nested in a category subfolder (Skills/Development/coding-guidelines).
61
+ await mkdir(join(skills, 'Development', 'coding-guidelines'), { recursive: true });
62
+ await writeFile(
63
+ join(skills, 'Development', 'coding-guidelines', 'SKILL.md'),
64
+ '---\nname: coding-guidelines\ndescription: Coding guidelines.\n---\n\n# Guidelines\n',
65
+ );
66
+ await writeFile(join(skills, 'Development', 'access.md'), '---\nwrite:\n - Developer\n---\n');
67
+ });
68
+ afterEach(() => rm(root, { recursive: true, force: true }));
69
+
70
+ test('lists skills with a block-scalar description parsed correctly', async () => {
71
+ const skills = await svc().listSkills();
72
+ expect(skills).toHaveLength(2);
73
+ const rfi = skills.find((s) => s.name === 'rfi')!;
74
+ expect(rfi).toBeDefined();
75
+ expect(rfi.path).toBe('Skills/rfi');
76
+ expect(rfi.version).toBe('1.4.0');
77
+ expect(rfi.description).not.toBe('|');
78
+ expect(rfi.description).toContain('Specialist RFI responder');
79
+ expect(rfi.description).toContain('grounded in a real knowledge-graph node');
80
+ });
81
+
82
+ test('discovers a skill nested in a category subfolder', async () => {
83
+ const skills = await svc().listSkills();
84
+ const cg = skills.find((s) => s.name === 'coding-guidelines')!;
85
+ expect(cg).toBeDefined();
86
+ expect(cg.path).toBe('Skills/Development/coding-guidelines');
87
+ expect(cg.description).toBe('Coding guidelines.');
88
+
89
+ const res = await svc().getSkill('user@x.eu', 'coding-guidelines');
90
+ expect(res.ok).toBe(true);
91
+ if (res.ok && res.kind === 'skill') {
92
+ expect(res.skill.path).toBe('Skills/Development/coding-guidelines');
93
+ expect(res.skill.body).toContain('# Guidelines');
94
+ }
95
+ });
96
+
97
+ test('refuses a colliding id (no auto-suffix) — the shared dedup rule', async () => {
98
+ const skills = join(root, wsId, KB_DIR, 'Skills');
99
+ // Two skills resolve to the same id `dup` (no frontmatter id/name → folder name).
100
+ await mkdir(join(skills, 'Zeta', 'dup'), { recursive: true });
101
+ await writeFile(join(skills, 'Zeta', 'dup', 'SKILL.md'), '---\ndescription: zeta dup\n---\n\n# Z\n');
102
+ await mkdir(join(skills, 'Alpha', 'dup'), { recursive: true });
103
+ await writeFile(join(skills, 'Alpha', 'dup', 'SKILL.md'), '---\ndescription: alpha dup\n---\n\n# A\n');
104
+
105
+ const list = await svc().listSkills();
106
+ // Only the first (smallest path) survives; the duplicate is dropped, not suffixed.
107
+ expect(list.filter((s) => s.name === 'dup').map((s) => s.path)).toEqual(['Skills/Alpha/dup']);
108
+ expect(list.find((s) => s.name === 'dup2')).toBeUndefined();
109
+
110
+ const a = await svc().getSkill('user@x.eu', 'dup');
111
+ expect(a.ok && a.kind === 'skill' && a.skill.path).toBe('Skills/Alpha/dup');
112
+ });
113
+
114
+ test('frontmatter `id`/`name` overrides the folder name for identity', async () => {
115
+ const skills = join(root, wsId, KB_DIR, 'Skills');
116
+ await mkdir(join(skills, 'folderx'), { recursive: true });
117
+ await writeFile(join(skills, 'folderx', 'SKILL.md'), '---\nid: my_skill\ndescription: d\n---\n\n# X\n');
118
+ const list = await svc().listSkills();
119
+ expect(list.find((s) => s.name === 'my_skill')?.path).toBe('Skills/folderx');
120
+ });
121
+
122
+ test('getSkill returns body, folder path, files and allowed-tools', async () => {
123
+ const res = await svc().getSkill('user@x.eu', 'rfi');
124
+ expect(res.ok).toBe(true);
125
+ if (res.ok && res.kind === 'skill') {
126
+ expect(res.skill.path).toBe('Skills/rfi');
127
+ expect(res.skill.body).toContain('# /rfi: Specialist RFI Responder');
128
+ expect(res.skill.files).toEqual(['Skills/rfi/scripts/build_xlsx.py']);
129
+ expect(res.skill.allowedTools).toEqual(['Bash', 'Read']);
130
+ }
131
+ });
132
+
133
+ test('getSkill with a `file` returns that bundled file content', async () => {
134
+ const res = await svc().getSkill('user@x.eu', 'rfi', 'scripts/build_xlsx.py');
135
+ expect(res.ok).toBe(true);
136
+ if (res.ok && res.kind === 'file') {
137
+ expect(res.file.path).toBe('Skills/rfi/scripts/build_xlsx.py');
138
+ expect(res.file.content).toContain('print("xlsx")');
139
+ }
140
+ });
141
+
142
+ test('getSkill rejects an unknown skill and path-traversal file', async () => {
143
+ expect(await svc().getSkill('user@x.eu', 'nope')).toEqual({ ok: false, error: 'not_found' });
144
+ const trav = await svc().getSkill('user@x.eu', 'rfi', '../../etc/passwd');
145
+ expect(trav).toEqual({ ok: false, error: 'invalid_file' });
146
+ });
147
+
148
+ test('listSkills filters by canRead for a given user', async () => {
149
+ const denyRfi: IAccessControl = {
150
+ canRead: async () => false,
151
+ canReadBatch: async (_w: string, _e: string, paths: string[]) =>
152
+ new Map(paths.map((p) => [p, false])),
153
+ } as unknown as IAccessControl;
154
+ expect(await svc(denyRfi).listSkills('user@x.eu')).toHaveLength(0);
155
+ // No email → global set, unfiltered.
156
+ expect(await svc(denyRfi).listSkills()).toHaveLength(2);
157
+ });
158
+
159
+ test('listSkills fails CLOSED: a path the checker gave no verdict for is hidden', async () => {
160
+ // A checker that "skips" every path (returns an empty map) must hide
161
+ // everything — a missing answer is a denial, never an exposure.
162
+ const noVerdicts: IAccessControl = {
163
+ canRead: async () => false,
164
+ canReadBatch: async () => new Map<string, boolean>(),
165
+ } as unknown as IAccessControl;
166
+ expect(await svc(noVerdicts).listSkills('user@x.eu')).toHaveLength(0);
167
+ });
168
+
169
+ test('getSkill is forbidden when the user cannot read it', async () => {
170
+ const denyRfi = {
171
+ canRead: async () => false,
172
+ canReadBatch: async (_w: string, _e: string, paths: string[]) => new Map(paths.map((p) => [p, false])),
173
+ } as unknown as IAccessControl;
174
+ expect(await svc(denyRfi).getSkill('user@x.eu', 'rfi')).toEqual({ ok: false, error: 'forbidden' });
175
+ });
176
+ });
@@ -0,0 +1,10 @@
1
+ export { SkillService } from './skills.service.js';
2
+ export { registerSkillsTools } from './skills.tools.js';
3
+ export { createSkillsRoutes } from './skills.routes.js';
4
+ export type {
5
+ ISkillService,
6
+ Skill,
7
+ SkillSummary,
8
+ SkillFileContent,
9
+ GetSkillResult,
10
+ } from './skills.contract.js';
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Skills are reusable specialist instructions living under `Skills/<name>/SKILL.md`
3
+ * in the KB repo. Discovery/loading is pinned to the DEFAULT branch — the catalog
4
+ * is a single global, released set (a skill on a draft isn't discoverable until
5
+ * merged). Progressive disclosure: `listSkills` = name + description (level 1),
6
+ * `getSkill` = full body + bundled-file paths (level 2), `getSkill(file)` = a
7
+ * bundled file's content (level 3).
8
+ */
9
+
10
+ export interface SkillSummary {
11
+ /** Canonical id = the skill's folder name (e.g. `rfi`). */
12
+ name: string;
13
+ description: string;
14
+ version?: string;
15
+ /** Repo-root-relative skill folder, e.g. `Skills/rfi`. */
16
+ path: string;
17
+ }
18
+
19
+ export interface Skill extends SkillSummary {
20
+ /** The SKILL.md markdown body (instructions to follow). */
21
+ body: string;
22
+ /** Pre-approved tools from the `allowed-tools` frontmatter, if declared. */
23
+ allowedTools?: string[];
24
+ /** Repo-root-relative bundled file paths, e.g. `Skills/rfi/scripts/build_xlsx.py`. */
25
+ files: string[];
26
+ }
27
+
28
+ export interface SkillFileContent {
29
+ /** The skill name. */
30
+ name: string;
31
+ /** The bundled file, relative to the skill folder (e.g. `scripts/build_xlsx.py`). */
32
+ file: string;
33
+ /** Repo-root-relative path of the file. */
34
+ path: string;
35
+ content: string;
36
+ }
37
+
38
+ export type GetSkillResult =
39
+ | { ok: true; kind: 'skill'; skill: Skill }
40
+ | { ok: true; kind: 'file'; file: SkillFileContent }
41
+ | { ok: false; error: 'not_found' | 'forbidden' | 'invalid_file' };
42
+
43
+ export interface ISkillService {
44
+ /**
45
+ * The default-branch skill catalog. When `userEmail` is given, filtered to
46
+ * skills that user may read (`canRead`); omit it for the global set (used to
47
+ * compose the tool descriptions in the manual).
48
+ */
49
+ listSkills(userEmail?: string): Promise<SkillSummary[]>;
50
+ /** Load a skill's body (+ files), or a bundled file's content when `file` is given. */
51
+ getSkill(userEmail: string, name: string, file?: string): Promise<GetSkillResult>;
52
+ /** Drop the cached catalog (call after a merge to the default branch). */
53
+ invalidate(): void;
54
+ }
@@ -0,0 +1,38 @@
1
+ import express from 'express';
2
+ import '../auth/auth.middleware.js'; // Express Request.userId / userEmail augmentation
3
+ import type { ISkillService } from './skills.contract.js';
4
+
5
+ /**
6
+ * Browser-facing (JWT) skill routes for the `/`-command menu, mounted behind
7
+ * `authMiddleware`. Backed by the SAME `SkillService` as the agent tool surface,
8
+ * so discovery, default-branch pinning, and per-user `canRead` filtering live
9
+ * ONCE — the frontend never re-implements skill discovery or bypasses access.
10
+ *
11
+ * GET /api/skills → { skills: SkillSummary[] } (filtered to this user)
12
+ * GET /api/skills/:name → GetSkillResult (body + files)
13
+ * GET /api/skills/:name?file=… → GetSkillResult (a bundled file's content)
14
+ */
15
+ export function createSkillsRoutes(skillService: ISkillService): express.Router {
16
+ const router = express.Router();
17
+
18
+ router.get('/skills', async (req, res) => {
19
+ const email = req.userEmail;
20
+ if (!email) {
21
+ res.status(401).json({ error: 'Unauthenticated' });
22
+ return;
23
+ }
24
+ res.json({ skills: await skillService.listSkills(email) });
25
+ });
26
+
27
+ router.get('/skills/:name', async (req, res) => {
28
+ const email = req.userEmail;
29
+ if (!email) {
30
+ res.status(401).json({ error: 'Unauthenticated' });
31
+ return;
32
+ }
33
+ const file = typeof req.query.file === 'string' ? req.query.file : undefined;
34
+ res.json(await skillService.getSkill(email, req.params.name, file));
35
+ });
36
+
37
+ return router;
38
+ }
@@ -0,0 +1,245 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+ import { parseDocument } from 'yaml';
4
+ import { DEFAULT_BRANCH, SKILLS_DIR } from '@bevel-software/platform-shared';
5
+ import type { WorkspaceService } from '../workspace/workspace.service.js';
6
+ import { workspaceIdForBranch } from '../workspace/workspace.service.js';
7
+ import type { IAccessControl } from '../access/access-control.interface.js';
8
+ import { extractFrontmatter, resolveDeclaredId, dedupeById } from '../../shared/frontmatter-id.js';
9
+ import { walkFiles } from '../../shared/fs-walk.js';
10
+ import { TtlCache } from '../../shared/ttl-cache.js';
11
+ import type {
12
+ ISkillService,
13
+ GetSkillResult,
14
+ Skill,
15
+ SkillSummary,
16
+ } from './skills.contract.js';
17
+
18
+ const CACHE_TTL_MS = 60_000;
19
+
20
+ interface ParsedSkill {
21
+ summary: SkillSummary;
22
+ body: string;
23
+ allowedTools?: string[];
24
+ files: string[];
25
+ }
26
+
27
+ /**
28
+ * Reads skills from the DEFAULT-branch workspace (never the caller's branch), so
29
+ * the catalog is one global, released set. Results are cached briefly and on a
30
+ * merge to default the cache should be dropped via `invalidate()`.
31
+ */
32
+ export class SkillService implements ISkillService {
33
+ private readonly cache: TtlCache<ParsedSkill[]>;
34
+
35
+ constructor(
36
+ private readonly workspaceService: WorkspaceService,
37
+ private readonly accessControl: IAccessControl,
38
+ private readonly kbDirName: string,
39
+ now: () => number = Date.now,
40
+ ) {
41
+ this.cache = new TtlCache(CACHE_TTL_MS, now);
42
+ }
43
+
44
+ invalidate(): void {
45
+ this.cache.invalidate();
46
+ }
47
+
48
+ async listSkills(userEmail?: string): Promise<SkillSummary[]> {
49
+ const skills = await this.scan();
50
+ const summaries = skills.map((s) => s.summary);
51
+ if (!userEmail) return summaries;
52
+ const wsId = workspaceIdForBranch(DEFAULT_BRANCH);
53
+ const allowed = await this.accessControl.canReadBatch(
54
+ wsId,
55
+ userEmail,
56
+ summaries.map((s) => `${s.path}/SKILL.md`),
57
+ );
58
+ // Fail closed: keep a skill only on an explicit `true` verdict — a missing
59
+ // entry counts as denied, matching the KB's default-deny read model (and the
60
+ // tool-manuals catalog). `!== false` would silently EXPOSE a skill any time
61
+ // the checker skips a path.
62
+ return summaries.filter((s) => allowed.get(`${s.path}/SKILL.md`) === true);
63
+ }
64
+
65
+ async getSkill(userEmail: string, name: string, file?: string): Promise<GetSkillResult> {
66
+ if (!isSafeName(name)) return { ok: false, error: 'not_found' };
67
+ const found = (await this.scan()).find((s) => s.summary.name === name);
68
+ if (!found) return { ok: false, error: 'not_found' };
69
+
70
+ const wsId = workspaceIdForBranch(DEFAULT_BRANCH);
71
+ if (!(await this.accessControl.canRead(wsId, userEmail, `${found.summary.path}/SKILL.md`))) {
72
+ return { ok: false, error: 'forbidden' };
73
+ }
74
+
75
+ if (file !== undefined) {
76
+ if (!isSafeRelFile(file)) return { ok: false, error: 'invalid_file' };
77
+ const repoPath = `${found.summary.path}/${file}`;
78
+ try {
79
+ const content = await this.workspaceService.readFile(wsId, `${this.kbDirName}/${repoPath}`);
80
+ return { ok: true, kind: 'file', file: { name, file, path: repoPath, content } };
81
+ } catch {
82
+ return { ok: false, error: 'not_found' };
83
+ }
84
+ }
85
+
86
+ const skill: Skill = {
87
+ ...found.summary,
88
+ body: found.body,
89
+ allowedTools: found.allowedTools,
90
+ files: found.files,
91
+ };
92
+ return { ok: true, kind: 'skill', skill };
93
+ }
94
+
95
+ // --- internal ---------------------------------------------------------------
96
+
97
+ private async scan(): Promise<ParsedSkill[]> {
98
+ const cached = this.cache.get();
99
+ if (cached) return cached;
100
+ const skills = await this.scanDisk();
101
+ this.cache.set(skills);
102
+ return skills;
103
+ }
104
+
105
+ private async scanDisk(): Promise<ParsedSkill[]> {
106
+ // Ensure the default-branch clone exists, then scan its Skills/ dir. Any
107
+ // failure (no workspace, no Skills/ dir) degrades to an empty catalog — the
108
+ // manual/tools must never break because skills can't be read.
109
+ let wsId: string;
110
+ try {
111
+ wsId = (await this.workspaceService.getOrCreateForBranch(DEFAULT_BRANCH)).id;
112
+ } catch {
113
+ return [];
114
+ }
115
+ const root = path.join(
116
+ await this.workspaceService.getWorkspacePath(wsId),
117
+ this.kbDirName,
118
+ SKILLS_DIR,
119
+ );
120
+
121
+ // Skills may be grouped in category subfolders (each carrying its own
122
+ // access.md), so a SKILL.md can live at any depth under Skills/. Walk the
123
+ // tree and treat every folder that directly contains a SKILL.md as a skill;
124
+ // don't descend past it — its inner files are bundled assets, not nested
125
+ // skills. The skill name is the leaf folder name; its path is the full
126
+ // Skills-relative folder (e.g. `Skills/Development/coding-guidelines`).
127
+ const out: ParsedSkill[] = [];
128
+ const walk = async (dir: string, relFolder: string): Promise<void> => {
129
+ let entries: import('node:fs').Dirent[];
130
+ try {
131
+ entries = await fs.readdir(dir, { withFileTypes: true });
132
+ } catch {
133
+ return;
134
+ }
135
+ if (entries.some((e) => e.isFile() && e.name === 'SKILL.md')) {
136
+ let raw: string;
137
+ try {
138
+ raw = await fs.readFile(path.join(dir, 'SKILL.md'), 'utf-8');
139
+ } catch {
140
+ return;
141
+ }
142
+ const fm = parseSkillFrontmatter(raw);
143
+ // Identity via the shared rule: frontmatter `id` → `name` → folder name.
144
+ // `getSkill()` refuses unsafe names (path separators, `.`/`..`), so a
145
+ // declared id that fails the same check would list but never fetch —
146
+ // fall back to the folder name (a readdir entry, safe by construction)
147
+ // to keep listing and lookup consistent.
148
+ const declared = resolveDeclaredId(fm.frontmatter, path.basename(dir));
149
+ const name = isSafeName(declared) ? declared : path.basename(dir);
150
+ out.push({
151
+ summary: { name, description: fm.description, version: fm.version, path: relFolder },
152
+ body: fm.body,
153
+ allowedTools: fm.allowedTools,
154
+ files: await listBundledFiles(dir, relFolder),
155
+ });
156
+ return; // a skill folder is a leaf — its subfolders hold assets, not skills
157
+ }
158
+ for (const entry of entries) {
159
+ if (!entry.isDirectory() || entry.name.startsWith('.')) continue;
160
+ await walk(path.join(dir, entry.name), `${relFolder}/${entry.name}`);
161
+ }
162
+ };
163
+ await walk(root, SKILLS_DIR);
164
+ // A skill's id (frontmatter `id`/`name`, else folder name) is how getSkill()
165
+ // resolves it, so it must be unique. Sort by (name, path) for a deterministic
166
+ // winner, then REFUSE later duplicates via the shared dedup — the same rule
167
+ // tools use (no silent auto-suffix that would rebind an id under the caller).
168
+ out.sort(
169
+ (a, b) =>
170
+ a.summary.name.localeCompare(b.summary.name) ||
171
+ a.summary.path.localeCompare(b.summary.path),
172
+ );
173
+ return dedupeById(out, (s) => s.summary.name, (s, id) =>
174
+ console.warn(
175
+ `[skills] skipping "${s.summary.path}": id "${id}" is already used by another skill — ` +
176
+ 'give it a unique `id`/`name` in its SKILL.md frontmatter.',
177
+ ),
178
+ );
179
+ }
180
+ }
181
+
182
+ // --- helpers ------------------------------------------------------------------
183
+
184
+ /** Skill names are folder names; reject anything that could escape the folder. */
185
+ function isSafeName(name: string): boolean {
186
+ return name.length > 0 && !name.includes('/') && !name.includes('\\') && name !== '.' && name !== '..';
187
+ }
188
+
189
+ /** A bundled-file path must stay inside the skill folder. */
190
+ function isSafeRelFile(file: string): boolean {
191
+ if (!file || file.includes('\\') || path.isAbsolute(file)) return false;
192
+ return file.split('/').every((seg) => seg.length > 0 && seg !== '..');
193
+ }
194
+
195
+ function scalarToString(value: unknown): string | undefined {
196
+ if (typeof value === 'string') return value;
197
+ if (typeof value === 'number' || typeof value === 'boolean') return String(value);
198
+ return undefined;
199
+ }
200
+
201
+ function parseSkillFrontmatter(raw: string): {
202
+ description: string;
203
+ version?: string;
204
+ allowedTools?: string[];
205
+ body: string;
206
+ /** The parsed frontmatter object (for shared id resolution: `id`/`name`). */
207
+ frontmatter: Record<string, unknown>;
208
+ } {
209
+ const fm = extractFrontmatter(raw);
210
+ if (!fm) return { description: '', body: raw.trimStart(), frontmatter: {} };
211
+
212
+ const body = fm.body.trimStart();
213
+ let data: Record<string, unknown> = {};
214
+ try {
215
+ // Resilient: `toJS` returns the best-effort value even if some entry is
216
+ // malformed, so one bad field never drops the rest.
217
+ const parsed = parseDocument(fm.frontmatter).toJS();
218
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
219
+ data = parsed as Record<string, unknown>;
220
+ }
221
+ } catch {
222
+ /* keep empty metadata */
223
+ }
224
+
225
+ const description = typeof data.description === 'string' ? data.description.trim() : '';
226
+ const metadata = (data.metadata ?? {}) as Record<string, unknown>;
227
+ const version = scalarToString(data.version) ?? scalarToString(metadata.version);
228
+
229
+ // `allowed-tools` is a space-separated string (agentskills) or a YAML list.
230
+ const at = data['allowed-tools'];
231
+ const allowedTools = Array.isArray(at)
232
+ ? at.map((t) => String(t))
233
+ : typeof at === 'string'
234
+ ? at.split(/\s+/).filter(Boolean)
235
+ : undefined;
236
+
237
+ return { description, version, allowedTools, body, frontmatter: data };
238
+ }
239
+
240
+ /** Repo-root-relative paths of every bundled file under a skill folder (excludes SKILL.md). */
241
+ async function listBundledFiles(dir: string, relFolder: string): Promise<string[]> {
242
+ return (await walkFiles(dir, () => true))
243
+ .filter((rel) => rel !== 'SKILL.md')
244
+ .map((rel) => `${relFolder}/${rel}`);
245
+ }
@@ -0,0 +1,121 @@
1
+ import type { Router, RequestHandler } from 'express';
2
+ import type { IToolRegistry, UtcpTool } from '../tool-registry/tool.contract.js';
3
+ import type { ToolContext } from '../tool-helpers/tool.contract.js';
4
+ import { toolDef } from '../tool-helpers/tool-def.js';
5
+ import type { ToolHandlerFactory } from '../tool-helpers/tool-handler.js';
6
+ import type { ISkillService } from './skills.contract.js';
7
+
8
+ /**
9
+ * Registers the two skill tools (both surfaces) and hosts their endpoints.
10
+ *
11
+ * The defs are registered as PROVIDERS (resolved at manual-build time) so each
12
+ * tool's description can name the currently-available skills — the agent sees
13
+ * what exists right in the tool catalog, no `list_skills` round-trip needed, and
14
+ * it auto-updates as the default-branch catalog changes. The hosted routes are
15
+ * static; only the description text is dynamic.
16
+ */
17
+ export function registerSkillsTools(
18
+ registry: IToolRegistry,
19
+ router: Router,
20
+ toolAuth: RequestHandler,
21
+ toolHandler: ToolHandlerFactory,
22
+ skillService: ISkillService,
23
+ ): void {
24
+ registry.registerExternalTool((ctx) => buildListSkillsDef(skillService, ctx.userEmail));
25
+ registry.registerInternalTool((ctx) => buildListSkillsDef(skillService, ctx.userEmail));
26
+ registry.registerExternalTool((ctx) => buildGetSkillDef(skillService, ctx.userEmail));
27
+ registry.registerInternalTool((ctx) => buildGetSkillDef(skillService, ctx.userEmail));
28
+
29
+ router.post(
30
+ '/agent/tools/list_skills',
31
+ toolAuth,
32
+ toolHandler(async (_args, ctx: ToolContext) => ({
33
+ skills: await skillService.listSkills(ctx.user.email),
34
+ })),
35
+ );
36
+
37
+ router.post(
38
+ '/agent/tools/get_skill',
39
+ toolAuth,
40
+ toolHandler(async (args, ctx: ToolContext) => {
41
+ const name = typeof args.name === 'string' ? args.name : '';
42
+ const file = typeof args.file === 'string' ? args.file : undefined;
43
+ if (!name) return { error: 'missing_name' };
44
+ return skillService.getSkill(ctx.user.email, name, file);
45
+ }),
46
+ );
47
+ }
48
+
49
+ /** "Currently available skills: `a`, `b`." (or a no-skills note), filtered to what the caller may read. */
50
+ async function availableSkillsLine(skillService: ISkillService, userEmail?: string): Promise<string> {
51
+ const skills = await skillService.listSkills(userEmail);
52
+ if (skills.length === 0) return 'No skills are currently available.';
53
+ return `Currently available skills: ${skills.map((s) => `\`${s.name}\``).join(', ')}.`;
54
+ }
55
+
56
+ async function buildListSkillsDef(skillService: ISkillService, userEmail?: string): Promise<UtcpTool> {
57
+ return toolDef({
58
+ name: 'list_skills',
59
+ description:
60
+ 'List the available skills (reusable specialist instructions) with their names and descriptions. ' +
61
+ 'Discover what skills exist before specialist work, then `get_skill` to load one. ' +
62
+ (await availableSkillsLine(skillService, userEmail)),
63
+ path: '/api/agent/tools/list_skills',
64
+ inputs: { type: 'object', properties: {}, additionalProperties: false },
65
+ outputs: {
66
+ type: 'object',
67
+ properties: {
68
+ skills: {
69
+ type: 'array',
70
+ description: 'Available skills.',
71
+ items: {
72
+ type: 'object',
73
+ properties: {
74
+ name: { type: 'string' },
75
+ description: { type: 'string' },
76
+ version: { type: 'string' },
77
+ path: { type: 'string' },
78
+ },
79
+ },
80
+ },
81
+ },
82
+ },
83
+ tags: ['skills'],
84
+ });
85
+ }
86
+
87
+ async function buildGetSkillDef(skillService: ISkillService, userEmail?: string): Promise<UtcpTool> {
88
+ return toolDef({
89
+ name: 'get_skill',
90
+ description:
91
+ 'Load a skill by name: returns its full instructions (SKILL.md body) to follow, plus the skill ' +
92
+ 'folder path and the list of bundled files. Pass `file` to fetch a bundled file’s content ' +
93
+ '(e.g. a script) instead of the body. ' +
94
+ (await availableSkillsLine(skillService, userEmail)),
95
+ path: '/api/agent/tools/get_skill',
96
+ inputs: {
97
+ type: 'object',
98
+ properties: {
99
+ name: { type: 'string', minLength: 1, description: 'Skill name (its folder name, e.g. `rfi`).' },
100
+ file: {
101
+ type: 'string',
102
+ description:
103
+ 'Optional bundled file path relative to the skill folder (e.g. `scripts/build_xlsx.py`) — ' +
104
+ 'fetch its content instead of the body.',
105
+ },
106
+ },
107
+ required: ['name'],
108
+ additionalProperties: false,
109
+ },
110
+ outputs: {
111
+ type: 'object',
112
+ description: 'On success carries `skill` (or `file` when `file` was passed); on failure carries `error`.',
113
+ properties: {
114
+ skill: { type: 'object', description: 'The loaded skill: name, description, body, files, ….' },
115
+ file: { type: 'object', description: 'A bundled file: name, file, path, content.' },
116
+ error: { type: 'string', description: 'Error code: `not_found`, `forbidden`, `invalid_file`, `missing_name`.' },
117
+ },
118
+ },
119
+ tags: ['skills'],
120
+ });
121
+ }