chainlesschain 0.162.19 → 0.162.25

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 (154) hide show
  1. package/package.json +2 -2
  2. package/src/assets/web-panel/.build-hash +1 -1
  3. package/src/assets/web-panel/assets/{AIOps-VbMLpnCu.js → AIOps-CAdsXHkz.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-BR6BrZ2w.js → ActionButton-JsLRBlBP.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-DWN2iHDA.js → Analytics-DeM96q71.js} +1 -1
  6. package/src/assets/web-panel/assets/{AppLayout-CyBXOO_H.js → AppLayout-eb_6mT6V.js} +2 -2
  7. package/src/assets/web-panel/assets/{Audit-Cu5a4b5S.js → Audit-BEOY-CQE.js} +1 -1
  8. package/src/assets/web-panel/assets/{Backup-D0vrJYkS.js → Backup-irFD_DBa.js} +1 -1
  9. package/src/assets/web-panel/assets/{BaseInput-DnFk3wDi.js → BaseInput-Dq7wtv_k.js} +1 -1
  10. package/src/assets/web-panel/assets/{Chat-DFMa9lEz.js → Chat-CstRKWdu.js} +1 -1
  11. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CpVazmEP.js → ChatBubbleRenderer-3BBqk317.js} +1 -1
  12. package/src/assets/web-panel/assets/{Checkbox-J23wKgNR.js → Checkbox-A8D25IT5.js} +1 -1
  13. package/src/assets/web-panel/assets/{Codegen-Ca6Z4r1p.js → Codegen-1EfMWeRA.js} +1 -1
  14. package/src/assets/web-panel/assets/{Col-BZ3XsxN2.js → Col-Bc08LzOn.js} +1 -1
  15. package/src/assets/web-panel/assets/{Community-DhK5H5dD.js → Community-BNnNv7xp.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compact-DjJMyddV.js → Compact-nFjLneHM.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compliance-Bup3Rk9z.js → Compliance-CZpaaHND.js} +1 -1
  18. package/src/assets/web-panel/assets/{Cowork-BqsPMIpo.js → Cowork-DzHugH3j.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cron-Ca69LFf-.js → Cron-C7YRyiN-.js} +1 -1
  20. package/src/assets/web-panel/assets/{Crosschain-mTB21YwK.js → Crosschain-er2h0L0q.js} +1 -1
  21. package/src/assets/web-panel/assets/{DID-C1_Eree4.js → DID-DaMdE0A7.js} +1 -1
  22. package/src/assets/web-panel/assets/{Dashboard-L2OWv5io.js → Dashboard-1z2K_E1B.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dropdown-CpqNwurh.js → Dropdown-B9NIqAXf.js} +1 -1
  24. package/src/assets/web-panel/assets/{EmailListRenderer-Mo7D9ADF.js → EmailListRenderer-CBHLFokz.js} +1 -1
  25. package/src/assets/web-panel/assets/{Federation-COTeKl2R.js → Federation-D2fEJEki.js} +1 -1
  26. package/src/assets/web-panel/assets/{FormItemContext-0oTTQ9MI.js → FormItemContext-tmsd70yG.js} +1 -1
  27. package/src/assets/web-panel/assets/{GenericCardRenderer-DrMs3upM.js → GenericCardRenderer-DW4Lnrsr.js} +1 -1
  28. package/src/assets/web-panel/assets/{Git-C6eFUBhz.js → Git-D8aBagAp.js} +1 -1
  29. package/src/assets/web-panel/assets/{Governance-5ivL10kw.js → Governance-CKDAHamy.js} +1 -1
  30. package/src/assets/web-panel/assets/{Inference-DcERJUS_.js → Inference-BLLp118j.js} +1 -1
  31. package/src/assets/web-panel/assets/{KnowledgeGraph-Dm1eQ_Hv.js → KnowledgeGraph-Cawx-yfu.js} +1 -1
  32. package/src/assets/web-panel/assets/{Logs-Cjt-JTuL.js → Logs-sWSzp5PY.js} +1 -1
  33. package/src/assets/web-panel/assets/{Marketplace-fNDRN8YJ.js → Marketplace-BQMX3dSy.js} +1 -1
  34. package/src/assets/web-panel/assets/{McpTools-kKgzl9Bb.js → McpTools-DjlFST3o.js} +1 -1
  35. package/src/assets/web-panel/assets/{Memory-BdJujXCH.js → Memory-LZE1wG7m.js} +1 -1
  36. package/src/assets/web-panel/assets/{MobileBridge-lmvJfnpK.js → MobileBridge-BWG47jQ6.js} +1 -1
  37. package/src/assets/web-panel/assets/{MobileProjects-ZM-DVPhi.js → MobileProjects-DHVv0tYo.js} +1 -1
  38. package/src/assets/web-panel/assets/{Mtc-CeoaWgzU.js → Mtc-Di1hrhM3.js} +1 -1
  39. package/src/assets/web-panel/assets/{MtcAudit-CRvKTLqr.js → MtcAudit-BowOCi-O.js} +1 -1
  40. package/src/assets/web-panel/assets/{Multisig-DnzFw69O.js → Multisig-CgpR0s8E.js} +1 -1
  41. package/src/assets/web-panel/assets/{NLProgramming-0xP2rtGN.js → NLProgramming-O4U3Plxd.js} +1 -1
  42. package/src/assets/web-panel/assets/{Notes-tJpp3z8e.js → Notes-Ce_5C6XT.js} +1 -1
  43. package/src/assets/web-panel/assets/{NotificationSettings-CRdpEoHX.js → NotificationSettings-BVVopkxj.js} +1 -1
  44. package/src/assets/web-panel/assets/{OrderTableRenderer-BEH9lAIb.js → OrderTableRenderer-XW2G50wt.js} +1 -1
  45. package/src/assets/web-panel/assets/{Organization-Dhwy6dXT.js → Organization-DaW54kdP.js} +1 -1
  46. package/src/assets/web-panel/assets/{Overflow-COwwTMb-.js → Overflow-CVTGMUVt.js} +1 -1
  47. package/src/assets/web-panel/assets/{P2P-79YWb-cn.js → P2P-CpEwrhBx.js} +1 -1
  48. package/src/assets/web-panel/assets/{PdhVaultBrowser-Dhn5S3Vs.js → PdhVaultBrowser-CDqun-Z9.js} +2 -2
  49. package/src/assets/web-panel/assets/{Permissions-ELRvDOlY.js → Permissions-BsSU3MaL.js} +1 -1
  50. package/src/assets/web-panel/assets/PersonalDataHub-BafcAH5d.js +1 -0
  51. package/src/assets/web-panel/assets/{PersonalDataHub-D0ncF92t.css → PersonalDataHub-DmUc89_0.css} +1 -1
  52. package/src/assets/web-panel/assets/{Pipeline-Dzi1zmAr.js → Pipeline-CPCDpDyd.js} +1 -1
  53. package/src/assets/web-panel/assets/{Privacy-BYzWkaRt.js → Privacy-oZEQvVWA.js} +1 -1
  54. package/src/assets/web-panel/assets/{ProjectInit-D_5DqLSS.js → ProjectInit-CRu5bDNW.js} +1 -1
  55. package/src/assets/web-panel/assets/{ProjectSettings-DrAAYJgR.js → ProjectSettings-ComIZ7gQ.js} +1 -1
  56. package/src/assets/web-panel/assets/{Projects-BOrF4_X8.js → Projects-Djr10qFp.js} +1 -1
  57. package/src/assets/web-panel/assets/{Providers-DYLWZVe4.js → Providers-CltNzV7e.js} +1 -1
  58. package/src/assets/web-panel/assets/{QuickAsk-k76cZTaF.js → QuickAsk-C21t1JEf.js} +1 -1
  59. package/src/assets/web-panel/assets/{Recommend-CXM4p6RB.js → Recommend-BjJForJo.js} +1 -1
  60. package/src/assets/web-panel/assets/{Reputation-DLnLpz8L.js → Reputation-Cp8Ym-Hk.js} +1 -1
  61. package/src/assets/web-panel/assets/{Row-BavvTUrL.js → Row-n8ruyEoT.js} +1 -1
  62. package/src/assets/web-panel/assets/{RssFeed-CtCarC8_.js → RssFeed-CosaiHvS.js} +1 -1
  63. package/src/assets/web-panel/assets/{Search-CJcDGc1x.js → Search-DUNSNFJZ.js} +1 -1
  64. package/src/assets/web-panel/assets/{Security-DB3GmnY9.js → Security-Z3WyX_MB.js} +1 -1
  65. package/src/assets/web-panel/assets/{Services-BWEvVHhz.js → Services-U0m9Oj8V.js} +1 -1
  66. package/src/assets/web-panel/assets/{Skeleton-BHbixeGV.js → Skeleton-B_M5sv2W.js} +1 -1
  67. package/src/assets/web-panel/assets/{Skills-DWwIjvjl.js → Skills-NKU9c6LT.js} +1 -1
  68. package/src/assets/web-panel/assets/{Sla-C1Qu9o0j.js → Sla-DscfpqF8.js} +1 -1
  69. package/src/assets/web-panel/assets/{SpeechSettings-BiEysZg1.js → SpeechSettings-DP0O84ej.js} +1 -1
  70. package/src/assets/web-panel/assets/{SyncSettings-XlOLFUv2.js → SyncSettings-P_WEyoH3.js} +1 -1
  71. package/src/assets/web-panel/assets/{Tasks-BKjOcYxW.js → Tasks-C8YAncnj.js} +1 -1
  72. package/src/assets/web-panel/assets/{Templates-BVKjc9j-.js → Templates-F12-SRc3.js} +1 -1
  73. package/src/assets/web-panel/assets/{Tenant-C33WmSiJ.js → Tenant-CULHbrwu.js} +1 -1
  74. package/src/assets/web-panel/assets/{Terminal-Dl8RJZHg.js → Terminal-DdYrQ0n3.js} +1 -1
  75. package/src/assets/web-panel/assets/{TimelineRenderer-CFN36N3H.js → TimelineRenderer-C12_BYAe.js} +1 -1
  76. package/src/assets/web-panel/assets/{Tokens-Dy2kxiCA.js → Tokens-8MVLlc0s.js} +1 -1
  77. package/src/assets/web-panel/assets/{Trigger-C7bt0leJ.js → Trigger-Bl6QmvKw.js} +1 -1
  78. package/src/assets/web-panel/assets/{Trust-CVKbWEMH.js → Trust-BH_aEsWy.js} +1 -1
  79. package/src/assets/web-panel/assets/{UkeySign-B91QGwbs.js → UkeySign-DsX2CeE4.js} +1 -1
  80. package/src/assets/web-panel/assets/{VideoEditing-C8xBqRiE.js → VideoEditing-DaRdn6e9.js} +1 -1
  81. package/src/assets/web-panel/assets/{Wallet-RW2IBbpH.js → Wallet-DO89dzlU.js} +1 -1
  82. package/src/assets/web-panel/assets/{WebAuthn-CZPv5ayn.js → WebAuthn-KUKNjImY.js} +1 -1
  83. package/src/assets/web-panel/assets/{WorkflowEditor-CFCwic4a.js → WorkflowEditor-CnSoP-Z9.js} +1 -1
  84. package/src/assets/web-panel/assets/{chat-PVfHUaHj.js → chat-Jp0M9E52.js} +1 -1
  85. package/src/assets/web-panel/assets/{colors-C4WA0-Iq.js → colors-Bkq4q91x.js} +1 -1
  86. package/src/assets/web-panel/assets/{compact-item-DQfLwjbC.js → compact-item-CCt1byem.js} +1 -1
  87. package/src/assets/web-panel/assets/{createContext-31PSlu0j.js → createContext-DwRLi0Uq.js} +1 -1
  88. package/src/assets/web-panel/assets/{hasIn-Csltfg47.js → hasIn-CTVm-2lw.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-DfbOwhkA.js → index-6OmglXey.js} +1 -1
  90. package/src/assets/web-panel/assets/{index-DdrYhK__.js → index-B2pkXVOU.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-DuZKKJDi.js → index-B3irAeY8.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-DW-7sqm0.js → index-B9q3wKEr.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-Ba6cQs-y.js → index-BD2U0Ciz.js} +3 -3
  94. package/src/assets/web-panel/assets/{index-CArRkfYM.js → index-BJmiHI2z.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-BiFRGYGH.js → index-B_U_xDvh.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-B-aRUTIJ.js → index-BhSbNePw.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BqOmboiA.js → index-BjGcDwb2.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-DVHR_To_.js → index-BtzUDs1M.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-DpEj71nk.js → index-BziGa10S.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-nAhW-NN4.js → index-C2ovimhG.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DSO9eU_G.js → index-C3ZzMEg0.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Cgt2_bmM.js → index-CDbgmmSF.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-CQWE2WKS.js → index-CFh73FRz.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-CmzuBE2G.js → index-CIBi-rGt.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CIeFJLHG.js → index-CJWYdgmz.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CfWk9Yzf.js → index-CLjugrcu.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BCxhSOsr.js → index-CPnSymMN.js} +1 -1
  108. package/src/assets/web-panel/assets/index-CR2wmKfw.js +1 -0
  109. package/src/assets/web-panel/assets/{index-CEtPU50W.js → index-CdlVwys1.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BLwrQAlK.js → index-CjJWQqPG.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BD-K1g5z.js → index-Cvrka2TD.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DUFwsCsD.js → index-D-UAtktg.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-C4gzD6Ra.js → index-DC-8E2CG.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BCyTEqF7.js → index-DFcr_PT2.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CpXm8DBk.js → index-DJegJP2N.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CdQUx-5Z.js → index-DRkGL2HJ.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DtUcq8Nn.js → index-DRwUdk7I.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-Dymm64KM.js → index-DWQ9NRWg.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-41v9Hflm.js → index-DXDSJwDk.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-8IVdEMKr.js → index-Db3R-khd.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-C_k_btzK.js → index-MdArO-BF.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CE8i90GF.js → index-TL3iHPdE.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CbpUjcEf.js → index-TqiVFiUf.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CEbbRpw2.js → index-eyVkd-kF.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-45Iyof95.js → index-hpRtUCjU.js} +1 -1
  126. package/src/assets/web-panel/assets/index-iXk8Oeci.js +1 -0
  127. package/src/assets/web-panel/assets/{index-P9rJg2C1.js → index-zwGGcR7I.js} +1 -1
  128. package/src/assets/web-panel/assets/{initDefaultProps-DPk1oFCk.js → initDefaultProps-9iSe4Eid.js} +1 -1
  129. package/src/assets/web-panel/assets/{motion-CzQ1k8MU.js → motion-CcUz2pq7.js} +1 -1
  130. package/src/assets/web-panel/assets/{move-BCExaQ0x.js → move-3Po9fM71.js} +1 -1
  131. package/src/assets/web-panel/assets/{omit-D71nF5o_.js → omit-BBcRnciw.js} +1 -1
  132. package/src/assets/web-panel/assets/{pickAttrs-pvCq8tx4.js → pickAttrs-UCqcWwOy.js} +1 -1
  133. package/src/assets/web-panel/assets/{placementArrow-D8lSLg_0.js → placementArrow-boVtHxA4.js} +1 -1
  134. package/src/assets/web-panel/assets/{responsiveObserve-ZN6pVHvM.js → responsiveObserve-V0qPHZOl.js} +1 -1
  135. package/src/assets/web-panel/assets/{slide-VHxyZhFr.js → slide-CZyysA_q.js} +1 -1
  136. package/src/assets/web-panel/assets/{statusUtils-B0jFTTFP.js → statusUtils-BLyCU5L3.js} +1 -1
  137. package/src/assets/web-panel/assets/{styleChecker-Bc6FRYW9.js → styleChecker-BfXrPW7h.js} +1 -1
  138. package/src/assets/web-panel/assets/{useFlexGapSupport-D4YDiqxr.js → useFlexGapSupport-Be2wILDi.js} +1 -1
  139. package/src/assets/web-panel/assets/{useFs-CQgQ7iah.js → useFs-CzJYoHOI.js} +1 -1
  140. package/src/assets/web-panel/assets/{usePersonalDataHub-LDh_Sq7B.js → usePersonalDataHub-__HEfTF9.js} +1 -1
  141. package/src/assets/web-panel/assets/{vnode-BwPvBDfI.js → vnode-C0XE0aCE.js} +1 -1
  142. package/src/assets/web-panel/assets/{zoom-r6u1_Sq8.js → zoom-CphwCBhl.js} +1 -1
  143. package/src/assets/web-panel/index.html +1 -1
  144. package/src/commands/__tests__/hub-bilibili-adb-sync.test.js +350 -0
  145. package/src/commands/__tests__/hub-douyin-adb-sync.test.js +199 -0
  146. package/src/commands/__tests__/hub-weibo-adb-sync.test.js +163 -0
  147. package/src/commands/__tests__/hub-xhs-adb-sync.test.js +155 -0
  148. package/src/commands/hub.js +600 -0
  149. package/src/gateways/ws/personal-data-hub-protocol.js +50 -0
  150. package/src/lib/host-adb-bridge.js +77 -1
  151. package/src/lib/personal-data-hub-wiring.js +349 -12
  152. package/src/assets/web-panel/assets/PersonalDataHub-DIWbfS5k.js +0 -1
  153. package/src/assets/web-panel/assets/index-3NsH3wNq.js +0 -1
  154. package/src/assets/web-panel/assets/index-DWtc_qRj.js +0 -1
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Phase 2a — cc hub douyin-adb-sync CLI command unit tests.
3
+ *
4
+ * Mirrors hub-bilibili-adb-sync.test.js. Synthesizes a fake hub whose
5
+ * `douyinAdbSync` returns canned `{ok, ...}` shapes matching the wiring
6
+ * contract.
7
+ *
8
+ * Covers:
9
+ * - Happy path: human + JSON
10
+ * - 5 typed failure reasons each emit the right inline tip + exit 1
11
+ * - Parser diagnostic warnings (msg / SIMPLE_USER missing)
12
+ * - Options forwarding (uid / limit-messages / limit-contacts / staging-dir / display-name)
13
+ */
14
+
15
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
16
+
17
+ import { _internal } from "../hub.js";
18
+
19
+ let logSpy, errSpy;
20
+ let prevExitCode;
21
+
22
+ function fakeHub(syncResult) {
23
+ return {
24
+ douyinAdbSync: vi.fn(async (_opts) => syncResult),
25
+ };
26
+ }
27
+
28
+ const HAPPY_RESULT = {
29
+ ok: true,
30
+ report: {
31
+ adapter: "social-douyin",
32
+ status: "ok",
33
+ rawCount: 12,
34
+ entityCounts: { events: 12, persons: 0, places: 0, items: 0, topics: 0 },
35
+ douyin: {
36
+ uid: "1234567890123456789",
37
+ eventCounts: { message: 10, contact: 2, total: 12 },
38
+ parserDiagnostic: {
39
+ hadMsgTable: true,
40
+ hadSimpleUserTable: true,
41
+ messageCount: 10,
42
+ contactCount: 2,
43
+ },
44
+ cleanupFailed: false,
45
+ },
46
+ },
47
+ };
48
+
49
+ beforeEach(() => {
50
+ logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
51
+ errSpy = vi.spyOn(console, "error").mockImplementation(() => {});
52
+ prevExitCode = process.exitCode;
53
+ process.exitCode = 0;
54
+ });
55
+
56
+ afterEach(() => {
57
+ logSpy.mockRestore();
58
+ errSpy.mockRestore();
59
+ process.exitCode = prevExitCode;
60
+ });
61
+
62
+ describe("cc hub douyin-adb-sync — happy path", () => {
63
+ it("prints human-readable summary by default", async () => {
64
+ const hub = fakeHub(HAPPY_RESULT);
65
+ await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
66
+ expect(hub.douyinAdbSync).toHaveBeenCalledOnce();
67
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
68
+ expect(out).toMatch(/douyin-adb-sync succeeded/);
69
+ expect(out).toMatch(/uid:.*1234567890123456789/);
70
+ expect(out).toMatch(/messages:\s+10/);
71
+ expect(out).toMatch(/contacts:\s+2/);
72
+ expect(out).toMatch(/total:\s+12/);
73
+ });
74
+
75
+ it("--json outputs raw result", async () => {
76
+ const hub = fakeHub(HAPPY_RESULT);
77
+ await _internal.cmdDouyinAdbSync({ _getHub: async () => hub, json: true });
78
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
79
+ const parsed = JSON.parse(out);
80
+ expect(parsed.ok).toBe(true);
81
+ expect(parsed.report.douyin.uid).toBe("1234567890123456789");
82
+ });
83
+
84
+ it("renders missing-msg-table warning", async () => {
85
+ const result = JSON.parse(JSON.stringify(HAPPY_RESULT));
86
+ result.report.douyin.parserDiagnostic.hadMsgTable = false;
87
+ const hub = fakeHub(result);
88
+ await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
89
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
90
+ expect(out).toMatch(/msg table not found/);
91
+ });
92
+
93
+ it("renders missing-SIMPLE_USER warning", async () => {
94
+ const result = JSON.parse(JSON.stringify(HAPPY_RESULT));
95
+ result.report.douyin.parserDiagnostic.hadSimpleUserTable = false;
96
+ const hub = fakeHub(result);
97
+ await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
98
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
99
+ expect(out).toMatch(/SIMPLE_USER table not found/);
100
+ });
101
+ });
102
+
103
+ describe("cc hub douyin-adb-sync — failure reasons", () => {
104
+ it("BRIDGE_UNAVAILABLE → exit 1 + install tip", async () => {
105
+ const hub = fakeHub({
106
+ ok: false,
107
+ reason: "BRIDGE_UNAVAILABLE",
108
+ message: "adb not found",
109
+ });
110
+ await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
111
+ expect(process.exitCode).toBe(1);
112
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
113
+ expect(out).toMatch(/Install Android Platform Tools/);
114
+ });
115
+
116
+ it("DOUYIN_NO_ROOT → exit 1 + Magisk tip", async () => {
117
+ const hub = fakeHub({
118
+ ok: false,
119
+ reason: "DOUYIN_NO_ROOT",
120
+ message: "uid=2000",
121
+ });
122
+ await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
123
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
124
+ expect(out).toMatch(/Magisk root/);
125
+ });
126
+
127
+ it("DOUYIN_NOT_INSTALLED → install tip", async () => {
128
+ const hub = fakeHub({
129
+ ok: false,
130
+ reason: "DOUYIN_NOT_INSTALLED",
131
+ message: "dir missing",
132
+ });
133
+ await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
134
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
135
+ expect(out).toMatch(/Install Douyin App on the phone/);
136
+ });
137
+
138
+ it("DOUYIN_NO_IM_DB → login+open-chat tip", async () => {
139
+ const hub = fakeHub({
140
+ ok: false,
141
+ reason: "DOUYIN_NO_IM_DB",
142
+ message: "no <uid>_im.db",
143
+ });
144
+ await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
145
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
146
+ expect(out).toMatch(/Log in to Douyin App.*open any chat thread/);
147
+ });
148
+
149
+ it("DOUYIN_MULTIPLE_USERS → --uid tip", async () => {
150
+ const hub = fakeHub({
151
+ ok: false,
152
+ reason: "DOUYIN_MULTIPLE_USERS",
153
+ message: "multiple",
154
+ });
155
+ await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
156
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
157
+ expect(out).toMatch(/--uid <19-digit>/);
158
+ });
159
+ });
160
+
161
+ describe("cc hub douyin-adb-sync — options forwarding", () => {
162
+ it("forwards --uid", async () => {
163
+ const hub = fakeHub(HAPPY_RESULT);
164
+ await _internal.cmdDouyinAdbSync({
165
+ _getHub: async () => hub,
166
+ uid: "1234567890123456789",
167
+ });
168
+ expect(hub.douyinAdbSync.mock.calls[0][0].uid).toBe("1234567890123456789");
169
+ });
170
+
171
+ it("forwards limit-messages + limit-contacts → limits object", async () => {
172
+ const hub = fakeHub(HAPPY_RESULT);
173
+ await _internal.cmdDouyinAdbSync({
174
+ _getHub: async () => hub,
175
+ limitMessages: "500",
176
+ limitContacts: "100",
177
+ });
178
+ const arg = hub.douyinAdbSync.mock.calls[0][0];
179
+ expect(arg.limits).toEqual({ messages: 500, contacts: 100 });
180
+ });
181
+
182
+ it("forwards display-name + staging-dir", async () => {
183
+ const hub = fakeHub(HAPPY_RESULT);
184
+ await _internal.cmdDouyinAdbSync({
185
+ _getHub: async () => hub,
186
+ displayName: "alice",
187
+ stagingDir: "/tmp/x",
188
+ });
189
+ const arg = hub.douyinAdbSync.mock.calls[0][0];
190
+ expect(arg.displayName).toBe("alice");
191
+ expect(arg.stagingDir).toBe("/tmp/x");
192
+ });
193
+ });
194
+
195
+ describe("cc hub douyin-adb-sync — _internal export", () => {
196
+ it("cmdDouyinAdbSync is exported", () => {
197
+ expect(typeof _internal.cmdDouyinAdbSync).toBe("function");
198
+ });
199
+ });
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Phase 3a — cc hub weibo-adb-sync CLI command unit tests.
3
+ *
4
+ * Same _getHub test-seam pattern. Mirrors hub-bilibili / hub-douyin tests.
5
+ */
6
+
7
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
8
+
9
+ import { _internal } from "../hub.js";
10
+
11
+ let logSpy, errSpy;
12
+ let prevExitCode;
13
+
14
+ function fakeHub(syncResult) {
15
+ return { weiboAdbSync: vi.fn(async (_opts) => syncResult) };
16
+ }
17
+
18
+ const HAPPY_RESULT = {
19
+ ok: true,
20
+ report: {
21
+ adapter: "social-weibo",
22
+ status: "ok",
23
+ rawCount: 25,
24
+ entityCounts: { events: 25, persons: 0, places: 0, items: 0, topics: 0 },
25
+ weibo: {
26
+ uid: 1234567890,
27
+ eventCounts: { post: 15, favourite: 5, follow: 5, total: 25 },
28
+ lastErrorCode: 0,
29
+ lastErrorMessage: null,
30
+ cookieDiagnostic: { cookieCount: 6, hasSub: true, hadEncrypted: false },
31
+ uidFetchFailed: false,
32
+ cleanupFailed: false,
33
+ },
34
+ },
35
+ };
36
+
37
+ beforeEach(() => {
38
+ logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
39
+ errSpy = vi.spyOn(console, "error").mockImplementation(() => {});
40
+ prevExitCode = process.exitCode;
41
+ process.exitCode = 0;
42
+ });
43
+
44
+ afterEach(() => {
45
+ logSpy.mockRestore();
46
+ errSpy.mockRestore();
47
+ process.exitCode = prevExitCode;
48
+ });
49
+
50
+ describe("cc hub weibo-adb-sync — happy path", () => {
51
+ it("prints human summary", async () => {
52
+ const hub = fakeHub(HAPPY_RESULT);
53
+ await _internal.cmdWeiboAdbSync({ _getHub: async () => hub });
54
+ expect(hub.weiboAdbSync).toHaveBeenCalledOnce();
55
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
56
+ expect(out).toMatch(/weibo-adb-sync succeeded/);
57
+ expect(out).toMatch(/uid:.*1234567890/);
58
+ expect(out).toMatch(/posts:\s+15/);
59
+ expect(out).toMatch(/favourites:\s+5/);
60
+ expect(out).toMatch(/follows:\s+5/);
61
+ expect(out).toMatch(/total:\s+25/);
62
+ });
63
+
64
+ it("--json outputs raw result", async () => {
65
+ const hub = fakeHub(HAPPY_RESULT);
66
+ await _internal.cmdWeiboAdbSync({ _getHub: async () => hub, json: true });
67
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
68
+ const parsed = JSON.parse(out);
69
+ expect(parsed.ok).toBe(true);
70
+ expect(parsed.report.weibo.uid).toBe(1234567890);
71
+ });
72
+
73
+ it("renders uidFetchFailed warning when set", async () => {
74
+ const result = JSON.parse(JSON.stringify(HAPPY_RESULT));
75
+ result.report.weibo.uidFetchFailed = true;
76
+ result.report.weibo.lastErrorCode = -4;
77
+ result.report.weibo.uid = null;
78
+ const hub = fakeHub(result);
79
+ await _internal.cmdWeiboAdbSync({ _getHub: async () => hub });
80
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
81
+ expect(out).toMatch(/api\/config returned login=false/);
82
+ expect(out).toMatch(/uid fetch failed/);
83
+ });
84
+ });
85
+
86
+ describe("cc hub weibo-adb-sync — failure reasons", () => {
87
+ it("BRIDGE_UNAVAILABLE → exit 1 + install tip", async () => {
88
+ const hub = fakeHub({
89
+ ok: false,
90
+ reason: "BRIDGE_UNAVAILABLE",
91
+ message: "adb not found",
92
+ });
93
+ await _internal.cmdWeiboAdbSync({ _getHub: async () => hub });
94
+ expect(process.exitCode).toBe(1);
95
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
96
+ expect(out).toMatch(/Install Android Platform Tools/);
97
+ });
98
+
99
+ it("WEIBO_NO_ROOT → Magisk tip", async () => {
100
+ const hub = fakeHub({
101
+ ok: false,
102
+ reason: "WEIBO_NO_ROOT",
103
+ message: "uid=2000",
104
+ });
105
+ await _internal.cmdWeiboAdbSync({ _getHub: async () => hub });
106
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
107
+ expect(out).toMatch(/Magisk root/);
108
+ });
109
+
110
+ it("WEIBO_NOT_INSTALLED → install tip", async () => {
111
+ const hub = fakeHub({
112
+ ok: false,
113
+ reason: "WEIBO_NOT_INSTALLED",
114
+ message: "Cookies path missing",
115
+ });
116
+ await _internal.cmdWeiboAdbSync({ _getHub: async () => hub });
117
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
118
+ expect(out).toMatch(/Install Weibo App/);
119
+ });
120
+
121
+ it("WEIBO_COOKIES_INCOMPLETE → relog tip (SUB missing)", async () => {
122
+ const hub = fakeHub({
123
+ ok: false,
124
+ reason: "WEIBO_COOKIES_INCOMPLETE",
125
+ message: "missing SUB",
126
+ });
127
+ await _internal.cmdWeiboAdbSync({ _getHub: async () => hub });
128
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
129
+ expect(out).toMatch(/SUB cookie missing.*relog/);
130
+ });
131
+ });
132
+
133
+ describe("cc hub weibo-adb-sync — options forwarding", () => {
134
+ it("forwards limit-post / limit-favourite / limit-follow", async () => {
135
+ const hub = fakeHub(HAPPY_RESULT);
136
+ await _internal.cmdWeiboAdbSync({
137
+ _getHub: async () => hub,
138
+ limitPost: "50",
139
+ limitFavourite: "30",
140
+ limitFollow: "100",
141
+ });
142
+ const arg = hub.weiboAdbSync.mock.calls[0][0];
143
+ expect(arg.limits).toEqual({ post: 50, favourite: 30, follow: 100 });
144
+ });
145
+
146
+ it("forwards display-name + staging-dir", async () => {
147
+ const hub = fakeHub(HAPPY_RESULT);
148
+ await _internal.cmdWeiboAdbSync({
149
+ _getHub: async () => hub,
150
+ displayName: "alice",
151
+ stagingDir: "/tmp/x",
152
+ });
153
+ const arg = hub.weiboAdbSync.mock.calls[0][0];
154
+ expect(arg.displayName).toBe("alice");
155
+ expect(arg.stagingDir).toBe("/tmp/x");
156
+ });
157
+ });
158
+
159
+ describe("cc hub weibo-adb-sync — _internal export", () => {
160
+ it("cmdWeiboAdbSync is exported", () => {
161
+ expect(typeof _internal.cmdWeiboAdbSync).toBe("function");
162
+ });
163
+ });
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Phase 3c — cc hub xhs-adb-sync CLI command unit tests.
3
+ *
4
+ * Mirror of hub-weibo-adb-sync test. Covers meFetchFailed warning + 461
5
+ * partial-result warning (X-S signing best-effort).
6
+ */
7
+
8
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
9
+
10
+ import { _internal } from "../hub.js";
11
+
12
+ let logSpy, errSpy;
13
+ let prevExitCode;
14
+
15
+ function fakeHub(syncResult) {
16
+ return { xhsAdbSync: vi.fn(async (_opts) => syncResult) };
17
+ }
18
+
19
+ const HAPPY_RESULT = {
20
+ ok: true,
21
+ report: {
22
+ adapter: "social-xiaohongshu",
23
+ status: "ok",
24
+ rawCount: 20,
25
+ entityCounts: { events: 20, persons: 0, places: 0, items: 0, topics: 0 },
26
+ xhs: {
27
+ userId: "5e8c8f7e1234abcdef",
28
+ nickname: "Alice",
29
+ eventCounts: { note: 15, liked: 3, follow: 2, total: 20 },
30
+ lastErrorCode: 0,
31
+ lastErrorMessage: null,
32
+ cookieDiagnostic: { cookieCount: 8, hadEncrypted: false },
33
+ meFetchFailed: false,
34
+ cleanupFailed: false,
35
+ },
36
+ },
37
+ };
38
+
39
+ beforeEach(() => {
40
+ logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
41
+ errSpy = vi.spyOn(console, "error").mockImplementation(() => {});
42
+ prevExitCode = process.exitCode;
43
+ process.exitCode = 0;
44
+ });
45
+
46
+ afterEach(() => {
47
+ logSpy.mockRestore();
48
+ errSpy.mockRestore();
49
+ process.exitCode = prevExitCode;
50
+ });
51
+
52
+ describe("cc hub xhs-adb-sync — happy path", () => {
53
+ it("prints human summary with nickname", async () => {
54
+ const hub = fakeHub(HAPPY_RESULT);
55
+ await _internal.cmdXhsAdbSync({ _getHub: async () => hub });
56
+ expect(hub.xhsAdbSync).toHaveBeenCalledOnce();
57
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
58
+ expect(out).toMatch(/xhs-adb-sync succeeded/);
59
+ expect(out).toMatch(/userId:.*5e8c8f7e/);
60
+ expect(out).toMatch(/nickname:\s+Alice/);
61
+ expect(out).toMatch(/notes:\s+15/);
62
+ expect(out).toMatch(/liked:\s+3/);
63
+ expect(out).toMatch(/follows:\s+2/);
64
+ expect(out).toMatch(/total:\s+20/);
65
+ });
66
+
67
+ it("--json outputs raw result", async () => {
68
+ const hub = fakeHub(HAPPY_RESULT);
69
+ await _internal.cmdXhsAdbSync({ _getHub: async () => hub, json: true });
70
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
71
+ const parsed = JSON.parse(out);
72
+ expect(parsed.ok).toBe(true);
73
+ expect(parsed.report.xhs.userId).toBe("5e8c8f7e1234abcdef");
74
+ });
75
+
76
+ it("renders meFetchFailed warning when set", async () => {
77
+ const result = JSON.parse(JSON.stringify(HAPPY_RESULT));
78
+ result.report.xhs.meFetchFailed = true;
79
+ result.report.xhs.lastErrorCode = -7;
80
+ result.report.xhs.userId = null;
81
+ const hub = fakeHub(result);
82
+ await _internal.cmdXhsAdbSync({ _getHub: async () => hub });
83
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
84
+ expect(out).toMatch(/\/user\/me returned no user_id/);
85
+ expect(out).toMatch(/me fetch failed/);
86
+ });
87
+
88
+ it("renders X-S 461 partial-result warning", async () => {
89
+ const result = JSON.parse(JSON.stringify(HAPPY_RESULT));
90
+ result.report.xhs.lastErrorCode = 461;
91
+ result.report.xhs.lastErrorMessage = "X-S validation failed";
92
+ result.report.xhs.eventCounts.total = 5; // partial — only 5 events got through
93
+ const hub = fakeHub(result);
94
+ await _internal.cmdXhsAdbSync({ _getHub: async () => hub });
95
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
96
+ expect(out).toMatch(/X-S 签名 best-effort/);
97
+ expect(out).toMatch(/lastErrorCode=461/);
98
+ });
99
+ });
100
+
101
+ describe("cc hub xhs-adb-sync — failure reasons", () => {
102
+ it("BRIDGE_UNAVAILABLE → exit 1 + install tip", async () => {
103
+ const hub = fakeHub({
104
+ ok: false,
105
+ reason: "BRIDGE_UNAVAILABLE",
106
+ message: "adb not found",
107
+ });
108
+ await _internal.cmdXhsAdbSync({ _getHub: async () => hub });
109
+ expect(process.exitCode).toBe(1);
110
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
111
+ expect(out).toMatch(/Install Android Platform Tools/);
112
+ });
113
+
114
+ it("XHS_NO_ROOT → Magisk tip", async () => {
115
+ const hub = fakeHub({
116
+ ok: false,
117
+ reason: "XHS_NO_ROOT",
118
+ message: "uid=2000",
119
+ });
120
+ await _internal.cmdXhsAdbSync({ _getHub: async () => hub });
121
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
122
+ expect(out).toMatch(/Magisk root/);
123
+ });
124
+
125
+ it("XHS_COOKIES_INCOMPLETE → a1/web_session tip", async () => {
126
+ const hub = fakeHub({
127
+ ok: false,
128
+ reason: "XHS_COOKIES_INCOMPLETE",
129
+ message: "missing a1",
130
+ });
131
+ await _internal.cmdXhsAdbSync({ _getHub: async () => hub });
132
+ const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
133
+ expect(out).toMatch(/a1 \/ web_session cookie missing/);
134
+ });
135
+ });
136
+
137
+ describe("cc hub xhs-adb-sync — options forwarding", () => {
138
+ it("forwards limit-note / limit-liked / limit-follow", async () => {
139
+ const hub = fakeHub(HAPPY_RESULT);
140
+ await _internal.cmdXhsAdbSync({
141
+ _getHub: async () => hub,
142
+ limitNote: "20",
143
+ limitLiked: "15",
144
+ limitFollow: "50",
145
+ });
146
+ const arg = hub.xhsAdbSync.mock.calls[0][0];
147
+ expect(arg.limits).toEqual({ note: 20, liked: 15, follow: 50 });
148
+ });
149
+ });
150
+
151
+ describe("cc hub xhs-adb-sync — _internal export", () => {
152
+ it("cmdXhsAdbSync is exported", () => {
153
+ expect(typeof _internal.cmdXhsAdbSync).toBe("function");
154
+ });
155
+ });