@bevel-software/platform-core-backend 0.35.0 → 0.37.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 (851) hide show
  1. package/agent-guide/directory-structure.md +1 -1
  2. package/agent-guide/onboarding.md +111 -0
  3. package/agent-guide/start-here.md +1 -0
  4. package/agent-guide/tool-manuals.md +1 -0
  5. package/dist/core/catalog-cache-invalidation.d.ts +2 -2
  6. package/dist/core/catalog-cache-invalidation.d.ts.map +1 -1
  7. package/dist/core/compose-embed.d.ts +2 -2
  8. package/dist/core/compose-embed.d.ts.map +1 -1
  9. package/dist/core/compose-embed.js +1 -1
  10. package/dist/core/compose-embed.js.map +1 -1
  11. package/dist/core/core-ports.d.ts +19 -4
  12. package/dist/core/core-ports.d.ts.map +1 -1
  13. package/dist/core/core-ports.js.map +1 -1
  14. package/dist/core/create-core-server.d.ts.map +1 -1
  15. package/dist/core/create-core-server.js +26 -24
  16. package/dist/core/create-core-server.js.map +1 -1
  17. package/dist/core/create-core-services.d.ts +19 -13
  18. package/dist/core/create-core-services.d.ts.map +1 -1
  19. package/dist/core/create-core-services.js +72 -57
  20. package/dist/core/create-core-services.js.map +1 -1
  21. package/dist/core/lifecycle.d.ts +4 -4
  22. package/dist/core/lifecycle.d.ts.map +1 -1
  23. package/dist/core/lifecycle.js +5 -5
  24. package/dist/core/lifecycle.js.map +1 -1
  25. package/dist/core-config.d.ts +2 -2
  26. package/dist/core-config.js +3 -3
  27. package/dist/core-config.js.map +1 -1
  28. package/dist/index.d.ts +4 -4
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +3 -3
  31. package/dist/index.js.map +1 -1
  32. package/dist/modules/access/access-control.service.js +1 -1
  33. package/dist/modules/access/access-control.service.js.map +1 -1
  34. package/dist/modules/access/access-declarations.d.ts +2 -2
  35. package/dist/modules/access/access-declarations.d.ts.map +1 -1
  36. package/dist/modules/access/access-declarations.js +2 -2
  37. package/dist/modules/access/access-declarations.js.map +1 -1
  38. package/dist/modules/access/access-mutation.service.d.ts +2 -2
  39. package/dist/modules/access/access-mutation.service.d.ts.map +1 -1
  40. package/dist/modules/access/access-mutation.service.js +2 -2
  41. package/dist/modules/access/access-mutation.service.js.map +1 -1
  42. package/dist/modules/access/access-requests.routes.d.ts +2 -2
  43. package/dist/modules/access/access-requests.routes.d.ts.map +1 -1
  44. package/dist/modules/access/access-requests.routes.js +5 -5
  45. package/dist/modules/access/access-requests.routes.js.map +1 -1
  46. package/dist/modules/access/access-requests.service.d.ts +2 -2
  47. package/dist/modules/access/access-requests.service.d.ts.map +1 -1
  48. package/dist/modules/access/access-requests.service.js +11 -11
  49. package/dist/modules/access/access-requests.service.js.map +1 -1
  50. package/dist/modules/access/access.routes.d.ts +2 -2
  51. package/dist/modules/access/access.routes.d.ts.map +1 -1
  52. package/dist/modules/access/access.routes.js +9 -9
  53. package/dist/modules/access/access.routes.js.map +1 -1
  54. package/dist/modules/access/admin-locked-commit.d.ts +5 -5
  55. package/dist/modules/access/admin-locked-commit.d.ts.map +1 -1
  56. package/dist/modules/access/admin-locked-commit.js +7 -7
  57. package/dist/modules/access/admin-locked-commit.js.map +1 -1
  58. package/dist/modules/access/admin-route-helpers.d.ts +1 -1
  59. package/dist/modules/access/admin-route-helpers.js +5 -5
  60. package/dist/modules/access/admin-route-helpers.js.map +1 -1
  61. package/dist/modules/access/change-read-gate.d.ts +1 -1
  62. package/dist/modules/access/change-read-gate.js +1 -1
  63. package/dist/modules/access/groups-admin.service.d.ts +7 -7
  64. package/dist/modules/access/groups-admin.service.d.ts.map +1 -1
  65. package/dist/modules/access/groups-admin.service.js +6 -6
  66. package/dist/modules/access/groups-admin.service.js.map +1 -1
  67. package/dist/modules/access/reference-scan.d.ts +1 -1
  68. package/dist/modules/access/roles-admin.service.d.ts +7 -7
  69. package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
  70. package/dist/modules/access/roles-admin.service.js +8 -8
  71. package/dist/modules/access/roles-admin.service.js.map +1 -1
  72. package/dist/modules/access/synced-groups-committer.d.ts +4 -4
  73. package/dist/modules/access/synced-groups-committer.d.ts.map +1 -1
  74. package/dist/modules/access/synced-groups-committer.js +7 -7
  75. package/dist/modules/access/synced-groups-committer.js.map +1 -1
  76. package/dist/modules/access/user-access-removal.service.d.ts +6 -6
  77. package/dist/modules/access/user-access-removal.service.d.ts.map +1 -1
  78. package/dist/modules/access/user-access-removal.service.js +4 -4
  79. package/dist/modules/access/user-access-removal.service.js.map +1 -1
  80. package/dist/modules/access-model/access-errors.d.ts +4 -4
  81. package/dist/modules/access-model/access-errors.d.ts.map +1 -1
  82. package/dist/modules/access-model/access-errors.js +4 -4
  83. package/dist/modules/access-model/access-errors.js.map +1 -1
  84. package/dist/modules/access-model/access-grammar.d.ts +1 -1
  85. package/dist/modules/access-model/access-grammar.js +4 -4
  86. package/dist/modules/access-model/change-gate.d.ts +1 -1
  87. package/dist/modules/access-model/change-gate.js +1 -1
  88. package/dist/modules/access-model/roles-yaml-guard.d.ts +4 -4
  89. package/dist/modules/access-model/roles-yaml-guard.d.ts.map +1 -1
  90. package/dist/modules/access-model/roles-yaml-guard.js +4 -4
  91. package/dist/modules/access-model/roles-yaml-guard.js.map +1 -1
  92. package/dist/modules/agent-guide/agent-guide.d.ts +19 -14
  93. package/dist/modules/agent-guide/agent-guide.d.ts.map +1 -1
  94. package/dist/modules/agent-guide/agent-guide.js +42 -18
  95. package/dist/modules/agent-guide/agent-guide.js.map +1 -1
  96. package/dist/modules/agent-guide/guide-budget.d.ts +5 -2
  97. package/dist/modules/agent-guide/guide-budget.d.ts.map +1 -1
  98. package/dist/modules/agent-guide/guide-budget.js +6 -2
  99. package/dist/modules/agent-guide/guide-budget.js.map +1 -1
  100. package/dist/modules/agent-instructions/agent-instructions.routes.d.ts +12 -5
  101. package/dist/modules/agent-instructions/agent-instructions.routes.d.ts.map +1 -1
  102. package/dist/modules/agent-instructions/agent-instructions.routes.js +13 -6
  103. package/dist/modules/agent-instructions/agent-instructions.routes.js.map +1 -1
  104. package/dist/modules/agent-instructions/compose.d.ts +15 -8
  105. package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
  106. package/dist/modules/agent-instructions/compose.js +24 -10
  107. package/dist/modules/agent-instructions/compose.js.map +1 -1
  108. package/dist/modules/agent-instructions/shared-file-rules.d.ts +14 -6
  109. package/dist/modules/agent-instructions/shared-file-rules.d.ts.map +1 -1
  110. package/dist/modules/agent-instructions/shared-file-rules.js +51 -11
  111. package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -1
  112. package/dist/modules/auth/account-erasure.service.d.ts +36 -7
  113. package/dist/modules/auth/account-erasure.service.d.ts.map +1 -1
  114. package/dist/modules/auth/account-erasure.service.js +30 -10
  115. package/dist/modules/auth/account-erasure.service.js.map +1 -1
  116. package/dist/modules/auth/account-hooks.d.ts +20 -0
  117. package/dist/modules/auth/account-hooks.d.ts.map +1 -1
  118. package/dist/modules/auth/account-hooks.js +10 -0
  119. package/dist/modules/auth/account-hooks.js.map +1 -1
  120. package/dist/modules/auth/account-switch-lock.js +2 -2
  121. package/dist/modules/auth/account-switch-lock.js.map +1 -1
  122. package/dist/modules/auth/account.routes.d.ts +7 -2
  123. package/dist/modules/auth/account.routes.d.ts.map +1 -1
  124. package/dist/modules/auth/account.routes.js +23 -4
  125. package/dist/modules/auth/account.routes.js.map +1 -1
  126. package/dist/modules/auth/auth.service.d.ts +1 -1
  127. package/dist/modules/auth/auth.service.js +4 -4
  128. package/dist/modules/auth/auth.service.js.map +1 -1
  129. package/dist/modules/auth/index.d.ts +1 -0
  130. package/dist/modules/auth/index.d.ts.map +1 -1
  131. package/dist/modules/database/connection.d.ts.map +1 -1
  132. package/dist/modules/database/connection.js +11 -0
  133. package/dist/modules/database/connection.js.map +1 -1
  134. package/dist/modules/database/core-schema.js +2 -2
  135. package/dist/modules/database/core-schema.js.map +1 -1
  136. package/dist/modules/diff/diff.routes.d.ts +3 -3
  137. package/dist/modules/diff/diff.routes.d.ts.map +1 -1
  138. package/dist/modules/diff/diff.routes.js +7 -7
  139. package/dist/modules/diff/diff.routes.js.map +1 -1
  140. package/dist/modules/embed/embed.routes.js +1 -1
  141. package/dist/modules/embed/embed.routes.js.map +1 -1
  142. package/dist/modules/embed/embed.service.d.ts +4 -4
  143. package/dist/modules/embed/embed.service.d.ts.map +1 -1
  144. package/dist/modules/embed/embed.service.js +18 -18
  145. package/dist/modules/embed/embed.service.js.map +1 -1
  146. package/dist/modules/kb-fs/branch-name.js +8 -8
  147. package/dist/modules/kb-fs/branch-name.js.map +1 -1
  148. package/dist/modules/kb-fs/file-change-notifier.d.ts +51 -26
  149. package/dist/modules/kb-fs/file-change-notifier.d.ts.map +1 -1
  150. package/dist/modules/kb-fs/file-change-notifier.js +6 -8
  151. package/dist/modules/kb-fs/file-change-notifier.js.map +1 -1
  152. package/dist/modules/kb-fs/locking-filesystem.d.ts +9 -16
  153. package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
  154. package/dist/modules/kb-fs/locking-filesystem.js +31 -39
  155. package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
  156. package/dist/modules/kb-fs/repo-path.js +5 -5
  157. package/dist/modules/kb-fs/repo-path.js.map +1 -1
  158. package/dist/modules/kb-fs/tmp-ref.d.ts +2 -2
  159. package/dist/modules/kb-fs/tmp-ref.d.ts.map +1 -1
  160. package/dist/modules/kb-fs/tmp-ref.js +2 -2
  161. package/dist/modules/kb-fs/tmp-ref.js.map +1 -1
  162. package/dist/modules/kb-sync/index.d.ts +1 -1
  163. package/dist/modules/kb-sync/index.d.ts.map +1 -1
  164. package/dist/modules/kb-sync/kb-sync.interface.d.ts +3 -3
  165. package/dist/modules/kb-sync/kb-sync.interface.d.ts.map +1 -1
  166. package/dist/modules/kb-sync/kb-sync.service.d.ts +3 -3
  167. package/dist/modules/kb-sync/kb-sync.service.d.ts.map +1 -1
  168. package/dist/modules/kb-sync/kb-sync.service.js +10 -10
  169. package/dist/modules/kb-sync/kb-sync.service.js.map +1 -1
  170. package/dist/modules/mcp/mcp.service.d.ts +11 -4
  171. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  172. package/dist/modules/mcp/mcp.service.js +75 -19
  173. package/dist/modules/mcp/mcp.service.js.map +1 -1
  174. package/dist/modules/onboarding/onboarding.contract.d.ts +1 -1
  175. package/dist/modules/onboarding/onboarding.routes.js +2 -2
  176. package/dist/modules/onboarding/onboarding.routes.js.map +1 -1
  177. package/dist/modules/onboarding/starter-pack.service.d.ts +5 -7
  178. package/dist/modules/onboarding/starter-pack.service.d.ts.map +1 -1
  179. package/dist/modules/onboarding/starter-pack.service.js +4 -4
  180. package/dist/modules/onboarding/starter-pack.service.js.map +1 -1
  181. package/dist/modules/plugins/join-request-jobs.service.d.ts +2 -2
  182. package/dist/modules/plugins/join-request-jobs.service.d.ts.map +1 -1
  183. package/dist/modules/plugins/join-request-jobs.service.js +7 -7
  184. package/dist/modules/plugins/join-request-jobs.service.js.map +1 -1
  185. package/dist/modules/plugins/join-requests.service.d.ts +3 -3
  186. package/dist/modules/plugins/join-requests.service.d.ts.map +1 -1
  187. package/dist/modules/plugins/join-requests.service.js +5 -5
  188. package/dist/modules/plugins/join-requests.service.js.map +1 -1
  189. package/dist/modules/plugins/plugin-rename.service.js +1 -1
  190. package/dist/modules/plugins/plugin-rename.service.js.map +1 -1
  191. package/dist/modules/plugins/plugins.routes.d.ts +2 -2
  192. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  193. package/dist/modules/plugins/plugins.routes.js +8 -8
  194. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  195. package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +77 -2
  196. package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -1
  197. package/dist/modules/secrets-vault/db-secrets-vault.service.js +479 -53
  198. package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -1
  199. package/dist/modules/secrets-vault/index.d.ts +2 -1
  200. package/dist/modules/secrets-vault/index.d.ts.map +1 -1
  201. package/dist/modules/secrets-vault/index.js +1 -0
  202. package/dist/modules/secrets-vault/index.js.map +1 -1
  203. package/dist/modules/secrets-vault/managed-sign-in-erasure.d.ts +36 -0
  204. package/dist/modules/secrets-vault/managed-sign-in-erasure.d.ts.map +1 -0
  205. package/dist/modules/secrets-vault/managed-sign-in-erasure.js +37 -0
  206. package/dist/modules/secrets-vault/managed-sign-in-erasure.js.map +1 -0
  207. package/dist/modules/secrets-vault/secrets-vault.contract.d.ts +152 -0
  208. package/dist/modules/secrets-vault/secrets-vault.contract.d.ts.map +1 -1
  209. package/dist/modules/secrets-vault/secrets-vault.contract.js.map +1 -1
  210. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +7 -1
  211. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
  212. package/dist/modules/secrets-vault/secrets-vault.routes.js +125 -10
  213. package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
  214. package/dist/modules/settings/connection-check.js +1 -1
  215. package/dist/modules/settings/connection-check.js.map +1 -1
  216. package/dist/modules/settings/deployment-settings.service.js +1 -1
  217. package/dist/modules/settings/git-root-folders.js +1 -1
  218. package/dist/modules/settings/git-root-folders.js.map +1 -1
  219. package/dist/modules/settings/setup.routes.d.ts +1 -1
  220. package/dist/modules/settings/setup.routes.js +1 -1
  221. package/dist/modules/skills/pending-skills.service.d.ts +3 -3
  222. package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
  223. package/dist/modules/skills/pending-skills.service.js +4 -4
  224. package/dist/modules/skills/pending-skills.service.js.map +1 -1
  225. package/dist/modules/skills/skill-access-requests.routes.d.ts +2 -2
  226. package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -1
  227. package/dist/modules/skills/skill-access-requests.routes.js +5 -5
  228. package/dist/modules/skills/skill-access-requests.routes.js.map +1 -1
  229. package/dist/modules/tool-helpers/tool-context.d.ts +4 -4
  230. package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
  231. package/dist/modules/tool-helpers/tool-context.js +2 -2
  232. package/dist/modules/tool-helpers/tool-context.js.map +1 -1
  233. package/dist/modules/tool-helpers/tool-handler.js +2 -2
  234. package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
  235. package/dist/modules/tool-helpers/tool.contract.d.ts +4 -4
  236. package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
  237. package/dist/modules/tool-manuals/mcp-server-edit.service.js +1 -1
  238. package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
  239. package/dist/modules/tool-manuals/pending-tools.service.d.ts +3 -3
  240. package/dist/modules/tool-manuals/pending-tools.service.d.ts.map +1 -1
  241. package/dist/modules/tool-manuals/pending-tools.service.js +4 -4
  242. package/dist/modules/tool-manuals/pending-tools.service.js.map +1 -1
  243. package/dist/modules/tool-manuals/tool-delete.service.js +1 -1
  244. package/dist/modules/tool-manuals/tool-delete.service.js.map +1 -1
  245. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +43 -3
  246. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
  247. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +6 -0
  248. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  249. package/dist/modules/tool-manuals/tool-manuals.service.js +51 -5
  250. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  251. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +3 -0
  252. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  253. package/dist/modules/tool-manuals/tool-manuals.tools.js +36 -15
  254. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  255. package/dist/modules/version-control/agent-tools/change-request-read-shape.d.ts.map +1 -0
  256. package/dist/modules/version-control/agent-tools/change-request-read-shape.js.map +1 -0
  257. package/dist/modules/version-control/agent-tools/change-request-read.tools.d.ts.map +1 -0
  258. package/dist/modules/{workflow → version-control}/agent-tools/change-request-read.tools.js +2 -2
  259. package/dist/modules/version-control/agent-tools/change-request-read.tools.js.map +1 -0
  260. package/dist/modules/version-control/agent-tools/change-request-summary.d.ts.map +1 -0
  261. package/dist/modules/version-control/agent-tools/change-request-summary.js.map +1 -0
  262. package/dist/modules/{workflow/agent-tools/workflow.tools.d.ts → version-control/agent-tools/version-control.tools.d.ts} +4 -4
  263. package/dist/modules/version-control/agent-tools/version-control.tools.d.ts.map +1 -0
  264. package/dist/modules/{workflow/agent-tools/workflow.tools.js → version-control/agent-tools/version-control.tools.js} +31 -31
  265. package/dist/modules/version-control/agent-tools/version-control.tools.js.map +1 -0
  266. package/dist/modules/{workflow → version-control}/change-request-hooks.d.ts +1 -1
  267. package/dist/modules/version-control/change-request-hooks.d.ts.map +1 -0
  268. package/dist/modules/version-control/change-request-hooks.js.map +1 -0
  269. package/dist/modules/version-control/change-request-review/approval-lock.d.ts.map +1 -0
  270. package/dist/modules/version-control/change-request-review/approval-lock.js.map +1 -0
  271. package/dist/modules/{workflow/review-workflow/review-workflow.interface.d.ts → version-control/change-request-review/change-request-review.interface.d.ts} +2 -2
  272. package/dist/modules/version-control/change-request-review/change-request-review.interface.d.ts.map +1 -0
  273. package/dist/modules/version-control/change-request-review/change-request-review.interface.js +2 -0
  274. package/dist/modules/version-control/change-request-review/change-request-review.interface.js.map +1 -0
  275. package/dist/modules/{workflow/review-workflow/review-workflow.service.d.ts → version-control/change-request-review/change-request-review.service.d.ts} +3 -3
  276. package/dist/modules/version-control/change-request-review/change-request-review.service.d.ts.map +1 -0
  277. package/dist/modules/{workflow/review-workflow/review-workflow.service.js → version-control/change-request-review/change-request-review.service.js} +26 -26
  278. package/dist/modules/version-control/change-request-review/change-request-review.service.js.map +1 -0
  279. package/dist/modules/{workflow → version-control}/event-bus.d.ts +8 -8
  280. package/dist/modules/version-control/event-bus.d.ts.map +1 -0
  281. package/dist/modules/{workflow → version-control}/event-bus.js +4 -4
  282. package/dist/modules/version-control/event-bus.js.map +1 -0
  283. package/dist/modules/{workflow → version-control}/events-delivery.d.ts +4 -4
  284. package/dist/modules/version-control/events-delivery.d.ts.map +1 -0
  285. package/dist/modules/version-control/events-delivery.js.map +1 -0
  286. package/dist/modules/{workflow → version-control}/events.routes.d.ts +4 -4
  287. package/dist/modules/version-control/events.routes.d.ts.map +1 -0
  288. package/dist/modules/version-control/events.routes.js.map +1 -0
  289. package/dist/modules/{workflow → version-control}/file-lock.service.d.ts +2 -2
  290. package/dist/modules/version-control/file-lock.service.d.ts.map +1 -0
  291. package/dist/modules/{workflow → version-control}/file-lock.service.js +6 -6
  292. package/dist/modules/version-control/file-lock.service.js.map +1 -0
  293. package/dist/modules/version-control/git/change-request-link.d.ts.map +1 -0
  294. package/dist/modules/version-control/git/change-request-link.js.map +1 -0
  295. package/dist/modules/version-control/git/git-version.d.ts.map +1 -0
  296. package/dist/modules/version-control/git/git-version.js.map +1 -0
  297. package/dist/modules/{workflow → version-control}/git/git.service.d.ts +26 -8
  298. package/dist/modules/version-control/git/git.service.d.ts.map +1 -0
  299. package/dist/modules/{workflow → version-control}/git/git.service.js +106 -55
  300. package/dist/modules/version-control/git/git.service.js.map +1 -0
  301. package/dist/modules/version-control/git/merge-commit.d.ts.map +1 -0
  302. package/dist/modules/version-control/git/merge-commit.js.map +1 -0
  303. package/dist/modules/version-control/git/node-git-runner.d.ts.map +1 -0
  304. package/dist/modules/{workflow → version-control}/git/node-git-runner.js +1 -1
  305. package/dist/modules/version-control/git/node-git-runner.js.map +1 -0
  306. package/dist/modules/{workflow → version-control}/git/pull-request.service.d.ts +5 -5
  307. package/dist/modules/version-control/git/pull-request.service.d.ts.map +1 -0
  308. package/dist/modules/{workflow → version-control}/git/pull-request.service.js +10 -10
  309. package/dist/modules/version-control/git/pull-request.service.js.map +1 -0
  310. package/dist/modules/{workflow → version-control}/index.d.ts +6 -5
  311. package/dist/modules/version-control/index.d.ts.map +1 -0
  312. package/dist/modules/{workflow → version-control}/index.js +3 -2
  313. package/dist/modules/version-control/index.js.map +1 -0
  314. package/dist/modules/{workflow → version-control}/pending-commits.service.d.ts +2 -2
  315. package/dist/modules/version-control/pending-commits.service.d.ts.map +1 -0
  316. package/dist/modules/{workflow → version-control}/pending-commits.service.js +2 -2
  317. package/dist/modules/version-control/pending-commits.service.js.map +1 -0
  318. package/dist/modules/{workflow → version-control}/pending-commits.worker.d.ts +5 -5
  319. package/dist/modules/version-control/pending-commits.worker.d.ts.map +1 -0
  320. package/dist/modules/{workflow → version-control}/pending-commits.worker.js +3 -3
  321. package/dist/modules/version-control/pending-commits.worker.js.map +1 -0
  322. package/dist/modules/{workflow → version-control}/read-on-branch.d.ts +2 -2
  323. package/dist/modules/version-control/read-on-branch.d.ts.map +1 -0
  324. package/dist/modules/{workflow → version-control}/read-on-branch.js +2 -2
  325. package/dist/modules/version-control/read-on-branch.js.map +1 -0
  326. package/dist/modules/version-control/recovery-bot.d.ts.map +1 -0
  327. package/dist/modules/version-control/recovery-bot.js.map +1 -0
  328. package/dist/modules/version-control/sanitize-error.d.ts.map +1 -0
  329. package/dist/modules/version-control/sanitize-error.js.map +1 -0
  330. package/dist/modules/{workflow/workflow-hooks.d.ts → version-control/version-control-hooks.d.ts} +33 -6
  331. package/dist/modules/version-control/version-control-hooks.d.ts.map +1 -0
  332. package/dist/modules/{workflow/workflow-hooks.js → version-control/version-control-hooks.js} +20 -3
  333. package/dist/modules/version-control/version-control-hooks.js.map +1 -0
  334. package/dist/modules/{workflow/workflow.routes.d.ts → version-control/version-control.routes.d.ts} +6 -5
  335. package/dist/modules/version-control/version-control.routes.d.ts.map +1 -0
  336. package/dist/modules/{workflow/workflow.routes.js → version-control/version-control.routes.js} +61 -60
  337. package/dist/modules/version-control/version-control.routes.js.map +1 -0
  338. package/dist/modules/{workflow/workflow.service.d.ts → version-control/version-control.service.d.ts} +26 -46
  339. package/dist/modules/version-control/version-control.service.d.ts.map +1 -0
  340. package/dist/modules/{workflow/workflow.service.js → version-control/version-control.service.js} +93 -107
  341. package/dist/modules/version-control/version-control.service.js.map +1 -0
  342. package/dist/modules/workspace/agent-access.gate.d.ts +5 -5
  343. package/dist/modules/workspace/agent-access.gate.d.ts.map +1 -1
  344. package/dist/modules/workspace/agent-access.gate.js +1 -1
  345. package/dist/modules/workspace/git-internals.middleware.d.ts +1 -1
  346. package/dist/modules/workspace/git-internals.middleware.js +2 -2
  347. package/dist/modules/workspace/kb-repository.js +1 -1
  348. package/dist/modules/workspace/kb-repository.js.map +1 -1
  349. package/dist/modules/workspace/startup/kb-git.d.ts +1 -1
  350. package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -1
  351. package/dist/modules/workspace/startup/kb-git.js +1 -1
  352. package/dist/modules/workspace/startup/kb-git.js.map +1 -1
  353. package/dist/modules/workspace/startup/steps/seed-tree.d.ts +2 -2
  354. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  355. package/dist/modules/workspace/startup/steps/seed-tree.js +1 -1
  356. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  357. package/dist/modules/workspace/startup/steps/template-files.step.d.ts +2 -2
  358. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
  359. package/dist/modules/workspace/startup/steps/template-files.step.js +2 -2
  360. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
  361. package/dist/modules/workspace/startup/steps/template-source.d.ts +17 -4
  362. package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
  363. package/dist/modules/workspace/startup/steps/template-source.js +8 -5
  364. package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
  365. package/dist/modules/workspace/workspace-tmp.js +3 -3
  366. package/dist/modules/workspace/workspace-tmp.js.map +1 -1
  367. package/dist/modules/workspace/workspace.routes.d.ts +4 -4
  368. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  369. package/dist/modules/workspace/workspace.routes.js +22 -22
  370. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  371. package/dist/modules/workspace/workspace.service.d.ts +6 -6
  372. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  373. package/dist/modules/workspace/workspace.service.js +11 -11
  374. package/dist/modules/workspace/workspace.service.js.map +1 -1
  375. package/dist/modules/workspace/workspace.tools.d.ts +2 -1
  376. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  377. package/dist/modules/workspace/workspace.tools.js +15 -10
  378. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  379. package/dist/shared/canonical-file-identity.d.ts +2 -2
  380. package/dist/shared/canonical-file-identity.js +5 -5
  381. package/dist/shared/canonical-file-identity.js.map +1 -1
  382. package/dist/shared/domain-errors.d.ts +39 -39
  383. package/dist/shared/domain-errors.d.ts.map +1 -1
  384. package/dist/shared/domain-errors.js +44 -44
  385. package/dist/shared/domain-errors.js.map +1 -1
  386. package/dist/shared/fire-and-forget.d.ts +14 -0
  387. package/dist/shared/fire-and-forget.d.ts.map +1 -0
  388. package/dist/shared/fire-and-forget.js +23 -0
  389. package/dist/shared/fire-and-forget.js.map +1 -0
  390. package/dist/shared/git.contract.d.ts +1 -1
  391. package/dist/shared/git.contract.js +1 -1
  392. package/dist/shared/http-errors.d.ts +3 -3
  393. package/dist/shared/http-errors.d.ts.map +1 -1
  394. package/dist/shared/http-errors.js +1 -1
  395. package/dist/shared/http-errors.js.map +1 -1
  396. package/dist/shared/pending-proposals.d.ts +3 -3
  397. package/dist/shared/pending-proposals.d.ts.map +1 -1
  398. package/dist/shared/pending-proposals.js +2 -2
  399. package/dist/shared/pending-proposals.js.map +1 -1
  400. package/dist/tenancy/static-tenant-source.js +1 -1
  401. package/dist/tenancy/static-tenant-source.js.map +1 -1
  402. package/migrations/0012_agent_audit.sql +40 -40
  403. package/migrations/0013_agent_identity_and_key_soft_delete.sql +29 -29
  404. package/migrations/meta/0012_snapshot.json +2246 -2246
  405. package/migrations/meta/0013_snapshot.json +2258 -2258
  406. package/package.json +4 -4
  407. package/src/__tests__/account-admin.ts +27 -0
  408. package/src/__tests__/capturing-logger.ts +36 -0
  409. package/src/__tests__/hexis-catalog.ts +4 -4
  410. package/src/__tests__/kb-context.ts +30 -30
  411. package/src/__tests__/kb-layout-config.test.ts +21 -0
  412. package/src/__tests__/open-change-gate.ts +1 -1
  413. package/src/__tests__/real-access.ts +16 -0
  414. package/src/__tests__/real-auth.ts +13 -0
  415. package/src/__tests__/real-readers.ts +27 -0
  416. package/src/__tests__/real-version-control.ts +22 -0
  417. package/src/__tests__/tool-handler.ts +15 -0
  418. package/src/__tests__/tool-wiring.ts +10 -4
  419. package/src/__tests__/workspace-service.ts +1 -1
  420. package/src/core/__tests__/catalog-cache-invalidation.test.ts +3 -3
  421. package/src/core/__tests__/commit-announcements-wired-once.test.ts +53 -0
  422. package/src/core/__tests__/compose-embed.test.ts +1 -1
  423. package/src/core/__tests__/damaged-document.tools.test.ts +3 -3
  424. package/src/core/__tests__/erasure-slices-wired-once.test.ts +46 -0
  425. package/src/core/__tests__/gated-boot.test.ts +2 -2
  426. package/src/core/__tests__/lifecycle.test.ts +9 -9
  427. package/src/core/catalog-cache-invalidation.ts +2 -2
  428. package/src/core/compose-embed.ts +3 -3
  429. package/src/core/core-ports.ts +19 -4
  430. package/src/core/create-core-server.ts +39 -25
  431. package/src/core/create-core-services.ts +83 -65
  432. package/src/core/lifecycle.ts +9 -9
  433. package/src/core-config.ts +3 -3
  434. package/src/index.ts +5 -5
  435. package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +4 -4
  436. package/src/modules/access/__tests__/access-own-read-grant.test.ts +14 -14
  437. package/src/modules/access/__tests__/access-requests.routes.test.ts +23 -23
  438. package/src/modules/access/__tests__/access.routes.admins.test.ts +4 -4
  439. package/src/modules/access/__tests__/access.routes.batch.test.ts +4 -4
  440. package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +6 -6
  441. package/src/modules/access/__tests__/access.routes.group-grant.test.ts +6 -6
  442. package/src/modules/access/__tests__/access.routes.overrides.test.ts +5 -5
  443. package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +6 -6
  444. package/src/modules/access/__tests__/access.routes.prospective.test.ts +3 -3
  445. package/src/modules/access/__tests__/access.routes.revoke.test.ts +6 -6
  446. package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +6 -6
  447. package/src/modules/access/__tests__/admin-locked-commit.test.ts +6 -6
  448. package/src/modules/access/__tests__/admin-route-helpers.test.ts +5 -5
  449. package/src/modules/access/__tests__/groups-admin.service.test.ts +44 -44
  450. package/src/modules/access/__tests__/roles-admin.security.test.ts +14 -13
  451. package/src/modules/access/__tests__/roles-admin.service.test.ts +34 -34
  452. package/src/modules/access/__tests__/roles-capabilities.test.ts +29 -29
  453. package/src/modules/access/__tests__/roles.routes.test.ts +11 -11
  454. package/src/modules/access/__tests__/synced-groups-committer.test.ts +14 -14
  455. package/src/modules/access/__tests__/user-access-removal.service.test.ts +33 -33
  456. package/src/modules/access/access-control.service.ts +1 -1
  457. package/src/modules/access/access-declarations.ts +2 -2
  458. package/src/modules/access/access-mutation.service.ts +2 -2
  459. package/src/modules/access/access-requests.routes.ts +7 -7
  460. package/src/modules/access/access-requests.service.ts +13 -13
  461. package/src/modules/access/access.routes.ts +11 -11
  462. package/src/modules/access/admin-locked-commit.ts +11 -11
  463. package/src/modules/access/admin-route-helpers.ts +5 -5
  464. package/src/modules/access/change-read-gate.ts +1 -1
  465. package/src/modules/access/groups-admin.service.ts +7 -7
  466. package/src/modules/access/reference-scan.ts +1 -1
  467. package/src/modules/access/roles-admin.service.ts +9 -9
  468. package/src/modules/access/synced-groups-committer.ts +11 -11
  469. package/src/modules/access/user-access-removal.service.ts +7 -7
  470. package/src/modules/access-model/__tests__/access-grammar.test.ts +2 -2
  471. package/src/modules/access-model/access-errors.ts +4 -4
  472. package/src/modules/access-model/access-grammar.ts +4 -4
  473. package/src/modules/access-model/change-gate.ts +1 -1
  474. package/src/modules/access-model/roles-yaml-guard.ts +4 -4
  475. package/src/modules/agent-guide/__tests__/agent-guide.test.ts +19 -4
  476. package/src/modules/agent-guide/__tests__/agent-guide.tools.test.ts +1 -1
  477. package/src/modules/agent-guide/__tests__/guide-matches-code.test.ts +2 -2
  478. package/src/modules/agent-guide/agent-guide.ts +48 -22
  479. package/src/modules/agent-guide/guide-budget.ts +6 -2
  480. package/src/modules/agent-instructions/__tests__/agent-instructions.route.test.ts +4 -5
  481. package/src/modules/agent-instructions/__tests__/compose.test.ts +1 -1
  482. package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +113 -7
  483. package/src/modules/agent-instructions/agent-instructions.routes.ts +12 -5
  484. package/src/modules/agent-instructions/compose.ts +24 -9
  485. package/src/modules/agent-instructions/shared-file-rules.ts +53 -11
  486. package/src/modules/agent-scope/__tests__/agent-surfaces.connect-as.test.ts +1 -1
  487. package/src/modules/audit/__tests__/agent-rest-audit.middleware.test.ts +113 -113
  488. package/src/modules/audit/__tests__/event-classifier.test.ts +121 -121
  489. package/src/modules/audit/event-classifier.ts +155 -155
  490. package/src/modules/auth/__tests__/account-deactivation.test.ts +1 -1
  491. package/src/modules/auth/__tests__/account-erasure.approval-gate.test.ts +4 -4
  492. package/src/modules/auth/__tests__/account-erasure.participants.test.ts +56 -0
  493. package/src/modules/auth/__tests__/account-switch-lock.pg.test.ts +2 -2
  494. package/src/modules/auth/__tests__/account-switch-lock.test.ts +2 -2
  495. package/src/modules/auth/__tests__/account.routes.test.ts +73 -11
  496. package/src/modules/auth/__tests__/auth.service.test.ts +1 -1
  497. package/src/modules/auth/account-erasure.service.ts +27 -9
  498. package/src/modules/auth/account-hooks.ts +34 -0
  499. package/src/modules/auth/account-switch-lock.ts +2 -2
  500. package/src/modules/auth/account.routes.ts +23 -5
  501. package/src/modules/auth/auth.service.ts +4 -4
  502. package/src/modules/auth/index.ts +1 -0
  503. package/src/modules/database/__tests__/advisory-lock.test.ts +169 -169
  504. package/src/modules/database/__tests__/connection.pg.test.ts +55 -0
  505. package/src/modules/database/__tests__/connection.test.ts +30 -0
  506. package/src/modules/database/__tests__/migrations-unqualified.test.ts +32 -32
  507. package/src/modules/database/connection.ts +12 -0
  508. package/src/modules/database/core-schema.ts +2 -2
  509. package/src/modules/diff/__tests__/diff.routes.read-gate.test.ts +2 -2
  510. package/src/modules/diff/__tests__/diff.routes.rejectPathsLocked.test.ts +12 -12
  511. package/src/modules/diff/diff.routes.ts +8 -8
  512. package/src/modules/embed/__tests__/embed.service.lock.test.ts +7 -7
  513. package/src/modules/embed/__tests__/embed.service.test.ts +48 -62
  514. package/src/modules/embed/__tests__/embed.tools.test.ts +1 -1
  515. package/src/modules/embed/embed.routes.ts +1 -1
  516. package/src/modules/embed/embed.service.ts +17 -17
  517. package/src/modules/kb-fs/__tests__/branch-name.test.ts +2 -2
  518. package/src/modules/kb-fs/__tests__/file-change-notifier.test.ts +23 -4
  519. package/src/modules/kb-fs/__tests__/locking-filesystem.test.ts +264 -305
  520. package/src/modules/kb-fs/__tests__/move-with-edits.test.ts +103 -40
  521. package/src/modules/kb-fs/__tests__/repo-path.test.ts +8 -8
  522. package/src/modules/kb-fs/branch-name.ts +8 -8
  523. package/src/modules/kb-fs/file-change-notifier.ts +55 -32
  524. package/src/modules/kb-fs/locking-filesystem.ts +34 -48
  525. package/src/modules/kb-fs/repo-path.ts +5 -5
  526. package/src/modules/kb-fs/tmp-ref.ts +3 -3
  527. package/src/modules/kb-sync/__tests__/kb-sync.service.test.ts +36 -36
  528. package/src/modules/kb-sync/index.ts +1 -1
  529. package/src/modules/kb-sync/kb-sync.interface.ts +3 -3
  530. package/src/modules/kb-sync/kb-sync.service.ts +9 -9
  531. package/src/modules/marketplace/__tests__/github-facade.test.ts +1 -1
  532. package/src/modules/marketplace/__tests__/marketplace-git.test.ts +1 -1
  533. package/src/modules/mcp/__tests__/mcp-proxy-helpers.test.ts +4 -2
  534. package/src/modules/mcp/__tests__/mcp.e2e.test.ts +69 -8
  535. package/src/modules/mcp/__tests__/mcp.service.test.ts +91 -13
  536. package/src/modules/mcp/__tests__/read-only-hint.pg.test.ts +194 -0
  537. package/src/modules/mcp/mcp.service.ts +89 -28
  538. package/src/modules/onboarding/__tests__/starter-pack.service.test.ts +59 -59
  539. package/src/modules/onboarding/onboarding.contract.ts +1 -1
  540. package/src/modules/onboarding/onboarding.routes.ts +2 -2
  541. package/src/modules/onboarding/starter-pack.service.ts +7 -9
  542. package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +1 -1
  543. package/src/modules/plugins/__tests__/compile-marketplace.test.ts +1 -1
  544. package/src/modules/plugins/__tests__/join-request-jobs.service.test.ts +43 -43
  545. package/src/modules/plugins/__tests__/join-requests.service.test.ts +19 -19
  546. package/src/modules/plugins/__tests__/join-requests.settlement.test.ts +26 -26
  547. package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +46 -21
  548. package/src/modules/plugins/__tests__/plugins.routes.test.ts +31 -31
  549. package/src/modules/plugins/join-request-jobs.service.ts +10 -10
  550. package/src/modules/plugins/join-requests.service.ts +4 -4
  551. package/src/modules/plugins/plugin-rename.service.ts +1 -1
  552. package/src/modules/plugins/plugins.routes.ts +9 -9
  553. package/src/modules/secrets-vault/__tests__/db-secrets-vault.managed.test.ts +773 -0
  554. package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +28 -1
  555. package/src/modules/secrets-vault/__tests__/managed-sign-in.route.test.ts +351 -0
  556. package/src/modules/secrets-vault/db-secrets-vault.service.ts +562 -95
  557. package/src/modules/secrets-vault/index.ts +7 -0
  558. package/src/modules/secrets-vault/managed-sign-in-erasure.ts +41 -0
  559. package/src/modules/secrets-vault/secrets-variable-loader.ts +134 -134
  560. package/src/modules/secrets-vault/secrets-vault.contract.ts +152 -0
  561. package/src/modules/secrets-vault/secrets-vault.routes.ts +157 -10
  562. package/src/modules/settings/__tests__/repository-source.test.ts +1 -1
  563. package/src/modules/settings/__tests__/setup.routes.layout-phase.test.ts +1 -1
  564. package/src/modules/settings/__tests__/setup.routes.managed-phase.test.ts +1 -1
  565. package/src/modules/settings/connection-check.ts +1 -1
  566. package/src/modules/settings/deployment-settings.service.ts +1 -1
  567. package/src/modules/settings/git-root-folders.ts +1 -1
  568. package/src/modules/settings/setup.routes.ts +1 -1
  569. package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +3 -3
  570. package/src/modules/skills/__tests__/branch-skills.tools.test.ts +1 -1
  571. package/src/modules/skills/__tests__/pending-skills.service.test.ts +8 -8
  572. package/src/modules/skills/__tests__/skill-access-requests.routes.test.ts +18 -18
  573. package/src/modules/skills/__tests__/skills.service.test.ts +3 -3
  574. package/src/modules/skills/pending-skills.service.ts +3 -3
  575. package/src/modules/skills/skill-access-requests.routes.ts +7 -7
  576. package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +4 -4
  577. package/src/modules/tool-helpers/__tests__/branch-declaration.test.ts +3 -3
  578. package/src/modules/tool-helpers/__tests__/can-write.tools.test.ts +3 -3
  579. package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +4 -4
  580. package/src/modules/tool-helpers/__tests__/tools-surface.test.ts +3 -3
  581. package/src/modules/tool-helpers/__tests__/validate-token.test.ts +1 -1
  582. package/src/modules/tool-helpers/tool-context.ts +6 -6
  583. package/src/modules/tool-helpers/tool-handler.ts +2 -2
  584. package/src/modules/tool-helpers/tool.contract.ts +4 -4
  585. package/src/modules/tool-manuals/__tests__/pending-tools.service.test.ts +9 -9
  586. package/src/modules/tool-manuals/__tests__/tool-manuals.managed-sign-in.test.ts +89 -0
  587. package/src/modules/tool-manuals/__tests__/tool-manuals.restart.test.ts +1 -1
  588. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +36 -1
  589. package/src/modules/tool-manuals/mcp-server-edit.service.ts +1 -1
  590. package/src/modules/tool-manuals/pending-tools.service.ts +3 -3
  591. package/src/modules/tool-manuals/tool-delete.service.ts +1 -1
  592. package/src/modules/tool-manuals/tool-manuals.contract.ts +41 -3
  593. package/src/modules/tool-manuals/tool-manuals.service.ts +53 -5
  594. package/src/modules/tool-manuals/tool-manuals.tools.ts +41 -15
  595. package/src/modules/tool-registry/__tests__/own-tool-schemas.test.ts +4 -4
  596. package/src/modules/tool-registry/__tests__/read-only-hints.test.ts +3 -3
  597. package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +6 -6
  598. package/src/modules/{workflow → version-control}/__tests__/apply-failure.test.ts +54 -54
  599. package/src/modules/{workflow → version-control}/__tests__/event-bus.test.ts +27 -27
  600. package/src/modules/{workflow → version-control}/__tests__/events-delivery.test.ts +37 -37
  601. package/src/modules/{workflow → version-control}/__tests__/file-lock.service.deletion-gate.test.ts +2 -2
  602. package/src/modules/{workflow → version-control}/__tests__/file-lock.service.path-identity.test.ts +8 -8
  603. package/src/modules/{workflow → version-control}/__tests__/merge-announces-tree.test.ts +11 -11
  604. package/src/modules/{workflow → version-control}/__tests__/pending-commits.worker.concurrency.test.ts +9 -9
  605. package/src/modules/{workflow → version-control}/__tests__/pending-commits.worker.test.ts +25 -25
  606. package/src/modules/{workflow → version-control}/__tests__/preserve-roles-yaml.test.ts +42 -42
  607. package/src/modules/version-control/__tests__/public-surface.test.ts +114 -0
  608. package/src/modules/{workflow/__tests__/workflow.routes.folder-proposals.test.ts → version-control/__tests__/version-control.routes.folder-proposals.test.ts} +18 -18
  609. package/src/modules/{workflow/__tests__/workflow.routes.fork-point-file.test.ts → version-control/__tests__/version-control.routes.fork-point-file.test.ts} +19 -19
  610. package/src/modules/{workflow/__tests__/workflow.routes.history-read-gate.test.ts → version-control/__tests__/version-control.routes.history-read-gate.test.ts} +13 -13
  611. package/src/modules/{workflow/__tests__/workflow.routes.lock-path.test.ts → version-control/__tests__/version-control.routes.lock-path.test.ts} +18 -18
  612. package/src/modules/{workflow/__tests__/workflow.routes.open-change-request.test.ts → version-control/__tests__/version-control.routes.open-change-request.test.ts} +7 -7
  613. package/src/modules/{workflow/__tests__/workflow.routes.push-refused.test.ts → version-control/__tests__/version-control.routes.push-refused.test.ts} +14 -14
  614. package/src/modules/{workflow/__tests__/workflow.service.branch-in-use.test.ts → version-control/__tests__/version-control.service.branch-in-use.test.ts} +6 -6
  615. package/src/modules/{workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts → version-control/__tests__/version-control.service.commitFileWhileLocked.test.ts} +14 -14
  616. package/src/modules/{workflow/__tests__/workflow.service.delete-branch.test.ts → version-control/__tests__/version-control.service.delete-branch.test.ts} +14 -14
  617. package/src/modules/{workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts → version-control/__tests__/version-control.service.deleted-branch-sweep.test.ts} +4 -4
  618. package/src/modules/{workflow/__tests__/workflow.service.facade.test.ts → version-control/__tests__/version-control.service.facade.test.ts} +100 -102
  619. package/src/modules/{workflow/__tests__/workflow.service.folder-proposals.test.ts → version-control/__tests__/version-control.service.folder-proposals.test.ts} +7 -7
  620. package/src/modules/{workflow/__tests__/workflow.service.platform-restore.test.ts → version-control/__tests__/version-control.service.platform-restore.test.ts} +6 -6
  621. package/src/modules/{workflow/__tests__/workflow.service.read-gate.test.ts → version-control/__tests__/version-control.service.read-gate.test.ts} +9 -9
  622. package/src/modules/{workflow/__tests__/workflow.service.releaseLock.test.ts → version-control/__tests__/version-control.service.releaseLock.test.ts} +85 -75
  623. package/src/modules/{workflow/__tests__/workflow.service.repository-replaced.test.ts → version-control/__tests__/version-control.service.repository-replaced.test.ts} +4 -4
  624. package/src/modules/{workflow/__tests__/workflow.service.sync.test.ts → version-control/__tests__/version-control.service.sync.test.ts} +17 -17
  625. package/src/modules/{workflow/__tests__/workflow.service.update-change-request.pg.test.ts → version-control/__tests__/version-control.service.update-change-request.pg.test.ts} +6 -6
  626. package/src/modules/{workflow/__tests__/workflow.service.update-change-request.test.ts → version-control/__tests__/version-control.service.update-change-request.test.ts} +11 -11
  627. package/src/modules/{workflow/__tests__/workflow.service.update-from-target.test.ts → version-control/__tests__/version-control.service.update-from-target.test.ts} +22 -22
  628. package/src/modules/{workflow → version-control}/agent-tools/__tests__/change-request-read.tools.test.ts +3 -3
  629. package/src/modules/{workflow → version-control}/agent-tools/__tests__/update-change-request.parity.test.ts +16 -16
  630. package/src/modules/{workflow/agent-tools/__tests__/workflow.tools.test.ts → version-control/agent-tools/__tests__/version-control.tools.test.ts} +9 -9
  631. package/src/modules/{workflow → version-control}/agent-tools/change-request-read.tools.ts +2 -2
  632. package/src/modules/{workflow/agent-tools/workflow.tools.ts → version-control/agent-tools/version-control.tools.ts} +30 -30
  633. package/src/modules/{workflow → version-control}/change-request-hooks.ts +1 -1
  634. package/src/modules/{workflow/review-workflow → version-control/change-request-review}/__tests__/approval-states.test.ts +5 -5
  635. package/src/modules/{workflow/review-workflow → version-control/change-request-review}/__tests__/cancel-pr.test.ts +8 -8
  636. package/src/modules/{workflow/review-workflow → version-control/change-request-review}/__tests__/carry-approvals-forward.test.ts +6 -6
  637. package/src/modules/{workflow/review-workflow → version-control/change-request-review}/__tests__/erase-approver.test.ts +5 -5
  638. package/src/modules/{workflow/review-workflow → version-control/change-request-review}/__tests__/merge-gate.test.ts +3 -3
  639. package/src/modules/{workflow/review-workflow → version-control/change-request-review}/__tests__/merge-records-own-commit.test.ts +3 -3
  640. package/src/modules/{workflow/review-workflow/review-workflow.interface.ts → version-control/change-request-review/change-request-review.interface.ts} +1 -1
  641. package/src/modules/{workflow/review-workflow/review-workflow.service.ts → version-control/change-request-review/change-request-review.service.ts} +28 -28
  642. package/src/modules/{workflow → version-control}/event-bus.ts +14 -14
  643. package/src/modules/{workflow → version-control}/events-delivery.ts +11 -11
  644. package/src/modules/{workflow → version-control}/events.routes.ts +5 -5
  645. package/src/modules/{workflow → version-control}/file-lock.service.ts +6 -6
  646. package/src/modules/{workflow → version-control}/git/__tests__/git-test-helpers.ts +3 -3
  647. package/src/modules/{workflow → version-control}/git/__tests__/git.service.accessGating.test.ts +5 -5
  648. package/src/modules/{workflow → version-control}/git/__tests__/git.service.appliedChange.test.ts +4 -4
  649. package/src/modules/{workflow → version-control}/git/__tests__/git.service.changedFilesForPr.test.ts +16 -16
  650. package/src/modules/{workflow → version-control}/git/__tests__/git.service.changedPathsMemo.test.ts +2 -2
  651. package/src/modules/{workflow → version-control}/git/__tests__/git.service.commitChanges.test.ts +3 -3
  652. package/src/modules/{workflow → version-control}/git/__tests__/git.service.commitFile.strayPath.test.ts +10 -10
  653. package/src/modules/{workflow → version-control}/git/__tests__/git.service.commitFile.test.ts +3 -3
  654. package/src/modules/version-control/git/__tests__/git.service.commitLanded.test.ts +199 -0
  655. package/src/modules/{workflow → version-control}/git/__tests__/git.service.createBranch.test.ts +3 -3
  656. package/src/modules/{workflow → version-control}/git/__tests__/git.service.deleteBranch.test.ts +7 -7
  657. package/src/modules/{workflow → version-control}/git/__tests__/git.service.diffFileAtCommit.test.ts +9 -9
  658. package/src/modules/{workflow → version-control}/git/__tests__/git.service.diffFileBetweenBranches.test.ts +23 -23
  659. package/src/modules/{workflow → version-control}/git/__tests__/git.service.fileBytesAtCommit.test.ts +7 -7
  660. package/src/modules/{workflow → version-control}/git/__tests__/git.service.fileContentsAtCommit.test.ts +3 -3
  661. package/src/modules/{workflow → version-control}/git/__tests__/git.service.forkPoint.test.ts +2 -2
  662. package/src/modules/{workflow → version-control}/git/__tests__/git.service.history-guards.test.ts +2 -2
  663. package/src/modules/{workflow → version-control}/git/__tests__/git.service.list-branches.test.ts +12 -12
  664. package/src/modules/{workflow → version-control}/git/__tests__/git.service.listTrackedFiles.test.ts +2 -2
  665. package/src/modules/{workflow → version-control}/git/__tests__/git.service.logForFile.test.ts +6 -6
  666. package/src/modules/{workflow → version-control}/git/__tests__/git.service.mergeChangeRequest.test.ts +99 -22
  667. package/src/modules/{workflow → version-control}/git/__tests__/git.service.mergeIntoBranch.test.ts +16 -16
  668. package/src/modules/{workflow → version-control}/git/__tests__/git.service.pendingChanges.test.ts +2 -2
  669. package/src/modules/{workflow → version-control}/git/__tests__/git.service.postMergePull.test.ts +5 -5
  670. package/src/modules/{workflow → version-control}/git/__tests__/git.service.prFetchFailure.test.ts +2 -2
  671. package/src/modules/{workflow → version-control}/git/__tests__/git.service.pull.test.ts +12 -12
  672. package/src/modules/{workflow → version-control}/git/__tests__/git.service.readFileAtRef.test.ts +3 -3
  673. package/src/modules/{workflow → version-control}/git/__tests__/git.service.revertPathsAndPush.test.ts +2 -2
  674. package/src/modules/{workflow → version-control}/git/__tests__/git.service.status.test.ts +4 -4
  675. package/src/modules/{workflow → version-control}/git/__tests__/git.service.syncFromRemote.test.ts +8 -8
  676. package/src/modules/{workflow → version-control}/git/__tests__/git.service.worktrees.test.ts +4 -4
  677. package/src/modules/{workflow → version-control}/git/__tests__/pull-request.service.list-fetch.test.ts +2 -2
  678. package/src/modules/{workflow → version-control}/git/__tests__/pull-request.service.test.ts +6 -6
  679. package/src/modules/{workflow → version-control}/git/git.service.ts +112 -59
  680. package/src/modules/{workflow → version-control}/git/node-git-runner.ts +1 -1
  681. package/src/modules/{workflow → version-control}/git/pull-request.service.ts +12 -12
  682. package/src/modules/{workflow → version-control}/index.ts +6 -5
  683. package/src/modules/{workflow → version-control}/pending-commits.service.ts +2 -2
  684. package/src/modules/{workflow → version-control}/pending-commits.worker.ts +8 -8
  685. package/src/modules/{workflow → version-control}/read-on-branch.ts +2 -2
  686. package/src/modules/{workflow/workflow-hooks.ts → version-control/version-control-hooks.ts} +44 -5
  687. package/src/modules/{workflow/workflow.routes.ts → version-control/version-control.routes.ts} +64 -63
  688. package/src/modules/{workflow/workflow.service.ts → version-control/version-control.service.ts} +96 -109
  689. package/src/modules/workspace/__tests__/agent-access.gate.test.ts +8 -8
  690. package/src/modules/workspace/__tests__/agent-downloads.test.ts +13 -16
  691. package/src/modules/workspace/__tests__/agent-uploads.test.ts +11 -12
  692. package/src/modules/workspace/__tests__/escape-sequences.routes.test.ts +11 -16
  693. package/src/modules/workspace/__tests__/file-stat-access.test.ts +3 -3
  694. package/src/modules/workspace/__tests__/git-internals.security.test.ts +27 -27
  695. package/src/modules/workspace/__tests__/kb-repository.test.ts +1 -1
  696. package/src/modules/workspace/__tests__/rest-tool-arguments.test.ts +3 -3
  697. package/src/modules/workspace/__tests__/start-session.default-branch.test.ts +152 -0
  698. package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +6 -6
  699. package/src/modules/workspace/__tests__/workspace-tmp.tools.test.ts +13 -14
  700. package/src/modules/workspace/__tests__/workspace.routes.at-ref.test.ts +6 -6
  701. package/src/modules/workspace/__tests__/workspace.routes.branch-errors.test.ts +4 -4
  702. package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +6 -6
  703. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +8 -8
  704. package/src/modules/workspace/__tests__/workspace.routes.download-implies-read.test.ts +4 -4
  705. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +6 -6
  706. package/src/modules/workspace/__tests__/workspace.routes.file-writes.test.ts +6 -6
  707. package/src/modules/workspace/__tests__/workspace.routes.folder-zip-access.test.ts +4 -4
  708. package/src/modules/workspace/__tests__/workspace.routes.folders.test.ts +6 -6
  709. package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +7 -7
  710. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +13 -13
  711. package/src/modules/workspace/__tests__/workspace.service.any-workspace-credentials.test.ts +1 -1
  712. package/src/modules/workspace/__tests__/workspace.service.replaced-repository.test.ts +1 -1
  713. package/src/modules/workspace/__tests__/workspace.service.worktrees.test.ts +1 -1
  714. package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +5 -5
  715. package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +5 -5
  716. package/src/modules/workspace/__tests__/workspace.tools.test.ts +27 -27
  717. package/src/modules/workspace/agent-access.gate.ts +5 -5
  718. package/src/modules/workspace/git-internals.middleware.ts +2 -2
  719. package/src/modules/workspace/kb-repository.ts +1 -1
  720. package/src/modules/workspace/startup/__tests__/kb-startup-runner.degraded.test.ts +1 -1
  721. package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +1 -1
  722. package/src/modules/workspace/startup/__tests__/kb-startup-runner.worktrees.test.ts +1 -1
  723. package/src/modules/workspace/startup/kb-git.ts +1 -1
  724. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +94 -70
  725. package/src/modules/workspace/startup/steps/seed-tree.ts +4 -5
  726. package/src/modules/workspace/startup/steps/template-files.step.ts +4 -5
  727. package/src/modules/workspace/startup/steps/template-source.ts +21 -6
  728. package/src/modules/workspace/workspace-tmp.ts +4 -4
  729. package/src/modules/workspace/workspace.routes.ts +26 -26
  730. package/src/modules/workspace/workspace.service.ts +11 -11
  731. package/src/modules/workspace/workspace.tools.ts +17 -10
  732. package/src/shared/__tests__/canonical-file-identity.test.ts +5 -5
  733. package/src/shared/__tests__/fire-and-forget.test.ts +39 -0
  734. package/src/shared/__tests__/http-errors.test.ts +4 -4
  735. package/src/shared/canonical-file-identity.ts +5 -5
  736. package/src/shared/domain-errors.ts +44 -44
  737. package/src/shared/fire-and-forget.ts +26 -0
  738. package/src/shared/git.contract.ts +1 -1
  739. package/src/shared/http-errors.ts +3 -3
  740. package/src/shared/kb-context.ts +130 -130
  741. package/src/shared/pending-proposals.ts +4 -4
  742. package/src/tenancy/__tests__/tenant-host.test.ts +372 -372
  743. package/src/tenancy/__tests__/tenant-runtime.test.ts +221 -221
  744. package/src/tenancy/__tests__/tenant-secrets.test.ts +35 -35
  745. package/src/tenancy/index.ts +35 -35
  746. package/src/tenancy/static-tenant-source.ts +1 -1
  747. package/src/tenancy/tenant-host.ts +261 -261
  748. package/src/tenancy/tenant-runtime.ts +208 -208
  749. package/src/tenancy/tenant-source.contract.ts +59 -59
  750. package/dist/modules/workflow/agent-tools/change-request-read-shape.d.ts.map +0 -1
  751. package/dist/modules/workflow/agent-tools/change-request-read-shape.js.map +0 -1
  752. package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts.map +0 -1
  753. package/dist/modules/workflow/agent-tools/change-request-read.tools.js.map +0 -1
  754. package/dist/modules/workflow/agent-tools/change-request-summary.d.ts.map +0 -1
  755. package/dist/modules/workflow/agent-tools/change-request-summary.js.map +0 -1
  756. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +0 -1
  757. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +0 -1
  758. package/dist/modules/workflow/change-request-hooks.d.ts.map +0 -1
  759. package/dist/modules/workflow/change-request-hooks.js.map +0 -1
  760. package/dist/modules/workflow/event-bus.d.ts.map +0 -1
  761. package/dist/modules/workflow/event-bus.js.map +0 -1
  762. package/dist/modules/workflow/events-delivery.d.ts.map +0 -1
  763. package/dist/modules/workflow/events-delivery.js.map +0 -1
  764. package/dist/modules/workflow/events.routes.d.ts.map +0 -1
  765. package/dist/modules/workflow/events.routes.js.map +0 -1
  766. package/dist/modules/workflow/file-lock.service.d.ts.map +0 -1
  767. package/dist/modules/workflow/file-lock.service.js.map +0 -1
  768. package/dist/modules/workflow/git/change-request-link.d.ts.map +0 -1
  769. package/dist/modules/workflow/git/change-request-link.js.map +0 -1
  770. package/dist/modules/workflow/git/git-version.d.ts.map +0 -1
  771. package/dist/modules/workflow/git/git-version.js.map +0 -1
  772. package/dist/modules/workflow/git/git.service.d.ts.map +0 -1
  773. package/dist/modules/workflow/git/git.service.js.map +0 -1
  774. package/dist/modules/workflow/git/merge-commit.d.ts.map +0 -1
  775. package/dist/modules/workflow/git/merge-commit.js.map +0 -1
  776. package/dist/modules/workflow/git/node-git-runner.d.ts.map +0 -1
  777. package/dist/modules/workflow/git/node-git-runner.js.map +0 -1
  778. package/dist/modules/workflow/git/pull-request.service.d.ts.map +0 -1
  779. package/dist/modules/workflow/git/pull-request.service.js.map +0 -1
  780. package/dist/modules/workflow/index.d.ts.map +0 -1
  781. package/dist/modules/workflow/index.js.map +0 -1
  782. package/dist/modules/workflow/pending-commits.service.d.ts.map +0 -1
  783. package/dist/modules/workflow/pending-commits.service.js.map +0 -1
  784. package/dist/modules/workflow/pending-commits.worker.d.ts.map +0 -1
  785. package/dist/modules/workflow/pending-commits.worker.js.map +0 -1
  786. package/dist/modules/workflow/read-on-branch.d.ts.map +0 -1
  787. package/dist/modules/workflow/read-on-branch.js.map +0 -1
  788. package/dist/modules/workflow/recovery-bot.d.ts.map +0 -1
  789. package/dist/modules/workflow/recovery-bot.js.map +0 -1
  790. package/dist/modules/workflow/review-workflow/approval-lock.d.ts.map +0 -1
  791. package/dist/modules/workflow/review-workflow/approval-lock.js.map +0 -1
  792. package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts.map +0 -1
  793. package/dist/modules/workflow/review-workflow/review-workflow.interface.js +0 -2
  794. package/dist/modules/workflow/review-workflow/review-workflow.interface.js.map +0 -1
  795. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +0 -1
  796. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +0 -1
  797. package/dist/modules/workflow/sanitize-error.d.ts.map +0 -1
  798. package/dist/modules/workflow/sanitize-error.js.map +0 -1
  799. package/dist/modules/workflow/workflow-hooks.d.ts.map +0 -1
  800. package/dist/modules/workflow/workflow-hooks.js.map +0 -1
  801. package/dist/modules/workflow/workflow.routes.d.ts.map +0 -1
  802. package/dist/modules/workflow/workflow.routes.js.map +0 -1
  803. package/dist/modules/workflow/workflow.service.d.ts.map +0 -1
  804. package/dist/modules/workflow/workflow.service.js.map +0 -1
  805. package/src/modules/mcp/__tests__/read-only-hint.e2e.test.ts +0 -213
  806. /package/dist/modules/{workflow → version-control}/agent-tools/change-request-read-shape.d.ts +0 -0
  807. /package/dist/modules/{workflow → version-control}/agent-tools/change-request-read-shape.js +0 -0
  808. /package/dist/modules/{workflow → version-control}/agent-tools/change-request-read.tools.d.ts +0 -0
  809. /package/dist/modules/{workflow → version-control}/agent-tools/change-request-summary.d.ts +0 -0
  810. /package/dist/modules/{workflow → version-control}/agent-tools/change-request-summary.js +0 -0
  811. /package/dist/modules/{workflow → version-control}/change-request-hooks.js +0 -0
  812. /package/dist/modules/{workflow/review-workflow → version-control/change-request-review}/approval-lock.d.ts +0 -0
  813. /package/dist/modules/{workflow/review-workflow → version-control/change-request-review}/approval-lock.js +0 -0
  814. /package/dist/modules/{workflow → version-control}/events-delivery.js +0 -0
  815. /package/dist/modules/{workflow → version-control}/events.routes.js +0 -0
  816. /package/dist/modules/{workflow → version-control}/git/change-request-link.d.ts +0 -0
  817. /package/dist/modules/{workflow → version-control}/git/change-request-link.js +0 -0
  818. /package/dist/modules/{workflow → version-control}/git/git-version.d.ts +0 -0
  819. /package/dist/modules/{workflow → version-control}/git/git-version.js +0 -0
  820. /package/dist/modules/{workflow → version-control}/git/merge-commit.d.ts +0 -0
  821. /package/dist/modules/{workflow → version-control}/git/merge-commit.js +0 -0
  822. /package/dist/modules/{workflow → version-control}/git/node-git-runner.d.ts +0 -0
  823. /package/dist/modules/{workflow → version-control}/recovery-bot.d.ts +0 -0
  824. /package/dist/modules/{workflow → version-control}/recovery-bot.js +0 -0
  825. /package/dist/modules/{workflow → version-control}/sanitize-error.d.ts +0 -0
  826. /package/dist/modules/{workflow → version-control}/sanitize-error.js +0 -0
  827. /package/src/modules/{workflow → version-control}/__tests__/change-request-hooks.test.ts +0 -0
  828. /package/src/modules/{workflow → version-control}/__tests__/fake-file-lock-db.ts +0 -0
  829. /package/src/modules/{workflow → version-control}/__tests__/pending-commits.canonical.test.ts +0 -0
  830. /package/src/modules/{workflow → version-control}/__tests__/pending-commits.enqueue-if-absent.test.ts +0 -0
  831. /package/src/modules/{workflow → version-control}/__tests__/pending-commits.repository-replaced.test.ts +0 -0
  832. /package/src/modules/{workflow → version-control}/__tests__/sanitize-error.test.ts +0 -0
  833. /package/src/modules/{workflow → version-control}/agent-tools/__tests__/change-request-read-shape.test.ts +0 -0
  834. /package/src/modules/{workflow → version-control}/agent-tools/change-request-read-shape.ts +0 -0
  835. /package/src/modules/{workflow → version-control}/agent-tools/change-request-summary.ts +0 -0
  836. /package/src/modules/{workflow/review-workflow → version-control/change-request-review}/approval-lock.ts +0 -0
  837. /package/src/modules/{workflow → version-control}/git/__tests__/branchAuthor.test.ts +0 -0
  838. /package/src/modules/{workflow → version-control}/git/__tests__/change-request-link.test.ts +0 -0
  839. /package/src/modules/{workflow → version-control}/git/__tests__/git-version.failure.test.ts +0 -0
  840. /package/src/modules/{workflow → version-control}/git/__tests__/git-version.test.ts +0 -0
  841. /package/src/modules/{workflow → version-control}/git/__tests__/node-git-runner.test.ts +0 -0
  842. /package/src/modules/{workflow → version-control}/git/__tests__/pull-request.service.getPrDetail.test.ts +0 -0
  843. /package/src/modules/{workflow → version-control}/git/__tests__/pull-request.service.placeholder.test.ts +0 -0
  844. /package/src/modules/{workflow → version-control}/git/__tests__/pull-request.service.viewer-can-cancel.test.ts +0 -0
  845. /package/src/modules/{workflow → version-control}/git/__tests__/pull-request.service.viewer-can-delete.test.ts +0 -0
  846. /package/src/modules/{workflow → version-control}/git/__tests__/pull-request.service.viewer-can-update.test.ts +0 -0
  847. /package/src/modules/{workflow → version-control}/git/change-request-link.ts +0 -0
  848. /package/src/modules/{workflow → version-control}/git/git-version.ts +0 -0
  849. /package/src/modules/{workflow → version-control}/git/merge-commit.ts +0 -0
  850. /package/src/modules/{workflow → version-control}/recovery-bot.ts +0 -0
  851. /package/src/modules/{workflow → version-control}/sanitize-error.ts +0 -0
@@ -3,12 +3,13 @@ import { isDeepStrictEqual } from 'node:util';
3
3
  import { logger } from '../../shared/logging.js';
4
4
  const log = logger('vault');
5
5
  import { and, desc, eq, inArray, isNull, like, or } from 'drizzle-orm';
6
- import { secrets } from '../database/index.js';
6
+ import { pgErrorCode, secrets } from '../database/index.js';
7
7
  import { TokenCrypto } from '../../shared/token-crypto.js';
8
8
  import { assertSafeFetchUrl } from '../../shared/ssrf.js';
9
9
  import { readCapped } from '../../shared/read-capped.js';
10
10
  import { standardTokenErrorCode } from '../../shared/oauth-token-error.js';
11
11
  import { isKeyInNamespace, InvalidSecretError, SecretNotFoundError, SecretOAuthError, } from './secrets-vault.contract.js';
12
+ import { timingSafeStringEqual } from '../auth/index.js';
12
13
  const MAX_KEY_LEN = 200;
13
14
  const MAX_LABEL_LEN = 200;
14
15
  const MAX_VALUE_LEN = 100_000;
@@ -16,6 +17,32 @@ const MAX_VALUE_LEN = 100_000;
16
17
  const REFRESH_SKEW_MS = 60_000;
17
18
  /** Upper bound on a token-endpoint round-trip, so a hung provider can't block callers. */
18
19
  const TOKEN_REQUEST_TIMEOUT_MS = 10_000;
20
+ /** Upper bound on telling a provider a managed sign-in is over, so a deletion never waits on it. */
21
+ const REVOKE_TIMEOUT_MS = 10_000;
22
+ /** Upper bound on a broker renewing a managed token: past it the stale token is served and the next call asks again. */
23
+ const REFRESH_TIMEOUT_MS = 15_000;
24
+ /** How many times a guarded replacement re-reads a row that changed under its revoke before giving up. */
25
+ const REPLACE_ATTEMPTS = 3;
26
+ /** How many times a handoff re-reads a row a refresh rotated under it (the nonce rides along) before refusing. */
27
+ const HANDOFF_ATTEMPTS = 3;
28
+ /** `work`, or a rejection once `ms` have passed: a handler that never settles must not hold the vault. */
29
+ async function bounded(work, ms, what) {
30
+ let timer;
31
+ try {
32
+ return await Promise.race([
33
+ work,
34
+ new Promise((_, reject) => {
35
+ timer = setTimeout(() => reject(new Error(`${what} did not settle within ${ms}ms`)), ms);
36
+ }),
37
+ ]);
38
+ }
39
+ finally {
40
+ if (timer)
41
+ clearTimeout(timer);
42
+ }
43
+ }
44
+ /** How often a managed sign-in's opening is retried against a row that keeps changing under it. */
45
+ const BEGIN_MANAGED_ATTEMPTS = 3;
19
46
  /** How much of a refusing token endpoint's body is read for its error code: an OAuth error object, never a whole error page. */
20
47
  const TOKEN_ERROR_BODY_MAX_BYTES = 2048;
21
48
  // Hexis's own sentences for a refused token request: what to change, in our
@@ -111,6 +138,19 @@ export class DbSecretsVaultService {
111
138
  now;
112
139
  scopeOf;
113
140
  cryptoInstance = null;
141
+ /**
142
+ * How a MANAGED sign-in's tokens are renewed and revoked — through the
143
+ * broker and the provider respectively. Setter-injected: both depend on
144
+ * the connector catalog, which is built after this service. Without them a
145
+ * managed token that expires is served stale (a transient, retried on the
146
+ * next call) and a disconnect deletes without revoking.
147
+ */
148
+ managedRefresher;
149
+ managedRevoker;
150
+ setManagedTokenHandlers(handlers) {
151
+ this.managedRefresher = handlers.refresher;
152
+ this.managedRevoker = handlers.revoker;
153
+ }
114
154
  constructor(db,
115
155
  /** 32-byte AES key (hex/base64); empty disables secret read/write with a clear error. */
116
156
  encKey, now = Date.now,
@@ -178,15 +218,18 @@ export class DbSecretsVaultService {
178
218
  }
179
219
  const label = this.normaliseLabel(input.label);
180
220
  const valueEncrypted = this.crypto().encrypt(input.value);
221
+ // The caller's row may hold a managed sign-in: its tokens are told to the
222
+ // provider before this value replaces them, as on every replacement.
181
223
  // Upsert on (user_id, key): re-saving a key replaces its value in place.
182
- const [row] = await this.db
224
+ const row = await this.revokedReplacement(and(eq(secrets.userId, userId), eq(secrets.key, key)), (guard) => this.db
183
225
  .insert(secrets)
184
226
  .values({ userId, key, kind: 'static', label, valueEncrypted, oauthMeta: null })
185
227
  .onConflictDoUpdate({
186
228
  target: [secrets.userId, secrets.key],
187
229
  set: { kind: 'static', label, valueEncrypted, oauthMeta: null, updatedAt: new Date() },
230
+ ...(guard ? { setWhere: guard } : {}),
188
231
  })
189
- .returning();
232
+ .returning());
190
233
  this.notifyMutation(userId);
191
234
  return this.toSummary(row);
192
235
  }
@@ -198,7 +241,9 @@ export class DbSecretsVaultService {
198
241
  const blob = { clientSecret: provider.clientSecret };
199
242
  const valueEncrypted = this.crypto().encrypt(JSON.stringify(blob));
200
243
  const oauthMeta = this.publicProviderMeta(provider);
201
- const [row] = await this.db
244
+ // A managed sign-in under this key loses its tokens here: the provider is
245
+ // told first, as on every replacement.
246
+ const row = await this.revokedReplacement(and(eq(secrets.userId, userId), eq(secrets.key, key)), (guard) => this.db
202
247
  .insert(secrets)
203
248
  .values({ userId, key, kind: 'oauth', label, valueEncrypted, oauthMeta })
204
249
  .onConflictDoUpdate({
@@ -206,17 +251,15 @@ export class DbSecretsVaultService {
206
251
  // Replacing an oauth secret's provider config drops any existing tokens
207
252
  // (they belonged to the old client) — the user must re-authorize.
208
253
  set: { kind: 'oauth', label, valueEncrypted, oauthMeta, updatedAt: new Date() },
254
+ ...(guard ? { setWhere: guard } : {}),
209
255
  })
210
- .returning();
256
+ .returning());
211
257
  this.notifyMutation(userId);
212
258
  return this.toSummary(row);
213
259
  }
214
260
  async remove(userId, id) {
215
- const res = await this.db
216
- .delete(secrets)
217
- .where(and(eq(secrets.id, id), eq(secrets.userId, userId)))
218
- .returning({ id: secrets.id });
219
- if (res.length === 0)
261
+ const gone = await this.revokeThenDelete(and(eq(secrets.id, id), eq(secrets.userId, userId)));
262
+ if (gone.length === 0)
220
263
  throw new SecretNotFoundError(id);
221
264
  this.notifyMutation(userId);
222
265
  }
@@ -230,38 +273,186 @@ export class DbSecretsVaultService {
230
273
  }
231
274
  const label = this.normaliseLabel(input.label);
232
275
  const valueEncrypted = this.crypto().encrypt(input.value);
276
+ // A shared row that held a managed workspace connection is told to its
277
+ // provider before this value replaces it; the tokens would otherwise go
278
+ // unrevoked with the row's kind.
233
279
  // Upsert the ONE shared row for this key (user_id NULL). The conflict target
234
280
  // is the partial unique index `secrets_shared_key_unq` — hence `targetWhere`.
235
- const [row] = await this.db
281
+ const row = await this.revokedReplacement(and(isNull(secrets.userId), eq(secrets.key, key)), (guard) => this.db
236
282
  .insert(secrets)
237
283
  .values({ userId: null, key, kind: 'static', label, valueEncrypted, oauthMeta: null })
238
284
  .onConflictDoUpdate({
239
285
  target: secrets.key,
240
286
  targetWhere: isNull(secrets.userId),
241
287
  set: { kind: 'static', label, valueEncrypted, oauthMeta: null, updatedAt: new Date() },
288
+ ...(guard ? { setWhere: guard } : {}),
242
289
  })
243
- .returning();
290
+ .returning());
244
291
  this.notifyMutation(null);
245
292
  return this.toSummary(row);
246
293
  }
247
294
  async removeShared(key) {
248
- const res = await this.db
249
- .delete(secrets)
250
- .where(and(isNull(secrets.userId), eq(secrets.key, key)))
251
- .returning({ id: secrets.id });
252
- if (res.length === 0)
295
+ const gone = await this.revokeThenDelete(and(isNull(secrets.userId), eq(secrets.key, key)));
296
+ if (gone.length === 0)
253
297
  throw new SecretNotFoundError(key);
254
298
  this.notifyMutation(null);
255
299
  }
256
300
  async removeUserByKey(userId, key) {
257
- const res = await this.db
258
- .delete(secrets)
259
- .where(and(eq(secrets.userId, userId), eq(secrets.key, key)))
260
- .returning({ id: secrets.id });
261
- if (res.length === 0)
301
+ const gone = await this.revokeThenDelete(and(eq(secrets.userId, userId), eq(secrets.key, key)));
302
+ if (gone.length === 0)
262
303
  throw new SecretNotFoundError(key);
263
304
  this.notifyMutation(userId);
264
305
  }
306
+ /**
307
+ * Delete the rows `where` names, each told to its provider first when it
308
+ * is a managed sign-in with tokens (see {@link revokeRow}). The delete is
309
+ * guarded on the ciphertext the revoke read: a handoff or a refresh landing
310
+ * in between has replaced the tokens, and deleting THOSE unrevoked is the
311
+ * leak the revoke exists to prevent. A miss re-reads the row and goes
312
+ * again, bounded; what could not be settled in those passes is left
313
+ * standing rather than deleted blind.
314
+ */
315
+ async revokeThenDelete(where) {
316
+ // No revoker, nothing to read first: one plain delete, as every removal
317
+ // was before managed sign-ins, and no miss to re-read for.
318
+ if (!this.managedRevoker) {
319
+ return this.db.delete(secrets).where(where).returning({ id: secrets.id, userId: secrets.userId, kind: secrets.kind });
320
+ }
321
+ const gone = [];
322
+ for (let attempt = 0; attempt < 3; attempt++) {
323
+ const rows = await this.db.select().from(secrets).where(where);
324
+ if (rows.length === 0)
325
+ break;
326
+ // Every row's revocation at once, so a bulk delete (a namespace, a
327
+ // person's connections) waits one revocation's bound, not one per row.
328
+ await Promise.all(rows.map((row) => this.revokeRow(row)));
329
+ let missed = false;
330
+ for (const row of rows) {
331
+ const deleted = await this.db
332
+ .delete(secrets)
333
+ .where(and(eq(secrets.id, row.id), eq(secrets.valueEncrypted, row.valueEncrypted)))
334
+ .returning({ id: secrets.id, userId: secrets.userId, kind: secrets.kind });
335
+ if (deleted.length === 0)
336
+ missed = true;
337
+ else
338
+ gone.push(...deleted);
339
+ }
340
+ if (!missed)
341
+ break;
342
+ }
343
+ return gone;
344
+ }
345
+ async removeManagedRowsOfUser(userId, within) {
346
+ if (within)
347
+ return this.removeManagedRowsLocked(userId, within);
348
+ // Every oauth row of the user whose meta names a managed app. Read
349
+ // first (the managed mark lives in JSON the WHERE cannot see), revoked,
350
+ // then deleted by id; the per-user filter on the delete is what keeps a
351
+ // row read for this user from ever deleting another's.
352
+ const rows = await this.db
353
+ .select()
354
+ .from(secrets)
355
+ .where(and(eq(secrets.userId, userId), eq(secrets.kind, 'oauth')));
356
+ const managed = rows.filter((r) => this.managedRefOf(r.oauthMeta) !== null);
357
+ if (managed.length === 0)
358
+ return 0;
359
+ const deleted = await this.revokeThenDelete(and(eq(secrets.userId, userId), inArray(secrets.id, managed.map((r) => r.id))));
360
+ if (deleted.length > 0)
361
+ this.notifyMutation(userId);
362
+ // A row the guarded delete could not settle (its tokens kept changing
363
+ // under the revoke) is still here, unrevoked. The caller is told rather
364
+ // than left to believe the person holds nothing: an erasure refuses and
365
+ // is retried, a switch-off logs it and the row is refused on use.
366
+ if (deleted.length < managed.length) {
367
+ throw new SecretOAuthError(`${managed.length - deleted.length} managed sign-in(s) kept changing while being revoked and were not removed; try again`);
368
+ }
369
+ return deleted.length;
370
+ }
371
+ /**
372
+ * The same removal inside a caller's transaction (an account erasure, just
373
+ * before the user row goes): the rows are LOCKED for the transaction, so a
374
+ * handoff or a refresh arriving now waits and then finds no row, which is
375
+ * what makes the revoke final. No guard is needed under the lock; the
376
+ * revoke stays bounded (see {@link revokeRow}), so the transaction never
377
+ * waits on a provider longer than that.
378
+ */
379
+ async removeManagedRowsLocked(userId, tx) {
380
+ const rows = await tx
381
+ .select()
382
+ .from(secrets)
383
+ .where(and(eq(secrets.userId, userId), eq(secrets.kind, 'oauth')))
384
+ .for('update');
385
+ const managed = rows.filter((r) => this.managedRefOf(r.oauthMeta) !== null);
386
+ if (managed.length === 0)
387
+ return 0;
388
+ await Promise.all(managed.map((row) => this.revokeRow(row)));
389
+ await tx.delete(secrets).where(and(eq(secrets.userId, userId), inArray(secrets.id, managed.map((r) => r.id))));
390
+ this.notifyMutation(userId);
391
+ return managed.length;
392
+ }
393
+ /**
394
+ * Replace what `where` names with `write`, a managed sign-in's tokens told
395
+ * to their provider first (see {@link revokeRow}; best effort, never holding
396
+ * the user's decision). The write is guarded on the ciphertext the revoke
397
+ * read (`setWhere`): a refresh or a handoff landing in between has rotated
398
+ * the tokens, and writing over THOSE unrevoked is the leak the revoke exists
399
+ * to prevent — as the guarded delete of {@link revokeThenDelete}. A miss
400
+ * re-reads and goes again, bounded; a row that kept changing is left as it
401
+ * is and the caller is told. With no revoker wired there is nothing to read
402
+ * first: one plain write, as every replacement was before managed sign-ins.
403
+ */
404
+ async revokedReplacement(where, write) {
405
+ if (!this.managedRevoker)
406
+ return (await write())[0];
407
+ for (let attempt = 0; attempt < REPLACE_ATTEMPTS; attempt++) {
408
+ const rows = await this.db.select().from(secrets).where(where);
409
+ await Promise.all(rows.map((row) => this.revokeRow(row)));
410
+ // The row as it was read, or no row at all: a conflict with anything
411
+ // else (a row written meanwhile) is a miss, and the next pass reads it.
412
+ const guard = rows.length > 0
413
+ ? inArray(secrets.valueEncrypted, rows.map((row) => row.valueEncrypted))
414
+ : eq(secrets.valueEncrypted, '');
415
+ const written = await write(guard);
416
+ if (written.length > 0)
417
+ return written[0];
418
+ }
419
+ throw new SecretOAuthError('the sign-in kept changing while being replaced; try again');
420
+ }
421
+ async revokeRow(row) {
422
+ if (!this.managedRevoker || row.kind !== 'oauth')
423
+ return;
424
+ const ref = this.managedRefOf(row.oauthMeta);
425
+ if (!ref)
426
+ return;
427
+ const tokens = this.readTokensSafe(row.valueEncrypted);
428
+ if (!tokens?.access_token)
429
+ return;
430
+ // Bounded: the delete that follows is the user's decision, and a revoker
431
+ // that never settles must not hold it.
432
+ try {
433
+ await bounded(this.managedRevoker.revoke(ref, { access_token: tokens.access_token, refresh_token: tokens.refresh_token }), REVOKE_TIMEOUT_MS, 'revocation');
434
+ }
435
+ catch (err) {
436
+ // The key and the connector name the sign-in. The error itself stays
437
+ // out: a revoker's message is its own, and this line is the one place a
438
+ // token could otherwise reach a log from this path.
439
+ log.warn('revoking a managed sign-in with its provider failed; deleting it here anyway', {
440
+ key: row.key,
441
+ connector: ref.connectorId,
442
+ failure: err instanceof Error ? err.name : typeof err,
443
+ });
444
+ }
445
+ }
446
+ /** The managed reference a row's public meta carries, or null for an ordinary sign-in. */
447
+ managedRefOf(raw) {
448
+ const meta = (raw ?? {});
449
+ const m = meta.managed;
450
+ if (!m || typeof m !== 'object')
451
+ return null;
452
+ const connectorId = typeof m.connectorId === 'string' ? m.connectorId : '';
453
+ const scopeSet = typeof m.scopeSet === 'string' ? m.scopeSet : '';
454
+ return connectorId && scopeSet ? { connectorId, scopeSet } : null;
455
+ }
265
456
  async countNamespace(prefix) {
266
457
  return tally(await this.namespaceRows(prefix));
267
458
  }
@@ -282,10 +473,10 @@ export class DbSecretsVaultService {
282
473
  const rows = await this.namespaceRows(prefix);
283
474
  if (rows.length === 0)
284
475
  break;
285
- const deleted = await this.db
286
- .delete(secrets)
287
- .where(inArray(secrets.id, rows.map((r) => r.id)))
288
- .returning({ userId: secrets.userId, kind: secrets.kind });
476
+ // A managed sign-in under the namespace is told to its provider
477
+ // before the delete, for the same reason the per-row removals do —
478
+ // and guarded the same way, when a revoker is there to need it.
479
+ const deleted = await this.revokeThenDelete(inArray(secrets.id, rows.map((r) => r.id)));
289
480
  gone.push(...deleted);
290
481
  }
291
482
  }
@@ -335,6 +526,7 @@ export class DbSecretsVaultService {
335
526
  userId: secrets.userId,
336
527
  kind: secrets.kind,
337
528
  valueEncrypted: secrets.valueEncrypted,
529
+ oauthMeta: secrets.oauthMeta,
338
530
  })
339
531
  .from(secrets)
340
532
  .where(and(inArray(secrets.key, keys), or(isNull(secrets.userId), eq(secrets.userId, userId))));
@@ -343,6 +535,15 @@ export class DbSecretsVaultService {
343
535
  const adminRow = rows.find((r) => r.key === key && r.userId === null);
344
536
  // Decrypt+parse the oauth row's token set once, then derive both fields from it.
345
537
  const tokens = userRow?.kind === 'oauth' ? this.readTokensSafe(userRow.valueEncrypted) : undefined;
538
+ // The shared row holds tokens only for a managed workspace connection;
539
+ // an ordinary sign-in's shared row is the client secret and reads as
540
+ // "no tokens" here, which is the truthful answer for it.
541
+ const adminTokens = adminRow?.kind === 'oauth' ? this.readTokensSafe(adminRow.valueEncrypted) : undefined;
542
+ const adminMeta = (adminRow?.oauthMeta ?? null);
543
+ const accountOf = (meta) => {
544
+ const a = meta?.account;
545
+ return typeof a === 'string' && a ? a : undefined;
546
+ };
346
547
  return {
347
548
  key,
348
549
  adminConfigured: !!adminRow,
@@ -356,9 +557,154 @@ export class DbSecretsVaultService {
356
557
  // Only meaningful for an oauth row: the scopes the caller's token was granted,
357
558
  // so a coverage check can tell whether it still covers the tool's live scopes.
358
559
  grantedScopes: userRow?.kind === 'oauth' ? tokens?.scope : undefined,
560
+ adminAuthorized: adminRow?.kind === 'oauth' ? Boolean(adminTokens?.access_token) : undefined,
561
+ adminGrantedScopes: adminRow?.kind === 'oauth' ? adminTokens?.scope : undefined,
562
+ userAccount: userRow?.kind === 'oauth' ? accountOf(userRow.oauthMeta) : undefined,
563
+ adminAccount: adminRow?.kind === 'oauth' ? accountOf(adminMeta) : undefined,
564
+ // An owner's own app on the shared row: a client id without the managed mark.
565
+ adminBringsOwnApp: adminRow?.kind === 'oauth'
566
+ ? this.managedRefOf(adminMeta) === null && typeof adminMeta?.clientId === 'string' && adminMeta.clientId !== ''
567
+ : undefined,
359
568
  };
360
569
  });
361
570
  }
571
+ async beginManagedConnection(input) {
572
+ const key = this.requireKey(input.key);
573
+ const userId = input.userId === null ? null : this.requireUserId(input.userId);
574
+ const ref = input.provider.managed;
575
+ if (!ref)
576
+ throw new InvalidSecretError('a managed sign-in needs its connector reference');
577
+ if (typeof input.nonce !== 'string' || input.nonce.length < 16)
578
+ throw new InvalidSecretError('nonce is required');
579
+ const oauthMeta = this.publicProviderMeta(this.requireProvider(input.provider, { managed: true }));
580
+ const where = userId === null ? and(isNull(secrets.userId), eq(secrets.key, key)) : and(eq(secrets.userId, userId), eq(secrets.key, key));
581
+ // Read-modify-write on a LIVE credential: a refresh running concurrently
582
+ // may rotate the tokens between the read and the write, and writing our
583
+ // copy over them would leave the row holding a dead refresh token. So the
584
+ // update is guarded on the ciphertext read, and a miss re-reads and
585
+ // rebuilds from the fresh row; bounded, so a row that keeps changing
586
+ // fails loudly rather than forever. The same rule `beginOAuth` follows.
587
+ for (let attempt = 0; attempt < BEGIN_MANAGED_ATTEMPTS; attempt++) {
588
+ const [existing] = await this.db.select().from(secrets).where(where).limit(1);
589
+ // Keep what the SAME connection already holds (its tokens, so an
590
+ // abandoned reconnect costs nothing). The same connection means the same
591
+ // connector and scope set: a row of another connector's, or of another
592
+ // set's, holds a token for something else, and a declaration that
593
+ // changed must not hand it to the new one. Start clean over anything
594
+ // else too — a static value or an owner-app sign-in under this key.
595
+ const storedRef = existing?.kind === 'oauth' ? this.managedRefOf(existing.oauthMeta) : null;
596
+ const sameConnection = storedRef !== null && storedRef.connectorId === ref.connectorId && storedRef.scopeSet === ref.scopeSet;
597
+ let kept = {};
598
+ if (existing && sameConnection) {
599
+ try {
600
+ kept = this.readBlob(existing.valueEncrypted);
601
+ }
602
+ catch {
603
+ kept = {};
604
+ }
605
+ }
606
+ const next = { tokens: kept.tokens, pendingNonce: input.nonce };
607
+ const valueEncrypted = this.crypto().encrypt(JSON.stringify(next));
608
+ const account = sameConnection ? existing.oauthMeta?.account : undefined;
609
+ const meta = typeof account === 'string' && account ? { ...oauthMeta, account } : oauthMeta;
610
+ if (!existing) {
611
+ try {
612
+ await this.db.insert(secrets).values({ userId, key, kind: 'oauth', label: null, valueEncrypted, oauthMeta: meta });
613
+ return;
614
+ }
615
+ catch (err) {
616
+ // Another start of the same sign-in inserted the row first: the
617
+ // next pass finds it and updates it, as it would any existing row.
618
+ if (pgErrorCode(err) === '23505')
619
+ continue; // unique_violation
620
+ throw err;
621
+ }
622
+ }
623
+ // A row that held ANOTHER connection's tokens is about to lose them:
624
+ // the provider is told first, as on every other replacement.
625
+ if (!sameConnection && storedRef)
626
+ await this.revokeRow(existing);
627
+ const written = await this.db
628
+ .update(secrets)
629
+ .set({ kind: 'oauth', valueEncrypted, oauthMeta: meta, updatedAt: new Date() })
630
+ .where(and(eq(secrets.id, existing.id), eq(secrets.valueEncrypted, existing.valueEncrypted)))
631
+ .returning({ id: secrets.id });
632
+ if (Array.isArray(written) && written.length === 0)
633
+ continue;
634
+ // A row that held something ELSE (a value, another connection's
635
+ // tokens, an owner's app) no longer does: caches keyed on it are told.
636
+ // The same connection's tokens carried over unchanged tell nobody.
637
+ if (!kept.tokens)
638
+ this.notifyMutation(userId);
639
+ return;
640
+ }
641
+ throw new SecretOAuthError('The sign-in could not be opened: its stored credential kept changing. Try again.');
642
+ }
643
+ async completeManagedConnection(input) {
644
+ const key = this.requireKey(input.key);
645
+ const userId = input.userId === null ? null : this.requireUserId(input.userId);
646
+ const where = userId === null ? and(isNull(secrets.userId), eq(secrets.key, key)) : and(eq(secrets.userId, userId), eq(secrets.key, key));
647
+ // Every refusal below is the same words: a caller that can tell "no such
648
+ // sign-in" from "wrong nonce" from "already used" has learned which rows
649
+ // exist, and the handoff route is reachable with the broker secret alone.
650
+ const refused = () => new SecretOAuthError('No managed sign-in is waiting for this handoff');
651
+ const tokens = input.tokens;
652
+ if (typeof tokens?.access_token !== 'string' || !tokens.access_token) {
653
+ throw new InvalidSecretError('the handoff carries no access token');
654
+ }
655
+ // Read, check the nonce, write guarded on what was read; and again when
656
+ // the write misses. A miss with the nonce still on the row is a refresh
657
+ // that rotated the row's tokens meanwhile (a refresh carries the nonce
658
+ // across, see `inFlightOf`), not a second handoff: the broker delivered
659
+ // these tokens once, and refusing them would lose a valid sign-in for
660
+ // good. A row whose nonce is gone or changed refuses on the re-read.
661
+ for (let attempt = 0;; attempt++) {
662
+ const [row] = await this.db.select().from(secrets).where(where).limit(1);
663
+ if (!row || row.kind !== 'oauth' || !this.managedRefOf(row.oauthMeta))
664
+ throw refused();
665
+ let blob;
666
+ try {
667
+ blob = this.readBlob(row.valueEncrypted);
668
+ }
669
+ catch {
670
+ throw refused();
671
+ }
672
+ if (!blob.pendingNonce || typeof input.nonce !== 'string' || !timingSafeStringEqual(input.nonce, blob.pendingNonce)) {
673
+ throw refused();
674
+ }
675
+ const meta = { ...(row.oauthMeta ?? {}) };
676
+ // A broker that echoes no `scope` delivered what the sign-in asked for:
677
+ // the scopes the row was opened with stand in, as `pendingScopes` does
678
+ // for the code exchange. Stored as unknown, the grant would count as
679
+ // covering nothing, and the sign-in would read as under-scoped for good.
680
+ // An EMPTY scope is not "none echoed": it is an empty grant, kept as such.
681
+ const requested = Array.isArray(meta.scopes) && meta.scopes.length > 0 ? meta.scopes.map(String).join(' ') : undefined;
682
+ const stored = {
683
+ access_token: tokens.access_token,
684
+ refresh_token: typeof tokens.refresh_token === 'string' ? tokens.refresh_token : undefined,
685
+ expires_at: typeof tokens.expires_at === 'number' ? tokens.expires_at : undefined,
686
+ token_type: typeof tokens.token_type === 'string' ? tokens.token_type : undefined,
687
+ scope: typeof tokens.scope === 'string' ? tokens.scope : requested,
688
+ };
689
+ // The nonce is one-time: it leaves with the handoff it was minted for,
690
+ // so the same handoff presented twice finds nothing to match.
691
+ const next = { tokens: stored };
692
+ if (typeof input.account === 'string' && input.account.trim())
693
+ meta.account = input.account.trim().slice(0, MAX_LABEL_LEN);
694
+ // Guarded on the ciphertext read above: two handoffs racing for one
695
+ // nonce cannot both land, whichever the provider sent first wins.
696
+ const landed = await this.db
697
+ .update(secrets)
698
+ .set({ valueEncrypted: this.crypto().encrypt(JSON.stringify(next)), oauthMeta: meta, updatedAt: new Date() })
699
+ .where(and(eq(secrets.id, row.id), eq(secrets.valueEncrypted, row.valueEncrypted)))
700
+ .returning({ id: secrets.id });
701
+ if (!(Array.isArray(landed) && landed.length === 0))
702
+ break;
703
+ if (attempt + 1 >= HANDOFF_ATTEMPTS)
704
+ throw refused();
705
+ }
706
+ this.notifyMutation(userId);
707
+ }
362
708
  /**
363
709
  * Decrypt+parse an oauth row's token set once, or undefined if the blob can't be
364
710
  * read — a corrupted row or rotated encKey must degrade to "not authorized", not throw.
@@ -495,14 +841,18 @@ export class DbSecretsVaultService {
495
841
  const blob = { clientSecret: provider.clientSecret };
496
842
  const valueEncrypted = this.crypto().encrypt(JSON.stringify(blob));
497
843
  const oauthMeta = this.publicProviderMeta(provider);
498
- await this.db
844
+ // An owner's own app replacing a managed workspace connection: the
845
+ // connection's tokens are revoked with the provider before they go.
846
+ await this.revokedReplacement(and(isNull(secrets.userId), eq(secrets.key, key)), (guard) => this.db
499
847
  .insert(secrets)
500
848
  .values({ userId: null, key, kind: 'oauth', label: null, valueEncrypted, oauthMeta })
501
849
  .onConflictDoUpdate({
502
850
  target: secrets.key,
503
851
  targetWhere: isNull(secrets.userId),
504
852
  set: { kind: 'oauth', valueEncrypted, oauthMeta, updatedAt: new Date() },
505
- });
853
+ ...(guard ? { setWhere: guard } : {}),
854
+ })
855
+ .returning({ id: secrets.id }));
506
856
  this.notifyMutation(null);
507
857
  }
508
858
  async beginToolOAuthByKey(input) {
@@ -532,8 +882,11 @@ export class DbSecretsVaultService {
532
882
  }
533
883
  // The save's own validation (https, no private or local address), BEFORE
534
884
  // the caller's row is written or a URL built: a declaration that fails it
535
- // sends nothing anywhere.
536
- meta = this.requireProvider({ ...input.provider, publicClient: false });
885
+ // sends nothing anywhere. A MANAGED declaration names no client of its
886
+ // own; reaching here means an owner pinned the deployment's own app on
887
+ // the shared row, and that app's id is the one the flow runs with.
888
+ const clientId = input.provider.clientId || this.readMeta(shared.oauthMeta).clientId;
889
+ meta = this.requireProvider({ ...input.provider, clientId, publicClient: false });
537
890
  oauthMeta = this.publicProviderMeta(meta);
538
891
  // A MOVED PROPERTY, decided on the ticket (OAuth-Sign-In-Follows-The-Live-
539
892
  // Declaration, 2026-10-27): the secret used to be bound to the token
@@ -610,14 +963,20 @@ export class DbSecretsVaultService {
610
963
  pendingScopes,
611
964
  };
612
965
  const valueEncrypted = this.crypto().encrypt(JSON.stringify(blob));
613
- const [row] = await this.db
966
+ // A managed sign-in on the caller's row (an owner pinned their own app
967
+ // after the person connected through the broker) is replaced by this
968
+ // start: its tokens are told to the provider first, and the write is
969
+ // guarded on what the revoke read. Tokens carried over above were minted
970
+ // under THIS configuration, never a managed one.
971
+ const row = await this.revokedReplacement(and(eq(secrets.userId, userId), eq(secrets.key, key)), (guard) => this.db
614
972
  .insert(secrets)
615
973
  .values({ userId, key, kind: 'oauth', label: shared.label, valueEncrypted, oauthMeta })
616
974
  .onConflictDoUpdate({
617
975
  target: [secrets.userId, secrets.key],
618
976
  set: { kind: 'oauth', valueEncrypted, oauthMeta, updatedAt: new Date() },
977
+ ...(guard ? { setWhere: guard } : {}),
619
978
  })
620
- .returning();
979
+ .returning());
621
980
  // Build the consent URL exactly as beginOAuth does, from the configuration
622
981
  // this start uses, with the requested scopes chosen above.
623
982
  const url = new URL(meta.authorizationUrl);
@@ -695,10 +1054,16 @@ export class DbSecretsVaultService {
695
1054
  return result.accessToken;
696
1055
  }
697
1056
  async forceRefresh(userId, key) {
1057
+ // The caller's own row, or — for a variable the manual declares shared
1058
+ // (a managed workspace connection) — the one shared row every caller
1059
+ // resolves. Same tier rule as `resolve`, so a 401 against a shared
1060
+ // token repairs the row the call actually used.
1061
+ const scope = (await this.scopeOf?.(key)) ?? 'admin';
1062
+ const scopeFilter = scope === 'user' ? eq(secrets.userId, userId) : isNull(secrets.userId);
698
1063
  const [row] = await this.db
699
1064
  .select()
700
1065
  .from(secrets)
701
- .where(and(eq(secrets.userId, userId), eq(secrets.key, key)))
1066
+ .where(and(scopeFilter, eq(secrets.key, key)))
702
1067
  .limit(1);
703
1068
  if (!row || row.kind !== 'oauth')
704
1069
  return 'skipped';
@@ -739,18 +1104,38 @@ export class DbSecretsVaultService {
739
1104
  return this.wipeTokens(row, blob);
740
1105
  }
741
1106
  const meta = this.readMeta(row.oauthMeta);
742
- const body = new URLSearchParams({
743
- grant_type: 'refresh_token',
744
- refresh_token: tokens.refresh_token,
745
- client_id: meta.clientId,
746
- });
747
- if (blob.clientSecret)
748
- body.set('client_secret', blob.clientSecret);
749
- if (meta.resource)
750
- body.set('resource', meta.resource);
751
1107
  let refreshed;
752
1108
  try {
753
- refreshed = await this.tokenRequest(meta.tokenUrl, body);
1109
+ if (meta.managed) {
1110
+ // A managed sign-in renews through the broker, which holds the
1111
+ // client secret this deployment never sees. No broker wired is an
1112
+ // outage from here, not a dead grant: the stale token is served and
1113
+ // the next call asks again.
1114
+ if (!this.managedRefresher)
1115
+ return { outcome: 'transient' };
1116
+ // Bounded like a revocation: a broker that never answers is an outage
1117
+ // (the stale token is served) and must not hold every resolution.
1118
+ const delivered = await bounded(this.managedRefresher.refresh(meta.managed, tokens.refresh_token), REFRESH_TIMEOUT_MS, 'the broker refresh');
1119
+ refreshed = {
1120
+ access_token: delivered.access_token,
1121
+ refresh_token: delivered.refresh_token,
1122
+ expires_at: delivered.expires_at,
1123
+ token_type: delivered.token_type,
1124
+ scope: delivered.scope,
1125
+ };
1126
+ }
1127
+ else {
1128
+ const body = new URLSearchParams({
1129
+ grant_type: 'refresh_token',
1130
+ refresh_token: tokens.refresh_token,
1131
+ client_id: meta.clientId,
1132
+ });
1133
+ if (blob.clientSecret)
1134
+ body.set('client_secret', blob.clientSecret);
1135
+ if (meta.resource)
1136
+ body.set('resource', meta.resource);
1137
+ refreshed = await this.tokenRequest(meta.tokenUrl, body);
1138
+ }
754
1139
  }
755
1140
  catch (err) {
756
1141
  // A DEFINITIVE provider rejection (400/401 — invalid_grant and friends)
@@ -771,7 +1156,12 @@ export class DbSecretsVaultService {
771
1156
  : result.outcome === 'refreshed'
772
1157
  ? 'the row had been rotated by a concurrent refresh meanwhile; the rotated sign-in is kept'
773
1158
  : 'the row had been removed or replaced meanwhile; nothing wiped';
774
- log.warn(`refresh refused for "${row.key}", ${did}: ${err.message}`);
1159
+ // A managed row's refusal came from the refresher, whose words are its
1160
+ // own (a port may put the refresh token it was handed in them): only
1161
+ // the status it reported is logged. The vault's own token request
1162
+ // writes fixed sentences, which are safe to repeat.
1163
+ const why = meta.managed ? `the broker refused it (HTTP ${err.providerStatus ?? 'unknown'})` : err.message;
1164
+ log.warn(`refresh refused for "${row.key}", ${did}: ${why}`);
775
1165
  return result;
776
1166
  }
777
1167
  return { outcome: 'transient' };
@@ -785,7 +1175,10 @@ export class DbSecretsVaultService {
785
1175
  // value, empty included, is the provider's word.
786
1176
  if (refreshed.scope === undefined)
787
1177
  refreshed.scope = tokens.scope;
788
- const next = { clientSecret: blob.clientSecret, tokens: refreshed };
1178
+ // A sign-in in flight on this row (a managed reconnect waiting for its
1179
+ // handoff, a consent waiting for its exchange) survives the refresh: the
1180
+ // nonce or verifier it minted is what that handoff must match.
1181
+ const next = { clientSecret: blob.clientSecret, tokens: refreshed, ...this.inFlightOf(blob) };
789
1182
  // Optimistic concurrency: only persist if the stored ciphertext is unchanged,
790
1183
  // so a concurrent refresh on the same row doesn't clobber (Microsoft pattern).
791
1184
  const stored = await this.db
@@ -831,9 +1224,23 @@ export class DbSecretsVaultService {
831
1224
  return undefined;
832
1225
  }
833
1226
  }
834
- /** Drop a dead grant's token set, keeping the client secret. See {@link refreshRow}. */
1227
+ /**
1228
+ * What a row holds for a sign-in IN FLIGHT: the one-time nonce a managed
1229
+ * handoff must echo, the PKCE verifier and requested scopes a code exchange
1230
+ * must present. A refresh or a wipe rewrites the row's tokens, never these:
1231
+ * dropping them would refuse the handoff or the exchange that is about to
1232
+ * land, for a reason the person could not see.
1233
+ */
1234
+ inFlightOf(blob) {
1235
+ return {
1236
+ ...(blob.pendingNonce ? { pendingNonce: blob.pendingNonce } : {}),
1237
+ ...(blob.pendingVerifier ? { pendingVerifier: blob.pendingVerifier } : {}),
1238
+ ...(blob.pendingScopes ? { pendingScopes: blob.pendingScopes } : {}),
1239
+ };
1240
+ }
1241
+ /** Drop a dead grant's token set, keeping the client secret and any sign-in in flight. See {@link refreshRow}. */
835
1242
  async wipeTokens(row, blob) {
836
- const next = { clientSecret: blob.clientSecret };
1243
+ const next = { clientSecret: blob.clientSecret, ...this.inFlightOf(blob) };
837
1244
  // Guarded on the ciphertext we read, so a concurrent refresh that
838
1245
  // already persisted ROTATED tokens can't be wiped by our stale
839
1246
  // failure. When that guard trips (0 rows), the failure was against a
@@ -866,7 +1273,7 @@ export class DbSecretsVaultService {
866
1273
  const blob = { clientSecret: provider.clientSecret };
867
1274
  const valueEncrypted = this.crypto().encrypt(JSON.stringify(blob));
868
1275
  const oauthMeta = this.publicProviderMeta(provider);
869
- await this.db
1276
+ await this.revokedReplacement(and(isNull(secrets.userId), eq(secrets.key, key)), (guard) => this.db
870
1277
  .insert(secrets)
871
1278
  .values({ userId: null, key, kind: 'oauth', label, valueEncrypted, oauthMeta })
872
1279
  // Preserve an existing row's label on re-upsert (matches
@@ -876,7 +1283,9 @@ export class DbSecretsVaultService {
876
1283
  target: secrets.key,
877
1284
  targetWhere: isNull(secrets.userId),
878
1285
  set: { kind: 'oauth', valueEncrypted, oauthMeta, updatedAt: new Date() },
879
- });
1286
+ ...(guard ? { setWhere: guard } : {}),
1287
+ })
1288
+ .returning({ id: secrets.id }));
880
1289
  this.notifyMutation(null);
881
1290
  }
882
1291
  async getSharedOAuthProvider(key) {
@@ -970,13 +1379,17 @@ export class DbSecretsVaultService {
970
1379
  const authorizationUrl = typeof meta.authorizationUrl === 'string' ? meta.authorizationUrl : '';
971
1380
  const tokenUrl = typeof meta.tokenUrl === 'string' ? meta.tokenUrl : '';
972
1381
  const clientId = typeof meta.clientId === 'string' ? meta.clientId : '';
973
- if (!authorizationUrl || !tokenUrl || !clientId) {
1382
+ const managed = this.managedRefOf(meta) ?? undefined;
1383
+ // A managed row has no client id of its own (the broker's app is the
1384
+ // client); everything else must name one, or no flow can run from it.
1385
+ if (!authorizationUrl || !tokenUrl || (!clientId && !managed)) {
974
1386
  throw new SecretOAuthError('OAuth secret is missing provider configuration');
975
1387
  }
976
1388
  return {
977
1389
  authorizationUrl,
978
1390
  tokenUrl,
979
1391
  clientId,
1392
+ managed,
980
1393
  scopes: Array.isArray(meta.scopes) ? meta.scopes.map(String) : undefined,
981
1394
  authParams: meta.authParams && typeof meta.authParams === 'object'
982
1395
  ? meta.authParams
@@ -996,16 +1409,27 @@ export class DbSecretsVaultService {
996
1409
  ...(p.pkce ? { pkce: true } : {}),
997
1410
  ...(p.publicClient ? { publicClient: true } : {}),
998
1411
  ...(p.resource ? { resource: p.resource } : {}),
1412
+ ...(p.managed ? { managed: { connectorId: p.managed.connectorId, scopeSet: p.managed.scopeSet } } : {}),
1413
+ ...(p.account ? { account: p.account } : {}),
999
1414
  };
1000
1415
  }
1001
- requireProvider(p) {
1416
+ /**
1417
+ * @param opts.managed Accept a MANAGED provider (no client id of its own,
1418
+ * a connector reference instead). Only the managed sign-in paths pass it:
1419
+ * everywhere else a provider needs a client id, and a `managed` field a
1420
+ * caller slipped in is dropped rather than making the row one.
1421
+ */
1422
+ requireProvider(p, opts = {}) {
1002
1423
  if (!p || typeof p !== 'object')
1003
1424
  throw new InvalidSecretError('provider is required');
1004
1425
  const cfg = p;
1005
1426
  const authorizationUrl = this.requireUrl(cfg.authorizationUrl, 'authorizationUrl');
1006
1427
  const tokenUrl = this.requireUrl(cfg.tokenUrl, 'tokenUrl');
1007
- const clientId = typeof cfg.clientId === 'string' ? cfg.clientId.trim() : '';
1008
- if (!clientId)
1428
+ const managed = opts.managed ? (this.managedRefOf(cfg) ?? undefined) : undefined;
1429
+ // A managed sign-in has no client of its own: whatever id a caller sends
1430
+ // beside the connector reference is not stored, so no row can claim one.
1431
+ const clientId = managed ? '' : typeof cfg.clientId === 'string' ? cfg.clientId.trim() : '';
1432
+ if (!clientId && !managed)
1009
1433
  throw new InvalidSecretError('clientId is required');
1010
1434
  const scopes = Array.isArray(cfg.scopes) ? cfg.scopes.map(String) : undefined;
1011
1435
  const authParams = cfg.authParams && typeof cfg.authParams === 'object'
@@ -1025,6 +1449,8 @@ export class DbSecretsVaultService {
1025
1449
  resource: typeof cfg.resource === 'string' && cfg.resource.trim()
1026
1450
  ? this.requireUrl(cfg.resource, 'resource')
1027
1451
  : undefined,
1452
+ managed,
1453
+ account: typeof cfg.account === 'string' && cfg.account.trim() ? cfg.account.trim().slice(0, MAX_LABEL_LEN) : undefined,
1028
1454
  };
1029
1455
  }
1030
1456
  requireUrl(value, field) {