chainlesschain 0.162.25 → 0.162.27
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-CAdsXHkz.js → AIOps-D67bnWOm.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-JsLRBlBP.js → ActionButton-z7o1N942.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DeM96q71.js → Analytics-ygwetD7a.js} +1 -1
- package/src/assets/web-panel/assets/{AppLayout-eb_6mT6V.js → AppLayout-DKIKC0vr.js} +2 -2
- package/src/assets/web-panel/assets/{Audit-BEOY-CQE.js → Audit-RfvwANd0.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-irFD_DBa.js → Backup-CLC0Npju.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Dq7wtv_k.js → BaseInput-Cy955ldQ.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CstRKWdu.js → Chat-Di1G3WpZ.js} +1 -1
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-3BBqk317.js → ChatBubbleRenderer-D2CwVV3N.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-A8D25IT5.js → Checkbox-mM6T49x7.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-1EfMWeRA.js → Codegen-CFRknQ28.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Bc08LzOn.js → Col-Md7VPq32.js} +1 -1
- package/src/assets/web-panel/assets/{Community-BNnNv7xp.js → Community-B75271cm.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-nFjLneHM.js → Compact-BOrAa1JM.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CZpaaHND.js → Compliance-CqgTFpLC.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DzHugH3j.js → Cowork-Bvdzx2lF.js} +1 -1
- package/src/assets/web-panel/assets/{Cron-C7YRyiN-.js → Cron-BP3ZLMIx.js} +1 -1
- package/src/assets/web-panel/assets/{Crosschain-er2h0L0q.js → Crosschain-Dy8IWecD.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DaMdE0A7.js → DID-DxnpBszy.js} +1 -1
- package/src/assets/web-panel/assets/{Dashboard-1z2K_E1B.js → Dashboard-h8TY-9dT.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-B9NIqAXf.js → Dropdown-CfIh_9pn.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CBHLFokz.js → EmailListRenderer-egkHFDB9.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-D2fEJEki.js → Federation-iXsC9ljf.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-tmsd70yG.js → FormItemContext-D16LYrK1.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DW4Lnrsr.js → GenericCardRenderer-B2l7qvIp.js} +1 -1
- package/src/assets/web-panel/assets/{Git-D8aBagAp.js → Git-DshuXpeI.js} +1 -1
- package/src/assets/web-panel/assets/{Governance-CKDAHamy.js → Governance-BzgoQvxX.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BLLp118j.js → Inference-CMikYc6i.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Cawx-yfu.js → KnowledgeGraph-DAP_uKkx.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-sWSzp5PY.js → Logs-Zax7aDPt.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-BQMX3dSy.js → Marketplace-DC8_c3hX.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DjlFST3o.js → McpTools-CvpCNH6E.js} +1 -1
- package/src/assets/web-panel/assets/{Memory-LZE1wG7m.js → Memory-BVgvCyNB.js} +1 -1
- package/src/assets/web-panel/assets/{MobileBridge-BWG47jQ6.js → MobileBridge-BvffJp-I.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DHVv0tYo.js → MobileProjects-BBEmZ56X.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Di1hrhM3.js → Mtc-D4Lg-E10.js} +1 -1
- package/src/assets/web-panel/assets/{MtcAudit-BowOCi-O.js → MtcAudit-BpuX4w67.js} +1 -1
- package/src/assets/web-panel/assets/{Multisig-CgpR0s8E.js → Multisig-CclH6FTt.js} +1 -1
- package/src/assets/web-panel/assets/{NLProgramming-O4U3Plxd.js → NLProgramming-DPBSg0ot.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Ce_5C6XT.js → Notes-CapzFL8Y.js} +1 -1
- package/src/assets/web-panel/assets/{NotificationSettings-BVVopkxj.js → NotificationSettings-Fxts3vW8.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-XW2G50wt.js → OrderTableRenderer-DexmnSf8.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DaW54kdP.js → Organization-Cx9wnh2C.js} +1 -1
- package/src/assets/web-panel/assets/{Overflow-CVTGMUVt.js → Overflow-uNU3Jy_O.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CpEwrhBx.js → P2P-DZqGX3zP.js} +1 -1
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CDqun-Z9.js → PdhVaultBrowser-BbXlJUmU.js} +2 -2
- package/src/assets/web-panel/assets/{Permissions-BsSU3MaL.js → Permissions-tSlqIXRk.js} +1 -1
- package/src/assets/web-panel/assets/{PersonalDataHub-DmUc89_0.css → PersonalDataHub-CO9-IYDY.css} +1 -1
- package/src/assets/web-panel/assets/PersonalDataHub-DdPngiX0.js +2 -0
- package/src/assets/web-panel/assets/{Pipeline-CPCDpDyd.js → Pipeline-G-YXvU25.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-oZEQvVWA.js → Privacy-BIDsJhkC.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CRu5bDNW.js → ProjectInit-DTGzvgQ9.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectSettings-ComIZ7gQ.js → ProjectSettings-8QjihLTL.js} +1 -1
- package/src/assets/web-panel/assets/{Projects-Djr10qFp.js → Projects-D7S7x7R1.js} +1 -1
- package/src/assets/web-panel/assets/Providers-BNI-WkmA.css +1 -0
- package/src/assets/web-panel/assets/Providers-DpTXneeZ.js +1 -0
- package/src/assets/web-panel/assets/{QuickAsk-C21t1JEf.js → QuickAsk-C83JwW8d.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BjJForJo.js → Recommend-PO0TXid1.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-Cp8Ym-Hk.js → Reputation-pwXhN9Lv.js} +1 -1
- package/src/assets/web-panel/assets/{Row-n8ruyEoT.js → Row-829tJQ3D.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CosaiHvS.js → RssFeed-Btnw67Mk.js} +1 -1
- package/src/assets/web-panel/assets/{Search-DUNSNFJZ.js → Search-olQ94qFA.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Z3WyX_MB.js → Security-C_Vfuu0K.js} +1 -1
- package/src/assets/web-panel/assets/{Services-U0m9Oj8V.js → Services-ByfhJMDp.js} +1 -1
- package/src/assets/web-panel/assets/{Skeleton-B_M5sv2W.js → Skeleton-CWxck8Jk.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-NKU9c6LT.js → Skills-yady6VUJ.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DscfpqF8.js → Sla-Dc_HEsj7.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DP0O84ej.js → SpeechSettings--vhH3ORV.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-P_WEyoH3.js → SyncSettings-GUPyaG2O.js} +1 -1
- package/src/assets/web-panel/assets/{Tasks-C8YAncnj.js → Tasks-Sj1OYuDS.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-F12-SRc3.js → Templates-rdiV_eFo.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CULHbrwu.js → Tenant-N76bdElE.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DdYrQ0n3.js → Terminal-KZ1H0ObH.js} +1 -1
- package/src/assets/web-panel/assets/{TimelineRenderer-C12_BYAe.js → TimelineRenderer-D7nI-o49.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-8MVLlc0s.js → Tokens-c2LL4v7q.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Bl6QmvKw.js → Trigger-B57LuN-B.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BH_aEsWy.js → Trust-BMmdOSoP.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DsX2CeE4.js → UkeySign-CtGUfuxi.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DaRdn6e9.js → VideoEditing-CzrCzzLF.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DO89dzlU.js → Wallet-Ciiwlppn.js} +1 -1
- package/src/assets/web-panel/assets/{WebAuthn-KUKNjImY.js → WebAuthn-BPFoLjnF.js} +1 -1
- package/src/assets/web-panel/assets/{WorkflowEditor-CnSoP-Z9.js → WorkflowEditor-Bf8UZPRx.js} +1 -1
- package/src/assets/web-panel/assets/{chat-Jp0M9E52.js → chat-aoVkknKT.js} +1 -1
- package/src/assets/web-panel/assets/{colors-Bkq4q91x.js → colors-CKv2MZMK.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-CCt1byem.js → compact-item-1FPS5mTP.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DwRLi0Uq.js → createContext-o2GXZ1sO.js} +1 -1
- package/src/assets/web-panel/assets/{hasIn-CTVm-2lw.js → hasIn-CMm7HgH-.js} +1 -1
- package/src/assets/web-panel/assets/{index-TqiVFiUf.js → index-866hrngI.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9q3wKEr.js → index-8AzFTShP.js} +1 -1
- package/src/assets/web-panel/assets/index-BHtt98Qo.js +1 -0
- package/src/assets/web-panel/assets/{index-Cvrka2TD.js → index-BQcTgRAZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJegJP2N.js → index-BSqFVnSI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CIBi-rGt.js → index-BUWd4FFK.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRwUdk7I.js → index-Bb7YRgoc.js} +1 -1
- package/src/assets/web-panel/assets/{index-hpRtUCjU.js → index-BbJDxap_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DC-8E2CG.js → index-BwA5hOgO.js} +1 -1
- package/src/assets/web-panel/assets/{index-CPnSymMN.js → index-CFgWbJuM.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDbgmmSF.js → index-CXDN0kh7.js} +1 -1
- package/src/assets/web-panel/assets/{index-BhSbNePw.js → index-CXHs9New.js} +1 -1
- package/src/assets/web-panel/assets/{index-DXDSJwDk.js → index-CalorQK0.js} +1 -1
- package/src/assets/web-panel/assets/{index-BziGa10S.js → index-CcfXX0ID.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3irAeY8.js → index-CdDX6sEY.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWQ9NRWg.js → index-Ch-sPaT4.js} +1 -1
- package/src/assets/web-panel/assets/{index-MdArO-BF.js → index-Chh-oVTw.js} +1 -1
- package/src/assets/web-panel/assets/{index-zwGGcR7I.js → index-Cr1ZwF59.js} +1 -1
- package/src/assets/web-panel/assets/{index-BtzUDs1M.js → index-Cr2EOK21.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2pkXVOU.js → index-Crp4UcP-.js} +1 -1
- package/src/assets/web-panel/assets/index-Cul_OH-A.js +1 -0
- package/src/assets/web-panel/assets/{index-TL3iHPdE.js → index-D1QEfzq_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BjGcDwb2.js → index-D3aMAQEQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_U_xDvh.js → index-D3bKIme7.js} +1 -1
- package/src/assets/web-panel/assets/{index-CjJWQqPG.js → index-DCxs8O-B.js} +1 -1
- package/src/assets/web-panel/assets/{index-Db3R-khd.js → index-DDP25Jlo.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFcr_PT2.js → index-DT76REiB.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-UAtktg.js → index-DZ747YY7.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2ovimhG.js → index-De4hAcPZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdlVwys1.js → index-DoVMBKvC.js} +1 -1
- package/src/assets/web-panel/assets/{index-BD2U0Ciz.js → index-JP5LGd1K.js} +3 -3
- package/src/assets/web-panel/assets/{index-BJmiHI2z.js → index-OiF8vib7.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3ZzMEg0.js → index-Y_UOzu30.js} +1 -1
- package/src/assets/web-panel/assets/{index-CFh73FRz.js → index-bJ5UBvQQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-eyVkd-kF.js → index-dXE5uCaT.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLjugrcu.js → index-fyC4Vx7E.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRkGL2HJ.js → index-g4LWpdR7.js} +1 -1
- package/src/assets/web-panel/assets/{index-6OmglXey.js → index-u3FjYN52.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJWYdgmz.js → index-yhq2Pttf.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-9iSe4Eid.js → initDefaultProps-Co0jgVso.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CcUz2pq7.js → motion-Zw-nUuCZ.js} +1 -1
- package/src/assets/web-panel/assets/{move-3Po9fM71.js → move-O_Pya0SD.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BBcRnciw.js → omit-bqQYnuYR.js} +1 -1
- package/src/assets/web-panel/assets/parsers-UEvh_ShA.js +4 -0
- package/src/assets/web-panel/assets/{pickAttrs-UCqcWwOy.js → pickAttrs-PeesUh3N.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-boVtHxA4.js → placementArrow-DoUJMHry.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-V0qPHZOl.js → responsiveObserve-QHPYy6hK.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CZyysA_q.js → slide-H_RDRwbZ.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BLyCU5L3.js → statusUtils-RuUT_noY.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BfXrPW7h.js → styleChecker-DuWlOmft.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Be2wILDi.js → useFlexGapSupport-CJmU3crw.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CzJYoHOI.js → useFs-CBYaEAuH.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-__HEfTF9.js → usePersonalDataHub-B0x06BwX.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-C0XE0aCE.js → vnode-B2BMGDRL.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CphwCBhl.js → zoom-D_OEfpnp.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/__tests__/hub-ask.test.js +104 -1
- 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/hub.js +353 -1
- package/src/gateways/ws/personal-data-hub-protocol.js +34 -0
- package/src/lib/personal-data-hub-wiring.js +218 -0
- package/src/assets/web-panel/assets/PersonalDataHub-BafcAH5d.js +0 -1
- package/src/assets/web-panel/assets/Providers-BEakqcO5.css +0 -1
- package/src/assets/web-panel/assets/Providers-CltNzV7e.js +0 -2
- package/src/assets/web-panel/assets/index-CR2wmKfw.js +0 -1
- package/src/assets/web-panel/assets/index-iXk8Oeci.js +0 -1
- package/src/assets/web-panel/assets/parsers-DftYMnlk.js +0 -3
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 6c — cc hub toutiao-adb-sync CLI command unit tests.
|
|
3
|
+
*
|
|
4
|
+
* Mirror of hub-xhs-adb-sync. Covers profileFetchFailed + CLI no-bridge
|
|
5
|
+
* short-circuit banner + lastErrorCode propagation.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
9
|
+
|
|
10
|
+
import { _internal } from "../hub.js";
|
|
11
|
+
|
|
12
|
+
let logSpy, errSpy;
|
|
13
|
+
let prevExitCode;
|
|
14
|
+
|
|
15
|
+
function fakeHub(syncResult) {
|
|
16
|
+
return { toutiaoAdbSync: vi.fn(async (_opts) => syncResult) };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const HAPPY_RESULT = {
|
|
20
|
+
ok: true,
|
|
21
|
+
report: {
|
|
22
|
+
adapter: "social-toutiao",
|
|
23
|
+
status: "ok",
|
|
24
|
+
rawCount: 26,
|
|
25
|
+
entityCounts: { events: 26, persons: 1, places: 0, items: 0, topics: 0 },
|
|
26
|
+
toutiao: {
|
|
27
|
+
uid: "12345",
|
|
28
|
+
nickname: "Alice",
|
|
29
|
+
eventCounts: {
|
|
30
|
+
profile: 1,
|
|
31
|
+
feed: 15,
|
|
32
|
+
collection: 5,
|
|
33
|
+
search: 5,
|
|
34
|
+
total: 26,
|
|
35
|
+
},
|
|
36
|
+
lastErrorCode: 0,
|
|
37
|
+
lastErrorMessage: null,
|
|
38
|
+
cookieDiagnostic: { cookieCount: 8, hadEncrypted: false },
|
|
39
|
+
profileFetchFailed: false,
|
|
40
|
+
signProviderUsed: "ToutiaoSignBridge",
|
|
41
|
+
signProviderHits: 3,
|
|
42
|
+
signProviderFallbacks: 0,
|
|
43
|
+
cleanupFailed: false,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
beforeEach(() => {
|
|
49
|
+
logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
50
|
+
errSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
51
|
+
prevExitCode = process.exitCode;
|
|
52
|
+
process.exitCode = 0;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
afterEach(() => {
|
|
56
|
+
logSpy.mockRestore();
|
|
57
|
+
errSpy.mockRestore();
|
|
58
|
+
process.exitCode = prevExitCode;
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe("cc hub toutiao-adb-sync — happy path", () => {
|
|
62
|
+
it("prints human summary with nickname", async () => {
|
|
63
|
+
const hub = fakeHub(HAPPY_RESULT);
|
|
64
|
+
await _internal.cmdToutiaoAdbSync({ _getHub: async () => hub });
|
|
65
|
+
expect(hub.toutiaoAdbSync).toHaveBeenCalledOnce();
|
|
66
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
67
|
+
expect(out).toMatch(/toutiao-adb-sync succeeded/);
|
|
68
|
+
expect(out).toMatch(/uid:.*12345/);
|
|
69
|
+
expect(out).toMatch(/nickname:\s+Alice/);
|
|
70
|
+
expect(out).toMatch(/profile:\s+1/);
|
|
71
|
+
expect(out).toMatch(/feed:\s+15/);
|
|
72
|
+
expect(out).toMatch(/collection:\s+5/);
|
|
73
|
+
expect(out).toMatch(/search:\s+5/);
|
|
74
|
+
expect(out).toMatch(/total:\s+26/);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("--json outputs raw result", async () => {
|
|
78
|
+
const hub = fakeHub(HAPPY_RESULT);
|
|
79
|
+
await _internal.cmdToutiaoAdbSync({
|
|
80
|
+
_getHub: async () => hub,
|
|
81
|
+
json: true,
|
|
82
|
+
});
|
|
83
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
84
|
+
const parsed = JSON.parse(out);
|
|
85
|
+
expect(parsed.ok).toBe(true);
|
|
86
|
+
expect(parsed.report.toutiao.uid).toBe("12345");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("renders profileFetchFailed warning when set", async () => {
|
|
90
|
+
const result = JSON.parse(JSON.stringify(HAPPY_RESULT));
|
|
91
|
+
result.report.toutiao.profileFetchFailed = true;
|
|
92
|
+
result.report.toutiao.lastErrorCode = 1;
|
|
93
|
+
result.report.toutiao.lastErrorMessage = "token expired";
|
|
94
|
+
result.report.toutiao.uid = null;
|
|
95
|
+
const hub = fakeHub(result);
|
|
96
|
+
await _internal.cmdToutiaoAdbSync({ _getHub: async () => hub });
|
|
97
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
98
|
+
expect(out).toMatch(/passport\/info\/v2 returned no user_id/);
|
|
99
|
+
expect(out).toMatch(/profile fetch failed/);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("renders 'no sign bridge' short-circuit banner in CLI context", async () => {
|
|
103
|
+
const result = JSON.parse(JSON.stringify(HAPPY_RESULT));
|
|
104
|
+
result.report.toutiao.signProviderUsed = "none";
|
|
105
|
+
result.report.toutiao.signProviderHits = 0;
|
|
106
|
+
result.report.toutiao.signProviderFallbacks = 3;
|
|
107
|
+
result.report.toutiao.eventCounts.feed = 0;
|
|
108
|
+
result.report.toutiao.eventCounts.collection = 0;
|
|
109
|
+
result.report.toutiao.eventCounts.search = 0;
|
|
110
|
+
result.report.toutiao.eventCounts.total = 1; // just profile
|
|
111
|
+
result.report.toutiao.lastErrorCode = -99;
|
|
112
|
+
const hub = fakeHub(result);
|
|
113
|
+
await _internal.cmdToutiaoAdbSync({ _getHub: async () => hub });
|
|
114
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
115
|
+
expect(out).toMatch(/3 signed endpoints short-circuited/);
|
|
116
|
+
expect(out).toMatch(/no sign bridge in CLI context/);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("renders lastErrorCode partial-result warning (non-(-99))", async () => {
|
|
120
|
+
const result = JSON.parse(JSON.stringify(HAPPY_RESULT));
|
|
121
|
+
result.report.toutiao.lastErrorCode = 412;
|
|
122
|
+
result.report.toutiao.lastErrorMessage = "HTTP 412";
|
|
123
|
+
const hub = fakeHub(result);
|
|
124
|
+
await _internal.cmdToutiaoAdbSync({ _getHub: async () => hub });
|
|
125
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
126
|
+
expect(out).toMatch(/partial: lastErrorCode=412/);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe("cc hub toutiao-adb-sync — failure paths", () => {
|
|
131
|
+
function failCase(reason, expectedHint) {
|
|
132
|
+
return async () => {
|
|
133
|
+
const hub = fakeHub({ ok: false, reason, message: "synthetic" });
|
|
134
|
+
await _internal.cmdToutiaoAdbSync({ _getHub: async () => hub });
|
|
135
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
136
|
+
expect(out).toMatch(new RegExp(`toutiao-adb-sync failed: ${reason}`));
|
|
137
|
+
if (expectedHint) {
|
|
138
|
+
expect(out).toMatch(expectedHint);
|
|
139
|
+
}
|
|
140
|
+
expect(process.exitCode).toBe(1);
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
it("BRIDGE_UNAVAILABLE banner", failCase("BRIDGE_UNAVAILABLE", /ADB_PATH/));
|
|
145
|
+
it("TOUTIAO_NO_ROOT banner", failCase("TOUTIAO_NO_ROOT", /Magisk root/));
|
|
146
|
+
it(
|
|
147
|
+
"TOUTIAO_NOT_INSTALLED banner",
|
|
148
|
+
failCase("TOUTIAO_NOT_INSTALLED", /com\.ss\.android\.article\.news/),
|
|
149
|
+
);
|
|
150
|
+
it(
|
|
151
|
+
"TOUTIAO_COOKIES_INCOMPLETE banner",
|
|
152
|
+
failCase("TOUTIAO_COOKIES_INCOMPLETE", /sessionid \/ sessionid_ss/),
|
|
153
|
+
);
|
|
154
|
+
it(
|
|
155
|
+
"TOUTIAO_COOKIES_TRUNCATED banner",
|
|
156
|
+
failCase("TOUTIAO_COOKIES_TRUNCATED", /unplug \+ replug USB/),
|
|
157
|
+
);
|
|
158
|
+
});
|
package/src/commands/hub.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import chalk from "chalk";
|
|
19
19
|
import ora from "ora";
|
|
20
20
|
import { logger } from "../lib/logger.js";
|
|
21
|
-
import { getHub } from "../lib/personal-data-hub-wiring.js";
|
|
21
|
+
import { getHub, getHubMinimal } from "../lib/personal-data-hub-wiring.js";
|
|
22
22
|
import { getAIChatWizard } from "../lib/personal-data-hub-aichat-wizard.js";
|
|
23
23
|
|
|
24
24
|
function printJson(obj) {
|
|
@@ -121,6 +121,55 @@ async function cmdAsk(question, options) {
|
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
// ─── retrieve-context (LLM-free RAG preflight) ─────────────────────────
|
|
125
|
+
//
|
|
126
|
+
// 2026-05-27 — Bridges Android CLOUD_ANDROID route to RAG. AnalysisEngine
|
|
127
|
+
// already exposes `retrieveContext()` which runs parseQuery → _gatherFacts
|
|
128
|
+
// → buildPrompt and returns the LLM-ready messages WITHOUT calling any
|
|
129
|
+
// LLM. This subcommand surfaces that JSON to stdout so a non-Ollama
|
|
130
|
+
// caller (Android cloud LLM provider — Doubao / DeepSeek / Kimi) can:
|
|
131
|
+
// 1. Spawn `cc hub retrieve-context "<q>" --max-facts 20 --json`
|
|
132
|
+
// 2. Parse JSON → get { messages, factIds, factCount, parsed, ... }
|
|
133
|
+
// 3. POST messages to the cloud LLM provider directly
|
|
134
|
+
// 4. Validate citations from the answer against factIds locally
|
|
135
|
+
//
|
|
136
|
+
// Privacy invariant: retrieveContext does NOT invoke any LLM, so it never
|
|
137
|
+
// touches `acceptNonLocal` — the caller's own gate is the gate. The
|
|
138
|
+
// returned messages contain raw user data (events / persons / items)
|
|
139
|
+
// formatted as the prompt's FACTS block; the caller is responsible for
|
|
140
|
+
// where they POST it.
|
|
141
|
+
|
|
142
|
+
async function cmdRetrieveContext(question, options) {
|
|
143
|
+
try {
|
|
144
|
+
// §S4.1 cold-start optimization — when --minimal (or default to true
|
|
145
|
+
// since this command never needs adapters), use getHubMinimal which
|
|
146
|
+
// skips the 50+ adapter registry + KG/RAG sinks + email account auto-
|
|
147
|
+
// load + ADB extension imports. retrieveContext only touches vault
|
|
148
|
+
// queries + AnalysisEngine, so the full hub init is wasted work.
|
|
149
|
+
// In-APK Android cold-start drops from ~90s to <5s. Tests can still
|
|
150
|
+
// pass _getHub override for stubbing.
|
|
151
|
+
const useMinimal = options.minimal !== false; // default true
|
|
152
|
+
const hub = options._getHub
|
|
153
|
+
? await options._getHub()
|
|
154
|
+
: useMinimal
|
|
155
|
+
? await getHubMinimal()
|
|
156
|
+
: await getHub();
|
|
157
|
+
if (!hub.engine) throw new Error("Analysis engine unavailable");
|
|
158
|
+
const maxFacts = parsePositiveInt(options.maxFacts);
|
|
159
|
+
const maxQueryLimit = parsePositiveInt(options.maxQueryLimit);
|
|
160
|
+
const retrieveOptions = { skipAudit: false };
|
|
161
|
+
if (maxFacts !== null) retrieveOptions.maxFacts = maxFacts;
|
|
162
|
+
if (maxQueryLimit !== null) retrieveOptions.maxQueryLimit = maxQueryLimit;
|
|
163
|
+
const result = await hub.engine.retrieveContext(question, retrieveOptions);
|
|
164
|
+
// Always JSON output — this command is machine-only by design. The
|
|
165
|
+
// shape mirrors AnalysisEngine.retrieveContext return + the system
|
|
166
|
+
// prompt baked in (so the caller doesn't need to re-fetch it).
|
|
167
|
+
printJson(result);
|
|
168
|
+
} catch (err) {
|
|
169
|
+
fail(null, err, true /* json */);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
124
173
|
// ─── stats ────────────────────────────────────────────────────────────
|
|
125
174
|
|
|
126
175
|
async function cmdStats(options) {
|
|
@@ -1192,6 +1241,240 @@ async function cmdXhsAdbSync(options) {
|
|
|
1192
1241
|
}
|
|
1193
1242
|
}
|
|
1194
1243
|
|
|
1244
|
+
/**
|
|
1245
|
+
* Phase 6d — `cc hub kuaishou-adb-sync`
|
|
1246
|
+
*
|
|
1247
|
+
* Pulls www.kuaishou.com cookies from the user's Android Kuaishou App,
|
|
1248
|
+
* fetches uid + profile via cookie's api_ph payload (PURE COOKIE PARSE,
|
|
1249
|
+
* no HTTP) + 3 signed GraphQL endpoints (watch / collect / search).
|
|
1250
|
+
* CLI context has NO sign bridge — 3 signed endpoints short-circuit
|
|
1251
|
+
* with lastErrorCode=-99. Desktop wiring upgrades via KuaishouSignBridge.
|
|
1252
|
+
*/
|
|
1253
|
+
async function cmdKuaishouAdbSync(options) {
|
|
1254
|
+
try {
|
|
1255
|
+
const hub = await (options._getHub || getHub)();
|
|
1256
|
+
const result = await hub.kuaishouAdbSync({
|
|
1257
|
+
stagingDir: options.stagingDir,
|
|
1258
|
+
displayName: options.displayName,
|
|
1259
|
+
limits:
|
|
1260
|
+
options.limitWatch || options.limitCollect || options.limitSearch
|
|
1261
|
+
? {
|
|
1262
|
+
watch: parsePositiveInt(options.limitWatch),
|
|
1263
|
+
collect: parsePositiveInt(options.limitCollect),
|
|
1264
|
+
search: parsePositiveInt(options.limitSearch),
|
|
1265
|
+
}
|
|
1266
|
+
: undefined,
|
|
1267
|
+
});
|
|
1268
|
+
if (options.json) {
|
|
1269
|
+
printJson(result);
|
|
1270
|
+
return;
|
|
1271
|
+
}
|
|
1272
|
+
if (!result.ok) {
|
|
1273
|
+
logger.log(chalk.red(`✗ kuaishou-adb-sync failed: ${result.reason}`));
|
|
1274
|
+
logger.log(chalk.gray(` ${result.message || ""}`));
|
|
1275
|
+
if (result.reason === "BRIDGE_UNAVAILABLE") {
|
|
1276
|
+
logger.log(
|
|
1277
|
+
chalk.gray(
|
|
1278
|
+
" Install Android Platform Tools or set ADB_PATH=/path/to/adb",
|
|
1279
|
+
),
|
|
1280
|
+
);
|
|
1281
|
+
} else if (result.reason === "KUAISHOU_NO_ROOT") {
|
|
1282
|
+
logger.log(
|
|
1283
|
+
chalk.gray(
|
|
1284
|
+
" Phone needs Magisk root — Kuaishou release APK isn't debuggable",
|
|
1285
|
+
),
|
|
1286
|
+
);
|
|
1287
|
+
} else if (result.reason === "KUAISHOU_NOT_INSTALLED") {
|
|
1288
|
+
logger.log(
|
|
1289
|
+
chalk.gray(
|
|
1290
|
+
" Install 快手 (com.smile.gifmaker, NOT 极速版 com.kuaishou.nebula) + log in once + open any video (WebView populates cookies), then retry",
|
|
1291
|
+
),
|
|
1292
|
+
);
|
|
1293
|
+
} else if (result.reason === "KUAISHOU_COOKIES_INCOMPLETE") {
|
|
1294
|
+
logger.log(
|
|
1295
|
+
chalk.gray(
|
|
1296
|
+
" userId / kuaishou.web.cp.api_ph missing — relog on the Kuaishou App",
|
|
1297
|
+
),
|
|
1298
|
+
);
|
|
1299
|
+
} else if (
|
|
1300
|
+
result.reason === "KUAISHOU_COOKIES_TRUNCATED" ||
|
|
1301
|
+
result.reason === "KUAISHOU_NOT_SQLITE"
|
|
1302
|
+
) {
|
|
1303
|
+
logger.log(
|
|
1304
|
+
chalk.gray(
|
|
1305
|
+
" ADB stream may be corrupted; unplug + replug USB and retry",
|
|
1306
|
+
),
|
|
1307
|
+
);
|
|
1308
|
+
}
|
|
1309
|
+
process.exitCode = 1;
|
|
1310
|
+
return;
|
|
1311
|
+
}
|
|
1312
|
+
const report = result.report || {};
|
|
1313
|
+
const kuaishou = report.kuaishou || {};
|
|
1314
|
+
const counts = kuaishou.eventCounts || {};
|
|
1315
|
+
logger.log(chalk.green(`✓ kuaishou-adb-sync succeeded`));
|
|
1316
|
+
logger.log(
|
|
1317
|
+
` uid: ${chalk.cyan(kuaishou.uid || "(profile fetch failed)")}`,
|
|
1318
|
+
);
|
|
1319
|
+
if (kuaishou.nickname) {
|
|
1320
|
+
logger.log(` nickname: ${kuaishou.nickname}`);
|
|
1321
|
+
}
|
|
1322
|
+
logger.log(` profile: ${counts.profile || 0}`);
|
|
1323
|
+
logger.log(` watch: ${counts.watch || 0}`);
|
|
1324
|
+
logger.log(` collect: ${counts.collect || 0}`);
|
|
1325
|
+
logger.log(` search: ${counts.search || 0}`);
|
|
1326
|
+
logger.log(` total: ${counts.total || 0}`);
|
|
1327
|
+
logger.log(` status: ${report.status || "?"}`);
|
|
1328
|
+
logger.log(` rawCount: ${report.rawCount || 0}`);
|
|
1329
|
+
if (kuaishou.profileFetchFailed) {
|
|
1330
|
+
logger.log(
|
|
1331
|
+
chalk.yellow(
|
|
1332
|
+
` ⚠ cookie 缺 kuaishou.web.cp.api_ph — relog on Kuaishou (lastErrorCode=${kuaishou.lastErrorCode})`,
|
|
1333
|
+
),
|
|
1334
|
+
);
|
|
1335
|
+
} else if (
|
|
1336
|
+
kuaishou.signProviderUsed === "none" &&
|
|
1337
|
+
counts.watch === 0 &&
|
|
1338
|
+
counts.collect === 0 &&
|
|
1339
|
+
counts.search === 0
|
|
1340
|
+
) {
|
|
1341
|
+
logger.log(
|
|
1342
|
+
chalk.yellow(
|
|
1343
|
+
` ⚠ 3 signed endpoints short-circuited (no sign bridge in CLI context) — run from desktop app to enable __NS_sig3 via Electron WebContentsView`,
|
|
1344
|
+
),
|
|
1345
|
+
);
|
|
1346
|
+
} else if (kuaishou.lastErrorCode) {
|
|
1347
|
+
logger.log(
|
|
1348
|
+
chalk.yellow(
|
|
1349
|
+
` ⚠ partial: lastErrorCode=${kuaishou.lastErrorCode} (${kuaishou.lastErrorMessage || "?"})`,
|
|
1350
|
+
),
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1353
|
+
if (kuaishou.cleanupFailed) {
|
|
1354
|
+
logger.log(chalk.gray(` (note: staging cleanup failed — non-fatal)`));
|
|
1355
|
+
}
|
|
1356
|
+
} catch (err) {
|
|
1357
|
+
fail(null, err, options.json);
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
/**
|
|
1362
|
+
* Phase 6c — `cc hub toutiao-adb-sync`
|
|
1363
|
+
*
|
|
1364
|
+
* Pulls www.toutiao.com cookies from the user's Android Toutiao App,
|
|
1365
|
+
* fetches uid + profile (no _sig) + 3 signed endpoints (feed / collection
|
|
1366
|
+
* / search). CLI context has NO sign bridge — 3 signed endpoints short-
|
|
1367
|
+
* circuit with lastErrorCode=-99 (no HTTP traffic). Desktop wiring
|
|
1368
|
+
* upgrades via ToutiaoSignBridge (Electron WebContentsView).
|
|
1369
|
+
*/
|
|
1370
|
+
async function cmdToutiaoAdbSync(options) {
|
|
1371
|
+
try {
|
|
1372
|
+
const hub = await (options._getHub || getHub)();
|
|
1373
|
+
const result = await hub.toutiaoAdbSync({
|
|
1374
|
+
stagingDir: options.stagingDir,
|
|
1375
|
+
displayName: options.displayName,
|
|
1376
|
+
limits:
|
|
1377
|
+
options.limitFeed || options.limitCollection || options.limitSearch
|
|
1378
|
+
? {
|
|
1379
|
+
feed: parsePositiveInt(options.limitFeed),
|
|
1380
|
+
collection: parsePositiveInt(options.limitCollection),
|
|
1381
|
+
search: parsePositiveInt(options.limitSearch),
|
|
1382
|
+
}
|
|
1383
|
+
: undefined,
|
|
1384
|
+
});
|
|
1385
|
+
if (options.json) {
|
|
1386
|
+
printJson(result);
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
if (!result.ok) {
|
|
1390
|
+
logger.log(chalk.red(`✗ toutiao-adb-sync failed: ${result.reason}`));
|
|
1391
|
+
logger.log(chalk.gray(` ${result.message || ""}`));
|
|
1392
|
+
if (result.reason === "BRIDGE_UNAVAILABLE") {
|
|
1393
|
+
logger.log(
|
|
1394
|
+
chalk.gray(
|
|
1395
|
+
" Install Android Platform Tools or set ADB_PATH=/path/to/adb",
|
|
1396
|
+
),
|
|
1397
|
+
);
|
|
1398
|
+
} else if (result.reason === "TOUTIAO_NO_ROOT") {
|
|
1399
|
+
logger.log(
|
|
1400
|
+
chalk.gray(
|
|
1401
|
+
" Phone needs Magisk root — Toutiao release APK isn't debuggable",
|
|
1402
|
+
),
|
|
1403
|
+
);
|
|
1404
|
+
} else if (result.reason === "TOUTIAO_NOT_INSTALLED") {
|
|
1405
|
+
logger.log(
|
|
1406
|
+
chalk.gray(
|
|
1407
|
+
" Install 今日头条 (com.ss.android.article.news, NOT 极速版/.lite) + log in once + open any article (WebView populates cookies), then retry",
|
|
1408
|
+
),
|
|
1409
|
+
);
|
|
1410
|
+
} else if (result.reason === "TOUTIAO_COOKIES_INCOMPLETE") {
|
|
1411
|
+
logger.log(
|
|
1412
|
+
chalk.gray(
|
|
1413
|
+
" sessionid / sessionid_ss missing — relog on the Toutiao App",
|
|
1414
|
+
),
|
|
1415
|
+
);
|
|
1416
|
+
} else if (
|
|
1417
|
+
result.reason === "TOUTIAO_COOKIES_TRUNCATED" ||
|
|
1418
|
+
result.reason === "TOUTIAO_NOT_SQLITE"
|
|
1419
|
+
) {
|
|
1420
|
+
logger.log(
|
|
1421
|
+
chalk.gray(
|
|
1422
|
+
" ADB stream may be corrupted; unplug + replug USB and retry",
|
|
1423
|
+
),
|
|
1424
|
+
);
|
|
1425
|
+
}
|
|
1426
|
+
process.exitCode = 1;
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
const report = result.report || {};
|
|
1430
|
+
const toutiao = report.toutiao || {};
|
|
1431
|
+
const counts = toutiao.eventCounts || {};
|
|
1432
|
+
logger.log(chalk.green(`✓ toutiao-adb-sync succeeded`));
|
|
1433
|
+
logger.log(
|
|
1434
|
+
` uid: ${chalk.cyan(toutiao.uid || "(profile fetch failed)")}`,
|
|
1435
|
+
);
|
|
1436
|
+
if (toutiao.nickname) {
|
|
1437
|
+
logger.log(` nickname: ${toutiao.nickname}`);
|
|
1438
|
+
}
|
|
1439
|
+
logger.log(` profile: ${counts.profile || 0}`);
|
|
1440
|
+
logger.log(` feed: ${counts.feed || 0}`);
|
|
1441
|
+
logger.log(` collection: ${counts.collection || 0}`);
|
|
1442
|
+
logger.log(` search: ${counts.search || 0}`);
|
|
1443
|
+
logger.log(` total: ${counts.total || 0}`);
|
|
1444
|
+
logger.log(` status: ${report.status || "?"}`);
|
|
1445
|
+
logger.log(` rawCount: ${report.rawCount || 0}`);
|
|
1446
|
+
if (toutiao.profileFetchFailed) {
|
|
1447
|
+
logger.log(
|
|
1448
|
+
chalk.yellow(
|
|
1449
|
+
` ⚠ passport/info/v2 returned no user_id — cookie expired or sessionid missing (lastErrorCode=${toutiao.lastErrorCode})`,
|
|
1450
|
+
),
|
|
1451
|
+
);
|
|
1452
|
+
} else if (
|
|
1453
|
+
toutiao.signProviderUsed === "none" &&
|
|
1454
|
+
counts.feed === 0 &&
|
|
1455
|
+
counts.collection === 0 &&
|
|
1456
|
+
counts.search === 0
|
|
1457
|
+
) {
|
|
1458
|
+
logger.log(
|
|
1459
|
+
chalk.yellow(
|
|
1460
|
+
` ⚠ 3 signed endpoints short-circuited (no sign bridge in CLI context) — run from desktop app to enable _signature via Electron WebContentsView`,
|
|
1461
|
+
),
|
|
1462
|
+
);
|
|
1463
|
+
} else if (toutiao.lastErrorCode) {
|
|
1464
|
+
logger.log(
|
|
1465
|
+
chalk.yellow(
|
|
1466
|
+
` ⚠ partial: lastErrorCode=${toutiao.lastErrorCode} (${toutiao.lastErrorMessage || "?"})`,
|
|
1467
|
+
),
|
|
1468
|
+
);
|
|
1469
|
+
}
|
|
1470
|
+
if (toutiao.cleanupFailed) {
|
|
1471
|
+
logger.log(chalk.gray(` (note: staging cleanup failed — non-fatal)`));
|
|
1472
|
+
}
|
|
1473
|
+
} catch (err) {
|
|
1474
|
+
fail(null, err, options.json);
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1195
1478
|
/**
|
|
1196
1479
|
* Phase 3a — `cc hub weibo-adb-sync`
|
|
1197
1480
|
*
|
|
@@ -1726,6 +2009,25 @@ export function registerHubCommand(program) {
|
|
|
1726
2009
|
.option("--json", "Output JSON")
|
|
1727
2010
|
.action(cmdAsk);
|
|
1728
2011
|
|
|
2012
|
+
hub
|
|
2013
|
+
.command("retrieve-context <question>")
|
|
2014
|
+
.description(
|
|
2015
|
+
"RAG preflight — gather facts + build LLM prompt WITHOUT calling LLM (for cloud-LLM callers that need RAG context)",
|
|
2016
|
+
)
|
|
2017
|
+
.option(
|
|
2018
|
+
"--max-facts <n>",
|
|
2019
|
+
"Cap facts in prompt (default 80; on-device small models e.g. Qwen2.5-1.5B should pass 20)",
|
|
2020
|
+
)
|
|
2021
|
+
.option(
|
|
2022
|
+
"--max-query-limit <n>",
|
|
2023
|
+
"Cap vault queryEvents limit (default 200; small-model callers should pass 50)",
|
|
2024
|
+
)
|
|
2025
|
+
.option(
|
|
2026
|
+
"--no-minimal",
|
|
2027
|
+
"Use full hub init (with adapters / KG / RAG sinks). Default uses minimal init (vault + engine only) which is ~10-20x faster on cold-start.",
|
|
2028
|
+
)
|
|
2029
|
+
.action(cmdRetrieveContext);
|
|
2030
|
+
|
|
1729
2031
|
hub
|
|
1730
2032
|
.command("stats")
|
|
1731
2033
|
.description("Vault row counts + registered adapter list + hub paths")
|
|
@@ -1819,6 +2121,53 @@ export function registerHubCommand(program) {
|
|
|
1819
2121
|
.option("--json", "Output JSON")
|
|
1820
2122
|
.action(cmdWeiboAdbSync);
|
|
1821
2123
|
|
|
2124
|
+
// Phase 6d — Kuaishou C 路径 one-shot (www.kuaishou.com cookies + profile
|
|
2125
|
+
// from api_ph + 3 GraphQL endpoints with __NS_sig3 + kpf/kpn).
|
|
2126
|
+
// CLI: signed endpoints short-circuit. Desktop: KuaishouSignBridge.
|
|
2127
|
+
hub
|
|
2128
|
+
.command("kuaishou-adb-sync")
|
|
2129
|
+
.description(
|
|
2130
|
+
"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.",
|
|
2131
|
+
)
|
|
2132
|
+
.option(
|
|
2133
|
+
"--limit-watch <n>",
|
|
2134
|
+
"Cap recommended feed watch history (default 50)",
|
|
2135
|
+
)
|
|
2136
|
+
.option("--limit-collect <n>", "Cap own posted photos (default 100)")
|
|
2137
|
+
.option("--limit-search <n>", "Cap search history (default 50)")
|
|
2138
|
+
.option(
|
|
2139
|
+
"--display-name <s>",
|
|
2140
|
+
"Account displayName for the snapshot (default = api_ph user_name)",
|
|
2141
|
+
)
|
|
2142
|
+
.option(
|
|
2143
|
+
"--staging-dir <path>",
|
|
2144
|
+
"Custom dir for the temp snapshot JSON (default os.tmpdir())",
|
|
2145
|
+
)
|
|
2146
|
+
.option("--json", "Output JSON")
|
|
2147
|
+
.action(cmdKuaishouAdbSync);
|
|
2148
|
+
|
|
2149
|
+
// Phase 6c — Toutiao C 路径 one-shot (www.toutiao.com cookies + profile +
|
|
2150
|
+
// 3 endpoints with _signature). CLI context: signed endpoints short-circuit
|
|
2151
|
+
// (-99) with no HTTP traffic. Desktop: ToutiaoSignBridge → ~100% hit.
|
|
2152
|
+
hub
|
|
2153
|
+
.command("toutiao-adb-sync")
|
|
2154
|
+
.description(
|
|
2155
|
+
"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.",
|
|
2156
|
+
)
|
|
2157
|
+
.option("--limit-feed <n>", "Cap recommended feed (default 50)")
|
|
2158
|
+
.option("--limit-collection <n>", "Cap saved articles (default 200)")
|
|
2159
|
+
.option("--limit-search <n>", "Cap search history (default 100)")
|
|
2160
|
+
.option(
|
|
2161
|
+
"--display-name <s>",
|
|
2162
|
+
"Account displayName for the snapshot (default = passport screen_name)",
|
|
2163
|
+
)
|
|
2164
|
+
.option(
|
|
2165
|
+
"--staging-dir <path>",
|
|
2166
|
+
"Custom dir for the temp snapshot JSON (default os.tmpdir())",
|
|
2167
|
+
)
|
|
2168
|
+
.option("--json", "Output JSON")
|
|
2169
|
+
.action(cmdToutiaoAdbSync);
|
|
2170
|
+
|
|
1822
2171
|
// Phase 3c — Xhs C 路径 one-shot (xiaohongshu.com cookies + 4 endpoints with X-S signing)
|
|
1823
2172
|
hub
|
|
1824
2173
|
.command("xhs-adb-sync")
|
|
@@ -2098,6 +2447,7 @@ export function registerHubCommand(program) {
|
|
|
2098
2447
|
// real `getHub()` call. The commander wiring above is the runtime path.
|
|
2099
2448
|
export const _internal = {
|
|
2100
2449
|
cmdAsk,
|
|
2450
|
+
cmdRetrieveContext,
|
|
2101
2451
|
parsePositiveInt,
|
|
2102
2452
|
cmdAIChatList,
|
|
2103
2453
|
cmdAIChatLogin,
|
|
@@ -2115,6 +2465,8 @@ export const _internal = {
|
|
|
2115
2465
|
cmdDouyinAdbSync,
|
|
2116
2466
|
cmdWeiboAdbSync,
|
|
2117
2467
|
cmdXhsAdbSync,
|
|
2468
|
+
cmdToutiaoAdbSync,
|
|
2469
|
+
cmdKuaishouAdbSync,
|
|
2118
2470
|
interpretWechatProbe,
|
|
2119
2471
|
_defaultKnownVendors,
|
|
2120
2472
|
};
|
|
@@ -442,6 +442,40 @@ export const PERSONAL_DATA_HUB_HANDLERS = {
|
|
|
442
442
|
}),
|
|
443
443
|
),
|
|
444
444
|
|
|
445
|
+
// Phase 6c — Toutiao C 路径 one-shot sync (www.toutiao.com cookies +
|
|
446
|
+
// passport profile + 3 _signature endpoints). CLI/web context with no
|
|
447
|
+
// desktop bridge: 3 signed endpoints short-circuit (no HTTP). Desktop
|
|
448
|
+
// wiring uses ToutiaoSignBridge → ~100% hit.
|
|
449
|
+
"personal-data-hub.toutiao-adb-sync": async (msg) =>
|
|
450
|
+
withHub((hub) =>
|
|
451
|
+
hub.toutiaoAdbSync({
|
|
452
|
+
limits: msg && msg.limits,
|
|
453
|
+
stagingDir: msg && msg.stagingDir,
|
|
454
|
+
displayName: msg && msg.displayName,
|
|
455
|
+
}),
|
|
456
|
+
),
|
|
457
|
+
|
|
458
|
+
// Phase 6d — Kuaishou C 路径 one-shot sync (www.kuaishou.com cookies +
|
|
459
|
+
// profile from api_ph payload + 3 GraphQL endpoints with __NS_sig3 +
|
|
460
|
+
// kpf/kpn). CLI/web context: signed endpoints short-circuit (no HTTP).
|
|
461
|
+
// Desktop wiring uses KuaishouSignBridge → ~100% hit.
|
|
462
|
+
"personal-data-hub.kuaishou-adb-sync": async (msg) =>
|
|
463
|
+
withHub((hub) =>
|
|
464
|
+
hub.kuaishouAdbSync({
|
|
465
|
+
limits: msg && msg.limits,
|
|
466
|
+
stagingDir: msg && msg.stagingDir,
|
|
467
|
+
displayName: msg && msg.displayName,
|
|
468
|
+
}),
|
|
469
|
+
),
|
|
470
|
+
|
|
471
|
+
// Phase 6e — Bridge dry-run doctor. Spins up Xhs / Toutiao / Kuaishou
|
|
472
|
+
// sign bridges with empty cookie, probes for candidate signing globals,
|
|
473
|
+
// times each phase. No phone needed. Detects SDK rotation BEFORE the
|
|
474
|
+
// user starts a real sync. Desktop-only — CLI/web-shell-no-desktop
|
|
475
|
+
// returns MODULE_LOAD_FAILED.
|
|
476
|
+
"personal-data-hub.bridge-doctor": async () =>
|
|
477
|
+
withHub((hub) => hub.bridgeDoctor()),
|
|
478
|
+
|
|
445
479
|
// ─── Phase 8 — EntityResolver review / merge / unmerge ───────────────
|
|
446
480
|
|
|
447
481
|
"personal-data-hub.review-queue-list": async (msg) =>
|