create-principles-disciple 1.145.0 → 1.145.3
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.
- package/LICENSE +73 -21
- package/NOTICE +2 -0
- package/README.md +1 -1
- package/_release/product-identity.json +2 -2
- package/codex-adapter/package.json +5 -3
- package/console/dist/server/models/ApprovalsGroupedConsoleModel.js +4 -4
- package/console/dist/ui/i18n/en.json +17 -16
- package/console/dist/ui/i18n/zh-CN.json +17 -16
- package/console/dist/ui/pages/focus/FocusPage.js +9 -5
- package/console/dist/ui/pages/focus/OwnerDecisionCard.js +1 -1
- package/console/dist/ui/pages/principles/PrincipleDetailPage.js +10 -4
- package/console/dist/ui/pages/principles/PrinciplesPage.js +1 -1
- package/console/dist/ui/utils/reading-layout.d.ts +19 -0
- package/console/dist/ui/utils/reading-layout.js +46 -0
- package/console/dist/web/assets/app.js +30 -28
- package/console/package.json +2 -1
- package/core/dist/runtime-v2/index.d.ts +10 -0
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +5 -0
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.d.ts +25 -6
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.js +21 -7
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.js.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-run-correlation.d.ts +82 -0
- package/core/dist/runtime-v2/internalization/artificer-run-correlation.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/artificer-run-correlation.js +79 -0
- package/core/dist/runtime-v2/internalization/artificer-run-correlation.js.map +1 -0
- package/core/dist/runtime-v2/internalization/artificer-runner.d.ts +16 -2
- package/core/dist/runtime-v2/internalization/artificer-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-runner.js +89 -9
- package/core/dist/runtime-v2/internalization/artificer-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/consumer-evidence-preflight.d.ts +141 -0
- package/core/dist/runtime-v2/internalization/consumer-evidence-preflight.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/consumer-evidence-preflight.js +284 -0
- package/core/dist/runtime-v2/internalization/consumer-evidence-preflight.js.map +1 -0
- package/core/dist/runtime-v2/internalization/evidence-readiness.d.ts +170 -0
- package/core/dist/runtime-v2/internalization/evidence-readiness.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/evidence-readiness.js +335 -0
- package/core/dist/runtime-v2/internalization/evidence-readiness.js.map +1 -0
- package/core/dist/runtime-v2/internalization/owner-evidence-recovery.d.ts +190 -0
- package/core/dist/runtime-v2/internalization/owner-evidence-recovery.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/owner-evidence-recovery.js +488 -0
- package/core/dist/runtime-v2/internalization/owner-evidence-recovery.js.map +1 -0
- package/core/dist/runtime-v2/internalization/owner-retry.d.ts +23 -1
- package/core/dist/runtime-v2/internalization/owner-retry.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/owner-retry.js +19 -3
- package/core/dist/runtime-v2/internalization/owner-retry.js.map +1 -1
- package/core/dist/runtime-v2/internalization/peer-runner-contracts.d.ts +8 -0
- package/core/dist/runtime-v2/internalization/peer-runner-contracts.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/peer-runner-contracts.js.map +1 -1
- package/core/dist/runtime-v2/internalization/pitask-metadata.d.ts +12 -0
- package/core/dist/runtime-v2/internalization/pitask-metadata.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/pitask-metadata.js +24 -0
- package/core/dist/runtime-v2/internalization/pitask-metadata.js.map +1 -1
- package/core/dist/runtime-v2/recovery-actions-log.d.ts +40 -0
- package/core/dist/runtime-v2/recovery-actions-log.d.ts.map +1 -1
- package/core/dist/runtime-v2/recovery-actions-log.js +77 -2
- package/core/dist/runtime-v2/recovery-actions-log.js.map +1 -1
- package/core/dist/runtime-v2/store/runtime-state-manager.d.ts +6 -1
- package/core/dist/runtime-v2/store/runtime-state-manager.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/runtime-state-manager.js +6 -2
- package/core/dist/runtime-v2/store/runtime-state-manager.js.map +1 -1
- package/core/dist/runtime-v2/store/task/memory-task-store.d.ts +3 -1
- package/core/dist/runtime-v2/store/task/memory-task-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/task/memory-task-store.js +6 -1
- package/core/dist/runtime-v2/store/task/memory-task-store.js.map +1 -1
- package/core/dist/runtime-v2/store/task/sqlite-task-store.d.ts +3 -1
- package/core/dist/runtime-v2/store/task/sqlite-task-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/task/sqlite-task-store.js +10 -2
- package/core/dist/runtime-v2/store/task/sqlite-task-store.js.map +1 -1
- package/core/dist/runtime-v2/store/task/task-store.d.ts +11 -5
- package/core/dist/runtime-v2/store/task/task-store.d.ts.map +1 -1
- package/core/dist/telemetry-event.d.ts +2 -2
- package/core/dist/telemetry-event.d.ts.map +1 -1
- package/core/dist/telemetry-event.js +13 -0
- package/core/dist/telemetry-event.js.map +1 -1
- package/core/package.json +9 -3
- package/dist/installers/workbuddy-host-installer.d.ts +16 -3
- package/dist/installers/workbuddy-host-installer.d.ts.map +1 -1
- package/dist/installers/workbuddy-host-installer.js +57 -10
- package/dist/installers/workbuddy-host-installer.js.map +1 -1
- package/host-runtime/dist/internalization-consumer-cycle.d.ts +12 -1
- package/host-runtime/dist/internalization-consumer-cycle.js +141 -16
- package/host-runtime/dist/workspace-telemetry-emitter.js +13 -0
- package/host-runtime/package.json +5 -3
- package/install-layout/package.json +5 -3
- package/package.json +6 -5
- package/pd-cli/dist/commands/runtime-internalization-audit-artificer-evidence.d.ts +44 -0
- package/pd-cli/dist/commands/runtime-internalization-audit-artificer-evidence.d.ts.map +1 -0
- package/pd-cli/dist/commands/runtime-internalization-audit-artificer-evidence.js +138 -0
- package/pd-cli/dist/commands/runtime-internalization-audit-artificer-evidence.js.map +1 -0
- package/pd-cli/dist/commands/runtime-internalization-evidence.d.ts +72 -0
- package/pd-cli/dist/commands/runtime-internalization-evidence.d.ts.map +1 -0
- package/pd-cli/dist/commands/runtime-internalization-evidence.js +424 -0
- package/pd-cli/dist/commands/runtime-internalization-evidence.js.map +1 -0
- package/pd-cli/dist/commands/runtime-internalization-run-once.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-once.js +22 -1
- package/pd-cli/dist/commands/runtime-internalization-run-once.js.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-rulehost.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-rulehost.js +45 -4
- package/pd-cli/dist/commands/runtime-internalization-run-rulehost.js.map +1 -1
- package/pd-cli/dist/index.js +8 -0
- package/pd-cli/dist/index.js.map +1 -1
- package/pd-cli/dist/services/artificer-evidence-audit.d.ts +156 -0
- package/pd-cli/dist/services/artificer-evidence-audit.d.ts.map +1 -0
- package/pd-cli/dist/services/artificer-evidence-audit.js +321 -0
- package/pd-cli/dist/services/artificer-evidence-audit.js.map +1 -0
- package/pd-cli/dist/services/rulehost-pipeline-runner.d.ts.map +1 -1
- package/pd-cli/dist/services/rulehost-pipeline-runner.js +17 -3
- package/pd-cli/dist/services/rulehost-pipeline-runner.js.map +1 -1
- package/pd-cli/package.json +5 -3
- package/plugin/dist/bundle.js +491 -491
- package/plugin/dist/openclaw.plugin.json +1 -1
- package/plugin/dist/rulehost-evidence.js +26 -26
- package/plugin/openclaw.plugin.json +1 -1
- package/plugin/package.json +5 -3
- package/release-manager/dist/installers/workbuddy-host-installer.d.ts +16 -3
- package/release-manager/dist/installers/workbuddy-host-installer.d.ts.map +1 -1
- package/release-manager/dist/installers/workbuddy-host-installer.js +57 -10
- package/release-manager/dist/installers/workbuddy-host-installer.js.map +1 -1
- package/release-manager/package.json +5 -4
- package/workbuddy-adapter/package.json +5 -3
- package/console/dist/ui/utils/navigation.d.ts +0 -9
- package/console/dist/ui/utils/navigation.js +0 -7
- package/core/dist/runtime-v2/internalization/dimension-coverage-policy.d.ts +0 -54
- package/core/dist/runtime-v2/internalization/dimension-coverage-policy.d.ts.map +0 -1
- package/core/dist/runtime-v2/internalization/dimension-coverage-policy.js +0 -70
- package/core/dist/runtime-v2/internalization/dimension-coverage-policy.js.map +0 -1
package/LICENSE
CHANGED
|
@@ -1,21 +1,73 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
|
10
|
+
|
|
11
|
+
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
|
12
|
+
|
|
13
|
+
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
|
14
|
+
|
|
15
|
+
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
|
16
|
+
|
|
17
|
+
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
|
18
|
+
|
|
19
|
+
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
|
20
|
+
|
|
21
|
+
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
|
22
|
+
|
|
23
|
+
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
|
24
|
+
|
|
25
|
+
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
|
26
|
+
|
|
27
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
|
28
|
+
|
|
29
|
+
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
|
30
|
+
|
|
31
|
+
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
|
32
|
+
|
|
33
|
+
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
|
34
|
+
|
|
35
|
+
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
|
36
|
+
|
|
37
|
+
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
|
|
38
|
+
|
|
39
|
+
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
|
40
|
+
|
|
41
|
+
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
|
42
|
+
|
|
43
|
+
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
|
44
|
+
|
|
45
|
+
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
|
46
|
+
|
|
47
|
+
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
|
48
|
+
|
|
49
|
+
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
|
50
|
+
|
|
51
|
+
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
|
52
|
+
|
|
53
|
+
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
|
54
|
+
|
|
55
|
+
END OF TERMS AND CONDITIONS
|
|
56
|
+
|
|
57
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
58
|
+
|
|
59
|
+
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
|
|
60
|
+
|
|
61
|
+
Copyright [yyyy] [name of copyright owner]
|
|
62
|
+
|
|
63
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
64
|
+
you may not use this file except in compliance with the License.
|
|
65
|
+
You may obtain a copy of the License at
|
|
66
|
+
|
|
67
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
68
|
+
|
|
69
|
+
Unless required by applicable law or agreed to in writing, software
|
|
70
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
71
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
72
|
+
See the License for the specific language governing permissions and
|
|
73
|
+
limitations under the License.
|
package/NOTICE
ADDED
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@principles/codex-adapter",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"description": "Codex CLI host adapter for Principles Disciple — implements HostAdapter interface for OpenAI Codex CLI's stdin/stdout JSON hook model (ADR-0020).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -22,7 +22,9 @@
|
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
24
|
"dist",
|
|
25
|
-
"README.md"
|
|
25
|
+
"README.md",
|
|
26
|
+
"LICENSE",
|
|
27
|
+
"NOTICE"
|
|
26
28
|
],
|
|
27
29
|
"scripts": {
|
|
28
30
|
"build": "tsc",
|
|
@@ -41,7 +43,7 @@
|
|
|
41
43
|
"vite": "^8.3.4",
|
|
42
44
|
"vitest": "^5.0.0"
|
|
43
45
|
},
|
|
44
|
-
"license": "
|
|
46
|
+
"license": "Apache-2.0",
|
|
45
47
|
"repository": {
|
|
46
48
|
"type": "git",
|
|
47
49
|
"url": "git+https://github.com/csuzngjh/principles.git",
|
|
@@ -64,7 +64,7 @@ function extractCandidateDescription(contentJson) {
|
|
|
64
64
|
const principleText = principleRaw ? principleRaw.trim() : null;
|
|
65
65
|
const ruleText = ruleRaw ? ruleRaw.trim() : null;
|
|
66
66
|
if (principleText && ruleText)
|
|
67
|
-
return `${principleText}
|
|
67
|
+
return `${principleText} — ${ruleText}`;
|
|
68
68
|
if (ruleText)
|
|
69
69
|
return ruleText;
|
|
70
70
|
if (principleText)
|
|
@@ -79,7 +79,7 @@ function extractCandidateDescription(contentJson) {
|
|
|
79
79
|
const title = typeof draft.title === 'string' ? draft.title.trim() : '';
|
|
80
80
|
const statement = typeof draft.statement === 'string' ? draft.statement.trim() : '';
|
|
81
81
|
if (title && statement)
|
|
82
|
-
return `${title}
|
|
82
|
+
return `${title} — ${statement}`;
|
|
83
83
|
if (title)
|
|
84
84
|
return title;
|
|
85
85
|
if (statement)
|
|
@@ -148,7 +148,7 @@ export class ApprovalsGroupedConsoleModel {
|
|
|
148
148
|
async getApprovalsGrouped(targetHost) {
|
|
149
149
|
const stateDbPath = path.join(this.workspaceDir, '.pd', 'state.db');
|
|
150
150
|
if (!fs.existsSync(stateDbPath)) {
|
|
151
|
-
return { groups: [], generatedAt: new Date().toISOString(), note: 'state.db not found
|
|
151
|
+
return { groups: [], generatedAt: new Date().toISOString(), note: 'state.db not found — workspace may not be initialized' };
|
|
152
152
|
}
|
|
153
153
|
const conn = new SqliteConnection({ workspaceDir: this.workspaceDir, readonly: true });
|
|
154
154
|
try {
|
|
@@ -161,7 +161,7 @@ export class ApprovalsGroupedConsoleModel {
|
|
|
161
161
|
}
|
|
162
162
|
catch (err) {
|
|
163
163
|
if (isMissingTableError(err)) {
|
|
164
|
-
return { groups: [], generatedAt: new Date().toISOString(), note: 'approval table not found
|
|
164
|
+
return { groups: [], generatedAt: new Date().toISOString(), note: 'approval table not found — workspace may not be initialized' };
|
|
165
165
|
}
|
|
166
166
|
throw err;
|
|
167
167
|
}
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"tagLowRisk": "Low Risk",
|
|
96
96
|
"recordCount": "{{count}} record(s)",
|
|
97
97
|
"deviationCount": "deviation(s)",
|
|
98
|
-
"evidenceSummary": "
|
|
98
|
+
"evidenceSummary": "Approval records: {{count}}",
|
|
99
99
|
"untitledCandidate": "Untitled candidate principle",
|
|
100
100
|
"promptCapacityUnconfirmed": "Host capacity unconfirmed: the applicable hosts of this workspace take different injection routes; the numbers below are not bound to a specific host.",
|
|
101
101
|
"promptCapacitySharedRoute": "shared injection (billed on the full injected block)",
|
|
@@ -107,18 +107,18 @@
|
|
|
107
107
|
"promptScopeShared": "Forecast window (shared route, billed on the full injected block, unit=chars)",
|
|
108
108
|
"promptScopeList": "Forecast window (list route, billed on the selected lines{{full}}, unit=chars)",
|
|
109
109
|
"promptScopeFullRender": "; full injected block ≈ {{count}} chars",
|
|
110
|
-
"artifactUnavailableNote": "The draft artifact this approval points to is no longer in the artifact store (likely superseded by a newer revision), so its content cannot be shown. If in doubt, reject it; the raw artifact ID is shown in the
|
|
111
|
-
"unlinkedCandidateNote": "No principle name is available for this card: its lineage cannot be resolved to a principle, and no readable title could be extracted from its stored content. Judge it from the
|
|
110
|
+
"artifactUnavailableNote": "The draft artifact this approval points to is no longer in the artifact store (likely superseded by a newer revision), so its content cannot be shown. If in doubt, reject it; the raw artifact ID is shown in the replacement section's current-artifact field.",
|
|
111
|
+
"unlinkedCandidateNote": "No principle name is available for this card: its lineage cannot be resolved to a principle, and no readable title could be extracted from its stored content. Judge it from the approval records below; if you cannot decide, you can reject it.",
|
|
112
112
|
"approveAction": "Approve",
|
|
113
113
|
"rejectAction": "Reject",
|
|
114
|
-
"editAction": "
|
|
114
|
+
"editAction": "Replace pending version",
|
|
115
115
|
"confirmReject": "Confirm reject",
|
|
116
|
-
"confirmEdit": "Confirm
|
|
116
|
+
"confirmEdit": "Confirm replacement",
|
|
117
117
|
"cancelAction": "Cancel",
|
|
118
118
|
"rejectReasonLabel": "Reject reason (required)",
|
|
119
119
|
"rejectReasonPlaceholder": "Explain why this is rejected",
|
|
120
|
-
"editReasonLabel": "
|
|
121
|
-
"editReasonPlaceholder": "Explain why
|
|
120
|
+
"editReasonLabel": "Replacement reason (required)",
|
|
121
|
+
"editReasonPlaceholder": "Explain why this pending version needs replacing",
|
|
122
122
|
"editNewArtifactPlaceholder": "Enter validated revision artifact ID",
|
|
123
123
|
"currentArtifactLabel": "Current artifact",
|
|
124
124
|
"approveSucceededCount": "Approved {{count}} principle(s)",
|
|
@@ -150,10 +150,10 @@
|
|
|
150
150
|
"overflowTitle": "{{count}} more warning(s)"
|
|
151
151
|
},
|
|
152
152
|
"rejectSucceeded": "Rejected",
|
|
153
|
-
"editSucceeded": "
|
|
153
|
+
"editSucceeded": "Pending version replaced",
|
|
154
154
|
"approveFailed": "Approval failed, please retry.",
|
|
155
155
|
"rejectFailed": "Rejection failed, please retry.",
|
|
156
|
-
"editFailed": "
|
|
156
|
+
"editFailed": "Replacement failed. Please try again later.",
|
|
157
157
|
"partialFailure": "Action completed, but {{failedCount}}/{{totalCount}} record(s) failed: {{reason}}",
|
|
158
158
|
"unknownFailure": "Check the service logs.",
|
|
159
159
|
"onboardingTitle": "How PD Works",
|
|
@@ -385,7 +385,8 @@
|
|
|
385
385
|
"formationDiagnosisLabel": "Diagnosis",
|
|
386
386
|
"formationRootCauseLabel": "Root cause",
|
|
387
387
|
"formationEvidenceLabel": "Supporting evidence",
|
|
388
|
-
"formationUnavailableNote": "The source diagnosis is currently unreadable; this principle is still decided on the evidence shown."
|
|
388
|
+
"formationUnavailableNote": "The source diagnosis is currently unreadable; this principle is still decided on the evidence shown.",
|
|
389
|
+
"checksDisclosure": "Deterministic checks (technical detail)"
|
|
389
390
|
},
|
|
390
391
|
"revisionReviewUnavailable": "Revision review is incomplete or multiple versions are pending. Check the artifacts and prior version before approval; rejection remains available.",
|
|
391
392
|
"revisionIntentReview": "Review the revised statement against the retained intent, including triggers, required actions, and exceptions.",
|
|
@@ -766,28 +767,28 @@
|
|
|
766
767
|
"approve": "Approve Principle",
|
|
767
768
|
"park": "Park",
|
|
768
769
|
"reject": "Reject",
|
|
769
|
-
"editAction": "
|
|
770
|
+
"editAction": "Replace pending version",
|
|
770
771
|
"confirmApprove": "After approval, the principle will activate via prompt channel. Confirm approval?",
|
|
771
772
|
"confirm": "Confirm",
|
|
772
773
|
"cancel": "Cancel",
|
|
773
774
|
"rejectReasonPlaceholder": "Please explain why you reject (required)",
|
|
774
775
|
"approveNoteLabel": "Approval note (optional)",
|
|
775
776
|
"approveNotePlaceholder": "Why you approve — recorded as the decision note (may be left blank)",
|
|
776
|
-
"editReasonLabel": "
|
|
777
|
-
"editReasonPlaceholder": "Explain why
|
|
777
|
+
"editReasonLabel": "Replacement reason (required)",
|
|
778
|
+
"editReasonPlaceholder": "Explain why this pending version needs replacing",
|
|
778
779
|
"editNewArtifactPlaceholder": "Enter validated revision artifact ID",
|
|
779
780
|
"currentArtifactLabel": "Current artifact",
|
|
780
781
|
"confirmReject": "Confirm Rejection",
|
|
781
|
-
"confirmEdit": "Confirm
|
|
782
|
+
"confirmEdit": "Confirm replacement",
|
|
782
783
|
"approved": "Approved / Will activate via prompt channel",
|
|
783
784
|
"rejected": "Rejected",
|
|
784
|
-
"editSucceeded": "
|
|
785
|
+
"editSucceeded": "Pending version replaced",
|
|
785
786
|
"parked": "Parked",
|
|
786
787
|
"viewActivation": "View activation status",
|
|
787
788
|
"approveFailed": "Approval failed. Please try again later.",
|
|
788
789
|
"partialFailure": "Decision applied, but {{failedCount}}/{{totalCount}} records failed: {{reason}}",
|
|
789
790
|
"rejectFailed": "Rejection failed. Please try again later.",
|
|
790
|
-
"editFailed": "
|
|
791
|
+
"editFailed": "Replacement failed. Please try again later.",
|
|
791
792
|
"unknownFailure": "Check the service logs.",
|
|
792
793
|
"decisionTitle": "Decision Actions",
|
|
793
794
|
"parkUnavailable": "Park is not yet available",
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"tagLowRisk": "低风险",
|
|
96
96
|
"recordCount": "{{count}} 条记录",
|
|
97
97
|
"deviationCount": "条偏差",
|
|
98
|
-
"evidenceSummary": "
|
|
98
|
+
"evidenceSummary": "审批记录:{{count}} 条",
|
|
99
99
|
"untitledCandidate": "待命名候选原则",
|
|
100
100
|
"promptCapacityUnconfirmed": "当前宿主容量未确认:本工作区适用的宿主会走不同的注入路由,以下数字未绑定具体宿主。",
|
|
101
101
|
"promptCapacitySharedRoute": "共享注入(按完整注入块计费)",
|
|
@@ -107,18 +107,18 @@
|
|
|
107
107
|
"promptScopeShared": "预测窗口(共享注入路由,按完整注入块计费,单位=字符)",
|
|
108
108
|
"promptScopeList": "预测窗口(列表注入路由,按选中行计费{{full}},单位=字符)",
|
|
109
109
|
"promptScopeFullRender": ",完整注入块约 {{count}} 字符",
|
|
110
|
-
"artifactUnavailableNote": "
|
|
111
|
-
"unlinkedCandidateNote": "
|
|
110
|
+
"artifactUnavailableNote": "该审批指向的草稿原件已不在工件库中(可能已被新版本取代),内容无法显示。如无法判断,可选择拒绝;原始工件编号可点「替换待审版本」后在「当前工件」一栏查看。",
|
|
111
|
+
"unlinkedCandidateNote": "这张卡片没有可展示的原则名称:无法把它的血缘解析到某条原则,也没能从其存档内容里提取出可读的标题。请依据下方的审批记录判断;如无法判断,可选择拒绝。",
|
|
112
112
|
"approveAction": "批准",
|
|
113
113
|
"rejectAction": "拒绝",
|
|
114
|
-
"editAction": "
|
|
114
|
+
"editAction": "替换待审版本",
|
|
115
115
|
"confirmReject": "确认拒绝",
|
|
116
|
-
"confirmEdit": "
|
|
116
|
+
"confirmEdit": "确认替换",
|
|
117
117
|
"cancelAction": "取消",
|
|
118
118
|
"rejectReasonLabel": "拒绝原因(必填)",
|
|
119
119
|
"rejectReasonPlaceholder": "请说明拒绝原因",
|
|
120
|
-
"editReasonLabel": "
|
|
121
|
-
"editReasonPlaceholder": "
|
|
120
|
+
"editReasonLabel": "替换原因(必填)",
|
|
121
|
+
"editReasonPlaceholder": "请说明为什么需要替换这份待审版本",
|
|
122
122
|
"editNewArtifactPlaceholder": "输入新的已验证工件 ID",
|
|
123
123
|
"currentArtifactLabel": "当前工件",
|
|
124
124
|
"approveSucceededCount": "已批准 {{count}} 条原则",
|
|
@@ -150,10 +150,10 @@
|
|
|
150
150
|
"overflowTitle": "还有 {{count}} 条警告"
|
|
151
151
|
},
|
|
152
152
|
"rejectSucceeded": "已拒绝",
|
|
153
|
-
"editSucceeded": "
|
|
153
|
+
"editSucceeded": "已替换待审版本",
|
|
154
154
|
"approveFailed": "批准失败,请稍后重试。",
|
|
155
155
|
"rejectFailed": "拒绝失败,请稍后重试。",
|
|
156
|
-
"editFailed": "
|
|
156
|
+
"editFailed": "替换失败,请稍后重试。",
|
|
157
157
|
"partialFailure": "操作完成,但 {{failedCount}}/{{totalCount}} 条记录失败:{{reason}}",
|
|
158
158
|
"unknownFailure": "请检查服务日志。",
|
|
159
159
|
"onboardingTitle": "PD 的工作方式",
|
|
@@ -385,7 +385,8 @@
|
|
|
385
385
|
"formationDiagnosisLabel": "诊断",
|
|
386
386
|
"formationRootCauseLabel": "根因",
|
|
387
387
|
"formationEvidenceLabel": "支撑证据",
|
|
388
|
-
"formationUnavailableNote": "来源诊断当前不可读;这条原则仍按现有证据供你裁决。"
|
|
388
|
+
"formationUnavailableNote": "来源诊断当前不可读;这条原则仍按现有证据供你裁决。",
|
|
389
|
+
"checksDisclosure": "确定性检查(技术详情)"
|
|
389
390
|
},
|
|
390
391
|
"revisionReviewUnavailable": "修订对照信息不完整或同时存在多个待审版本,请先核对工件与旧版本;仍可拒绝本次修订。",
|
|
391
392
|
"revisionIntentReview": "修订复核:确认新正文保留触发条件、行动要求和必要例外,并与沿用意图一致。",
|
|
@@ -766,28 +767,28 @@
|
|
|
766
767
|
"approve": "批准原则",
|
|
767
768
|
"park": "暂存",
|
|
768
769
|
"reject": "拒绝",
|
|
769
|
-
"editAction": "
|
|
770
|
+
"editAction": "替换待审版本",
|
|
770
771
|
"confirmApprove": "批准后原则将通过提示词通道激活。确认批准?",
|
|
771
772
|
"confirm": "确认",
|
|
772
773
|
"cancel": "取消",
|
|
773
774
|
"rejectReasonPlaceholder": "请说明拒绝原因(必填)",
|
|
774
775
|
"approveNoteLabel": "批准备注(可选)",
|
|
775
776
|
"approveNotePlaceholder": "写下批准的理由,将作为裁决记录保存(可留空)",
|
|
776
|
-
"editReasonLabel": "
|
|
777
|
-
"editReasonPlaceholder": "
|
|
777
|
+
"editReasonLabel": "替换原因(必填)",
|
|
778
|
+
"editReasonPlaceholder": "请说明为什么需要替换这份待审版本",
|
|
778
779
|
"editNewArtifactPlaceholder": "输入新的已验证工件 ID",
|
|
779
780
|
"currentArtifactLabel": "当前工件",
|
|
780
781
|
"confirmReject": "确认拒绝",
|
|
781
|
-
"confirmEdit": "
|
|
782
|
+
"confirmEdit": "确认替换",
|
|
782
783
|
"approved": "已批准 / 将通过提示词通道激活",
|
|
783
784
|
"rejected": "已拒绝",
|
|
784
|
-
"editSucceeded": "
|
|
785
|
+
"editSucceeded": "已替换待审版本",
|
|
785
786
|
"parked": "已暂存",
|
|
786
787
|
"viewActivation": "查看生效情况",
|
|
787
788
|
"approveFailed": "批准失败,请稍后重试。",
|
|
788
789
|
"partialFailure": "决策已执行,但 {{failedCount}}/{{totalCount}} 条记录失败:{{reason}}",
|
|
789
790
|
"rejectFailed": "拒绝失败,请稍后重试。",
|
|
790
|
-
"editFailed": "
|
|
791
|
+
"editFailed": "替换失败,请稍后重试。",
|
|
791
792
|
"unknownFailure": "请检查服务日志。",
|
|
792
793
|
"decisionTitle": "决策操作",
|
|
793
794
|
"parkUnavailable": "暂存尚未可用",
|
|
@@ -10,6 +10,7 @@ import { DailyThoughtCard } from "../../components/focus/daily-thought-card.js";
|
|
|
10
10
|
import { ShinyText } from "../../components/ui/shiny-text.js";
|
|
11
11
|
import { fetchGovernanceQueue, fetchApprovalsGrouped, approveApproval, rejectApproval, editApproval, fetchAllActivations, fetchOwnerDecisions, } from "../../api.js";
|
|
12
12
|
import { selectApprovalGroupDisplayTitle, showsUnlinkedCandidateNote, validateApprovalsGroupedData } from "./focus-validation.js";
|
|
13
|
+
import { splitReadingTitleBody } from "../../utils/reading-layout.js";
|
|
13
14
|
import { OwnerDecisionCard } from "./OwnerDecisionCard.js";
|
|
14
15
|
import { localizeApprovalWarning, splitApprovalWarnings } from "../../utils/approval-warning-localization.js";
|
|
15
16
|
/** PRI-908: how long the decided card stays visible before the pending list refresh removes it. */
|
|
@@ -273,6 +274,9 @@ function PendingReviewCard({ group, actionsLockedReason, onDecisionApplied, prom
|
|
|
273
274
|
const displayTitle = selectApprovalGroupDisplayTitle(group)
|
|
274
275
|
?? t("pages.focus.untitledCandidate", { defaultValue: "待命名候选原则" });
|
|
275
276
|
const unlinkedCandidateNote = showsUnlinkedCandidateNote(group);
|
|
277
|
+
// SPEC-PD-CONSOLE-READABILITY-002 切片1(R2/R3/R7):候选描述可能是整段规则
|
|
278
|
+
// 正文——不再整段充当加粗标题。短标题只作预览,逐字全文由正文块承载。
|
|
279
|
+
const readingLayout = splitReadingTitleBody(displayTitle);
|
|
276
280
|
async function applyDecisionToAllRecords(action, reason) {
|
|
277
281
|
// Only process pending records — skip already-approved/rejected to avoid
|
|
278
282
|
// stable partial failures on mixed-status groups.
|
|
@@ -371,7 +375,7 @@ function PendingReviewCard({ group, actionsLockedReason, onDecisionApplied, prom
|
|
|
371
375
|
const { allSucceeded, failedCount, failureReason } = summarizeDecisionResults(results);
|
|
372
376
|
const totalCount = results.length;
|
|
373
377
|
if (allSucceeded) {
|
|
374
|
-
toast.success(t("pages.focus.editSucceeded", { defaultValue: "
|
|
378
|
+
toast.success(t("pages.focus.editSucceeded", { defaultValue: "已替换待审版本" }));
|
|
375
379
|
setShowEditInput(false);
|
|
376
380
|
setEditReason("");
|
|
377
381
|
setNewArtifactId("");
|
|
@@ -379,7 +383,7 @@ function PendingReviewCard({ group, actionsLockedReason, onDecisionApplied, prom
|
|
|
379
383
|
}
|
|
380
384
|
else {
|
|
381
385
|
toast.error(t("pages.focus.partialFailure", {
|
|
382
|
-
defaultValue:
|
|
386
|
+
defaultValue: `替换完成,但 ${failedCount}/${totalCount} 条记录失败。`,
|
|
383
387
|
failedCount,
|
|
384
388
|
totalCount,
|
|
385
389
|
reason: failureReason ?? t("pages.focus.unknownFailure", { defaultValue: "请检查服务日志。" }),
|
|
@@ -388,7 +392,7 @@ function PendingReviewCard({ group, actionsLockedReason, onDecisionApplied, prom
|
|
|
388
392
|
}
|
|
389
393
|
}
|
|
390
394
|
catch {
|
|
391
|
-
toast.error(t("pages.focus.editFailed", { defaultValue: "
|
|
395
|
+
toast.error(t("pages.focus.editFailed", { defaultValue: "替换失败,请稍后重试。" }));
|
|
392
396
|
}
|
|
393
397
|
finally {
|
|
394
398
|
setActionLoading(false);
|
|
@@ -398,7 +402,7 @@ function PendingReviewCard({ group, actionsLockedReason, onDecisionApplied, prom
|
|
|
398
402
|
? "border-green/40 bg-green/10 text-green"
|
|
399
403
|
: "border-line bg-surface/80 text-ink-3"}`, role: "status", "data-testid": `decided-banner-${group.principleId}`, children: decidedOutcome === "approved"
|
|
400
404
|
? t("pages.focus.decidedApproved", { defaultValue: "已批准 ✓ 正在写入生效记录…" })
|
|
401
|
-
: t("pages.focus.decidedRejected", { defaultValue: "已拒绝" }) })), _jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx("span", { className: "inline-flex items-center border border-line rounded-[2px] px-[7px] py-1 font-mono text-[11px] text-ink-3 bg-surface/80 uppercase", children: channelLabel }), isReversible && (_jsx("span", { className: "inline-flex items-center border border-amber/35 text-amber rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase", children: primaryChannel === "prompt" ? t("pages.focus.tagReversible") : t("pages.focus.tagLowRisk") }))] }), _jsx("div", { className: "mt-[14px] mb-2 font-semibold text-ink leading-snug", children:
|
|
405
|
+
: t("pages.focus.decidedRejected", { defaultValue: "已拒绝" }) })), _jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx("span", { className: "inline-flex items-center border border-line rounded-[2px] px-[7px] py-1 font-mono text-[11px] text-ink-3 bg-surface/80 uppercase", children: channelLabel }), isReversible && (_jsx("span", { className: "inline-flex items-center border border-amber/35 text-amber rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase", children: primaryChannel === "prompt" ? t("pages.focus.tagReversible") : t("pages.focus.tagLowRisk") }))] }), _jsx("div", { className: "mt-[14px] mb-2 font-semibold text-ink leading-snug", "data-testid": `candidate-title-${group.principleId}`, children: readingLayout.title }), readingLayout.body !== null && (_jsx("div", { className: "mb-2 text-[15px] leading-relaxed text-ink whitespace-pre-wrap break-words", "data-testid": `candidate-body-${group.principleId}`, children: readingLayout.body })), group.artifactUnavailable === true && (_jsx("div", { className: "mb-2 text-[12.5px] leading-relaxed text-amber", "data-testid": `artifact-unavailable-${group.principleId}`, children: t("pages.focus.artifactUnavailableNote") })), unlinkedCandidateNote && (_jsx("div", { className: "mb-2 text-[12.5px] leading-relaxed text-amber", "data-testid": `unlinked-candidate-${group.principleId}`, children: t("pages.focus.unlinkedCandidateNote") })), _jsx("div", { className: "mt-2 px-3 py-2 bg-surface/60 border-l-2 border-gov text-ink-3 text-[13px] leading-snug", children: t("pages.focus.evidenceSummary", { count: group.records.length }) }), actionsLocked && (_jsxs("div", { className: "mt-3 rounded-[3px] border border-amber/40 bg-amber/5 p-3", "data-testid": `pending-actions-locked-${group.principleId}`, children: [_jsx("p", { className: "text-ink-2 text-[12.5px] leading-relaxed", children: actionsLockedReason }), _jsx(Link, { to: "/settings", "data-testid": `pending-actions-locked-settings-${group.principleId}`, 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") })] })), decidedOutcome === null && primaryChannel === "prompt" && promptInjection?.truncated === true && (_jsxs("div", { className: "mt-3 rounded-[3px] border border-amber/40 bg-amber/5 px-3 py-2 text-[12.5px] text-amber", "data-testid": `approve-queue-badge-${group.principleId}`, children: [promptInjection.productionRotates === true && group.fitsPromptBudget === true
|
|
402
406
|
? t("pages.focus.approveQueueBadgeRotation", {
|
|
403
407
|
defaultValue: "批准后可能排队:提示词注入位已满({{used}}/{{budget}} 字符)。当前按公平轮转选取,新原则会在后续轮次自行轮到,无需停用旧原则。",
|
|
404
408
|
used: promptInjection.usedChars,
|
|
@@ -420,7 +424,7 @@ function PendingReviewCard({ group, actionsLockedReason, onDecisionApplied, prom
|
|
|
420
424
|
full: promptInjection.fullRenderChars !== undefined
|
|
421
425
|
? t("pages.focus.promptScopeFullRender", { count: promptInjection.fullRenderChars })
|
|
422
426
|
: "",
|
|
423
|
-
}), promptInjection.hostKind !== undefined ? ` · ${promptInjection.hostKind === "openclaw" ? "OpenClaw" : promptInjection.hostKind === "workbuddy" ? "WorkBuddy" : "Codex"}` : ""] })] })), group.revisionReviewUnavailable === true && _jsx("p", { role: "alert", className: "mt-3 text-danger", children: t("pages.focus.revisionReviewUnavailable") }), group.revisionReview !== undefined && (_jsxs("div", { className: "mt-3 border border-line p-3 text-[12.5px]", "data-testid": `revision-intent-review-${group.principleId}`, children: [_jsx("p", { children: t("pages.focus.revisionIntentReview", { defaultValue: "修订复核:确认新正文保留触发条件、行动要求和必要例外,并与沿用意图一致。" }) }), _jsx("pre", { className: "mt-2 max-h-32 overflow-auto whitespace-pre-wrap", children: group.revisionReview.oldStatement }), _jsx("pre", { className: "mt-2 max-h-32 overflow-auto whitespace-pre-wrap", children: group.revisionReview.newStatement }), _jsx("dl", { className: "mt-2", children: Object.entries(group.revisionReview.intentFields).map(([key, value]) => _jsxs("div", { children: [_jsx("dt", { children: t(`pages.focus.intentField.${key}`, { defaultValue: key }) }), _jsx("dd", { children: value })] }, key)) }), _jsxs("label", { className: "mt-2 flex gap-2", children: [_jsx("input", { type: "checkbox", checked: intentReviewed, onChange: (event) => setIntentReviewed(event.target.checked) }), t("pages.focus.revisionIntentConfirmed", { defaultValue: "我已核对上述意图与新正文一致" })] })] })), _jsxs("div", { className: "flex gap-2 mt-4 flex-wrap items-center", children: [_jsx("button", { type: "button", onClick: handleApprove, disabled: decisionDisabled || (group.revisionReviewUnavailable === true || (group.revisionReview !== undefined && !intentReviewed)), "data-testid": `approve-btn-${group.principleId}`, className: "inline-flex items-center border border-gov bg-gov text-paper rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:bg-gov-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: actionLoading ? t("common.loading") + "…" : t("pages.focus.approveAction", { defaultValue: "批准" }) }), _jsx("button", { type: "button", onClick: () => { setShowEditInput((v) => !v); setShowRejectInput(false); }, disabled: decisionDisabled, "data-testid": `edit-btn-${group.principleId}`, className: "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 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.focus.editAction", { defaultValue: "
|
|
427
|
+
}), promptInjection.hostKind !== undefined ? ` · ${promptInjection.hostKind === "openclaw" ? "OpenClaw" : promptInjection.hostKind === "workbuddy" ? "WorkBuddy" : "Codex"}` : ""] })] })), group.revisionReviewUnavailable === true && _jsx("p", { role: "alert", className: "mt-3 text-danger", children: t("pages.focus.revisionReviewUnavailable") }), group.revisionReview !== undefined && (_jsxs("div", { className: "mt-3 border border-line p-3 text-[12.5px]", "data-testid": `revision-intent-review-${group.principleId}`, children: [_jsx("p", { children: t("pages.focus.revisionIntentReview", { defaultValue: "修订复核:确认新正文保留触发条件、行动要求和必要例外,并与沿用意图一致。" }) }), _jsx("pre", { className: "mt-2 max-h-32 overflow-auto whitespace-pre-wrap", children: group.revisionReview.oldStatement }), _jsx("pre", { className: "mt-2 max-h-32 overflow-auto whitespace-pre-wrap", children: group.revisionReview.newStatement }), _jsx("dl", { className: "mt-2", children: Object.entries(group.revisionReview.intentFields).map(([key, value]) => _jsxs("div", { children: [_jsx("dt", { children: t(`pages.focus.intentField.${key}`, { defaultValue: key }) }), _jsx("dd", { children: value })] }, key)) }), _jsxs("label", { className: "mt-2 flex gap-2", children: [_jsx("input", { type: "checkbox", checked: intentReviewed, onChange: (event) => setIntentReviewed(event.target.checked) }), t("pages.focus.revisionIntentConfirmed", { defaultValue: "我已核对上述意图与新正文一致" })] })] })), _jsxs("div", { className: "flex gap-2 mt-4 flex-wrap items-center", children: [_jsx("button", { type: "button", onClick: handleApprove, disabled: decisionDisabled || (group.revisionReviewUnavailable === true || (group.revisionReview !== undefined && !intentReviewed)), "data-testid": `approve-btn-${group.principleId}`, className: "inline-flex items-center border border-gov bg-gov text-paper rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:bg-gov-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: actionLoading ? t("common.loading") + "…" : t("pages.focus.approveAction", { defaultValue: "批准" }) }), _jsx("button", { type: "button", onClick: () => { setShowEditInput((v) => !v); setShowRejectInput(false); }, disabled: decisionDisabled, "data-testid": `edit-btn-${group.principleId}`, className: "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 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.focus.editAction", { defaultValue: "替换待审版本" }) }), _jsx("button", { type: "button", onClick: () => { setShowRejectInput((v) => !v); setShowEditInput(false); }, disabled: decisionDisabled, "data-testid": `reject-btn-${group.principleId}`, className: "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 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.focus.rejectAction", { defaultValue: "拒绝" }) }), _jsx(Link, { to: "/pain", className: "inline-flex items-center text-gov text-[12.5px] hover:underline focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.focus.viewFullChain") })] }), showRejectInput && (_jsxs("div", { className: "mt-3 p-3 border border-danger/20 rounded-[var(--radius-md)]", children: [_jsx("label", { className: "block font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3 mb-2", children: t("pages.focus.rejectReasonLabel", { defaultValue: "拒绝原因(必填)" }) }), _jsx("textarea", { value: rejectReason, onChange: (e) => setRejectReason(e.target.value), "data-testid": `reject-reason-${group.principleId}`, placeholder: t("pages.focus.rejectReasonPlaceholder", { defaultValue: "请说明拒绝原因" }), className: "w-full border border-line rounded-[var(--radius-md)] bg-surface text-ink px-3 py-2 text-[13px] min-h-[80px] resize-y focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov" }), _jsxs("div", { className: "flex gap-2 mt-2", children: [_jsx("button", { type: "button", onClick: handleReject, disabled: !rejectReason.trim() || actionLoading, "data-testid": `confirm-reject-${group.principleId}`, 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: t("pages.focus.confirmReject", { defaultValue: "确认拒绝" }) }), _jsx("button", { type: "button", onClick: () => { setShowRejectInput(false); setRejectReason(""); }, className: "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", children: t("pages.focus.cancelAction", { defaultValue: "取消" }) })] })] })), showEditInput && (_jsxs("div", { className: "mt-3 p-3 border border-gov/20 rounded-[var(--radius-md)]", children: [_jsx("label", { className: "block font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3 mb-2", children: t("pages.focus.editReasonLabel", { defaultValue: "替换原因(必填)" }) }), _jsxs("div", { className: "mb-2 text-ink-4 text-[12px] font-mono", children: [t("pages.focus.currentArtifactLabel", { defaultValue: "当前工件" }), ": ", currentArtifactId] }), _jsx("input", { type: "text", value: newArtifactId, onChange: (e) => setNewArtifactId(e.target.value), "data-testid": `edit-new-artifact-${group.principleId}`, placeholder: t("pages.focus.editNewArtifactPlaceholder", { defaultValue: "输入新的已验证工件 ID" }), className: "w-full border border-line rounded-[var(--radius-md)] bg-surface text-ink px-3 py-2 text-[13px] mb-2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov", "aria-label": t("pages.focus.editNewArtifactPlaceholder", { defaultValue: "输入新的已验证工件 ID" }) }), _jsx("textarea", { value: editReason, onChange: (e) => setEditReason(e.target.value), "data-testid": `edit-reason-${group.principleId}`, placeholder: t("pages.focus.editReasonPlaceholder", { defaultValue: "请说明为什么需要替换这份待审版本" }), className: "w-full border border-line rounded-[var(--radius-md)] bg-surface text-ink px-3 py-2 text-[13px] min-h-[80px] resize-y focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov" }), _jsxs("div", { className: "flex gap-2 mt-2", children: [_jsx("button", { type: "button", onClick: handleEdit, disabled: !editReason.trim() || !newArtifactId.trim() || actionLoading, "data-testid": `confirm-edit-${group.principleId}`, 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: t("pages.focus.confirmEdit", { defaultValue: "确认替换" }) }), _jsx("button", { type: "button", onClick: () => { setShowEditInput(false); setEditReason(""); setNewArtifactId(""); }, className: "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", children: t("pages.focus.cancelAction", { defaultValue: "取消" }) })] })] }))] }));
|
|
424
428
|
}
|
|
425
429
|
function StagnationSignalCard({ signal }) {
|
|
426
430
|
const { t } = useTranslation();
|
|
@@ -95,7 +95,7 @@ export function OwnerDecisionCard({ item, onResolved, governanceReady = true, ac
|
|
|
95
95
|
: item.kind === "rulecode_decision"
|
|
96
96
|
? t("pages.focus.ownerDecision.kindRulecode")
|
|
97
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 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}`) }), 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: () => {
|
|
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
99
|
if (!showInstruction) {
|
|
100
100
|
setShowInstruction(true);
|
|
101
101
|
return;
|
|
@@ -12,6 +12,7 @@ import { ReceiptCoverageDisclosure, getReceiptSourceStatusLabelKey } from "../..
|
|
|
12
12
|
import { formatDate } from "../../utils/format-date.js";
|
|
13
13
|
import { localizeAggregatedBlocker } from "../../utils/blocker-localization.js";
|
|
14
14
|
import { groupByReasonCode, formatGroupedReasonLine } from "../../utils/attention-presentation.js";
|
|
15
|
+
import { splitReadingTitleBody } from "../../utils/reading-layout.js";
|
|
15
16
|
// ── Runtime validation (H section) ──────────────────────────────────────────
|
|
16
17
|
function isString(v) {
|
|
17
18
|
return typeof v === "string";
|
|
@@ -459,16 +460,21 @@ export function PrincipleDetailPage() {
|
|
|
459
460
|
const receiptPresentation = receipts?.status === 'ok'
|
|
460
461
|
? getReceiptPresentation(receipts.effectCount, receipts.presenceCount)
|
|
461
462
|
: null;
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
463
|
+
// 切片1(R2/R3/R7):标题/正文分层——h1 只承载短标题预览;known 路径的逐字
|
|
464
|
+
// 全文在下方 learned 块渲染(一次),unknown 路径在此处正文块渲染(一次)。
|
|
465
|
+
const learnedText = ownerDecision?.learnedPrinciple.status === 'known'
|
|
466
|
+
? ownerDecision.learnedPrinciple.value.text
|
|
467
|
+
: undefined;
|
|
468
|
+
const learnedKnown = learnedText !== undefined;
|
|
469
|
+
const headlineLayout = splitReadingTitleBody(learnedText ?? principle.text);
|
|
470
|
+
return (_jsx(PageShell, { children: _jsxs("div", { className: "animate-[pdFadeIn_400ms_ease-out]", children: [_jsxs(Button, { variant: "ghost", onClick: () => navigate("/principles"), className: "mb-4 -ml-2", children: ["\u2190 ", t("principles.detail.backToList")] }), _jsxs("section", { className: "mb-8", children: [_jsx(SectionTitle, { children: t("principles.detail.conclusion") }), _jsx("h1", { className: "text-[22px] font-semibold text-ink leading-snug mb-3", "data-testid": "principle-detail-title", children: headlineLayout.title }), headlineLayout.body !== null && !learnedKnown && (_jsx("div", { className: "mb-3 text-[15px] leading-relaxed text-ink whitespace-pre-wrap break-words", "data-testid": "principle-detail-body", children: headlineLayout.body })), ownerDecision !== null && ownerDecision.learnedPrinciple.status !== 'known' && (_jsx("p", { className: "text-amber text-[13px] leading-relaxed mb-3", "data-testid": "owner-decision-technical-note", children: t("principles.detail.ownerDecision.technicalOriginalNote", {
|
|
465
471
|
defaultValue: "以上为原始技术建议文本;可读的行为准则暂缺(保留原文以保证可追溯)。",
|
|
466
472
|
}) })), _jsx("p", { className: "text-ink-3 text-[14px] leading-relaxed mb-3", children: t("principles.detail.policyNote") }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Button, { variant: "outline", size: "sm", disabled: true, children: t("principles.detail.modifyWording") }), _jsx("span", { className: "text-ink-4 text-[13px]", children: t("principles.detail.modifyWordingNote") }), _jsx(Button, { variant: "ghost", size: "sm", className: "ml-auto", "data-testid": "principle-feedback", onClick: () => {
|
|
467
473
|
const params = new URLSearchParams({ source: "principle_page", principleId: id ?? "" });
|
|
468
474
|
navigate(`/report-problem?${params.toString()}`);
|
|
469
475
|
}, children: t("reportProblem.entryFeedback") })] })] }), ownerDecision !== null && (_jsxs("section", { className: "mb-8", "aria-labelledby": "owner-decision-title", "data-testid": "owner-decision-view", children: [_jsx(SectionTitle, { children: t("principles.detail.ownerDecision.title", { defaultValue: "这条原则的决策视图" }) }), _jsxs("div", { className: "rounded-[var(--radius-md)] border border-gov/25 bg-gov/5 p-4", children: [_jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between", children: [_jsxs("div", { children: [_jsx("h2", { id: "owner-decision-title", className: "text-[18px] font-semibold text-ink", children: t(DECISION_STATE_LABEL_KEY[ownerDecision.decisionState]) }), _jsx("p", { className: "mt-1 text-[13px] leading-relaxed text-ink-2", children: localizeNextAction(ownerDecision.nextAction.code, ownerDecision.nextAction.ownerText, t) })] }), _jsx("span", { "data-testid": "owner-decision-state", className: "w-fit rounded-full border border-line px-2 py-1 font-mono text-[11px] text-ink-3", children: ownerDecision.sourceReadStatus === 'complete'
|
|
470
476
|
? t("principles.detail.ownerDecision.readsComplete", { defaultValue: "本次所需数据已读取" })
|
|
471
|
-
: t("principles.detail.ownerDecision.readsPartial", { defaultValue: "部分数据源读取失败" }) })] }), _jsx(OwnerNarrativeBlock, { testId: "owner-decision-incident", label: t("principles.detail.ownerDecision.incident", { defaultValue: "发生了什么" }), field: ownerDecision.incidentSummary }), _jsxs("div", { className: "mt-4", "data-testid": "owner-decision-learned", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.learned", { defaultValue: "Agent 学到的行为准则" }) }), ownerDecision.learnedPrinciple.status === 'known' ? (_jsxs(_Fragment, { children: [_jsx("p", { className: "mt-1 text-ink-2 text-[
|
|
477
|
+
: t("principles.detail.ownerDecision.readsPartial", { defaultValue: "部分数据源读取失败" }) })] }), _jsx(OwnerNarrativeBlock, { testId: "owner-decision-incident", label: t("principles.detail.ownerDecision.incident", { defaultValue: "发生了什么" }), field: ownerDecision.incidentSummary }), _jsxs("div", { className: "mt-4", "data-testid": "owner-decision-learned", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.learned", { defaultValue: "Agent 学到的行为准则" }) }), ownerDecision.learnedPrinciple.status === 'known' ? (_jsxs(_Fragment, { children: [_jsx("p", { className: "mt-1 text-ink-2 text-[15px] leading-relaxed whitespace-pre-wrap break-words", children: learnedText }), _jsx("p", { className: "mt-1 text-ink-4 text-[12px]", children: t("principles.detail.ownerDecision.sourceTierLabel", {
|
|
472
478
|
defaultValue: "来源:{{tier}}(未经改写)",
|
|
473
479
|
tier: t(`principles.detail.ownerDecision.tier.${ownerDecision.learnedPrinciple.value.sourceTier}`, { defaultValue: ownerDecision.learnedPrinciple.value.sourceTier }),
|
|
474
480
|
}) })] })) : (_jsx("p", { className: "mt-1 text-amber text-[13px] leading-relaxed", children: ownerDecision.learnedPrinciple.reason.ownerText }))] }), _jsx(OwnerNarrativeBlock, { testId: "owner-decision-rationale", label: t("principles.detail.ownerDecision.rationale", { defaultValue: "为什么这么判断" }), field: ownerDecision.rationale }), _jsx(OwnerNarrativeBlock, { testId: "owner-decision-applicability", label: t("principles.detail.ownerDecision.applicability", { defaultValue: "什么时候适用" }), field: ownerDecision.applicability }), _jsx(OwnerNarrativeBlock, { testId: "owner-decision-expected", label: t("principles.detail.ownerDecision.expected", { defaultValue: "批准后会怎样(拟议行为,未部署)" }), field: ownerDecision.expectedBehavior }), ownerDecision.currentEnforcement.status === 'known' && (_jsxs("div", { className: "mt-4", "data-testid": "owner-decision-enforcement", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.enforcementLabel", { defaultValue: "当前实际执行" }) }), _jsx("p", { className: "mt-1 text-ink-2 text-[14px] leading-relaxed", children: ownerDecision.currentEnforcement.value?.state === 'active'
|