chainlesschain 0.162.20 → 0.162.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-Buh_mYlF.js → AIOps-DEhhAYYj.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Dc7c0bZf.js → ActionButton-DEyfUz5F.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CR9TWfM-.js → Analytics-D1rjS61W.js} +1 -1
- package/src/assets/web-panel/assets/{AppLayout-DVfanUep.js → AppLayout-CptFJPy6.js} +2 -2
- package/src/assets/web-panel/assets/{Audit-BxojBqRe.js → Audit-BG6KQUHY.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CGkreaK9.js → Backup-D2ikQT54.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-B-Q2ZGfz.js → BaseInput-BG_d8yMt.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-Dd_VC5Av.js → Chat-CcHmGkLY.js} +1 -1
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-B64kZfRH.js → ChatBubbleRenderer-DIXrOHbn.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-NYBD1rCW.js → Checkbox-Bx2h6vT3.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-B3Kqhgv1.js → Codegen-o14zzfuK.js} +1 -1
- package/src/assets/web-panel/assets/{Col-2A3Bg2GC.js → Col-HlZjxy7V.js} +1 -1
- package/src/assets/web-panel/assets/{Community-C84SkDEJ.js → Community-DXxMflr2.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Crv3pyZJ.js → Compact-DbswbBjd.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-D4qasxoY.js → Compliance-C7Q4Da2p.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-Bfbvysw-.js → Cowork-BLImywOe.js} +1 -1
- package/src/assets/web-panel/assets/{Cron-Dkjyiekd.js → Cron-DpXu1G4m.js} +1 -1
- package/src/assets/web-panel/assets/{Crosschain-DbJm9Kjd.js → Crosschain-C4qokeJu.js} +1 -1
- package/src/assets/web-panel/assets/{DID-C2HI6acG.js → DID-C0BjPiij.js} +1 -1
- package/src/assets/web-panel/assets/{Dashboard-BXMY7QVP.js → Dashboard-CsfDXwPl.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DcOykpfh.js → Dropdown-CiwMUKrx.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Doo52F2M.js → EmailListRenderer-DX7xfm5a.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-cHubZT6U.js → Federation-CA4Ibsg0.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-B5OVlspi.js → FormItemContext-DvM0lU-7.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-OgA46PJq.js → GenericCardRenderer-REjsnTHA.js} +1 -1
- package/src/assets/web-panel/assets/{Git-_OKH_JOq.js → Git-ZhnSDQGH.js} +1 -1
- package/src/assets/web-panel/assets/{Governance-CTByBwSV.js → Governance-BL8iUV_g.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-C0nqgySA.js → Inference-BONrgLk-.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CWW4ZIqH.js → KnowledgeGraph-q9SAz7h7.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DrwqUltr.js → Logs-eHfEFnEZ.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-LJMRx-dm.js → Marketplace-DzwuVedm.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-F_EjC8j3.js → McpTools-BRoLIeq5.js} +1 -1
- package/src/assets/web-panel/assets/{Memory-VonDem9-.js → Memory-DjvAa1Ce.js} +1 -1
- package/src/assets/web-panel/assets/{MobileBridge-CUWxIrfb.js → MobileBridge-CGTanjsT.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CGOo70lk.js → MobileProjects-cTccXHwN.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CqUquFbQ.js → Mtc-CNUe29wS.js} +1 -1
- package/src/assets/web-panel/assets/{MtcAudit-CRVusaip.js → MtcAudit-COk24mdH.js} +1 -1
- package/src/assets/web-panel/assets/{Multisig-B0o8Mv8T.js → Multisig-CFq2j0BU.js} +1 -1
- package/src/assets/web-panel/assets/{NLProgramming-CxQINUhu.js → NLProgramming-dfRr-FGW.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-B6Q_apFW.js → Notes-iM4aoXiw.js} +1 -1
- package/src/assets/web-panel/assets/{NotificationSettings-DO-lgp6x.js → NotificationSettings-CeVJ-942.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DxoBoMtz.js → OrderTableRenderer-zQ5jvUZI.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DqJ_KawH.js → Organization-CTSWyMGT.js} +1 -1
- package/src/assets/web-panel/assets/{Overflow-Cg4iKODM.js → Overflow---n60sAp.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-n5GPMrwC.js → P2P-BCQurpAB.js} +1 -1
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BdZI0EJs.js → PdhVaultBrowser-C5L1qAc0.js} +2 -2
- package/src/assets/web-panel/assets/{Permissions-BjtwAIGb.js → Permissions-I8sgLLE5.js} +1 -1
- package/src/assets/web-panel/assets/PersonalDataHub-CEUfFRCj.js +2 -0
- package/src/assets/web-panel/assets/{PersonalDataHub-D0ncF92t.css → PersonalDataHub-CO9-IYDY.css} +1 -1
- package/src/assets/web-panel/assets/{Pipeline-BZe2-Flj.js → Pipeline-BTBjJaRd.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-OJqMon4c.js → Privacy-aCs44rpW.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Dw-5SMG1.js → ProjectInit-DZ2iIlbN.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectSettings-DxqW44cV.js → ProjectSettings-oYUtNgHP.js} +1 -1
- package/src/assets/web-panel/assets/{Projects-CPOqs2ec.js → Projects-FonFg0ie.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-hBfwscEl.js → Providers-CRmOuabY.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DA3WFFAr.js → QuickAsk-BHd6UZ1A.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DMpz3URg.js → Recommend-BkzGGuq-.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-6-z56FwC.js → Reputation-Do7cPr9u.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CL1Y6SfW.js → Row-D_sR3MmD.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BIHU2bMf.js → RssFeed-pWSbZ06l.js} +1 -1
- package/src/assets/web-panel/assets/{Search-CRAfuEX-.js → Search-BTL71JSs.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CVya3gvH.js → Security-8lbNoqY6.js} +1 -1
- package/src/assets/web-panel/assets/{Services-Cxv7_umF.js → Services-yr3QVduo.js} +1 -1
- package/src/assets/web-panel/assets/{Skeleton-D_GvsCtv.js → Skeleton-DdnY1ZTz.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DyiEpcvf.js → Skills-fk24WY3D.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-wiglQzXV.js → Sla-bOXRT7wR.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CLtovaa5.js → SpeechSettings-DjonFUbP.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BOgVef1O.js → SyncSettings-C-7HTl6d.js} +1 -1
- package/src/assets/web-panel/assets/{Tasks-Ik8AX7-J.js → Tasks-DDohfzFT.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CireiINW.js → Templates-C8PI_WTt.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-t7jF9NkQ.js → Tenant-CIvbeRkn.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-Btq_O951.js → Terminal-BuIPGugj.js} +1 -1
- package/src/assets/web-panel/assets/{TimelineRenderer-hC_Piiwy.js → TimelineRenderer-BefCbTxN.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BTIqA2J1.js → Tokens-gGAeez46.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Dzv2gJpK.js → Trigger-C_86E2v7.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-B13QpWOh.js → Trust-Beg23C1W.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CFj3UF4G.js → UkeySign--sGSaISg.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CGMOGTQb.js → VideoEditing-DIsnY6D_.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BkCJ573Y.js → Wallet-a7ECYY0i.js} +1 -1
- package/src/assets/web-panel/assets/{WebAuthn-C8dCrmGH.js → WebAuthn-CsVpkUE8.js} +1 -1
- package/src/assets/web-panel/assets/{WorkflowEditor-CclfhxwH.js → WorkflowEditor-BOJ4WTgl.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CW_X_A9l.js → chat-ezCR5ZZX.js} +1 -1
- package/src/assets/web-panel/assets/{colors-6GtheJb2.js → colors-DSUEQ7GR.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-tz7dJapw.js → compact-item-D4w3DGj_.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CbiGcRCw.js → createContext-B_hvu-NR.js} +1 -1
- package/src/assets/web-panel/assets/{hasIn-bmNFD3PH.js → hasIn-FY775Vpc.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxHmNJ8S.js → index-1ki6aTIz.js} +1 -1
- package/src/assets/web-panel/assets/{index-UId2JAY6.js → index-B3lbDu2b.js} +1 -1
- package/src/assets/web-panel/assets/{index-BM4slfDH.js → index-B9LXVosT.js} +1 -1
- package/src/assets/web-panel/assets/{index-b7sSMzkC.js → index-BGdchdRx.js} +1 -1
- package/src/assets/web-panel/assets/{index-KFdfLxVt.js → index-BGrm33US.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9sJpsz3.js → index-BHPD-_s2.js} +1 -1
- package/src/assets/web-panel/assets/{index-B6GgMo1k.js → index-BMnGj-Ui.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2P1c5yD.js → index-BSp1hSN8.js} +1 -1
- package/src/assets/web-panel/assets/{index-S9g45I5s.js → index-BaZmrJ6j.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cb33JbDx.js → index-BnvLdkR8.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQ7aJ-8s.js → index-BzME19Nh.js} +1 -1
- package/src/assets/web-panel/assets/{index-DeoJYTHX.js → index-C0wDzrUK.js} +3 -3
- package/src/assets/web-panel/assets/{index-CBNnbQxM.js → index-CAa3LSKI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLk3xgD2.js → index-CE3vDzJj.js} +1 -1
- package/src/assets/web-panel/assets/{index-De0xvTEv.js → index-CLp4V3Tb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKP-AZD3.js → index-CNUQnJsg.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzIQ0u4e.js → index-CSbCIyga.js} +1 -1
- package/src/assets/web-panel/assets/{index-UjxsY00y.js → index-CUNYcWEF.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgLF_zD1.js → index-CV-F9a_X.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5zlrlPd.js → index-CcvzscCg.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3UH6whC.js → index-CdzLJsac.js} +1 -1
- package/src/assets/web-panel/assets/{index-CU0MeCwH.js → index-Cug_yoee.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxdLksCx.js → index-CxMArAIk.js} +1 -1
- package/src/assets/web-panel/assets/index-CzkEIn_T.js +1 -0
- package/src/assets/web-panel/assets/index-D2PcvXPP.js +1 -0
- package/src/assets/web-panel/assets/{index-DMGJqZ-o.js → index-D6yJ0RMr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaYfMM7r.js → index-DM77-xyl.js} +1 -1
- package/src/assets/web-panel/assets/{index-CV9aPPYM.js → index-DfU6zsU8.js} +1 -1
- package/src/assets/web-panel/assets/{index-l2VM-W36.js → index-DqsQUPY7.js} +1 -1
- package/src/assets/web-panel/assets/{index-DK7ee5hC.js → index-DqxLCUYa.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaK59dFw.js → index-DtztktoP.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cs5KWviO.js → index-Dz8-7APi.js} +1 -1
- package/src/assets/web-panel/assets/{index-Da2RUdcb.js → index-Enin7rzK.js} +1 -1
- package/src/assets/web-panel/assets/{index-CYIwY9zQ.js → index-S6A76pR1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DvWXdCxl.js → index-ZGJo2fz1.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dj1N1idV.js → index-d0HXotWE.js} +1 -1
- package/src/assets/web-panel/assets/{index-CTnIkosg.js → index-gAtp_KkQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-zP_o4yKV.js → index-mlTTTHla.js} +1 -1
- package/src/assets/web-panel/assets/{index-BxCPkuTG.js → index-wWVM6ENX.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BTGwT0NA.js → initDefaultProps-BoLcNBz9.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BheHkG8e.js → motion-ouRvP3eO.js} +1 -1
- package/src/assets/web-panel/assets/{move-BkMMNkAw.js → move-BBITvaOV.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B9zmSFf6.js → omit-D8Yxdvbb.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CFNBcA5Z.js → pickAttrs-BIUy7mER.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-B4mvrUYw.js → placementArrow-CrNWpNSF.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BJqsSjxJ.js → responsiveObserve-aHLPN464.js} +1 -1
- package/src/assets/web-panel/assets/{slide-Cj78MXSi.js → slide-2qNtePjk.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Bk6ChXAV.js → statusUtils-FAF3iR3R.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B_YDSNYf.js → styleChecker-BNFTkrbl.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-q90prOQL.js → useFlexGapSupport-BgdPlW7E.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BtpFJ9kI.js → useFs-q1QvAh3f.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-C3qhf1sQ.js → usePersonalDataHub-DEZ6cY8C.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Bz2j0JiG.js → vnode-vp6H-NL_.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CzaEtel2.js → zoom-UatfJMw4.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/__tests__/hub-bilibili-adb-sync.test.js +350 -0
- package/src/commands/__tests__/hub-douyin-adb-sync.test.js +199 -0
- package/src/commands/__tests__/hub-kuaishou-adb-sync.test.js +161 -0
- package/src/commands/__tests__/hub-toutiao-adb-sync.test.js +158 -0
- package/src/commands/__tests__/hub-weibo-adb-sync.test.js +163 -0
- package/src/commands/__tests__/hub-xhs-adb-sync.test.js +155 -0
- package/src/commands/hub.js +883 -0
- package/src/gateways/ws/personal-data-hub-protocol.js +84 -0
- package/src/lib/host-adb-bridge.js +77 -1
- package/src/lib/personal-data-hub-wiring.js +471 -12
- package/src/assets/web-panel/assets/PersonalDataHub-Bsf3Wh6n.js +0 -1
- package/src/assets/web-panel/assets/index-BFkZAdio.js +0 -1
- package/src/assets/web-panel/assets/index-BhgINPAH.js +0 -1
package/src/commands/hub.js
CHANGED
|
@@ -977,6 +977,733 @@ async function cmdWechatList(options) {
|
|
|
977
977
|
}
|
|
978
978
|
}
|
|
979
979
|
|
|
980
|
+
/**
|
|
981
|
+
* Phase 1c — `cc hub bilibili-adb-sync`
|
|
982
|
+
*
|
|
983
|
+
* One-shot Bilibili C 路径 sync: pulls cookies from the user's Android
|
|
984
|
+
* Bilibili App via ADB, fetches history/favourite/dynamic/follow, writes
|
|
985
|
+
* a snapshot, and ingests via the existing social-bilibili adapter.
|
|
986
|
+
*
|
|
987
|
+
* Requires:
|
|
988
|
+
* - `adb` on PATH (or ADB_PATH env var) — see host-adb-bridge.js
|
|
989
|
+
* - exactly one Android device attached + authorized (set ADB_SERIAL if
|
|
990
|
+
* multiple are present)
|
|
991
|
+
* - phone rooted (Bilibili release APK isn't debuggable; we use `su -c
|
|
992
|
+
* base64` to read /data/data/tv.danmaku.bili/app_webview/Default/Cookies)
|
|
993
|
+
* - user already logged into the Bilibili App on the phone
|
|
994
|
+
*
|
|
995
|
+
* Common failure reasons (UI maps these to actionable banners):
|
|
996
|
+
* - BRIDGE_UNAVAILABLE — adb missing on host
|
|
997
|
+
* - BILIBILI_NOT_INSTALLED_OR_NEVER_LOGGED_IN — Cookies path absent
|
|
998
|
+
* - BILIBILI_NO_ROOT — phone isn't rooted
|
|
999
|
+
* - BILIBILI_COOKIES_INCOMPLETE — user logged out, or Keystore-wrapped
|
|
1000
|
+
* cookies we can't decrypt yet
|
|
1001
|
+
* - SYNC_FAILED — anything else (HTTP / vault error)
|
|
1002
|
+
*/
|
|
1003
|
+
async function cmdBilibiliAdbSync(options) {
|
|
1004
|
+
try {
|
|
1005
|
+
const hub = await (options._getHub || getHub)();
|
|
1006
|
+
const result = await hub.bilibiliAdbSync({
|
|
1007
|
+
stagingDir: options.stagingDir,
|
|
1008
|
+
displayName: options.displayName,
|
|
1009
|
+
limits:
|
|
1010
|
+
options.limitHistory ||
|
|
1011
|
+
options.limitFavourite ||
|
|
1012
|
+
options.limitDynamic ||
|
|
1013
|
+
options.limitFollow
|
|
1014
|
+
? {
|
|
1015
|
+
history: parsePositiveInt(options.limitHistory),
|
|
1016
|
+
favourite: parsePositiveInt(options.limitFavourite),
|
|
1017
|
+
dynamic: parsePositiveInt(options.limitDynamic),
|
|
1018
|
+
follow: parsePositiveInt(options.limitFollow),
|
|
1019
|
+
}
|
|
1020
|
+
: undefined,
|
|
1021
|
+
});
|
|
1022
|
+
if (options.json) {
|
|
1023
|
+
printJson(result);
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
if (!result.ok) {
|
|
1027
|
+
logger.log(chalk.red(`✗ bilibili-adb-sync failed: ${result.reason}`));
|
|
1028
|
+
logger.log(chalk.gray(` ${result.message || ""}`));
|
|
1029
|
+
// Inline tips for the common reasons — saves a doc lookup.
|
|
1030
|
+
if (result.reason === "BRIDGE_UNAVAILABLE") {
|
|
1031
|
+
logger.log(
|
|
1032
|
+
chalk.gray(
|
|
1033
|
+
" Install Android Platform Tools or set ADB_PATH=/path/to/adb",
|
|
1034
|
+
),
|
|
1035
|
+
);
|
|
1036
|
+
} else if (result.reason === "BILIBILI_NO_ROOT") {
|
|
1037
|
+
logger.log(
|
|
1038
|
+
chalk.gray(
|
|
1039
|
+
" Bilibili release APK isn't debuggable; root + Magisk required to read its Cookies DB",
|
|
1040
|
+
),
|
|
1041
|
+
);
|
|
1042
|
+
} else if (
|
|
1043
|
+
result.reason === "BILIBILI_NOT_INSTALLED_OR_NEVER_LOGGED_IN"
|
|
1044
|
+
) {
|
|
1045
|
+
logger.log(
|
|
1046
|
+
chalk.gray(
|
|
1047
|
+
" Install Bilibili App on the phone + log in once, then retry",
|
|
1048
|
+
),
|
|
1049
|
+
);
|
|
1050
|
+
} else if (result.reason === "BILIBILI_COOKIES_INCOMPLETE") {
|
|
1051
|
+
logger.log(
|
|
1052
|
+
chalk.gray(
|
|
1053
|
+
" Cookie file is missing required fields — relog on the phone",
|
|
1054
|
+
),
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
process.exitCode = 1;
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
const report = result.report || {};
|
|
1061
|
+
const bili = report.bilibili || {};
|
|
1062
|
+
const counts = bili.eventCounts || {};
|
|
1063
|
+
logger.log(chalk.green(`✓ bilibili-adb-sync succeeded`));
|
|
1064
|
+
logger.log(` uid: ${chalk.cyan(bili.uid)}`);
|
|
1065
|
+
logger.log(` history: ${counts.history || 0}`);
|
|
1066
|
+
logger.log(` favourite: ${counts.favourite || 0}`);
|
|
1067
|
+
logger.log(` dynamic: ${counts.dynamic || 0}`);
|
|
1068
|
+
logger.log(` follow: ${counts.follow || 0}`);
|
|
1069
|
+
logger.log(` total: ${counts.total || 0}`);
|
|
1070
|
+
if (bili.lastErrorCode) {
|
|
1071
|
+
logger.log(
|
|
1072
|
+
chalk.yellow(
|
|
1073
|
+
` ⚠ partial: lastErrorCode=${bili.lastErrorCode} (${bili.lastErrorMessage || "?"})`,
|
|
1074
|
+
),
|
|
1075
|
+
);
|
|
1076
|
+
}
|
|
1077
|
+
logger.log(` status: ${report.status || "?"}`);
|
|
1078
|
+
logger.log(` rawCount: ${report.rawCount || 0}`);
|
|
1079
|
+
const ec = report.entityCounts || {};
|
|
1080
|
+
logger.log(` events: ${ec.events || 0}`);
|
|
1081
|
+
if (bili.cleanupFailed) {
|
|
1082
|
+
logger.log(
|
|
1083
|
+
chalk.gray(` (note: staging file cleanup failed — non-fatal)`),
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
} catch (err) {
|
|
1087
|
+
fail(null, err, options.json);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
/**
|
|
1092
|
+
* Phase 3c — `cc hub xhs-adb-sync`
|
|
1093
|
+
*
|
|
1094
|
+
* Pulls xiaohongshu.com cookies from the user's Android Xhs App, fetches
|
|
1095
|
+
* userId + 3 endpoints (notes/liked/follows, X-S signed best-effort).
|
|
1096
|
+
* Inline tip per typed reason codes + meFetchFailed warning.
|
|
1097
|
+
*/
|
|
1098
|
+
async function cmdXhsAdbSync(options) {
|
|
1099
|
+
try {
|
|
1100
|
+
const hub = await (options._getHub || getHub)();
|
|
1101
|
+
const result = await hub.xhsAdbSync({
|
|
1102
|
+
stagingDir: options.stagingDir,
|
|
1103
|
+
displayName: options.displayName,
|
|
1104
|
+
limits:
|
|
1105
|
+
options.limitNote || options.limitLiked || options.limitFollow
|
|
1106
|
+
? {
|
|
1107
|
+
note: parsePositiveInt(options.limitNote),
|
|
1108
|
+
liked: parsePositiveInt(options.limitLiked),
|
|
1109
|
+
follow: parsePositiveInt(options.limitFollow),
|
|
1110
|
+
}
|
|
1111
|
+
: undefined,
|
|
1112
|
+
});
|
|
1113
|
+
if (options.json) {
|
|
1114
|
+
printJson(result);
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
if (!result.ok) {
|
|
1118
|
+
logger.log(chalk.red(`✗ xhs-adb-sync failed: ${result.reason}`));
|
|
1119
|
+
logger.log(chalk.gray(` ${result.message || ""}`));
|
|
1120
|
+
if (result.reason === "BRIDGE_UNAVAILABLE") {
|
|
1121
|
+
logger.log(
|
|
1122
|
+
chalk.gray(
|
|
1123
|
+
" Install Android Platform Tools or set ADB_PATH=/path/to/adb",
|
|
1124
|
+
),
|
|
1125
|
+
);
|
|
1126
|
+
} else if (result.reason === "XHS_NO_ROOT") {
|
|
1127
|
+
logger.log(
|
|
1128
|
+
chalk.gray(
|
|
1129
|
+
" Phone needs Magisk root — Xhs release APK isn't debuggable",
|
|
1130
|
+
),
|
|
1131
|
+
);
|
|
1132
|
+
} else if (result.reason === "XHS_NOT_INSTALLED") {
|
|
1133
|
+
logger.log(
|
|
1134
|
+
chalk.gray(
|
|
1135
|
+
" Install Xiaohongshu App on the phone + log in once, then retry",
|
|
1136
|
+
),
|
|
1137
|
+
);
|
|
1138
|
+
} else if (result.reason === "XHS_COOKIES_INCOMPLETE") {
|
|
1139
|
+
logger.log(
|
|
1140
|
+
chalk.gray(
|
|
1141
|
+
" a1 / web_session cookie missing — relog on the Xhs App",
|
|
1142
|
+
),
|
|
1143
|
+
);
|
|
1144
|
+
} else if (
|
|
1145
|
+
result.reason === "XHS_COOKIES_TRUNCATED" ||
|
|
1146
|
+
result.reason === "XHS_NOT_SQLITE"
|
|
1147
|
+
) {
|
|
1148
|
+
logger.log(
|
|
1149
|
+
chalk.gray(
|
|
1150
|
+
" ADB stream may be corrupted; unplug + replug USB and retry",
|
|
1151
|
+
),
|
|
1152
|
+
);
|
|
1153
|
+
}
|
|
1154
|
+
process.exitCode = 1;
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
1157
|
+
const report = result.report || {};
|
|
1158
|
+
const xhs = report.xhs || {};
|
|
1159
|
+
const counts = xhs.eventCounts || {};
|
|
1160
|
+
logger.log(chalk.green(`✓ xhs-adb-sync succeeded`));
|
|
1161
|
+
logger.log(
|
|
1162
|
+
` userId: ${chalk.cyan(xhs.userId || "(me fetch failed)")}`,
|
|
1163
|
+
);
|
|
1164
|
+
if (xhs.nickname) {
|
|
1165
|
+
logger.log(` nickname: ${xhs.nickname}`);
|
|
1166
|
+
}
|
|
1167
|
+
logger.log(` notes: ${counts.note || 0}`);
|
|
1168
|
+
logger.log(` liked: ${counts.liked || 0}`);
|
|
1169
|
+
logger.log(` follows: ${counts.follow || 0}`);
|
|
1170
|
+
logger.log(` total: ${counts.total || 0}`);
|
|
1171
|
+
logger.log(` status: ${report.status || "?"}`);
|
|
1172
|
+
logger.log(` rawCount: ${report.rawCount || 0}`);
|
|
1173
|
+
if (xhs.meFetchFailed) {
|
|
1174
|
+
logger.log(
|
|
1175
|
+
chalk.yellow(
|
|
1176
|
+
` ⚠ /user/me returned no user_id — cookie expired or web_session missing (lastErrorCode=${xhs.lastErrorCode})`,
|
|
1177
|
+
),
|
|
1178
|
+
);
|
|
1179
|
+
} else if (xhs.lastErrorCode) {
|
|
1180
|
+
// X-S sign best-effort: ~60% GET hit, <30% POST hit; 461 = X-S rejected
|
|
1181
|
+
logger.log(
|
|
1182
|
+
chalk.yellow(
|
|
1183
|
+
` ⚠ partial: lastErrorCode=${xhs.lastErrorCode} (${xhs.lastErrorMessage || "?"}) — X-S 签名 best-effort, 部分接口 461 可能正常`,
|
|
1184
|
+
),
|
|
1185
|
+
);
|
|
1186
|
+
}
|
|
1187
|
+
if (xhs.cleanupFailed) {
|
|
1188
|
+
logger.log(chalk.gray(` (note: staging cleanup failed — non-fatal)`));
|
|
1189
|
+
}
|
|
1190
|
+
} catch (err) {
|
|
1191
|
+
fail(null, err, options.json);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
/**
|
|
1196
|
+
* Phase 6d — `cc hub kuaishou-adb-sync`
|
|
1197
|
+
*
|
|
1198
|
+
* Pulls www.kuaishou.com cookies from the user's Android Kuaishou App,
|
|
1199
|
+
* fetches uid + profile via cookie's api_ph payload (PURE COOKIE PARSE,
|
|
1200
|
+
* no HTTP) + 3 signed GraphQL endpoints (watch / collect / search).
|
|
1201
|
+
* CLI context has NO sign bridge — 3 signed endpoints short-circuit
|
|
1202
|
+
* with lastErrorCode=-99. Desktop wiring upgrades via KuaishouSignBridge.
|
|
1203
|
+
*/
|
|
1204
|
+
async function cmdKuaishouAdbSync(options) {
|
|
1205
|
+
try {
|
|
1206
|
+
const hub = await (options._getHub || getHub)();
|
|
1207
|
+
const result = await hub.kuaishouAdbSync({
|
|
1208
|
+
stagingDir: options.stagingDir,
|
|
1209
|
+
displayName: options.displayName,
|
|
1210
|
+
limits:
|
|
1211
|
+
options.limitWatch || options.limitCollect || options.limitSearch
|
|
1212
|
+
? {
|
|
1213
|
+
watch: parsePositiveInt(options.limitWatch),
|
|
1214
|
+
collect: parsePositiveInt(options.limitCollect),
|
|
1215
|
+
search: parsePositiveInt(options.limitSearch),
|
|
1216
|
+
}
|
|
1217
|
+
: undefined,
|
|
1218
|
+
});
|
|
1219
|
+
if (options.json) {
|
|
1220
|
+
printJson(result);
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
if (!result.ok) {
|
|
1224
|
+
logger.log(chalk.red(`✗ kuaishou-adb-sync failed: ${result.reason}`));
|
|
1225
|
+
logger.log(chalk.gray(` ${result.message || ""}`));
|
|
1226
|
+
if (result.reason === "BRIDGE_UNAVAILABLE") {
|
|
1227
|
+
logger.log(
|
|
1228
|
+
chalk.gray(
|
|
1229
|
+
" Install Android Platform Tools or set ADB_PATH=/path/to/adb",
|
|
1230
|
+
),
|
|
1231
|
+
);
|
|
1232
|
+
} else if (result.reason === "KUAISHOU_NO_ROOT") {
|
|
1233
|
+
logger.log(
|
|
1234
|
+
chalk.gray(
|
|
1235
|
+
" Phone needs Magisk root — Kuaishou release APK isn't debuggable",
|
|
1236
|
+
),
|
|
1237
|
+
);
|
|
1238
|
+
} else if (result.reason === "KUAISHOU_NOT_INSTALLED") {
|
|
1239
|
+
logger.log(
|
|
1240
|
+
chalk.gray(
|
|
1241
|
+
" Install 快手 (com.smile.gifmaker, NOT 极速版 com.kuaishou.nebula) + log in once + open any video (WebView populates cookies), then retry",
|
|
1242
|
+
),
|
|
1243
|
+
);
|
|
1244
|
+
} else if (result.reason === "KUAISHOU_COOKIES_INCOMPLETE") {
|
|
1245
|
+
logger.log(
|
|
1246
|
+
chalk.gray(
|
|
1247
|
+
" userId / kuaishou.web.cp.api_ph missing — relog on the Kuaishou App",
|
|
1248
|
+
),
|
|
1249
|
+
);
|
|
1250
|
+
} else if (
|
|
1251
|
+
result.reason === "KUAISHOU_COOKIES_TRUNCATED" ||
|
|
1252
|
+
result.reason === "KUAISHOU_NOT_SQLITE"
|
|
1253
|
+
) {
|
|
1254
|
+
logger.log(
|
|
1255
|
+
chalk.gray(
|
|
1256
|
+
" ADB stream may be corrupted; unplug + replug USB and retry",
|
|
1257
|
+
),
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
process.exitCode = 1;
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
const report = result.report || {};
|
|
1264
|
+
const kuaishou = report.kuaishou || {};
|
|
1265
|
+
const counts = kuaishou.eventCounts || {};
|
|
1266
|
+
logger.log(chalk.green(`✓ kuaishou-adb-sync succeeded`));
|
|
1267
|
+
logger.log(
|
|
1268
|
+
` uid: ${chalk.cyan(kuaishou.uid || "(profile fetch failed)")}`,
|
|
1269
|
+
);
|
|
1270
|
+
if (kuaishou.nickname) {
|
|
1271
|
+
logger.log(` nickname: ${kuaishou.nickname}`);
|
|
1272
|
+
}
|
|
1273
|
+
logger.log(` profile: ${counts.profile || 0}`);
|
|
1274
|
+
logger.log(` watch: ${counts.watch || 0}`);
|
|
1275
|
+
logger.log(` collect: ${counts.collect || 0}`);
|
|
1276
|
+
logger.log(` search: ${counts.search || 0}`);
|
|
1277
|
+
logger.log(` total: ${counts.total || 0}`);
|
|
1278
|
+
logger.log(` status: ${report.status || "?"}`);
|
|
1279
|
+
logger.log(` rawCount: ${report.rawCount || 0}`);
|
|
1280
|
+
if (kuaishou.profileFetchFailed) {
|
|
1281
|
+
logger.log(
|
|
1282
|
+
chalk.yellow(
|
|
1283
|
+
` ⚠ cookie 缺 kuaishou.web.cp.api_ph — relog on Kuaishou (lastErrorCode=${kuaishou.lastErrorCode})`,
|
|
1284
|
+
),
|
|
1285
|
+
);
|
|
1286
|
+
} else if (
|
|
1287
|
+
kuaishou.signProviderUsed === "none" &&
|
|
1288
|
+
counts.watch === 0 &&
|
|
1289
|
+
counts.collect === 0 &&
|
|
1290
|
+
counts.search === 0
|
|
1291
|
+
) {
|
|
1292
|
+
logger.log(
|
|
1293
|
+
chalk.yellow(
|
|
1294
|
+
` ⚠ 3 signed endpoints short-circuited (no sign bridge in CLI context) — run from desktop app to enable __NS_sig3 via Electron WebContentsView`,
|
|
1295
|
+
),
|
|
1296
|
+
);
|
|
1297
|
+
} else if (kuaishou.lastErrorCode) {
|
|
1298
|
+
logger.log(
|
|
1299
|
+
chalk.yellow(
|
|
1300
|
+
` ⚠ partial: lastErrorCode=${kuaishou.lastErrorCode} (${kuaishou.lastErrorMessage || "?"})`,
|
|
1301
|
+
),
|
|
1302
|
+
);
|
|
1303
|
+
}
|
|
1304
|
+
if (kuaishou.cleanupFailed) {
|
|
1305
|
+
logger.log(chalk.gray(` (note: staging cleanup failed — non-fatal)`));
|
|
1306
|
+
}
|
|
1307
|
+
} catch (err) {
|
|
1308
|
+
fail(null, err, options.json);
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
/**
|
|
1313
|
+
* Phase 6c — `cc hub toutiao-adb-sync`
|
|
1314
|
+
*
|
|
1315
|
+
* Pulls www.toutiao.com cookies from the user's Android Toutiao App,
|
|
1316
|
+
* fetches uid + profile (no _sig) + 3 signed endpoints (feed / collection
|
|
1317
|
+
* / search). CLI context has NO sign bridge — 3 signed endpoints short-
|
|
1318
|
+
* circuit with lastErrorCode=-99 (no HTTP traffic). Desktop wiring
|
|
1319
|
+
* upgrades via ToutiaoSignBridge (Electron WebContentsView).
|
|
1320
|
+
*/
|
|
1321
|
+
async function cmdToutiaoAdbSync(options) {
|
|
1322
|
+
try {
|
|
1323
|
+
const hub = await (options._getHub || getHub)();
|
|
1324
|
+
const result = await hub.toutiaoAdbSync({
|
|
1325
|
+
stagingDir: options.stagingDir,
|
|
1326
|
+
displayName: options.displayName,
|
|
1327
|
+
limits:
|
|
1328
|
+
options.limitFeed || options.limitCollection || options.limitSearch
|
|
1329
|
+
? {
|
|
1330
|
+
feed: parsePositiveInt(options.limitFeed),
|
|
1331
|
+
collection: parsePositiveInt(options.limitCollection),
|
|
1332
|
+
search: parsePositiveInt(options.limitSearch),
|
|
1333
|
+
}
|
|
1334
|
+
: undefined,
|
|
1335
|
+
});
|
|
1336
|
+
if (options.json) {
|
|
1337
|
+
printJson(result);
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
if (!result.ok) {
|
|
1341
|
+
logger.log(chalk.red(`✗ toutiao-adb-sync failed: ${result.reason}`));
|
|
1342
|
+
logger.log(chalk.gray(` ${result.message || ""}`));
|
|
1343
|
+
if (result.reason === "BRIDGE_UNAVAILABLE") {
|
|
1344
|
+
logger.log(
|
|
1345
|
+
chalk.gray(
|
|
1346
|
+
" Install Android Platform Tools or set ADB_PATH=/path/to/adb",
|
|
1347
|
+
),
|
|
1348
|
+
);
|
|
1349
|
+
} else if (result.reason === "TOUTIAO_NO_ROOT") {
|
|
1350
|
+
logger.log(
|
|
1351
|
+
chalk.gray(
|
|
1352
|
+
" Phone needs Magisk root — Toutiao release APK isn't debuggable",
|
|
1353
|
+
),
|
|
1354
|
+
);
|
|
1355
|
+
} else if (result.reason === "TOUTIAO_NOT_INSTALLED") {
|
|
1356
|
+
logger.log(
|
|
1357
|
+
chalk.gray(
|
|
1358
|
+
" Install 今日头条 (com.ss.android.article.news, NOT 极速版/.lite) + log in once + open any article (WebView populates cookies), then retry",
|
|
1359
|
+
),
|
|
1360
|
+
);
|
|
1361
|
+
} else if (result.reason === "TOUTIAO_COOKIES_INCOMPLETE") {
|
|
1362
|
+
logger.log(
|
|
1363
|
+
chalk.gray(
|
|
1364
|
+
" sessionid / sessionid_ss missing — relog on the Toutiao App",
|
|
1365
|
+
),
|
|
1366
|
+
);
|
|
1367
|
+
} else if (
|
|
1368
|
+
result.reason === "TOUTIAO_COOKIES_TRUNCATED" ||
|
|
1369
|
+
result.reason === "TOUTIAO_NOT_SQLITE"
|
|
1370
|
+
) {
|
|
1371
|
+
logger.log(
|
|
1372
|
+
chalk.gray(
|
|
1373
|
+
" ADB stream may be corrupted; unplug + replug USB and retry",
|
|
1374
|
+
),
|
|
1375
|
+
);
|
|
1376
|
+
}
|
|
1377
|
+
process.exitCode = 1;
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
const report = result.report || {};
|
|
1381
|
+
const toutiao = report.toutiao || {};
|
|
1382
|
+
const counts = toutiao.eventCounts || {};
|
|
1383
|
+
logger.log(chalk.green(`✓ toutiao-adb-sync succeeded`));
|
|
1384
|
+
logger.log(
|
|
1385
|
+
` uid: ${chalk.cyan(toutiao.uid || "(profile fetch failed)")}`,
|
|
1386
|
+
);
|
|
1387
|
+
if (toutiao.nickname) {
|
|
1388
|
+
logger.log(` nickname: ${toutiao.nickname}`);
|
|
1389
|
+
}
|
|
1390
|
+
logger.log(` profile: ${counts.profile || 0}`);
|
|
1391
|
+
logger.log(` feed: ${counts.feed || 0}`);
|
|
1392
|
+
logger.log(` collection: ${counts.collection || 0}`);
|
|
1393
|
+
logger.log(` search: ${counts.search || 0}`);
|
|
1394
|
+
logger.log(` total: ${counts.total || 0}`);
|
|
1395
|
+
logger.log(` status: ${report.status || "?"}`);
|
|
1396
|
+
logger.log(` rawCount: ${report.rawCount || 0}`);
|
|
1397
|
+
if (toutiao.profileFetchFailed) {
|
|
1398
|
+
logger.log(
|
|
1399
|
+
chalk.yellow(
|
|
1400
|
+
` ⚠ passport/info/v2 returned no user_id — cookie expired or sessionid missing (lastErrorCode=${toutiao.lastErrorCode})`,
|
|
1401
|
+
),
|
|
1402
|
+
);
|
|
1403
|
+
} else if (
|
|
1404
|
+
toutiao.signProviderUsed === "none" &&
|
|
1405
|
+
counts.feed === 0 &&
|
|
1406
|
+
counts.collection === 0 &&
|
|
1407
|
+
counts.search === 0
|
|
1408
|
+
) {
|
|
1409
|
+
logger.log(
|
|
1410
|
+
chalk.yellow(
|
|
1411
|
+
` ⚠ 3 signed endpoints short-circuited (no sign bridge in CLI context) — run from desktop app to enable _signature via Electron WebContentsView`,
|
|
1412
|
+
),
|
|
1413
|
+
);
|
|
1414
|
+
} else if (toutiao.lastErrorCode) {
|
|
1415
|
+
logger.log(
|
|
1416
|
+
chalk.yellow(
|
|
1417
|
+
` ⚠ partial: lastErrorCode=${toutiao.lastErrorCode} (${toutiao.lastErrorMessage || "?"})`,
|
|
1418
|
+
),
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
if (toutiao.cleanupFailed) {
|
|
1422
|
+
logger.log(chalk.gray(` (note: staging cleanup failed — non-fatal)`));
|
|
1423
|
+
}
|
|
1424
|
+
} catch (err) {
|
|
1425
|
+
fail(null, err, options.json);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
/**
|
|
1430
|
+
* Phase 3a — `cc hub weibo-adb-sync`
|
|
1431
|
+
*
|
|
1432
|
+
* Pulls m.weibo.cn cookies from the user's Android Weibo App, fetches
|
|
1433
|
+
* UID + 3 endpoints (posts/favourites/follows), ingests via social-weibo
|
|
1434
|
+
* adapter snapshot mode. Inline tip per typed reason codes.
|
|
1435
|
+
*/
|
|
1436
|
+
async function cmdWeiboAdbSync(options) {
|
|
1437
|
+
try {
|
|
1438
|
+
const hub = await (options._getHub || getHub)();
|
|
1439
|
+
const result = await hub.weiboAdbSync({
|
|
1440
|
+
stagingDir: options.stagingDir,
|
|
1441
|
+
displayName: options.displayName,
|
|
1442
|
+
limits:
|
|
1443
|
+
options.limitPost || options.limitFavourite || options.limitFollow
|
|
1444
|
+
? {
|
|
1445
|
+
post: parsePositiveInt(options.limitPost),
|
|
1446
|
+
favourite: parsePositiveInt(options.limitFavourite),
|
|
1447
|
+
follow: parsePositiveInt(options.limitFollow),
|
|
1448
|
+
}
|
|
1449
|
+
: undefined,
|
|
1450
|
+
});
|
|
1451
|
+
if (options.json) {
|
|
1452
|
+
printJson(result);
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1455
|
+
if (!result.ok) {
|
|
1456
|
+
logger.log(chalk.red(`✗ weibo-adb-sync failed: ${result.reason}`));
|
|
1457
|
+
logger.log(chalk.gray(` ${result.message || ""}`));
|
|
1458
|
+
if (result.reason === "BRIDGE_UNAVAILABLE") {
|
|
1459
|
+
logger.log(
|
|
1460
|
+
chalk.gray(
|
|
1461
|
+
" Install Android Platform Tools or set ADB_PATH=/path/to/adb",
|
|
1462
|
+
),
|
|
1463
|
+
);
|
|
1464
|
+
} else if (result.reason === "WEIBO_NO_ROOT") {
|
|
1465
|
+
logger.log(
|
|
1466
|
+
chalk.gray(
|
|
1467
|
+
" Phone needs Magisk root — Weibo release APK isn't debuggable",
|
|
1468
|
+
),
|
|
1469
|
+
);
|
|
1470
|
+
} else if (result.reason === "WEIBO_NOT_INSTALLED") {
|
|
1471
|
+
logger.log(
|
|
1472
|
+
chalk.gray(
|
|
1473
|
+
" Install Weibo App on the phone + log in once, then retry",
|
|
1474
|
+
),
|
|
1475
|
+
);
|
|
1476
|
+
} else if (result.reason === "WEIBO_COOKIES_INCOMPLETE") {
|
|
1477
|
+
logger.log(
|
|
1478
|
+
chalk.gray(
|
|
1479
|
+
" SUB cookie missing — relog on the Weibo App (or app uses non-default WebView profile dir)",
|
|
1480
|
+
),
|
|
1481
|
+
);
|
|
1482
|
+
} else if (
|
|
1483
|
+
result.reason === "WEIBO_COOKIES_TRUNCATED" ||
|
|
1484
|
+
result.reason === "WEIBO_NOT_SQLITE"
|
|
1485
|
+
) {
|
|
1486
|
+
logger.log(
|
|
1487
|
+
chalk.gray(
|
|
1488
|
+
" ADB stream may be corrupted; unplug + replug USB and retry",
|
|
1489
|
+
),
|
|
1490
|
+
);
|
|
1491
|
+
}
|
|
1492
|
+
process.exitCode = 1;
|
|
1493
|
+
return;
|
|
1494
|
+
}
|
|
1495
|
+
const report = result.report || {};
|
|
1496
|
+
const wb = report.weibo || {};
|
|
1497
|
+
const counts = wb.eventCounts || {};
|
|
1498
|
+
logger.log(chalk.green(`✓ weibo-adb-sync succeeded`));
|
|
1499
|
+
logger.log(` uid: ${chalk.cyan(wb.uid || "(uid fetch failed)")}`);
|
|
1500
|
+
logger.log(` posts: ${counts.post || 0}`);
|
|
1501
|
+
logger.log(` favourites: ${counts.favourite || 0}`);
|
|
1502
|
+
logger.log(` follows: ${counts.follow || 0}`);
|
|
1503
|
+
logger.log(` total: ${counts.total || 0}`);
|
|
1504
|
+
logger.log(` status: ${report.status || "?"}`);
|
|
1505
|
+
logger.log(` rawCount: ${report.rawCount || 0}`);
|
|
1506
|
+
if (wb.uidFetchFailed) {
|
|
1507
|
+
logger.log(
|
|
1508
|
+
chalk.yellow(
|
|
1509
|
+
` ⚠ /api/config returned login=false — cookie expired or anti-bot redirect (lastErrorCode=${wb.lastErrorCode})`,
|
|
1510
|
+
),
|
|
1511
|
+
);
|
|
1512
|
+
} else if (wb.lastErrorCode) {
|
|
1513
|
+
logger.log(
|
|
1514
|
+
chalk.yellow(
|
|
1515
|
+
` ⚠ partial: lastErrorCode=${wb.lastErrorCode} (${wb.lastErrorMessage || "?"})`,
|
|
1516
|
+
),
|
|
1517
|
+
);
|
|
1518
|
+
}
|
|
1519
|
+
if (wb.cleanupFailed) {
|
|
1520
|
+
logger.log(chalk.gray(` (note: staging cleanup failed — non-fatal)`));
|
|
1521
|
+
}
|
|
1522
|
+
} catch (err) {
|
|
1523
|
+
fail(null, err, options.json);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
/**
|
|
1528
|
+
* Phase 2a — `cc hub douyin-adb-sync`
|
|
1529
|
+
*
|
|
1530
|
+
* Pulls <uid>_im.db from the user's Android Douyin App, parses msg +
|
|
1531
|
+
* SIMPLE_USER (abrignoni DFIR schema), ingests via social-douyin adapter
|
|
1532
|
+
* snapshot mode. Inline tip per 9 typed reason codes.
|
|
1533
|
+
*/
|
|
1534
|
+
async function cmdDouyinAdbSync(options) {
|
|
1535
|
+
try {
|
|
1536
|
+
const hub = await (options._getHub || getHub)();
|
|
1537
|
+
const result = await hub.douyinAdbSync({
|
|
1538
|
+
uid: options.uid,
|
|
1539
|
+
stagingDir: options.stagingDir,
|
|
1540
|
+
displayName: options.displayName,
|
|
1541
|
+
limits:
|
|
1542
|
+
options.limitMessages || options.limitContacts
|
|
1543
|
+
? {
|
|
1544
|
+
messages: parsePositiveInt(options.limitMessages),
|
|
1545
|
+
contacts: parsePositiveInt(options.limitContacts),
|
|
1546
|
+
}
|
|
1547
|
+
: undefined,
|
|
1548
|
+
});
|
|
1549
|
+
if (options.json) {
|
|
1550
|
+
printJson(result);
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1553
|
+
if (!result.ok) {
|
|
1554
|
+
logger.log(chalk.red(`✗ douyin-adb-sync failed: ${result.reason}`));
|
|
1555
|
+
logger.log(chalk.gray(` ${result.message || ""}`));
|
|
1556
|
+
if (result.reason === "BRIDGE_UNAVAILABLE") {
|
|
1557
|
+
logger.log(
|
|
1558
|
+
chalk.gray(
|
|
1559
|
+
" Install Android Platform Tools or set ADB_PATH=/path/to/adb",
|
|
1560
|
+
),
|
|
1561
|
+
);
|
|
1562
|
+
} else if (result.reason === "DOUYIN_NO_ROOT") {
|
|
1563
|
+
logger.log(
|
|
1564
|
+
chalk.gray(
|
|
1565
|
+
" Phone needs Magisk root — Douyin release APK isn't debuggable",
|
|
1566
|
+
),
|
|
1567
|
+
);
|
|
1568
|
+
} else if (result.reason === "DOUYIN_NOT_INSTALLED") {
|
|
1569
|
+
logger.log(chalk.gray(" Install Douyin App on the phone, then retry"));
|
|
1570
|
+
} else if (result.reason === "DOUYIN_NO_IM_DB") {
|
|
1571
|
+
logger.log(
|
|
1572
|
+
chalk.gray(
|
|
1573
|
+
" Log in to Douyin App + open any chat thread to materialize the IM database",
|
|
1574
|
+
),
|
|
1575
|
+
);
|
|
1576
|
+
} else if (result.reason === "DOUYIN_MULTIPLE_USERS") {
|
|
1577
|
+
logger.log(
|
|
1578
|
+
chalk.gray(
|
|
1579
|
+
" Multiple accounts on this phone — pass --uid <19-digit> to pick one",
|
|
1580
|
+
),
|
|
1581
|
+
);
|
|
1582
|
+
}
|
|
1583
|
+
process.exitCode = 1;
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
const report = result.report || {};
|
|
1587
|
+
const dy = report.douyin || {};
|
|
1588
|
+
const counts = dy.eventCounts || {};
|
|
1589
|
+
logger.log(chalk.green(`✓ douyin-adb-sync succeeded`));
|
|
1590
|
+
logger.log(` uid: ${chalk.cyan(dy.uid)}`);
|
|
1591
|
+
logger.log(` messages: ${counts.message || 0}`);
|
|
1592
|
+
logger.log(` contacts: ${counts.contact || 0}`);
|
|
1593
|
+
logger.log(` total: ${counts.total || 0}`);
|
|
1594
|
+
logger.log(` status: ${report.status || "?"}`);
|
|
1595
|
+
logger.log(` rawCount: ${report.rawCount || 0}`);
|
|
1596
|
+
const diag = dy.parserDiagnostic || {};
|
|
1597
|
+
if (!diag.hadMsgTable) {
|
|
1598
|
+
logger.log(
|
|
1599
|
+
chalk.yellow(
|
|
1600
|
+
` ⚠ msg table not found — Douyin App version may use a different IM schema`,
|
|
1601
|
+
),
|
|
1602
|
+
);
|
|
1603
|
+
}
|
|
1604
|
+
if (!diag.hadSimpleUserTable) {
|
|
1605
|
+
logger.log(
|
|
1606
|
+
chalk.yellow(
|
|
1607
|
+
` ⚠ SIMPLE_USER table not found — contacts won't be ingested`,
|
|
1608
|
+
),
|
|
1609
|
+
);
|
|
1610
|
+
}
|
|
1611
|
+
if (dy.cleanupFailed) {
|
|
1612
|
+
logger.log(chalk.gray(` (note: staging cleanup failed — non-fatal)`));
|
|
1613
|
+
}
|
|
1614
|
+
} catch (err) {
|
|
1615
|
+
fail(null, err, options.json);
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
/**
|
|
1620
|
+
* Phase 1e — `cc hub bilibili-adb-doctor`
|
|
1621
|
+
*
|
|
1622
|
+
* Dry-run env probe. Runs only the cookies-extraction half of the sync
|
|
1623
|
+
* pipeline (no api.bilibili.com calls, no vault writes) so the user can
|
|
1624
|
+
* confirm root + Bilibili-installed + cookie-complete BEFORE triggering
|
|
1625
|
+
* a real sync. Surfaces the same 9 typed reasons as bilibili-adb-sync
|
|
1626
|
+
* but with a green "✓ ready to sync" message on success.
|
|
1627
|
+
*
|
|
1628
|
+
* Use this as the first command in a real-device E2E session.
|
|
1629
|
+
*/
|
|
1630
|
+
async function cmdBilibiliAdbDoctor(options) {
|
|
1631
|
+
try {
|
|
1632
|
+
const hub = await (options._getHub || getHub)();
|
|
1633
|
+
const result = await hub.bilibiliAdbDoctor();
|
|
1634
|
+
if (options.json) {
|
|
1635
|
+
printJson(result);
|
|
1636
|
+
return;
|
|
1637
|
+
}
|
|
1638
|
+
if (!result.ok) {
|
|
1639
|
+
logger.log(chalk.red(`✗ bilibili-adb-doctor: ${result.reason}`));
|
|
1640
|
+
logger.log(chalk.gray(` ${result.message || ""}`));
|
|
1641
|
+
if (result.reason === "BRIDGE_UNAVAILABLE") {
|
|
1642
|
+
logger.log(
|
|
1643
|
+
chalk.gray(
|
|
1644
|
+
" Fix: install Android Platform Tools, or set ADB_PATH=/path/to/adb",
|
|
1645
|
+
),
|
|
1646
|
+
);
|
|
1647
|
+
} else if (result.reason === "BILIBILI_NO_ROOT") {
|
|
1648
|
+
logger.log(
|
|
1649
|
+
chalk.gray(
|
|
1650
|
+
" Fix: phone needs Magisk root — Bilibili release APK isn't debuggable",
|
|
1651
|
+
),
|
|
1652
|
+
);
|
|
1653
|
+
} else if (
|
|
1654
|
+
result.reason === "BILIBILI_NOT_INSTALLED_OR_NEVER_LOGGED_IN"
|
|
1655
|
+
) {
|
|
1656
|
+
logger.log(
|
|
1657
|
+
chalk.gray(" Fix: install Bilibili App + log in once on the phone"),
|
|
1658
|
+
);
|
|
1659
|
+
} else if (result.reason === "BILIBILI_COOKIES_INCOMPLETE") {
|
|
1660
|
+
logger.log(
|
|
1661
|
+
chalk.gray(
|
|
1662
|
+
" Fix: relog on the Bilibili App — required cookies are missing",
|
|
1663
|
+
),
|
|
1664
|
+
);
|
|
1665
|
+
} else if (
|
|
1666
|
+
result.reason === "BILIBILI_COOKIES_TRUNCATED" ||
|
|
1667
|
+
result.reason === "BILIBILI_NOT_SQLITE"
|
|
1668
|
+
) {
|
|
1669
|
+
logger.log(
|
|
1670
|
+
chalk.gray(
|
|
1671
|
+
" Fix: ADB stream may be corrupted; unplug + replug USB and retry",
|
|
1672
|
+
),
|
|
1673
|
+
);
|
|
1674
|
+
}
|
|
1675
|
+
process.exitCode = 1;
|
|
1676
|
+
return;
|
|
1677
|
+
}
|
|
1678
|
+
const diag = result.cookieDiagnostic || {};
|
|
1679
|
+
logger.log(chalk.green(`✓ bilibili-adb-doctor: env ready to sync`));
|
|
1680
|
+
logger.log(` uid: ${chalk.cyan(result.uid)}`);
|
|
1681
|
+
logger.log(` cookies found: ${diag.cookieCount || "?"}`);
|
|
1682
|
+
if (diag.hadEncrypted) {
|
|
1683
|
+
logger.log(
|
|
1684
|
+
chalk.yellow(
|
|
1685
|
+
` ⚠ encrypted rows: some cookies are Android-Keystore-wrapped (skipped)`,
|
|
1686
|
+
),
|
|
1687
|
+
);
|
|
1688
|
+
logger.log(
|
|
1689
|
+
chalk.gray(
|
|
1690
|
+
` This may indicate a newer Bilibili App on Android 14+ using Keystore wrap.`,
|
|
1691
|
+
),
|
|
1692
|
+
);
|
|
1693
|
+
}
|
|
1694
|
+
logger.log(
|
|
1695
|
+
` extracted at: ${new Date(result.extractedAt).toISOString()}`,
|
|
1696
|
+
);
|
|
1697
|
+
logger.log(
|
|
1698
|
+
chalk.gray(
|
|
1699
|
+
`\n Next: run \`cc hub bilibili-adb-sync\` to ingest 4 endpoints.`,
|
|
1700
|
+
),
|
|
1701
|
+
);
|
|
1702
|
+
} catch (err) {
|
|
1703
|
+
fail(null, err, options.json);
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
|
|
980
1707
|
/**
|
|
981
1708
|
* `cc hub wechat doctor` — env-probe + actionable interpretation +
|
|
982
1709
|
* inline reference to the Phase 12.9 §5.1 Frida hook trap table.
|
|
@@ -1273,6 +2000,155 @@ export function registerHubCommand(program) {
|
|
|
1273
2000
|
.option("--json", "Output JSON")
|
|
1274
2001
|
.action(cmdSyncAll);
|
|
1275
2002
|
|
|
2003
|
+
// Phase 1c — Bilibili C 路径 one-shot
|
|
2004
|
+
hub
|
|
2005
|
+
.command("bilibili-adb-sync")
|
|
2006
|
+
.description(
|
|
2007
|
+
"Bilibili C 路径: pull cookies via ADB from the user's Android Bilibili App, fetch 4 endpoints, ingest as snapshot. Needs rooted Android + Bilibili App logged in + `adb` on PATH.",
|
|
2008
|
+
)
|
|
2009
|
+
.option("--limit-history <n>", "Cap history items (default 200)")
|
|
2010
|
+
.option(
|
|
2011
|
+
"--limit-favourite <n>",
|
|
2012
|
+
"Cap favourite items per folder (default 50)",
|
|
2013
|
+
)
|
|
2014
|
+
.option("--limit-dynamic <n>", "Cap dynamic items (default 50)")
|
|
2015
|
+
.option("--limit-follow <n>", "Cap follow items (default 200)")
|
|
2016
|
+
.option(
|
|
2017
|
+
"--display-name <s>",
|
|
2018
|
+
"Account displayName for the snapshot (default empty)",
|
|
2019
|
+
)
|
|
2020
|
+
.option(
|
|
2021
|
+
"--staging-dir <path>",
|
|
2022
|
+
"Custom dir for the temp snapshot JSON (default os.tmpdir())",
|
|
2023
|
+
)
|
|
2024
|
+
.option("--json", "Output JSON")
|
|
2025
|
+
.action(cmdBilibiliAdbSync);
|
|
2026
|
+
|
|
2027
|
+
// Phase 1e — dry-run env probe (cookies only, no API, no vault write)
|
|
2028
|
+
hub
|
|
2029
|
+
.command("bilibili-adb-doctor")
|
|
2030
|
+
.description(
|
|
2031
|
+
"Bilibili C 路径 dry-run: probe adb + root + Bilibili App + cookies completeness without triggering a sync. Use this BEFORE `cc hub bilibili-adb-sync` to debug env issues.",
|
|
2032
|
+
)
|
|
2033
|
+
.option("--json", "Output JSON")
|
|
2034
|
+
.action(cmdBilibiliAdbDoctor);
|
|
2035
|
+
|
|
2036
|
+
// Phase 3a — Weibo C 路径 one-shot (m.weibo.cn cookies + 4 endpoints, sign-less)
|
|
2037
|
+
hub
|
|
2038
|
+
.command("weibo-adb-sync")
|
|
2039
|
+
.description(
|
|
2040
|
+
"Weibo C 路径: pull m.weibo.cn cookies via ADB from the user's Android Weibo App, fetch UID + 3 endpoints (posts/favourites/follows), ingest as snapshot. Needs rooted Android + Weibo App logged in + `adb` on PATH. No X-Bogus / WBI signing required.",
|
|
2041
|
+
)
|
|
2042
|
+
.option("--limit-post <n>", "Cap user-timeline posts (default 100)")
|
|
2043
|
+
.option("--limit-favourite <n>", "Cap favourite items (default 100)")
|
|
2044
|
+
.option("--limit-follow <n>", "Cap follow items (default 200)")
|
|
2045
|
+
.option(
|
|
2046
|
+
"--display-name <s>",
|
|
2047
|
+
"Account displayName for the snapshot (default empty)",
|
|
2048
|
+
)
|
|
2049
|
+
.option(
|
|
2050
|
+
"--staging-dir <path>",
|
|
2051
|
+
"Custom dir for the temp snapshot JSON (default os.tmpdir())",
|
|
2052
|
+
)
|
|
2053
|
+
.option("--json", "Output JSON")
|
|
2054
|
+
.action(cmdWeiboAdbSync);
|
|
2055
|
+
|
|
2056
|
+
// Phase 6d — Kuaishou C 路径 one-shot (www.kuaishou.com cookies + profile
|
|
2057
|
+
// from api_ph + 3 GraphQL endpoints with __NS_sig3 + kpf/kpn).
|
|
2058
|
+
// CLI: signed endpoints short-circuit. Desktop: KuaishouSignBridge.
|
|
2059
|
+
hub
|
|
2060
|
+
.command("kuaishou-adb-sync")
|
|
2061
|
+
.description(
|
|
2062
|
+
"Kuaishou C 路径: pull www.kuaishou.com cookies via ADB from the user's Android Kuaishou App (com.smile.gifmaker, NOT 极速版 com.kuaishou.nebula), parse profile from kuaishou.web.cp.api_ph cookie payload (no HTTP) + 3 GraphQL endpoints (watch/collect/search, __NS_sig3 + kpf/kpn — CLI short-circuits, desktop uses KuaishouSignBridge). Needs rooted Android + Kuaishou App logged in once + opened a video once + `adb` on PATH.",
|
|
2063
|
+
)
|
|
2064
|
+
.option(
|
|
2065
|
+
"--limit-watch <n>",
|
|
2066
|
+
"Cap recommended feed watch history (default 50)",
|
|
2067
|
+
)
|
|
2068
|
+
.option("--limit-collect <n>", "Cap own posted photos (default 100)")
|
|
2069
|
+
.option("--limit-search <n>", "Cap search history (default 50)")
|
|
2070
|
+
.option(
|
|
2071
|
+
"--display-name <s>",
|
|
2072
|
+
"Account displayName for the snapshot (default = api_ph user_name)",
|
|
2073
|
+
)
|
|
2074
|
+
.option(
|
|
2075
|
+
"--staging-dir <path>",
|
|
2076
|
+
"Custom dir for the temp snapshot JSON (default os.tmpdir())",
|
|
2077
|
+
)
|
|
2078
|
+
.option("--json", "Output JSON")
|
|
2079
|
+
.action(cmdKuaishouAdbSync);
|
|
2080
|
+
|
|
2081
|
+
// Phase 6c — Toutiao C 路径 one-shot (www.toutiao.com cookies + profile +
|
|
2082
|
+
// 3 endpoints with _signature). CLI context: signed endpoints short-circuit
|
|
2083
|
+
// (-99) with no HTTP traffic. Desktop: ToutiaoSignBridge → ~100% hit.
|
|
2084
|
+
hub
|
|
2085
|
+
.command("toutiao-adb-sync")
|
|
2086
|
+
.description(
|
|
2087
|
+
"Toutiao C 路径: pull www.toutiao.com cookies via ADB from the user's Android Toutiao App (com.ss.android.article.news, NOT 极速版), fetch profile (no _sig) + 3 endpoints (feed/collection/search, _signature required — CLI short-circuits, desktop uses ToutiaoSignBridge). Needs rooted Android + Toutiao App logged in once + `adb` on PATH.",
|
|
2088
|
+
)
|
|
2089
|
+
.option("--limit-feed <n>", "Cap recommended feed (default 50)")
|
|
2090
|
+
.option("--limit-collection <n>", "Cap saved articles (default 200)")
|
|
2091
|
+
.option("--limit-search <n>", "Cap search history (default 100)")
|
|
2092
|
+
.option(
|
|
2093
|
+
"--display-name <s>",
|
|
2094
|
+
"Account displayName for the snapshot (default = passport screen_name)",
|
|
2095
|
+
)
|
|
2096
|
+
.option(
|
|
2097
|
+
"--staging-dir <path>",
|
|
2098
|
+
"Custom dir for the temp snapshot JSON (default os.tmpdir())",
|
|
2099
|
+
)
|
|
2100
|
+
.option("--json", "Output JSON")
|
|
2101
|
+
.action(cmdToutiaoAdbSync);
|
|
2102
|
+
|
|
2103
|
+
// Phase 3c — Xhs C 路径 one-shot (xiaohongshu.com cookies + 4 endpoints with X-S signing)
|
|
2104
|
+
hub
|
|
2105
|
+
.command("xhs-adb-sync")
|
|
2106
|
+
.description(
|
|
2107
|
+
"Xhs C 路径: pull xiaohongshu.com cookies via ADB from the user's Android Xhs App, fetch userId + 3 endpoints (notes/liked/follows). Best-effort X-S signing (~60% GET hit rate). Needs rooted Android + Xhs App logged in + `adb` on PATH.",
|
|
2108
|
+
)
|
|
2109
|
+
.option("--limit-note <n>", "Cap user notes (default 30)")
|
|
2110
|
+
.option("--limit-liked <n>", "Cap liked notes (default 30)")
|
|
2111
|
+
.option("--limit-follow <n>", "Cap follow list (default 100)")
|
|
2112
|
+
.option(
|
|
2113
|
+
"--display-name <s>",
|
|
2114
|
+
"Account displayName for the snapshot (default = xhs nickname)",
|
|
2115
|
+
)
|
|
2116
|
+
.option(
|
|
2117
|
+
"--staging-dir <path>",
|
|
2118
|
+
"Custom dir for the temp snapshot JSON (default os.tmpdir())",
|
|
2119
|
+
)
|
|
2120
|
+
.option("--json", "Output JSON")
|
|
2121
|
+
.action(cmdXhsAdbSync);
|
|
2122
|
+
|
|
2123
|
+
// Phase 2a — Douyin C 路径 one-shot (pull <uid>_im.db → parse abrignoni DFIR schema)
|
|
2124
|
+
hub
|
|
2125
|
+
.command("douyin-adb-sync")
|
|
2126
|
+
.description(
|
|
2127
|
+
"Douyin C 路径: pull <uid>_im.db cohort via ADB from the user's Android Douyin App, parse msg + SIMPLE_USER (abrignoni DFIR), ingest as snapshot. Needs rooted Android + Douyin App logged in + `adb` on PATH.",
|
|
2128
|
+
)
|
|
2129
|
+
.option(
|
|
2130
|
+
"--uid <id>",
|
|
2131
|
+
"19-digit Douyin uid — required when multiple accounts logged in on the phone",
|
|
2132
|
+
)
|
|
2133
|
+
.option(
|
|
2134
|
+
"--limit-messages <n>",
|
|
2135
|
+
"Cap msg rows from the IM db (default 10000)",
|
|
2136
|
+
)
|
|
2137
|
+
.option(
|
|
2138
|
+
"--limit-contacts <n>",
|
|
2139
|
+
"Cap SIMPLE_USER rows from the IM db (default 5000)",
|
|
2140
|
+
)
|
|
2141
|
+
.option(
|
|
2142
|
+
"--display-name <s>",
|
|
2143
|
+
"Account displayName for the snapshot (default empty)",
|
|
2144
|
+
)
|
|
2145
|
+
.option(
|
|
2146
|
+
"--staging-dir <path>",
|
|
2147
|
+
"Custom dir for the temp snapshot JSON (default os.tmpdir())",
|
|
2148
|
+
)
|
|
2149
|
+
.option("--json", "Output JSON")
|
|
2150
|
+
.action(cmdDouyinAdbSync);
|
|
2151
|
+
|
|
1276
2152
|
hub
|
|
1277
2153
|
.command("rederive")
|
|
1278
2154
|
.description(
|
|
@@ -1515,6 +2391,13 @@ export const _internal = {
|
|
|
1515
2391
|
cmdWechatList,
|
|
1516
2392
|
cmdWechatUnregister,
|
|
1517
2393
|
cmdWechatDoctor,
|
|
2394
|
+
cmdBilibiliAdbSync,
|
|
2395
|
+
cmdBilibiliAdbDoctor,
|
|
2396
|
+
cmdDouyinAdbSync,
|
|
2397
|
+
cmdWeiboAdbSync,
|
|
2398
|
+
cmdXhsAdbSync,
|
|
2399
|
+
cmdToutiaoAdbSync,
|
|
2400
|
+
cmdKuaishouAdbSync,
|
|
1518
2401
|
interpretWechatProbe,
|
|
1519
2402
|
_defaultKnownVendors,
|
|
1520
2403
|
};
|