create-principles-disciple 1.109.0 → 1.111.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/console/dist/server/config/pd-config-store.d.ts +29 -0
  2. package/console/dist/server/config/pd-config-store.js +55 -0
  3. package/console/dist/server/feedback/channels.d.ts +36 -0
  4. package/console/dist/server/feedback/channels.js +89 -0
  5. package/console/dist/server/feedback/github-adapter.d.ts +44 -0
  6. package/console/dist/server/feedback/github-adapter.js +125 -0
  7. package/console/dist/server/feedback/ingest-adapter.d.ts +45 -0
  8. package/console/dist/server/feedback/ingest-adapter.js +129 -0
  9. package/console/dist/server/feedback/submit-service.d.ts +44 -0
  10. package/console/dist/server/feedback/submit-service.js +177 -0
  11. package/console/dist/server/index.js +23 -7
  12. package/console/dist/server/models/FeedbackReportConsoleModel.d.ts +8 -0
  13. package/console/dist/server/models/FeedbackReportConsoleModel.js +45 -0
  14. package/console/dist/server/routes/feedback-reports.d.ts +24 -0
  15. package/console/dist/server/routes/feedback-reports.js +151 -0
  16. package/console/dist/ui/api.d.ts +11 -3
  17. package/console/dist/ui/api.js +25 -2
  18. package/console/dist/ui/i18n/en.json +48 -2
  19. package/console/dist/ui/i18n/zh-CN.json +48 -2
  20. package/console/dist/ui/pages/ReportProblemValidators.d.ts +30 -0
  21. package/console/dist/ui/pages/ReportProblemValidators.js +66 -0
  22. package/console/dist/ui/pages/activation/ActivationPage.js +14 -3
  23. package/console/dist/ui/pages/pain/PainPage.js +6 -1
  24. package/console/dist/ui/pages/principles/PrincipleDetailPage.js +4 -1
  25. package/console/dist/ui/pages/report-problem/ReportProblemPage.js +263 -70
  26. package/console/dist/ui/utils/validators.d.ts +22 -0
  27. package/console/dist/ui/utils/validators.js +66 -0
  28. package/console/dist/web/assets/app.css +42 -0
  29. package/console/dist/web/assets/app.js +699 -127
  30. package/console/package.json +4 -4
  31. package/core/dist/runtime-v2/__tests__/architecture-regression.test.js +4 -0
  32. package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
  33. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js +1 -1
  34. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
  35. package/core/dist/runtime-v2/feedback/__tests__/fingerprint.test.d.ts +2 -0
  36. package/core/dist/runtime-v2/feedback/__tests__/fingerprint.test.d.ts.map +1 -0
  37. package/core/dist/runtime-v2/feedback/__tests__/fingerprint.test.js +126 -0
  38. package/core/dist/runtime-v2/feedback/__tests__/fingerprint.test.js.map +1 -0
  39. package/core/dist/runtime-v2/feedback/__tests__/slice1-typed-fields.test.d.ts +2 -0
  40. package/core/dist/runtime-v2/feedback/__tests__/slice1-typed-fields.test.d.ts.map +1 -0
  41. package/core/dist/runtime-v2/feedback/__tests__/slice1-typed-fields.test.js +278 -0
  42. package/core/dist/runtime-v2/feedback/__tests__/slice1-typed-fields.test.js.map +1 -0
  43. package/core/dist/runtime-v2/feedback/create-report.d.ts.map +1 -1
  44. package/core/dist/runtime-v2/feedback/create-report.js +38 -1
  45. package/core/dist/runtime-v2/feedback/create-report.js.map +1 -1
  46. package/core/dist/runtime-v2/feedback/feedback-types.d.ts +60 -0
  47. package/core/dist/runtime-v2/feedback/feedback-types.d.ts.map +1 -1
  48. package/core/dist/runtime-v2/feedback/feedback-types.js +58 -0
  49. package/core/dist/runtime-v2/feedback/feedback-types.js.map +1 -1
  50. package/core/dist/runtime-v2/feedback/fingerprint.d.ts +31 -0
  51. package/core/dist/runtime-v2/feedback/fingerprint.d.ts.map +1 -0
  52. package/core/dist/runtime-v2/feedback/fingerprint.js +51 -0
  53. package/core/dist/runtime-v2/feedback/fingerprint.js.map +1 -0
  54. package/core/dist/runtime-v2/feedback/index.d.ts +3 -2
  55. package/core/dist/runtime-v2/feedback/index.d.ts.map +1 -1
  56. package/core/dist/runtime-v2/feedback/index.js +2 -1
  57. package/core/dist/runtime-v2/feedback/index.js.map +1 -1
  58. package/core/dist/runtime-v2/feedback/privacy-preview.d.ts.map +1 -1
  59. package/core/dist/runtime-v2/feedback/privacy-preview.js +43 -0
  60. package/core/dist/runtime-v2/feedback/privacy-preview.js.map +1 -1
  61. package/core/dist/runtime-v2/feedback/render-markdown.d.ts.map +1 -1
  62. package/core/dist/runtime-v2/feedback/render-markdown.js +33 -0
  63. package/core/dist/runtime-v2/feedback/render-markdown.js.map +1 -1
  64. package/core/dist/runtime-v2/index.d.ts +2 -2
  65. package/core/dist/runtime-v2/index.d.ts.map +1 -1
  66. package/core/dist/runtime-v2/index.js +1 -1
  67. package/core/dist/runtime-v2/index.js.map +1 -1
  68. package/dist/installer.d.ts.map +1 -1
  69. package/dist/installer.js.map +1 -1
  70. package/dist/mvp-config.d.ts +22 -1
  71. package/dist/mvp-config.d.ts.map +1 -1
  72. package/dist/mvp-config.js +36 -1
  73. package/dist/mvp-config.js.map +1 -1
  74. package/package.json +1 -1
  75. package/plugin/dist/bundle.js +302 -302
  76. package/plugin/dist/openclaw.plugin.json +1 -18
  77. package/plugin/openclaw.plugin.json +2 -19
  78. package/plugin/package.json +3 -3
  79. package/plugin/scripts/sync-plugin.mjs +34 -33
@@ -525,6 +525,7 @@
525
525
  "loadError": "Unable to load feedback data. You can try refreshing the page.",
526
526
  "description": "Generate a privacy-preserving local feedback draft. The Console never auto-uploads — you choose what to share, how to share it, and when.",
527
527
  "deepLinked": "Deep-linked from {{source}}.",
528
+ "entryFeedback": "Feedback",
528
529
  "form": {
529
530
  "title": "Describe what happened",
530
531
  "description": "Only fields below are stored. Raw prompts, chat history, file contents, paths, env vars, and tokens are excluded by default.",
@@ -534,6 +535,25 @@
534
535
  "severityLow": "Low",
535
536
  "severityMedium": "Medium",
536
537
  "severityHigh": "High",
538
+ "blockingLevelLabel": "How much does it block you",
539
+ "blockingLevelNotSet": "Not set",
540
+ "blockingLevelBlocked": "Blocked me",
541
+ "blockingLevelWorkaround": "Workaround possible",
542
+ "blockingLevelMinor": "Doesn't affect me",
543
+ "frequencyLabel": "How often does it occur",
544
+ "frequencyNotSet": "Not set",
545
+ "frequencyAlways": "Every time",
546
+ "frequencyOften": "Often",
547
+ "frequencySometimes": "Sometimes",
548
+ "frequencyOnce": "Once",
549
+ "goalLabel": "What were you trying to do",
550
+ "stuckAtLabel": "Where did you get stuck",
551
+ "jobLabel": "What goal are you trying to achieve",
552
+ "currentWorkaroundLabel": "How do you work around it now",
553
+ "sawWhatLabel": "What did you see that worried you",
554
+ "whereSeenLabel": "Where did you see it",
555
+ "detailsToggle": "Additional details",
556
+ "detailsHide": "Collapse details",
537
557
  "titleLabel": "Title",
538
558
  "descriptionLabel": "Description",
539
559
  "stepsLabel": "Steps to reproduce (optional)",
@@ -567,7 +587,29 @@
567
587
  "copyEmail": "Copy email text",
568
588
  "openGithub": "Open GitHub issue URL",
569
589
  "openEmail": "Open Email",
570
- "delete": "Delete draft"
590
+ "delete": "Delete draft",
591
+ "sentBadge": "Sent",
592
+ "draftBadge": "Pending",
593
+ "markAsSent": "Mark as sent"
594
+ },
595
+ "channel": {
596
+ "title": "Send feedback",
597
+ "description": "This feedback is redacted and contains only what you filled in above. The Console never auto-uploads — clicking a button is your explicit submission.",
598
+ "ingest": "Submit in one click (recommended)",
599
+ "github": "Submit as a GitHub issue",
600
+ "email": "Open email",
601
+ "file": "Export file",
602
+ "disablingReason": "Unavailable: {{reason}}",
603
+ "confirmTitle": "Confirm sending feedback",
604
+ "confirmDescription": "After submitting, this redacted feedback will be sent to the maintainer feedback service. You cannot undo it, but you can delete the local draft afterwards.",
605
+ "confirmBodyLabel": "Content to send",
606
+ "confirmSubmit": "Confirm send",
607
+ "confirmCancel": "Cancel",
608
+ "receiptTitle": "Submitted",
609
+ "receiptTrackingId": "Tracking id",
610
+ "openIssue": "View issue",
611
+ "alreadySubmitted": "This draft was already submitted and was not re-submitted.",
612
+ "writeBackNote": "Submission complete, but status write-back failed. Please record the receipt manually."
571
613
  },
572
614
  "saved": {
573
615
  "title": "Saved drafts",
@@ -580,7 +622,11 @@
580
622
  "emailCopied": "Email text copied to clipboard",
581
623
  "copyFailed": "Copy failed",
582
624
  "loadFailed": "Failed to load draft",
583
- "deleteFailed": "Failed to delete draft"
625
+ "deleteFailed": "Failed to delete draft",
626
+ "submitSucceeded": "Submitted. Tracking id {{trackingId}}",
627
+ "submitFailed": "Submission failed",
628
+ "markSentSucceeded": "Marked as sent",
629
+ "channelsFailed": "Could not load send channels"
584
630
  },
585
631
  "errors": {
586
632
  "missingRequired": "Title and description are required.",
@@ -525,6 +525,7 @@
525
525
  "loadError": "无法加载反馈数据。你可以尝试刷新页面。",
526
526
  "description": "生成本地隐私可控的反馈草稿。控制台不会自动上传——你决定分享什么、如何分享、何时分享。",
527
527
  "deepLinked": "从 {{source}} 跳转而来。",
528
+ "entryFeedback": "反馈",
528
529
  "form": {
529
530
  "title": "描述发生了什么",
530
531
  "description": "仅存储以下字段。原始提示词、聊天记录、文件内容、路径、环境变量和令牌默认排除。",
@@ -534,6 +535,25 @@
534
535
  "severityLow": "低",
535
536
  "severityMedium": "中",
536
537
  "severityHigh": "高",
538
+ "blockingLevelLabel": "影响程度",
539
+ "blockingLevelNotSet": "未设置",
540
+ "blockingLevelBlocked": "卡住我了",
541
+ "blockingLevelWorkaround": "能绕过",
542
+ "blockingLevelMinor": "不影响",
543
+ "frequencyLabel": "出现频率",
544
+ "frequencyNotSet": "未设置",
545
+ "frequencyAlways": "每次",
546
+ "frequencyOften": "经常",
547
+ "frequencySometimes": "偶尔",
548
+ "frequencyOnce": "仅一次",
549
+ "goalLabel": "你当时想做什么",
550
+ "stuckAtLabel": "卡在哪一步",
551
+ "jobLabel": "你想达成什么目标",
552
+ "currentWorkaroundLabel": "现在是怎么凑合的",
553
+ "sawWhatLabel": "你看到了什么",
554
+ "whereSeenLabel": "在哪里看到的",
555
+ "detailsToggle": "补充细节",
556
+ "detailsHide": "收起细节",
537
557
  "titleLabel": "标题",
538
558
  "descriptionLabel": "描述",
539
559
  "stepsLabel": "复现步骤(可选)",
@@ -567,7 +587,29 @@
567
587
  "copyEmail": "复制邮件文本",
568
588
  "openGithub": "打开 GitHub issue 链接",
569
589
  "openEmail": "打开邮件",
570
- "delete": "删除草稿"
590
+ "delete": "删除草稿",
591
+ "sentBadge": "已发送",
592
+ "draftBadge": "待发送",
593
+ "markAsSent": "标记为已发送"
594
+ },
595
+ "channel": {
596
+ "title": "发送反馈",
597
+ "description": "反馈已脱敏,只发送你在上方填写的内容。控制台不会自动上传——点击按钮即是你主动提交。",
598
+ "ingest": "一键提交(推荐)",
599
+ "github": "提交到 GitHub issue",
600
+ "email": "打开邮件",
601
+ "file": "导出文件",
602
+ "disablingReason": "不可用:{{reason}}",
603
+ "confirmTitle": "确认提交反馈",
604
+ "confirmDescription": "提交后,下面这条脱敏反馈将被发送到维护者反馈服务。你无法撤销,但可稍后删除本地草稿。",
605
+ "confirmBodyLabel": "将发送的内容",
606
+ "confirmSubmit": "确认提交",
607
+ "confirmCancel": "取消",
608
+ "receiptTitle": "已提交",
609
+ "receiptTrackingId": "回执编号",
610
+ "openIssue": "查看 issue",
611
+ "alreadySubmitted": "此草稿已提交过,未重复提交。",
612
+ "writeBackNote": "提交完成,但状态写回失败。请手动记录回执。"
571
613
  },
572
614
  "saved": {
573
615
  "title": "已保存的草稿",
@@ -580,7 +622,11 @@
580
622
  "emailCopied": "邮件文本已复制到剪贴板",
581
623
  "copyFailed": "复制失败",
582
624
  "loadFailed": "加载草稿失败",
583
- "deleteFailed": "删除草稿失败"
625
+ "deleteFailed": "删除草稿失败",
626
+ "submitSucceeded": "已提交,回执编号 {{trackingId}}",
627
+ "submitFailed": "提交失败",
628
+ "markSentSucceeded": "已标记为已发送",
629
+ "channelsFailed": "无法获取发送通道"
584
630
  },
585
631
  "errors": {
586
632
  "missingRequired": "标题和描述为必填项。",
@@ -1,5 +1,9 @@
1
1
  export type FeedbackType = 'bug' | 'confusing' | 'privacy_concern' | 'feature_request' | 'other';
2
2
  export type UserSeverity = 'low' | 'medium' | 'high';
3
+ export type FeedbackFrequency = 'always' | 'often' | 'sometimes' | 'once';
4
+ export type FeedbackBlockingLevel = 'blocked' | 'workaround' | 'minor';
5
+ export type FeedbackStatus = 'draft' | 'submitted';
6
+ export type FeedbackSubmittedVia = 'ingest' | 'github' | 'email' | 'file';
3
7
  export type DraftRecord = {
4
8
  id: string;
5
9
  createdAt: string;
@@ -11,6 +15,14 @@ export type DraftRecord = {
11
15
  expectedBehavior?: string;
12
16
  actualBehavior?: string;
13
17
  userSeverity?: UserSeverity;
18
+ goal?: string;
19
+ stuckAt?: string;
20
+ job?: string;
21
+ currentWorkaround?: string;
22
+ sawWhat?: string;
23
+ whereSeen?: string;
24
+ frequency?: FeedbackFrequency;
25
+ blockingLevel?: FeedbackBlockingLevel;
14
26
  };
15
27
  diagnosticSummary: {
16
28
  versions: Record<string, unknown>;
@@ -39,13 +51,31 @@ export type DraftRecord = {
39
51
  githubIssueUrl: string;
40
52
  mailtoUrl: string;
41
53
  };
54
+ area?: string;
55
+ status?: FeedbackStatus;
56
+ submittedAt?: string;
57
+ submittedVia?: FeedbackSubmittedVia;
58
+ trackingId?: string;
59
+ externalUrl?: string;
42
60
  };
43
61
  export type FeedbackDraftSummary = {
44
62
  id: string;
45
63
  createdAt: string;
46
64
  type: string;
47
65
  title: string;
66
+ status?: string;
48
67
  };
68
+ /**
69
+ * 旧草稿 severity → blockingLevel 的展示映射(仅 UI 展示,不改文件,spec §5.2):
70
+ * high→blocked / medium→workaround / low→minor。
71
+ */
72
+ export declare function mapSeverityToBlockingLevel(severity: UserSeverity | undefined): FeedbackBlockingLevel | undefined;
73
+ /**
74
+ * 从 context(page / sourceDetail)归一化出反馈来源 area(spec §7)。
75
+ * area 值:failed_tasks / pain / principles / activation / focus / intent / error / general。
76
+ * 匹配失败缺省返回 'general'。
77
+ */
78
+ export declare function deriveFeedbackArea(context: Record<string, string> | undefined): string | undefined;
49
79
  export declare function parseDraftRecord(value: unknown): DraftRecord | null;
50
80
  export declare function parseDraftSummary(value: unknown): FeedbackDraftSummary | null;
51
81
  export declare function parseEnvelopeReport(value: unknown): DraftRecord | null;
@@ -6,6 +6,55 @@
6
6
  // The server returns JSON parsed via the standard fetch path. Per ERR-001
7
7
  // and ERR-005, every field must be runtime-validated before use; no `as`
8
8
  // casts are allowed to bypass validation.
9
+ const FEEDBACK_FREQUENCIES = ['always', 'often', 'sometimes', 'once'];
10
+ const FEEDBACK_BLOCKING_LEVELS = ['blocked', 'workaround', 'minor'];
11
+ const FEEDBACK_SUBMITTED_VIA = ['ingest', 'github', 'email', 'file'];
12
+ function isFeedbackFrequency(value) {
13
+ return typeof value === 'string' && FEEDBACK_FREQUENCIES.includes(value);
14
+ }
15
+ function isFeedbackBlockingLevel(value) {
16
+ return typeof value === 'string' && FEEDBACK_BLOCKING_LEVELS.includes(value);
17
+ }
18
+ function isFeedbackSubmittedVia(value) {
19
+ return typeof value === 'string' && FEEDBACK_SUBMITTED_VIA.includes(value);
20
+ }
21
+ /**
22
+ * 旧草稿 severity → blockingLevel 的展示映射(仅 UI 展示,不改文件,spec §5.2):
23
+ * high→blocked / medium→workaround / low→minor。
24
+ */
25
+ export function mapSeverityToBlockingLevel(severity) {
26
+ if (severity === 'high')
27
+ return 'blocked';
28
+ if (severity === 'medium')
29
+ return 'workaround';
30
+ if (severity === 'low')
31
+ return 'minor';
32
+ return undefined;
33
+ }
34
+ /**
35
+ * 从 context(page / sourceDetail)归一化出反馈来源 area(spec §7)。
36
+ * area 值:failed_tasks / pain / principles / activation / focus / intent / error / general。
37
+ * 匹配失败缺省返回 'general'。
38
+ */
39
+ export function deriveFeedbackArea(context) {
40
+ if (!context)
41
+ return undefined;
42
+ const haystack = `${context.page ?? ''} ${context.sourceDetail ?? ''}`.toLowerCase();
43
+ const tokens = [
44
+ ['failed_tasks', 'failed_tasks'],
45
+ ['pain', 'pain'],
46
+ ['principle', 'principles'],
47
+ ['activation', 'activation'],
48
+ ['focus', 'focus'],
49
+ ['intent', 'intent'],
50
+ ['error', 'error'],
51
+ ];
52
+ for (const [token, area] of tokens) {
53
+ if (haystack.includes(token))
54
+ return area;
55
+ }
56
+ return undefined;
57
+ }
9
58
  function isString(value) {
10
59
  return typeof value === 'string';
11
60
  }
@@ -68,6 +117,15 @@ export function parseDraftRecord(value) {
68
117
  userSeverity: userText.userSeverity === 'low' || userText.userSeverity === 'medium' || userText.userSeverity === 'high'
69
118
  ? userText.userSeverity
70
119
  : undefined,
120
+ // 类型化新字段(全部可选,旧草稿缺省兼容;枚举校验同 core)
121
+ goal: isString(userText.goal) ? userText.goal : undefined,
122
+ stuckAt: isString(userText.stuckAt) ? userText.stuckAt : undefined,
123
+ job: isString(userText.job) ? userText.job : undefined,
124
+ currentWorkaround: isString(userText.currentWorkaround) ? userText.currentWorkaround : undefined,
125
+ sawWhat: isString(userText.sawWhat) ? userText.sawWhat : undefined,
126
+ whereSeen: isString(userText.whereSeen) ? userText.whereSeen : undefined,
127
+ frequency: isFeedbackFrequency(userText.frequency) ? userText.frequency : undefined,
128
+ blockingLevel: isFeedbackBlockingLevel(userText.blockingLevel) ? userText.blockingLevel : undefined,
71
129
  },
72
130
  diagnosticSummary: {
73
131
  versions: asRecord(diagnostic.versions),
@@ -90,6 +148,13 @@ export function parseDraftRecord(value) {
90
148
  // "Open Email" button gracefully (rc-1: treat as unknown, no `as`).
91
149
  mailtoUrl: isString(outputs.mailtoUrl) ? outputs.mailtoUrl : '',
92
150
  },
151
+ // 来源与提交元数据(全部可选;status/trackingId/externalUrl 仅当枚举/字符串合法时保留)
152
+ area: isString(value.area) ? value.area : undefined,
153
+ status: value.status === 'draft' || value.status === 'submitted' ? value.status : undefined,
154
+ submittedAt: isString(value.submittedAt) ? value.submittedAt : undefined,
155
+ submittedVia: isFeedbackSubmittedVia(value.submittedVia) ? value.submittedVia : undefined,
156
+ trackingId: isString(value.trackingId) ? value.trackingId : undefined,
157
+ externalUrl: isString(value.externalUrl) ? value.externalUrl : undefined,
93
158
  };
94
159
  }
95
160
  export function parseDraftSummary(value) {
@@ -103,6 +168,7 @@ export function parseDraftSummary(value) {
103
168
  createdAt: value.createdAt,
104
169
  type: value.type,
105
170
  title: value.title,
171
+ status: isString(value.status) ? value.status : undefined,
106
172
  };
107
173
  }
108
174
  export function parseEnvelopeReport(value) {
@@ -1,12 +1,13 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState, useEffect, useCallback } from "react";
3
- import { Link } from "react-router-dom";
3
+ import { Link, useNavigate } from "react-router-dom";
4
4
  import { useTranslation } from "react-i18next";
5
5
  import { toast } from "sonner";
6
6
  import { PageShell } from "../../components/layout/page-shell.js";
7
7
  import { PageLoading } from "../../components/layout/page-loading.js";
8
8
  import { SectionTitle } from "../../components/layout/section-title.js";
9
9
  import { ShinyText } from "../../components/ui/shiny-text.js";
10
+ import { Button } from "../../components/ui/button.js";
10
11
  import { fetchAllActivations, disableActivation, fetchLifecycleMetrics, } from "../../api.js";
11
12
  import { validateActivationsData, validateLifecycleMetricsData, isReversibleChannel, } from "./ActivationValidators.js";
12
13
  import { enumLabel } from "../../utils/enum-labels.js";
@@ -21,13 +22,23 @@ function CapabilityBoundaryDeclaration() {
21
22
  }
22
23
  function ActivationFactCard({ record, lifecycleData, onDisable, disabling, }) {
23
24
  const { t } = useTranslation();
25
+ const navigate = useNavigate();
24
26
  const [showConfirm, setShowConfirm] = useState(false);
25
27
  const neverActivated = record.activatedAt === null;
26
28
  const channelLabel = getChannelLabel(record.channel, t);
27
29
  const reversible = isReversibleChannel(record.channel);
28
- return (_jsxs("article", { className: `relative pl-[22px] py-[18px] pr-[18px] bg-panel border rounded-[6px] transition-colors hover:border-line-2 ${neverActivated ? "border-amber/30 border-l-[3px] border-l-amber" : "border-line"}`, "data-testid": `activation-card-${record.activationId}`, children: [_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 ${record.status === "active"
30
+ return (_jsxs("article", { className: `relative pl-[22px] py-[18px] pr-[18px] bg-panel border rounded-[6px] transition-colors hover:border-line-2 ${neverActivated ? "border-amber/30 border-l-[3px] border-l-amber" : "border-line"}`, "data-testid": `activation-card-${record.activationId}`, children: [_jsxs("div", { className: "flex items-center gap-2 flex-wrap pr-24", children: [_jsx("span", { className: `inline-flex items-center border rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase ${record.status === "active"
29
31
  ? "border-green/35 text-green bg-green/5"
30
- : "border-line text-ink-4 bg-surface/80"}`, role: "status", children: record.status === "active" ? t("pages.activation.statusActive") : t("pages.activation.statusInactive") }), _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 }), reversible && (_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: t("pages.activation.tagReversible") })), !reversible && record.channel === "code_tool_hook" && (_jsx("span", { className: "inline-flex items-center border border-danger/35 text-danger rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase", children: t("pages.activation.tagHighRisk") })), neverActivated && (_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: t("pages.activation.tagNeverActivated") }))] }), _jsxs("div", { className: "mt-[14px] mb-2", children: [_jsx("span", { className: "text-ink-2 text-[13px]", children: t("pages.activation.principleLabel") }), " ", _jsx(Link, { to: `/principles/${record.principleId}`, className: "text-gov text-[13px] hover:underline focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", "data-testid": `principle-link-${record.principleId}`, title: record.principleId, children: record.action }), _jsx("span", { className: "ml-2 font-mono text-[11px] text-ink-4", children: record.principleId })] }), _jsxs("div", { className: "text-ink-3 text-[13px] leading-relaxed space-y-1", children: [_jsxs("div", { children: [_jsx("span", { className: "text-ink-4 font-mono text-[11px] uppercase", children: t("pages.activation.actionLabel") }), " ", _jsx("span", { className: "text-ink-2", children: record.action })] }), _jsxs("div", { children: [_jsx("span", { className: "text-ink-4 font-mono text-[11px] uppercase", children: t("pages.activation.targetLabel") }), " ", _jsx("span", { className: "text-ink-2 font-mono text-[12px]", children: record.targetRef })] }), _jsxs("div", { children: [_jsx("span", { className: "text-ink-4 font-mono text-[11px] uppercase", children: t("pages.activation.activatedAtLabel") }), " ", neverActivated ? (_jsx("span", { className: "text-amber", children: t("pages.activation.neverActivated") })) : (_jsx("span", { className: "text-ink-2 font-mono text-[12px] tabular-nums", children: new Date(record.activatedAt).toLocaleString() }))] })] }), lifecycleData !== undefined && (_jsxs("details", { className: "mt-4 group", children: [_jsx("summary", { className: "text-gov text-[13px] cursor-pointer hover:underline focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.activation.lifecycleToggle") }), _jsx("div", { className: "mt-2 pl-4 border-l-2 border-line", children: lifecycleData === null ? (_jsx("div", { className: "text-ink-4 text-[13px] py-2", children: t("pages.activation.lifecycleUnavailable") })) : lifecycleData.adherence.insufficientData ? (_jsx("div", { className: "text-ink-4 text-[13px] py-2", children: t("pages.activation.insufficientData") })) : (_jsxs("div", { className: "py-2 space-y-2", children: [_jsxs("div", { className: "text-ink-2 text-[13px]", children: [_jsx("span", { className: "font-mono font-semibold text-ink tabular-nums", children: lifecycleData.adherence.rate !== null
32
+ : "border-line text-ink-4 bg-surface/80"}`, role: "status", children: record.status === "active" ? t("pages.activation.statusActive") : t("pages.activation.statusInactive") }), _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 }), reversible && (_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: t("pages.activation.tagReversible") })), !reversible && record.channel === "code_tool_hook" && (_jsx("span", { className: "inline-flex items-center border border-danger/35 text-danger rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase", children: t("pages.activation.tagHighRisk") })), neverActivated && (_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: t("pages.activation.tagNeverActivated") }))] }), _jsx(Button, { variant: "ghost", size: "sm", className: "absolute top-[14px] right-[14px]", "data-testid": `activation-feedback-${record.activationId}`, onClick: () => {
33
+ const params = new URLSearchParams({
34
+ source: "activation_page",
35
+ activationId: record.activationId,
36
+ });
37
+ if (record.principleId) {
38
+ params.set("principleId", record.principleId);
39
+ }
40
+ navigate(`/report-problem?${params.toString()}`);
41
+ }, children: t("pages.reportProblem.entryFeedback") }), _jsxs("div", { className: "mt-[14px] mb-2", children: [_jsx("span", { className: "text-ink-2 text-[13px]", children: t("pages.activation.principleLabel") }), " ", _jsx(Link, { to: `/principles/${record.principleId}`, className: "text-gov text-[13px] hover:underline focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", "data-testid": `principle-link-${record.principleId}`, title: record.principleId, children: record.action }), _jsx("span", { className: "ml-2 font-mono text-[11px] text-ink-4", children: record.principleId })] }), _jsxs("div", { className: "text-ink-3 text-[13px] leading-relaxed space-y-1", children: [_jsxs("div", { children: [_jsx("span", { className: "text-ink-4 font-mono text-[11px] uppercase", children: t("pages.activation.actionLabel") }), " ", _jsx("span", { className: "text-ink-2", children: record.action })] }), _jsxs("div", { children: [_jsx("span", { className: "text-ink-4 font-mono text-[11px] uppercase", children: t("pages.activation.targetLabel") }), " ", _jsx("span", { className: "text-ink-2 font-mono text-[12px]", children: record.targetRef })] }), _jsxs("div", { children: [_jsx("span", { className: "text-ink-4 font-mono text-[11px] uppercase", children: t("pages.activation.activatedAtLabel") }), " ", neverActivated ? (_jsx("span", { className: "text-amber", children: t("pages.activation.neverActivated") })) : (_jsx("span", { className: "text-ink-2 font-mono text-[12px] tabular-nums", children: new Date(record.activatedAt).toLocaleString() }))] })] }), lifecycleData !== undefined && (_jsxs("details", { className: "mt-4 group", children: [_jsx("summary", { className: "text-gov text-[13px] cursor-pointer hover:underline focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.activation.lifecycleToggle") }), _jsx("div", { className: "mt-2 pl-4 border-l-2 border-line", children: lifecycleData === null ? (_jsx("div", { className: "text-ink-4 text-[13px] py-2", children: t("pages.activation.lifecycleUnavailable") })) : lifecycleData.adherence.insufficientData ? (_jsx("div", { className: "text-ink-4 text-[13px] py-2", children: t("pages.activation.insufficientData") })) : (_jsxs("div", { className: "py-2 space-y-2", children: [_jsxs("div", { className: "text-ink-2 text-[13px]", children: [_jsx("span", { className: "font-mono font-semibold text-ink tabular-nums", children: lifecycleData.adherence.rate !== null
31
42
  ? `${(lifecycleData.adherence.rate * 100).toFixed(0)}%`
32
43
  : "—" }), " ", _jsx("span", { className: "text-ink-3", children: t("pages.activation.adherenceLabel") }), _jsx("div", { className: "text-ink-4 text-[11px] mt-1 font-mono", children: t("pages.activation.lifecycleNote") })] }), lifecycleData.ruleMetrics.length > 0 && (_jsx("div", { className: "space-y-1", children: lifecycleData.ruleMetrics.map((rm) => (_jsxs("div", { className: "text-ink-3 text-[12px] font-mono", children: [_jsx("span", { className: "text-ink-2", children: rm.ruleId }), ":", " ", rm.triggered, " ", t("pages.activation.triggered"), " ", rm.lastTriggeredAt && (_jsxs("span", { className: "text-ink-4", children: ["(", new Date(rm.lastTriggeredAt).toLocaleString(), ")"] }))] }, rm.ruleId))) }))] })) })] })), record.status === "active" && reversible && (_jsx("div", { className: "mt-4", children: !showConfirm ? (_jsx("button", { onClick: () => setShowConfirm(true), disabled: disabling, 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 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", "data-testid": `disable-btn-${record.activationId}`, children: t("pages.activation.disableAction") })) : (_jsxs("div", { className: "flex items-center gap-3 px-[14px] py-[10px] bg-surface border border-amber/25 rounded-[4px]", role: "alert", "data-testid": `confirm-bar-${record.activationId}`, children: [_jsx("span", { className: "text-ink-2 text-[13px] flex-1", children: t("pages.activation.confirmDisable") }), _jsx("button", { onClick: () => {
33
44
  onDisable(record);
@@ -12,6 +12,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
12
12
  */
13
13
  import { useState, useEffect, useCallback } from 'react';
14
14
  import { useTranslation } from 'react-i18next';
15
+ import { useNavigate } from 'react-router-dom';
15
16
  import { PageShell } from '../../components/layout/page-shell.js';
16
17
  import { PageLoading } from '../../components/layout/page-loading.js';
17
18
  import { Badge } from '../../components/ui/badge.js';
@@ -124,6 +125,7 @@ function EmptyState({ t }) {
124
125
  }
125
126
  function EvidenceChainCard({ record, expanded, onToggle, t }) {
126
127
  const [copied, setCopied] = useState(false);
128
+ const navigate = useNavigate();
127
129
  const layer2Empty = isLayer2EffectivelyEmpty(record);
128
130
  const stateVariant = stateToVariant(record.state);
129
131
  const stateLabel = enumLabel('evidenceState', record.state, t);
@@ -133,7 +135,10 @@ function EvidenceChainCard({ record, expanded, onToggle, t }) {
133
135
  const confidenceDisplay = layers.layer2.confidence
134
136
  ? `${enumLabel('confidence', layers.layer2.confidence.label, t)} (${layers.layer2.confidence.raw.toFixed(2)})`
135
137
  : null;
136
- return (_jsxs(Card, { className: "overflow-hidden", children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx(Badge, { variant: stateVariant, children: stateLabel }), _jsx(Badge, { variant: "outline", children: sourceLabel }), record.admissionDecision && (_jsx(Badge, { variant: "secondary", children: enumLabel('admission', record.admissionDecision, t) }))] }), _jsx("span", { className: "font-mono text-[11px] text-ink-4 whitespace-nowrap", children: formatDate(record.observedAt) })] }) }), _jsxs(CardContent, { children: [_jsxs("div", { className: "space-y-3 mb-4", children: [_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldTrigger') }), layer2Empty ? (_jsx("p", { className: "text-ink-3 text-sm italic leading-relaxed", children: t('pages.pain.noHumanSummary') })) : (_jsx(CardTitle, { className: "text-[15px] leading-relaxed", children: layers.layer2.triggerSummary }))] }), layers.layer2.conclusion && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldConclusion') }), _jsx("p", { className: "text-ink text-sm leading-relaxed font-medium", children: layers.layer2.conclusion })] })), layers.layer2.applicability && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldApplicability') }), _jsx("p", { className: "text-ink-2 text-sm leading-relaxed", children: layers.layer2.applicability })] })), confidenceDisplay && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldConfidence') }), _jsx("p", { className: "text-ink-2 text-sm", children: confidenceDisplay })] })), layers.layer2.failureReason && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldFailureReason') }), _jsx("p", { className: "text-danger text-sm leading-relaxed", children: layers.layer2.failureReason })] })), layers.layer2.degradedReason && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldDegradedReason') }), _jsx("p", { className: "text-amber text-sm leading-relaxed", children: layers.layer2.degradedReason })] })), layers.layer2.nextAction && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldNextAction') }), _jsx("p", { className: "text-ink-2 text-sm leading-relaxed", children: layers.layer2.nextAction })] }))] }), shouldRenderIntentTensionPanel(layers.layer2.intentTension) && (_jsx(IntentTensionPanel, { tension: layers.layer2.intentTension, recordId: record.id, painId: record.id, taskId: record.linkedTaskId ?? undefined, linkedCandidateId: record.linkedCandidateId ?? undefined, t: t })), _jsxs("div", { className: "mt-4 pt-3 border-t border-line", children: [_jsxs("div", { className: "flex items-center gap-3 flex-wrap", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: async () => {
138
+ return (_jsxs(Card, { className: "overflow-hidden", children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx(Badge, { variant: stateVariant, children: stateLabel }), _jsx(Badge, { variant: "outline", children: sourceLabel }), record.admissionDecision && (_jsx(Badge, { variant: "secondary", children: enumLabel('admission', record.admissionDecision, t) }))] }), _jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [_jsx(Button, { variant: "ghost", size: "sm", "data-testid": `pain-feedback-${record.id}`, onClick: () => {
139
+ const params = new URLSearchParams({ source: "pain_page", painId: record.id });
140
+ navigate(`/report-problem?${params.toString()}`);
141
+ }, children: t('pages.reportProblem.entryFeedback') }), _jsx("span", { className: "font-mono text-[11px] text-ink-4 whitespace-nowrap", children: formatDate(record.observedAt) })] })] }) }), _jsxs(CardContent, { children: [_jsxs("div", { className: "space-y-3 mb-4", children: [_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldTrigger') }), layer2Empty ? (_jsx("p", { className: "text-ink-3 text-sm italic leading-relaxed", children: t('pages.pain.noHumanSummary') })) : (_jsx(CardTitle, { className: "text-[15px] leading-relaxed", children: layers.layer2.triggerSummary }))] }), layers.layer2.conclusion && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldConclusion') }), _jsx("p", { className: "text-ink text-sm leading-relaxed font-medium", children: layers.layer2.conclusion })] })), layers.layer2.applicability && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldApplicability') }), _jsx("p", { className: "text-ink-2 text-sm leading-relaxed", children: layers.layer2.applicability })] })), confidenceDisplay && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldConfidence') }), _jsx("p", { className: "text-ink-2 text-sm", children: confidenceDisplay })] })), layers.layer2.failureReason && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldFailureReason') }), _jsx("p", { className: "text-danger text-sm leading-relaxed", children: layers.layer2.failureReason })] })), layers.layer2.degradedReason && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldDegradedReason') }), _jsx("p", { className: "text-amber text-sm leading-relaxed", children: layers.layer2.degradedReason })] })), layers.layer2.nextAction && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldNextAction') }), _jsx("p", { className: "text-ink-2 text-sm leading-relaxed", children: layers.layer2.nextAction })] }))] }), shouldRenderIntentTensionPanel(layers.layer2.intentTension) && (_jsx(IntentTensionPanel, { tension: layers.layer2.intentTension, recordId: record.id, painId: record.id, taskId: record.linkedTaskId ?? undefined, linkedCandidateId: record.linkedCandidateId ?? undefined, t: t })), _jsxs("div", { className: "mt-4 pt-3 border-t border-line", children: [_jsxs("div", { className: "flex items-center gap-3 flex-wrap", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: async () => {
137
142
  try {
138
143
  await navigator.clipboard.writeText(buildDebugIdSummary(record));
139
144
  setCopied(true);
@@ -380,7 +380,10 @@ export function PrincipleDetailPage() {
380
380
  }
381
381
  const isPending = approvalGroup?.status === "pending" || principle.status === "candidate" || principle.status === "probation";
382
382
  const hasRules = principle.rules.length > 0;
383
- 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", children: principle.text }), _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") })] })] }), _jsxs("section", { className: "mb-8", children: [_jsx(SectionTitle, { children: t("principles.detail.channel") }), _jsx("p", { className: "text-ink-2 text-[14px] leading-relaxed", children: t("principles.detail.channelPromptReversible") })] }), _jsxs("section", { className: "mb-8", children: [_jsx(SectionTitle, { children: t("principles.detail.whyExists") }), _jsxs("div", { className: "space-y-3 mb-6", children: [_jsxs("div", { children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3", children: t("principles.detail.applicable", { defaultValue: "适用场景" }) }), _jsx("p", { className: "text-ink-2 text-[14px] leading-relaxed", children: principle.triggerPattern || t("principles.detail.notSpecified", { defaultValue: "未指定" }) })] }), _jsxs("div", { children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3", children: t("principles.detail.expectedBehavior", { defaultValue: "预期行为" }) }), _jsx("p", { className: "text-ink-2 text-[14px] leading-relaxed", children: principle.action || t("principles.detail.notSpecified", { defaultValue: "未指定" }) })] })] }), principle.derivedFromPainIds.length > 0 && (_jsxs("div", { children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3", children: t("principles.detail.evidence") }), _jsxs("div", { className: "mt-2 flex items-center gap-3 flex-wrap", children: [_jsx("p", { className: "text-ink-2 text-[14px] leading-relaxed", children: t("principles.detail.evidenceCount", {
383
+ 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", children: principle.text }), _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: () => {
384
+ const params = new URLSearchParams({ source: "principle_page", principleId: id ?? "" });
385
+ navigate(`/report-problem?${params.toString()}`);
386
+ }, children: t("reportProblem.entryFeedback") })] })] }), _jsxs("section", { className: "mb-8", children: [_jsx(SectionTitle, { children: t("principles.detail.channel") }), _jsx("p", { className: "text-ink-2 text-[14px] leading-relaxed", children: t("principles.detail.channelPromptReversible") })] }), _jsxs("section", { className: "mb-8", children: [_jsx(SectionTitle, { children: t("principles.detail.whyExists") }), _jsxs("div", { className: "space-y-3 mb-6", children: [_jsxs("div", { children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3", children: t("principles.detail.applicable", { defaultValue: "适用场景" }) }), _jsx("p", { className: "text-ink-2 text-[14px] leading-relaxed", children: principle.triggerPattern || t("principles.detail.notSpecified", { defaultValue: "未指定" }) })] }), _jsxs("div", { children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3", children: t("principles.detail.expectedBehavior", { defaultValue: "预期行为" }) }), _jsx("p", { className: "text-ink-2 text-[14px] leading-relaxed", children: principle.action || t("principles.detail.notSpecified", { defaultValue: "未指定" }) })] })] }), principle.derivedFromPainIds.length > 0 && (_jsxs("div", { children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3", children: t("principles.detail.evidence") }), _jsxs("div", { className: "mt-2 flex items-center gap-3 flex-wrap", children: [_jsx("p", { className: "text-ink-2 text-[14px] leading-relaxed", children: t("principles.detail.evidenceCount", {
384
387
  defaultValue: "已关联 {{count}} 条证据记录",
385
388
  count: principle.derivedFromPainIds.length,
386
389
  }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: async () => {