chainlesschain 0.162.12 → 0.162.14

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 (170) hide show
  1. package/README.md +29 -24
  2. package/package.json +5 -2
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-C3TDNq29.js → AIOps-D34d_Nh1.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-C9fE18pE.js → ActionButton-Br7HxCnl.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-wnZF602C.js → Analytics-bVKq79Xd.js} +1 -1
  7. package/src/assets/web-panel/assets/{AppLayout-BjgTMK7O.js → AppLayout-CWSLIbAz.js} +2 -2
  8. package/src/assets/web-panel/assets/{Audit-BBL0BW5_.js → Audit-Cmnu1qqa.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-BKLqYCWU.js → Backup-Rok20-TL.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-BGSzMCZs.js → BaseInput-BJzs_ZtT.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-CQWzZWEY.js → Chat-CSYapbcq.js} +1 -1
  12. package/src/assets/web-panel/assets/{Checkbox-BkTri12Q.js → Checkbox-BEa7Sr7e.js} +1 -1
  13. package/src/assets/web-panel/assets/{Codegen-BH1m09EO.js → Codegen-C9M4e7ne.js} +1 -1
  14. package/src/assets/web-panel/assets/{Col-BXnBuqIa.js → Col-DU9NoUIi.js} +1 -1
  15. package/src/assets/web-panel/assets/{Community-C_Nr4XCx.js → Community-DA9uz_jP.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compact-Du6GwLrj.js → Compact-3_bEraVw.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compliance-66M0oi1Q.js → Compliance-BtF8jWUQ.js} +1 -1
  18. package/src/assets/web-panel/assets/{Cowork-DQrkZRNd.js → Cowork-BqvA7oaM.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cron-CwdIFH_v.js → Cron-CxZy7Mzg.js} +1 -1
  20. package/src/assets/web-panel/assets/{Crosschain-DqlcrQ9L.js → Crosschain-1DB-XRGu.js} +1 -1
  21. package/src/assets/web-panel/assets/{DID-OmPLKf7L.js → DID-B6Ezp1pt.js} +1 -1
  22. package/src/assets/web-panel/assets/{Dashboard-D_dampTL.js → Dashboard-QDJ6VVsn.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dropdown-CA1W7jAn.js → Dropdown-CovsWjxG.js} +1 -1
  24. package/src/assets/web-panel/assets/{Federation-Chlk9a7s.js → Federation-DbRxS4Y4.js} +1 -1
  25. package/src/assets/web-panel/assets/{FormItemContext-t0UqYFLq.js → FormItemContext-9E9dNGtx.js} +1 -1
  26. package/src/assets/web-panel/assets/{Git-CEq0raYm.js → Git-CqEpyxRZ.js} +2 -2
  27. package/src/assets/web-panel/assets/{Governance-C06CX7Ge.js → Governance-On47KtGq.js} +1 -1
  28. package/src/assets/web-panel/assets/{Inference-6VIFHxIP.js → Inference-RZcjcyaq.js} +1 -1
  29. package/src/assets/web-panel/assets/{KnowledgeGraph-BCJPjMBQ.js → KnowledgeGraph-C-1rRAM9.js} +1 -1
  30. package/src/assets/web-panel/assets/{Logs-BBpOYFct.js → Logs-BuunmG_r.js} +1 -1
  31. package/src/assets/web-panel/assets/{Marketplace-BFH6jMWt.js → Marketplace-CromymyA.js} +1 -1
  32. package/src/assets/web-panel/assets/{McpTools-uCFvRqGs.js → McpTools-5XlFExh7.js} +1 -1
  33. package/src/assets/web-panel/assets/{Memory-B0Kux_KT.js → Memory-DjnUT7YM.js} +1 -1
  34. package/src/assets/web-panel/assets/{MobileBridge-DHow2jiK.js → MobileBridge-BrYIgLg6.js} +1 -1
  35. package/src/assets/web-panel/assets/{MobileProjects-BFo9YQZp.js → MobileProjects-CL5V3fTm.js} +1 -1
  36. package/src/assets/web-panel/assets/{Mtc-riOh1G_F.js → Mtc-CHYJq6zK.js} +1 -1
  37. package/src/assets/web-panel/assets/{MtcAudit-Bm-hE2SP.js → MtcAudit-BZxUO0qt.js} +1 -1
  38. package/src/assets/web-panel/assets/{Multisig-DfUQxh5a.js → Multisig-FZTmJgW1.js} +2 -2
  39. package/src/assets/web-panel/assets/{NLProgramming-DuNvLBEq.js → NLProgramming-C9Mhefph.js} +1 -1
  40. package/src/assets/web-panel/assets/{Notes-DB20wd3c.js → Notes-W7usj-Ar.js} +1 -1
  41. package/src/assets/web-panel/assets/{NotificationSettings-CB-GkOWR.js → NotificationSettings-PBuYv_Bh.js} +1 -1
  42. package/src/assets/web-panel/assets/{Organization-3bU7PZuG.js → Organization-CuYCE-rF.js} +4 -4
  43. package/src/assets/web-panel/assets/{Overflow-BGCPP_0Y.js → Overflow-Dojx-kzE.js} +1 -1
  44. package/src/assets/web-panel/assets/{OverrideContext-x9ZzjLwk.js → OverrideContext-C_4H9tGA.js} +1 -1
  45. package/src/assets/web-panel/assets/{P2P-BHgAe1oC.js → P2P-BgIaSrLX.js} +1 -1
  46. package/src/assets/web-panel/assets/{Permissions-BuOD4xwc.js → Permissions-Byj2dkF_.js} +1 -1
  47. package/src/assets/web-panel/assets/PersonalDataHub-CMOOI13-.js +1 -0
  48. package/src/assets/web-panel/assets/PersonalDataHub-Dvaa8niQ.css +1 -0
  49. package/src/assets/web-panel/assets/{Pipeline-DBS5U4LB.js → Pipeline-CWwEOF09.js} +1 -1
  50. package/src/assets/web-panel/assets/{Privacy-UNjIc5El.js → Privacy-VT7gldcN.js} +1 -1
  51. package/src/assets/web-panel/assets/{ProjectInit-CicqCJGy.js → ProjectInit-7UH3c3p7.js} +1 -1
  52. package/src/assets/web-panel/assets/{ProjectSettings-CIxAbt4Y.js → ProjectSettings-DqLp-72a.js} +1 -1
  53. package/src/assets/web-panel/assets/{Projects-BJycZScO.js → Projects-B_54eDhH.js} +1 -1
  54. package/src/assets/web-panel/assets/{Providers-DxXvprme.js → Providers-BIrNfNpc.js} +1 -1
  55. package/src/assets/web-panel/assets/{QuickAsk-rrqjU8_Y.js → QuickAsk-BbYPwCso.js} +1 -1
  56. package/src/assets/web-panel/assets/{Recommend-BEwHMhI7.js → Recommend-BF4qBssF.js} +1 -1
  57. package/src/assets/web-panel/assets/{Reputation-DoVKCCMn.js → Reputation-DPEzlC2V.js} +1 -1
  58. package/src/assets/web-panel/assets/{Row-F5XcDhHr.js → Row-DjHxhH1L.js} +1 -1
  59. package/src/assets/web-panel/assets/{RssFeed-cZrRG7k8.js → RssFeed-D0_j678P.js} +1 -1
  60. package/src/assets/web-panel/assets/{Search-B9ctZjqx.js → Search-DctfGehu.js} +1 -1
  61. package/src/assets/web-panel/assets/{Security-Z62hl1mc.js → Security-BFHggeYM.js} +1 -1
  62. package/src/assets/web-panel/assets/{Services-CQf5XqgZ.js → Services-CmrFMukV.js} +1 -1
  63. package/src/assets/web-panel/assets/{Skeleton-DuCKw2Eh.js → Skeleton-DR4vn_nS.js} +1 -1
  64. package/src/assets/web-panel/assets/{Skills-qVkhva0s.js → Skills-DlXG2yyV.js} +1 -1
  65. package/src/assets/web-panel/assets/{Sla-BQbatr7s.js → Sla-4PPGL3SE.js} +1 -1
  66. package/src/assets/web-panel/assets/{SpeechSettings-DLFBzAgD.js → SpeechSettings-D9EhJOqm.js} +1 -1
  67. package/src/assets/web-panel/assets/{SyncSettings-CrzETZMW.js → SyncSettings-Dasmbi0p.js} +1 -1
  68. package/src/assets/web-panel/assets/{Tasks-D_EQ1nJ7.js → Tasks-vilEiuPA.js} +1 -1
  69. package/src/assets/web-panel/assets/{Templates-D4y-dGRc.js → Templates-Ca9Rvktn.js} +1 -1
  70. package/src/assets/web-panel/assets/{Tenant-2XI0jkPn.js → Tenant-CEZb9gfK.js} +1 -1
  71. package/src/assets/web-panel/assets/{Terminal-fUi5V2Z9.js → Terminal-DanCBdbD.js} +1 -1
  72. package/src/assets/web-panel/assets/{Tokens-BuUNB2mg.js → Tokens-SPkClW2d.js} +1 -1
  73. package/src/assets/web-panel/assets/{Trigger-7DqLLuej.js → Trigger-B645yL7g.js} +1 -1
  74. package/src/assets/web-panel/assets/{Trust-CeACvTYx.js → Trust-D9sM_Ig0.js} +1 -1
  75. package/src/assets/web-panel/assets/{UkeySign-mDP9EXHq.js → UkeySign-B_Nr2K-u.js} +1 -1
  76. package/src/assets/web-panel/assets/{VideoEditing-veWlKclv.js → VideoEditing-U01Lea8j.js} +1 -1
  77. package/src/assets/web-panel/assets/{Wallet-Cd2Hheb8.js → Wallet-6xBySVV8.js} +1 -1
  78. package/src/assets/web-panel/assets/{WebAuthn-DyL7ZiHX.js → WebAuthn-DbgMoBu6.js} +3 -3
  79. package/src/assets/web-panel/assets/{WorkflowEditor-C7-7LJH9.js → WorkflowEditor-Bz-Y6IR2.js} +1 -1
  80. package/src/assets/web-panel/assets/{chat-DXomZMuo.js → chat-BC_O9hag.js} +1 -1
  81. package/src/assets/web-panel/assets/{collapseMotion-CjFH_Jop.js → collapseMotion-DfnRZex1.js} +1 -1
  82. package/src/assets/web-panel/assets/{colors-DlU92QNs.js → colors-ChlOGOvr.js} +1 -1
  83. package/src/assets/web-panel/assets/{compact-item-sBiTL8mX.js → compact-item-BSbAYGGF.js} +1 -1
  84. package/src/assets/web-panel/assets/{createContext-DZXEnzum.js → createContext-CFcZly5M.js} +1 -1
  85. package/src/assets/web-panel/assets/{echarts-Bq-n0MtJ.js → echarts-Dj_pBaVI.js} +1 -1
  86. package/src/assets/web-panel/assets/{hasIn-CpCHBZ2M.js → hasIn-BomYwwYE.js} +1 -1
  87. package/src/assets/web-panel/assets/{icons-CLQTHa5-.js → icons-BOPtEWK4.js} +4 -4
  88. package/src/assets/web-panel/assets/{index-B0Qbxr57.js → index-5Ewm6KZA.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-CjXSvceY.js → index-B6LJHQoE.js} +1 -1
  90. package/src/assets/web-panel/assets/{index-CD3iljXs.js → index-BEJ6YiLI.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-BK2AFy44.js → index-BGUbtM3R.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-Di1_EQ-X.js → index-BHGsFwYW.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-B23tuoo9.js → index-BHi69MHF.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-DUlPMzoM.js → index-BI1jAWcc.js} +1 -1
  95. package/src/assets/web-panel/assets/index-BIRYt1of.js +1 -0
  96. package/src/assets/web-panel/assets/{index-B3k9UPHc.js → index-BYDvb1pi.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-CwbWZubA.js → index-BZGdjNLA.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-ThrAiEF9.js → index-BwFykZ5U.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-CUe5t5Aa.js → index-ByZQNO0A.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-Dn8m1d1f.js → index-C0rr1X9W.js} +2 -2
  101. package/src/assets/web-panel/assets/{index-C6SDf50u.js → index-CBhoZhCO.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-ClN_JuFa.js → index-CCRSz2cR.js} +1 -1
  103. package/src/assets/web-panel/assets/index-CZfySmWX.js +1 -0
  104. package/src/assets/web-panel/assets/{index-Dq5Rn5VS.js → index-Cj47XwJQ.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-ChahjdYE.js → index-Cmzh8gKL.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Dyg6ikIL.js → index-CnxlKTDK.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-Dj9Nvz6S.js → index-CoF95pYK.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-TwQZkVGh.js → index-Ctx97mH-.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-s8tvk-fF.js → index-D0vX9jQA.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-X48zYgZ6.js → index-DNkth8dM.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DygNvCeR.js → index-DRp5_Xns.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-D_MzScPM.js → index-DW-Ji07y.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BqnhEJls.js → index-DXgE2VW6.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-CDyzZ8_O.js → index-D_0B3CiU.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-C59FgSkU.js → index-Dbf5YmDX.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-_zyXBoS7.js → index-DsNQ2hqI.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CJ7XYa5K.js → index-EY733h9z.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-ibFHnqHz.js → index-QD_n54XT.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CivbS-57.js → index-T5Y_9IPv.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-C52udT0_.js → index-b8GbH2Yi.js} +4 -4
  121. package/src/assets/web-panel/assets/{index-XI6772AD.js → index-gUACAWbM.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-F9cBucYf.js → index-onW325hZ.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DKe9jmKG.js → index-ozVPr1gj.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-D_IgY63-.js → index-slYX2rCE.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-B_-RETt0.js → index-t9u2bHpH.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DeGnHcp5.js → index-za1GUJBG.js} +1 -1
  127. package/src/assets/web-panel/assets/{initDefaultProps-DEi92ZnZ.js → initDefaultProps-DnadEaxu.js} +1 -1
  128. package/src/assets/web-panel/assets/{motion-BtYKzpOc.js → motion-CC_Na0Tl.js} +1 -1
  129. package/src/assets/web-panel/assets/{move-Cb3A1-v-.js → move-C2d9Mkk9.js} +1 -1
  130. package/src/assets/web-panel/assets/{omit-B6qPDdOf.js → omit-QvpKbF8p.js} +1 -1
  131. package/src/assets/web-panel/assets/{pickAttrs-DDyeQMUc.js → pickAttrs-Dm8r3X1_.js} +1 -1
  132. package/src/assets/web-panel/assets/{placementArrow-BPV6VO47.js → placementArrow-DaqaVfoX.js} +1 -1
  133. package/src/assets/web-panel/assets/{responsiveObserve-DJ1ra4dT.js → responsiveObserve-Iida9fIn.js} +1 -1
  134. package/src/assets/web-panel/assets/{slide-D6v8tHvB.js → slide-YqHexXQD.js} +1 -1
  135. package/src/assets/web-panel/assets/{statusUtils-DulKcQLZ.js → statusUtils-BGKLoeEt.js} +1 -1
  136. package/src/assets/web-panel/assets/{styleChecker-Bne7zwMt.js → styleChecker-aI-gsQO8.js} +1 -1
  137. package/src/assets/web-panel/assets/useFlexGapSupport-BiOsz4rc.js +1 -0
  138. package/src/assets/web-panel/assets/{useFs-CR-iLa4Z.js → useFs-CZy7Zo2X.js} +1 -1
  139. package/src/assets/web-panel/assets/{useMergedState-O7QXt4P5.js → useMergedState-WwedrFR0.js} +1 -1
  140. package/src/assets/web-panel/assets/{useRefs-0J6m8UWN.js → useRefs-Cdq8EWeF.js} +1 -1
  141. package/src/assets/web-panel/assets/{useState-CSzR8F8O.js → useState-DGS1NOyn.js} +1 -1
  142. package/src/assets/web-panel/assets/{vendor-M5lGV-wr.js → vendor-DhFY8mDK.js} +1 -1
  143. package/src/assets/web-panel/assets/{vnode-yL9axxBy.js → vnode-B6WqjmE4.js} +1 -1
  144. package/src/assets/web-panel/assets/{zoom-B-VCMXSD.js → zoom-DTeTrJ2z.js} +1 -1
  145. package/src/assets/web-panel/index.html +3 -3
  146. package/src/commands/__tests__/android.test.js +260 -0
  147. package/src/commands/__tests__/hub-aichat.test.js +277 -0
  148. package/src/commands/__tests__/hub-wechat.test.js +243 -0
  149. package/src/commands/android.js +284 -0
  150. package/src/commands/hub.js +457 -0
  151. package/src/commands/sync-providers.js +436 -0
  152. package/src/gateways/ws/personal-data-hub-protocol.js +88 -0
  153. package/src/index.js +6 -0
  154. package/src/lib/__tests__/personal-data-hub-aichat-wizard.test.js +209 -0
  155. package/src/lib/__tests__/sync-credentials.test.js +265 -0
  156. package/src/lib/__tests__/sync-engine-cli.test.js +293 -0
  157. package/src/lib/cc-android-bridge.js +162 -0
  158. package/src/lib/personal-data-hub-aichat-wizard.js +242 -0
  159. package/src/lib/personal-data-hub-wiring.js +258 -13
  160. package/src/lib/sync-cli-db.js +194 -0
  161. package/src/lib/sync-credentials.js +225 -0
  162. package/src/lib/sync-engine-cli.js +406 -0
  163. package/src/lib/sync-oss-client.js +273 -0
  164. package/src/lib/sync-webdav-client.js +194 -0
  165. package/src/lib/web-ui-server.js +2 -1
  166. package/src/assets/web-panel/assets/PersonalDataHub--WA-aZAJ.js +0 -1
  167. package/src/assets/web-panel/assets/PersonalDataHub-BK7I0Rsb.css +0 -1
  168. package/src/assets/web-panel/assets/index-CcRX6BlT.js +0 -1
  169. package/src/assets/web-panel/assets/index-z6h6tqP3.js +0 -1
  170. package/src/assets/web-panel/assets/useFlexGapSupport-C1miTomM.js +0 -1
@@ -0,0 +1,273 @@
1
+ /**
2
+ * S3 / OSS client for CLI (Phase 3c follow-up Phase 2).
3
+ *
4
+ * ESM port of desktop-app-vue/src/main/sync/oss-client.js — same API.
5
+ * Lazy-imports @aws-sdk/client-s3 so non-sync commands don't pay the
6
+ * load cost. Test seam _setS3LoaderForTest.
7
+ */
8
+
9
+ "use strict";
10
+
11
+ const RETRY_MAX = 3;
12
+ const RETRY_BASE_MS = 500;
13
+ const RETRY_MAX_MS = 8000;
14
+
15
+ let _s3Loader = async () => await import("@aws-sdk/client-s3");
16
+
17
+ function _setS3LoaderForTest(loader) {
18
+ _s3Loader = loader;
19
+ }
20
+
21
+ function _resetS3LoaderForTest() {
22
+ _s3Loader = async () => await import("@aws-sdk/client-s3");
23
+ }
24
+
25
+ function _isRetriable(status) {
26
+ return status === 429 || (status >= 500 && status < 600);
27
+ }
28
+
29
+ function _backoffMs(attempt) {
30
+ const base = RETRY_BASE_MS * Math.pow(2, attempt - 1);
31
+ const jitter = Math.random() * 0.3 * base;
32
+ return Math.min(RETRY_MAX_MS, Math.floor(base + jitter));
33
+ }
34
+
35
+ function _sleep(ms) {
36
+ return new Promise((res) => setTimeout(res, ms));
37
+ }
38
+
39
+ function _extractStatus(err) {
40
+ return (
41
+ err?.$metadata?.httpStatusCode ??
42
+ err?.statusCode ??
43
+ err?.status ??
44
+ err?.response?.status ??
45
+ null
46
+ );
47
+ }
48
+
49
+ function _extractEtag(headers) {
50
+ if (!headers) return null;
51
+ const raw = headers.ETag || headers.etag || null;
52
+ if (typeof raw !== "string") return null;
53
+ return raw.replace(/^"|"$/g, "");
54
+ }
55
+
56
+ function _normalizePrefix(remotePath) {
57
+ return String(remotePath || "")
58
+ .replace(/^\/+/, "")
59
+ .replace(/\/+$/, "");
60
+ }
61
+
62
+ class OSSClient {
63
+ constructor(opts = {}) {
64
+ this.endpoint = String(opts.endpoint || "").trim();
65
+ this.region = opts.region || "auto";
66
+ this.bucket = String(opts.bucket || "").trim();
67
+ this.accessKeyId = opts.accessKeyId || "";
68
+ this.secretAccessKey = opts.secretAccessKey || "";
69
+ this.remotePath = _normalizePrefix(opts.remotePath || "");
70
+ this.forcePathStyle = opts.forcePathStyle === true;
71
+ this._client = null;
72
+ this._cmds = null;
73
+ if (!this.endpoint) throw new Error("OSSClient: endpoint 必填");
74
+ if (!this.bucket) throw new Error("OSSClient: bucket 必填");
75
+ if (!this.accessKeyId) throw new Error("OSSClient: accessKeyId 必填");
76
+ if (!this.secretAccessKey)
77
+ throw new Error("OSSClient: secretAccessKey 必填");
78
+ }
79
+
80
+ async _ensureClient() {
81
+ if (this._client) return this._client;
82
+ const mod = await _s3Loader();
83
+ const S3Client = mod.S3Client || mod.default?.S3Client;
84
+ if (typeof S3Client !== "function") {
85
+ throw new Error("@aws-sdk/client-s3 module missing S3Client");
86
+ }
87
+ this._cmds = {
88
+ HeadBucketCommand:
89
+ mod.HeadBucketCommand || mod.default?.HeadBucketCommand,
90
+ PutObjectCommand: mod.PutObjectCommand || mod.default?.PutObjectCommand,
91
+ DeleteObjectCommand:
92
+ mod.DeleteObjectCommand || mod.default?.DeleteObjectCommand,
93
+ HeadObjectCommand:
94
+ mod.HeadObjectCommand || mod.default?.HeadObjectCommand,
95
+ ListObjectsV2Command:
96
+ mod.ListObjectsV2Command || mod.default?.ListObjectsV2Command,
97
+ };
98
+ for (const [name, ctor] of Object.entries(this._cmds)) {
99
+ if (typeof ctor !== "function") {
100
+ throw new Error(`@aws-sdk/client-s3 missing ${name}`);
101
+ }
102
+ }
103
+ this._client = new S3Client({
104
+ endpoint: this.endpoint,
105
+ region: this.region,
106
+ credentials: {
107
+ accessKeyId: this.accessKeyId,
108
+ secretAccessKey: this.secretAccessKey,
109
+ },
110
+ forcePathStyle: this.forcePathStyle,
111
+ });
112
+ return this._client;
113
+ }
114
+
115
+ _resolveKey(filename) {
116
+ const safe = String(filename || "").replace(/^\/+/, "");
117
+ if (!this.remotePath) return safe;
118
+ return `${this.remotePath}/${safe}`.replace(/\/{2,}/g, "/");
119
+ }
120
+
121
+ async _withRetry(label, fn) {
122
+ let lastErr;
123
+ for (let attempt = 1; attempt <= RETRY_MAX; attempt++) {
124
+ try {
125
+ return await fn();
126
+ } catch (err) {
127
+ lastErr = err;
128
+ const status = _extractStatus(err);
129
+ if (!_isRetriable(status) || attempt === RETRY_MAX) throw err;
130
+ await _sleep(_backoffMs(attempt));
131
+ }
132
+ }
133
+ throw lastErr;
134
+ }
135
+
136
+ async testConnection() {
137
+ try {
138
+ const client = await this._ensureClient();
139
+ const cmd = new this._cmds.HeadBucketCommand({ Bucket: this.bucket });
140
+ await this._withRetry("testConnection", () => client.send(cmd));
141
+ return { ok: true };
142
+ } catch (err) {
143
+ const status = _extractStatus(err);
144
+ if (status === 404) {
145
+ return {
146
+ ok: false,
147
+ status,
148
+ error: `Bucket ${this.bucket} 不存在;请确认名称大小写或先创建`,
149
+ };
150
+ }
151
+ if (status === 403) {
152
+ return {
153
+ ok: false,
154
+ status,
155
+ error:
156
+ "认证失败 (accessKey/secretKey 错误,或账户对该 bucket 无访问权限)",
157
+ };
158
+ }
159
+ if (status === 301 || status === 400) {
160
+ return {
161
+ ok: false,
162
+ status,
163
+ error: `endpoint / region 不匹配:${err?.message || "请确认 region 与 endpoint 对应"}`,
164
+ };
165
+ }
166
+ return { ok: false, status, error: err?.message || String(err) };
167
+ }
168
+ }
169
+
170
+ async putFile(filename, content, etag = null) {
171
+ const key = this._resolveKey(filename);
172
+ try {
173
+ const client = await this._ensureClient();
174
+ const params = {
175
+ Bucket: this.bucket,
176
+ Key: key,
177
+ Body: content,
178
+ ContentType: "text/markdown; charset=utf-8",
179
+ };
180
+ if (etag) params.IfMatch = etag;
181
+ const cmd = new this._cmds.PutObjectCommand(params);
182
+ const res = await this._withRetry("putFile", () => client.send(cmd));
183
+ const newEtag = _extractEtag({ ETag: res?.ETag });
184
+ return { ok: true, etag: newEtag, raw: res };
185
+ } catch (err) {
186
+ const status = _extractStatus(err);
187
+ if (status === 412) return { ok: false, conflict: true, status };
188
+ if (status === 501) return { ok: false, conflict: true, status };
189
+ return { ok: false, error: err?.message || String(err), status };
190
+ }
191
+ }
192
+
193
+ async deleteFile(filename, _etag = null) {
194
+ const key = this._resolveKey(filename);
195
+ try {
196
+ const client = await this._ensureClient();
197
+ const cmd = new this._cmds.DeleteObjectCommand({
198
+ Bucket: this.bucket,
199
+ Key: key,
200
+ });
201
+ await this._withRetry("deleteFile", () => client.send(cmd));
202
+ return { ok: true };
203
+ } catch (err) {
204
+ const status = _extractStatus(err);
205
+ if (status === 404) return { ok: true, alreadyAbsent: true };
206
+ return { ok: false, error: err?.message || String(err), status };
207
+ }
208
+ }
209
+
210
+ async getEtag(filename) {
211
+ const key = this._resolveKey(filename);
212
+ try {
213
+ const client = await this._ensureClient();
214
+ const cmd = new this._cmds.HeadObjectCommand({
215
+ Bucket: this.bucket,
216
+ Key: key,
217
+ });
218
+ const res = await this._withRetry("getEtag", () => client.send(cmd));
219
+ return _extractEtag({ ETag: res?.ETag });
220
+ } catch (err) {
221
+ if (_extractStatus(err) === 404) return null;
222
+ throw err;
223
+ }
224
+ }
225
+
226
+ async listRemote(subPath = "") {
227
+ const prefix = subPath
228
+ ? this._resolveKey(subPath).replace(/\/?$/, "/")
229
+ : this.remotePath
230
+ ? this.remotePath + "/"
231
+ : "";
232
+ const client = await this._ensureClient();
233
+ const items = [];
234
+ let continuationToken = undefined;
235
+ do {
236
+ const cmd = new this._cmds.ListObjectsV2Command({
237
+ Bucket: this.bucket,
238
+ Prefix: prefix,
239
+ ContinuationToken: continuationToken,
240
+ });
241
+ const res = await this._withRetry("listRemote", () => client.send(cmd));
242
+ const contents = res?.Contents || [];
243
+ for (const obj of contents) {
244
+ const key = obj.Key || "";
245
+ if (!key.endsWith(".md")) continue;
246
+ const basename = key.includes("/")
247
+ ? key.slice(key.lastIndexOf("/") + 1)
248
+ : key;
249
+ items.push({
250
+ filename: basename,
251
+ key,
252
+ etag: _extractEtag({ ETag: obj.ETag }),
253
+ size: obj.Size ?? 0,
254
+ lastmod: obj.LastModified
255
+ ? new Date(obj.LastModified).toISOString()
256
+ : null,
257
+ });
258
+ }
259
+ continuationToken = res?.IsTruncated
260
+ ? res.NextContinuationToken
261
+ : undefined;
262
+ } while (continuationToken);
263
+ return items;
264
+ }
265
+ }
266
+
267
+ export {
268
+ OSSClient,
269
+ RETRY_MAX,
270
+ RETRY_BASE_MS,
271
+ _setS3LoaderForTest,
272
+ _resetS3LoaderForTest,
273
+ };
@@ -0,0 +1,194 @@
1
+ /**
2
+ * WebDAV client for CLI (Phase 3c follow-up Phase 2).
3
+ *
4
+ * ESM port of desktop-app-vue/src/main/sync/webdav-client.js — same API:
5
+ * testConnection / putFile / deleteFile / getEtag / listRemote
6
+ *
7
+ * Lazy-imports `webdav` v5 (ESM-only) so the CLI doesn't pay the cost
8
+ * for non-sync commands. Test seam `_setWebdavLoaderForTest` injects
9
+ * a fake module without touching the real binding.
10
+ */
11
+
12
+ "use strict";
13
+
14
+ const RETRY_MAX = 3;
15
+ const RETRY_BASE_MS = 500;
16
+ const RETRY_MAX_MS = 8000;
17
+
18
+ let _webdavLoader = async () => await import("webdav");
19
+
20
+ function _setWebdavLoaderForTest(loader) {
21
+ _webdavLoader = loader;
22
+ }
23
+
24
+ function _resetWebdavLoaderForTest() {
25
+ _webdavLoader = async () => await import("webdav");
26
+ }
27
+
28
+ function _isRetriable(status) {
29
+ return status === 429 || (status >= 500 && status < 600);
30
+ }
31
+
32
+ function _backoffMs(attempt) {
33
+ const base = RETRY_BASE_MS * Math.pow(2, attempt - 1);
34
+ const jitter = Math.random() * 0.3 * base;
35
+ return Math.min(RETRY_MAX_MS, Math.floor(base + jitter));
36
+ }
37
+
38
+ function _sleep(ms) {
39
+ return new Promise((res) => setTimeout(res, ms));
40
+ }
41
+
42
+ function _extractStatus(err) {
43
+ return err?.status ?? err?.response?.status ?? err?.statusCode ?? null;
44
+ }
45
+
46
+ class WebDAVClient {
47
+ constructor(opts = {}) {
48
+ this.url = String(opts.url || "").trim();
49
+ this.username = opts.username || "";
50
+ this.password = opts.password || "";
51
+ this.remotePath = (opts.remotePath || "/").replace(/\/+$/, "") || "/";
52
+ this._client = null;
53
+ if (!this.url) throw new Error("WebDAVClient: url 必填");
54
+ }
55
+
56
+ async _ensureClient() {
57
+ if (this._client) return this._client;
58
+ const mod = await _webdavLoader();
59
+ const createClient = mod.createClient || mod.default?.createClient;
60
+ if (typeof createClient !== "function") {
61
+ throw new Error("webdav module missing createClient");
62
+ }
63
+ this._client = createClient(this.url, {
64
+ username: this.username,
65
+ password: this.password,
66
+ });
67
+ return this._client;
68
+ }
69
+
70
+ _resolveRemote(filename) {
71
+ const safe = String(filename || "").replace(/^\/+/, "");
72
+ return `${this.remotePath}/${safe}`.replace(/\/{2,}/g, "/");
73
+ }
74
+
75
+ async _withRetry(label, fn) {
76
+ let lastErr;
77
+ for (let attempt = 1; attempt <= RETRY_MAX; attempt++) {
78
+ try {
79
+ return await fn();
80
+ } catch (err) {
81
+ lastErr = err;
82
+ const status = _extractStatus(err);
83
+ if (!_isRetriable(status) || attempt === RETRY_MAX) throw err;
84
+ await _sleep(_backoffMs(attempt));
85
+ }
86
+ }
87
+ throw lastErr;
88
+ }
89
+
90
+ async testConnection() {
91
+ try {
92
+ const client = await this._ensureClient();
93
+ await this._withRetry("testConnection", () =>
94
+ client.stat(this.remotePath),
95
+ );
96
+ return { ok: true };
97
+ } catch (err) {
98
+ const status = _extractStatus(err);
99
+ if (status === 404) {
100
+ return {
101
+ ok: false,
102
+ status,
103
+ error: `远端路径 ${this.remotePath} 不存在;请先在网盘里创建`,
104
+ };
105
+ }
106
+ if (status === 401 || status === 403) {
107
+ return {
108
+ ok: false,
109
+ status,
110
+ error: "认证失败(用户名 / 密码错误,或账户无权限)",
111
+ };
112
+ }
113
+ return { ok: false, status, error: err?.message || String(err) };
114
+ }
115
+ }
116
+
117
+ async putFile(filename, content, etag = null) {
118
+ const target = this._resolveRemote(filename);
119
+ try {
120
+ const client = await this._ensureClient();
121
+ const headers = {};
122
+ if (etag) headers["If-Match"] = etag;
123
+ const res = await this._withRetry("putFile", () =>
124
+ client.putFileContents(target, content, { overwrite: true, headers }),
125
+ );
126
+ let newEtag = null;
127
+ try {
128
+ const stat = await client.stat(target);
129
+ newEtag = stat?.etag ?? stat?.props?.getetag ?? null;
130
+ } catch (_e) {
131
+ /* non-fatal */
132
+ }
133
+ return { ok: true, etag: newEtag, raw: res };
134
+ } catch (err) {
135
+ const status = _extractStatus(err);
136
+ if (status === 412) return { ok: false, conflict: true, status };
137
+ return { ok: false, error: err?.message || String(err), status };
138
+ }
139
+ }
140
+
141
+ async deleteFile(filename, etag = null) {
142
+ const target = this._resolveRemote(filename);
143
+ try {
144
+ const client = await this._ensureClient();
145
+ const headers = {};
146
+ if (etag) headers["If-Match"] = etag;
147
+ await this._withRetry("deleteFile", () =>
148
+ client.deleteFile(target, { headers }),
149
+ );
150
+ return { ok: true };
151
+ } catch (err) {
152
+ const status = _extractStatus(err);
153
+ if (status === 404) return { ok: true, alreadyAbsent: true };
154
+ if (status === 412) return { ok: false, conflict: true, status };
155
+ return { ok: false, error: err?.message || String(err), status };
156
+ }
157
+ }
158
+
159
+ async getEtag(filename) {
160
+ const target = this._resolveRemote(filename);
161
+ try {
162
+ const client = await this._ensureClient();
163
+ const stat = await this._withRetry("getEtag", () => client.stat(target));
164
+ return stat?.etag ?? stat?.props?.getetag ?? null;
165
+ } catch (err) {
166
+ if (_extractStatus(err) === 404) return null;
167
+ throw err;
168
+ }
169
+ }
170
+
171
+ async listRemote(subPath = "") {
172
+ const target = this._resolveRemote(subPath);
173
+ const client = await this._ensureClient();
174
+ const items = await this._withRetry("listRemote", () =>
175
+ client.getDirectoryContents(target),
176
+ );
177
+ return (items || [])
178
+ .filter((it) => it && it.type === "file" && it.basename?.endsWith(".md"))
179
+ .map((it) => ({
180
+ filename: it.basename,
181
+ etag: it.etag ?? null,
182
+ size: it.size ?? 0,
183
+ lastmod: it.lastmod ?? null,
184
+ }));
185
+ }
186
+ }
187
+
188
+ export {
189
+ WebDAVClient,
190
+ RETRY_MAX,
191
+ RETRY_BASE_MS,
192
+ _setWebdavLoaderForTest,
193
+ _resetWebdavLoaderForTest,
194
+ };
@@ -1211,7 +1211,8 @@ function findWebPanelDist(staticDir) {
1211
1211
  return fs.existsSync(path.join(staticDir, "index.html")) ? staticDir : null;
1212
1212
  }
1213
1213
  // 1. Source tree: packages/web-panel/dist/
1214
- const sourceDist = path.resolve(__dirname, "../../web-panel/dist");
1214
+ // __dirname = packages/cli/src/lib/ so we need three "../" to reach packages/.
1215
+ const sourceDist = path.resolve(__dirname, "../../../web-panel/dist");
1215
1216
  if (fs.existsSync(path.join(sourceDist, "index.html"))) {
1216
1217
  return sourceDist;
1217
1218
  }
@@ -1 +0,0 @@
1
- import{o as ut,M as g,R as u,c as a,N as t,K as y,r as M,a as ee,L as r,O as i,u as D,P as o,S as f,a0 as dt,a1 as pt,Q as h,F as H,Y as de,$ as ct,Z as ft,f as Me}from"./vendor-M5lGV-wr.js";import{u as mt,_ as vt,d as A}from"./index-C52udT0_.js";import{R as $e,aA as yt,O as gt,ak as _t,h as kt,aB as wt,Q as bt,aC as ht,aD as xt,y as Ct,q as Pt,aE as At,a2 as Mt,m as $t,e as ze}from"./icons-CLQTHa5-.js";function pe(w){if(!w)return w;if(w.error)throw new Error(w.error);return w.result!==void 0?w.result:w}function Se(w,m,s,d,x){return typeof w.onMessage!="function"||typeof w._send!="function"?w.sendRaw({type:m,...s},x).then(pe):new Promise((V,Q)=>{const C=typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).slice(2)}`,B=`${m}.event`,j=`${m}.end`;let G=setTimeout(()=>{w.offMessage&&w.offMessage(C),Q(new Error(`stream timeout (${x}ms): ${m}`))},x);const F=w.onMessage(C,$=>{if(!(!$||$.id!==C)){if($.type===B&&typeof d=="function"){try{d($.event||$)}catch{}return}if($.type===j){clearTimeout(G),typeof F=="function"?F():w.offMessage&&w.offMessage(C),V(pe($));return}$.type==="error"&&(clearTimeout(G),typeof F=="function"?F():w.offMessage&&w.offMessage(C),Q(new Error($.message||"stream error")))}});w._send({id:C,type:m,...s})})}function zt(){const w=mt(),m=(s,d={},x=3e4)=>w.sendRaw({type:s,...d},x).then(pe);return{async health(){return await m("personal-data-hub.health",{},8e3)},async stats(){return await m("personal-data-hub.stats",{},8e3)},async listAdapters(){return await m("personal-data-hub.list-adapters",{},5e3)},async syncAdapter(s,d={}){return await m("personal-data-hub.sync-adapter",{name:s,options:d},12e4)},async syncAll(s={}){return await m("personal-data-hub.sync-all",{options:s},6e5)},async registerMock({name:s="mock",count:d=20,seed:x=1}={}){return await m("personal-data-hub.register-mock",{name:s,count:d,seed:x})},async unregister(s){return await m("personal-data-hub.unregister",{name:s})},async ask(s,d={}){return await m("personal-data-hub.ask",{question:s,options:d},18e4)},async queryEvents(s={}){return await m("personal-data-hub.query-events",s,1e4)},async recentAudit(s={}){return await m("personal-data-hub.recent-audit",s,1e4)},async testEmailAuth(s){return await m("personal-data-hub.test-email-auth",{account:s},3e4)},async registerEmail(s,d={}){return await m("personal-data-hub.register-email",{account:s,opts:d},15e3)},async unregisterEmail(s){return await m("personal-data-hub.unregister-email",{email:s},5e3)},async listEmailAccounts(){return await m("personal-data-hub.list-email-accounts",{},5e3)},async eventDetail(s){return await m("personal-data-hub.event-detail",{eventId:s},5e3)},async syncAdapterStream(s,d={},x){return await Se(w,"personal-data-hub.sync-adapter-stream",{name:s,options:d},x,6e5)},async syncAllStream(s={},d){return await Se(w,"personal-data-hub.sync-all-stream",{options:s},d,9e5)},async registerAlipay(s,d={}){return await m("personal-data-hub.register-alipay",{account:s,opts:d},15e3)},async unregisterAlipay(s){return await m("personal-data-hub.unregister-alipay",{email:s},5e3)},async listAlipayAccounts(){return await m("personal-data-hub.list-alipay-accounts",{},5e3)},async importAlipayBill({zipPath:s,csvPath:d,zipPassword:x}={}){return await m("personal-data-hub.import-alipay-bill",{zipPath:s,csvPath:d,zipPassword:x},3e5)},async reviewQueueList(s=50){return await m("personal-data-hub.review-queue-list",{limit:s},5e3)},async reviewDecision(s,d){return await m("personal-data-hub.review-decision",{reviewId:s,decision:d},5e3)},async manualMerge(s,d){return await m("personal-data-hub.manual-merge",{aId:s,bId:d},5e3)},async manualUnmerge(s){return await m("personal-data-hub.manual-unmerge",{personId:s},5e3)},async resolverDrain(s=50){return await m("personal-data-hub.resolver-drain",{limit:s},18e4)},async resolverStats(){return await m("personal-data-hub.resolver-stats",{},5e3)},async skillsList(){return await m("personal-data-hub.skills-list",{},5e3)},async runSkill(s,d={}){return await m("personal-data-hub.run-skill",{name:s,options:d},12e4)}}}const St={class:"pdh-page"},Lt={class:"pdh-header"},Dt={class:"kv"},Et={key:0,class:"kv"},Ot={key:1,class:"kv"},Ut={class:"kv"},qt={key:0,class:"kv hint"},It={style:{"margin-top":"12px",display:"flex","justify-content":"space-between","align-items":"center"}},Qt={key:0,style:{"margin-top":"12px"}},Rt={key:1,style:{"margin-top":"12px"}},Ht={class:"answer"},Ft={style:{"margin-top":"8px","font-size":"12px",color:"var(--text-color-secondary, #888)"}},Tt={key:2,style:{"margin-top":"8px"}},Nt={style:{display:"flex","align-items":"center",gap:"8px"}},Vt={class:"hint",style:{"margin-top":"4px"}},Bt={key:0,style:{"margin-top":"16px"}},Gt={class:"json-pre",style:{"max-height":"300px",overflow:"auto"}},Kt={key:0,style:{"margin-top":"8px"}},Zt={key:2,style:{"margin-top":"12px"}},jt={class:"kv",style:{"margin-bottom":"4px"}},Jt={key:0,style:{color:"#faad14"}},Wt={key:2,class:"kv hint"},Yt={key:3,class:"kv hint",style:{color:"#ff4d4f"}},Xt={key:3,style:{"margin-top":"12px"}},ea={key:2,style:{"margin-top":"8px"}},ta={key:1},aa={style:{"margin-left":"8px"}},la={key:3,class:"json-pre"},na={style:{"margin-left":"6px"}},sa={key:0,style:{"margin-left":"6px"}},oa={key:0,class:"hint",style:{"margin-top":"4px"}},ia={key:0,style:{"margin-top":"8px"}},ra={style:{"margin-bottom":"12px"}},ua={class:"hint"},da={class:"kv"},pa={class:"kv",style:{"margin-top":"4px"}},ca={class:"kv"},fa={key:0,class:"hint",style:{"margin-top":"4px"}},ma={key:1,style:{"font-size":"11px"}},va={__name:"PersonalDataHub",setup(w,{expose:m}){const s=zt(),d=M(null),x=M(null),V=M([]),Q=M(""),C=M(null),B=M(""),j=M(!1),G=M(!1),F=M([]),$=M(null),K=M(!1),p=ee({provider:"qq",email:"",authCode:"",host:"",port:993,pdfPasswordHints:{idCardLast6:"",phoneLast6:"",cardLast6:""}}),E=M(null),se=M(!1),_=M(null),I=M(null),Le=[{name:"analysis.spending",label:"消费分析",icon:wt,description:"总支出 / 商家排行 / 月度趋势"},{name:"analysis.relations",label:"人际关系",icon:bt,description:"与每个人的互动频率 / 主动比例"},{name:"analysis.footprint",label:"足迹",icon:ht,description:"常去地点 / 出行模式"},{name:"analysis.interests",label:"兴趣画像",icon:xt,description:"从购买 / 浏览 / 收藏抽兴趣"},{name:"analysis.timeline",label:"时间线",icon:Ct,description:"跨源事件串成故事"}],oe=M(!1),ie=M([]),J=ee({queue:{pending:0},mergeGroups:0,reviewQueue:0}),te=M(!1),P=ee({email:"",zipPassword:"",filePath:""}),z=M(null),v=ee({active:!1,adapter:"",phase:"",mailbox:"",current:0,total:0,attempt:1,errorMessage:""}),c=ee({refresh:!1,ask:!1,addMock:!1,syncAll:!1,sync:{},audit:!1,testEmail:!1,saveEmail:!1,eventDetail:!1,importAlipay:!1,reviewQueue:!1,resolverDrain:!1,skill:!1}),De=[{title:"名称",dataIndex:"name",key:"name",width:140},{title:"版本",dataIndex:"version",key:"version",width:80},{title:"能力",key:"capabilities"},{title:"敏感度",key:"sensitivity",width:140},{title:"操作",key:"actions",width:160,align:"right"}],Ee=[{title:"时间",key:"at",dataIndex:"at",width:170},{title:"动作",dataIndex:"action",key:"action",width:200},{title:"详情",key:"details"}],Oe=[{title:"日期",key:"occurredAt",width:100},{title:"描述",dataIndex:"description",key:"description"},{title:"金额",key:"amount",width:140,align:"right"}];function Ue(l){return l==="high"?"red":l==="medium"?"orange":"default"}function qe(l){if(!l)return"";const e=l.entityCounts||{};return`events=${e.events??0} persons=${e.persons??0} | raw=${l.rawCount??0} invalid=${l.invalidCount??0} | KG triples=${l.kgTripleCount??0} RAG docs=${l.ragDocCount??0} | ${l.durationMs??0}ms`}async function R(){c.refresh=!0;try{d.value=await s.health(),x.value=await s.stats(),V.value=await s.listAdapters()}catch(l){A.error("刷新失败: "+l.message)}finally{c.refresh=!1}}async function ce(){if(Q.value.trim()){c.ask=!0,B.value="",C.value=null;try{C.value=await s.ask(Q.value.trim(),{acceptNonLocal:j.value})}catch(l){B.value=l.message}finally{c.ask=!1}}}async function Ie(){c.addMock=!0;try{await s.registerMock({count:30,seed:Date.now()%1e3}),await R(),A.success("MockAdapter 已注册(30 条 mock 数据 ready 同步)")}catch(l){A.error("注册失败: "+l.message)}finally{c.addMock=!1}}function fe(l=""){v.active=!0,v.adapter=l,v.phase="starting",v.mailbox="",v.current=0,v.total=0,v.attempt=1,v.errorMessage=""}function me(l){l&&(l.adapter&&(v.adapter=l.adapter),l.phase&&(v.phase=l.phase),typeof l.current=="number"&&(v.current=l.current),typeof l.total=="number"&&(v.total=l.total),typeof l.attempt=="number"&&(v.attempt=l.attempt),l.mailbox&&(v.mailbox=l.mailbox),l.phase==="error"&&(v.errorMessage=l.message||"sync error"))}async function Qe(l){c.sync[l]=!0,fe(l);try{typeof s.syncAdapterStream=="function"?$.value=await s.syncAdapterStream(l,{},me):$.value=await s.syncAdapter(l),await R()}catch(e){A.error(`同步 ${l} 失败: ${e.message}`)}finally{c.sync[l]=!1,v.active=!1}}async function Re(){c.syncAll=!0,fe("(all)");try{const l=typeof s.syncAllStream=="function"?await s.syncAllStream({},me):await s.syncAll();$.value=l?.[l.length-1]||null,await R(),A.success(`已同步 ${l?.length||0} 个 adapter`)}catch(l){A.error("同步失败: "+l.message)}finally{c.syncAll=!1,v.active=!1}}async function He(l){try{await s.unregister(l),await R()}catch(e){A.error("移除失败: "+e.message)}}async function Fe(l){if(l){c.audit=!0;try{F.value=await s.recentAudit({limit:200})}catch(e){A.error("审计日志加载失败: "+e.message)}finally{c.audit=!1}}}const ae=Me(()=>!(!p.email||!p.email.includes("@")||!p.authCode||p.authCode.length<4||p.provider==="custom"&&!p.host));function Te(l){return{qq:"QQ: 邮箱 → 设置 → 账户 → IMAP/SMTP → 开启 → 生成授权码",163:"163: 邮箱 → 设置 → POP3/SMTP/IMAP → 开启 IMAP/SMTP 服务 → 授权密码",189:"189: 设置 → 第三方客户端授权码",outlook:"Outlook: account.microsoft.com/security → App password",gmail:"Gmail: myaccount.google.com/apppasswords (需开启 2FA)",custom:"联系你的邮箱管理员获取 IMAP 端点 + app-password"}[l]||"请输入服务商授权码(不是登录密码)"}function ve(){p.provider="qq",p.email="",p.authCode="",p.host="",p.port=993,p.pdfPasswordHints={idCardLast6:"",phoneLast6:"",cardLast6:""},E.value=null}function ye(){const l={provider:p.provider,email:p.email.trim(),authCode:p.authCode};return p.provider==="custom"&&(l.host=p.host.trim(),l.port=p.port||993,l.secure=!0),l}function Ne(){const l={};for(const e of Object.keys(p.pdfPasswordHints)){const k=p.pdfPasswordHints[e];typeof k=="string"&&k.trim().length>0&&(l[e]=k.trim())}return Object.keys(l).length>0?l:null}async function Ve(){if(ae.value){c.testEmail=!0,E.value=null;try{E.value=await s.testEmailAuth(ye())}catch(l){E.value={ok:!1,error:l.message}}finally{c.testEmail=!1}}}async function Be(){if(!(!ae.value||!E.value?.ok)){c.saveEmail=!0;try{const l={},e=Ne();e&&(l.pdfPasswordHints=e),await s.registerEmail(ye(),l),A.success("邮箱账号已注册"),K.value=!1,ve(),await R()}catch(l){A.error("保存失败: "+l.message)}finally{c.saveEmail=!1}}}const ge=Me(()=>!(!P.email||!P.email.includes("@")||!P.filePath||P.filePath.length<3));function Ge(){P.email="",P.zipPassword="",P.filePath="",z.value=null}async function Ke(){if(ge.value){c.importAlipay=!0,z.value=null;try{await s.registerAlipay({email:P.email.trim(),zipPassword:P.zipPassword||void 0});const e=/\.zip$/i.test(P.filePath)?{zipPath:P.filePath,zipPassword:P.zipPassword||void 0}:{csvPath:P.filePath};z.value=await s.importAlipayBill(e),z.value?.status==="ok"?(A.success(`导入成功 — ${z.value.entityCounts?.events||0} 笔交易`),await R()):A.error("导入失败: "+(z.value?.error||z.value?.status))}catch(l){z.value={status:"error",error:l.message},A.error("导入失败: "+l.message)}finally{c.importAlipay=!1}}}async function _e(l){if(l){c.eventDetail=!0,se.value=!0;try{_.value=await s.eventDetail(l)}catch(e){_.value=null,A.error("事件详情加载失败: "+e.message)}finally{c.eventDetail=!1}}}m({showEventDetail:_e});async function Ze(l){c.skill=!0,I.value=null;try{I.value=await s.runSkill(l,{})}catch(e){A.error(`${l} 失败: ${e.message}`)}finally{c.skill=!1}}async function le(){c.reviewQueue=!0;try{ie.value=await s.reviewQueueList(50);const l=await s.resolverStats();Object.assign(J,l)}catch(l){A.error("待消歧加载失败: "+l.message)}finally{c.reviewQueue=!1}}async function je(){oe.value=!0,await le()}async function re(l,e){try{await s.reviewDecision(l,e),A.success(`已记录决策: ${e}`),await le()}catch(k){A.error("决策失败: "+k.message)}}async function Je(){c.resolverDrain=!0;try{const l=await s.resolverDrain(20);A.success(`drain 完成 — same=${l.same} different=${l.different} review=${l.review}`),await le()}catch(l){A.error("drain 失败: "+l.message)}finally{c.resolverDrain=!1}}async function We(){try{const l=await s.resolverStats();Object.assign(J,l)}catch{}}return ut(()=>{R(),We()}),(l,e)=>{const k=y("a-button"),Ye=y("a-badge"),L=y("a-space"),S=y("a-tag"),U=y("a-card"),W=y("a-col"),ke=y("a-row"),Xe=y("a-textarea"),et=y("a-checkbox"),q=y("a-alert"),T=y("a-divider"),tt=y("a-spin"),at=y("a-popconfirm"),ue=y("a-table"),we=y("a-empty"),be=y("a-progress"),Z=y("a-select-option"),lt=y("a-select"),O=y("a-form-item"),N=y("a-input"),he=y("a-tooltip"),xe=y("a-input-password"),nt=y("a-input-number"),Ce=y("a-form"),Y=y("a-drawer"),X=y("a-descriptions-item"),st=y("a-descriptions"),ot=y("a-list-item-meta"),Pe=y("a-list-item"),Ae=y("a-list"),it=y("a-collapse-panel"),rt=y("a-collapse");return r(),g("div",St,[u("div",Lt,[e[26]||(e[26]=u("div",null,[u("h2",{class:"page-title"},"个人数据中台"),u("p",{class:"page-sub"}," 让数据回归个人 — 各 app 数据本地加密落盘,本地 LLM 跨源分析,零云端外传。 ")],-1)),a(L,null,{default:t(()=>[a(k,{loading:c.refresh,onClick:R},{icon:t(()=>[a(D($e))]),default:t(()=>[e[23]||(e[23]=i(" 刷新 ",-1))]),_:1},8,["loading"]),a(Ye,{count:J.reviewQueue,offset:[0,0]},{default:t(()=>[a(k,{type:"primary",ghost:"",onClick:je},{icon:t(()=>[a(D(yt))]),default:t(()=>[e[24]||(e[24]=i(" 待消歧 ",-1))]),_:1})]),_:1},8,["count"]),a(k,{type:"primary",ghost:"",onClick:e[0]||(e[0]=n=>G.value=!0)},{icon:t(()=>[a(D(gt))]),default:t(()=>[e[25]||(e[25]=i(" 审计日志 ",-1))]),_:1})]),_:1})]),a(ke,{gutter:16,style:{"margin-bottom":"16px"}},{default:t(()=>[a(W,{xs:24,sm:12,md:6},{default:t(()=>[a(U,{size:"small",title:"Vault"},{extra:t(()=>[a(S,{color:d.value?.vault?.ok?"green":"red"},{default:t(()=>[i(o(d.value?.vault?.ok?"正常":"未就绪"),1)]),_:1},8,["color"])]),default:t(()=>[u("div",Dt,"schema v"+o(d.value?.vault?.schemaVersion??"?"),1),x.value?.vault?(r(),g("div",Et," 事件 "+o(x.value.vault.events)+" · 联系人 "+o(x.value.vault.persons),1)):f("",!0),x.value?.vault?(r(),g("div",Ot," 地点 "+o(x.value.vault.places)+" · 商品 "+o(x.value.vault.items)+" · 主题 "+o(x.value.vault.topics),1)):f("",!0)]),_:1})]),_:1}),a(W,{xs:24,sm:12,md:6},{default:t(()=>[a(U,{size:"small",title:"本地 LLM"},{extra:t(()=>[a(S,{color:d.value?.llm?.ok?d.value.llm.isLocal?"green":"orange":"red"},{default:t(()=>[i(o(d.value?.llm?.ok?d.value.llm.isLocal?"本地":"非本地":"未就绪"),1)]),_:1},8,["color"])]),default:t(()=>[u("div",Ut,o(d.value?.llm?.name||"—"),1),d.value?.llm?.ok&&!d.value.llm.isLocal?(r(),g("div",qt," ⚠️ 非本地 — ask 会被隐私 gate 拒绝,除非显式 acceptNonLocal ")):f("",!0)]),_:1})]),_:1}),a(W,{xs:24,sm:12,md:6},{default:t(()=>[a(U,{size:"small",title:"KG 索引"},{extra:t(()=>[a(S,{color:d.value?.kgSink?.ok?"green":"default"},{default:t(()=>[i(o(d.value?.kgSink?.ok?"已连接":"不可用"),1)]),_:1},8,["color"])]),default:t(()=>[e[27]||(e[27]=u("div",{class:"kv"},"events / persons → cc knowledge-graph 实体 + 关系",-1))]),_:1})]),_:1}),a(W,{xs:24,sm:12,md:6},{default:t(()=>[a(U,{size:"small",title:"RAG 索引"},{extra:t(()=>[a(S,{color:d.value?.ragSink?.ok?"green":"default"},{default:t(()=>[i(o(d.value?.ragSink?.ok?"已连接":"不可用"),1)]),_:1},8,["color"])]),default:t(()=>[e[28]||(e[28]=u("div",{class:"kv"},"文本 → BM25(vector 留待后续 phase)",-1))]),_:1})]),_:1})]),_:1}),a(U,{style:{"margin-bottom":"16px"}},{title:t(()=>[a(L,null,{default:t(()=>[a(D(kt)),e[29]||(e[29]=u("span",null,"问我数据",-1))]),_:1})]),default:t(()=>[a(Xe,{value:Q.value,"onUpdate:value":e[1]||(e[1]=n=>Q.value=n),rows:2,placeholder:"例:上个月在淘宝总共花了多少?/我妈生日那周买了啥送哪儿?",onKeydown:dt(pt(ce,["exact","prevent"]),["enter"])},null,8,["value","onKeydown"]),u("div",It,[a(et,{checked:j.value,"onUpdate:checked":e[2]||(e[2]=n=>j.value=n)},{default:t(()=>[...e[30]||(e[30]=[i("允许非本地 LLM (volcengine / anthropic 等)",-1)])]),_:1},8,["checked"]),a(k,{type:"primary",loading:c.ask,disabled:!Q.value.trim(),onClick:ce},{icon:t(()=>[a(D(_t))]),default:t(()=>[e[31]||(e[31]=i(" 提问 ",-1))]),_:1},8,["loading","disabled"])]),B.value?(r(),g("div",Qt,[a(q,{type:"error","show-icon":"",message:B.value},null,8,["message"])])):f("",!0),C.value?(r(),g("div",Rt,[C.value.warning==="no-facts"?(r(),h(q,{key:0,type:"warning","show-icon":"",message:"vault 里没找到匹配的事件('no-facts')—— 先同步几个 adapter 让数据进 vault",style:{"margin-bottom":"12px"}})):C.value.warning==="hallucinated-citations"?(r(),h(q,{key:1,type:"warning","show-icon":"",message:`LLM 引用了 ${C.value.hallucinatedCitations?.length||0} 个不存在的 event id —— 模型在编造`,style:{"margin-bottom":"12px"}},null,8,["message"])):f("",!0),u("div",Ht,o(C.value.answer),1),u("div",Ft," 引用 "+o(C.value.citations?.length||0)+" 条事实 · "+o(C.value.facts?.length||0)+" facts 入 prompt · "+o(C.value.durationMs)+"ms · "+o(C.value.model),1),C.value.citations?.length?(r(),g("div",Tt,[e[32]||(e[32]=u("span",{style:{"font-size":"12px",color:"var(--text-color-secondary, #888)"}},"事件链接(点击查看明细 / PDF 解密结果):",-1)),a(L,{style:{"margin-top":"4px"},wrap:""},{default:t(()=>[(r(!0),g(H,null,de(C.value.citations,n=>(r(),h(S,{key:n,color:"blue",style:{cursor:"pointer"},onClick:b=>_e(n)},{default:t(()=>[i(o(n),1)]),_:2},1032,["onClick"]))),128))]),_:1})])):f("",!0)])):f("",!0)]),_:1}),a(U,{style:{"margin-bottom":"16px"}},{title:t(()=>[a(L,null,{default:t(()=>[a(D(Pt)),e[33]||(e[33]=u("span",null,"分析 skill (Phase 11)",-1))]),_:1})]),extra:t(()=>[a(S,{color:"purple"},{default:t(()=>[...e[34]||(e[34]=[i("5 内置",-1)])]),_:1})]),default:t(()=>[a(ke,{gutter:[12,12]},{default:t(()=>[(r(),g(H,null,de(Le,n=>a(W,{xs:24,sm:12,md:8,key:n.name},{default:t(()=>[a(U,{size:"small",hoverable:"",onClick:b=>Ze(n.name)},{default:t(()=>[u("div",Nt,[(r(),h(ct(n.icon),{style:{"font-size":"18px",color:"#722ed1"}})),u("strong",null,o(n.label),1)]),u("div",Vt,o(n.description),1)]),_:2},1032,["onClick"])]),_:2},1024)),64))]),_:1}),I.value?(r(),g("div",Bt,[a(T,{plain:"",orientation:"left"},{default:t(()=>[i(o(I.value.skill)+" 结果",1)]),_:1}),a(tt,{spinning:c.skill},{default:t(()=>[u("pre",Gt,o(JSON.stringify(I.value,null,2)),1),I.value.llm_commentary||I.value.llm_narrative?(r(),g("div",Kt,[a(q,{type:"info",message:I.value.llm_commentary||I.value.llm_narrative},null,8,["message"])])):f("",!0)]),_:1},8,["spinning"])])):f("",!0)]),_:1}),a(U,{style:{"margin-bottom":"16px"}},{title:t(()=>[a(L,null,{default:t(()=>[a(D($t)),e[35]||(e[35]=u("span",null,"Adapters",-1))]),_:1})]),extra:t(()=>[a(L,null,{default:t(()=>[a(k,{onClick:e[3]||(e[3]=n=>K.value=!0)},{icon:t(()=>[a(D(At))]),default:t(()=>[e[36]||(e[36]=i(" 添加邮箱账号 ",-1))]),_:1}),a(k,{onClick:e[4]||(e[4]=n=>te.value=!0)},{icon:t(()=>[a(D(Mt))]),default:t(()=>[e[37]||(e[37]=i(" 导入支付宝账单 ",-1))]),_:1}),a(k,{onClick:Ie,loading:c.addMock},{default:t(()=>[...e[38]||(e[38]=[i(" 注册 MockAdapter(开发) ",-1)])]),_:1},8,["loading"]),a(k,{type:"primary",onClick:Re,loading:c.syncAll,disabled:!V.value.length},{default:t(()=>[...e[39]||(e[39]=[i(" 同步全部 ",-1)])]),_:1},8,["loading","disabled"])]),_:1})]),default:t(()=>[V.value.length?(r(),h(ue,{key:0,columns:De,"data-source":V.value,pagination:!1,"row-key":n=>n.name,size:"middle"},{bodyCell:t(({column:n,record:b})=>[n.key==="sensitivity"?(r(),g(H,{key:0},[a(S,{color:Ue(b.sensitivity)},{default:t(()=>[i(o(b.sensitivity),1)]),_:2},1032,["color"]),b.legalGate?(r(),h(S,{key:0,color:"red",style:{"margin-left":"4px"}},{default:t(()=>[...e[40]||(e[40]=[i("需法律确认",-1)])]),_:1})):f("",!0)],64)):n.key==="capabilities"?(r(!0),g(H,{key:1},de(b.capabilities,ne=>(r(),h(S,{key:ne,style:{"margin-right":"4px"}},{default:t(()=>[i(o(ne),1)]),_:2},1024))),128)):n.key==="actions"?(r(),h(L,{key:2},{default:t(()=>[a(k,{size:"small",loading:c.sync[b.name],onClick:ne=>Qe(b.name)},{default:t(()=>[...e[41]||(e[41]=[i(" 同步 ",-1)])]),_:1},8,["loading","onClick"]),a(at,{title:`从注册表移除 ${b.name}?(vault 数据不会删除)`,onConfirm:ne=>He(b.name)},{default:t(()=>[a(k,{size:"small",danger:""},{default:t(()=>[...e[42]||(e[42]=[i("移除",-1)])]),_:1})]),_:1},8,["title","onConfirm"])]),_:2},1024)):f("",!0)]),_:1},8,["data-source","row-key"])):(r(),h(we,{key:1,description:"无已注册 adapter — 点上方按钮注册 MockAdapter 看效果"})),v.active?(r(),g("div",Zt,[a(U,{size:"small",bordered:!0},{default:t(()=>[u("div",jt,[e[43]||(e[43]=u("strong",null,"同步进行中",-1)),i(" · "+o(v.adapter)+" · "+o(v.phase||"...")+" ",1),v.attempt&&v.attempt>1?(r(),g("span",Jt," (重试 #"+o(v.attempt)+") ",1)):f("",!0)]),v.total>0?(r(),h(be,{key:0,percent:Math.round(v.current/v.total*100),status:v.errorMessage?"exception":"active",size:"small"},null,8,["percent","status"])):(r(),h(be,{key:1,percent:0,status:"active",size:"small"})),v.mailbox?(r(),g("div",Wt," 邮箱 "+o(v.mailbox)+" · "+o(v.current)+" / "+o(v.total),1)):f("",!0),v.errorMessage?(r(),g("div",Yt,o(v.errorMessage),1)):f("",!0)]),_:1})])):f("",!0),$.value?(r(),g("div",Xt,[a(q,{type:$.value.status==="ok"?"success":"error","show-icon":"",message:`同步 ${$.value.adapter}: ${$.value.status}`,description:qe($.value)},null,8,["type","message","description"])])):f("",!0)]),_:1}),a(Y,{open:K.value,"onUpdate:open":e[14]||(e[14]=n=>K.value=n),title:"添加邮箱账号",placement:"right",width:"560","destroy-on-close":!0,onClose:ve},{footer:t(()=>[a(L,null,{default:t(()=>[a(k,{onClick:e[13]||(e[13]=n=>K.value=!1)},{default:t(()=>[...e[53]||(e[53]=[i("取消",-1)])]),_:1}),a(k,{loading:c.testEmail,disabled:!ae.value,onClick:Ve},{default:t(()=>[...e[54]||(e[54]=[i(" 测试连接 ",-1)])]),_:1},8,["loading","disabled"]),a(k,{type:"primary",loading:c.saveEmail,disabled:!ae.value||!E.value?.ok,onClick:Be},{default:t(()=>[...e[55]||(e[55]=[i(" 保存并注册 ",-1)])]),_:1},8,["loading","disabled"])]),_:1})]),default:t(()=>[a(q,{message:"数据回归个人 — 凭证落本地加密文件(与 vault 主密钥同目录),同步动作 100% 本地。",type:"info","show-icon":"",style:{"margin-bottom":"16px"}}),a(Ce,{layout:"vertical",model:p},{default:t(()=>[a(O,{label:"邮箱服务商",required:""},{default:t(()=>[a(lt,{value:p.provider,"onUpdate:value":e[5]||(e[5]=n=>p.provider=n),placeholder:"选择服务商"},{default:t(()=>[a(Z,{value:"qq"},{default:t(()=>[...e[44]||(e[44]=[i("QQ 邮箱 (imap.qq.com)",-1)])]),_:1}),a(Z,{value:"163"},{default:t(()=>[...e[45]||(e[45]=[i("网易邮箱 163/126",-1)])]),_:1}),a(Z,{value:"189"},{default:t(()=>[...e[46]||(e[46]=[i("189 邮箱",-1)])]),_:1}),a(Z,{value:"outlook"},{default:t(()=>[...e[47]||(e[47]=[i("Outlook / Hotmail",-1)])]),_:1}),a(Z,{value:"gmail"},{default:t(()=>[...e[48]||(e[48]=[i("Gmail",-1)])]),_:1}),a(Z,{value:"custom"},{default:t(()=>[...e[49]||(e[49]=[i("自定义 IMAP",-1)])]),_:1})]),_:1},8,["value"])]),_:1}),a(O,{label:"邮箱地址",required:""},{default:t(()=>[a(N,{value:p.email,"onUpdate:value":e[6]||(e[6]=n=>p.email=n),placeholder:"you@qq.com",autocomplete:"off"},null,8,["value"])]),_:1}),a(O,{required:""},{label:t(()=>[a(L,null,{default:t(()=>[e[50]||(e[50]=u("span",null,"授权码(非登录密码)",-1)),a(he,{title:Te(p.provider)},{default:t(()=>[a(D(ze),{style:{color:"#888"}})]),_:1},8,["title"])]),_:1})]),default:t(()=>[a(xe,{value:p.authCode,"onUpdate:value":e[7]||(e[7]=n=>p.authCode=n),placeholder:"例:QQ 邮箱 设置 → 账户 → 开启 IMAP/SMTP → 生成的授权码",autocomplete:"off"},null,8,["value"])]),_:1}),p.provider==="custom"?(r(),h(O,{key:0,label:"IMAP host"},{default:t(()=>[a(N,{value:p.host,"onUpdate:value":e[8]||(e[8]=n=>p.host=n),placeholder:"mail.example.com"},null,8,["value"])]),_:1})):f("",!0),p.provider==="custom"?(r(),h(O,{key:1,label:"端口"},{default:t(()=>[a(nt,{value:p.port,"onUpdate:value":e[9]||(e[9]=n=>p.port=n),min:1,max:65535,"default-value":993},null,8,["value"])]),_:1})):f("",!0),a(T,{orientation:"left",plain:""},{default:t(()=>[...e[51]||(e[51]=[i("PDF 账单解密提示(可选)",-1)])]),_:1}),e[52]||(e[52]=u("p",{class:"hint"},"银行 PDF 月结大多加密;提供几个常用候选项让 Phase 5.5 自动解锁:",-1)),a(O,{label:"身份证后 6 位"},{default:t(()=>[a(N,{value:p.pdfPasswordHints.idCardLast6,"onUpdate:value":e[10]||(e[10]=n=>p.pdfPasswordHints.idCardLast6=n),placeholder:"123456",autocomplete:"off"},null,8,["value"])]),_:1}),a(O,{label:"手机后 6 位"},{default:t(()=>[a(N,{value:p.pdfPasswordHints.phoneLast6,"onUpdate:value":e[11]||(e[11]=n=>p.pdfPasswordHints.phoneLast6=n),placeholder:"123456",autocomplete:"off"},null,8,["value"])]),_:1}),a(O,{label:"信用卡尾 6 位"},{default:t(()=>[a(N,{value:p.pdfPasswordHints.cardLast6,"onUpdate:value":e[12]||(e[12]=n=>p.pdfPasswordHints.cardLast6=n),placeholder:"123456",autocomplete:"off"},null,8,["value"])]),_:1}),E.value?(r(),g("div",ea,[a(q,{type:E.value.ok?"success":"error","show-icon":"",message:E.value.ok?"凭证有效 — 可以保存":`认证失败: ${E.value.reason||E.value.error}`},null,8,["type","message"])])):f("",!0)]),_:1},8,["model"])]),_:1},8,["open"]),a(Y,{open:se.value,"onUpdate:open":e[15]||(e[15]=n=>se.value=n),title:_.value?`事件 ${_.value.event.id}`:"加载中...",placement:"right",width:"640","destroy-on-close":!0},{default:t(()=>[_.value?(r(),g(H,{key:0},[a(st,{column:1,size:"small",bordered:""},{default:t(()=>[a(X,{label:"类型"},{default:t(()=>[i(o(_.value.event.subtype),1)]),_:1}),a(X,{label:"发生于"},{default:t(()=>[i(o(new Date(_.value.event.occurredAt).toLocaleString()),1)]),_:1}),a(X,{label:"actor"},{default:t(()=>[i(o(_.value.event.actor),1)]),_:1}),_.value.event.content?.title?(r(),h(X,{key:0,label:"标题"},{default:t(()=>[i(o(_.value.event.content.title),1)]),_:1})):f("",!0),_.value.event.source?.adapter?(r(),h(X,{key:1,label:"来源 adapter"},{default:t(()=>[i(o(_.value.event.source.adapter)+" @ v"+o(_.value.event.source.adapterVersion),1)]),_:1})):f("",!0)]),_:1}),_.value.classification?(r(),h(T,{key:0,orientation:"left",plain:""},{default:t(()=>[...e[56]||(e[56]=[i("分类",-1)])]),_:1})):f("",!0),_.value.classification?(r(),g("div",ta,[a(S,{color:"blue"},{default:t(()=>[i(o(_.value.classification.category),1)]),_:1}),a(S,null,{default:t(()=>[i(o(_.value.classification.layer),1)]),_:1}),u("span",aa,"置信 "+o(Math.round((_.value.classification.confidence||0)*100))+"%",1)])):f("",!0),_.value.extraction?(r(),h(T,{key:2,orientation:"left",plain:""},{default:t(()=>[i("结构化字段("+o(_.value.extraction.template)+")",1)]),_:1})):f("",!0),_.value.extraction?(r(),g("pre",la,o(JSON.stringify(_.value.extraction.fields,null,2)),1)):f("",!0),_.value.extraction?.pdfExtraction?(r(),h(T,{key:4,orientation:"left",plain:""},{default:t(()=>[...e[57]||(e[57]=[i("PDF 解密 / 解析",-1)])]),_:1})):f("",!0),_.value.extraction?.pdfExtraction?(r(),h(Ae,{key:5,"data-source":_.value.extraction.pdfExtraction,size:"small"},{renderItem:t(({item:n})=>[a(Pe,null,{default:t(()=>[a(ot,{title:n.filename},{description:t(()=>[u("div",null,[a(S,{color:n.decrypted?"green":"red"},{default:t(()=>[i(o(n.decrypted?"已解密":"解密失败"),1)]),_:2},1032,["color"]),u("span",na,"尝试 "+o(n.attempted)+" 次",1),n.transactionsExtracted!=null?(r(),g("span",sa," · 提取 "+o(n.transactionsExtracted)+" 条交易 ",1)):f("",!0)]),n.error?(r(),g("div",oa,o(n.error),1)):f("",!0)]),_:2},1032,["title"])]),_:2},1024)]),_:1},8,["data-source"])):f("",!0),_.value.extraction?.fields?.transactions?.length?(r(),g(H,{key:6},[a(T,{orientation:"left",plain:""},{default:t(()=>[...e[58]||(e[58]=[i("交易明细",-1)])]),_:1}),a(ue,{columns:Oe,"data-source":_.value.extraction.fields.transactions,pagination:{pageSize:10,size:"small"},"row-key":(n,b)=>b,size:"small"},{bodyCell:t(({column:n,record:b})=>[n.key==="occurredAt"?(r(),g(H,{key:0},[i(o(new Date(b.occurredAtMs).toLocaleDateString()),1)],64)):n.key==="amount"?(r(),g("span",{key:1,class:ft(b.amount.direction==="in"?"amount-in":"amount-out")},o(b.amount.direction==="in"?"+":"-")+o(b.amount.value.toFixed(2))+" "+o(b.amount.currency),3)):f("",!0)]),_:1},8,["data-source","row-key"])],64)):f("",!0)],64)):(r(),h(we,{key:1,description:"无事件数据"}))]),_:1},8,["open","title"]),a(Y,{open:te.value,"onUpdate:open":e[20]||(e[20]=n=>te.value=n),title:"导入支付宝账单",placement:"right",width:"560","destroy-on-close":!0,onClose:Ge},{footer:t(()=>[a(L,null,{default:t(()=>[a(k,{onClick:e[19]||(e[19]=n=>te.value=!1)},{default:t(()=>[...e[64]||(e[64]=[i("关闭",-1)])]),_:1}),a(k,{type:"primary",loading:c.importAlipay,disabled:!ge.value,onClick:Ke},{default:t(()=>[...e[65]||(e[65]=[i(" 注册账户 + 导入 ",-1)])]),_:1},8,["loading","disabled"])]),_:1})]),default:t(()=>[a(q,{message:"支付宝官方导出 CSV — 服务器侧全量、稳定无风控。3 分钟拿到 12 个月流水。",type:"info","show-icon":"",style:{"margin-bottom":"16px"}}),a(rt,{bordered:!1,style:{"margin-bottom":"12px"}},{default:t(()=>[a(it,{header:"如何导出账单(首次必看)"},{default:t(()=>[...e[59]||(e[59]=[u("ol",{style:{"padding-left":"18px","font-size":"13px"}},[u("li",null,"支付宝 app → 我的 → 账单 → 右上角 ⋯"),u("li",null,'点 "开具交易流水证明"'),u("li",null,"选月份范围(最长 12 个月)"),u("li",null,'用途选 "个人对账"'),u("li",null,"发送到你的绑定邮箱"),u("li",null,[i("从邮箱下载 "),u("code",null,"alipay_record_*.zip")]),u("li",null,"解压密码 = 你的身份证后 6 位")],-1)])]),_:1})]),_:1}),a(Ce,{layout:"vertical",model:P},{default:t(()=>[a(O,{label:"支付宝绑定邮箱(账户标识)",required:""},{default:t(()=>[a(N,{value:P.email,"onUpdate:value":e[16]||(e[16]=n=>P.email=n),placeholder:"alipay-bound@example.com",autocomplete:"off"},null,8,["value"])]),_:1}),a(O,null,{label:t(()=>[a(L,null,{default:t(()=>[e[60]||(e[60]=u("span",null,"ZIP 密码(身份证后 6 位)",-1)),a(he,{title:"支付宝 ZIP 默认密码 = 身份证号后 6 位。也支持自定义密码。"},{default:t(()=>[a(D(ze),{style:{color:"#888"}})]),_:1})]),_:1})]),default:t(()=>[a(xe,{value:P.zipPassword,"onUpdate:value":e[17]||(e[17]=n=>P.zipPassword=n),placeholder:"例:123456",autocomplete:"off"},null,8,["value"]),e[61]||(e[61]=u("div",{class:"hint",style:{"margin-top":"4px"}}," 空白则解析时再问,或导入的 ZIP 未加密。 ",-1))]),_:1}),a(T,{orientation:"left",plain:""},{default:t(()=>[...e[62]||(e[62]=[i("选择文件",-1)])]),_:1}),a(O,{label:"ZIP 或 CSV 文件路径"},{default:t(()=>[a(N,{value:P.filePath,"onUpdate:value":e[18]||(e[18]=n=>P.filePath=n),placeholder:"C:\\\\Users\\\\you\\\\Downloads\\\\alipay_record_xxx.zip","allow-clear":""},null,8,["value"]),e[63]||(e[63]=u("div",{class:"hint",style:{"margin-top":"4px"}}," 桌面版可通过 Electron 文件选择器自动填充;web-shell 复制完整路径。 ",-1))]),_:1}),z.value?(r(),g("div",ia,[a(q,{type:z.value.status==="ok"?"success":"error","show-icon":"",message:z.value.status==="ok"?`导入成功 — ${z.value.entityCounts?.events||0} 笔交易`:`导入失败: ${z.value.error||z.value.status}`,description:z.value.status==="ok"?`${z.value.entityCounts?.persons||0} 个交易对方 · ${z.value.kgTripleCount||0} KG triples · ${z.value.durationMs||0}ms`:null},null,8,["type","message","description"])])):f("",!0)]),_:1},8,["model"])]),_:1},8,["open"]),a(Y,{open:oe.value,"onUpdate:open":e[21]||(e[21]=n=>oe.value=n),title:"待消歧(EntityResolver 模糊判定)",placement:"right",width:"640","destroy-on-close":!0},{default:t(()=>[ie.value.length===0&&!c.reviewQueue?(r(),h(q,{key:0,type:"success","show-icon":"",message:"无待消歧 pair — 所有跨源 Person 已确定。",style:{"margin-bottom":"12px"}})):f("",!0),u("div",ra,[a(L,null,{default:t(()=>[a(k,{loading:c.reviewQueue,onClick:le},{icon:t(()=>[a(D($e))]),default:t(()=>[e[66]||(e[66]=i(" 刷新 ",-1))]),_:1},8,["loading"]),a(k,{loading:c.resolverDrain,onClick:Je},{default:t(()=>[...e[67]||(e[67]=[i(" 手动 drain 队列 ",-1)])]),_:1},8,["loading"]),u("span",ua," queue: "+o(J.queue?.pending||0)+" pending · "+o(J.mergeGroups||0)+" groups ",1)]),_:1})]),a(Ae,{"data-source":ie.value,pagination:{pageSize:5,size:"small"},size:"small"},{renderItem:t(({item:n})=>[a(Pe,null,{default:t(()=>[a(U,{size:"small",style:{width:"100%"}},{default:t(()=>[u("div",da,[u("strong",null,"Pair #"+o(n.id),1),n.embed_sim?(r(),h(S,{key:0,color:"blue",style:{"margin-left":"8px"}},{default:t(()=>[i(" sim "+o(Number(n.embed_sim).toFixed(2)),1)]),_:2},1024)):f("",!0),n.llm_verdict?(r(),h(S,{key:1,color:n.llm_verdict==="yes"?"green":n.llm_verdict==="no"?"red":"orange",style:{"margin-left":"4px"}},{default:t(()=>[i(" LLM: "+o(n.llm_verdict),1)]),_:2},1032,["color"])):f("",!0)]),u("div",pa,"A: "+o(n.a_person_id),1),u("div",ca,"B: "+o(n.b_person_id),1),n.llm_reason?(r(),g("div",fa," LLM 理由: "+o(n.llm_reason),1)):f("",!0),a(L,{style:{"margin-top":"8px"}},{default:t(()=>[a(k,{size:"small",type:"primary",onClick:b=>re(n.id,"same")},{default:t(()=>[...e[68]||(e[68]=[i("同一人",-1)])]),_:1},8,["onClick"]),a(k,{size:"small",danger:"",onClick:b=>re(n.id,"different")},{default:t(()=>[...e[69]||(e[69]=[i("不同人",-1)])]),_:1},8,["onClick"]),a(k,{size:"small",onClick:b=>re(n.id,"skip")},{default:t(()=>[...e[70]||(e[70]=[i("跳过",-1)])]),_:1},8,["onClick"])]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:1},8,["data-source"])]),_:1},8,["open"]),a(Y,{open:G.value,"onUpdate:open":e[22]||(e[22]=n=>G.value=n),title:"审计日志(数据 lineage)",placement:"right",width:"600",onAfterOpenChange:Fe},{default:t(()=>[a(ue,{columns:Ee,"data-source":F.value,pagination:{pageSize:20,size:"small"},"row-key":n=>n.id,size:"small"},{bodyCell:t(({column:n,record:b})=>[n.key==="at"?(r(),g(H,{key:0},[i(o(new Date(b.at).toLocaleString()),1)],64)):n.key==="details"?(r(),g("code",ma,o(b.details||"—"),1)):f("",!0)]),_:1},8,["data-source","row-key"])]),_:1},8,["open"])])}}},ka=vt(va,[["__scopeId","data-v-60393590"]]);export{ka as default};
@@ -1 +0,0 @@
1
- .pdh-page[data-v-60393590]{padding:16px;max-width:1400px;margin:0 auto}.pdh-header[data-v-60393590]{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:24px;gap:16px;flex-wrap:wrap}.page-title[data-v-60393590]{margin:0 0 4px;font-size:22px;font-weight:600}.page-sub[data-v-60393590]{margin:0;color:var(--text-color-secondary, #888);font-size:13px}.kv[data-v-60393590]{font-size:13px;color:var(--text-color, #333);line-height:1.6}.kv.hint[data-v-60393590]{color:#faad14;font-size:12px;margin-top:4px}.answer[data-v-60393590]{white-space:pre-wrap;font-size:14px;line-height:1.7;background:var(--bg-elevated, #fafafa);padding:12px;border-radius:6px;border-left:3px solid #1677ff}.hint[data-v-60393590]{color:var(--text-color-secondary, #888);font-size:12px}.json-pre[data-v-60393590]{font-size:12px;background:var(--bg-elevated, #fafafa);padding:10px;border-radius:4px;max-height:280px;overflow:auto}.amount-in[data-v-60393590]{color:#52c41a;font-weight:600}.amount-out[data-v-60393590]{color:#ff4d4f;font-weight:600}
@@ -1 +0,0 @@
1
- import{C as o}from"./Col-BXnBuqIa.js";import{S as t}from"./index-C52udT0_.js";import"./index-XI6772AD.js";import"./vendor-M5lGV-wr.js";import"./icons-CLQTHa5-.js";const s=t(o);export{s as default};
@@ -1 +0,0 @@
1
- import{A as o}from"./Row-F5XcDhHr.js";import{S as t}from"./index-C52udT0_.js";import"./responsiveObserve-DJ1ra4dT.js";import"./vendor-M5lGV-wr.js";import"./useFlexGapSupport-C1miTomM.js";import"./styleChecker-Bne7zwMt.js";import"./index-XI6772AD.js";import"./icons-CLQTHa5-.js";const l=t(o);export{l as default};
@@ -1 +0,0 @@
1
- import{d as o}from"./styleChecker-Bne7zwMt.js";import{o as t,s}from"./vendor-M5lGV-wr.js";const r=(()=>{const e=s(!1);return t(()=>{e.value=o()}),e});export{r as u};