@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,710 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+ import { parse as parseYaml } from 'yaml';
4
+ import '@utcp/http'; // side effect: register the 'http' call-template type (http + inline sub-manuals)
5
+ import '@utcp/mcp'; // side effect: register the 'mcp' call-template type (mcp `.tool` sources)
6
+ import { UtcpManualSerializer, CallTemplateSerializer, DefaultVariableSubstitutor, } from '@utcp/sdk';
7
+ import { DEFAULT_BRANCH, TOOLS_DIR } from '@bevel-software/platform-shared';
8
+ import { workspaceIdForBranch } from '../workspace/workspace.service.js';
9
+ import { assertSafeFetchUrl } from '../../shared/ssrf.js';
10
+ import { extractFrontmatter, resolveDeclaredId, isValidId, dedupeById } from '../../shared/frontmatter-id.js';
11
+ import { walkFiles } from '../../shared/fs-walk.js';
12
+ import { TtlCache } from '../../shared/ttl-cache.js';
13
+ import { utcpNamespacePrefix, utcpNamespacedKey, MCP_OAUTH_VAR, INTERNAL_MANUAL_NAME, } from '../../shared/utcp-namespace.js';
14
+ import { EXTERNAL_KB_MANUAL_NAME, } from './tool-manuals.contract.js';
15
+ const CACHE_TTL_MS = 60_000;
16
+ /**
17
+ * UTCP namespaces a user `.tool` may NOT claim: they belong to built-in manuals
18
+ * whose loopback creds are pre-seeded on the agent's code-mode client (the
19
+ * internal `Bevel` manual carries the `source:'internal'` token + connector
20
+ * creds; the external KB manual carries the caller's bearer). A `.tool`
21
+ * reproducing one of these namespaces would resolve those seeded vars and could
22
+ * exfiltrate them, so the scanner refuses it. Compared case-insensitively —
23
+ * defensive, though the live collision is the mixed-case `Bevel` reachable via
24
+ * the `name` fallback (an explicit `id` must already be lowercase snake_case).
25
+ */
26
+ const RESERVED_TOOL_NAMESPACES = [INTERNAL_MANUAL_NAME, EXTERNAL_KB_MANUAL_NAME].map((n) => n.toLowerCase());
27
+ /**
28
+ * Variable names the platform seeds for its own (Bevel-hosted) manuals:
29
+ * `<ns>_API_URL` points a manual at the backend and `<ns>_CONNECTION_KEY`
30
+ * carries the platform bearer. No user `.tool` may REFERENCE them
31
+ * (`${API_URL}` / `$API_URL`), in any `.tool` type: the only seeded user
32
+ * namespace is an inline `.tool`'s (its discovery template is platform-served),
33
+ * and a reference inside author-written content would resolve platform creds
34
+ * into a request the author shaped. Refusing every `.tool` at the producing
35
+ * boundary makes "user tools never carry platform credentials" structural
36
+ * rather than dependent on which namespaces happen to be seeded.
37
+ */
38
+ const RESERVED_VARIABLE_NAMES = ['API_URL', 'CONNECTION_KEY'];
39
+ /** The SDK substitutor's reference grammar, exactly: `${VAR}` or `$VAR`. */
40
+ const VARIABLE_REFERENCE_RE = /\$\{([a-zA-Z0-9_]+)\}|\$([a-zA-Z0-9_]+)/g;
41
+ /**
42
+ * A REFERENCE is reserved by SUFFIX, not by exact name: the substitutor looks a
43
+ * variable up under the manual's UTCP namespace first, so `${<ns>_CONNECTION_KEY}`
44
+ * resolves the very same seeded value the bare `${CONNECTION_KEY}` does. Matching
45
+ * the bare name only would let a `.tool` reach the platform bearer just by
46
+ * spelling the namespace out. Suffix matching also refuses harmless-looking
47
+ * near-misses (`MY_API_URL`) — deliberately fail-closed: a `.tool` author who
48
+ * wants their own base URL has the whole namespace minus two suffixes.
49
+ */
50
+ function isReservedVariableRef(varName) {
51
+ return RESERVED_VARIABLE_NAMES.some((reserved) => varName.endsWith(reserved));
52
+ }
53
+ /** Throw if any string in the `.tool` document references a reserved variable. */
54
+ function assertNoReservedVariableRefs(doc, name) {
55
+ const text = JSON.stringify(doc) ?? '';
56
+ for (const match of text.matchAll(VARIABLE_REFERENCE_RE)) {
57
+ const varName = match[1] ?? match[2];
58
+ if (isReservedVariableRef(varName)) {
59
+ throw new Error(`\`.tool\` "${name}" references the reserved variable "${match[0]}" — ` +
60
+ 'API_URL and CONNECTION_KEY (bare or namespaced, e.g. `<namespace>_CONNECTION_KEY`) ' +
61
+ 'are seeded by the platform for its own manuals and may not appear anywhere in a `.tool`.');
62
+ }
63
+ }
64
+ }
65
+ const manualSerializer = new UtcpManualSerializer();
66
+ const callTemplateSerializer = new CallTemplateSerializer();
67
+ // `findRequiredVariables` is a pure walk — one shared instance is fine.
68
+ const variableSubstitutor = new DefaultVariableSubstitutor();
69
+ /**
70
+ * Reads `*.tool` manuals from the DEFAULT-branch workspace (never the caller's
71
+ * branch), so the catalog is one global, released set — same discipline as
72
+ * Skills. Results are cached briefly; drop via `invalidate()` after a merge to
73
+ * default. Any read failure degrades to an empty catalog: the MCP/UTCP endpoint
74
+ * must never break because a `.tool` can't be read.
75
+ */
76
+ export class ToolManualService {
77
+ workspaceService;
78
+ accessControl;
79
+ kbDirName;
80
+ cache;
81
+ mcpAuthDiscovery;
82
+ constructor(workspaceService, accessControl, kbDirName, now = Date.now) {
83
+ this.workspaceService = workspaceService;
84
+ this.accessControl = accessControl;
85
+ this.kbDirName = kbDirName;
86
+ this.cache = new TtlCache(CACHE_TTL_MS, now);
87
+ }
88
+ /**
89
+ * Wire the MCP OAuth auto-discovery (setter injection: the discovery service
90
+ * depends on the vault, which is constructed after this service — the same
91
+ * reason the vault takes `scopeOfVariable` as a closure). Optional: without
92
+ * it, bare `type: mcp` tools simply aren't decorated.
93
+ */
94
+ setMcpAuthDiscovery(discovery) {
95
+ this.mcpAuthDiscovery = discovery;
96
+ }
97
+ invalidate() {
98
+ this.cache.invalidate();
99
+ }
100
+ async listAccessible(userEmail) {
101
+ const manuals = await this.accessibleManuals(userEmail);
102
+ return manuals.map((m) => ({
103
+ slug: m.slug,
104
+ name: m.name,
105
+ path: m.path,
106
+ type: m.type,
107
+ variables: m.variables,
108
+ remote: m.remote,
109
+ setup: m.setup,
110
+ }));
111
+ }
112
+ async listLocalOnly(userEmail) {
113
+ const manuals = await this.accessibleManuals(userEmail);
114
+ return manuals.filter((m) => m.remote === false).map((m) => ({ name: m.name, path: m.path }));
115
+ }
116
+ async userScopedKeysForManual(manualName) {
117
+ // The per-user (`user`-scoped) variables a manual declares, keyed the SAME
118
+ // way the vault stores them — the UTCP-namespaced key (underscores in the
119
+ // manual name doubled), so a readiness check reads the exact rows `resolve`
120
+ // would. `oauth` lets the pre-check treat a not-yet-authorized sign-in as
121
+ // still-missing.
122
+ const manual = (await this.scan()).find((m) => m.name === manualName);
123
+ return (manual?.variables ?? [])
124
+ .filter((v) => v.scope === 'user')
125
+ .map((v) => ({
126
+ key: utcpNamespacedKey(manualName, v.name),
127
+ name: v.name,
128
+ label: v.label ?? null,
129
+ oauth: v.oauth != null,
130
+ // The permissions the tool declares RIGHT NOW — the pre-check compares these
131
+ // against the caller's granted scopes to catch a token that predates a scope
132
+ // addition. Read live so a `.tool` edit self-heals on the next call.
133
+ oauthScopes: v.oauth?.scopes,
134
+ }));
135
+ }
136
+ async scopeOfVariable(effectiveKey) {
137
+ // UTCP looks up `<namespace-with-doubled-underscores>_<VAR>`. Find the manual
138
+ // whose namespace prefixes this key; the declared var is the remainder. Match
139
+ // the LONGEST prefix so a manual `a` can't shadow `a_b` when both exist. (A
140
+ // plain first-underscore split would mis-parse a snake_case manual name.)
141
+ let best = null;
142
+ for (const m of await this.scan()) {
143
+ const prefix = utcpNamespacePrefix(m.name);
144
+ if (effectiveKey.startsWith(prefix) && (!best || prefix.length > best.len)) {
145
+ best = { manual: m, varName: effectiveKey.slice(prefix.length), len: prefix.length };
146
+ }
147
+ }
148
+ if (!best)
149
+ return 'admin';
150
+ const declared = best.manual.variables?.find((v) => v.name === best.varName);
151
+ return declared?.scope ?? 'admin';
152
+ }
153
+ async toManualCallTemplates(userEmail, opts) {
154
+ const manuals = await this.accessibleManuals(userEmail);
155
+ const out = [];
156
+ for (const m of manuals) {
157
+ // Remote consumers (the hosted MCP proxy) don't get local-only manuals —
158
+ // they'd fail server-side. Discovery of them happens via `list_local_tools`.
159
+ if (opts?.remoteOnly && m.remote === false)
160
+ continue;
161
+ try {
162
+ out.push(callTemplateSerializer.validateDict(this.buildCallTemplateDict(m)));
163
+ }
164
+ catch (err) {
165
+ // A `.tool` that produces an invalid call-template is dropped here — at
166
+ // the producing boundary — so the served list is always valid.
167
+ console.warn(`[tool-manuals] skipping "${m.path}": ${err instanceof Error ? err.message : String(err)}`);
168
+ }
169
+ }
170
+ return out;
171
+ }
172
+ async resolveInlineManual(userEmail, slug) {
173
+ const found = (await this.scan()).find((m) => m.slug === slug);
174
+ if (!found || found.type !== 'inline')
175
+ return null;
176
+ const wsId = workspaceIdForBranch(DEFAULT_BRANCH);
177
+ if (!(await this.accessControl.canRead(wsId, userEmail, found.path)))
178
+ return null;
179
+ try {
180
+ return manualSerializer.validateDict({
181
+ utcp_version: '1.1.0',
182
+ manual_version: '1.0.0',
183
+ tools: found.tools ?? [],
184
+ });
185
+ }
186
+ catch {
187
+ return null;
188
+ }
189
+ }
190
+ async preview(content) {
191
+ let descriptor;
192
+ try {
193
+ descriptor = normalizeToolManual('draft', 'Tools/draft.tool', content);
194
+ }
195
+ catch (err) {
196
+ return { ok: false, errors: [err instanceof Error ? err.message : String(err)] };
197
+ }
198
+ if (descriptor.type === 'inline') {
199
+ try {
200
+ const manual = manualSerializer.validateDict({
201
+ utcp_version: '1.1.0',
202
+ manual_version: '1.0.0',
203
+ tools: descriptor.tools ?? [],
204
+ });
205
+ const tools = (manual.tools ?? []).map((t) => ({
206
+ name: String(t.name ?? ''),
207
+ description: typeof t.description === 'string' ? t.description : undefined,
208
+ }));
209
+ return { ok: true, tools };
210
+ }
211
+ catch (err) {
212
+ return { ok: false, errors: [err instanceof Error ? err.message : String(err)] };
213
+ }
214
+ }
215
+ // http / mcp resolve their tools at runtime (a network round-trip we don't
216
+ // perform in preview), but still validate the call-template the same way
217
+ // `toManualCallTemplates` does, so a draft that discovery would reject is
218
+ // reported here instead of appearing valid.
219
+ try {
220
+ callTemplateSerializer.validateDict(this.buildCallTemplateDict(descriptor));
221
+ }
222
+ catch (err) {
223
+ return { ok: false, errors: [err instanceof Error ? err.message : String(err)] };
224
+ }
225
+ return { ok: true, tools: [] };
226
+ }
227
+ // --- internal --------------------------------------------------------------
228
+ /** Build the raw UTCP manual call-template dict for one descriptor (validated by the caller). */
229
+ buildCallTemplateDict(m) {
230
+ if (m.type === 'inline') {
231
+ return {
232
+ name: m.name,
233
+ call_template_type: 'http',
234
+ http_method: 'GET',
235
+ url: `\${API_URL}/api/tools/${m.slug}/manual`,
236
+ content_type: 'application/json',
237
+ headers: { Authorization: 'Bearer ${CONNECTION_KEY}' },
238
+ };
239
+ }
240
+ if (m.type === 'mcp') {
241
+ // Remote (HTTP/streamable) MCP server. Exact plugin field shape is
242
+ // finalized in Phase 4 (native `@utcp/mcp`); the proxy try/catches
243
+ // registration so an unsupported template never breaks the session.
244
+ return {
245
+ name: m.name,
246
+ call_template_type: 'mcp',
247
+ config: {
248
+ mcpServers: {
249
+ [m.name]: {
250
+ transport: 'http',
251
+ url: m.url,
252
+ ...(m.headers ? { headers: m.headers } : {}),
253
+ },
254
+ },
255
+ },
256
+ };
257
+ }
258
+ // http: a URL returning a UTCP manual.
259
+ return {
260
+ name: m.name,
261
+ call_template_type: 'http',
262
+ http_method: m.httpMethod ?? 'GET',
263
+ url: m.url,
264
+ content_type: 'application/json',
265
+ ...(m.headers ? { headers: m.headers } : {}),
266
+ };
267
+ }
268
+ async accessibleManuals(userEmail) {
269
+ const manuals = await this.scan();
270
+ if (manuals.length === 0)
271
+ return [];
272
+ const wsId = workspaceIdForBranch(DEFAULT_BRANCH);
273
+ const allowed = await this.accessControl.canReadBatch(wsId, userEmail, manuals.map((m) => m.path));
274
+ // Fail closed: keep a manual only on an explicit `true` verdict (a missing
275
+ // entry is treated as denied, matching the KB's default-deny read model).
276
+ return manuals.filter((m) => allowed.get(m.path) === true);
277
+ }
278
+ async scan() {
279
+ const cached = this.cache.get();
280
+ if (cached)
281
+ return cached;
282
+ const manuals = await this.scanDisk();
283
+ await this.decorateMcpOAuth(manuals);
284
+ // AFTER the oauth decoration, so an injected `${MCP_OAUTH}` header ref is
285
+ // already declared and isn't re-surfaced as a bare admin key.
286
+ for (const m of manuals)
287
+ this.surfaceReferencedVariables(m);
288
+ this.cache.set(manuals);
289
+ return manuals;
290
+ }
291
+ /**
292
+ * Auto-surface every `${VAR}` a manual actually references, for ANY tool
293
+ * type — using UTCP's own required-variables walk, so the surfaced list
294
+ * can't drift from what substitution will demand at registration/call time.
295
+ * Referenced-but-undeclared vars become `scope: admin` entries (matching
296
+ * `scopeOfVariable`'s default for undeclared keys), which puts them in the
297
+ * secrets UI without the author having to write a `variables:` block. The
298
+ * block stays the way to add metadata: `scope: user`, labels, oauth.
299
+ */
300
+ surfaceReferencedVariables(m) {
301
+ let refs;
302
+ try {
303
+ refs = variableSubstitutor.findRequiredVariables(this.buildCallTemplateDict(m), m.name);
304
+ // An inline manual's credential refs live in its embedded tools'
305
+ // templates, not the (Bevel-hosted) discovery template.
306
+ if (m.type === 'inline' && m.tools) {
307
+ refs.push(...variableSubstitutor.findRequiredVariables(m.tools, m.name));
308
+ }
309
+ }
310
+ catch {
311
+ return; // a malformed template is reported elsewhere; never break the scan
312
+ }
313
+ const prefix = utcpNamespacePrefix(m.name);
314
+ const declared = new Set((m.variables ?? []).map((v) => v.name));
315
+ for (const ref of new Set(refs)) {
316
+ if (!ref.startsWith(prefix))
317
+ continue;
318
+ const name = ref.slice(prefix.length);
319
+ // Reserved names are seeded by the proxy per session — not credentials.
320
+ if (name === 'API_URL' || name === 'CONNECTION_KEY' || declared.has(name))
321
+ continue;
322
+ m.variables = [...(m.variables ?? []), { name, scope: 'admin' }];
323
+ }
324
+ }
325
+ /**
326
+ * Zero-config OAuth for bare `type: mcp` manuals: when discovery finds the
327
+ * remote server demands OAuth (and the file doesn't configure auth itself),
328
+ * decorate the descriptor with a synthetic user-scoped `MCP_OAUTH` variable
329
+ * and an `Authorization: Bearer ${MCP_OAUTH}` header. Decorating HERE — the
330
+ * one place descriptors are built — means every consumer inherits it:
331
+ * /connect lists the sign-in, `scopeOfVariable` resolves it per-user,
332
+ * `userScopedKeysForManual` gates unauthorized callers, and the call
333
+ * template carries the header for the variable loader to fill.
334
+ */
335
+ async decorateMcpOAuth(manuals) {
336
+ const discovery = this.mcpAuthDiscovery;
337
+ if (!discovery)
338
+ return;
339
+ const eligible = manuals.filter((m) => {
340
+ if (m.type !== 'mcp' || !m.url)
341
+ return false;
342
+ // Local-only servers aren't probeable from here; templated URLs aren't
343
+ // resolvable without a caller. Both keep their file-declared behavior.
344
+ if (m.remote === false || m.url.includes('${'))
345
+ return false;
346
+ // The file configures auth itself — explicit wins over discovery.
347
+ const hasAuthHeader = Object.keys(m.headers ?? {}).some((h) => h.toLowerCase() === 'authorization');
348
+ const hasOAuthVar = (m.variables ?? []).some((v) => v.oauth != null);
349
+ return !hasAuthHeader && !hasOAuthVar;
350
+ });
351
+ // Probe every eligible server CONCURRENTLY — a cold scan with several bare
352
+ // mcp tools shouldn't pay one network round-trip per tool in series. The
353
+ // mutation still happens per-manual after its own probe settles.
354
+ await Promise.all(eligible.map(async (m) => {
355
+ try {
356
+ const found = await discovery.statusFor(m.name, m.url);
357
+ // Record the setup requirement so the secrets UI can tell an admin
358
+ // whether anything needs configuring — especially the `unsupported`
359
+ // case, which otherwise only surfaced in server logs.
360
+ if (found.status === 'open') {
361
+ m.setup = { kind: 'open' };
362
+ return;
363
+ }
364
+ if (found.status === 'unsupported') {
365
+ m.setup = { kind: 'oauth-manual', reason: found.reason };
366
+ return;
367
+ }
368
+ m.setup = { kind: 'oauth-auto' };
369
+ m.headers = { ...(m.headers ?? {}), Authorization: `Bearer \${${MCP_OAUTH_VAR}}` };
370
+ m.variables = [
371
+ ...(m.variables ?? []),
372
+ {
373
+ name: MCP_OAUTH_VAR,
374
+ scope: 'user',
375
+ label: `${m.name} sign-in`,
376
+ // NO `scopes` here, deliberately. A variable's declared scopes are
377
+ // REQUIRED back from the token (needsReauth + the call-time gate),
378
+ // which is right for file-authored scopes but not for discovery's
379
+ // machine-guessed ones (the PRM's `scopes_supported`): providers
380
+ // don't reliably echo them (e.g. Granola's AS grants OIDC scopes
381
+ // instead), which would permanently flag-and-block an authorized
382
+ // sign-in. The shared provider row still carries them, so the
383
+ // authorize request itself is unchanged; an under-scoped token
384
+ // simply 401s at call time and re-enters auth there.
385
+ oauth: {
386
+ authorizationUrl: found.provider.authorizationUrl,
387
+ tokenUrl: found.provider.tokenUrl,
388
+ clientId: found.provider.clientId,
389
+ },
390
+ },
391
+ ];
392
+ }
393
+ catch (err) {
394
+ // Discovery must never break the catalog — the tool just stays bare.
395
+ console.warn(`[tool-manuals] mcp auth discovery failed for "${m.path}": ${err instanceof Error ? err.message : String(err)}`);
396
+ }
397
+ }));
398
+ }
399
+ async scanDisk() {
400
+ let wsId;
401
+ try {
402
+ wsId = (await this.workspaceService.getOrCreateForBranch(DEFAULT_BRANCH)).id;
403
+ }
404
+ catch {
405
+ return [];
406
+ }
407
+ const root = path.join(await this.workspaceService.getWorkspacePath(wsId), this.kbDirName, TOOLS_DIR);
408
+ const files = (await walkFiles(root, (n) => n.toLowerCase().endsWith('.tool'))).map((rel) => ({
409
+ abs: path.join(root, rel),
410
+ rel: `${TOOLS_DIR}/${rel}`,
411
+ }));
412
+ const parsed = [];
413
+ for (const f of files) {
414
+ let content;
415
+ try {
416
+ content = await fs.readFile(f.abs, 'utf-8');
417
+ }
418
+ catch {
419
+ continue;
420
+ }
421
+ let descriptor;
422
+ try {
423
+ descriptor = normalizeToolManual(baseName(f.rel), f.rel, content);
424
+ }
425
+ catch {
426
+ // A malformed `.tool` is skipped rather than breaking the catalog.
427
+ continue;
428
+ }
429
+ // The route slug IS the id (unique after dedup below, snake_case → URL-safe),
430
+ // so the URL a user sees matches the tool's declared identity.
431
+ descriptor.slug = descriptor.name;
432
+ parsed.push(descriptor);
433
+ }
434
+ // The manual name (= its id) is the UTCP variable namespace secrets bind to, so
435
+ // it must be unique. A collision is REFUSED — not auto-suffixed, which would
436
+ // silently rebind a configured secret to a different file. The winner is
437
+ // deterministic (files scanned in sorted path order); the shared `dedupeById`
438
+ // is the one dedup rule across tools and skills.
439
+ return dedupeById(parsed, (m) => m.name, (m, id) => console.warn(`[tool-manuals] skipping "${m.path}": manual id "${id}" is already used by another ` +
440
+ '`.tool` — give it a unique `id` (the id is the secret-variable namespace and must be unique).'));
441
+ }
442
+ }
443
+ // --- helpers ------------------------------------------------------------------
444
+ function baseName(rel) {
445
+ const base = rel.slice(rel.lastIndexOf('/') + 1);
446
+ return base.replace(/\.tool$/i, '');
447
+ }
448
+ /**
449
+ * Deterministically derive a `.tool`'s UTCP manual name — the variable namespace
450
+ * secrets bind to via `<manual>_<VAR>`. ALPHANUMERIC ONLY (no underscores) so the
451
+ * prefix splits cleanly on a single underscore, and a pure function of the file's
452
+ * own declared name: it never depends on what other `.tool`s exist, so a
453
+ * configured secret's namespace can't drift when the catalog changes. Collisions
454
+ * are refused by the scanner (see `scanDisk`), not silently suffixed. A name that
455
+ * strips to empty (or starts with a digit) is prefixed `tool`; because the KB
456
+ * manual name (`KNOWLEDGE_BASE`) contains an underscore, a user name can never
457
+ * collide with it after stripping.
458
+ */
459
+ function manualName(raw) {
460
+ const name = raw.replace(/[^a-zA-Z0-9]/g, '');
461
+ if (!name || /^[0-9]/.test(name))
462
+ return `tool${name}`;
463
+ return name;
464
+ }
465
+ /**
466
+ * Parse + normalize a `.tool` file into a descriptor. THE TOOL IS THE
467
+ * FRONTMATTER: a fenced file's single `---` YAML block carries everything —
468
+ * `id`/`name`, access verbs (`read`/`write`/`owner`/`download`, read straight
469
+ * from the file by the access resolver, not here), and the config
470
+ * (`type`/`url`/`variables`/…). Text after the closing fence is free-form notes
471
+ * the parser ignores. A fence-less file is the legacy form (the whole file is
472
+ * the object — JSON can't carry fences). Throws on a structurally invalid
473
+ * object or a malformed explicit `id`. `slug` is provisional (the scanner
474
+ * dedups it); `name` is the FINAL UTCP manual namespace.
475
+ */
476
+ export function normalizeToolManual(provisionalSlug, repoPath, content) {
477
+ // THE TOOL IS THE FRONTMATTER. A fenced `.tool` is one `---` YAML block
478
+ // carrying everything — identity (`id`/`name`), access verbs, and config —
479
+ // and anything after the closing fence is free-form notes the parser ignores
480
+ // (like a SKILL.md body). One object serves every reader: the access resolver
481
+ // finds its verbs inside the fence, the id index finds `id`/`name`, and the
482
+ // config keys live in the same object. A fence-less file is the legacy form
483
+ // (the whole file is the object) — JSON `.tool`s can't carry fences.
484
+ const fm = extractFrontmatter(content);
485
+ const source = fm ? fm.frontmatter : content;
486
+ const parsed = parseYaml(source);
487
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
488
+ throw new Error('`.tool` file must be a YAML/JSON object (in the `---` block when fenced)');
489
+ }
490
+ const obj = parsed;
491
+ const type = normalizeType(obj.type);
492
+ // Identity: an explicit `id` is used VERBATIM as the UTCP manual namespace, so
493
+ // it must be lowercase snake_case (UTCP's namespace grammar). With no explicit
494
+ // id, fall back to `name` then the filename and sanitize (legacy behaviour —
495
+ // keeps existing tools' namespaces).
496
+ const explicitId = typeof obj.id === 'string' ? obj.id.trim() : '';
497
+ let name;
498
+ if (explicitId) {
499
+ if (!isValidId(explicitId)) {
500
+ throw new Error(`tool id "${explicitId}" must be lowercase snake_case (letters, digits, underscores)`);
501
+ }
502
+ name = explicitId;
503
+ }
504
+ else {
505
+ name = manualName(resolveDeclaredId(obj, provisionalSlug));
506
+ }
507
+ // A `.tool` may not reproduce a built-in manual's UTCP namespace — that would
508
+ // let it read the loopback creds seeded under that namespace on the agent's
509
+ // code-mode client (internal token, connector creds, KB bearer).
510
+ if (RESERVED_TOOL_NAMESPACES.includes(name.toLowerCase())) {
511
+ throw new Error(`tool namespace "${name}" is reserved for a built-in manual — choose a different \`id\`/\`name\` ` +
512
+ "(a `.tool` sharing a built-in namespace could read that manual's seeded credentials).");
513
+ }
514
+ // Any `.tool` content — url, headers, inline tool templates, notes — may not
515
+ // reference the platform-seeded variables.
516
+ assertNoReservedVariableRefs(obj, name);
517
+ const descriptor = {
518
+ slug: provisionalSlug,
519
+ name,
520
+ path: repoPath,
521
+ type,
522
+ };
523
+ const variables = normalizeVariables(obj.variables);
524
+ if (variables.length)
525
+ descriptor.variables = variables;
526
+ descriptor.remote = normalizeRemote(obj.remote);
527
+ if (type === 'inline') {
528
+ const tools = Array.isArray(obj.tools) ? obj.tools : undefined;
529
+ if (!tools)
530
+ throw new Error('inline `.tool` must have a `tools` array');
531
+ descriptor.tools = tools;
532
+ }
533
+ else {
534
+ const url = typeof obj.url === 'string' ? obj.url.trim() : '';
535
+ if (!url)
536
+ throw new Error(`${type} \`.tool\` must have a \`url\``);
537
+ descriptor.url = url;
538
+ // SSRF: a remote-capable `.tool` triggers a server-side discovery fetch to
539
+ // this URL (the MCP proxy AND now the in-process agent + headless routines),
540
+ // so a literal private/loopback/metadata host is refused at the producing
541
+ // boundary. Only a TEMPLATED HOSTNAME (resolved at call time) is
542
+ // uncheckable here — a `${...}` in the scheme, userinfo, port, path, or
543
+ // query still leaves a concrete network target (`${S}://169.254.169.254/x`
544
+ // and `http://${U}@169.254.169.254/x` target the metadata IP no matter what
545
+ // resolves), so the guard must still run against the literal host. The
546
+ // authority is therefore taken from `://` INDEPENDENT of the scheme being
547
+ // literal, and when the raw url can't parse (templated scheme or port) the
548
+ // check runs on a synthetic `<scheme-or-http>//host`. A BACKSLASH behaves as
549
+ // a slash for http(s) in WHATWG `new URL` — BOTH as the scheme separator
550
+ // (`${S}:\\169.254.169.254\\p` → the IP is the host) and inside the
551
+ // authority (`http://169.254.169.254\@${HOST}/x` fetches the IP, the `\@…`
552
+ // becoming path). So the authority separator is `:` + two `[\/]` (not just
553
+ // `://`), and `\` also terminates the authority alongside `/?#`; otherwise a
554
+ // literal internal host slips past as a templated scheme or userinfo.
555
+ // Local-only (`remote: false`) `.tool`s are never fetched server-side, so
556
+ // are exempt.
557
+ const literalScheme = /^([a-zA-Z][a-zA-Z0-9+.-]*:)[\\/]{2}/.exec(url)?.[1];
558
+ const sepMatch = /:[\\/]{2}/.exec(url);
559
+ const sepIdx = sepMatch ? sepMatch.index : -1;
560
+ const authority = sepIdx >= 0 ? url.slice(sepIdx + 3).split(/[/\\?#]/, 1)[0] : url;
561
+ const hostPort = authority.slice(authority.lastIndexOf('@') + 1);
562
+ const host = hostPort.startsWith('[') ? hostPort.slice(0, hostPort.indexOf(']') + 1) : hostPort.split(':')[0];
563
+ if (descriptor.remote !== false && !host.includes('${')) {
564
+ const checkUrl = literalScheme && !authority.includes('${')
565
+ ? url // fully literal scheme + authority → validate the URL as-is
566
+ : sepIdx >= 0
567
+ ? `${literalScheme ?? 'http:'}//${host}` // templated scheme/userinfo/port, literal host
568
+ : url; // no authority shape at all → parse raw (refuses malformed)
569
+ assertSafeFetchUrl(checkUrl, { label: `\`.tool\` "${name}" url` });
570
+ }
571
+ if (obj.headers && typeof obj.headers === 'object' && !Array.isArray(obj.headers)) {
572
+ descriptor.headers = obj.headers;
573
+ }
574
+ if (type === 'http') {
575
+ const m = typeof obj.httpMethod === 'string' ? obj.httpMethod.toUpperCase() : 'GET';
576
+ descriptor.httpMethod = m === 'POST' ? 'POST' : 'GET';
577
+ }
578
+ }
579
+ return descriptor;
580
+ }
581
+ /**
582
+ * Parse the optional `variables:` block of a `.tool` file. Each entry names a
583
+ * `${VAR}` and who provisions it (`admin` default | `user`). Throws on a
584
+ * malformed entry so the whole file is skipped (never silently mis-scoped) — a
585
+ * mis-scoped variable is a security-relevant mistake, not a soft warning.
586
+ */
587
+ function normalizeVariables(raw) {
588
+ if (raw === undefined || raw === null)
589
+ return [];
590
+ if (!Array.isArray(raw))
591
+ throw new Error('`variables` must be an array');
592
+ const seen = new Set();
593
+ return raw.map((entry) => {
594
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
595
+ throw new Error('each `variables` entry must be an object');
596
+ }
597
+ const e = entry;
598
+ const name = typeof e.name === 'string' ? e.name.trim() : '';
599
+ if (!/^[A-Za-z0-9_]+$/.test(name)) {
600
+ throw new Error(`variable name "${name}" must match [A-Za-z0-9_]+`);
601
+ }
602
+ if (RESERVED_VARIABLE_NAMES.includes(name)) {
603
+ throw new Error(`variable name "${name}" is reserved for platform seeding and may not be declared by a \`.tool\``);
604
+ }
605
+ if (seen.has(name))
606
+ throw new Error(`duplicate variable "${name}"`);
607
+ seen.add(name);
608
+ const rawScope = typeof e.scope === 'string' ? e.scope.toLowerCase().trim() : '';
609
+ if (rawScope && rawScope !== 'admin' && rawScope !== 'user') {
610
+ throw new Error(`variable "${name}" has invalid scope "${e.scope}" (expected admin|user)`);
611
+ }
612
+ const scope = rawScope === 'user' ? 'user' : 'admin';
613
+ const label = typeof e.label === 'string' && e.label.trim() ? e.label.trim() : undefined;
614
+ const oauth = normalizeVariableOAuth(name, e.oauth);
615
+ // OAuth is inherently per-caller — each user signs in for their own token. An
616
+ // admin-shared OAuth token would leak one user's token to all callers.
617
+ if (oauth && scope !== 'user') {
618
+ throw new Error(`variable "${name}" with oauth must be scope:user`);
619
+ }
620
+ return {
621
+ name,
622
+ scope,
623
+ ...(label ? { label } : {}),
624
+ ...(oauth ? { oauth } : {}),
625
+ };
626
+ });
627
+ }
628
+ /**
629
+ * Parse a variable's optional OAuth provider config. Carries PUBLIC config only —
630
+ * never a client secret. Both URLs are validated with the SAME SSRF-safe check the
631
+ * vault uses for OAuth endpoints (`assertSafeFetchUrl` with https required), so a
632
+ * `.tool` author can't aim a sign-in/token exchange at an internal host.
633
+ */
634
+ function normalizeVariableOAuth(name, raw) {
635
+ if (raw === undefined || raw === null)
636
+ return undefined;
637
+ if (typeof raw !== 'object' || Array.isArray(raw)) {
638
+ throw new Error(`variable "${name}" oauth must be an object`);
639
+ }
640
+ const o = raw;
641
+ // Confidential OAuth material is provisioned only through the protected
642
+ // client-secret route; reject it here so a plaintext `.tool` can't smuggle one in.
643
+ for (const forbidden of ['clientSecret', 'client_secret', 'secret']) {
644
+ if (o[forbidden] !== undefined) {
645
+ throw new Error(`variable "${name}" oauth.${forbidden} must be set through the protected client-secret route`);
646
+ }
647
+ }
648
+ const safeUrl = (v, field) => {
649
+ const s = typeof v === 'string' ? v.trim() : '';
650
+ try {
651
+ assertSafeFetchUrl(s, { requireHttps: true, label: `${name} oauth.${field}` });
652
+ }
653
+ catch (err) {
654
+ throw new Error(err instanceof Error ? err.message : `variable "${name}" oauth.${field} invalid`);
655
+ }
656
+ return s;
657
+ };
658
+ const authorizationUrl = safeUrl(o.authorizationUrl, 'authorizationUrl');
659
+ const tokenUrl = safeUrl(o.tokenUrl, 'tokenUrl');
660
+ const clientId = typeof o.clientId === 'string' && o.clientId.trim() ? o.clientId.trim() : '';
661
+ if (!clientId)
662
+ throw new Error(`variable "${name}" oauth.clientId is required`);
663
+ let scopes;
664
+ if (o.scopes !== undefined) {
665
+ if (!Array.isArray(o.scopes) || !o.scopes.every((s) => typeof s === 'string')) {
666
+ throw new Error(`variable "${name}" oauth.scopes must be string[]`);
667
+ }
668
+ scopes = o.scopes;
669
+ }
670
+ let authParams;
671
+ if (o.authParams !== undefined) {
672
+ if (typeof o.authParams !== 'object' || Array.isArray(o.authParams)) {
673
+ throw new Error(`variable "${name}" oauth.authParams must be an object of string values`);
674
+ }
675
+ const entries = Object.entries(o.authParams);
676
+ if (!entries.every(([, v]) => typeof v === 'string')) {
677
+ throw new Error(`variable "${name}" oauth.authParams values must be strings`);
678
+ }
679
+ authParams = Object.fromEntries(entries);
680
+ }
681
+ return {
682
+ authorizationUrl,
683
+ tokenUrl,
684
+ clientId,
685
+ ...(scopes ? { scopes } : {}),
686
+ ...(authParams ? { authParams } : {}),
687
+ };
688
+ }
689
+ /**
690
+ * Parse the optional `remote` flag. Absent ⇒ `true` (remote-capable, the default).
691
+ * A non-boolean throws so the file is skipped rather than silently mis-classified.
692
+ */
693
+ function normalizeRemote(raw) {
694
+ if (raw === undefined || raw === null)
695
+ return true;
696
+ if (typeof raw !== 'boolean')
697
+ throw new Error('`remote` must be a boolean');
698
+ return raw;
699
+ }
700
+ function normalizeType(raw) {
701
+ const t = typeof raw === 'string' ? raw.toLowerCase().trim() : '';
702
+ if (t === 'http')
703
+ return 'http';
704
+ if (t === 'mcp')
705
+ return 'mcp';
706
+ if (t === 'inline' || t === 'text' || t === '')
707
+ return 'inline';
708
+ throw new Error(`unknown \`.tool\` type: ${raw}`);
709
+ }
710
+ //# sourceMappingURL=tool-manuals.service.js.map