reviewflow 3.22.0 → 3.24.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 (219) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +44 -1
  3. package/dist/config/projectConfig.d.ts +1 -0
  4. package/dist/config/projectConfig.d.ts.map +1 -1
  5. package/dist/config/projectConfig.js +13 -0
  6. package/dist/config/projectConfig.js.map +1 -1
  7. package/dist/dashboard/index.html +30 -6
  8. package/dist/dashboard/modules/desktopNotifications.d.ts +7 -1
  9. package/dist/dashboard/modules/desktopNotifications.d.ts.map +1 -1
  10. package/dist/dashboard/modules/desktopNotifications.js +194 -15
  11. package/dist/dashboard/modules/desktopNotifications.js.map +1 -1
  12. package/dist/dashboard/modules/i18n.d.ts.map +1 -1
  13. package/dist/dashboard/modules/i18n.js +22 -2
  14. package/dist/dashboard/modules/i18n.js.map +1 -1
  15. package/dist/dashboard/modules/settingsModal.d.ts +17 -0
  16. package/dist/dashboard/modules/settingsModal.d.ts.map +1 -1
  17. package/dist/dashboard/modules/settingsModal.js +33 -0
  18. package/dist/dashboard/modules/settingsModal.js.map +1 -1
  19. package/dist/frameworks/claude/claudeInvoker.d.ts +2 -0
  20. package/dist/frameworks/claude/claudeInvoker.d.ts.map +1 -1
  21. package/dist/frameworks/claude/claudeInvoker.js +14 -3
  22. package/dist/frameworks/claude/claudeInvoker.js.map +1 -1
  23. package/dist/frameworks/queue/pQueueAdapter.d.ts +27 -0
  24. package/dist/frameworks/queue/pQueueAdapter.d.ts.map +1 -1
  25. package/dist/frameworks/queue/pQueueAdapter.js +4 -0
  26. package/dist/frameworks/queue/pQueueAdapter.js.map +1 -1
  27. package/dist/main/routes.d.ts.map +1 -1
  28. package/dist/main/routes.js +20 -0
  29. package/dist/main/routes.js.map +1 -1
  30. package/dist/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.d.ts.map +1 -1
  31. package/dist/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.js +13 -0
  32. package/dist/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.js.map +1 -1
  33. package/dist/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.d.ts +4 -2
  34. package/dist/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.d.ts.map +1 -1
  35. package/dist/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.js +21 -0
  36. package/dist/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.js.map +1 -1
  37. package/dist/modules/platform-integration/entities/approvalRevocation/approvalRevocation.gateway.d.ts +10 -0
  38. package/dist/modules/platform-integration/entities/approvalRevocation/approvalRevocation.gateway.d.ts.map +1 -0
  39. package/dist/modules/platform-integration/entities/approvalRevocation/approvalRevocation.gateway.js +2 -0
  40. package/dist/modules/platform-integration/entities/approvalRevocation/approvalRevocation.gateway.js.map +1 -0
  41. package/dist/modules/platform-integration/entities/github/githubIssueCommentEvent.guard.d.ts +50 -0
  42. package/dist/modules/platform-integration/entities/github/githubIssueCommentEvent.guard.d.ts.map +1 -0
  43. package/dist/modules/platform-integration/entities/github/githubIssueCommentEvent.guard.js +21 -0
  44. package/dist/modules/platform-integration/entities/github/githubIssueCommentEvent.guard.js.map +1 -0
  45. package/dist/modules/platform-integration/entities/github/githubPullRequestEvent.guard.d.ts +12 -0
  46. package/dist/modules/platform-integration/entities/github/githubPullRequestEvent.guard.d.ts.map +1 -1
  47. package/dist/modules/platform-integration/entities/github/githubPullRequestEvent.guard.js +4 -0
  48. package/dist/modules/platform-integration/entities/github/githubPullRequestEvent.guard.js.map +1 -1
  49. package/dist/modules/platform-integration/entities/github/githubPullRequestReviewEvent.guard.d.ts +53 -0
  50. package/dist/modules/platform-integration/entities/github/githubPullRequestReviewEvent.guard.d.ts.map +1 -0
  51. package/dist/modules/platform-integration/entities/github/githubPullRequestReviewEvent.guard.js +23 -0
  52. package/dist/modules/platform-integration/entities/github/githubPullRequestReviewEvent.guard.js.map +1 -0
  53. package/dist/modules/platform-integration/entities/gitlab/gitlabNoteEvent.guard.d.ts +62 -0
  54. package/dist/modules/platform-integration/entities/gitlab/gitlabNoteEvent.guard.d.ts.map +1 -0
  55. package/dist/modules/platform-integration/entities/gitlab/gitlabNoteEvent.guard.js +33 -0
  56. package/dist/modules/platform-integration/entities/gitlab/gitlabNoteEvent.guard.js.map +1 -0
  57. package/dist/modules/platform-integration/entities/noteComment/noteCommentPost.gateway.d.ts +9 -0
  58. package/dist/modules/platform-integration/entities/noteComment/noteCommentPost.gateway.d.ts.map +1 -0
  59. package/dist/modules/platform-integration/entities/noteComment/noteCommentPost.gateway.js +2 -0
  60. package/dist/modules/platform-integration/entities/noteComment/noteCommentPost.gateway.js.map +1 -0
  61. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/eventFilter.d.ts +28 -0
  62. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/eventFilter.d.ts.map +1 -1
  63. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/eventFilter.js +48 -0
  64. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/eventFilter.js.map +1 -1
  65. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/github.controller.d.ts +10 -0
  66. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/github.controller.d.ts.map +1 -1
  67. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/github.controller.js +171 -1
  68. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/github.controller.js.map +1 -1
  69. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/gitlab.controller.d.ts +10 -0
  70. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/gitlab.controller.d.ts.map +1 -1
  71. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/gitlab.controller.js +132 -5
  72. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/gitlab.controller.js.map +1 -1
  73. package/dist/modules/platform-integration/interface-adapters/gateways/cli/approvalRevocation.github.cli.gateway.d.ts +8 -0
  74. package/dist/modules/platform-integration/interface-adapters/gateways/cli/approvalRevocation.github.cli.gateway.d.ts.map +1 -0
  75. package/dist/modules/platform-integration/interface-adapters/gateways/cli/approvalRevocation.github.cli.gateway.js +15 -0
  76. package/dist/modules/platform-integration/interface-adapters/gateways/cli/approvalRevocation.github.cli.gateway.js.map +1 -0
  77. package/dist/modules/platform-integration/interface-adapters/gateways/cli/approvalRevocation.gitlab.cli.gateway.d.ts +8 -0
  78. package/dist/modules/platform-integration/interface-adapters/gateways/cli/approvalRevocation.gitlab.cli.gateway.d.ts.map +1 -0
  79. package/dist/modules/platform-integration/interface-adapters/gateways/cli/approvalRevocation.gitlab.cli.gateway.js +12 -0
  80. package/dist/modules/platform-integration/interface-adapters/gateways/cli/approvalRevocation.gitlab.cli.gateway.js.map +1 -0
  81. package/dist/modules/platform-integration/interface-adapters/gateways/cli/noteCommentPost.github.cli.gateway.d.ts +8 -0
  82. package/dist/modules/platform-integration/interface-adapters/gateways/cli/noteCommentPost.github.cli.gateway.d.ts.map +1 -0
  83. package/dist/modules/platform-integration/interface-adapters/gateways/cli/noteCommentPost.github.cli.gateway.js +11 -0
  84. package/dist/modules/platform-integration/interface-adapters/gateways/cli/noteCommentPost.github.cli.gateway.js.map +1 -0
  85. package/dist/modules/platform-integration/interface-adapters/gateways/cli/noteCommentPost.gitlab.cli.gateway.d.ts +8 -0
  86. package/dist/modules/platform-integration/interface-adapters/gateways/cli/noteCommentPost.gitlab.cli.gateway.d.ts.map +1 -0
  87. package/dist/modules/platform-integration/interface-adapters/gateways/cli/noteCommentPost.gitlab.cli.gateway.js +12 -0
  88. package/dist/modules/platform-integration/interface-adapters/gateways/cli/noteCommentPost.gitlab.cli.gateway.js.map +1 -0
  89. package/dist/modules/tracking/entities/bypassMarker/bypassMarker.d.ts +10 -0
  90. package/dist/modules/tracking/entities/bypassMarker/bypassMarker.d.ts.map +1 -0
  91. package/dist/modules/tracking/entities/bypassMarker/bypassMarker.js +17 -0
  92. package/dist/modules/tracking/entities/bypassMarker/bypassMarker.js.map +1 -0
  93. package/dist/modules/tracking/entities/qualityGate/qualityGate.d.ts +15 -0
  94. package/dist/modules/tracking/entities/qualityGate/qualityGate.d.ts.map +1 -0
  95. package/dist/modules/tracking/entities/qualityGate/qualityGate.js +24 -0
  96. package/dist/modules/tracking/entities/qualityGate/qualityGate.js.map +1 -0
  97. package/dist/modules/tracking/entities/tracking/trackedMr.d.ts +6 -0
  98. package/dist/modules/tracking/entities/tracking/trackedMr.d.ts.map +1 -1
  99. package/dist/modules/tracking/entities/tracking/trackedMr.js.map +1 -1
  100. package/dist/modules/tracking/interface-adapters/controllers/http/mrTracking.routes.d.ts +1 -0
  101. package/dist/modules/tracking/interface-adapters/controllers/http/mrTracking.routes.d.ts.map +1 -1
  102. package/dist/modules/tracking/interface-adapters/controllers/http/mrTracking.routes.js +14 -3
  103. package/dist/modules/tracking/interface-adapters/controllers/http/mrTracking.routes.js.map +1 -1
  104. package/dist/modules/tracking/interface-adapters/controllers/http/mrTrackingAdvanced.routes.d.ts.map +1 -1
  105. package/dist/modules/tracking/interface-adapters/controllers/http/mrTrackingAdvanced.routes.js +1 -0
  106. package/dist/modules/tracking/interface-adapters/controllers/http/mrTrackingAdvanced.routes.js.map +1 -1
  107. package/dist/modules/tracking/usecases/tracking/handlePlatformApproval.usecase.d.ts +28 -0
  108. package/dist/modules/tracking/usecases/tracking/handlePlatformApproval.usecase.d.ts.map +1 -0
  109. package/dist/modules/tracking/usecases/tracking/handlePlatformApproval.usecase.js +37 -0
  110. package/dist/modules/tracking/usecases/tracking/handlePlatformApproval.usecase.js.map +1 -0
  111. package/dist/modules/tracking/usecases/tracking/recordBypass.usecase.d.ts +28 -0
  112. package/dist/modules/tracking/usecases/tracking/recordBypass.usecase.d.ts.map +1 -0
  113. package/dist/modules/tracking/usecases/tracking/recordBypass.usecase.js +28 -0
  114. package/dist/modules/tracking/usecases/tracking/recordBypass.usecase.js.map +1 -0
  115. package/dist/modules/tracking/usecases/tracking/recordReviewCompletion.usecase.d.ts +1 -0
  116. package/dist/modules/tracking/usecases/tracking/recordReviewCompletion.usecase.d.ts.map +1 -1
  117. package/dist/modules/tracking/usecases/tracking/recordReviewCompletion.usecase.js +10 -1
  118. package/dist/modules/tracking/usecases/tracking/recordReviewCompletion.usecase.js.map +1 -1
  119. package/dist/modules/tracking/usecases/tracking/trackAssignment.usecase.d.ts.map +1 -1
  120. package/dist/modules/tracking/usecases/tracking/trackAssignment.usecase.js +1 -0
  121. package/dist/modules/tracking/usecases/tracking/trackAssignment.usecase.js.map +1 -1
  122. package/dist/modules/tracking/usecases/tracking/transitionState.usecase.d.ts +15 -2
  123. package/dist/modules/tracking/usecases/tracking/transitionState.usecase.d.ts.map +1 -1
  124. package/dist/modules/tracking/usecases/tracking/transitionState.usecase.js +8 -2
  125. package/dist/modules/tracking/usecases/tracking/transitionState.usecase.js.map +1 -1
  126. package/dist/modules/worktree-management/entities/gitCommand/gitCommand.gateway.d.ts +1 -1
  127. package/dist/modules/worktree-management/entities/gitCommand/gitCommand.gateway.d.ts.map +1 -1
  128. package/dist/modules/worktree-management/services/claudeCwd.d.ts +15 -0
  129. package/dist/modules/worktree-management/services/claudeCwd.d.ts.map +1 -0
  130. package/dist/modules/worktree-management/services/claudeCwd.js +45 -0
  131. package/dist/modules/worktree-management/services/claudeCwd.js.map +1 -0
  132. package/dist/tests/acceptance/170-prebuilt-worktree-lifecycle.acceptance.test.js +1 -0
  133. package/dist/tests/acceptance/170-prebuilt-worktree-lifecycle.acceptance.test.js.map +1 -1
  134. package/dist/tests/acceptance/180-quality-threshold-block-approval-iter-B.acceptance.test.d.ts +17 -0
  135. package/dist/tests/acceptance/180-quality-threshold-block-approval-iter-B.acceptance.test.d.ts.map +1 -0
  136. package/dist/tests/acceptance/180-quality-threshold-block-approval-iter-B.acceptance.test.js +294 -0
  137. package/dist/tests/acceptance/180-quality-threshold-block-approval-iter-B.acceptance.test.js.map +1 -0
  138. package/dist/tests/acceptance/180-quality-threshold-block-approval-iter-C.acceptance.test.d.ts +16 -0
  139. package/dist/tests/acceptance/180-quality-threshold-block-approval-iter-C.acceptance.test.d.ts.map +1 -0
  140. package/dist/tests/acceptance/180-quality-threshold-block-approval-iter-C.acceptance.test.js +316 -0
  141. package/dist/tests/acceptance/180-quality-threshold-block-approval-iter-C.acceptance.test.js.map +1 -0
  142. package/dist/tests/acceptance/180-quality-threshold-block-approval.acceptance.test.d.ts +20 -0
  143. package/dist/tests/acceptance/180-quality-threshold-block-approval.acceptance.test.d.ts.map +1 -0
  144. package/dist/tests/acceptance/180-quality-threshold-block-approval.acceptance.test.js +146 -0
  145. package/dist/tests/acceptance/180-quality-threshold-block-approval.acceptance.test.js.map +1 -0
  146. package/dist/tests/factories/projectConfig.factory.d.ts +1 -0
  147. package/dist/tests/factories/projectConfig.factory.d.ts.map +1 -1
  148. package/dist/tests/factories/projectConfig.factory.js +3 -0
  149. package/dist/tests/factories/projectConfig.factory.js.map +1 -1
  150. package/dist/tests/factories/trackedMr.factory.d.ts.map +1 -1
  151. package/dist/tests/factories/trackedMr.factory.js +1 -0
  152. package/dist/tests/factories/trackedMr.factory.js.map +1 -1
  153. package/dist/tests/stubs/approvalRevocation.stub.d.ts +7 -0
  154. package/dist/tests/stubs/approvalRevocation.stub.d.ts.map +1 -0
  155. package/dist/tests/stubs/approvalRevocation.stub.js +11 -0
  156. package/dist/tests/stubs/approvalRevocation.stub.js.map +1 -0
  157. package/dist/tests/stubs/noteCommentPost.stub.d.ts +6 -0
  158. package/dist/tests/stubs/noteCommentPost.stub.d.ts.map +1 -0
  159. package/dist/tests/stubs/noteCommentPost.stub.js +7 -0
  160. package/dist/tests/stubs/noteCommentPost.stub.js.map +1 -0
  161. package/dist/tests/units/config/projectConfig.test.js +62 -0
  162. package/dist/tests/units/config/projectConfig.test.js.map +1 -1
  163. package/dist/tests/units/dashboard/modules/desktopNotifications.test.js +230 -13
  164. package/dist/tests/units/dashboard/modules/desktopNotifications.test.js.map +1 -1
  165. package/dist/tests/units/dashboard/modules/settingsModal.test.js +106 -2
  166. package/dist/tests/units/dashboard/modules/settingsModal.test.js.map +1 -1
  167. package/dist/tests/units/interface-adapters/controllers/webhook/eventFilter.test.js +50 -1
  168. package/dist/tests/units/interface-adapters/controllers/webhook/eventFilter.test.js.map +1 -1
  169. package/dist/tests/units/interface-adapters/controllers/webhook/github.controller.test.js +6 -0
  170. package/dist/tests/units/interface-adapters/controllers/webhook/github.controller.test.js.map +1 -1
  171. package/dist/tests/units/interface-adapters/controllers/webhook/gitlab.controller.test.js +10 -0
  172. package/dist/tests/units/interface-adapters/controllers/webhook/gitlab.controller.test.js.map +1 -1
  173. package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.test.js +39 -0
  174. package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.test.js.map +1 -1
  175. package/dist/tests/units/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.test.js +69 -0
  176. package/dist/tests/units/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.test.js.map +1 -1
  177. package/dist/tests/units/modules/platform-integration/entities/github/githubIssueCommentEvent.guard.test.d.ts +2 -0
  178. package/dist/tests/units/modules/platform-integration/entities/github/githubIssueCommentEvent.guard.test.d.ts.map +1 -0
  179. package/dist/tests/units/modules/platform-integration/entities/github/githubIssueCommentEvent.guard.test.js +39 -0
  180. package/dist/tests/units/modules/platform-integration/entities/github/githubIssueCommentEvent.guard.test.js.map +1 -0
  181. package/dist/tests/units/modules/platform-integration/entities/github/githubPullRequestReviewEvent.guard.test.d.ts +2 -0
  182. package/dist/tests/units/modules/platform-integration/entities/github/githubPullRequestReviewEvent.guard.test.d.ts.map +1 -0
  183. package/dist/tests/units/modules/platform-integration/entities/github/githubPullRequestReviewEvent.guard.test.js +54 -0
  184. package/dist/tests/units/modules/platform-integration/entities/github/githubPullRequestReviewEvent.guard.test.js.map +1 -0
  185. package/dist/tests/units/modules/platform-integration/entities/gitlab/gitlabNoteEvent.guard.test.d.ts +2 -0
  186. package/dist/tests/units/modules/platform-integration/entities/gitlab/gitlabNoteEvent.guard.test.d.ts.map +1 -0
  187. package/dist/tests/units/modules/platform-integration/entities/gitlab/gitlabNoteEvent.guard.test.js +48 -0
  188. package/dist/tests/units/modules/platform-integration/entities/gitlab/gitlabNoteEvent.guard.test.js.map +1 -0
  189. package/dist/tests/units/modules/tracking/entities/bypassMarker/bypassMarker.test.d.ts +2 -0
  190. package/dist/tests/units/modules/tracking/entities/bypassMarker/bypassMarker.test.d.ts.map +1 -0
  191. package/dist/tests/units/modules/tracking/entities/bypassMarker/bypassMarker.test.js +29 -0
  192. package/dist/tests/units/modules/tracking/entities/bypassMarker/bypassMarker.test.js.map +1 -0
  193. package/dist/tests/units/modules/tracking/entities/qualityGate/qualityGate.test.d.ts +2 -0
  194. package/dist/tests/units/modules/tracking/entities/qualityGate/qualityGate.test.d.ts.map +1 -0
  195. package/dist/tests/units/modules/tracking/entities/qualityGate/qualityGate.test.js +52 -0
  196. package/dist/tests/units/modules/tracking/entities/qualityGate/qualityGate.test.js.map +1 -0
  197. package/dist/tests/units/modules/tracking/interface-adapters/controllers/http/mrTracking.routes.test.d.ts +2 -0
  198. package/dist/tests/units/modules/tracking/interface-adapters/controllers/http/mrTracking.routes.test.d.ts.map +1 -0
  199. package/dist/tests/units/modules/tracking/interface-adapters/controllers/http/mrTracking.routes.test.js +103 -0
  200. package/dist/tests/units/modules/tracking/interface-adapters/controllers/http/mrTracking.routes.test.js.map +1 -0
  201. package/dist/tests/units/modules/tracking/usecases/tracking/handlePlatformApproval.usecase.test.d.ts +2 -0
  202. package/dist/tests/units/modules/tracking/usecases/tracking/handlePlatformApproval.usecase.test.d.ts.map +1 -0
  203. package/dist/tests/units/modules/tracking/usecases/tracking/handlePlatformApproval.usecase.test.js +113 -0
  204. package/dist/tests/units/modules/tracking/usecases/tracking/handlePlatformApproval.usecase.test.js.map +1 -0
  205. package/dist/tests/units/modules/tracking/usecases/tracking/recordBypass.usecase.test.d.ts +2 -0
  206. package/dist/tests/units/modules/tracking/usecases/tracking/recordBypass.usecase.test.d.ts.map +1 -0
  207. package/dist/tests/units/modules/tracking/usecases/tracking/recordBypass.usecase.test.js +77 -0
  208. package/dist/tests/units/modules/tracking/usecases/tracking/recordBypass.usecase.test.js.map +1 -0
  209. package/dist/tests/units/modules/worktree-management/services/claudeCwd.test.d.ts +2 -0
  210. package/dist/tests/units/modules/worktree-management/services/claudeCwd.test.d.ts.map +1 -0
  211. package/dist/tests/units/modules/worktree-management/services/claudeCwd.test.js +111 -0
  212. package/dist/tests/units/modules/worktree-management/services/claudeCwd.test.js.map +1 -0
  213. package/dist/tests/units/modules/worktree-management/usecases/sweepStaleWorktrees.usecase.test.js +1 -0
  214. package/dist/tests/units/modules/worktree-management/usecases/sweepStaleWorktrees.usecase.test.js.map +1 -1
  215. package/dist/tests/units/usecases/tracking/recordReviewCompletion.usecase.test.js +71 -0
  216. package/dist/tests/units/usecases/tracking/recordReviewCompletion.usecase.test.js.map +1 -1
  217. package/dist/tests/units/usecases/tracking/transitionState.usecase.test.js +87 -4
  218. package/dist/tests/units/usecases/tracking/transitionState.usecase.test.js.map +1 -1
  219. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.24.0](https://github.com/DGouron/review-flow/compare/reviewflow-v3.23.0...reviewflow-v3.24.0) (2026-05-26)
9
+
10
+
11
+ ### Added
12
+
13
+ * **dashboard:** expose qualityThreshold in settings + read-only display ([#214](https://github.com/DGouron/review-flow/issues/214)) ([2d65635](https://github.com/DGouron/review-flow/commit/2d65635b1a24d4d6e30b52f79c21d1ab131e5cf8))
14
+ * **dashboard:** rich, interactive desktop notifications ([#213](https://github.com/DGouron/review-flow/issues/213)) ([3c2580a](https://github.com/DGouron/review-flow/commit/3c2580a104147da67c7bd71bd943a47f9f6517b2))
15
+
16
+
17
+ ### Fixed
18
+
19
+ * **worktree:** preserve sub-path between localPath and gitRoot when launching Claude ([#216](https://github.com/DGouron/review-flow/issues/216)) ([b4867c8](https://github.com/DGouron/review-flow/commit/b4867c8c8809dd93e72980357aad309cdd82e1e6))
20
+
21
+ ## [3.23.0](https://github.com/DGouron/review-flow/compare/reviewflow-v3.22.0...reviewflow-v3.23.0) (2026-05-26)
22
+
23
+
24
+ ### Added
25
+
26
+ * **tracking:** block approval below quality threshold (SPEC-180 iter A) ([#209](https://github.com/DGouron/review-flow/issues/209)) ([9b1f4ca](https://github.com/DGouron/review-flow/commit/9b1f4ca9b40df65b612176465014592f7aab9a73))
27
+ * **tracking:** comment-based bypass for quality gate (SPEC-180 iter B) ([#211](https://github.com/DGouron/review-flow/issues/211)) ([77e6356](https://github.com/DGouron/review-flow/commit/77e6356c2780f6300cd6a127f170a282ba72c4e0))
28
+ * **tracking:** platform unapprove + FR comment on non-qualified MR (SPEC-180 iter C) ([#212](https://github.com/DGouron/review-flow/issues/212)) ([35c5e32](https://github.com/DGouron/review-flow/commit/35c5e320bb8879fc26d14253be4071de0d08d78b))
29
+
8
30
  ## [3.22.0](https://github.com/DGouron/review-flow/compare/reviewflow-v3.21.0...reviewflow-v3.22.0) (2026-05-25)
9
31
 
10
32
 
package/README.md CHANGED
@@ -26,7 +26,11 @@ GitLab/GitHub webhook ──► Review server receives event
26
26
  Queue deduplicates & schedules
27
27
 
28
28
 
29
- Claude Code runs review skill
29
+ Pre-built worktree ensured
30
+ (~/.reviewflow/worktrees/...)
31
+
32
+
33
+ Claude Code dispatched in --bg mode
30
34
 
31
35
  ┌─────────┼─────────┐
32
36
  ▼ ▼ ▼
@@ -45,6 +49,7 @@ GitLab/GitHub webhook ──► Review server receives event
45
49
 
46
50
 
47
51
  Dev pushes fixes ──► Auto follow-up
52
+ (same worktree, fast-forwarded)
48
53
  ```
49
54
 
50
55
  ---
@@ -148,6 +153,43 @@ Review behavior is defined by [Claude Code skills](https://docs.anthropic.com/en
148
153
 
149
154
  ---
150
155
 
156
+ ## Under the Hood
157
+
158
+ For contributors and curious operators — what actually happens between the webhook and the posted review.
159
+
160
+ ### Background sessions, not foreground spawn
161
+
162
+ Earlier versions of Reviewflow invoked `claude -p` and streamed JSON in the foreground. The server now dispatches each review as a **detached background session** with `claude --bg`. The Fastify process returns the session ID immediately and observes completion asynchronously.
163
+
164
+ Completion is detected via **three independent signals in first-wins semantics**:
165
+
166
+ 1. **MCP `set_phase('completed')`** — Claude's skill calls the MCP server when the review finishes
167
+ 2. **`claude agents --json` polling** — every 30s, looks for `completed` / `failed` / `stopped`
168
+ 3. **15-minute hard timeout** — backstop if the other two miss
169
+
170
+ Whichever fires first wins; the other two are cancelled. The review report is then read from `<worktree>/.claude/reviews/report-<mrNumber>.md` and the session is cleaned with `claude stop` + `claude rm`.
171
+
172
+ ### Isolated git worktrees
173
+
174
+ Each MR runs in its own pre-built git worktree at `~/.reviewflow/worktrees/<platform>-<slug>-<mrNumber>`. This:
175
+
176
+ - **Isolates concurrent reviews** so they cannot step on each other's index
177
+ - **Keeps your main checkout untouched** — `git checkout` inside Claude no longer pollutes your working branch
178
+ - **Speeds up followups** — the worktree is fetched + reset to the new HEAD, never recreated from scratch
179
+ - **Self-cleans** — `removeWorktree` runs on merge/close, plus a daily sweep reclaims worktrees of MRs closed >24h ago or with `mtime` >7 days
180
+
181
+ Full state machine: [Worktree Lifecycle](https://dgouron.github.io/review-flow/architecture/worktree-lifecycle).
182
+
183
+ ### Supervisor health
184
+
185
+ The Claude agents supervisor (long-running daemon that hosts background sessions) is probed every 60 seconds. If it dies, a detached spawn brings it back under a PID-validated file lock at `~/.reviewflow/supervisor.lock`. The `/health` endpoint surfaces the live state and reports `status: degraded` when the supervisor is down — Reviewflow keeps booting, but reviews will fail fast.
186
+
187
+ ### Token budget cap
188
+
189
+ Every session's token usage is parsed from the Claude transcript and persisted. A configurable monthly budget caps further dispatch and broadcasts a budget panel update over WebSocket whenever a session completes. The hourly billing audit calls `claude /usage` and pauses dispatch if it detects unexpected API-pool usage (the OAuth subscription is the only billing path that should be active).
190
+
191
+ ---
192
+
151
193
  ## Quick Start
152
194
 
153
195
  ### 1. Install
@@ -219,6 +261,7 @@ For detailed setup, see the **[Quick Start Guide](https://dgouron.github.io/revi
219
261
  | Review Skills Guide | [guide/review-skills](https://dgouron.github.io/review-flow/guide/review-skills) |
220
262
  | MCP Tools Reference | [reference/mcp-tools](https://dgouron.github.io/review-flow/reference/mcp-tools) |
221
263
  | Architecture | [architecture](https://dgouron.github.io/review-flow/architecture/) |
264
+ | Worktree Lifecycle | [architecture/worktree-lifecycle](https://dgouron.github.io/review-flow/architecture/worktree-lifecycle) |
222
265
  | Deployment | [deployment](https://dgouron.github.io/review-flow/deployment/) |
223
266
  | Troubleshooting | [guide/troubleshooting](https://dgouron.github.io/review-flow/guide/troubleshooting) |
224
267
 
@@ -15,6 +15,7 @@ export interface ProjectConfig {
15
15
  followupAgents?: AgentDefinition[];
16
16
  routingPolicy?: RoutingPolicy;
17
17
  externalLink?: string;
18
+ qualityThreshold?: number;
18
19
  }
19
20
  /**
20
21
  * Load project configuration from .claude/reviews/config.json
@@ -1 +1 @@
1
- {"version":3,"file":"projectConfig.d.ts","sourceRoot":"","sources":["../../src/config/projectConfig.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sEAAsE,CAAC;AAC5G,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8DAA8D,CAAC;AAC7F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yEAAyE,CAAC;AAC7G,OAAO,EACL,KAAK,WAAW,EAKjB,MAAM,kEAAkE,CAAC;AAG1E,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,eAAe,EAAE,CAAC;IACnC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA8ED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAU9E;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,aAAa,CAqEjF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,EAAE,GAAG,SAAS,CAOjF;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,MAAM,GAChB,eAAe,EAAE,GAAG,SAAS,CAgB/B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,CAO9D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAOjE;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,EAAE,GAAG,SAAS,CAOlF"}
1
+ {"version":3,"file":"projectConfig.d.ts","sourceRoot":"","sources":["../../src/config/projectConfig.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sEAAsE,CAAC;AAC5G,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8DAA8D,CAAC;AAC7F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yEAAyE,CAAC;AAC7G,OAAO,EACL,KAAK,WAAW,EAKjB,MAAM,kEAAkE,CAAC;AAG1E,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,eAAe,EAAE,CAAC;IACnC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAwFD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAU9E;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,aAAa,CA0EjF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,EAAE,GAAG,SAAS,CAOjF;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,MAAM,GAChB,eAAe,EAAE,GAAG,SAAS,CAgB/B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,CAO9D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAOjE;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,EAAE,GAAG,SAAS,CAOlF"}
@@ -18,6 +18,15 @@ function parseRetentionDays(value) {
18
18
  }
19
19
  return DEFAULT_RETENTION_DAYS;
20
20
  }
21
+ function parseQualityThreshold(value) {
22
+ if (value === undefined || value === null) {
23
+ return undefined;
24
+ }
25
+ if (typeof value !== 'number' || !Number.isInteger(value) || value < 0 || value > 10) {
26
+ throw new Error('Invalid qualityThreshold: must be an integer between 0 and 10');
27
+ }
28
+ return value;
29
+ }
21
30
  function validateAgents(agents) {
22
31
  if (!Array.isArray(agents)) {
23
32
  return false;
@@ -134,6 +143,10 @@ export function parseProjectConfig(parsed) {
134
143
  if (externalLink !== undefined) {
135
144
  config.externalLink = externalLink;
136
145
  }
146
+ const qualityThreshold = parseQualityThreshold(parsed.qualityThreshold);
147
+ if (qualityThreshold !== undefined) {
148
+ config.qualityThreshold = qualityThreshold;
149
+ }
137
150
  return config;
138
151
  }
139
152
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"projectConfig.js","sourceRoot":"","sources":["../../src/config/projectConfig.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"projectConfig.js","sourceRoot":"","sources":["../../src/config/projectConfig.ts"],"names":[],"mappings":"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"}
@@ -399,6 +399,7 @@
399
399
  buildSettingsViewModel,
400
400
  renderSettingsModalHtml,
401
401
  validateExternalLink,
402
+ validateQualityThreshold,
402
403
  extractFormPayload,
403
404
  } from './modules/settingsModal.js';
404
405
 
@@ -664,10 +665,18 @@
664
665
 
665
666
  const desktopPayload = getDesktopNotificationPayload(notification, t);
666
667
  if (!desktopPayload) return;
667
- new Notification(desktopPayload.title, {
668
+ const desktopNotif = new Notification(desktopPayload.title, {
668
669
  body: desktopPayload.body,
669
670
  tag: desktopPayload.tag,
671
+ icon: desktopPayload.iconDataUri,
670
672
  });
673
+ desktopNotif.onclick = () => {
674
+ window.focus();
675
+ if (desktopPayload.url) {
676
+ window.open(desktopPayload.url, '_blank', 'noopener');
677
+ }
678
+ desktopNotif.close();
679
+ };
671
680
  }
672
681
 
673
682
  function dispatchReviewNotifications(activeReviews, recentReviews) {
@@ -1708,12 +1717,13 @@
1708
1717
  const assigneeDisplay = mr.assignment?.displayName || assigneeUsername;
1709
1718
  const ownerLabel = t('lane.owner', { owner: assigneeDisplay });
1710
1719
  const qualityScore = typeof mr.latestScore === 'number' ? mr.latestScore : null;
1711
- const qualityProgress = getQualityProgress(qualityScore, QUALITY_TARGET_SCORE);
1720
+ const activeQualityTarget = currentProjectConfig?.qualityThreshold ?? QUALITY_TARGET_SCORE;
1721
+ const qualityProgress = getQualityProgress(qualityScore, activeQualityTarget);
1712
1722
  const qualityTarget = qualityProgress.qualityTarget;
1713
1723
  const qualityDelta = qualityProgress.targetDelta;
1714
1724
  const qualityState = qualityScore === null
1715
1725
  ? 'unknown'
1716
- : qualityScore >= QUALITY_TARGET_SCORE
1726
+ : qualityScore >= activeQualityTarget
1717
1727
  ? 'excellent'
1718
1728
  : qualityScore >= 6
1719
1729
  ? 'warning'
@@ -1722,7 +1732,7 @@
1722
1732
  ? t('quality.notAvailable')
1723
1733
  : qualityScore >= 10
1724
1734
  ? t('quality.perfect')
1725
- : qualityScore >= QUALITY_TARGET_SCORE
1735
+ : qualityScore >= activeQualityTarget
1726
1736
  ? t('quality.onTarget')
1727
1737
  : qualityScore >= 6
1728
1738
  ? t('quality.belowTarget')
@@ -1852,7 +1862,9 @@
1852
1862
  const pendingApprovalCount = document.getElementById('pending-approval-count');
1853
1863
 
1854
1864
  pendingFixSection.classList.remove('hidden');
1855
- const rankedPendingFix = rankPendingFixForNowLane(currentData.pendingFix);
1865
+ const rankedPendingFix = rankPendingFixForNowLane(currentData.pendingFix, {
1866
+ qualityTarget: currentProjectConfig?.qualityThreshold ?? QUALITY_TARGET_SCORE,
1867
+ });
1856
1868
  const queueLanesModel = buildQueueLanesModel(rankedPendingFix, currentData.pendingApproval);
1857
1869
 
1858
1870
  mrDataStore.clear();
@@ -2577,13 +2589,21 @@
2577
2589
  if (errorEl) errorEl.textContent = linkValidation.message;
2578
2590
  return;
2579
2591
  }
2592
+ const thresholdRaw = payload.qualityThreshold ?? '';
2593
+ const thresholdValidation = validateQualityThreshold(thresholdRaw);
2594
+ if (!thresholdValidation.ok) {
2595
+ if (errorEl) errorEl.textContent = thresholdValidation.message;
2596
+ return;
2597
+ }
2598
+ const requestBody = { ...payload };
2599
+ requestBody.qualityThreshold = thresholdRaw === '' ? null : Number(thresholdRaw);
2580
2600
  try {
2581
2601
  const response = await fetch(
2582
2602
  `${API_URL}/api/project-config?path=${encodeURIComponent(activeTabId)}`,
2583
2603
  {
2584
2604
  method: 'PATCH',
2585
2605
  headers: { 'Content-Type': 'application/json' },
2586
- body: JSON.stringify(payload),
2606
+ body: JSON.stringify(requestBody),
2587
2607
  },
2588
2608
  );
2589
2609
  if (!response.ok) {
@@ -2591,6 +2611,10 @@
2591
2611
  if (errorEl) errorEl.textContent = errorPayload?.error || 'Échec de la sauvegarde';
2592
2612
  return;
2593
2613
  }
2614
+ const updated = await response.json().catch(() => null);
2615
+ if (updated?.config) {
2616
+ currentProjectConfig = updated.config;
2617
+ }
2594
2618
  closeSettingsModal();
2595
2619
  refreshOverviewSection();
2596
2620
  } catch {
@@ -10,7 +10,7 @@ export function shouldNotifyDesktop(options: {
10
10
  /**
11
11
  * @param {{ kind: string, review: Record<string, unknown> }} notification
12
12
  * @param {(key: string, params?: Record<string, string | number>) => string} translate
13
- * @returns {{ title: string, body: string, tag: string } | null}
13
+ * @returns {{ title: string, body: string, tag: string, url: string | null, iconDataUri: string } | null}
14
14
  */
15
15
  export function getDesktopNotificationPayload(notification: {
16
16
  kind: string;
@@ -19,5 +19,11 @@ export function getDesktopNotificationPayload(notification: {
19
19
  title: string;
20
20
  body: string;
21
21
  tag: string;
22
+ url: string | null;
23
+ iconDataUri: string;
22
24
  } | null;
25
+ export type KindFormat = {
26
+ emoji: string;
27
+ labelKey: string;
28
+ };
23
29
  //# sourceMappingURL=desktopNotifications.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"desktopNotifications.d.ts","sourceRoot":"","sources":["../../../src/dashboard/modules/desktopNotifications.js"],"names":[],"mappings":"AAAA;;;GAGG;AACH,6CAHW;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,OAAO,CAAC;IAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAE,GAC5E,OAAO,CAMnB;AAED;;;;GAIG;AACH,4DAJW;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,aACjD,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,MAAM,GAC/D;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAwB/D"}
1
+ {"version":3,"file":"desktopNotifications.d.ts","sourceRoot":"","sources":["../../../src/dashboard/modules/desktopNotifications.js"],"names":[],"mappings":"AAAA;;;GAGG;AACH,6CAHW;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,OAAO,CAAC;IAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAE,GAC5E,OAAO,CAMnB;AAyLD;;;;GAIG;AACH,4DAJW;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,aACjD,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,MAAM,GAC/D;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAoBxG;;WA5Ma,MAAM;cACN,MAAM"}
@@ -8,31 +8,210 @@ export function shouldNotifyDesktop(options) {
8
8
  return options.isDocumentHidden;
9
9
  }
10
10
 
11
+ /**
12
+ * @typedef {Object} KindFormat
13
+ * @property {string} emoji
14
+ * @property {string} labelKey
15
+ */
16
+
17
+ /** @type {Record<string, KindFormat>} */
18
+ const KIND_FORMATS = {
19
+ reviewStarted: { emoji: '🔍', labelKey: 'notify.label.reviewStarted' },
20
+ followupStarted: { emoji: '🔁', labelKey: 'notify.label.followupStarted' },
21
+ reviewCompleted: { emoji: '✅', labelKey: 'notify.label.reviewCompleted' },
22
+ followupCompleted: { emoji: '✅', labelKey: 'notify.label.followupCompleted' },
23
+ reviewFailed: { emoji: '❌', labelKey: 'notify.label.reviewFailed' },
24
+ reviewPendingConfirmation: { emoji: '⏳', labelKey: 'notify.label.reviewPendingConfirmation' },
25
+ };
26
+
27
+ // Size category thresholds (sum of additions + deletions).
28
+ // Tweak here if you find them off — kept central on purpose.
29
+ const SIZE_THRESHOLD_SMALL_MAX = 50;
30
+ const SIZE_THRESHOLD_MEDIUM_MAX = 300;
31
+ const SIZE_EMOJI = { small: '🪶', medium: '🚀', big: '🐘' };
32
+
33
+ /**
34
+ * @param {unknown} value
35
+ * @returns {number | null}
36
+ */
37
+ function toFiniteNumber(value) {
38
+ return typeof value === 'number' && Number.isFinite(value) ? value : null;
39
+ }
40
+
41
+ /**
42
+ * @param {Record<string, unknown> | undefined} sizeMetrics
43
+ * @returns {'small' | 'medium' | 'big'}
44
+ */
45
+ function categorizeSize(sizeMetrics) {
46
+ if (!sizeMetrics) return 'small';
47
+ const additions = toFiniteNumber(sizeMetrics.additions);
48
+ const deletions = toFiniteNumber(sizeMetrics.deletions);
49
+ if (additions !== null && deletions !== null) {
50
+ const total = additions + deletions;
51
+ if (total < SIZE_THRESHOLD_SMALL_MAX) return 'small';
52
+ if (total < SIZE_THRESHOLD_MEDIUM_MAX) return 'medium';
53
+ return 'big';
54
+ }
55
+ const filesChanged = toFiniteNumber(sizeMetrics.filesChanged);
56
+ if (filesChanged !== null) {
57
+ if (filesChanged <= 3) return 'small';
58
+ if (filesChanged <= 10) return 'medium';
59
+ return 'big';
60
+ }
61
+ return 'small';
62
+ }
63
+
64
+ /**
65
+ * @param {Record<string, unknown>} review
66
+ * @returns {string | null}
67
+ */
68
+ function buildSizeLine(review) {
69
+ const metrics = review.sizeMetrics;
70
+ if (!metrics || typeof metrics !== 'object') return null;
71
+ const typed = /** @type {Record<string, unknown>} */ (metrics);
72
+ const additions = toFiniteNumber(typed.additions);
73
+ const deletions = toFiniteNumber(typed.deletions);
74
+ const filesChanged = toFiniteNumber(typed.filesChanged);
75
+ const hasAnyStat = additions !== null || deletions !== null || filesChanged !== null;
76
+ if (!hasAnyStat) return null;
77
+ const emoji = SIZE_EMOJI[categorizeSize(typed)];
78
+ const parts = [];
79
+ if (additions !== null && deletions !== null) {
80
+ parts.push(`+${additions}/-${deletions}`);
81
+ }
82
+ if (filesChanged !== null) {
83
+ parts.push(`${filesChanged} files`);
84
+ }
85
+ return `${emoji} ${parts.join(' · ')}`;
86
+ }
87
+
88
+ /**
89
+ * @param {unknown} actor
90
+ * @returns {string | null}
91
+ */
92
+ function resolveActorName(actor) {
93
+ if (!actor || typeof actor !== 'object') return null;
94
+ const typed = /** @type {{ displayName?: unknown, username?: unknown }} */ (actor);
95
+ if (typeof typed.displayName === 'string' && typed.displayName.length > 0) {
96
+ return typed.displayName;
97
+ }
98
+ if (typeof typed.username === 'string' && typed.username.length > 0) {
99
+ return typed.username;
100
+ }
101
+ return null;
102
+ }
103
+
104
+ /**
105
+ * @param {Record<string, unknown>} review
106
+ * @returns {string | null}
107
+ */
108
+ function resolveAuthor(review) {
109
+ return resolveActorName(review.author) ?? resolveActorName(review.assignedBy);
110
+ }
111
+
112
+ /**
113
+ * @param {Record<string, unknown>} review
114
+ * @returns {string | null}
115
+ */
116
+ function resolveProjectShortName(review) {
117
+ if (typeof review.project !== 'string' || review.project.length === 0) return null;
118
+ const segments = review.project.split('/');
119
+ const last = segments[segments.length - 1];
120
+ return last && last.length > 0 ? last : null;
121
+ }
122
+
123
+ /**
124
+ * @param {Record<string, unknown>} review
125
+ * @returns {'gitlab' | 'github'}
126
+ */
127
+ function resolvePlatform(review) {
128
+ const id = typeof review.id === 'string' ? review.id : '';
129
+ return id.startsWith('github') ? 'github' : 'gitlab';
130
+ }
131
+
132
+ /**
133
+ * @param {Record<string, unknown>} review
134
+ * @returns {'!' | '#'}
135
+ */
136
+ function resolveMrPrefix(review) {
137
+ return resolvePlatform(review) === 'github' ? '#' : '!';
138
+ }
139
+
140
+ const PLATFORM_ICONS = {
141
+ gitlab: buildPlatformIconDataUri('GL', 'FC6D26'),
142
+ github: buildPlatformIconDataUri('GH', '181717'),
143
+ };
144
+
145
+ /**
146
+ * @param {string} label
147
+ * @param {string} hexColor
148
+ * @returns {string}
149
+ */
150
+ function buildPlatformIconDataUri(label, hexColor) {
151
+ const svg =
152
+ `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">` +
153
+ `<rect width="64" height="64" rx="12" fill="#${hexColor}"/>` +
154
+ `<text x="32" y="42" font-size="28" text-anchor="middle" fill="white" ` +
155
+ `font-family="-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif" font-weight="700">${label}</text>` +
156
+ '</svg>';
157
+ return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;
158
+ }
159
+
160
+ /**
161
+ * @param {KindFormat} format
162
+ * @param {(key: string) => string} translate
163
+ * @param {Record<string, unknown>} review
164
+ * @returns {string}
165
+ */
166
+ function buildTitle(format, translate, review) {
167
+ const mrNumber = typeof review.mrNumber === 'number' ? String(review.mrNumber) : '?';
168
+ const mrToken = `${resolveMrPrefix(review)}${mrNumber}`;
169
+ const label = translate(format.labelKey);
170
+ const author = resolveAuthor(review);
171
+ const segments = author
172
+ ? [`${format.emoji} ${label}`, author, mrToken]
173
+ : [`${format.emoji} ${label}`, mrToken];
174
+ return segments.join(' · ');
175
+ }
176
+
177
+ /**
178
+ * @param {Record<string, unknown>} review
179
+ * @returns {string}
180
+ */
181
+ function buildBody(review) {
182
+ const lines = [];
183
+ const title = typeof review.title === 'string' ? review.title.trim() : '';
184
+ if (title.length > 0) lines.push(title);
185
+ const sizeLine = buildSizeLine(review);
186
+ const project = resolveProjectShortName(review);
187
+ const secondLineParts = [];
188
+ if (sizeLine) secondLineParts.push(sizeLine);
189
+ if (project) secondLineParts.push(project);
190
+ if (secondLineParts.length > 0) lines.push(secondLineParts.join(' · '));
191
+ return lines.join('\n');
192
+ }
193
+
11
194
  /**
12
195
  * @param {{ kind: string, review: Record<string, unknown> }} notification
13
196
  * @param {(key: string, params?: Record<string, string | number>) => string} translate
14
- * @returns {{ title: string, body: string, tag: string } | null}
197
+ * @returns {{ title: string, body: string, tag: string, url: string | null, iconDataUri: string } | null}
15
198
  */
16
199
  export function getDesktopNotificationPayload(notification, translate) {
200
+ const format = KIND_FORMATS[notification.kind];
201
+ if (!format) return null;
202
+
17
203
  const mrNumber = typeof notification.review.mrNumber === 'number'
18
204
  ? String(notification.review.mrNumber)
19
205
  : '?';
20
-
21
- const messageKeyByKind = {
22
- reviewStarted: 'notify.reviewStarted',
23
- followupStarted: 'notify.followupStarted',
24
- reviewCompleted: 'notify.reviewCompleted',
25
- followupCompleted: 'notify.followupCompleted',
26
- reviewFailed: 'notify.reviewFailed',
27
- reviewPendingConfirmation: 'notify.reviewPendingConfirmation',
28
- };
29
-
30
- const messageKey = messageKeyByKind[notification.kind];
31
- if (!messageKey) return null;
206
+ const url = typeof notification.review.mrUrl === 'string' && notification.review.mrUrl.length > 0
207
+ ? notification.review.mrUrl
208
+ : null;
32
209
 
33
210
  return {
34
- title: translate('notify.desktopTitle'),
35
- body: translate(messageKey, { mrNumber }),
211
+ title: buildTitle(format, translate, notification.review),
212
+ body: buildBody(notification.review),
36
213
  tag: `reviewflow-${notification.kind}-${mrNumber}`,
214
+ url,
215
+ iconDataUri: PLATFORM_ICONS[resolvePlatform(notification.review)],
37
216
  };
38
217
  }
@@ -1 +1 @@
1
- {"version":3,"file":"desktopNotifications.js","sourceRoot":"","sources":["../../../src/dashboard/modules/desktopNotifications.js"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAO;IACzC,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACnD,IAAI,OAAO,CAAC,iBAAiB,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACpD,OAAO,OAAO,CAAC,gBAAgB,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,6BAA6B,CAAC,YAAY,EAAE,SAAS;IACnE,MAAM,QAAQ,GAAG,OAAO,YAAY,CAAC,MAAM,CAAC,QAAQ,KAAK,QAAQ;QAC/D,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC;QACtC,CAAC,CAAC,GAAG,CAAC;IAER,MAAM,gBAAgB,GAAG;QACvB,aAAa,EAAE,sBAAsB;QACrC,eAAe,EAAE,wBAAwB;QACzC,eAAe,EAAE,wBAAwB;QACzC,iBAAiB,EAAE,0BAA0B;QAC7C,YAAY,EAAE,qBAAqB;QACnC,yBAAyB,EAAE,kCAAkC;KAC9D,CAAC;IAEF,MAAM,UAAU,GAAG,gBAAgB,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACvD,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAE7B,OAAO;QACL,KAAK,EAAE,SAAS,CAAC,qBAAqB,CAAC;QACvC,IAAI,EAAE,SAAS,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,CAAC;QACzC,GAAG,EAAE,cAAc,YAAY,CAAC,IAAI,IAAI,QAAQ,EAAE;KACnD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"desktopNotifications.js","sourceRoot":"","sources":["../../../src/dashboard/modules/desktopNotifications.js"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/dashboard/modules/i18n.js"],"names":[],"mappings":"AAo0BA,6BAA6B;AAC7B,+BADc,IAAI,GAAG,IAAI,CAGxB;AAED,oCAAoC;AACpC,sCADY,IAAI,GAAG,IAAI,QAGtB;AAED;;;;GAIG;AACH,uBAJW,MAAM,WACN,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAC7B,MAAM,CAUlB"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/dashboard/modules/i18n.js"],"names":[],"mappings":"AAw1BA,6BAA6B;AAC7B,+BADc,IAAI,GAAG,IAAI,CAGxB;AAED,oCAAoC;AACpC,sCADY,IAAI,GAAG,IAAI,QAGtB;AAED;;;;GAIG;AACH,uBAJW,MAAM,WACN,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAC7B,MAAM,CAUlB"}
@@ -60,7 +60,7 @@ const translations = {
60
60
  'quality.trendFlat': 'Stable',
61
61
  'quality.trendUnknown': 'No trend yet',
62
62
 
63
- // Notifications
63
+ // Notifications — toast labels (in-page)
64
64
  'notify.reviewStarted': 'Review started for !{{mrNumber}}',
65
65
  'notify.followupStarted': 'Follow-up started for !{{mrNumber}}',
66
66
  'notify.reviewCompleted': 'Review completed for !{{mrNumber}}',
@@ -69,6 +69,13 @@ const translations = {
69
69
  'notify.followupRequested': 'Follow-up requested for !{{mrNumber}}',
70
70
  'notify.reviewPendingConfirmation': 'Review awaiting your confirmation for !{{mrNumber}}',
71
71
  'notify.desktopTitle': 'Reviewflow alert',
72
+ // Notifications — desktop labels (short, used in rich payload)
73
+ 'notify.label.reviewStarted': 'Review',
74
+ 'notify.label.followupStarted': 'Follow-up',
75
+ 'notify.label.reviewCompleted': 'Review done',
76
+ 'notify.label.followupCompleted': 'Follow-up done',
77
+ 'notify.label.reviewFailed': 'Review failed',
78
+ 'notify.label.reviewPendingConfirmation': 'Awaiting confirmation',
72
79
 
73
80
  // Loading
74
81
  'loading.data': 'Syncing dashboard data...',
@@ -176,6 +183,9 @@ const translations = {
176
183
  'settings.reviewFollowupSkill': 'Review followup skill',
177
184
  'settings.externalLink': 'External link (HTTPS)',
178
185
  'settings.externalLinkPlaceholder': 'https://notion.so/team/project',
186
+ 'settings.qualityThreshold': 'Quality threshold (0-10)',
187
+ 'settings.qualityThresholdPlaceholder': 'e.g. 7',
188
+ 'settings.qualityThresholdHint': 'Approval is reverted when score falls below this threshold. Leave empty to disable.',
179
189
  'settings.cancel': 'Cancel',
180
190
  'settings.save': 'Save',
181
191
  'empty.reviewsNoProject': 'Load a project to see reviews',
@@ -475,7 +485,7 @@ const translations = {
475
485
  'quality.trendFlat': 'Stable',
476
486
  'quality.trendUnknown': 'Pas de tendance',
477
487
 
478
- // Notifications
488
+ // Notifications — toast labels (in-page)
479
489
  'notify.reviewStarted': 'Review démarrée pour !{{mrNumber}}',
480
490
  'notify.followupStarted': 'Follow-up démarré pour !{{mrNumber}}',
481
491
  'notify.reviewCompleted': 'Review terminée pour !{{mrNumber}}',
@@ -484,6 +494,13 @@ const translations = {
484
494
  'notify.followupRequested': 'Follow-up demandé pour !{{mrNumber}}',
485
495
  'notify.reviewPendingConfirmation': 'Review en attente de votre confirmation pour !{{mrNumber}}',
486
496
  'notify.desktopTitle': 'Alerte Reviewflow',
497
+ // Notifications — desktop labels (short, used in rich payload)
498
+ 'notify.label.reviewStarted': 'Review',
499
+ 'notify.label.followupStarted': 'Follow-up',
500
+ 'notify.label.reviewCompleted': 'Review terminée',
501
+ 'notify.label.followupCompleted': 'Follow-up terminé',
502
+ 'notify.label.reviewFailed': 'Review échouée',
503
+ 'notify.label.reviewPendingConfirmation': 'En attente',
487
504
 
488
505
  // Loading
489
506
  'loading.data': 'Synchronisation des données du dashboard...',
@@ -591,6 +608,9 @@ const translations = {
591
608
  'settings.reviewFollowupSkill': 'Skill de review followup',
592
609
  'settings.externalLink': 'Lien externe (HTTPS)',
593
610
  'settings.externalLinkPlaceholder': 'https://notion.so/team/projet',
611
+ 'settings.qualityThreshold': 'Seuil de qualité (0-10)',
612
+ 'settings.qualityThresholdPlaceholder': 'ex. 7',
613
+ 'settings.qualityThresholdHint': "L'approbation est annulée si le score passe sous ce seuil. Laisser vide pour désactiver.",
594
614
  'settings.cancel': 'Annuler',
595
615
  'settings.save': 'Enregistrer',
596
616
  'empty.reviewsNoProject': 'Charger un projet pour voir les reviews',