@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,767 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { join } from 'node:path';
3
+ import { ToolError } from '../tool-helpers/tool.contract.js';
4
+ import { BRANCH_INPUT, toolDef } from '../tool-helpers/tool-def.js';
5
+ import { recordOntologyRead, assertOntologyWriteAllowed, assertShellAllowedWithinOntology, ONTOLOGY_BOUNDARY_NOTE, SESSION_ID_INPUT, } from './session-ontology.gate.js';
6
+ import { requireInternalSource, requireExternalSource } from '../tool-auth/tool-auth.middleware.js';
7
+ import { workspaceIdForBranch } from './workspace.service.js';
8
+ // Leaf-level shared primitive (same exception `workspace.service.ts` already
9
+ // relies on) — not a workflow service, so this stays inside the module boundary.
10
+ import { assertValidBranchName } from '../workflow/git/branch-name.js';
11
+ import { toKbRelative, resolveReadableMap } from '../access/kb-read-filter.js';
12
+ /** Throw a 403 ToolError if the gate denies reading `wsPath` (a KB node). */
13
+ async function assertCanRead(gate, wsPath) {
14
+ const rel = toKbRelative(wsPath, gate.kbDirName);
15
+ if (rel === null)
16
+ return; // not a KB node — not governed by read rules
17
+ const ok = await gate.accessControl.canRead(gate.workspaceId, gate.userEmail, rel);
18
+ if (!ok)
19
+ throw new ToolError(`You don't have permission to read "${wsPath}".`, 403);
20
+ }
21
+ /**
22
+ * Drop the file entries the caller may not read from a directory listing.
23
+ * Directory entries and non-KB files are always kept (a directory itself has
24
+ * no `read:` verdict; its restricted children are filtered when read/listed) —
25
+ * this is the AGENT's inclusion policy and differs from the explorer tree,
26
+ * which hides restricted directories outright. Uses the FULL `canReadBatch`
27
+ * (per-node frontmatter honoured), via the shared `resolveReadableMap`. One
28
+ * batched ACL load per directory.
29
+ */
30
+ async function filterReadableEntries(gate, dir, entries) {
31
+ const fileWsPaths = [];
32
+ for (const e of entries) {
33
+ if (e.type === 'directory')
34
+ continue;
35
+ fileWsPaths.push(dir ? `${dir}/${e.name}` : e.name);
36
+ }
37
+ if (fileWsPaths.length === 0)
38
+ return entries;
39
+ const verdict = await resolveReadableMap((wid, email, rels) => gate.accessControl.canReadBatch(wid, email, rels), gate.workspaceId, gate.userEmail, gate.kbDirName, fileWsPaths);
40
+ return entries.filter((e) => {
41
+ if (e.type === 'directory')
42
+ return true;
43
+ const wsPath = dir ? `${dir}/${e.name}` : e.name;
44
+ return verdict.get(wsPath) === true;
45
+ });
46
+ }
47
+ /**
48
+ * Appended (centrally, in `mount`) to EVERY workspace tool description. A KB
49
+ * author can drop a `CLAUDE.md` at the workspace root to document conventions
50
+ * for that knowledge base; agents (ours and external) should consult it before
51
+ * touching files. It rides on every entrypoint — reads (grep/list_files/
52
+ * file_stat) included — because any of them can be a session's first touch.
53
+ */
54
+ const KB_CONVENTIONS_NOTE = ' Before your first read or change in a workspace, read `CLAUDE.md` at the KB root (if it exists) — it holds the author\'s conventions for this knowledge base, and you should follow them.';
55
+ const int = (description) => ({ type: 'integer', description });
56
+ const str = (description) => ({ type: 'string', description });
57
+ function asText(content) {
58
+ return typeof content === 'string' ? content : content.toString('utf8');
59
+ }
60
+ /** JS grep over the workspace tree (read methods only) — bounded by match + depth caps. */
61
+ async function grepWalk(fs, dir, re, out, max, depth, gate, recordOntologyRead) {
62
+ if (out.length >= max || depth > 12)
63
+ return;
64
+ let entries;
65
+ try {
66
+ entries = (await fs.readdir(dir || '.'));
67
+ }
68
+ catch {
69
+ return;
70
+ }
71
+ // Filter unreadable KB nodes out of the walk so grep never opens — or leaks
72
+ // a line from — a file the caller may not read.
73
+ entries = await filterReadableEntries(gate, dir, entries);
74
+ for (const e of entries) {
75
+ if (out.length >= max)
76
+ return;
77
+ if (e.name === '.git' || e.name === 'node_modules')
78
+ continue;
79
+ const p = dir ? `${dir}/${e.name}` : e.name;
80
+ if (e.type === 'directory') {
81
+ await grepWalk(fs, p, re, out, max, depth + 1, gate, recordOntologyRead);
82
+ }
83
+ else {
84
+ // Opening a file under a named ontology is a read of that ontology — even
85
+ // for a root-level grep that resolves to a neutral root. Record it so a
86
+ // cross-ontology grep poisons later writes (closes the read-leak).
87
+ await recordOntologyRead(p);
88
+ let content;
89
+ try {
90
+ content = asText(await fs.readFile(p));
91
+ }
92
+ catch {
93
+ continue;
94
+ }
95
+ if (content.includes(String.fromCharCode(0)))
96
+ continue; // skip binary (NUL)
97
+ const lines = content.split('\n');
98
+ for (let i = 0; i < lines.length && out.length < max; i++) {
99
+ re.lastIndex = 0;
100
+ if (re.test(lines[i]))
101
+ out.push({ path: p, line: i + 1, text: lines[i].slice(0, 300) });
102
+ }
103
+ }
104
+ }
105
+ }
106
+ /**
107
+ * Workspace domain tools: the file primitives (replacing Mastra's auto-injected
108
+ * Workspace tools) + unzip. Most just re-expose the SAME `LocalFilesystem`
109
+ * methods Mastra's tools call (via `ctx.getFilesystem(a.branch as string)`), so behaviour is
110
+ * identical and write-side ops still flow through the lock/commit pipeline.
111
+ * `edit_file`, `grep`, and `execute_command` are tool-level (no filesystem
112
+ * method), so they're implemented here. File ops are `both`; `execute_command`
113
+ * is INTERNAL-only (arbitrary shell as the caller is too dangerous to expose).
114
+ */
115
+ export function registerWorkspaceTools(registry, router, toolAuth, toolHandler, spillStore, accessControl, kbDirName, sessionOntologyGate, writePolicy, sessionSink) {
116
+ /** Build the per-call read gate from the tool's branch input + caller identity. */
117
+ const readGateFor = (branch, ctx) => ({
118
+ accessControl,
119
+ kbDirName,
120
+ workspaceId: workspaceIdForBranch(branch),
121
+ userEmail: ctx.user.email,
122
+ });
123
+ const mount = (spec) => {
124
+ const path = `/api/agent/tools/${spec.name}`;
125
+ const def = toolDef({
126
+ name: spec.name,
127
+ // Every workspace entrypoint carries the CLAUDE.md reminder, appended once
128
+ // here so no tool (especially the read-only ones a session hits first) can
129
+ // miss it.
130
+ description: spec.description + KB_CONVENTIONS_NOTE,
131
+ path,
132
+ inputs: spec.inputs,
133
+ outputs: spec.outputs,
134
+ tags: spec.write ? ['workspace', 'write'] : ['workspace'],
135
+ });
136
+ registry.registerInternalTool(def);
137
+ if (!spec.internalOnly)
138
+ registry.registerExternalTool(def);
139
+ // Internal-only tools (e.g. `execute_command`) keep their route mounted —
140
+ // our agent calls it over the same loopback — but gate it to internal-source
141
+ // callers so an external connection key can't invoke it by name.
142
+ router.post(path.slice('/api'.length), toolAuth, ...(spec.internalOnly ? [requireInternalSource] : []), toolHandler(spec.handler, { write: spec.write }));
143
+ };
144
+ // ── session bootstrap (external agents) ─────────────────────────────────
145
+ // Every read/write tool below scopes the ontology-session boundary off a
146
+ // `sessionId`. The in-process agent carries its thread id, but an external
147
+ // agent has no ambient run id and so cannot satisfy the gate until it has
148
+ // one. This mints that id up front (called ONCE); the MCP proxy then threads
149
+ // it onto every later gated call via its sessionId-output continuity
150
+ // convention. EXTERNAL-ONLY (not registered internal): the in-process agent
151
+ // already supplies its session id and ignores any body value.
152
+ //
153
+ // WHAT the minted id is backed by is the `ISessionSink` port's business
154
+ // (session-sink.ts). In the enterprise app it is a REAL chat-thread id, so
155
+ // the SAME id works end to end: KB reads scope the ontology boundary under
156
+ // it, AND `ask` accepts it (its sessionId IS a chat thread, resolved via
157
+ // getThread) — that unification is what stops a caller reading from one
158
+ // ontology and then having `ask` write into another. In a core-only
159
+ // deployment (no chat/ask) the default sink mints a bare id, which is all
160
+ // the ontology gate needs.
161
+ const startSessionDef = toolDef({
162
+ name: 'start_session',
163
+ description: 'Mint the KnowledgeBase session id this run needs to read or write the knowledge ontologies. Call this ONCE, before any other KnowledgeBase tool, and only once per run — every gated tool needs the `sessionId` it returns to enforce the one-ontology-per-conversation boundary, and minting a new id mid-run resets that boundary. The id is also a chat session in the app, so you can hand the SAME id to the `ask` tool: reads and ask then share one ontology boundary. Pass the returned id explicitly as `sessionId` on every subsequent KnowledgeBase tool call (direct MCP calls and inside `call_tool_chain` alike). Returns `{ sessionId }`.',
164
+ path: '/api/agent/tools/start_session',
165
+ inputs: { type: 'object', properties: {}, additionalProperties: false },
166
+ outputs: {
167
+ type: 'object',
168
+ properties: { sessionId: str('The minted session id — pass it as `sessionId` on subsequent KnowledgeBase tool calls and to `ask`.') },
169
+ required: ['sessionId'],
170
+ },
171
+ tags: ['workspace'],
172
+ });
173
+ registry.registerExternalTool(startSessionDef);
174
+ // Mint the session id via the sink and return it (see comment above: one id
175
+ // spans start_session -> reads -> ask, closing the ontology-pollution gap).
176
+ router.post('/agent/tools/start_session', toolAuth,
177
+ // External-only: an internal token already carries its run's sessionId, so
178
+ // minting a new thread mid-run would reset the ontology boundary. Note
179
+ // "external" includes the MCP proxy's `externalProxy` loopback tokens
180
+ // (OAuth/JWT MCP sessions) — the verifier resolves those to
181
+ // `source: 'external'`, and one such session may legitimately mint several
182
+ // per-chat sessionIds over its lifetime.
183
+ requireExternalSource, toolHandler(async (_args, ctx) => {
184
+ const { sessionId } = await sessionSink.createSession(ctx.user.id, new Date());
185
+ return { sessionId };
186
+ }));
187
+ // ── reads ──────────────────────────────────────────────────────────────
188
+ mount({
189
+ name: 'read_file',
190
+ description: 'Read a workspace file as text. Returns `{ path, content }`. Optional `offset`/`limit` slice the content (characters for a file, bytes for a `__tool_chain_spill__/…` ref) — use them to page through large files or a `call_tool_chain` spill rather than reading multi-MB in full. A spill ref is workspace-independent: `branch` is ignored for it.' +
191
+ ONTOLOGY_BOUNDARY_NOTE,
192
+ inputs: {
193
+ type: 'object',
194
+ properties: {
195
+ branch: BRANCH_INPUT,
196
+ path: str('Workspace-relative path, or a `__tool_chain_spill__/…` ref from a truncated `call_tool_chain`.'),
197
+ offset: int('Start character index (default 0).'),
198
+ limit: int('Max characters to return from `offset`.'),
199
+ sessionId: SESSION_ID_INPUT,
200
+ },
201
+ required: ['branch', 'path'],
202
+ additionalProperties: false,
203
+ },
204
+ outputs: {
205
+ type: 'object',
206
+ properties: { path: str('The path that was read (echoes the input).'), content: str('File (or spill) content, sliced if offset/limit were given.') },
207
+ required: ['path', 'content'],
208
+ },
209
+ write: false,
210
+ handler: async (a, ctx) => {
211
+ const p = a.path;
212
+ const offset = typeof a.offset === 'number' ? a.offset : undefined;
213
+ const limit = typeof a.limit === 'number' ? a.limit : undefined;
214
+ if (spillStore.isSpillRef(p)) {
215
+ return { path: p, content: await spillStore.read(p, offset, limit) };
216
+ }
217
+ await recordOntologyRead(sessionOntologyGate, ctx, p);
218
+ await assertCanRead(readGateFor(a.branch, ctx), p);
219
+ const fs = await ctx.getFilesystem(a.branch);
220
+ const content = asText(await fs.readFile(p));
221
+ const start = offset && offset > 0 ? offset : 0;
222
+ const sliced = offset !== undefined || limit !== undefined
223
+ ? content.slice(start, limit !== undefined ? start + limit : undefined)
224
+ : content;
225
+ return { path: p, content: sliced };
226
+ },
227
+ });
228
+ mount({
229
+ name: 'list_files',
230
+ description: 'List a directory. Returns `{ path, entries: [{ name, type, size? }] }`. Omit `path` for the workspace root.' +
231
+ ONTOLOGY_BOUNDARY_NOTE,
232
+ inputs: {
233
+ type: 'object',
234
+ properties: {
235
+ branch: BRANCH_INPUT,
236
+ path: str('Workspace-relative directory (default: root).'),
237
+ sessionId: SESSION_ID_INPUT,
238
+ },
239
+ required: ['branch'],
240
+ additionalProperties: false,
241
+ },
242
+ outputs: {
243
+ type: 'object',
244
+ properties: {
245
+ path: str('The directory listed (empty string for the root).'),
246
+ entries: {
247
+ type: 'array',
248
+ description: 'Directory entries.',
249
+ items: {
250
+ type: 'object',
251
+ properties: { name: str('Entry name.'), type: str('`file` or `directory`.'), size: int('Size in bytes (files only).') },
252
+ required: ['name', 'type'],
253
+ },
254
+ },
255
+ },
256
+ required: ['path', 'entries'],
257
+ },
258
+ write: false,
259
+ handler: async (a, ctx) => {
260
+ const dir = a.path || '';
261
+ await recordOntologyRead(sessionOntologyGate, ctx, dir);
262
+ const fs = await ctx.getFilesystem(a.branch);
263
+ const entries = (await fs.readdir(dir || '.'));
264
+ const filtered = await filterReadableEntries(readGateFor(a.branch, ctx), dir, entries);
265
+ return { path: a.path ?? '', entries: filtered };
266
+ },
267
+ });
268
+ mount({
269
+ name: 'file_stat',
270
+ description: 'Get a file/directory\'s metadata (name, type, size, …) without reading content.' +
271
+ ONTOLOGY_BOUNDARY_NOTE,
272
+ inputs: {
273
+ type: 'object',
274
+ properties: {
275
+ branch: BRANCH_INPUT,
276
+ path: str('Workspace-relative path.'),
277
+ sessionId: SESSION_ID_INPUT,
278
+ },
279
+ required: ['branch', 'path'],
280
+ additionalProperties: false,
281
+ },
282
+ outputs: {
283
+ type: 'object',
284
+ description: "The filesystem entry's metadata.",
285
+ properties: { name: str('Entry name.'), type: str('`file` or `directory`.'), size: int('Size in bytes.') },
286
+ additionalProperties: true,
287
+ },
288
+ write: false,
289
+ handler: async (a, ctx) => {
290
+ const p = a.path;
291
+ await recordOntologyRead(sessionOntologyGate, ctx, p);
292
+ await assertCanRead(readGateFor(a.branch, ctx), p);
293
+ return (await ctx.getFilesystem(a.branch)).stat(p);
294
+ },
295
+ });
296
+ mount({
297
+ name: 'grep',
298
+ description: 'Regex content search across the workspace. Returns `{ matches: [{ path, line, text }] }` (capped). Use to find where something is defined/referenced.' +
299
+ ONTOLOGY_BOUNDARY_NOTE,
300
+ inputs: {
301
+ type: 'object',
302
+ properties: {
303
+ branch: BRANCH_INPUT,
304
+ pattern: str('JavaScript regular expression.'),
305
+ path: str('Subtree to search (default: whole workspace).'),
306
+ ignore_case: { type: 'boolean', description: 'Case-insensitive match.' },
307
+ max_results: { type: 'integer', minimum: 1, maximum: 1000, description: 'Cap on matches (default 200).' },
308
+ sessionId: SESSION_ID_INPUT,
309
+ },
310
+ required: ['branch', 'pattern'],
311
+ additionalProperties: false,
312
+ },
313
+ outputs: {
314
+ type: 'object',
315
+ properties: {
316
+ matches: {
317
+ type: 'array',
318
+ description: 'Matching lines (capped by `max_results`).',
319
+ items: {
320
+ type: 'object',
321
+ properties: { path: str('Workspace-relative file path.'), line: int('1-based line number.'), text: str('The matching line (truncated to 300 chars).') },
322
+ required: ['path', 'line', 'text'],
323
+ },
324
+ },
325
+ truncated: { type: 'boolean', description: 'True if the match cap was hit and results may be incomplete.' },
326
+ },
327
+ required: ['matches', 'truncated'],
328
+ },
329
+ write: false,
330
+ handler: async (a, ctx) => {
331
+ let re;
332
+ try {
333
+ re = new RegExp(a.pattern, a.ignore_case ? 'i' : '');
334
+ }
335
+ catch (err) {
336
+ throw new ToolError(`Invalid regex: ${err.message}`, 400);
337
+ }
338
+ const searchRoot = typeof a.path === 'string' ? a.path : '';
339
+ // The search root itself is checked here (fail-closed for an agent grep on
340
+ // a named subtree with no sessionId); each file the walk actually opens is
341
+ // recorded per-file below, so a root-level grep that reaches into multiple
342
+ // ontologies still records each one (and can poison later writes).
343
+ await recordOntologyRead(sessionOntologyGate, ctx, searchRoot);
344
+ const out = [];
345
+ const max = typeof a.max_results === 'number' ? Math.min(a.max_results, 1000) : 200;
346
+ await grepWalk(await ctx.getFilesystem(a.branch), searchRoot, re, out, max, 0, readGateFor(a.branch, ctx), (p) => recordOntologyRead(sessionOntologyGate, ctx, p));
347
+ return { matches: out, truncated: out.length >= max };
348
+ },
349
+ });
350
+ // ── writes (through the lock/commit pipeline) ───────────────────────────
351
+ mount({
352
+ name: 'write_file',
353
+ description: 'Write (create or overwrite) a workspace file. The change is committed + pushed as you. Returns `{ path, bytes }`.' +
354
+ ONTOLOGY_BOUNDARY_NOTE,
355
+ inputs: {
356
+ type: 'object',
357
+ properties: {
358
+ branch: BRANCH_INPUT,
359
+ path: str('Workspace-relative path.'),
360
+ content: str('Full file content.'),
361
+ sessionId: SESSION_ID_INPUT,
362
+ },
363
+ required: ['branch', 'path', 'content'],
364
+ additionalProperties: false,
365
+ },
366
+ outputs: {
367
+ type: 'object',
368
+ properties: { path: str('The path written (echoes the input).'), bytes: int('Number of bytes written.') },
369
+ required: ['path', 'bytes'],
370
+ },
371
+ write: true,
372
+ handler: async (a, ctx) => {
373
+ // NB: this is a no-op for chat + `ontology_ingest` — it only bites when a
374
+ // routine executor has explicitly restricted THIS session's `ctx.sessionId`
375
+ // (today only `watchlist_check`, to `.html`). Unrestricted sessions pass straight
376
+ // through (see `assertPathWritable`), so it does not limit other agents.
377
+ writePolicy.assertPathWritable(ctx.sessionId, a.path);
378
+ await assertOntologyWriteAllowed(sessionOntologyGate, ctx, a.path);
379
+ const fs = await ctx.getFilesystem(a.branch);
380
+ await fs.writeFile(a.path, a.content);
381
+ return { path: a.path, bytes: Buffer.byteLength(a.content, 'utf8') };
382
+ },
383
+ });
384
+ mount({
385
+ name: 'write_files',
386
+ description: 'Batch-write many files in ONE commit — far faster than calling write_file once per file when ' +
387
+ 'creating many files at once (e.g. seeding a knowledge base). Each entry is `{ path, content }`; all ' +
388
+ 'are created/overwritten and committed + pushed together as you. Prefer this over many write_file ' +
389
+ 'calls. All files must be in the SAME ontology (the boundary below applies to the batch). Returns `{ count }`.' +
390
+ ONTOLOGY_BOUNDARY_NOTE,
391
+ inputs: {
392
+ type: 'object',
393
+ properties: {
394
+ branch: BRANCH_INPUT,
395
+ files: {
396
+ type: 'array',
397
+ description: 'Files to write; each created or overwritten.',
398
+ items: {
399
+ type: 'object',
400
+ properties: { path: str('Workspace-relative path.'), content: str('Full file content.') },
401
+ required: ['path', 'content'],
402
+ additionalProperties: false,
403
+ },
404
+ },
405
+ sessionId: SESSION_ID_INPUT,
406
+ },
407
+ required: ['branch', 'files'],
408
+ additionalProperties: false,
409
+ },
410
+ outputs: {
411
+ type: 'object',
412
+ properties: { count: int('Number of files written.') },
413
+ required: ['count'],
414
+ },
415
+ write: true,
416
+ handler: async (a, ctx) => {
417
+ const files = a.files ?? [];
418
+ if (files.length === 0)
419
+ return { count: 0 };
420
+ // Gate every path first (records ontology touches; a cross-ontology batch
421
+ // is blocked exactly like the per-file write tools).
422
+ for (const f of files)
423
+ writePolicy.assertPathWritable(ctx.sessionId, f.path);
424
+ for (const f of files)
425
+ await assertOntologyWriteAllowed(sessionOntologyGate, ctx, f.path);
426
+ // `write: true` guarantees a LockingFilesystem here; `writeFiles` lands the
427
+ // whole batch as one commit. Structural cast avoids a workflow-internal import.
428
+ const fs = (await ctx.getFilesystem(a.branch));
429
+ await fs.writeFiles(files.map((f) => ({ path: f.path, content: f.content })), `Write ${files.length} file(s)`);
430
+ return { count: files.length };
431
+ },
432
+ });
433
+ mount({
434
+ name: 'edit_file',
435
+ description: 'Replace an exact string in a workspace file. `old_string` must appear exactly once unless `replace_all`. Committed + pushed as you.' +
436
+ ONTOLOGY_BOUNDARY_NOTE,
437
+ inputs: {
438
+ type: 'object',
439
+ properties: {
440
+ branch: BRANCH_INPUT,
441
+ path: str('Workspace-relative path.'),
442
+ old_string: str('Exact text to replace (include enough context to be unique).'),
443
+ new_string: str('Replacement text.'),
444
+ replace_all: { type: 'boolean', description: 'Replace every occurrence instead of requiring a unique match.' },
445
+ sessionId: SESSION_ID_INPUT,
446
+ },
447
+ required: ['branch', 'path', 'old_string', 'new_string'],
448
+ additionalProperties: false,
449
+ },
450
+ outputs: {
451
+ type: 'object',
452
+ properties: { path: str('The path edited (echoes the input).'), replaced: int('Number of occurrences replaced.') },
453
+ required: ['path', 'replaced'],
454
+ },
455
+ write: true,
456
+ handler: async (a, ctx) => {
457
+ writePolicy.assertPathWritable(ctx.sessionId, a.path);
458
+ await assertOntologyWriteAllowed(sessionOntologyGate, ctx, a.path);
459
+ const fs = await ctx.getFilesystem(a.branch);
460
+ const path = a.path;
461
+ const oldStr = a.old_string;
462
+ const newStr = a.new_string;
463
+ const content = asText(await fs.readFile(path));
464
+ const count = oldStr ? content.split(oldStr).length - 1 : 0;
465
+ if (count === 0)
466
+ throw new ToolError('old_string not found in the file.', 400);
467
+ if (count > 1 && a.replace_all !== true) {
468
+ throw new ToolError(`old_string appears ${count} times — add more context to make it unique, or set replace_all.`, 400);
469
+ }
470
+ const updated = a.replace_all === true ? content.split(oldStr).join(newStr) : content.replace(oldStr, newStr);
471
+ await fs.writeFile(path, updated);
472
+ return { path, replaced: a.replace_all === true ? count : 1 };
473
+ },
474
+ });
475
+ mount({
476
+ name: 'delete_file',
477
+ description: 'Delete a workspace file. Committed + pushed as you.' + ONTOLOGY_BOUNDARY_NOTE,
478
+ inputs: {
479
+ type: 'object',
480
+ properties: {
481
+ branch: BRANCH_INPUT,
482
+ path: str('Workspace-relative path.'),
483
+ sessionId: SESSION_ID_INPUT,
484
+ },
485
+ required: ['branch', 'path'],
486
+ additionalProperties: false,
487
+ },
488
+ outputs: {
489
+ type: 'object',
490
+ properties: { path: str('The path deleted (echoes the input).'), deleted: { type: 'boolean', description: 'Always true on success.' } },
491
+ required: ['path', 'deleted'],
492
+ },
493
+ write: true,
494
+ handler: async (a, ctx) => {
495
+ // A delete propagates no cross-ontology information (it removes a node, it
496
+ // doesn't carry bytes from elsewhere), so it is NOT ontology-write-gated — it
497
+ // only records the ontology it touched, like a read. The extension policy
498
+ // DOES apply though: a dashboard-only run must not delete graph `.md` nodes.
499
+ writePolicy.assertPathWritable(ctx.sessionId, a.path);
500
+ await recordOntologyRead(sessionOntologyGate, ctx, a.path);
501
+ await (await ctx.getFilesystem(a.branch)).deleteFile(a.path);
502
+ return { path: a.path, deleted: true };
503
+ },
504
+ });
505
+ mount({
506
+ name: 'mkdir',
507
+ description: 'Create a directory (recursive). An empty dir gets a `.gitkeep` so it persists in git.' + ONTOLOGY_BOUNDARY_NOTE,
508
+ inputs: {
509
+ type: 'object',
510
+ properties: {
511
+ branch: BRANCH_INPUT,
512
+ path: str('Workspace-relative directory.'),
513
+ sessionId: SESSION_ID_INPUT,
514
+ },
515
+ required: ['branch', 'path'],
516
+ additionalProperties: false,
517
+ },
518
+ outputs: {
519
+ type: 'object',
520
+ properties: { path: str('The directory created (echoes the input).'), created: { type: 'boolean', description: 'Always true on success.' } },
521
+ required: ['path', 'created'],
522
+ },
523
+ write: true,
524
+ handler: async (a, ctx) => {
525
+ writePolicy.assertPathWritable(ctx.sessionId, a.path);
526
+ await assertOntologyWriteAllowed(sessionOntologyGate, ctx, a.path);
527
+ await (await ctx.getFilesystem(a.branch)).mkdir(a.path, { recursive: true });
528
+ return { path: a.path, created: true };
529
+ },
530
+ });
531
+ mount({
532
+ name: 'move_file',
533
+ description: 'Move/rename a workspace file. Lands as a delete + create. Committed + pushed as you.' + ONTOLOGY_BOUNDARY_NOTE,
534
+ inputs: {
535
+ type: 'object',
536
+ properties: {
537
+ branch: BRANCH_INPUT,
538
+ src: str('Source path.'),
539
+ dest: str('Destination path.'),
540
+ sessionId: SESSION_ID_INPUT,
541
+ },
542
+ required: ['branch', 'src', 'dest'],
543
+ additionalProperties: false,
544
+ },
545
+ outputs: {
546
+ type: 'object',
547
+ properties: { src: str('Source path (echoes the input).'), dest: str('Destination path (echoes the input).'), moved: { type: 'boolean', description: 'Always true on success.' } },
548
+ required: ['src', 'dest', 'moved'],
549
+ },
550
+ write: true,
551
+ handler: async (a, ctx) => {
552
+ // A move CARRIES the source content into the destination — a genuine
553
+ // cross-ontology flow if the two differ — so BOTH endpoints are write-gated
554
+ // (unlike a plain delete, which moves no content). Check both BEFORE
555
+ // touching disk so a blocked endpoint can't leave the source already deleted.
556
+ writePolicy.assertPathWritable(ctx.sessionId, a.src);
557
+ writePolicy.assertPathWritable(ctx.sessionId, a.dest);
558
+ await assertOntologyWriteAllowed(sessionOntologyGate, ctx, a.src);
559
+ await assertOntologyWriteAllowed(sessionOntologyGate, ctx, a.dest);
560
+ await (await ctx.getFilesystem(a.branch)).moveFile(a.src, a.dest);
561
+ return { src: a.src, dest: a.dest, moved: true };
562
+ },
563
+ });
564
+ mount({
565
+ name: 'copy_file',
566
+ description: 'Copy a workspace file to a new path. Committed + pushed as you.' + ONTOLOGY_BOUNDARY_NOTE,
567
+ inputs: {
568
+ type: 'object',
569
+ properties: {
570
+ branch: BRANCH_INPUT,
571
+ src: str('Source path.'),
572
+ dest: str('Destination path.'),
573
+ sessionId: SESSION_ID_INPUT,
574
+ },
575
+ required: ['branch', 'src', 'dest'],
576
+ additionalProperties: false,
577
+ },
578
+ outputs: {
579
+ type: 'object',
580
+ properties: { src: str('Source path (echoes the input).'), dest: str('Destination path (echoes the input).'), copied: { type: 'boolean', description: 'Always true on success.' } },
581
+ required: ['src', 'dest', 'copied'],
582
+ },
583
+ write: true,
584
+ handler: async (a, ctx) => {
585
+ // A copy CARRIES the source content into the destination — a genuine
586
+ // cross-ontology flow if the two differ — so BOTH endpoints are write-gated.
587
+ // Check both before touching disk.
588
+ writePolicy.assertPathWritable(ctx.sessionId, a.src);
589
+ writePolicy.assertPathWritable(ctx.sessionId, a.dest);
590
+ await assertOntologyWriteAllowed(sessionOntologyGate, ctx, a.src);
591
+ await assertOntologyWriteAllowed(sessionOntologyGate, ctx, a.dest);
592
+ await (await ctx.getFilesystem(a.branch)).copyFile(a.src, a.dest);
593
+ return { src: a.src, dest: a.dest, copied: true };
594
+ },
595
+ });
596
+ mount({
597
+ name: 'unzip',
598
+ description: 'Extract a .zip already in the workspace (defaults to the zip\'s parent). Returns extracted files + skipped entries. Existing files are overwritten.' +
599
+ ONTOLOGY_BOUNDARY_NOTE,
600
+ inputs: {
601
+ type: 'object',
602
+ properties: {
603
+ branch: BRANCH_INPUT,
604
+ path: str('Workspace-relative .zip path.'),
605
+ destination: str("Directory to extract into (default: the zip's parent)."),
606
+ sessionId: SESSION_ID_INPUT,
607
+ },
608
+ required: ['branch', 'path'],
609
+ additionalProperties: false,
610
+ },
611
+ outputs: {
612
+ type: 'object',
613
+ properties: {
614
+ destination: str('Directory the archive was extracted into.'),
615
+ extracted: { type: 'array', items: { type: 'string' }, description: 'Workspace-relative paths of the files written.' },
616
+ skipped: {
617
+ type: 'array',
618
+ description: 'Entries that were not extracted, with the reason.',
619
+ items: {
620
+ type: 'object',
621
+ properties: { path: str('Entry path inside the archive.'), reason: str('Why it was skipped (e.g. unsafe path, size cap).') },
622
+ required: ['path', 'reason'],
623
+ },
624
+ },
625
+ },
626
+ required: ['destination', 'extracted', 'skipped'],
627
+ },
628
+ write: true,
629
+ handler: async (a, ctx) => {
630
+ const zipPath = a.path;
631
+ // Reading the source archive pins/records the source ontology, so a session
632
+ // can't unzip from ontology A into ontology B without the A read counting.
633
+ await recordOntologyRead(sessionOntologyGate, ctx, zipPath);
634
+ return ctx.workspaceService.unzipFile(workspaceIdForBranch(a.branch), zipPath, typeof a.destination === 'string' ? a.destination : undefined,
635
+ // Each extracted file is a write: a cross-ontology or write-blocked entry
636
+ // is skipped (not extracted), so an archive can't bypass the boundary — the
637
+ // extension policy applies per entry too, so a restricted run can't unzip a
638
+ // `.md` into the graph.
639
+ (wsRelPath) => {
640
+ writePolicy.assertPathWritable(ctx.sessionId, wsRelPath);
641
+ return assertOntologyWriteAllowed(sessionOntologyGate, ctx, wsRelPath);
642
+ });
643
+ },
644
+ });
645
+ // ── shell (internal-only) ───────────────────────────────────────────────
646
+ mount({
647
+ name: 'execute_command',
648
+ description: 'Run a shell command in the workspace directory. Returns `{ stdout, stderr, exitCode }` (output capped). Use for git status/log, grep/rg, build/test commands.' +
649
+ ONTOLOGY_BOUNDARY_NOTE,
650
+ internalOnly: true,
651
+ inputs: {
652
+ type: 'object',
653
+ properties: {
654
+ branch: BRANCH_INPUT,
655
+ command: str('The shell command line to run.'),
656
+ timeout_ms: { type: 'integer', minimum: 1000, maximum: 120000, description: 'Timeout in ms (default 30000).' },
657
+ sessionId: SESSION_ID_INPUT,
658
+ },
659
+ required: ['branch', 'command'],
660
+ additionalProperties: false,
661
+ },
662
+ outputs: {
663
+ type: 'object',
664
+ properties: {
665
+ stdout: str('Captured standard output (truncated to 50,000 chars).'),
666
+ stderr: str('Captured standard error (truncated to 50,000 chars).'),
667
+ exitCode: int('Process exit code; -1 if it was killed (timeout/abort) or failed to spawn.'),
668
+ },
669
+ required: ['stdout', 'stderr', 'exitCode'],
670
+ },
671
+ write: true,
672
+ handler: async (a, ctx) => {
673
+ // Refuse a missing branch FIRST — before the policy gates below — so a
674
+ // malformed call always gets the 400 that names what is missing, rather
675
+ // than a 403 from a restricted session masking it. Unlike the file tools
676
+ // (which route through `getOrCreateForUser` and fall back to the default
677
+ // branch), execute_command turns `branch` straight into a workspace — so
678
+ // an absent value would `encodeURIComponent(undefined)` to the string
679
+ // "undefined", then try to CLONE a branch literally named "undefined",
680
+ // 500ing and leaving an `<workspaces>/undefined/` shell behind. Fail with
681
+ // a clear 4xx naming the missing context instead.
682
+ const branch = a.branch;
683
+ if (typeof branch !== 'string' || branch.trim().length === 0) {
684
+ throw new ToolError('execute_command requires a `branch`: pass the branch (draft) whose workspace to run the command in — the one you are currently working on.', 400);
685
+ }
686
+ // Then the SHAPE of the value, via the one canonical validator every other
687
+ // branch path uses — no hand-maintained list of suspicious literals here,
688
+ // which would both miss malformed refs (`..`, `-x`, `foo/.lock`) and
689
+ // reserve names git considers perfectly valid. Note this runs on the RAW
690
+ // string: a whitespace-padded `" main "` is refused rather than silently
691
+ // trimmed into a different branch than the caller passed.
692
+ try {
693
+ assertValidBranchName(branch);
694
+ }
695
+ catch (err) {
696
+ throw new ToolError(`execute_command got an invalid \`branch\`: ${err.message} — ` +
697
+ 'pass the exact branch (draft) whose workspace to run the command in.', 400);
698
+ }
699
+ // Shell is a write path with no single target path to check, so enforce the
700
+ // boundary at the session level: refuse once the run is already write-blocked,
701
+ // or when the run is restricted to a file type (shell could write anything).
702
+ writePolicy.assertUnrestricted(ctx.sessionId);
703
+ await assertShellAllowedWithinOntology(sessionOntologyGate, ctx);
704
+ // Canonical per-branch bootstrap entry point — it owns the workspace-id
705
+ // encoding and the single-flight clone, so the shell never derives a
706
+ // workspace path by hand.
707
+ const cwd = (await ctx.workspaceService.getOrCreateForBranch(branch)).absolutePath;
708
+ const timeoutMs = typeof a.timeout_ms === 'number' ? a.timeout_ms : 30_000;
709
+ // cwd is the workspace ROOT so shell paths match the workspace-relative
710
+ // paths every other file tool uses — but the git clone lives one level
711
+ // deeper, at <workspace>/<kbDirName>/.git. For a bare `git status` /
712
+ // `git diff` (what the agent prompt teaches) point git there explicitly so
713
+ // it resolves the KB clone instead of failing with "not a git repository".
714
+ //
715
+ // Because the command runs under `shell: true`, GIT_DIR/GIT_WORK_TREE
716
+ // apply to the WHOLE shell, so restrict the override to a *standalone* bare
717
+ // `git …` invocation. Otherwise the KB repo context would (a) leak into a
718
+ // chained step that spawns its own git — `git commit && npm ci` — and (b)
719
+ // override a caller's explicit `git -C …` / `--git-dir` / `--work-tree`.
720
+ const command = a.command.trim();
721
+ const isStandaloneGit = /^git(\s|$)/.test(command) &&
722
+ !/[;&|`\n]|\$\(/.test(command) &&
723
+ !/(?:^|\s)(?:-C|--git-dir|--work-tree)(?:[=\s]|$)/.test(command);
724
+ const env = isStandaloneGit
725
+ ? {
726
+ ...process.env,
727
+ GIT_DIR: join(cwd, kbDirName, '.git'),
728
+ GIT_WORK_TREE: join(cwd, kbDirName),
729
+ }
730
+ : process.env;
731
+ return new Promise((resolve) => {
732
+ const child = spawn(a.command, { cwd, shell: true, env });
733
+ let stdout = '';
734
+ let stderr = '';
735
+ const timer = setTimeout(() => child.kill('SIGKILL'), timeoutMs);
736
+ // If the caller disconnects (request aborted), kill the child instead of
737
+ // letting it run to the timeout; the resulting `close`/`error` settles
738
+ // the promise through `finish`.
739
+ const onAbort = () => child.kill('SIGKILL');
740
+ ctx.abortSignal.addEventListener('abort', onAbort, { once: true });
741
+ const finish = (value) => {
742
+ clearTimeout(timer);
743
+ ctx.abortSignal.removeEventListener('abort', onAbort);
744
+ resolve(value);
745
+ };
746
+ // Cap accumulation while streaming so a verbose command can't exhaust
747
+ // memory before `close`; the final slice keeps the output bound.
748
+ const OUTPUT_CAP = 50_000;
749
+ child.stdout.on('data', (d) => {
750
+ if (stdout.length < OUTPUT_CAP)
751
+ stdout += d.toString();
752
+ });
753
+ child.stderr.on('data', (d) => {
754
+ if (stderr.length < OUTPUT_CAP)
755
+ stderr += d.toString();
756
+ });
757
+ child.on('close', (code) => {
758
+ finish({ stdout: stdout.slice(0, 50_000), stderr: stderr.slice(0, 50_000), exitCode: code ?? -1 });
759
+ });
760
+ child.on('error', (err) => {
761
+ finish({ stdout, stderr: `${stderr}\n${String(err)}`.slice(0, 50_000), exitCode: -1 });
762
+ });
763
+ });
764
+ },
765
+ });
766
+ }
767
+ //# sourceMappingURL=workspace.tools.js.map