create-principles-disciple 1.146.4 → 1.146.6

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 (308) hide show
  1. package/_release/product-identity.json +1 -1
  2. package/package.json +3 -3
  3. package/release-manager/package.json +3 -3
  4. package/console/dist/ui/App.d.ts +0 -1
  5. package/console/dist/ui/App.js +0 -172
  6. package/console/dist/ui/api.d.ts +0 -611
  7. package/console/dist/ui/api.js +0 -1094
  8. package/console/dist/ui/components/auth/login-form.d.ts +0 -4
  9. package/console/dist/ui/components/auth/login-form.js +0 -142
  10. package/console/dist/ui/components/auth/splash-screen.d.ts +0 -9
  11. package/console/dist/ui/components/auth/splash-screen.js +0 -22
  12. package/console/dist/ui/components/error-boundary.d.ts +0 -15
  13. package/console/dist/ui/components/error-boundary.js +0 -30
  14. package/console/dist/ui/components/focus/daily-thought-card.d.ts +0 -1
  15. package/console/dist/ui/components/focus/daily-thought-card.js +0 -41
  16. package/console/dist/ui/components/language-switcher.d.ts +0 -2
  17. package/console/dist/ui/components/language-switcher.js +0 -17
  18. package/console/dist/ui/components/layout/app-sidebar.d.ts +0 -27
  19. package/console/dist/ui/components/layout/app-sidebar.js +0 -128
  20. package/console/dist/ui/components/layout/page-loading.d.ts +0 -13
  21. package/console/dist/ui/components/layout/page-loading.js +0 -14
  22. package/console/dist/ui/components/layout/page-shell.d.ts +0 -12
  23. package/console/dist/ui/components/layout/page-shell.js +0 -11
  24. package/console/dist/ui/components/layout/section-title.d.ts +0 -10
  25. package/console/dist/ui/components/layout/section-title.js +0 -9
  26. package/console/dist/ui/components/notifications/NotificationProvider.d.ts +0 -14
  27. package/console/dist/ui/components/notifications/NotificationProvider.js +0 -136
  28. package/console/dist/ui/components/notifications/favicon-badge.d.ts +0 -3
  29. package/console/dist/ui/components/notifications/favicon-badge.js +0 -68
  30. package/console/dist/ui/components/notifications/notification-reducer.d.ts +0 -9
  31. package/console/dist/ui/components/notifications/notification-reducer.js +0 -9
  32. package/console/dist/ui/components/notifications/sound-storage.d.ts +0 -3
  33. package/console/dist/ui/components/notifications/sound-storage.js +0 -37
  34. package/console/dist/ui/components/notifications/useNotifications.d.ts +0 -1
  35. package/console/dist/ui/components/notifications/useNotifications.js +0 -9
  36. package/console/dist/ui/components/onboarding/CircuitDiagram.d.ts +0 -8
  37. package/console/dist/ui/components/onboarding/CircuitDiagram.js +0 -18
  38. package/console/dist/ui/components/onboarding/DemoResultView.d.ts +0 -22
  39. package/console/dist/ui/components/onboarding/DemoResultView.js +0 -33
  40. package/console/dist/ui/components/onboarding/SlashCommandsCard.d.ts +0 -16
  41. package/console/dist/ui/components/onboarding/SlashCommandsCard.js +0 -20
  42. package/console/dist/ui/components/onboarding/slashCommands.d.ts +0 -20
  43. package/console/dist/ui/components/onboarding/slashCommands.js +0 -22
  44. package/console/dist/ui/components/receipts/ReceiptCoverageDisclosure.d.ts +0 -6
  45. package/console/dist/ui/components/receipts/ReceiptCoverageDisclosure.js +0 -66
  46. package/console/dist/ui/components/theme-provider.d.ts +0 -14
  47. package/console/dist/ui/components/theme-provider.js +0 -40
  48. package/console/dist/ui/components/theme-toggle.d.ts +0 -2
  49. package/console/dist/ui/components/theme-toggle.js +0 -11
  50. package/console/dist/ui/components/ui/alert-dialog.d.ts +0 -20
  51. package/console/dist/ui/components/ui/alert-dialog.js +0 -26
  52. package/console/dist/ui/components/ui/badge.d.ts +0 -9
  53. package/console/dist/ui/components/ui/badge.js +0 -22
  54. package/console/dist/ui/components/ui/button.d.ts +0 -11
  55. package/console/dist/ui/components/ui/button.js +0 -34
  56. package/console/dist/ui/components/ui/card.d.ts +0 -8
  57. package/console/dist/ui/components/ui/card.js +0 -16
  58. package/console/dist/ui/components/ui/charts.d.ts +0 -51
  59. package/console/dist/ui/components/ui/charts.js +0 -72
  60. package/console/dist/ui/components/ui/dialog.d.ts +0 -19
  61. package/console/dist/ui/components/ui/dialog.js +0 -22
  62. package/console/dist/ui/components/ui/input.d.ts +0 -3
  63. package/console/dist/ui/components/ui/input.js +0 -8
  64. package/console/dist/ui/components/ui/markdown.d.ts +0 -24
  65. package/console/dist/ui/components/ui/markdown.js +0 -119
  66. package/console/dist/ui/components/ui/progress-bar.d.ts +0 -20
  67. package/console/dist/ui/components/ui/progress-bar.js +0 -38
  68. package/console/dist/ui/components/ui/select.d.ts +0 -13
  69. package/console/dist/ui/components/ui/select.js +0 -26
  70. package/console/dist/ui/components/ui/separator.d.ts +0 -3
  71. package/console/dist/ui/components/ui/separator.js +0 -6
  72. package/console/dist/ui/components/ui/sheet.d.ts +0 -25
  73. package/console/dist/ui/components/ui/sheet.js +0 -37
  74. package/console/dist/ui/components/ui/shiny-text.d.ts +0 -28
  75. package/console/dist/ui/components/ui/shiny-text.js +0 -46
  76. package/console/dist/ui/components/ui/skeleton.d.ts +0 -3
  77. package/console/dist/ui/components/ui/skeleton.js +0 -6
  78. package/console/dist/ui/components/ui/sonner.d.ts +0 -3
  79. package/console/dist/ui/components/ui/sonner.js +0 -13
  80. package/console/dist/ui/components/ui/tooltip.d.ts +0 -7
  81. package/console/dist/ui/components/ui/tooltip.js +0 -10
  82. package/console/dist/ui/data/daily-thoughts.d.ts +0 -15
  83. package/console/dist/ui/data/daily-thoughts.js +0 -164
  84. package/console/dist/ui/hooks/useNotificationSound.d.ts +0 -12
  85. package/console/dist/ui/hooks/useNotificationSound.js +0 -74
  86. package/console/dist/ui/i18n/en.json +0 -2399
  87. package/console/dist/ui/i18n/index.d.ts +0 -2
  88. package/console/dist/ui/i18n/index.js +0 -32
  89. package/console/dist/ui/i18n/zh-CN.json +0 -2399
  90. package/console/dist/ui/main.d.ts +0 -1
  91. package/console/dist/ui/main.js +0 -9
  92. package/console/dist/ui/pages/ReportProblemValidators.d.ts +0 -144
  93. package/console/dist/ui/pages/ReportProblemValidators.js +0 -418
  94. package/console/dist/ui/pages/activation/ActivationPage.d.ts +0 -1
  95. package/console/dist/ui/pages/activation/ActivationPage.js +0 -512
  96. package/console/dist/ui/pages/activation/ActivationValidators.d.ts +0 -20
  97. package/console/dist/ui/pages/activation/ActivationValidators.js +0 -160
  98. package/console/dist/ui/pages/control-center/AgentCard.d.ts +0 -31
  99. package/console/dist/ui/pages/control-center/AgentCard.js +0 -212
  100. package/console/dist/ui/pages/control-center/AgentGroup.d.ts +0 -26
  101. package/console/dist/ui/pages/control-center/AgentGroup.js +0 -38
  102. package/console/dist/ui/pages/control-center/ControlCenterPage.d.ts +0 -1
  103. package/console/dist/ui/pages/control-center/ControlCenterPage.js +0 -509
  104. package/console/dist/ui/pages/control-center/DesignGatePanel.d.ts +0 -1
  105. package/console/dist/ui/pages/control-center/DesignGatePanel.js +0 -137
  106. package/console/dist/ui/pages/control-center/RuntimeProfileManager.d.ts +0 -31
  107. package/console/dist/ui/pages/control-center/RuntimeProfileManager.js +0 -199
  108. package/console/dist/ui/pages/control-center/WorkflowDiagram.d.ts +0 -17
  109. package/console/dist/ui/pages/control-center/WorkflowDiagram.js +0 -55
  110. package/console/dist/ui/pages/debt/DebtPage.d.ts +0 -2
  111. package/console/dist/ui/pages/debt/DebtPage.js +0 -222
  112. package/console/dist/ui/pages/design-system/DesignSystemPage.d.ts +0 -2
  113. package/console/dist/ui/pages/design-system/DesignSystemPage.js +0 -30
  114. package/console/dist/ui/pages/examiner/ExaminerPage.d.ts +0 -15
  115. package/console/dist/ui/pages/examiner/ExaminerPage.js +0 -158
  116. package/console/dist/ui/pages/failed-tasks/FailedTasksPage.d.ts +0 -1
  117. package/console/dist/ui/pages/failed-tasks/FailedTasksPage.js +0 -421
  118. package/console/dist/ui/pages/focus/ApprovalSubjectReading.d.ts +0 -24
  119. package/console/dist/ui/pages/focus/ApprovalSubjectReading.js +0 -133
  120. package/console/dist/ui/pages/focus/FocusPage.d.ts +0 -123
  121. package/console/dist/ui/pages/focus/FocusPage.js +0 -567
  122. package/console/dist/ui/pages/focus/OwnerDecisionCard.d.ts +0 -9
  123. package/console/dist/ui/pages/focus/OwnerDecisionCard.js +0 -111
  124. package/console/dist/ui/pages/focus/OwnerWorkbench.d.ts +0 -19
  125. package/console/dist/ui/pages/focus/OwnerWorkbench.js +0 -75
  126. package/console/dist/ui/pages/focus/RuleCandidateBindingPanel.d.ts +0 -34
  127. package/console/dist/ui/pages/focus/RuleCandidateBindingPanel.js +0 -298
  128. package/console/dist/ui/pages/focus/focus-validation.d.ts +0 -40
  129. package/console/dist/ui/pages/focus/focus-validation.js +0 -211
  130. package/console/dist/ui/pages/intent/IntentOnboarding.d.ts +0 -67
  131. package/console/dist/ui/pages/intent/IntentOnboarding.js +0 -289
  132. package/console/dist/ui/pages/intent/IntentPage.d.ts +0 -1
  133. package/console/dist/ui/pages/intent/IntentPage.js +0 -252
  134. package/console/dist/ui/pages/pain/PainEvidenceValidators.d.ts +0 -59
  135. package/console/dist/ui/pages/pain/PainEvidenceValidators.js +0 -125
  136. package/console/dist/ui/pages/pain/PainPage.d.ts +0 -1
  137. package/console/dist/ui/pages/pain/PainPage.js +0 -420
  138. package/console/dist/ui/pages/pain/pain-card-helpers.d.ts +0 -175
  139. package/console/dist/ui/pages/pain/pain-card-helpers.js +0 -181
  140. package/console/dist/ui/pages/principles/CorePrinciplesPage.d.ts +0 -10
  141. package/console/dist/ui/pages/principles/CorePrinciplesPage.js +0 -59
  142. package/console/dist/ui/pages/principles/PrincipleDetailPage.d.ts +0 -60
  143. package/console/dist/ui/pages/principles/PrincipleDetailPage.js +0 -602
  144. package/console/dist/ui/pages/principles/PrinciplesPage.d.ts +0 -1
  145. package/console/dist/ui/pages/principles/PrinciplesPage.js +0 -327
  146. package/console/dist/ui/pages/principles/PrinciplesViewNav.d.ts +0 -8
  147. package/console/dist/ui/pages/principles/PrinciplesViewNav.js +0 -15
  148. package/console/dist/ui/pages/report-problem/ReportProblemPage.d.ts +0 -1
  149. package/console/dist/ui/pages/report-problem/ReportProblemPage.js +0 -467
  150. package/console/dist/ui/pages/settings/SettingsPage.d.ts +0 -4
  151. package/console/dist/ui/pages/settings/SettingsPage.js +0 -457
  152. package/console/dist/ui/pages/settings/UpdatePage.d.ts +0 -1
  153. package/console/dist/ui/pages/settings/UpdatePage.js +0 -215
  154. package/console/dist/ui/pages/welcome/WelcomePage.d.ts +0 -5
  155. package/console/dist/ui/pages/welcome/WelcomePage.js +0 -187
  156. package/console/dist/ui/utils/agent-metadata.d.ts +0 -71
  157. package/console/dist/ui/utils/agent-metadata.js +0 -284
  158. package/console/dist/ui/utils/approval-review.d.ts +0 -30
  159. package/console/dist/ui/utils/approval-review.js +0 -50
  160. package/console/dist/ui/utils/approval-warning-localization.d.ts +0 -34
  161. package/console/dist/ui/utils/approval-warning-localization.js +0 -148
  162. package/console/dist/ui/utils/attention-presentation.d.ts +0 -35
  163. package/console/dist/ui/utils/attention-presentation.js +0 -46
  164. package/console/dist/ui/utils/blocker-localization.d.ts +0 -23
  165. package/console/dist/ui/utils/blocker-localization.js +0 -36
  166. package/console/dist/ui/utils/control-center-helpers.d.ts +0 -79
  167. package/console/dist/ui/utils/control-center-helpers.js +0 -189
  168. package/console/dist/ui/utils/enum-labels.d.ts +0 -50
  169. package/console/dist/ui/utils/enum-labels.js +0 -171
  170. package/console/dist/ui/utils/format-date.d.ts +0 -11
  171. package/console/dist/ui/utils/format-date.js +0 -17
  172. package/console/dist/ui/utils/onboarding-state.d.ts +0 -25
  173. package/console/dist/ui/utils/onboarding-state.js +0 -77
  174. package/console/dist/ui/utils/reading-layout.d.ts +0 -20
  175. package/console/dist/ui/utils/reading-layout.js +0 -46
  176. package/console/dist/ui/utils/rule-binding-validators.d.ts +0 -13
  177. package/console/dist/ui/utils/rule-binding-validators.js +0 -188
  178. package/console/dist/ui/utils/runtime-mode.d.ts +0 -11
  179. package/console/dist/ui/utils/runtime-mode.js +0 -11
  180. package/console/dist/ui/utils/token-storage.d.ts +0 -22
  181. package/console/dist/ui/utils/token-storage.js +0 -47
  182. package/console/dist/ui/utils/validators.d.ts +0 -1178
  183. package/console/dist/ui/utils/validators.js +0 -3297
  184. package/release-manager/dist/bootstrap-entry.d.ts +0 -2
  185. package/release-manager/dist/bootstrap-entry.d.ts.map +0 -1
  186. package/release-manager/dist/bootstrap-entry.js.map +0 -1
  187. package/release-manager/dist/i18n.d.ts +0 -6
  188. package/release-manager/dist/i18n.d.ts.map +0 -1
  189. package/release-manager/dist/i18n.js.map +0 -1
  190. package/release-manager/dist/index.d.ts +0 -7
  191. package/release-manager/dist/index.d.ts.map +0 -1
  192. package/release-manager/dist/index.js +0 -656
  193. package/release-manager/dist/index.js.map +0 -1
  194. package/release-manager/dist/installer.d.ts +0 -629
  195. package/release-manager/dist/installer.d.ts.map +0 -1
  196. package/release-manager/dist/installer.js.map +0 -1
  197. package/release-manager/dist/installers/codex-host-installer.d.ts +0 -39
  198. package/release-manager/dist/installers/codex-host-installer.d.ts.map +0 -1
  199. package/release-manager/dist/installers/codex-host-installer.js.map +0 -1
  200. package/release-manager/dist/installers/index.d.ts +0 -51
  201. package/release-manager/dist/installers/index.d.ts.map +0 -1
  202. package/release-manager/dist/installers/index.js.map +0 -1
  203. package/release-manager/dist/installers/openclaw-host-installer.d.ts +0 -14
  204. package/release-manager/dist/installers/openclaw-host-installer.d.ts.map +0 -1
  205. package/release-manager/dist/installers/openclaw-host-installer.js.map +0 -1
  206. package/release-manager/dist/installers/workbuddy-host-installer.d.ts +0 -335
  207. package/release-manager/dist/installers/workbuddy-host-installer.d.ts.map +0 -1
  208. package/release-manager/dist/installers/workbuddy-host-installer.js.map +0 -1
  209. package/release-manager/dist/mvp-config.d.ts +0 -233
  210. package/release-manager/dist/mvp-config.d.ts.map +0 -1
  211. package/release-manager/dist/mvp-config.js.map +0 -1
  212. package/release-manager/dist/prompts.d.ts +0 -43
  213. package/release-manager/dist/prompts.d.ts.map +0 -1
  214. package/release-manager/dist/prompts.js +0 -268
  215. package/release-manager/dist/prompts.js.map +0 -1
  216. package/release-manager/dist/skill-language.d.ts +0 -32
  217. package/release-manager/dist/skill-language.d.ts.map +0 -1
  218. package/release-manager/dist/skill-language.js.map +0 -1
  219. package/release-manager/dist/uninstaller.d.ts +0 -68
  220. package/release-manager/dist/uninstaller.d.ts.map +0 -1
  221. package/release-manager/dist/uninstaller.js +0 -746
  222. package/release-manager/dist/uninstaller.js.map +0 -1
  223. package/release-manager/dist/update/apply-payload.d.ts +0 -143
  224. package/release-manager/dist/update/apply-payload.d.ts.map +0 -1
  225. package/release-manager/dist/update/apply-payload.js.map +0 -1
  226. package/release-manager/dist/update/atomic-file.d.ts +0 -35
  227. package/release-manager/dist/update/atomic-file.d.ts.map +0 -1
  228. package/release-manager/dist/update/atomic-file.js.map +0 -1
  229. package/release-manager/dist/update/bootstrap-executor.d.ts +0 -21
  230. package/release-manager/dist/update/bootstrap-executor.d.ts.map +0 -1
  231. package/release-manager/dist/update/bootstrap-executor.js.map +0 -1
  232. package/release-manager/dist/update/bootstrap-protocol.d.ts +0 -56
  233. package/release-manager/dist/update/bootstrap-protocol.d.ts.map +0 -1
  234. package/release-manager/dist/update/bootstrap-protocol.js.map +0 -1
  235. package/release-manager/dist/update/channel-metadata.d.ts +0 -28
  236. package/release-manager/dist/update/channel-metadata.d.ts.map +0 -1
  237. package/release-manager/dist/update/channel-metadata.js.map +0 -1
  238. package/release-manager/dist/update/channel-promotion.d.ts +0 -39
  239. package/release-manager/dist/update/channel-promotion.d.ts.map +0 -1
  240. package/release-manager/dist/update/channel-promotion.js +0 -55
  241. package/release-manager/dist/update/channel-promotion.js.map +0 -1
  242. package/release-manager/dist/update/console-surface.d.ts +0 -19
  243. package/release-manager/dist/update/console-surface.d.ts.map +0 -1
  244. package/release-manager/dist/update/console-surface.js.map +0 -1
  245. package/release-manager/dist/update/data-compatibility.d.ts +0 -35
  246. package/release-manager/dist/update/data-compatibility.d.ts.map +0 -1
  247. package/release-manager/dist/update/data-compatibility.js +0 -45
  248. package/release-manager/dist/update/data-compatibility.js.map +0 -1
  249. package/release-manager/dist/update/install-layout.d.ts +0 -105
  250. package/release-manager/dist/update/install-layout.d.ts.map +0 -1
  251. package/release-manager/dist/update/install-layout.js.map +0 -1
  252. package/release-manager/dist/update/product-identity.d.ts +0 -70
  253. package/release-manager/dist/update/product-identity.d.ts.map +0 -1
  254. package/release-manager/dist/update/product-identity.js.map +0 -1
  255. package/release-manager/dist/update/release-asset-manifest.d.ts +0 -31
  256. package/release-manager/dist/update/release-asset-manifest.d.ts.map +0 -1
  257. package/release-manager/dist/update/release-asset-manifest.js.map +0 -1
  258. package/release-manager/dist/update/release-identity.d.ts +0 -33
  259. package/release-manager/dist/update/release-identity.d.ts.map +0 -1
  260. package/release-manager/dist/update/release-identity.js.map +0 -1
  261. package/release-manager/dist/update/release-manager-authority.d.ts +0 -39
  262. package/release-manager/dist/update/release-manager-authority.d.ts.map +0 -1
  263. package/release-manager/dist/update/release-manager-authority.js.map +0 -1
  264. package/release-manager/dist/update/release-manager.d.ts +0 -156
  265. package/release-manager/dist/update/release-manager.d.ts.map +0 -1
  266. package/release-manager/dist/update/release-manager.js.map +0 -1
  267. package/release-manager/dist/update/release-metadata-publisher.d.ts +0 -199
  268. package/release-manager/dist/update/release-metadata-publisher.d.ts.map +0 -1
  269. package/release-manager/dist/update/release-metadata-publisher.js +0 -478
  270. package/release-manager/dist/update/release-metadata-publisher.js.map +0 -1
  271. package/release-manager/dist/update/release-metadata-source.d.ts +0 -85
  272. package/release-manager/dist/update/release-metadata-source.d.ts.map +0 -1
  273. package/release-manager/dist/update/release-metadata-source.js.map +0 -1
  274. package/release-manager/dist/update/release-metadata.d.ts +0 -60
  275. package/release-manager/dist/update/release-metadata.d.ts.map +0 -1
  276. package/release-manager/dist/update/release-metadata.js.map +0 -1
  277. package/release-manager/dist/update/release-policy.d.ts +0 -51
  278. package/release-manager/dist/update/release-policy.d.ts.map +0 -1
  279. package/release-manager/dist/update/release-policy.js.map +0 -1
  280. package/release-manager/dist/update/rollback-policy.d.ts +0 -56
  281. package/release-manager/dist/update/rollback-policy.d.ts.map +0 -1
  282. package/release-manager/dist/update/rollback-policy.js +0 -61
  283. package/release-manager/dist/update/rollback-policy.js.map +0 -1
  284. package/release-manager/dist/update/transaction-journal.d.ts +0 -212
  285. package/release-manager/dist/update/transaction-journal.d.ts.map +0 -1
  286. package/release-manager/dist/update/transaction-journal.js.map +0 -1
  287. package/release-manager/dist/update/trust-metadata.d.ts +0 -55
  288. package/release-manager/dist/update/trust-metadata.d.ts.map +0 -1
  289. package/release-manager/dist/update/trust-metadata.js.map +0 -1
  290. package/release-manager/dist/update/trust-root-provisioning.d.ts +0 -99
  291. package/release-manager/dist/update/trust-root-provisioning.d.ts.map +0 -1
  292. package/release-manager/dist/update/trust-root-provisioning.js.map +0 -1
  293. package/release-manager/dist/update/update-history.d.ts +0 -46
  294. package/release-manager/dist/update/update-history.d.ts.map +0 -1
  295. package/release-manager/dist/update/update-history.js +0 -123
  296. package/release-manager/dist/update/update-history.js.map +0 -1
  297. package/release-manager/dist/utils/config-file-io.d.ts +0 -34
  298. package/release-manager/dist/utils/config-file-io.d.ts.map +0 -1
  299. package/release-manager/dist/utils/config-file-io.js.map +0 -1
  300. package/release-manager/dist/utils/env.d.ts +0 -94
  301. package/release-manager/dist/utils/env.d.ts.map +0 -1
  302. package/release-manager/dist/utils/env.js.map +0 -1
  303. package/release-manager/dist/utils/logger.d.ts +0 -15
  304. package/release-manager/dist/utils/logger.d.ts.map +0 -1
  305. package/release-manager/dist/utils/logger.js.map +0 -1
  306. package/release-manager/dist/utils/workspace-divergence.d.ts +0 -36
  307. package/release-manager/dist/utils/workspace-divergence.d.ts.map +0 -1
  308. package/release-manager/dist/utils/workspace-divergence.js.map +0 -1
@@ -1,111 +0,0 @@
1
- import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- /**
3
- * OwnerDecisionCard — PRI-629 统一 Owner Inbox 的决策卡(evaluator/rollout)。
4
- *
5
- * 第一层只回答 Owner 关心的问题 (SPEC §26): 发生了什么 / 为什么找我 /
6
- * 机器建议 / 可执行动作与后果。taskId / repairIteration / reasonCode 等
7
- * 实现细节收纳在折叠的高级诊断里。动作经 resolveOwnerDecision 服务端重读
8
- * durable facts — stale → 409,由本组件以可理解文案呈现并触发刷新。
9
- */
10
- import { useState } from "react";
11
- import { Link } from "react-router-dom";
12
- import { useTranslation } from "react-i18next";
13
- import { toast } from "sonner";
14
- import { resolveOwnerDecision } from "../../api.js";
15
- export function OwnerDecisionCard({ item, onResolved, governanceReady = true, actionsLockedReason, }) {
16
- const { t } = useTranslation();
17
- const [actionLoading, setActionLoading] = useState(null);
18
- const [instruction, setInstruction] = useState("");
19
- const [showInstruction, setShowInstruction] = useState(false);
20
- const [showAdvanced, setShowAdvanced] = useState(false);
21
- const [partialEvidenceAcknowledged, setPartialEvidenceAcknowledged] = useState(false);
22
- const isTaskDecision = item.kind === "evaluator_review" || item.kind === "rollout_review";
23
- const canAccept = item.allowedActions.includes("accept_current");
24
- const canRevise = item.allowedActions.includes("revise_once");
25
- const canReject = item.allowedActions.includes("reject_current");
26
- const requiresPartialAcknowledgement = item.review?.capability.acceptRequirement.kind === "acknowledge_partial_evidence";
27
- const evidenceUnavailable = item.evidenceUnavailableReason !== undefined;
28
- // PRI-798 P1-2: when accept is unavailable the copy must name the actual
29
- // reason — the adversarial hard gate, a missing activation candidate, or
30
- // insufficient review evidence are different situations with different next
31
- // actions. Discriminate on the structured reason codes, never on !canAccept.
32
- const acceptBlockedCopy = (() => {
33
- const acceptRequirement = item.review?.capability.acceptRequirement;
34
- if (acceptRequirement?.kind === "forbidden" &&
35
- (acceptRequirement.reasonCode === "adversarial_hard_gate_failed" ||
36
- acceptRequirement.reasonCode === "adversarial_hard_gate_not_passed")) {
37
- return t("pages.focus.ownerDecision.acceptBlockedHardGate");
38
- }
39
- if (item.reasonCode === "rollout_activation_candidate_unresolved") {
40
- return t("pages.focus.ownerDecision.acceptBlockedNoCandidate");
41
- }
42
- return t("pages.focus.ownerDecision.acceptBlockedGeneric");
43
- })();
44
- async function handleAction(action) {
45
- if (action === "revise_once" && showInstruction && instruction.trim().length === 0) {
46
- // 指导为空也可以提交 — instruction 是可选的;这里仅在展开输入后要求非空确认
47
- // (避免误提交空指导),Owner 可收起输入直接提交。
48
- toast.error(t("pages.focus.ownerDecision.instructionRequired"));
49
- return;
50
- }
51
- setActionLoading(action);
52
- try {
53
- const response = await resolveOwnerDecision(item.taskId, {
54
- action,
55
- reviewKey: item.reviewKey,
56
- expectedRevisionEpoch: item.expectedRevisionEpoch,
57
- expectedSourceRunId: item.expectedSourceRunId,
58
- expectedSourceArtifactId: item.expectedSourceArtifactId,
59
- expectedSourceArtifactHash: item.expectedSourceArtifactHash,
60
- expectedEvidenceDigest: item.expectedEvidenceDigest ?? "",
61
- ...(action === "accept_current" && requiresPartialAcknowledgement && partialEvidenceAcknowledged
62
- ? { acknowledgement: { kind: "partial_evidence", acknowledged: true } }
63
- : {}),
64
- ...(action === "revise_once" && instruction.trim().length > 0
65
- ? { ownerInstruction: instruction.trim() }
66
- : { ownerInstruction: null }),
67
- });
68
- if (!response.success) {
69
- if (response.error === "stale_owner_decision") {
70
- toast.error(t("pages.focus.ownerDecision.staleError"));
71
- }
72
- else if (response.error === "already_resolved") {
73
- toast.info(t("pages.focus.ownerDecision.alreadyResolved"));
74
- }
75
- else {
76
- toast.error(response.error ?? t("pages.focus.ownerDecision.actionFailed"));
77
- }
78
- onResolved();
79
- return;
80
- }
81
- toast.success(t("pages.focus.ownerDecision.resolved"));
82
- onResolved();
83
- }
84
- catch {
85
- toast.error(t("pages.focus.ownerDecision.actionFailed"));
86
- }
87
- finally {
88
- setActionLoading(null);
89
- }
90
- }
91
- const kindLabel = item.kind === "rollout_review"
92
- ? t("pages.focus.ownerDecision.kindRollout")
93
- : item.kind === "activation_approval"
94
- ? t("pages.focus.ownerDecision.kindApproval")
95
- : item.kind === "rulecode_decision"
96
- ? t("pages.focus.ownerDecision.kindRulecode")
97
- : t("pages.focus.ownerDecision.kindEvaluator");
98
- return (_jsxs("article", { className: "bg-panel border border-line rounded-[6px] p-4 mb-3", "data-testid": `owner-decision-${item.taskId}`, children: [_jsxs("div", { className: "flex items-start justify-between gap-3 mb-2", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-ink text-[14px] font-medium leading-snug", children: item.title }), _jsx("div", { className: "mt-1 text-ink-4 text-[11px] font-mono uppercase tracking-[0.08em]", children: kindLabel })] }), item.legacy && (_jsx("span", { className: "shrink-0 text-ink-4 border border-line rounded-[2px] px-[7px] py-[3px] text-[10.5px] font-mono", children: t("pages.focus.ownerDecision.legacyBadge") }))] }), _jsx("p", { className: "text-ink-2 text-[13px] leading-relaxed mb-2", children: item.summary }), item.review?.brief.kind === "evaluator" && (_jsxs("div", { className: "mb-3 grid gap-2 text-[12.5px] leading-relaxed", children: [item.review.brief.principle?.statement && (_jsxs("p", { children: [_jsx("span", { className: "font-medium text-ink", children: t("pages.focus.ownerDecision.principleLabel") }), " ", item.review.brief.principle.statement] })), item.review.brief.implementation?.summary && (_jsxs("p", { children: [_jsx("span", { className: "font-medium text-ink", children: t("pages.focus.ownerDecision.implementationLabel") }), " ", item.review.brief.implementation.summary] })), (item.review.brief.concerns?.length ?? 0) > 0 && (_jsxs("p", { className: "text-amber", children: [_jsx("span", { className: "font-medium", children: t("pages.focus.ownerDecision.concernLabel") }), " ", item.review.brief.concerns?.[0]] })), (item.review.brief.qualityChecklist?.items?.length ?? 0) > 0 && (_jsxs("div", { className: "mt-1 rounded-[3px] border border-line bg-surface-2 p-2", "data-testid": `owner-quality-checklist-${item.taskId}`, children: [_jsx("div", { className: "font-mono text-[10.5px] uppercase tracking-[0.06em] text-ink-3 mb-1", children: t("pages.focus.ownerDecision.qualityChecklistLabel") }), _jsx("ul", { className: "grid gap-0.5", children: item.review.brief.qualityChecklist?.items.map((qItem) => (_jsxs("li", { className: "flex items-start gap-1.5 text-[12px]", children: [_jsx("span", { className: qItem.pass ? "text-emerald" : "text-amber", "aria-hidden": "true", children: qItem.pass ? "✓" : "!" }), _jsx("span", { className: "sr-only", children: qItem.pass ? t("pages.focus.ownerDecision.qualityCheckStatus.passed") : t("pages.focus.ownerDecision.qualityCheckStatus.failed") }), _jsxs("span", { className: "text-ink-2", children: [_jsx("span", { className: "font-medium", children: t(`pages.focus.ownerDecision.qualityCheck.${qItem.id}`) }), " ", qItem.note] })] }, qItem.id))) })] })), item.review.brief.formationEvidence && (_jsxs("div", { className: "mt-1 rounded-[3px] border border-line bg-surface-2 p-2", "data-testid": `owner-formation-evidence-${item.taskId}`, children: [_jsx("div", { className: "font-mono text-[10.5px] uppercase tracking-[0.06em] text-ink-3 mb-1", children: t("pages.focus.ownerDecision.formationLabel") }), item.review.brief.formationEvidence.sourcePainId ? (_jsxs("p", { className: "text-ink-2", children: [_jsx("span", { className: "font-medium", children: t("pages.focus.ownerDecision.formationPainLabel") }), " ", _jsx("span", { className: "font-mono text-[11.5px]", children: item.review.brief.formationEvidence.sourcePainId })] })) : null, item.review.brief.formationEvidence.diagnosis?.summary && (_jsxs("p", { className: "text-ink-2", children: [_jsx("span", { className: "font-medium", children: t("pages.focus.ownerDecision.formationDiagnosisLabel") }), " ", item.review.brief.formationEvidence.diagnosis.summary] })), item.review.brief.formationEvidence.diagnosis?.rootCause && (_jsxs("p", { className: "text-ink-2", children: [_jsx("span", { className: "font-medium", children: t("pages.focus.ownerDecision.formationRootCauseLabel") }), " ", item.review.brief.formationEvidence.diagnosis.rootCause] })), (item.review.brief.formationEvidence.diagnosis?.evidence.length ?? 0) > 0 && (_jsxs("div", { children: [_jsx("span", { className: "font-medium text-ink-2", children: t("pages.focus.ownerDecision.formationEvidenceLabel") }), _jsx("ul", { className: "mt-0.5 grid gap-0.5 text-[12px] text-ink-3", children: item.review.brief.formationEvidence.diagnosis?.evidence.slice(0, 3).map((row, index) => (_jsxs("li", { children: [_jsx("span", { className: "font-mono text-[11px]", children: row.sourceRef }), " ", row.note] }, `${row.sourceRef}-${index}`))) })] })), !item.review.brief.formationEvidence.diagnosis && (_jsx("p", { className: "text-ink-3", children: t("pages.focus.ownerDecision.formationUnavailableNote") }))] }))] })), item.review && (_jsxs("div", { className: "mb-2 flex flex-wrap items-center gap-2 text-[10.5px] font-mono uppercase tracking-[0.06em]", children: [_jsx("span", { className: "rounded-[2px] border border-line px-2 py-1 text-ink-3", children: t(`pages.focus.ownerDecision.evidence.${item.review.evidence.completeness}`) }), _jsxs("details", { "data-testid": `owner-checks-${item.taskId}`, children: [_jsx("summary", { className: "cursor-pointer text-ink-4 hover:text-ink-3", children: t("pages.focus.ownerDecision.checksDisclosure") }), _jsx("div", { className: "mt-1 flex flex-wrap gap-2", children: item.review.evidence.deterministicChecks.map(check => (_jsxs("span", { className: "rounded-[2px] border border-line px-2 py-1 text-ink-3", children: [check.check, ": ", check.status] }, check.check))) })] })] })), item.machineRecommendation && (_jsxs("p", { className: "text-ink-3 text-[12.5px] mb-1", children: [_jsx("span", { className: "font-medium", children: t("pages.focus.ownerDecision.machineRecommendationLabel") }), " ", item.machineRecommendation, item.score !== undefined && _jsx("span", { className: "font-mono ml-1", children: item.score.toFixed(2) })] })), item.kind === "rollout_review" && (_jsx("p", { className: "text-ink-4 text-[12px] mb-1", children: t("pages.focus.ownerDecision.rolloutSafetyNote") })), evidenceUnavailable ? (_jsxs("div", { className: "mt-3 rounded-[3px] border border-amber/40 bg-amber/5 p-3", children: [_jsx("p", { className: "text-ink-2 text-[12.5px] leading-relaxed", children: t("pages.focus.ownerDecision.evidenceUnavailable") }), _jsx(Link, { to: `/failed-tasks?taskId=${encodeURIComponent(item.taskId)}`, "data-testid": `owner-evidence-recover-${item.taskId}`, className: "mt-2 inline-flex items-center border border-line text-ink bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors", children: t("pages.focus.ownerDecision.goRecoverCta") })] })) : isTaskDecision ? (_jsxs(_Fragment, { children: [showInstruction && (_jsxs("div", { className: "mt-2 mb-2", children: [_jsx("label", { className: "block font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3 mb-2", children: t("pages.focus.ownerDecision.instructionLabel") }), _jsx("textarea", { value: instruction, onChange: (e) => setInstruction(e.target.value.slice(0, 500)), "data-testid": `owner-instruction-${item.taskId}`, placeholder: t("pages.focus.ownerDecision.instructionPlaceholder"), className: "w-full border border-line rounded-[var(--radius-md)] bg-surface text-ink px-3 py-2 text-[13px] min-h-[64px] resize-y focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov" })] })), requiresPartialAcknowledgement && (_jsxs("label", { className: "mt-2 mb-1 flex items-start gap-2 text-[12px] text-ink-3", children: [_jsx("input", { type: "checkbox", checked: partialEvidenceAcknowledged, onChange: (event) => setPartialEvidenceAcknowledged(event.target.checked), "data-testid": `owner-partial-evidence-ack-${item.taskId}`, className: "mt-0.5" }), _jsx("span", { children: t("pages.focus.ownerDecision.partialEvidenceAcknowledgement") })] })), !governanceReady && actionsLockedReason && (_jsxs("div", { className: "mt-3 rounded-[3px] border border-amber/40 bg-amber/5 p-3", "data-testid": `owner-actions-locked-${item.taskId}`, children: [_jsx("p", { className: "text-ink-2 text-[12.5px] leading-relaxed", children: actionsLockedReason }), _jsx(Link, { to: "/settings", "data-testid": `owner-actions-locked-settings-${item.taskId}`, className: "mt-2 inline-flex items-center border border-line text-ink bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors", children: t("pages.focus.ownerDecision.goSettingsCta") })] })), _jsxs("div", { className: "flex flex-wrap gap-2 mt-3", children: [canAccept && (_jsx("button", { type: "button", onClick: () => handleAction("accept_current"), disabled: !governanceReady || actionLoading !== null || (requiresPartialAcknowledgement && !partialEvidenceAcknowledged), "data-testid": `owner-accept-${item.taskId}`, className: "inline-flex items-center border border-gov text-gov bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-gov/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed", children: actionLoading === "accept_current" ? t("common.loading") : t("pages.focus.ownerDecision.acceptCurrent") })), canRevise && (_jsx("button", { type: "button", onClick: () => {
99
- if (!showInstruction) {
100
- setShowInstruction(true);
101
- return;
102
- }
103
- void handleAction("revise_once");
104
- }, disabled: !governanceReady || actionLoading !== null, "data-testid": `owner-revise-${item.taskId}`, className: "inline-flex items-center border border-line text-ink bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed", children: actionLoading === "revise_once" ? t("common.loading") : t("pages.focus.ownerDecision.reviseOnce") })), canReject && (_jsx("button", { type: "button", onClick: () => handleAction("reject_current"), disabled: !governanceReady || actionLoading !== null, "data-testid": `owner-reject-${item.taskId}`, className: "inline-flex items-center border border-danger text-danger bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-danger/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed", children: actionLoading === "reject_current" ? t("common.loading") : t("pages.focus.ownerDecision.rejectCurrent") }))] }), _jsx("div", { className: "mt-2 text-ink-4 text-[11.5px] leading-relaxed", children: canAccept
105
- ? t("pages.focus.ownerDecision.actionConsequence")
106
- : acceptBlockedCopy }), _jsxs("button", { type: "button", onClick: () => setShowAdvanced(!showAdvanced), className: "mt-2 text-ink-4 text-[11px] font-mono uppercase tracking-[0.08em] hover:text-ink-3", "data-testid": `owner-advanced-toggle-${item.taskId}`, children: [showAdvanced ? "▾" : "▸", " ", t("pages.focus.ownerDecision.advanced")] }), showAdvanced && (_jsxs("dl", { className: "mt-2 grid gap-1 text-[11.5px] font-mono text-ink-4", children: [_jsxs("div", { children: ["taskId: ", item.taskId] }), _jsxs("div", { children: ["reasonCode: ", item.reasonCode] }), _jsxs("div", { children: ["reviewKey: ", item.reviewKey.slice(0, 24), "\u2026"] }), _jsxs("div", { children: ["epoch: ", item.expectedRevisionEpoch] }), item.review?.brief.requiredChanges.map((change, index) => (_jsxs("div", { children: ["requiredChange: ", change] }, `${change}-${index}`))), item.review?.evidence.items.map((evidence, index) => (_jsxs("div", { children: [evidence.evidenceClass, "/", evidence.label, ": ", evidence.value] }, `${evidence.label}-${index}`))), item.review?.brief.kind === "evaluator" && item.review.brief.formationEvidence && (_jsxs(_Fragment, { children: [_jsxs("div", { children: ["dreamerArtifact: ", item.review.brief.formationEvidence.provenance.sourceDreamerArtifactId] }), item.review.brief.formationEvidence.provenance.sourceDiagnosisArtifactId && (_jsxs("div", { children: ["diagnosisArtifact: ", item.review.brief.formationEvidence.provenance.sourceDiagnosisArtifactId] })), item.review.brief.formationEvidence.notes.map((note, index) => (_jsxs("div", { children: ["formationNote: ", note] }, `${note}-${index}`)))] }))] }))] })) : (_jsxs("div", { className: "mt-2", children: [_jsx("p", { className: "text-ink-4 text-[12px] mb-2", children: item.kind === "activation_approval"
107
- ? t("pages.focus.ownerDecision.approvalHint")
108
- : t("pages.focus.ownerDecision.rulecodeHint") }), item.kind === "activation_approval" ? (_jsx(Link, { to: item.principleId !== undefined
109
- ? `/principles/${encodeURIComponent(item.principleId)}`
110
- : "/principles", "data-testid": `go-approvals-${item.taskId}`, className: "inline-flex items-center border border-gov text-gov bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-gov/5 transition-colors", children: t("pages.focus.ownerDecision.goApprovalsCta") })) : (_jsx(Link, { to: `/activation?activationId=${encodeURIComponent(item.taskId)}`, "data-testid": `go-activation-${item.taskId}`, className: "inline-flex items-center border border-gov text-gov bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-gov/5 transition-colors", children: t("pages.focus.ownerDecision.goActivationCta") }))] }))] }));
111
- }
@@ -1,19 +0,0 @@
1
- import { type ReactNode } from 'react';
2
- export type OwnerWorkItemKind = 'prompt' | 'rule' | 'promotion' | 'revision' | 'validation' | 'binding' | 'archive' | 'approval' | 'unknown';
3
- export interface OwnerWorkItem {
4
- key: string;
5
- title: string;
6
- kind: OwnerWorkItemKind;
7
- summary: string;
8
- reference?: string;
9
- content: ReactNode;
10
- }
11
- /** Presentation only: list grouping never changes an action's identity or authority. */
12
- export declare function OwnerWorkbench({ items, completed, uncertain }: {
13
- items: OwnerWorkItem[];
14
- completed: {
15
- key: string;
16
- message: string;
17
- } | null;
18
- uncertain: boolean;
19
- }): import("react").JSX.Element;
@@ -1,75 +0,0 @@
1
- import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useRef } from 'react';
3
- import { useSearchParams } from 'react-router-dom';
4
- import { useTranslation } from 'react-i18next';
5
- import { Archive, CircleHelp, ClipboardCheck, Code2, FilePenLine, FlaskConical, Link2, MessageSquareText, ShieldCheck } from 'lucide-react';
6
- // Type describes the decision, not an inferred urgency or permission.
7
- const KIND_PRESENTATION = {
8
- prompt: { icon: MessageSquareText, label: 'promptReview', style: 'border-gov/30 bg-gov/10 text-gov' },
9
- rule: { icon: Code2, label: 'ruleReview', style: 'border-ink-3/30 bg-ink-3/10 text-ink-2' },
10
- promotion: { icon: ShieldCheck, label: 'rulePromotion', style: 'border-amber/30 bg-amber/10 text-ink-2' },
11
- revision: { icon: FilePenLine, label: 'revisionDecision', style: 'border-amber/30 text-ink-2' },
12
- validation: { icon: FlaskConical, label: 'validationReview', style: 'border-gov/30 text-gov' },
13
- binding: { icon: Link2, label: 'bindingReview', style: 'border-gov/30 text-gov' },
14
- archive: { icon: Archive, label: 'archiveReview', style: 'border-line bg-surface text-ink-3' },
15
- approval: { icon: ClipboardCheck, label: 'approvalMaterialReview', style: 'border-line text-ink-2' },
16
- unknown: { icon: CircleHelp, label: 'unknownReview', style: 'border-line text-ink-3' },
17
- };
18
- function WorkItemType({ kind }) {
19
- const { t } = useTranslation();
20
- const { icon: Icon, label, style } = KIND_PRESENTATION[kind];
21
- return _jsxs("span", { "data-testid": "owner-work-type", "data-kind": kind, className: `inline-flex max-w-full items-center gap-1.5 rounded-[4px] border px-2 py-1 text-[11px] font-medium leading-relaxed ${style}`, children: [_jsx(Icon, { "aria-hidden": "true", className: "h-3.5 w-3.5 shrink-0", strokeWidth: 1.75 }), t(`pages.focus.workbench.${label}`)] });
22
- }
23
- /** Presentation only: list grouping never changes an action's identity or authority. */
24
- export function OwnerWorkbench({ items, completed, uncertain }) {
25
- const { t } = useTranslation();
26
- const [params, setParams] = useSearchParams();
27
- const selectedKey = params.get('review') ?? '';
28
- const selected = items.find(item => item.key === selectedKey);
29
- const heading = useRef(null);
30
- const list = useRef(null);
31
- const lastSelected = useRef('');
32
- const listScroll = useRef(0);
33
- // A deep link can arrive before the items do. `focusKey` only becomes the
34
- // selection once the item exists, so the effect re-runs when it appears
35
- // without stealing focus on every data refresh.
36
- const focusKey = selected ? selectedKey : '';
37
- useEffect(() => {
38
- if (focusKey) {
39
- heading.current?.focus({ preventScroll: true });
40
- const reading = heading.current?.closest('[data-testid="owner-work-reading"]');
41
- if (reading && (reading.getBoundingClientRect().top < 0 || reading.getBoundingClientRect().top > window.innerHeight - 100))
42
- reading.scrollIntoView({ block: 'start' });
43
- const current = list.current?.querySelector('[aria-current="true"]');
44
- if (current && list.current && list.current.scrollHeight > list.current.clientHeight) {
45
- list.current.scrollTop = Math.max(0, current.offsetTop - list.current.offsetTop - 24);
46
- }
47
- }
48
- else if (selectedKey) {
49
- heading.current?.focus({ preventScroll: true });
50
- }
51
- else if (lastSelected.current && list.current) {
52
- list.current.scrollTop = listScroll.current;
53
- const previous = Array.from(list.current.querySelectorAll('[data-item-key]')).find(button => button.dataset.itemKey === lastSelected.current);
54
- previous?.focus({ preventScroll: true });
55
- if (previous && (previous.getBoundingClientRect().top < 0 || previous.getBoundingClientRect().bottom > window.innerHeight))
56
- previous.scrollIntoView({ block: 'nearest' });
57
- }
58
- }, [focusKey, selectedKey]);
59
- function choose(key) {
60
- if (!key && selectedKey) {
61
- lastSelected.current = selectedKey;
62
- listScroll.current = list.current?.scrollTop ?? 0;
63
- }
64
- const next = new URLSearchParams(params);
65
- if (key)
66
- next.set('review', key);
67
- else
68
- next.delete('review');
69
- setParams(next, { preventScrollReset: true });
70
- }
71
- const completedHere = completed?.key === selectedKey ? completed : null;
72
- const selectedIndex = items.findIndex(item => item.key === selectedKey);
73
- const nextItem = selectedIndex >= 0 ? items[selectedIndex + 1] : undefined;
74
- return _jsxs("section", { className: "owner-workbench", "data-testid": "owner-workbench", children: [_jsxs("nav", { ref: list, tabIndex: -1, className: `owner-work-list ${selected ? 'owner-work-list-selected' : ''}`, "aria-label": t('pages.focus.workbench.list'), children: [_jsxs("div", { className: "mb-3 flex items-baseline justify-between gap-3", children: [_jsx("h2", { className: "text-[15px] font-medium text-ink", children: t('pages.focus.workbench.list') }), _jsx("span", { className: "text-[12px] text-ink-4", children: t('pages.focus.workbench.count', { count: items.length }) })] }), items.length === 0 && _jsx("p", { className: "text-sm leading-relaxed text-ink-3", children: t(uncertain ? 'pages.focus.workbench.uncertain' : 'pages.focus.workbench.empty') }), _jsx("ol", { className: "space-y-2", children: items.map(item => _jsx("li", { children: _jsxs("button", { type: "button", onClick: () => choose(item.key), "aria-current": selected?.key === item.key ? 'true' : undefined, "data-testid": "owner-work-item", "data-item-key": item.key, className: `w-full rounded-[6px] border px-4 py-4 text-left transition-colors focus-visible:outline-2 focus-visible:outline-gov ${selected?.key === item.key ? 'border-gov bg-gov/5' : 'border-line bg-panel hover:border-gov/50'}`, children: [_jsx("span", { className: "mb-3 block", children: _jsx(WorkItemType, { kind: item.kind }) }), _jsx("span", { className: "block text-[14px] font-medium leading-relaxed text-ink break-words", children: item.title }), _jsx("span", { className: "mt-2 block text-[12.5px] leading-relaxed text-ink-3 line-clamp-2", children: item.summary }), item.reference && items.some(other => other.key !== item.key && other.title === item.title && other.summary === item.summary) && _jsx("span", { className: "mt-2 block break-all font-mono text-[11px] text-ink-4", children: item.reference })] }) }, item.key)) })] }), _jsx("div", { className: "owner-work-reading min-w-0", "data-testid": "owner-work-reading", children: selected ? _jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "mb-5 text-[13px] text-gov underline underline-offset-4", onClick: () => choose(''), children: t('pages.focus.workbench.back') }), _jsx("div", { className: "mb-3", children: _jsx(WorkItemType, { kind: selected.kind }) }), _jsx("h2", { ref: heading, tabIndex: -1, className: "mb-6 text-[22px] font-semibold leading-snug text-ink break-words", children: selected.title }), _jsx("div", { children: selected.content }, selected.key), _jsxs("footer", { className: "mt-7 border-t border-line pt-5", children: [_jsx("p", { className: "mb-3 text-[12.5px] text-ink-3", children: t('pages.focus.workbench.readingEnd') }), nextItem && _jsx("button", { type: "button", className: "text-[13px] text-gov underline underline-offset-4", onClick: () => choose(nextItem.key), children: t('pages.focus.workbench.next') })] })] }) : _jsxs("div", { className: "py-10 text-ink-3", children: [_jsx("h2", { ref: heading, tabIndex: -1, className: "mb-3 text-[22px] font-medium text-ink", children: t(completedHere ? 'pages.focus.workbench.completed' : selectedKey ? 'pages.focus.workbench.notCurrent' : 'pages.focus.workbench.startTitle') }), _jsx("p", { role: completedHere ? 'status' : undefined, className: "max-w-[440px] text-[14px] leading-relaxed", children: completedHere?.message ?? t(selectedKey ? 'pages.focus.workbench.notCurrentBody' : 'pages.focus.workbench.startBody') }), items[0] && _jsx("button", { type: "button", className: "mt-6 rounded-[4px] border border-gov bg-gov px-4 py-2.5 text-sm text-paper", onClick: () => choose(items[0].key), children: t(completedHere ? 'pages.focus.workbench.next' : 'pages.focus.workbench.start') })] }) })] });
75
- }
@@ -1,34 +0,0 @@
1
- import type { RuleBindingQueueItem } from '../../../shared/rule-candidate-binding-contract.js';
2
- export type RuleBindingCardState = 'awaiting_owner' | 'bound_generating' | 'bound_blocked' | 'bound_advanced' | 'bound_not_built' | 'bound_ambiguous' | 'revoked' | 'attention';
3
- /** ERR-106: exhaustive display map over the card state union — no default branch. */
4
- export declare const RULE_BINDING_CARD_STATE_KEY: Record<RuleBindingCardState, string>;
5
- export declare const RULE_BINDING_CARD_STATE_CLASS: Record<RuleBindingCardState, string>;
6
- export declare function deriveRuleBindingCardState(item: RuleBindingQueueItem): RuleBindingCardState;
7
- export interface RuleBindingPainGroup {
8
- key: string;
9
- pain: RuleBindingQueueItem['pain'];
10
- items: RuleBindingQueueItem[];
11
- }
12
- /** Group by canonical pain id; a missing pain id gets its own per-candidate
13
- * group so unattributable candidates never vanish into someone else's group. */
14
- export declare function groupRuleBindingQueue(items: RuleBindingQueueItem[]): RuleBindingPainGroup[];
15
- /** The resume action may only appear when the real backend says ready AND the
16
- * chain is not currently running — a revision during an active run would be
17
- * a fake retry, not the bounded source revision. */
18
- export declare function canOfferRuleBindingResume(item: RuleBindingQueueItem): boolean;
19
- /**
20
- * PRI-1048 R6 #4: the source-correction entry applies when the bounded
21
- * source-correction budget is available on a bound+blocked chain — the shape
22
- * where the binding revision budget is typically already spent (the 52d
23
- * production candidate). Real eligibility is resolved server-side
24
- * (previewRuleSourceCorrection); click-time authority is reviseRuleSourceOnce.
25
- */
26
- export declare function canOfferSourceCorrection(item: Pick<RuleBindingQueueItem, 'binding' | 'generation' | 'sourceCorrection'>): boolean;
27
- /** Model-synthesized fallback sources must stay localized (CodeRabbit PRI-1048:
28
- * `unknown` previously fell through to raw English in the zh-CN group header). */
29
- export declare const PAIN_SOURCE_KEY: Record<string, string>;
30
- /** Inline in Governance Focus; assignment, rule approval and live promotion remain separate. */
31
- export declare function RuleCandidateBindingPanel({ candidateId, onChanged }?: {
32
- candidateId?: string;
33
- onChanged?: () => void;
34
- }): import("react").JSX.Element | null;
@@ -1,298 +0,0 @@
1
- import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useState } from 'react';
3
- import { useTranslation } from 'react-i18next';
4
- import { Link } from 'react-router-dom';
5
- import { fetchRuleBindingQueue, fetchRuleBindingReview, mutateRuleBinding, reviseRuleBindingOnce, correctRuleSource } from '../../api.js';
6
- import { splitReadingTitleBody } from '../../utils/reading-layout.js';
7
- /**
8
- * PRI-1048 治理焦点「规则的正式原则归属」队列。
9
- * 按痛苦信号分组的有界卡片列表;每张卡默认回答三问:
10
- * 这是哪次反馈 / 现在卡在哪 / 我要做什么。技术 ID 与原始 JSON 只进「技术详情」。
11
- * 归属、规则审批、激活三权分立不变(文案见 separate/declaration)。
12
- */
13
- /** Collapsed first screen shows at most this many pain groups. */
14
- const COLLAPSED_GROUP_LIMIT = 3;
15
- /** ERR-106: exhaustive display map over the card state union — no default branch. */
16
- export const RULE_BINDING_CARD_STATE_KEY = {
17
- awaiting_owner: 'pages.focus.ruleBinding.stateAwaitingOwner',
18
- bound_generating: 'pages.focus.ruleBinding.stateBoundGenerating',
19
- bound_blocked: 'pages.focus.ruleBinding.stateBoundBlocked',
20
- bound_advanced: 'pages.focus.ruleBinding.stateBoundAdvanced',
21
- bound_not_built: 'pages.focus.ruleBinding.stateBoundNotBuilt',
22
- bound_ambiguous: 'pages.focus.ruleBinding.stateBoundAmbiguous',
23
- revoked: 'pages.focus.ruleBinding.stateRevoked',
24
- attention: 'pages.focus.ruleBinding.stateAttention',
25
- };
26
- export const RULE_BINDING_CARD_STATE_CLASS = {
27
- awaiting_owner: 'border-gov/40 text-gov',
28
- bound_generating: 'border-green/40 text-green',
29
- bound_blocked: 'border-amber/45 text-amber',
30
- bound_advanced: 'border-green/40 text-green',
31
- bound_not_built: 'border-line text-ink-3',
32
- bound_ambiguous: 'border-amber/45 text-amber',
33
- revoked: 'border-line text-ink-3',
34
- attention: 'border-amber/45 text-amber',
35
- };
36
- export function deriveRuleBindingCardState(item) {
37
- switch (item.binding.status) {
38
- case 'unlinked': return 'awaiting_owner';
39
- case 'binding_revoked': return 'revoked';
40
- case 'attention': return 'attention';
41
- case 'bound':
42
- switch (item.generation?.stage) {
43
- case null:
44
- case undefined:
45
- case 'not_built': return 'bound_not_built';
46
- case 'in_progress': return 'bound_generating';
47
- case 'blocked': return 'bound_blocked';
48
- case 'advanced': return 'bound_advanced';
49
- case 'ambiguous': return 'bound_ambiguous';
50
- }
51
- }
52
- }
53
- /** Group by canonical pain id; a missing pain id gets its own per-candidate
54
- * group so unattributable candidates never vanish into someone else's group. */
55
- export function groupRuleBindingQueue(items) {
56
- const groups = new Map();
57
- for (const item of items) {
58
- const key = item.pain.painId === '' ? `candidate:${item.candidateId}` : item.pain.painId;
59
- const group = groups.get(key) ?? { key, pain: item.pain, items: [] };
60
- group.items.push(item);
61
- groups.set(key, group);
62
- }
63
- return [...groups.values()];
64
- }
65
- /** The resume action may only appear when the real backend says ready AND the
66
- * chain is not currently running — a revision during an active run would be
67
- * a fake retry, not the bounded source revision. */
68
- export function canOfferRuleBindingResume(item) {
69
- return item.binding.status === 'bound'
70
- && item.resume?.status === 'ready'
71
- && item.generation?.stage !== 'in_progress'
72
- && item.generation?.stage !== 'ambiguous';
73
- }
74
- /**
75
- * PRI-1048 R6 #4: the source-correction entry applies when the bounded
76
- * source-correction budget is available on a bound+blocked chain — the shape
77
- * where the binding revision budget is typically already spent (the 52d
78
- * production candidate). Real eligibility is resolved server-side
79
- * (previewRuleSourceCorrection); click-time authority is reviseRuleSourceOnce.
80
- */
81
- export function canOfferSourceCorrection(item) {
82
- return item.binding.status === 'bound'
83
- && item.generation?.stage === 'blocked'
84
- && item.sourceCorrection?.status === 'ready';
85
- }
86
- /** ERR-106: next-step copy and the left bar also use exhaustive maps. */
87
- const RULE_BINDING_NEXT_STEP_KEY = {
88
- awaiting_owner: 'pages.focus.ruleBinding.nextAwaitingOwner',
89
- bound_generating: 'pages.focus.ruleBinding.nextBoundGenerating',
90
- bound_blocked: 'pages.focus.ruleBinding.nextBoundBlocked',
91
- bound_advanced: 'pages.focus.ruleBinding.nextBoundAdvanced',
92
- bound_not_built: 'pages.focus.ruleBinding.nextBoundNotBuilt',
93
- bound_ambiguous: 'pages.focus.ruleBinding.nextBoundAmbiguous',
94
- revoked: 'pages.focus.ruleBinding.nextRevoked',
95
- attention: 'pages.focus.ruleBinding.nextAttention',
96
- };
97
- const RULE_BINDING_CARD_STATE_BAR = {
98
- awaiting_owner: 'bg-gov',
99
- bound_generating: 'bg-green',
100
- bound_blocked: 'bg-amber',
101
- bound_advanced: 'bg-green',
102
- bound_not_built: 'bg-line-2',
103
- bound_ambiguous: 'bg-amber',
104
- revoked: 'bg-line-2',
105
- attention: 'bg-amber',
106
- };
107
- /** Model-synthesized fallback sources must stay localized (CodeRabbit PRI-1048:
108
- * `unknown` previously fell through to raw English in the zh-CN group header). */
109
- export const PAIN_SOURCE_KEY = {
110
- unreadable: 'pages.focus.ruleBinding.sourceUnreadable',
111
- unknown: 'pages.focus.ruleBinding.sourceUnknown',
112
- manual: 'pages.focus.ruleBinding.sourceManual',
113
- tool_failure: 'pages.focus.ruleBinding.sourceToolFailure',
114
- };
115
- const STAGE_KIND_KEY = {
116
- dreamer: 'pages.focus.ruleBinding.stageDreamer',
117
- philosopher: 'pages.focus.ruleBinding.stagePhilosopher',
118
- scribe: 'pages.focus.ruleBinding.stageScribe',
119
- artificer: 'pages.focus.ruleBinding.stageArtificer',
120
- evaluator: 'pages.focus.ruleBinding.stageEvaluator',
121
- rollout_reviewer: 'pages.focus.ruleBinding.stageRolloutReviewer',
122
- };
123
- /** i18n with graceful fallback to the raw server code (visible, not dropped). */
124
- function codeText(t, prefix, code) {
125
- if (!code)
126
- return '';
127
- const key = `${prefix}.${code}`;
128
- const text = t(key);
129
- return text === key ? code : text;
130
- }
131
- function painSourceLabel(t, source) {
132
- const key = PAIN_SOURCE_KEY[source];
133
- return key ? t(key) : source;
134
- }
135
- function stageKindLabel(t, stageKind) {
136
- if (!stageKind)
137
- return null;
138
- const key = STAGE_KIND_KEY[stageKind];
139
- return key ? t(key) : stageKind;
140
- }
141
- /** Inline in Governance Focus; assignment, rule approval and live promotion remain separate. */
142
- export function RuleCandidateBindingPanel({ candidateId, onChanged } = {}) {
143
- const { t } = useTranslation();
144
- const [queue, setQueue] = useState(null);
145
- const [review, setReview] = useState(null);
146
- const [openCandidateId, setOpenCandidateId] = useState('');
147
- const [search, setSearch] = useState('');
148
- const [selectedId, setSelectedId] = useState('');
149
- const [reason, setReason] = useState('');
150
- const [busy, setBusy] = useState(false);
151
- const [message, setMessage] = useState('');
152
- const [error, setError] = useState('');
153
- const [showAllGroups, setShowAllGroups] = useState(false);
154
- useEffect(() => {
155
- let active = true;
156
- void fetchRuleBindingQueue().then(result => {
157
- if (!active)
158
- return;
159
- if (result.success)
160
- setQueue(result.data);
161
- else
162
- setError([result.error, result.nextAction].filter(Boolean).join(' ') || t('pages.focus.ruleBinding.unavailable'));
163
- });
164
- return () => { active = false; };
165
- }, [t]);
166
- async function load(candidateId, query = '') {
167
- setBusy(true);
168
- setError('');
169
- const result = await fetchRuleBindingReview(candidateId, query);
170
- if (result.success) {
171
- setReview(result.data);
172
- setOpenCandidateId(candidateId);
173
- setSelectedId('');
174
- }
175
- else
176
- setError([result.error, result.nextAction].filter(Boolean).join(' ') || t('pages.focus.ruleBinding.unavailable'));
177
- setBusy(false);
178
- }
179
- useEffect(() => { if (candidateId)
180
- void load(candidateId); }, [candidateId]);
181
- function closeReview() { setOpenCandidateId(''); setReview(null); setSearch(''); setReason(''); }
182
- async function refreshQueue() {
183
- const result = await fetchRuleBindingQueue();
184
- if (result.success) {
185
- setQueue(result.data);
186
- onChanged?.();
187
- }
188
- }
189
- async function decide(action) {
190
- if (!review)
191
- return;
192
- const target = review.eligibleTargets.find(p => p.principleId === selectedId);
193
- if (action === 'bind' && !target)
194
- return;
195
- setBusy(true);
196
- setError('');
197
- setMessage('');
198
- const requestId = crypto.randomUUID();
199
- const common = { expectedRevision: review.currentRevision, reason, requestId };
200
- const result = await mutateRuleBinding(review.candidateId, action === 'bind' && target
201
- ? { ...common, action: 'bind', resumeOnce: true, principleId: target.principleId, expectedCandidateDigest: review.candidateDigest, expectedPrincipleDigest: target.digest }
202
- : { ...common, action: 'revoke', resumeOnce: false });
203
- if (result.success) {
204
- setMessage(action === 'revoke' ? t('pages.focus.ruleBinding.revoked')
205
- : result.data.revisionStatus === 'refused' ? t('pages.focus.ruleBinding.resumeFailed') : t('pages.focus.ruleBinding.bound'));
206
- await load(review.candidateId, search);
207
- await refreshQueue();
208
- }
209
- else
210
- setError([result.error, result.nextAction].filter(Boolean).join(' ') || t('pages.focus.ruleBinding.unavailable'));
211
- setBusy(false);
212
- }
213
- /** Only reachable when the real resolver said ready (canOfferRuleBindingResume). */
214
- async function revise() {
215
- if (!review?.resume || review.resume.status !== 'ready' || review.resume.scribeTaskId === null || review.resume.taskRevisionEpoch === null)
216
- return;
217
- setBusy(true);
218
- setError('');
219
- setMessage('');
220
- const result = await reviseRuleBindingOnce(review.candidateId, {
221
- expectedBindingRevision: review.currentRevision,
222
- expectedScribeTaskId: review.resume.scribeTaskId,
223
- expectedTaskRevisionEpoch: review.resume.taskRevisionEpoch,
224
- requestId: crypto.randomUUID(),
225
- });
226
- if (result.success) {
227
- setMessage(result.data.status === 'revision_already_started'
228
- ? t('pages.focus.ruleBinding.reviseAlreadyStarted')
229
- : t('pages.focus.ruleBinding.reviseStarted'));
230
- await load(review.candidateId, search);
231
- await refreshQueue();
232
- }
233
- else
234
- setError([result.error, result.nextAction].filter(Boolean).join(' ') || t('pages.focus.ruleBinding.unavailable'));
235
- setBusy(false);
236
- }
237
- /** PRI-1048 R6 #4: only reachable when the server preview said ready
238
- * (canOfferSourceCorrection); the server re-validates every CAS input. */
239
- async function correctSource() {
240
- const preview = review?.sourceCorrection;
241
- if (!review || !preview || preview.status !== 'ready'
242
- || preview.scribeTaskId === null || preview.artificerTaskId === null
243
- || preview.scribeArtifactDigest === null || preview.expectedBindingRevision === null)
244
- return;
245
- setBusy(true);
246
- setError('');
247
- setMessage('');
248
- const result = await correctRuleSource(review.candidateId, {
249
- expectedBindingRevision: preview.expectedBindingRevision,
250
- expectedScribeTaskId: preview.scribeTaskId,
251
- expectedArtificerTaskId: preview.artificerTaskId,
252
- expectedScribeArtifactDigest: preview.scribeArtifactDigest,
253
- reason,
254
- requestId: crypto.randomUUID(),
255
- });
256
- if (result.success) {
257
- setMessage(result.data.status === 'revision_already_started'
258
- ? t('pages.focus.ruleBinding.sourceCorrectionAlreadyStarted')
259
- : t('pages.focus.ruleBinding.sourceCorrectionStarted'));
260
- await load(review.candidateId, search);
261
- await refreshQueue();
262
- }
263
- else
264
- setError([result.error, result.nextAction].filter(Boolean).join(' ') || t('pages.focus.ruleBinding.unavailable'));
265
- setBusy(false);
266
- }
267
- if ((queue === null || queue.items.length === 0) && !error)
268
- return null;
269
- const groups = groupRuleBindingQueue((queue?.items ?? []).filter(item => candidateId === undefined || item.candidateId === candidateId));
270
- const visibleGroups = showAllGroups ? groups : groups.slice(0, COLLAPSED_GROUP_LIMIT);
271
- const bound = review?.currentBinding?.action === 'bind';
272
- return _jsxs("section", { className: "mb-7 rounded border border-line p-4", "data-testid": "rule-binding-panel", "aria-label": t('pages.focus.ruleBinding.title'), children: [_jsx("h2", { className: "text-sm font-medium", children: t('pages.focus.ruleBinding.title') }), _jsx("p", { className: "mt-2 text-sm text-ink-3", children: t('pages.focus.ruleBinding.separate') }), queue && _jsx("p", { className: "mt-2 text-[13px] text-ink-3", role: "status", "data-testid": "rule-binding-counts", children: t('pages.focus.ruleBinding.countsLine', { candidates: queue.summary.candidates, painGroups: queue.summary.painGroups, bound: queue.summary.bound, unlinked: queue.summary.unlinked, blocked: queue.summary.blocked }) }), queue?.truncated && _jsx("p", { className: "mt-1 text-[12.5px] text-amber", children: t('pages.focus.ruleBinding.truncatedNote', { count: queue.items.length }) }), error && _jsx("p", { role: "alert", className: "my-2 text-amber", children: error }), message && _jsx("p", { role: "status", className: "my-2", children: message }), visibleGroups.map(group => _jsxs("div", { className: "mt-4", "data-testid": "rule-binding-pain-group", children: [_jsxs("div", { className: "border-l-2 border-line pl-3", children: [_jsxs("div", { className: "text-[13px] text-ink-2 leading-relaxed", children: [_jsx("span", { className: "font-medium text-ink", children: t('pages.focus.ruleBinding.groupPrefix') }), ' ', group.pain.text
273
- ? splitReadingTitleBody(group.pain.text).title
274
- : t('pages.focus.ruleBinding.painUnrecorded')] }), _jsxs("div", { className: "mt-0.5 text-[11.5px] text-ink-4", children: [painSourceLabel(t, group.pain.source), group.pain.createdAt ? ` · ${group.pain.createdAt.slice(0, 10)}` : '', ' · ', t('pages.focus.ruleBinding.groupCount', { count: group.items.length })] })] }), group.items.map(item => {
275
- const cardState = deriveRuleBindingCardState(item);
276
- const layout = splitReadingTitleBody(item.text);
277
- const open = openCandidateId === item.candidateId;
278
- return _jsxs("article", { className: "relative mt-3 pl-[22px] py-[14px] pr-[18px] bg-panel border border-line rounded-[6px]", "data-testid": `rule-binding-card-${item.candidateId}`, children: [_jsx("div", { className: `absolute left-0 top-0 bottom-0 w-[3px] rounded-l-[6px] ${RULE_BINDING_CARD_STATE_BAR[cardState]}` }), _jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx("span", { className: `inline-flex items-center border rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase ${RULE_BINDING_CARD_STATE_CLASS[cardState]}`, children: t(RULE_BINDING_CARD_STATE_KEY[cardState]) }), (() => {
279
- const stageLabel = stageKindLabel(t, item.generation?.stageKind ?? null);
280
- return stageLabel
281
- ? _jsxs("span", { className: "text-[11.5px] text-ink-4", children: [t('pages.focus.ruleBinding.currentStage'), stageLabel] })
282
- : null;
283
- })()] }), _jsx("div", { className: "mt-[10px] mb-1 font-semibold text-ink leading-snug", "data-testid": `rule-binding-title-${item.candidateId}`, children: layout.title }), layout.body !== null && _jsx("div", { className: "mb-2 text-[14px] leading-relaxed text-ink-2 whitespace-pre-wrap break-words", children: layout.body }), item.binding.status === 'bound' && _jsxs("div", { className: "mt-2 px-3 py-2 bg-surface/60 border-l-2 border-gov text-[13px] leading-relaxed", children: [_jsx("span", { className: "text-ink-3", children: t('pages.focus.ruleBinding.boundTo') }), ' ', _jsx("span", { className: "text-ink", children: splitReadingTitleBody(item.binding.principle.text).title }), ' · ', _jsxs("span", { className: "text-ink-4", children: [t(`principles.status${item.binding.principle.status[0]?.toUpperCase()}${item.binding.principle.status.slice(1)}`, { defaultValue: item.binding.principle.status }), " \u00B7 ", t('pages.focus.ruleBinding.version'), " ", item.binding.principle.version] }), ' · ', _jsx(Link, { to: `/principles/${item.binding.principle.principleId}`, className: "text-gov underline", children: t('pages.focus.ruleBinding.viewPrinciple') })] }), cardState === 'bound_blocked' && item.generation && _jsxs("div", { className: "mt-2 text-[12.5px] leading-relaxed text-amber", "data-testid": `rule-binding-blocked-${item.candidateId}`, children: [t('pages.focus.ruleBinding.blockedLine', {
284
- stage: stageKindLabel(t, item.generation.stageKind) ?? '',
285
- reason: codeText(t, 'pages.focus.ruleBinding.blockReason', item.generation.reasonCode) || t('pages.focus.ruleBinding.blockReasonUnknown'),
286
- }), _jsx("div", { className: "mt-0.5 text-ink-3", children: t('pages.focus.ruleBinding.blockedNoOwnerApproval') }), item.generation.detail && _jsxs("details", { className: "mt-1 text-[11.5px]", children: [_jsx("summary", { className: "cursor-pointer select-none", children: t('pages.focus.ruleBinding.blockedDetail') }), _jsx("pre", { className: "mt-1 max-h-40 overflow-auto whitespace-pre-wrap break-words font-mono text-[11px]", children: item.generation.detail })] })] }), cardState === 'attention' && _jsx("div", { className: "mt-2 text-[12.5px] leading-relaxed text-amber", "data-testid": `rule-binding-attention-${item.candidateId}`, children: t('pages.focus.ruleBinding.attentionLine', { reason: item.binding.status === 'attention' ? item.binding.reason : '' }) }), _jsxs("div", { className: "mt-2 text-[12.5px] text-ink-3 leading-relaxed", "data-testid": `rule-binding-next-${item.candidateId}`, children: [_jsx("span", { className: "font-medium", children: t('pages.focus.ruleBinding.nextLabel') }), ' ', cardState === 'bound_blocked' && item.resume?.status === 'refused'
287
- ? t('pages.focus.ruleBinding.nextBoundBlockedNoResume', { reason: codeText(t, 'pages.focus.ruleBinding.resumeReason', item.resume.reason) })
288
- : t(RULE_BINDING_NEXT_STEP_KEY[cardState])] }), _jsxs("details", { className: "mt-2 text-[11.5px] text-ink-4", children: [_jsx("summary", { className: "cursor-pointer select-none", children: t('pages.focus.ruleBinding.techDetails') }), _jsxs("dl", { className: "mt-1 font-mono text-[11px] break-all", children: [_jsxs("div", { children: ["candidateId: ", item.candidateId] }), _jsxs("div", { children: ["painId: ", item.pain.painId || '—'] }), item.binding.status === 'bound' && _jsxs("div", { children: ["bindingRevision: ", item.binding.principle.revision, " \u00B7 decidedAt: ", item.binding.principle.decidedAt || '—'] }), item.resume && _jsxs("div", { children: ["resume: ", item.resume.status, item.resume.reason ? ` (${item.resume.reason})` : '', item.resume.scribeTaskId ? ` · ${item.resume.scribeTaskId}` : ''] })] })] }), _jsx("button", { type: "button", className: "mt-3 inline-flex items-center border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed", disabled: busy, "aria-expanded": open, onClick: () => { if (open)
289
- closeReview();
290
- else {
291
- setSearch('');
292
- setReason('');
293
- void load(item.candidateId);
294
- } }, children: open ? t('pages.focus.ruleBinding.closeReview') : t('pages.focus.ruleBinding.openReview') }), open && review && review.candidateId === item.candidateId && _jsxs("div", { className: "mt-4 border-t border-line pt-3", children: [_jsx("h3", { className: "font-medium text-[13px]", children: t('pages.focus.ruleBinding.candidate') }), _jsx("p", { className: "mt-1 whitespace-pre-wrap text-sm", children: review.candidateText }), _jsxs("p", { className: "mt-2 text-sm", children: [t('pages.focus.ruleBinding.pain'), "\uFF1A", review.sourcePain.text ?? t('pages.focus.ruleBinding.painUnrecorded')] }), _jsxs("details", { className: "mt-2 text-sm", children: [_jsx("summary", { children: t('pages.focus.ruleBinding.evidence') }), _jsx("pre", { className: "whitespace-pre-wrap break-words", children: review.evidence })] }), bound && review.boundPrinciple && _jsxs(_Fragment, { children: [_jsxs("div", { className: "mt-3 px-3 py-2 bg-surface/60 border-l-2 border-gov text-[13px] leading-relaxed", children: [_jsx("div", { className: "whitespace-pre-wrap", children: review.boundPrinciple.text }), _jsxs("div", { className: "mt-1 text-ink-4", children: [t('pages.focus.ruleBinding.boundSince', { revision: review.boundPrinciple.revision, date: review.boundPrinciple.decidedAt.slice(0, 10) || '—' }), " \u00B7 ", _jsx(Link, { to: `/principles/${review.boundPrinciple.principleId}`, className: "text-gov underline", children: t('pages.focus.ruleBinding.viewPrinciple') })] })] }), canOfferRuleBindingResume({ ...item, resume: review.resume }) && _jsx("button", { type: "button", className: "mt-3 rounded border border-gov bg-gov text-paper px-3 py-2 text-sm disabled:opacity-50", disabled: busy, onClick: () => void revise(), children: t('pages.focus.ruleBinding.reviseCta') }), canOfferSourceCorrection({ ...item, sourceCorrection: review.sourceCorrection }) && _jsx("button", { type: "button", className: "mt-3 ml-2 rounded border border-gov bg-gov text-paper px-3 py-2 text-sm disabled:opacity-50", disabled: busy || !reason.trim(), "data-testid": "rule-binding-source-correct-cta", onClick: () => void correctSource(), children: t('pages.focus.ruleBinding.sourceCorrectionCta') }), review.resume?.status === 'refused' && _jsx("p", { className: "mt-3 text-[12.5px] text-ink-3 leading-relaxed", children: t('pages.focus.ruleBinding.resumeUnavailable', { reason: codeText(t, 'pages.focus.ruleBinding.resumeReason', review.resume.reason) }) }), review.generation?.stage === 'blocked' && review.sourceCorrection?.status === 'unavailable' && _jsx("p", { className: "mt-2 text-[12.5px] text-ink-4 leading-relaxed", children: t('pages.focus.ruleBinding.sourceCorrectionUnavailable', { reason: review.sourceCorrection.reason ?? '' }) }), review.generation?.stage === 'in_progress' && _jsx("p", { className: "mt-3 text-[12.5px] text-ink-3", children: t('pages.focus.ruleBinding.nextBoundGenerating') })] }), !bound && _jsxs(_Fragment, { children: [_jsx("p", { className: "mt-3 text-sm text-ink-3", children: t('pages.focus.ruleBinding.chooseTarget') }), _jsxs("form", { className: "mt-3 flex gap-2", onSubmit: event => { event.preventDefault(); void load(review.candidateId, search); }, children: [_jsx("input", { value: search, onChange: event => setSearch(event.target.value), maxLength: 200, "aria-label": t('pages.focus.ruleBinding.search'), className: "border border-line p-2 text-sm" }), _jsx("button", { disabled: busy, type: "submit", children: t('pages.focus.ruleBinding.search') })] }), review.eligibleTargets.length === 0 && _jsxs("p", { className: "mt-2 text-sm", children: [t('pages.focus.ruleBinding.noTarget'), " ", _jsx(Link, { to: "/principles", className: "underline", children: t('pages.focus.ruleBinding.formation') })] }), review.eligibleTargets.map(target => _jsxs("label", { className: "my-3 block border border-line p-3 text-sm", children: [_jsx("input", { type: "radio", name: "binding-target", value: target.principleId, checked: selectedId === target.principleId, onChange: () => setSelectedId(target.principleId) }), _jsxs("span", { className: "ml-2", children: [t(`principles.status${target.status[0]?.toUpperCase()}${target.status.slice(1)}`, { defaultValue: target.status }), " \u00B7 ", t('pages.focus.ruleBinding.version'), " ", target.version] }), _jsx("p", { className: "mt-2 whitespace-pre-wrap", children: target.text })] }, target.principleId)), _jsx("p", { className: "mt-3 text-sm text-ink-3", children: review.resumeNotice }), _jsx("p", { className: "mt-2 text-sm", children: t('pages.focus.ruleBinding.declaration') })] }), _jsxs("label", { className: "mt-3 block text-sm", children: [t('pages.focus.ruleBinding.reason'), _jsx("textarea", { className: "mt-1 block w-full border border-line p-2", maxLength: 2000, value: reason, onChange: event => setReason(event.target.value) })] }), _jsxs("div", { className: "mt-3 flex gap-2 flex-wrap", children: [!bound && _jsx("button", { type: "button", className: "rounded border border-gov px-3 py-2 text-sm disabled:opacity-50", disabled: busy || !reason.trim() || !selectedId, onClick: () => void decide('bind'), children: t('pages.focus.ruleBinding.bind') }), bound && _jsx("button", { type: "button", className: "rounded border border-line px-3 py-2 text-sm disabled:opacity-50", disabled: busy || !reason.trim(), onClick: () => void decide('revoke'), children: t('pages.focus.ruleBinding.revokeSecondary') })] }), _jsxs("p", { className: "mt-3 text-sm text-ink-3", children: [t('pages.focus.ruleBinding.revokeBoundary'), " ", _jsx(Link, { to: "/activation", className: "underline", children: t('pages.focus.ruleBinding.stop') })] })] })] }, item.candidateId);
295
- })] }, group.key)), groups.length > COLLAPSED_GROUP_LIMIT && _jsx("button", { type: "button", className: "mt-3 text-[12.5px] text-gov underline", onClick: () => setShowAllGroups(value => !value), "aria-expanded": showAllGroups, "data-testid": "rule-binding-groups-toggle", children: showAllGroups
296
- ? t('pages.focus.ruleBinding.hideRemaining')
297
- : t('pages.focus.ruleBinding.viewRemaining', { count: groups.length - COLLAPSED_GROUP_LIMIT }) })] });
298
- }