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.
- package/package.json +2 -2
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-VbMLpnCu.js → AIOps-CAdsXHkz.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BR6BrZ2w.js → ActionButton-JsLRBlBP.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DWN2iHDA.js → Analytics-DeM96q71.js} +1 -1
- package/src/assets/web-panel/assets/{AppLayout-CyBXOO_H.js → AppLayout-eb_6mT6V.js} +2 -2
- package/src/assets/web-panel/assets/{Audit-Cu5a4b5S.js → Audit-BEOY-CQE.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-D0vrJYkS.js → Backup-irFD_DBa.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DnFk3wDi.js → BaseInput-Dq7wtv_k.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-DFMa9lEz.js → Chat-CstRKWdu.js} +1 -1
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CpVazmEP.js → ChatBubbleRenderer-3BBqk317.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-J23wKgNR.js → Checkbox-A8D25IT5.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-Ca6Z4r1p.js → Codegen-1EfMWeRA.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BZ3XsxN2.js → Col-Bc08LzOn.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DhK5H5dD.js → Community-BNnNv7xp.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DjJMyddV.js → Compact-nFjLneHM.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Bup3Rk9z.js → Compliance-CZpaaHND.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BqsPMIpo.js → Cowork-DzHugH3j.js} +1 -1
- package/src/assets/web-panel/assets/{Cron-Ca69LFf-.js → Cron-C7YRyiN-.js} +1 -1
- package/src/assets/web-panel/assets/{Crosschain-mTB21YwK.js → Crosschain-er2h0L0q.js} +1 -1
- package/src/assets/web-panel/assets/{DID-C1_Eree4.js → DID-DaMdE0A7.js} +1 -1
- package/src/assets/web-panel/assets/{Dashboard-L2OWv5io.js → Dashboard-1z2K_E1B.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CpqNwurh.js → Dropdown-B9NIqAXf.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Mo7D9ADF.js → EmailListRenderer-CBHLFokz.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-COTeKl2R.js → Federation-D2fEJEki.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-0oTTQ9MI.js → FormItemContext-tmsd70yG.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DrMs3upM.js → GenericCardRenderer-DW4Lnrsr.js} +1 -1
- package/src/assets/web-panel/assets/{Git-C6eFUBhz.js → Git-D8aBagAp.js} +1 -1
- package/src/assets/web-panel/assets/{Governance-5ivL10kw.js → Governance-CKDAHamy.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DcERJUS_.js → Inference-BLLp118j.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Dm1eQ_Hv.js → KnowledgeGraph-Cawx-yfu.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-Cjt-JTuL.js → Logs-sWSzp5PY.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-fNDRN8YJ.js → Marketplace-BQMX3dSy.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-kKgzl9Bb.js → McpTools-DjlFST3o.js} +1 -1
- package/src/assets/web-panel/assets/{Memory-BdJujXCH.js → Memory-LZE1wG7m.js} +1 -1
- package/src/assets/web-panel/assets/{MobileBridge-lmvJfnpK.js → MobileBridge-BWG47jQ6.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-ZM-DVPhi.js → MobileProjects-DHVv0tYo.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CeoaWgzU.js → Mtc-Di1hrhM3.js} +1 -1
- package/src/assets/web-panel/assets/{MtcAudit-CRvKTLqr.js → MtcAudit-BowOCi-O.js} +1 -1
- package/src/assets/web-panel/assets/{Multisig-DnzFw69O.js → Multisig-CgpR0s8E.js} +1 -1
- package/src/assets/web-panel/assets/{NLProgramming-0xP2rtGN.js → NLProgramming-O4U3Plxd.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-tJpp3z8e.js → Notes-Ce_5C6XT.js} +1 -1
- package/src/assets/web-panel/assets/{NotificationSettings-CRdpEoHX.js → NotificationSettings-BVVopkxj.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-BEH9lAIb.js → OrderTableRenderer-XW2G50wt.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-Dhwy6dXT.js → Organization-DaW54kdP.js} +1 -1
- package/src/assets/web-panel/assets/{Overflow-COwwTMb-.js → Overflow-CVTGMUVt.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-79YWb-cn.js → P2P-CpEwrhBx.js} +1 -1
- package/src/assets/web-panel/assets/{PdhVaultBrowser-Dhn5S3Vs.js → PdhVaultBrowser-CDqun-Z9.js} +2 -2
- package/src/assets/web-panel/assets/{Permissions-ELRvDOlY.js → Permissions-BsSU3MaL.js} +1 -1
- package/src/assets/web-panel/assets/PersonalDataHub-BafcAH5d.js +1 -0
- package/src/assets/web-panel/assets/{PersonalDataHub-D0ncF92t.css → PersonalDataHub-DmUc89_0.css} +1 -1
- package/src/assets/web-panel/assets/{Pipeline-Dzi1zmAr.js → Pipeline-CPCDpDyd.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BYzWkaRt.js → Privacy-oZEQvVWA.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-D_5DqLSS.js → ProjectInit-CRu5bDNW.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectSettings-DrAAYJgR.js → ProjectSettings-ComIZ7gQ.js} +1 -1
- package/src/assets/web-panel/assets/{Projects-BOrF4_X8.js → Projects-Djr10qFp.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DYLWZVe4.js → Providers-CltNzV7e.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-k76cZTaF.js → QuickAsk-C21t1JEf.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CXM4p6RB.js → Recommend-BjJForJo.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-DLnLpz8L.js → Reputation-Cp8Ym-Hk.js} +1 -1
- package/src/assets/web-panel/assets/{Row-BavvTUrL.js → Row-n8ruyEoT.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CtCarC8_.js → RssFeed-CosaiHvS.js} +1 -1
- package/src/assets/web-panel/assets/{Search-CJcDGc1x.js → Search-DUNSNFJZ.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DB3GmnY9.js → Security-Z3WyX_MB.js} +1 -1
- package/src/assets/web-panel/assets/{Services-BWEvVHhz.js → Services-U0m9Oj8V.js} +1 -1
- package/src/assets/web-panel/assets/{Skeleton-BHbixeGV.js → Skeleton-B_M5sv2W.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DWwIjvjl.js → Skills-NKU9c6LT.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-C1Qu9o0j.js → Sla-DscfpqF8.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BiEysZg1.js → SpeechSettings-DP0O84ej.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-XlOLFUv2.js → SyncSettings-P_WEyoH3.js} +1 -1
- package/src/assets/web-panel/assets/{Tasks-BKjOcYxW.js → Tasks-C8YAncnj.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BVKjc9j-.js → Templates-F12-SRc3.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-C33WmSiJ.js → Tenant-CULHbrwu.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-Dl8RJZHg.js → Terminal-DdYrQ0n3.js} +1 -1
- package/src/assets/web-panel/assets/{TimelineRenderer-CFN36N3H.js → TimelineRenderer-C12_BYAe.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Dy2kxiCA.js → Tokens-8MVLlc0s.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-C7bt0leJ.js → Trigger-Bl6QmvKw.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CVKbWEMH.js → Trust-BH_aEsWy.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B91QGwbs.js → UkeySign-DsX2CeE4.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-C8xBqRiE.js → VideoEditing-DaRdn6e9.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-RW2IBbpH.js → Wallet-DO89dzlU.js} +1 -1
- package/src/assets/web-panel/assets/{WebAuthn-CZPv5ayn.js → WebAuthn-KUKNjImY.js} +1 -1
- package/src/assets/web-panel/assets/{WorkflowEditor-CFCwic4a.js → WorkflowEditor-CnSoP-Z9.js} +1 -1
- package/src/assets/web-panel/assets/{chat-PVfHUaHj.js → chat-Jp0M9E52.js} +1 -1
- package/src/assets/web-panel/assets/{colors-C4WA0-Iq.js → colors-Bkq4q91x.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DQfLwjbC.js → compact-item-CCt1byem.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-31PSlu0j.js → createContext-DwRLi0Uq.js} +1 -1
- package/src/assets/web-panel/assets/{hasIn-Csltfg47.js → hasIn-CTVm-2lw.js} +1 -1
- package/src/assets/web-panel/assets/{index-DfbOwhkA.js → index-6OmglXey.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdrYhK__.js → index-B2pkXVOU.js} +1 -1
- package/src/assets/web-panel/assets/{index-DuZKKJDi.js → index-B3irAeY8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DW-7sqm0.js → index-B9q3wKEr.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ba6cQs-y.js → index-BD2U0Ciz.js} +3 -3
- package/src/assets/web-panel/assets/{index-CArRkfYM.js → index-BJmiHI2z.js} +1 -1
- package/src/assets/web-panel/assets/{index-BiFRGYGH.js → index-B_U_xDvh.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-aRUTIJ.js → index-BhSbNePw.js} +1 -1
- package/src/assets/web-panel/assets/{index-BqOmboiA.js → index-BjGcDwb2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DVHR_To_.js → index-BtzUDs1M.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpEj71nk.js → index-BziGa10S.js} +1 -1
- package/src/assets/web-panel/assets/{index-nAhW-NN4.js → index-C2ovimhG.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSO9eU_G.js → index-C3ZzMEg0.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cgt2_bmM.js → index-CDbgmmSF.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQWE2WKS.js → index-CFh73FRz.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmzuBE2G.js → index-CIBi-rGt.js} +1 -1
- package/src/assets/web-panel/assets/{index-CIeFJLHG.js → index-CJWYdgmz.js} +1 -1
- package/src/assets/web-panel/assets/{index-CfWk9Yzf.js → index-CLjugrcu.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCxhSOsr.js → index-CPnSymMN.js} +1 -1
- package/src/assets/web-panel/assets/index-CR2wmKfw.js +1 -0
- package/src/assets/web-panel/assets/{index-CEtPU50W.js → index-CdlVwys1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BLwrQAlK.js → index-CjJWQqPG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BD-K1g5z.js → index-Cvrka2TD.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUFwsCsD.js → index-D-UAtktg.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4gzD6Ra.js → index-DC-8E2CG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCyTEqF7.js → index-DFcr_PT2.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpXm8DBk.js → index-DJegJP2N.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdQUx-5Z.js → index-DRkGL2HJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DtUcq8Nn.js → index-DRwUdk7I.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dymm64KM.js → index-DWQ9NRWg.js} +1 -1
- package/src/assets/web-panel/assets/{index-41v9Hflm.js → index-DXDSJwDk.js} +1 -1
- package/src/assets/web-panel/assets/{index-8IVdEMKr.js → index-Db3R-khd.js} +1 -1
- package/src/assets/web-panel/assets/{index-C_k_btzK.js → index-MdArO-BF.js} +1 -1
- package/src/assets/web-panel/assets/{index-CE8i90GF.js → index-TL3iHPdE.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbpUjcEf.js → index-TqiVFiUf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEbbRpw2.js → index-eyVkd-kF.js} +1 -1
- package/src/assets/web-panel/assets/{index-45Iyof95.js → index-hpRtUCjU.js} +1 -1
- package/src/assets/web-panel/assets/index-iXk8Oeci.js +1 -0
- package/src/assets/web-panel/assets/{index-P9rJg2C1.js → index-zwGGcR7I.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DPk1oFCk.js → initDefaultProps-9iSe4Eid.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CzQ1k8MU.js → motion-CcUz2pq7.js} +1 -1
- package/src/assets/web-panel/assets/{move-BCExaQ0x.js → move-3Po9fM71.js} +1 -1
- package/src/assets/web-panel/assets/{omit-D71nF5o_.js → omit-BBcRnciw.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-pvCq8tx4.js → pickAttrs-UCqcWwOy.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-D8lSLg_0.js → placementArrow-boVtHxA4.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-ZN6pVHvM.js → responsiveObserve-V0qPHZOl.js} +1 -1
- package/src/assets/web-panel/assets/{slide-VHxyZhFr.js → slide-CZyysA_q.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-B0jFTTFP.js → statusUtils-BLyCU5L3.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Bc6FRYW9.js → styleChecker-BfXrPW7h.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-D4YDiqxr.js → useFlexGapSupport-Be2wILDi.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CQgQ7iah.js → useFs-CzJYoHOI.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-LDh_Sq7B.js → usePersonalDataHub-__HEfTF9.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BwPvBDfI.js → vnode-C0XE0aCE.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-r6u1_Sq8.js → zoom-CphwCBhl.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-weibo-adb-sync.test.js +163 -0
- package/src/commands/__tests__/hub-xhs-adb-sync.test.js +155 -0
- package/src/commands/hub.js +600 -0
- package/src/gateways/ws/personal-data-hub-protocol.js +50 -0
- package/src/lib/host-adb-bridge.js +77 -1
- package/src/lib/personal-data-hub-wiring.js +349 -12
- package/src/assets/web-panel/assets/PersonalDataHub-DIWbfS5k.js +0 -1
- package/src/assets/web-panel/assets/index-3NsH3wNq.js +0 -1
- package/src/assets/web-panel/assets/index-DWtc_qRj.js +0 -1
package/src/commands/hub.js
CHANGED
|
@@ -977,6 +977,499 @@ 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 3a — `cc hub weibo-adb-sync`
|
|
1197
|
+
*
|
|
1198
|
+
* Pulls m.weibo.cn cookies from the user's Android Weibo App, fetches
|
|
1199
|
+
* UID + 3 endpoints (posts/favourites/follows), ingests via social-weibo
|
|
1200
|
+
* adapter snapshot mode. Inline tip per typed reason codes.
|
|
1201
|
+
*/
|
|
1202
|
+
async function cmdWeiboAdbSync(options) {
|
|
1203
|
+
try {
|
|
1204
|
+
const hub = await (options._getHub || getHub)();
|
|
1205
|
+
const result = await hub.weiboAdbSync({
|
|
1206
|
+
stagingDir: options.stagingDir,
|
|
1207
|
+
displayName: options.displayName,
|
|
1208
|
+
limits:
|
|
1209
|
+
options.limitPost || options.limitFavourite || options.limitFollow
|
|
1210
|
+
? {
|
|
1211
|
+
post: parsePositiveInt(options.limitPost),
|
|
1212
|
+
favourite: parsePositiveInt(options.limitFavourite),
|
|
1213
|
+
follow: parsePositiveInt(options.limitFollow),
|
|
1214
|
+
}
|
|
1215
|
+
: undefined,
|
|
1216
|
+
});
|
|
1217
|
+
if (options.json) {
|
|
1218
|
+
printJson(result);
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
if (!result.ok) {
|
|
1222
|
+
logger.log(chalk.red(`✗ weibo-adb-sync failed: ${result.reason}`));
|
|
1223
|
+
logger.log(chalk.gray(` ${result.message || ""}`));
|
|
1224
|
+
if (result.reason === "BRIDGE_UNAVAILABLE") {
|
|
1225
|
+
logger.log(
|
|
1226
|
+
chalk.gray(
|
|
1227
|
+
" Install Android Platform Tools or set ADB_PATH=/path/to/adb",
|
|
1228
|
+
),
|
|
1229
|
+
);
|
|
1230
|
+
} else if (result.reason === "WEIBO_NO_ROOT") {
|
|
1231
|
+
logger.log(
|
|
1232
|
+
chalk.gray(
|
|
1233
|
+
" Phone needs Magisk root — Weibo release APK isn't debuggable",
|
|
1234
|
+
),
|
|
1235
|
+
);
|
|
1236
|
+
} else if (result.reason === "WEIBO_NOT_INSTALLED") {
|
|
1237
|
+
logger.log(
|
|
1238
|
+
chalk.gray(
|
|
1239
|
+
" Install Weibo App on the phone + log in once, then retry",
|
|
1240
|
+
),
|
|
1241
|
+
);
|
|
1242
|
+
} else if (result.reason === "WEIBO_COOKIES_INCOMPLETE") {
|
|
1243
|
+
logger.log(
|
|
1244
|
+
chalk.gray(
|
|
1245
|
+
" SUB cookie missing — relog on the Weibo App (or app uses non-default WebView profile dir)",
|
|
1246
|
+
),
|
|
1247
|
+
);
|
|
1248
|
+
} else if (
|
|
1249
|
+
result.reason === "WEIBO_COOKIES_TRUNCATED" ||
|
|
1250
|
+
result.reason === "WEIBO_NOT_SQLITE"
|
|
1251
|
+
) {
|
|
1252
|
+
logger.log(
|
|
1253
|
+
chalk.gray(
|
|
1254
|
+
" ADB stream may be corrupted; unplug + replug USB and retry",
|
|
1255
|
+
),
|
|
1256
|
+
);
|
|
1257
|
+
}
|
|
1258
|
+
process.exitCode = 1;
|
|
1259
|
+
return;
|
|
1260
|
+
}
|
|
1261
|
+
const report = result.report || {};
|
|
1262
|
+
const wb = report.weibo || {};
|
|
1263
|
+
const counts = wb.eventCounts || {};
|
|
1264
|
+
logger.log(chalk.green(`✓ weibo-adb-sync succeeded`));
|
|
1265
|
+
logger.log(` uid: ${chalk.cyan(wb.uid || "(uid fetch failed)")}`);
|
|
1266
|
+
logger.log(` posts: ${counts.post || 0}`);
|
|
1267
|
+
logger.log(` favourites: ${counts.favourite || 0}`);
|
|
1268
|
+
logger.log(` follows: ${counts.follow || 0}`);
|
|
1269
|
+
logger.log(` total: ${counts.total || 0}`);
|
|
1270
|
+
logger.log(` status: ${report.status || "?"}`);
|
|
1271
|
+
logger.log(` rawCount: ${report.rawCount || 0}`);
|
|
1272
|
+
if (wb.uidFetchFailed) {
|
|
1273
|
+
logger.log(
|
|
1274
|
+
chalk.yellow(
|
|
1275
|
+
` ⚠ /api/config returned login=false — cookie expired or anti-bot redirect (lastErrorCode=${wb.lastErrorCode})`,
|
|
1276
|
+
),
|
|
1277
|
+
);
|
|
1278
|
+
} else if (wb.lastErrorCode) {
|
|
1279
|
+
logger.log(
|
|
1280
|
+
chalk.yellow(
|
|
1281
|
+
` ⚠ partial: lastErrorCode=${wb.lastErrorCode} (${wb.lastErrorMessage || "?"})`,
|
|
1282
|
+
),
|
|
1283
|
+
);
|
|
1284
|
+
}
|
|
1285
|
+
if (wb.cleanupFailed) {
|
|
1286
|
+
logger.log(chalk.gray(` (note: staging cleanup failed — non-fatal)`));
|
|
1287
|
+
}
|
|
1288
|
+
} catch (err) {
|
|
1289
|
+
fail(null, err, options.json);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
/**
|
|
1294
|
+
* Phase 2a — `cc hub douyin-adb-sync`
|
|
1295
|
+
*
|
|
1296
|
+
* Pulls <uid>_im.db from the user's Android Douyin App, parses msg +
|
|
1297
|
+
* SIMPLE_USER (abrignoni DFIR schema), ingests via social-douyin adapter
|
|
1298
|
+
* snapshot mode. Inline tip per 9 typed reason codes.
|
|
1299
|
+
*/
|
|
1300
|
+
async function cmdDouyinAdbSync(options) {
|
|
1301
|
+
try {
|
|
1302
|
+
const hub = await (options._getHub || getHub)();
|
|
1303
|
+
const result = await hub.douyinAdbSync({
|
|
1304
|
+
uid: options.uid,
|
|
1305
|
+
stagingDir: options.stagingDir,
|
|
1306
|
+
displayName: options.displayName,
|
|
1307
|
+
limits:
|
|
1308
|
+
options.limitMessages || options.limitContacts
|
|
1309
|
+
? {
|
|
1310
|
+
messages: parsePositiveInt(options.limitMessages),
|
|
1311
|
+
contacts: parsePositiveInt(options.limitContacts),
|
|
1312
|
+
}
|
|
1313
|
+
: undefined,
|
|
1314
|
+
});
|
|
1315
|
+
if (options.json) {
|
|
1316
|
+
printJson(result);
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
if (!result.ok) {
|
|
1320
|
+
logger.log(chalk.red(`✗ douyin-adb-sync failed: ${result.reason}`));
|
|
1321
|
+
logger.log(chalk.gray(` ${result.message || ""}`));
|
|
1322
|
+
if (result.reason === "BRIDGE_UNAVAILABLE") {
|
|
1323
|
+
logger.log(
|
|
1324
|
+
chalk.gray(
|
|
1325
|
+
" Install Android Platform Tools or set ADB_PATH=/path/to/adb",
|
|
1326
|
+
),
|
|
1327
|
+
);
|
|
1328
|
+
} else if (result.reason === "DOUYIN_NO_ROOT") {
|
|
1329
|
+
logger.log(
|
|
1330
|
+
chalk.gray(
|
|
1331
|
+
" Phone needs Magisk root — Douyin release APK isn't debuggable",
|
|
1332
|
+
),
|
|
1333
|
+
);
|
|
1334
|
+
} else if (result.reason === "DOUYIN_NOT_INSTALLED") {
|
|
1335
|
+
logger.log(chalk.gray(" Install Douyin App on the phone, then retry"));
|
|
1336
|
+
} else if (result.reason === "DOUYIN_NO_IM_DB") {
|
|
1337
|
+
logger.log(
|
|
1338
|
+
chalk.gray(
|
|
1339
|
+
" Log in to Douyin App + open any chat thread to materialize the IM database",
|
|
1340
|
+
),
|
|
1341
|
+
);
|
|
1342
|
+
} else if (result.reason === "DOUYIN_MULTIPLE_USERS") {
|
|
1343
|
+
logger.log(
|
|
1344
|
+
chalk.gray(
|
|
1345
|
+
" Multiple accounts on this phone — pass --uid <19-digit> to pick one",
|
|
1346
|
+
),
|
|
1347
|
+
);
|
|
1348
|
+
}
|
|
1349
|
+
process.exitCode = 1;
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
const report = result.report || {};
|
|
1353
|
+
const dy = report.douyin || {};
|
|
1354
|
+
const counts = dy.eventCounts || {};
|
|
1355
|
+
logger.log(chalk.green(`✓ douyin-adb-sync succeeded`));
|
|
1356
|
+
logger.log(` uid: ${chalk.cyan(dy.uid)}`);
|
|
1357
|
+
logger.log(` messages: ${counts.message || 0}`);
|
|
1358
|
+
logger.log(` contacts: ${counts.contact || 0}`);
|
|
1359
|
+
logger.log(` total: ${counts.total || 0}`);
|
|
1360
|
+
logger.log(` status: ${report.status || "?"}`);
|
|
1361
|
+
logger.log(` rawCount: ${report.rawCount || 0}`);
|
|
1362
|
+
const diag = dy.parserDiagnostic || {};
|
|
1363
|
+
if (!diag.hadMsgTable) {
|
|
1364
|
+
logger.log(
|
|
1365
|
+
chalk.yellow(
|
|
1366
|
+
` ⚠ msg table not found — Douyin App version may use a different IM schema`,
|
|
1367
|
+
),
|
|
1368
|
+
);
|
|
1369
|
+
}
|
|
1370
|
+
if (!diag.hadSimpleUserTable) {
|
|
1371
|
+
logger.log(
|
|
1372
|
+
chalk.yellow(
|
|
1373
|
+
` ⚠ SIMPLE_USER table not found — contacts won't be ingested`,
|
|
1374
|
+
),
|
|
1375
|
+
);
|
|
1376
|
+
}
|
|
1377
|
+
if (dy.cleanupFailed) {
|
|
1378
|
+
logger.log(chalk.gray(` (note: staging cleanup failed — non-fatal)`));
|
|
1379
|
+
}
|
|
1380
|
+
} catch (err) {
|
|
1381
|
+
fail(null, err, options.json);
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
/**
|
|
1386
|
+
* Phase 1e — `cc hub bilibili-adb-doctor`
|
|
1387
|
+
*
|
|
1388
|
+
* Dry-run env probe. Runs only the cookies-extraction half of the sync
|
|
1389
|
+
* pipeline (no api.bilibili.com calls, no vault writes) so the user can
|
|
1390
|
+
* confirm root + Bilibili-installed + cookie-complete BEFORE triggering
|
|
1391
|
+
* a real sync. Surfaces the same 9 typed reasons as bilibili-adb-sync
|
|
1392
|
+
* but with a green "✓ ready to sync" message on success.
|
|
1393
|
+
*
|
|
1394
|
+
* Use this as the first command in a real-device E2E session.
|
|
1395
|
+
*/
|
|
1396
|
+
async function cmdBilibiliAdbDoctor(options) {
|
|
1397
|
+
try {
|
|
1398
|
+
const hub = await (options._getHub || getHub)();
|
|
1399
|
+
const result = await hub.bilibiliAdbDoctor();
|
|
1400
|
+
if (options.json) {
|
|
1401
|
+
printJson(result);
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
if (!result.ok) {
|
|
1405
|
+
logger.log(chalk.red(`✗ bilibili-adb-doctor: ${result.reason}`));
|
|
1406
|
+
logger.log(chalk.gray(` ${result.message || ""}`));
|
|
1407
|
+
if (result.reason === "BRIDGE_UNAVAILABLE") {
|
|
1408
|
+
logger.log(
|
|
1409
|
+
chalk.gray(
|
|
1410
|
+
" Fix: install Android Platform Tools, or set ADB_PATH=/path/to/adb",
|
|
1411
|
+
),
|
|
1412
|
+
);
|
|
1413
|
+
} else if (result.reason === "BILIBILI_NO_ROOT") {
|
|
1414
|
+
logger.log(
|
|
1415
|
+
chalk.gray(
|
|
1416
|
+
" Fix: phone needs Magisk root — Bilibili release APK isn't debuggable",
|
|
1417
|
+
),
|
|
1418
|
+
);
|
|
1419
|
+
} else if (
|
|
1420
|
+
result.reason === "BILIBILI_NOT_INSTALLED_OR_NEVER_LOGGED_IN"
|
|
1421
|
+
) {
|
|
1422
|
+
logger.log(
|
|
1423
|
+
chalk.gray(" Fix: install Bilibili App + log in once on the phone"),
|
|
1424
|
+
);
|
|
1425
|
+
} else if (result.reason === "BILIBILI_COOKIES_INCOMPLETE") {
|
|
1426
|
+
logger.log(
|
|
1427
|
+
chalk.gray(
|
|
1428
|
+
" Fix: relog on the Bilibili App — required cookies are missing",
|
|
1429
|
+
),
|
|
1430
|
+
);
|
|
1431
|
+
} else if (
|
|
1432
|
+
result.reason === "BILIBILI_COOKIES_TRUNCATED" ||
|
|
1433
|
+
result.reason === "BILIBILI_NOT_SQLITE"
|
|
1434
|
+
) {
|
|
1435
|
+
logger.log(
|
|
1436
|
+
chalk.gray(
|
|
1437
|
+
" Fix: ADB stream may be corrupted; unplug + replug USB and retry",
|
|
1438
|
+
),
|
|
1439
|
+
);
|
|
1440
|
+
}
|
|
1441
|
+
process.exitCode = 1;
|
|
1442
|
+
return;
|
|
1443
|
+
}
|
|
1444
|
+
const diag = result.cookieDiagnostic || {};
|
|
1445
|
+
logger.log(chalk.green(`✓ bilibili-adb-doctor: env ready to sync`));
|
|
1446
|
+
logger.log(` uid: ${chalk.cyan(result.uid)}`);
|
|
1447
|
+
logger.log(` cookies found: ${diag.cookieCount || "?"}`);
|
|
1448
|
+
if (diag.hadEncrypted) {
|
|
1449
|
+
logger.log(
|
|
1450
|
+
chalk.yellow(
|
|
1451
|
+
` ⚠ encrypted rows: some cookies are Android-Keystore-wrapped (skipped)`,
|
|
1452
|
+
),
|
|
1453
|
+
);
|
|
1454
|
+
logger.log(
|
|
1455
|
+
chalk.gray(
|
|
1456
|
+
` This may indicate a newer Bilibili App on Android 14+ using Keystore wrap.`,
|
|
1457
|
+
),
|
|
1458
|
+
);
|
|
1459
|
+
}
|
|
1460
|
+
logger.log(
|
|
1461
|
+
` extracted at: ${new Date(result.extractedAt).toISOString()}`,
|
|
1462
|
+
);
|
|
1463
|
+
logger.log(
|
|
1464
|
+
chalk.gray(
|
|
1465
|
+
`\n Next: run \`cc hub bilibili-adb-sync\` to ingest 4 endpoints.`,
|
|
1466
|
+
),
|
|
1467
|
+
);
|
|
1468
|
+
} catch (err) {
|
|
1469
|
+
fail(null, err, options.json);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
|
|
980
1473
|
/**
|
|
981
1474
|
* `cc hub wechat doctor` — env-probe + actionable interpretation +
|
|
982
1475
|
* inline reference to the Phase 12.9 §5.1 Frida hook trap table.
|
|
@@ -1273,6 +1766,108 @@ export function registerHubCommand(program) {
|
|
|
1273
1766
|
.option("--json", "Output JSON")
|
|
1274
1767
|
.action(cmdSyncAll);
|
|
1275
1768
|
|
|
1769
|
+
// Phase 1c — Bilibili C 路径 one-shot
|
|
1770
|
+
hub
|
|
1771
|
+
.command("bilibili-adb-sync")
|
|
1772
|
+
.description(
|
|
1773
|
+
"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.",
|
|
1774
|
+
)
|
|
1775
|
+
.option("--limit-history <n>", "Cap history items (default 200)")
|
|
1776
|
+
.option(
|
|
1777
|
+
"--limit-favourite <n>",
|
|
1778
|
+
"Cap favourite items per folder (default 50)",
|
|
1779
|
+
)
|
|
1780
|
+
.option("--limit-dynamic <n>", "Cap dynamic items (default 50)")
|
|
1781
|
+
.option("--limit-follow <n>", "Cap follow items (default 200)")
|
|
1782
|
+
.option(
|
|
1783
|
+
"--display-name <s>",
|
|
1784
|
+
"Account displayName for the snapshot (default empty)",
|
|
1785
|
+
)
|
|
1786
|
+
.option(
|
|
1787
|
+
"--staging-dir <path>",
|
|
1788
|
+
"Custom dir for the temp snapshot JSON (default os.tmpdir())",
|
|
1789
|
+
)
|
|
1790
|
+
.option("--json", "Output JSON")
|
|
1791
|
+
.action(cmdBilibiliAdbSync);
|
|
1792
|
+
|
|
1793
|
+
// Phase 1e — dry-run env probe (cookies only, no API, no vault write)
|
|
1794
|
+
hub
|
|
1795
|
+
.command("bilibili-adb-doctor")
|
|
1796
|
+
.description(
|
|
1797
|
+
"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.",
|
|
1798
|
+
)
|
|
1799
|
+
.option("--json", "Output JSON")
|
|
1800
|
+
.action(cmdBilibiliAdbDoctor);
|
|
1801
|
+
|
|
1802
|
+
// Phase 3a — Weibo C 路径 one-shot (m.weibo.cn cookies + 4 endpoints, sign-less)
|
|
1803
|
+
hub
|
|
1804
|
+
.command("weibo-adb-sync")
|
|
1805
|
+
.description(
|
|
1806
|
+
"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.",
|
|
1807
|
+
)
|
|
1808
|
+
.option("--limit-post <n>", "Cap user-timeline posts (default 100)")
|
|
1809
|
+
.option("--limit-favourite <n>", "Cap favourite items (default 100)")
|
|
1810
|
+
.option("--limit-follow <n>", "Cap follow items (default 200)")
|
|
1811
|
+
.option(
|
|
1812
|
+
"--display-name <s>",
|
|
1813
|
+
"Account displayName for the snapshot (default empty)",
|
|
1814
|
+
)
|
|
1815
|
+
.option(
|
|
1816
|
+
"--staging-dir <path>",
|
|
1817
|
+
"Custom dir for the temp snapshot JSON (default os.tmpdir())",
|
|
1818
|
+
)
|
|
1819
|
+
.option("--json", "Output JSON")
|
|
1820
|
+
.action(cmdWeiboAdbSync);
|
|
1821
|
+
|
|
1822
|
+
// Phase 3c — Xhs C 路径 one-shot (xiaohongshu.com cookies + 4 endpoints with X-S signing)
|
|
1823
|
+
hub
|
|
1824
|
+
.command("xhs-adb-sync")
|
|
1825
|
+
.description(
|
|
1826
|
+
"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.",
|
|
1827
|
+
)
|
|
1828
|
+
.option("--limit-note <n>", "Cap user notes (default 30)")
|
|
1829
|
+
.option("--limit-liked <n>", "Cap liked notes (default 30)")
|
|
1830
|
+
.option("--limit-follow <n>", "Cap follow list (default 100)")
|
|
1831
|
+
.option(
|
|
1832
|
+
"--display-name <s>",
|
|
1833
|
+
"Account displayName for the snapshot (default = xhs nickname)",
|
|
1834
|
+
)
|
|
1835
|
+
.option(
|
|
1836
|
+
"--staging-dir <path>",
|
|
1837
|
+
"Custom dir for the temp snapshot JSON (default os.tmpdir())",
|
|
1838
|
+
)
|
|
1839
|
+
.option("--json", "Output JSON")
|
|
1840
|
+
.action(cmdXhsAdbSync);
|
|
1841
|
+
|
|
1842
|
+
// Phase 2a — Douyin C 路径 one-shot (pull <uid>_im.db → parse abrignoni DFIR schema)
|
|
1843
|
+
hub
|
|
1844
|
+
.command("douyin-adb-sync")
|
|
1845
|
+
.description(
|
|
1846
|
+
"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.",
|
|
1847
|
+
)
|
|
1848
|
+
.option(
|
|
1849
|
+
"--uid <id>",
|
|
1850
|
+
"19-digit Douyin uid — required when multiple accounts logged in on the phone",
|
|
1851
|
+
)
|
|
1852
|
+
.option(
|
|
1853
|
+
"--limit-messages <n>",
|
|
1854
|
+
"Cap msg rows from the IM db (default 10000)",
|
|
1855
|
+
)
|
|
1856
|
+
.option(
|
|
1857
|
+
"--limit-contacts <n>",
|
|
1858
|
+
"Cap SIMPLE_USER rows from the IM db (default 5000)",
|
|
1859
|
+
)
|
|
1860
|
+
.option(
|
|
1861
|
+
"--display-name <s>",
|
|
1862
|
+
"Account displayName for the snapshot (default empty)",
|
|
1863
|
+
)
|
|
1864
|
+
.option(
|
|
1865
|
+
"--staging-dir <path>",
|
|
1866
|
+
"Custom dir for the temp snapshot JSON (default os.tmpdir())",
|
|
1867
|
+
)
|
|
1868
|
+
.option("--json", "Output JSON")
|
|
1869
|
+
.action(cmdDouyinAdbSync);
|
|
1870
|
+
|
|
1276
1871
|
hub
|
|
1277
1872
|
.command("rederive")
|
|
1278
1873
|
.description(
|
|
@@ -1515,6 +2110,11 @@ export const _internal = {
|
|
|
1515
2110
|
cmdWechatList,
|
|
1516
2111
|
cmdWechatUnregister,
|
|
1517
2112
|
cmdWechatDoctor,
|
|
2113
|
+
cmdBilibiliAdbSync,
|
|
2114
|
+
cmdBilibiliAdbDoctor,
|
|
2115
|
+
cmdDouyinAdbSync,
|
|
2116
|
+
cmdWeiboAdbSync,
|
|
2117
|
+
cmdXhsAdbSync,
|
|
1518
2118
|
interpretWechatProbe,
|
|
1519
2119
|
_defaultKnownVendors,
|
|
1520
2120
|
};
|
|
@@ -392,6 +392,56 @@ export const PERSONAL_DATA_HUB_HANDLERS = {
|
|
|
392
392
|
"personal-data-hub.list-wechat-accounts": async () =>
|
|
393
393
|
withHub((hub) => hub.listWechatAccounts()),
|
|
394
394
|
|
|
395
|
+
// ─── Phase 1c — Bilibili C 路径 one-shot sync ─────────────────────────
|
|
396
|
+
//
|
|
397
|
+
// Pulls cookies from the user's Android Bilibili App via ADB, fetches 4
|
|
398
|
+
// endpoints, ingests as a snapshot. Returns the standard
|
|
399
|
+
// `{ok, report?, reason?, message?}` shape — see hub.bilibiliAdbSync for
|
|
400
|
+
// the full reason taxonomy. UI maps reasons to banner strings.
|
|
401
|
+
"personal-data-hub.bilibili-adb-sync": async (msg) =>
|
|
402
|
+
withHub((hub) =>
|
|
403
|
+
hub.bilibiliAdbSync({
|
|
404
|
+
limits: msg && msg.limits,
|
|
405
|
+
stagingDir: msg && msg.stagingDir,
|
|
406
|
+
displayName: msg && msg.displayName,
|
|
407
|
+
}),
|
|
408
|
+
),
|
|
409
|
+
|
|
410
|
+
// Phase 1e — dry-run env probe (cookies path only, no API calls / vault writes)
|
|
411
|
+
"personal-data-hub.bilibili-adb-doctor": async () =>
|
|
412
|
+
withHub((hub) => hub.bilibiliAdbDoctor()),
|
|
413
|
+
|
|
414
|
+
// Phase 2a — Douyin C 路径 one-shot sync (db extraction)
|
|
415
|
+
"personal-data-hub.douyin-adb-sync": async (msg) =>
|
|
416
|
+
withHub((hub) =>
|
|
417
|
+
hub.douyinAdbSync({
|
|
418
|
+
uid: msg && msg.uid,
|
|
419
|
+
limits: msg && msg.limits,
|
|
420
|
+
stagingDir: msg && msg.stagingDir,
|
|
421
|
+
displayName: msg && msg.displayName,
|
|
422
|
+
}),
|
|
423
|
+
),
|
|
424
|
+
|
|
425
|
+
// Phase 3a — Weibo C 路径 one-shot sync (m.weibo.cn cookies + 4 endpoints)
|
|
426
|
+
"personal-data-hub.weibo-adb-sync": async (msg) =>
|
|
427
|
+
withHub((hub) =>
|
|
428
|
+
hub.weiboAdbSync({
|
|
429
|
+
limits: msg && msg.limits,
|
|
430
|
+
stagingDir: msg && msg.stagingDir,
|
|
431
|
+
displayName: msg && msg.displayName,
|
|
432
|
+
}),
|
|
433
|
+
),
|
|
434
|
+
|
|
435
|
+
// Phase 3c — Xhs C 路径 one-shot sync (xiaohongshu.com cookies + 4 endpoints X-S signed)
|
|
436
|
+
"personal-data-hub.xhs-adb-sync": async (msg) =>
|
|
437
|
+
withHub((hub) =>
|
|
438
|
+
hub.xhsAdbSync({
|
|
439
|
+
limits: msg && msg.limits,
|
|
440
|
+
stagingDir: msg && msg.stagingDir,
|
|
441
|
+
displayName: msg && msg.displayName,
|
|
442
|
+
}),
|
|
443
|
+
),
|
|
444
|
+
|
|
395
445
|
// ─── Phase 8 — EntityResolver review / merge / unmerge ───────────────
|
|
396
446
|
|
|
397
447
|
"personal-data-hub.review-queue-list": async (msg) =>
|