chainlesschain 0.162.13 → 0.162.15
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/README.md +1 -1
- package/package.json +2 -2
- package/src/assets/web-panel/assets/{AIOps-Bq_zxhCr.js → AIOps-Dr5poTWh.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CaevDm9t.js → ActionButton-DLOGPHQ-.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-B0gOmwPw.js → Analytics-DBlO3FPX.js} +1 -1
- package/src/assets/web-panel/assets/{AppLayout-DWhZiV0Q.js → AppLayout-BrMarmWx.js} +2 -2
- package/src/assets/web-panel/assets/{Audit-ZuZJBCxo.js → Audit-DX6omFqA.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CX7jhH5l.js → Backup-0QSLlQkB.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CVLx7HVq.js → BaseInput-Dn4GFfR8.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-C6yL5tRD.js → Chat-CMTeA0Zo.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BePhbqVq.js → Checkbox-BQQxf6iA.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-B5E4x1Lm.js → Codegen-D2vrazFC.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CWhNU6A7.js → Col-P1hVDVKm.js} +1 -1
- package/src/assets/web-panel/assets/{Community-mSEAuJhp.js → Community-CPcDkABv.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DSudHzX3.js → Compact-DvBQwE-b.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CxJLYjyn.js → Compliance-GX2qsHkq.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-C-trppQj.js → Cowork-CEEISrBb.js} +1 -1
- package/src/assets/web-panel/assets/{Cron-_Ij4v5fY.js → Cron-Y3D6wB4C.js} +1 -1
- package/src/assets/web-panel/assets/{Crosschain-eLHXzp5T.js → Crosschain-CnCjDKKD.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BP04AUUB.js → DID-CJ2EFB5b.js} +1 -1
- package/src/assets/web-panel/assets/{Dashboard-CzEeQv62.js → Dashboard-CWujrs70.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-C_SGOB22.js → Dropdown-BzKSQA5P.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BgaP4BOv.js → Federation-DgaAWIwd.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BxGLLt9r.js → FormItemContext-BitgB4Gb.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Bt_uM_Gw.js → Git-Bzj4vLLf.js} +1 -1
- package/src/assets/web-panel/assets/{Governance-N2-0RG_o.js → Governance-D7DEdSBD.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-eS3g-CzP.js → Inference-CVsGLfcX.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CUuvNVah.js → KnowledgeGraph-CF6C6ZNo.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-wPbwEt2r.js → Logs-C0Er-tt8.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-DH91kTwo.js → Marketplace-_E7uwUUU.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-D-GyyBrI.js → McpTools-dHbktLMV.js} +1 -1
- package/src/assets/web-panel/assets/{Memory-BOtUy-tw.js → Memory-CaQ4UY7b.js} +1 -1
- package/src/assets/web-panel/assets/{MobileBridge-DIP__XQd.js → MobileBridge-BbOh0uJt.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-1nqr1UsU.js → MobileProjects-CfdNEimZ.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CCE0x7h2.js → Mtc-HLvyepRP.js} +1 -1
- package/src/assets/web-panel/assets/{MtcAudit-BBkz0XUO.js → MtcAudit-DMaHGoIr.js} +1 -1
- package/src/assets/web-panel/assets/{Multisig-CIKSJvTY.js → Multisig-DFNZf0AB.js} +1 -1
- package/src/assets/web-panel/assets/{NLProgramming-BDkgeFcq.js → NLProgramming-cZwXhWy2.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-ONiUxfN1.js → Notes-U_3n8Zid.js} +1 -1
- package/src/assets/web-panel/assets/{NotificationSettings-CGcyKEIe.js → NotificationSettings-B4VvhkKf.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BZtMYBJt.js → Organization-BIwBFrdX.js} +1 -1
- package/src/assets/web-panel/assets/{Overflow-C4LfFZAI.js → Overflow-_zxR8gF2.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-D71Cpk-m.js → P2P-DJXmWhLC.js} +1 -1
- package/src/assets/web-panel/assets/{Permissions-DRGYF29v.js → Permissions-DwJ35K8Z.js} +1 -1
- package/src/assets/web-panel/assets/{PersonalDataHub-CfRYoIua.js → PersonalDataHub-CzZXLXGN.js} +1 -1
- package/src/assets/web-panel/assets/{Pipeline-BOyp0_Qo.js → Pipeline-DjtRGM8X.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-a_AcphvF.js → Privacy-BJhsIhGf.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CFu1grYt.js → ProjectInit-DEx5SDLh.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectSettings-p54Eivhh.js → ProjectSettings-B6qDg7nn.js} +1 -1
- package/src/assets/web-panel/assets/{Projects-DkB88XAu.js → Projects-CKkTgrBf.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-EK7f8DEd.js → Providers-3GEshcW_.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CpO0w3iP.js → QuickAsk-BfUXbKxa.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BUJVQdv9.js → Recommend-DgxYasSJ.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-kU2fOuZt.js → Reputation-CWvVg_V1.js} +1 -1
- package/src/assets/web-panel/assets/{Row-oGWRbk6g.js → Row-42M5ot1v.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-saC_46Yo.js → RssFeed-Do3isL1x.js} +1 -1
- package/src/assets/web-panel/assets/{Search-CjtRqFUu.js → Search-_7wgwjaR.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BX0NBVfQ.js → Security-DKB6pe8t.js} +1 -1
- package/src/assets/web-panel/assets/{Services-Bgxsnei_.js → Services-BHrBJAcB.js} +1 -1
- package/src/assets/web-panel/assets/{Skeleton-CwBb3k2a.js → Skeleton-C8L-EfGp.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CZCMYH6Z.js → Skills-CU66huTh.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-Djy1uHnZ.js → Sla-DA8AKNmI.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CGUI_Uyh.js → SpeechSettings-CufjYTzV.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DK2CKHRD.js → SyncSettings-D_VAYHIg.js} +1 -1
- package/src/assets/web-panel/assets/{Tasks-BKiOzeIO.js → Tasks-BE6nYh9k.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CnQpleXj.js → Templates-BfRbttd6.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DwKz0cjm.js → Tenant-YO71CL80.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-A7t_wsR8.js → Terminal-D1mQaE_Z.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BqYY9l44.js → Tokens-CvnNQtX4.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BI4bXFmi.js → Trigger-BnN19FJt.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-yMynKTRG.js → Trust-C6oZLHqp.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Br4IScM6.js → UkeySign-BOhFYuWu.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CWcThGsP.js → VideoEditing-NMc6-qc-.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CZcAtjxj.js → Wallet-BALmcKtd.js} +1 -1
- package/src/assets/web-panel/assets/{WebAuthn-BnTZFMA0.js → WebAuthn-6IVe-W6O.js} +1 -1
- package/src/assets/web-panel/assets/{WorkflowEditor-N7gGz3_n.js → WorkflowEditor-BIv20DXb.js} +1 -1
- package/src/assets/web-panel/assets/{chat-D175ZIO0.js → chat-CiceyA69.js} +1 -1
- package/src/assets/web-panel/assets/{colors-LKhZyttv.js → colors-CxwvpRW0.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-CsJSebxT.js → compact-item-N6ASDseQ.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BJ_CPYFC.js → createContext-CQ8PEhyP.js} +1 -1
- package/src/assets/web-panel/assets/{hasIn-CzD3IqH8.js → hasIn-DDiIuryC.js} +1 -1
- package/src/assets/web-panel/assets/{index-BhiZDGg7.js → index-1jBrqw2R.js} +1 -1
- package/src/assets/web-panel/assets/index-1losWCP0.js +1 -0
- package/src/assets/web-panel/assets/{index-CRGNuUIM.js → index-92sMXPmR.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dm-3kvtD.js → index-BCgZTQf8.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZluCuTH.js → index-BKLatStI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CTIkCKav.js → index-BKmY57ry.js} +1 -1
- package/src/assets/web-panel/assets/{index-E7t1hAnk.js → index-BZ4O1Vp7.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7ZcBI5s.js → index-BdmcwwMp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BNVLVzN5.js → index-Bj-mAQFK.js} +1 -1
- package/src/assets/web-panel/assets/{index-R1cFADfk.js → index-BjvirvV4.js} +1 -1
- package/src/assets/web-panel/assets/{index-BvF2tC6C.js → index-Bw6UqIkJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-6qPbrYF7.js → index-BzdEj9_B.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMvdoiFr.js → index-C43WIe_p.js} +1 -1
- package/src/assets/web-panel/assets/{index-BjOrt4vw.js → index-CHsNn-Qv.js} +1 -1
- package/src/assets/web-panel/assets/{index-BsirlkJ0.js → index-COIxnEwP.js} +1 -1
- package/src/assets/web-panel/assets/{index-D401L3yx.js → index-C_dbCu-F.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDSZDDb2.js → index-Cb0QVAZL.js} +3 -3
- package/src/assets/web-panel/assets/{index-BV-__mlC.js → index-CcUK2M7W.js} +1 -1
- package/src/assets/web-panel/assets/{index-DXp1jVsK.js → index-ClASVywF.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8kltMTW.js → index-CnArbjXg.js} +1 -1
- package/src/assets/web-panel/assets/{index-Kn-Of5ew.js → index-Cur_KKpV.js} +1 -1
- package/src/assets/web-panel/assets/{index-RIO4JKMP.js → index-Cwk0olXV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKjBAdm0.js → index-D0yG93O4.js} +1 -1
- package/src/assets/web-panel/assets/{index-BSNibAqz.js → index-D58a5SL3.js} +1 -1
- package/src/assets/web-panel/assets/{index-uTEVWPYA.js → index-DEjAgx2R.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJVkBmSc.js → index-DUKjS4kF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmJdof_c.js → index-DWKigrAM.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2HBKw07.js → index-DcMESTJs.js} +1 -1
- package/src/assets/web-panel/assets/{index-DnPt5OdD.js → index-DgwpVvQq.js} +1 -1
- package/src/assets/web-panel/assets/{index-DOO73rHE.js → index-Dj2wgF3A.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5IZCkZG.js → index-DobYLmfZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-JTX9A7w0.js → index-Dp3r80qO.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyHdYUeZ.js → index-DtpWqJ-2.js} +1 -1
- package/src/assets/web-panel/assets/index-EoP_WtDt.js +1 -0
- package/src/assets/web-panel/assets/{index-BEDFHKO3.js → index-_BHtKVC_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXH9ujMW.js → index-bYorCa3r.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dd7dICwB.js → index-hn9LVkIY.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7UYymse.js → index-mmpauJ3E.js} +1 -1
- package/src/assets/web-panel/assets/{index-DM3uBEWD.js → index-xQlQRo2j.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CBW0okek.js → initDefaultProps-1MKZtqXZ.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DGAffQ0Z.js → motion-DFBQpRS8.js} +1 -1
- package/src/assets/web-panel/assets/{move-DFJ0-5IW.js → move-CiI8Ada0.js} +1 -1
- package/src/assets/web-panel/assets/{omit-AvrDghg1.js → omit-CjeFoPcC.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-D7csw9i1.js → pickAttrs-Be3kefJq.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-hZ6Lg6kG.js → placementArrow-Be5Ra1_B.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DLLx5VvS.js → responsiveObserve-NCu3YHiX.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BaRIT3ev.js → slide-f23lSB4X.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Cdjyuhrz.js → statusUtils-Dq99US_U.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CbrNybTt.js → styleChecker-B-UUq5Ww.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-B8gAhiRC.js → useFlexGapSupport-D6aUzeVO.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BZPy4ICP.js → useFs-DU-R5a4I.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-6Y0NDMVv.js → vnode-N7r8LSGe.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DTbMGsSH.js → zoom-07xoxB1t.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/__tests__/android.test.js +260 -0
- package/src/commands/__tests__/hub-wechat.test.js +186 -15
- package/src/commands/android.js +284 -0
- package/src/commands/hub.js +263 -19
- package/src/gateways/ws/personal-data-hub-protocol.js +28 -8
- package/src/index.js +2 -0
- package/src/lib/__tests__/cc-android-bridge.test.js +245 -0
- package/src/lib/cc-android-bridge.js +206 -0
- package/src/lib/personal-data-hub-wiring.js +98 -20
- package/src/lib/web-ui-server.js +2 -1
- package/src/assets/web-panel/assets/index-CY1mQA2I.js +0 -1
- package/src/assets/web-panel/assets/index-D9nXHfUB.js +0 -1
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cc android` — Android-side data + control commands.
|
|
3
|
+
*
|
|
4
|
+
* Plan A Sub-Phase A7 scaffold. Exposes the bridge surface from
|
|
5
|
+
* `lib/cc-android-bridge.js` as commander subcommands. Method shapes mirror
|
|
6
|
+
* `docs/design/Personal_Data_Hub_Android_Standalone_Cc.md` §6.1.
|
|
7
|
+
*
|
|
8
|
+
* **v0.1 status**: native JNI bridge (`cc-android-bridge.node`) not yet
|
|
9
|
+
* bundled (A6 in progress). On non-Android hosts every command exits non-zero
|
|
10
|
+
* with `ANDROID_BRIDGE_NOT_AVAILABLE`. On Android with a missing binding,
|
|
11
|
+
* same error with a different reason string. This lets the surface land and
|
|
12
|
+
* be tested ahead of the JNI shipping work.
|
|
13
|
+
*
|
|
14
|
+
* All commands support `--json` for scripting and exit non-zero on error.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import chalk from "chalk";
|
|
18
|
+
import { logger } from "../lib/logger.js";
|
|
19
|
+
import * as bridgeModule from "../lib/cc-android-bridge.js";
|
|
20
|
+
|
|
21
|
+
function printJson(obj) {
|
|
22
|
+
console.log(JSON.stringify(obj, null, 2));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function fail(err, asJson) {
|
|
26
|
+
const msg = err && err.message ? err.message : String(err);
|
|
27
|
+
const code = err && err.code ? err.code : null;
|
|
28
|
+
if (asJson) {
|
|
29
|
+
printJson({ error: msg, code });
|
|
30
|
+
} else {
|
|
31
|
+
logger.error(chalk.red(`✗ ${msg}`));
|
|
32
|
+
}
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function run(method, params, options) {
|
|
37
|
+
try {
|
|
38
|
+
const result = await _deps.bridge.invoke(method, params);
|
|
39
|
+
if (options.json) {
|
|
40
|
+
printJson(result);
|
|
41
|
+
} else {
|
|
42
|
+
console.log(JSON.stringify(result, null, 2));
|
|
43
|
+
}
|
|
44
|
+
} catch (err) {
|
|
45
|
+
fail(err, options.json);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ─── caps ────────────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
async function cmdCaps(options) {
|
|
52
|
+
const capsResult = _deps.bridge.caps();
|
|
53
|
+
if (options.json) {
|
|
54
|
+
printJson(capsResult);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (capsResult.available) {
|
|
58
|
+
logger.log(chalk.green("✓ android bridge available"));
|
|
59
|
+
} else {
|
|
60
|
+
logger.log(
|
|
61
|
+
chalk.yellow(`⚠ android bridge unavailable: ${capsResult.reason}`),
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ─── contacts / sms / calls — P1 ContentResolver ─────────────────────
|
|
67
|
+
|
|
68
|
+
function cmdContactsPull(options) {
|
|
69
|
+
return run(
|
|
70
|
+
"contacts.query",
|
|
71
|
+
{ since: options.since ? Number(options.since) : undefined },
|
|
72
|
+
options,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
function cmdSmsPull(options) {
|
|
76
|
+
return run(
|
|
77
|
+
"sms.query",
|
|
78
|
+
{ since: options.since ? Number(options.since) : undefined },
|
|
79
|
+
options,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
function cmdCallsPull(options) {
|
|
83
|
+
return run(
|
|
84
|
+
"calls.query",
|
|
85
|
+
{ since: options.since ? Number(options.since) : undefined },
|
|
86
|
+
options,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ─── app — PackageManager ────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
function cmdAppList(options) {
|
|
93
|
+
return run("app.list", { includeSystem: !!options.system }, options);
|
|
94
|
+
}
|
|
95
|
+
function cmdAppLaunch(pkg, options) {
|
|
96
|
+
return run("app.launch", { pkg }, options);
|
|
97
|
+
}
|
|
98
|
+
function cmdAppIntent(pkg, action, options) {
|
|
99
|
+
const extras = {};
|
|
100
|
+
if (Array.isArray(options.extra)) {
|
|
101
|
+
for (const kv of options.extra) {
|
|
102
|
+
const idx = kv.indexOf("=");
|
|
103
|
+
if (idx > 0) extras[kv.slice(0, idx)] = kv.slice(idx + 1);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return run("app.intent", { pkg, action, extras }, options);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ─── fs — SAF / sandbox ──────────────────────────────────────────────
|
|
110
|
+
|
|
111
|
+
function cmdFsRead(target, options) {
|
|
112
|
+
return run("fs.read", { target }, options);
|
|
113
|
+
}
|
|
114
|
+
function cmdFsList(target, options) {
|
|
115
|
+
return run("fs.list", { target }, options);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ─── a11y — Accessibility Service ────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
function cmdA11yQuery(options) {
|
|
121
|
+
return run("a11y.query", { filter: options.filter }, options);
|
|
122
|
+
}
|
|
123
|
+
function cmdA11yClick(nodeId, options) {
|
|
124
|
+
return run("a11y.click", { nodeId }, options);
|
|
125
|
+
}
|
|
126
|
+
function cmdA11yType(text, options) {
|
|
127
|
+
return run("a11y.type", { text }, options);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ─── shizuku / root ──────────────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
function cmdShizukuExec(cmd, options) {
|
|
133
|
+
return run("shizuku.exec", { cmd }, options);
|
|
134
|
+
}
|
|
135
|
+
function cmdRootExec(cmd, options) {
|
|
136
|
+
return run("root.exec", { cmd }, options);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ─── perms ────────────────────────────────────────────────────────────
|
|
140
|
+
|
|
141
|
+
function cmdPerms(name, options) {
|
|
142
|
+
return run("perms.check", { name }, options);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ─── Commander wire-up ───────────────────────────────────────────────
|
|
146
|
+
|
|
147
|
+
export function registerAndroidCommand(program) {
|
|
148
|
+
const android = program
|
|
149
|
+
.command("android")
|
|
150
|
+
.description(
|
|
151
|
+
"Android-native bridge: ContentResolver / SAF / Accessibility / Shizuku / root (Plan A A7)",
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
android
|
|
155
|
+
.command("caps")
|
|
156
|
+
.description("Probe what bridge capabilities are available on this device")
|
|
157
|
+
.option("--json", "Output JSON")
|
|
158
|
+
.action(cmdCaps);
|
|
159
|
+
|
|
160
|
+
const contacts = android
|
|
161
|
+
.command("contacts")
|
|
162
|
+
.description("ContentResolver: contacts");
|
|
163
|
+
contacts
|
|
164
|
+
.command("pull")
|
|
165
|
+
.description("Pull contacts (READ_CONTACTS runtime permission required)")
|
|
166
|
+
.option("--since <ms>", "Watermark — only newer entries")
|
|
167
|
+
.option("--json", "Output JSON")
|
|
168
|
+
.action(cmdContactsPull);
|
|
169
|
+
|
|
170
|
+
const sms = android.command("sms").description("ContentResolver: SMS");
|
|
171
|
+
sms
|
|
172
|
+
.command("pull")
|
|
173
|
+
.description("Pull SMS (READ_SMS runtime permission required)")
|
|
174
|
+
.option("--since <ms>", "Watermark")
|
|
175
|
+
.option("--json", "Output JSON")
|
|
176
|
+
.action(cmdSmsPull);
|
|
177
|
+
|
|
178
|
+
const calls = android
|
|
179
|
+
.command("calls")
|
|
180
|
+
.description("ContentResolver: call log");
|
|
181
|
+
calls
|
|
182
|
+
.command("pull")
|
|
183
|
+
.description("Pull call log (READ_CALL_LOG runtime permission required)")
|
|
184
|
+
.option("--since <ms>", "Watermark")
|
|
185
|
+
.option("--json", "Output JSON")
|
|
186
|
+
.action(cmdCallsPull);
|
|
187
|
+
|
|
188
|
+
const app = android
|
|
189
|
+
.command("app")
|
|
190
|
+
.description("PackageManager: app inventory + Intent");
|
|
191
|
+
app
|
|
192
|
+
.command("list")
|
|
193
|
+
.description("List installed packages")
|
|
194
|
+
.option("--system", "Include system packages")
|
|
195
|
+
.option("--json", "Output JSON")
|
|
196
|
+
.action(cmdAppList);
|
|
197
|
+
app
|
|
198
|
+
.command("launch <pkg>")
|
|
199
|
+
.description("Launch app by package id (default activity)")
|
|
200
|
+
.option("--json", "Output JSON")
|
|
201
|
+
.action(cmdAppLaunch);
|
|
202
|
+
app
|
|
203
|
+
.command("intent <pkg> <action>")
|
|
204
|
+
.description("Fire an Intent at <pkg> with <action>")
|
|
205
|
+
.option(
|
|
206
|
+
"--extra <kv...>",
|
|
207
|
+
"Repeatable extras as KEY=VAL (e.g. --extra foo=bar --extra n=1)",
|
|
208
|
+
)
|
|
209
|
+
.option("--json", "Output JSON")
|
|
210
|
+
.action(cmdAppIntent);
|
|
211
|
+
|
|
212
|
+
const fs = android.command("fs").description("SAF / sandbox filesystem");
|
|
213
|
+
fs.command("read <target>")
|
|
214
|
+
.description("Read file (sandbox path OR SAF tree URI)")
|
|
215
|
+
.option("--json", "Output JSON")
|
|
216
|
+
.action(cmdFsRead);
|
|
217
|
+
fs.command("list <target>")
|
|
218
|
+
.description("List directory")
|
|
219
|
+
.option("--json", "Output JSON")
|
|
220
|
+
.action(cmdFsList);
|
|
221
|
+
|
|
222
|
+
const a11y = android.command("a11y").description("Accessibility Service");
|
|
223
|
+
a11y
|
|
224
|
+
.command("query")
|
|
225
|
+
.description("Dump current screen's node tree")
|
|
226
|
+
.option("--filter <css>", "css-like filter")
|
|
227
|
+
.option("--json", "Output JSON")
|
|
228
|
+
.action(cmdA11yQuery);
|
|
229
|
+
a11y
|
|
230
|
+
.command("click <nodeId>")
|
|
231
|
+
.description("Click a node")
|
|
232
|
+
.option("--json", "Output JSON")
|
|
233
|
+
.action(cmdA11yClick);
|
|
234
|
+
a11y
|
|
235
|
+
.command("type <text>")
|
|
236
|
+
.description("Type text into focused field")
|
|
237
|
+
.option("--json", "Output JSON")
|
|
238
|
+
.action(cmdA11yType);
|
|
239
|
+
|
|
240
|
+
const shizuku = android
|
|
241
|
+
.command("shizuku")
|
|
242
|
+
.description("Shizuku ADB-like privileges");
|
|
243
|
+
shizuku
|
|
244
|
+
.command("exec <cmd>")
|
|
245
|
+
.description("Run shell via Shizuku")
|
|
246
|
+
.option("--json", "Output JSON")
|
|
247
|
+
.action(cmdShizukuExec);
|
|
248
|
+
|
|
249
|
+
const root = android.command("root").description("Magisk root su");
|
|
250
|
+
root
|
|
251
|
+
.command("exec <cmd>")
|
|
252
|
+
.description("Run shell as root")
|
|
253
|
+
.option("--json", "Output JSON")
|
|
254
|
+
.action(cmdRootExec);
|
|
255
|
+
|
|
256
|
+
android
|
|
257
|
+
.command("perms <name>")
|
|
258
|
+
.description("Check (and request) a runtime permission")
|
|
259
|
+
.option("--json", "Output JSON")
|
|
260
|
+
.action(cmdPerms);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// _deps injection seam — tests reach in and replace `bridge` with a mock so
|
|
264
|
+
// the cmd* functions exercise the routing code without a real bridge.
|
|
265
|
+
export const _deps = { bridge: bridgeModule };
|
|
266
|
+
|
|
267
|
+
// Test-only exports.
|
|
268
|
+
export const _cmds = {
|
|
269
|
+
cmdCaps,
|
|
270
|
+
cmdContactsPull,
|
|
271
|
+
cmdSmsPull,
|
|
272
|
+
cmdCallsPull,
|
|
273
|
+
cmdAppList,
|
|
274
|
+
cmdAppLaunch,
|
|
275
|
+
cmdAppIntent,
|
|
276
|
+
cmdFsRead,
|
|
277
|
+
cmdFsList,
|
|
278
|
+
cmdA11yQuery,
|
|
279
|
+
cmdA11yClick,
|
|
280
|
+
cmdA11yType,
|
|
281
|
+
cmdShizukuExec,
|
|
282
|
+
cmdRootExec,
|
|
283
|
+
cmdPerms,
|
|
284
|
+
};
|
package/src/commands/hub.js
CHANGED
|
@@ -191,6 +191,9 @@ async function cmdSyncAdapter(name, options) {
|
|
|
191
191
|
if (options.since) opts.since = Number(options.since);
|
|
192
192
|
if (options.until) opts.until = Number(options.until);
|
|
193
193
|
if (options.limit) opts.limit = Number(options.limit);
|
|
194
|
+
// Plan A v0.1 — system-data-android needs a snapshot file path. Generic
|
|
195
|
+
// pass-through so other input-driven adapters reuse the same flag.
|
|
196
|
+
if (options.input) opts.inputPath = String(options.input);
|
|
194
197
|
const report = await hub.registry.syncAdapter(name, opts);
|
|
195
198
|
if (spinner) spinner.succeed(`synced ${name}`);
|
|
196
199
|
if (options.json) {
|
|
@@ -496,8 +499,13 @@ async function cmdAIChatHealth(options) {
|
|
|
496
499
|
const factoryDeps = options._factoryDeps || {};
|
|
497
500
|
const hubDir =
|
|
498
501
|
factoryDeps.hubDir || (await (options._getHub || getHub)()).hubDir;
|
|
499
|
-
|
|
500
|
-
|
|
502
|
+
// Bypass vite import-analysis (which can't resolve subpath exports
|
|
503
|
+
// for dynamic imports in vitest SSR mode) by composing the specifier
|
|
504
|
+
// at runtime — the static analyzer skips non-literal arguments.
|
|
505
|
+
const hcSpecifier =
|
|
506
|
+
"@chainlesschain/personal-data-hub" +
|
|
507
|
+
"/adapters/ai-chat-history/health-checker";
|
|
508
|
+
const { createAIChatHealthChecker } = await import(hcSpecifier);
|
|
501
509
|
const { createAccountsStore, createVendorAdapterBridge } =
|
|
502
510
|
await import("../lib/personal-data-hub-aichat-wizard.js");
|
|
503
511
|
const accountsStore =
|
|
@@ -566,13 +574,25 @@ async function cmdWechatEnvProbe(options) {
|
|
|
566
574
|
return;
|
|
567
575
|
}
|
|
568
576
|
logger.log(chalk.bold("WeChat env-probe:"));
|
|
569
|
-
logger.log(
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
logger.log(
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
577
|
+
logger.log(
|
|
578
|
+
` ${probe.ok ? chalk.green("✓") : chalk.red("✗")} suggested: ${chalk.cyan(probe.suggestedKeyProvider)}`,
|
|
579
|
+
);
|
|
580
|
+
logger.log(
|
|
581
|
+
` device: ${probe.device.reachable ? chalk.green("reachable") : chalk.red("unreachable")}${probe.device.serial ? " (" + probe.device.serial + ")" : ""} abi=${probe.device.abi || "?"}`,
|
|
582
|
+
);
|
|
583
|
+
logger.log(
|
|
584
|
+
` root: ${probe.root.detected ? chalk.green("yes") : chalk.gray("no")} magisk=${probe.root.magiskInstalled ? "yes" : "no"}`,
|
|
585
|
+
);
|
|
586
|
+
logger.log(
|
|
587
|
+
` frida-server: ${probe.frida.serverRunning ? chalk.green("running") : chalk.gray("not running")}${probe.frida.port ? " :" + probe.frida.port : ""}`,
|
|
588
|
+
);
|
|
589
|
+
logger.log(
|
|
590
|
+
` wechat: ${probe.wechat.installed ? chalk.green(probe.wechat.versionName) : chalk.gray("not installed")}`,
|
|
591
|
+
);
|
|
592
|
+
for (const reason of probe.reasons || [])
|
|
593
|
+
logger.log(` · ${chalk.gray(reason)}`);
|
|
594
|
+
for (const w of probe.warnings || [])
|
|
595
|
+
logger.log(` ${chalk.yellow("!")} ${chalk.yellow(w)}`);
|
|
576
596
|
} catch (err) {
|
|
577
597
|
fail(null, err, options.json);
|
|
578
598
|
}
|
|
@@ -589,16 +609,21 @@ async function cmdWechatRegister(options) {
|
|
|
589
609
|
dbPath: options.db || null,
|
|
590
610
|
wechatDataPath: options.wechatDataPath || null,
|
|
591
611
|
keyProviderOverride: options.forceProvider || null,
|
|
592
|
-
fridaOpts: options.fridaDeviceId
|
|
612
|
+
fridaOpts: options.fridaDeviceId
|
|
613
|
+
? { deviceId: options.fridaDeviceId }
|
|
614
|
+
: null,
|
|
593
615
|
});
|
|
594
616
|
if (options.json) {
|
|
595
617
|
printJson(r);
|
|
596
618
|
return;
|
|
597
619
|
}
|
|
598
620
|
if (!r.ok) {
|
|
599
|
-
logger.error(
|
|
621
|
+
logger.error(
|
|
622
|
+
chalk.red(`✗ ${r.reason || "register failed"}: ${r.message || ""}`),
|
|
623
|
+
);
|
|
600
624
|
if (r.probe) {
|
|
601
|
-
for (const reason of r.probe.reasons || [])
|
|
625
|
+
for (const reason of r.probe.reasons || [])
|
|
626
|
+
logger.error(chalk.gray(" · " + reason));
|
|
602
627
|
}
|
|
603
628
|
process.exit(1);
|
|
604
629
|
}
|
|
@@ -624,13 +649,202 @@ async function cmdWechatList(options) {
|
|
|
624
649
|
}
|
|
625
650
|
logger.log(chalk.bold("Registered WeChat accounts:"));
|
|
626
651
|
for (const row of rows) {
|
|
627
|
-
logger.log(
|
|
652
|
+
logger.log(
|
|
653
|
+
` • uin=${chalk.cyan(row.uin)} provider=${row.chosenKeyProvider || "?"} db=${row.dbPath || "(none)"} regAt=${row.registeredAt ? new Date(row.registeredAt).toISOString() : "?"}`,
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
} catch (err) {
|
|
657
|
+
fail(null, err, options.json);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* `cc hub wechat doctor` — env-probe + actionable interpretation +
|
|
663
|
+
* inline reference to the Phase 12.9 §5.1 Frida hook trap table.
|
|
664
|
+
*
|
|
665
|
+
* Designed to be the single command user runs on a rooted Android during
|
|
666
|
+
* Phase 12.9 real-device E2E to figure out "what should I do next?" —
|
|
667
|
+
* combines env-probe output + readiness checklist (per md5 vs frida
|
|
668
|
+
* path) + post-register telemetry fields to capture if hook fails.
|
|
669
|
+
*
|
|
670
|
+
* Returns the same JSON as env-probe + a `doctor` block under --json so
|
|
671
|
+
* scripts can branch on `doctor.readiness === 'ready' | 'blocked' | 'partial'`.
|
|
672
|
+
*/
|
|
673
|
+
async function cmdWechatDoctor(options) {
|
|
674
|
+
try {
|
|
675
|
+
const hub = await (options._getHub || getHub)();
|
|
676
|
+
const probe = await hub.probeWechatEnv();
|
|
677
|
+
|
|
678
|
+
// Determine readiness + concrete next-action based on probe shape.
|
|
679
|
+
const advice = interpretWechatProbe(probe);
|
|
680
|
+
|
|
681
|
+
if (options.json) {
|
|
682
|
+
printJson({ probe, doctor: advice });
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// Human-readable: re-use env-probe formatting then append advice.
|
|
687
|
+
logger.log(chalk.bold("WeChat env-probe:"));
|
|
688
|
+
logger.log(
|
|
689
|
+
` ${probe.ok ? chalk.green("✓") : chalk.red("✗")} suggested: ${chalk.cyan(probe.suggestedKeyProvider)}`,
|
|
690
|
+
);
|
|
691
|
+
logger.log(
|
|
692
|
+
` device: ${probe.device.reachable ? chalk.green("reachable") : chalk.red("unreachable")}${probe.device.serial ? " (" + probe.device.serial + ")" : ""} abi=${probe.device.abi || "?"}`,
|
|
693
|
+
);
|
|
694
|
+
logger.log(
|
|
695
|
+
` root: ${probe.root.detected ? chalk.green("yes") : chalk.gray("no")} magisk=${probe.root.magiskInstalled ? "yes" : "no"}`,
|
|
696
|
+
);
|
|
697
|
+
logger.log(
|
|
698
|
+
` frida-server: ${probe.frida.serverRunning ? chalk.green("running") : chalk.gray("not running")}${probe.frida.port ? " :" + probe.frida.port : ""}`,
|
|
699
|
+
);
|
|
700
|
+
logger.log(
|
|
701
|
+
` wechat: ${probe.wechat.installed ? chalk.green(probe.wechat.versionName) : chalk.gray("not installed")}`,
|
|
702
|
+
);
|
|
703
|
+
|
|
704
|
+
logger.log("");
|
|
705
|
+
const statusColor =
|
|
706
|
+
advice.readiness === "ready"
|
|
707
|
+
? chalk.green
|
|
708
|
+
: advice.readiness === "partial"
|
|
709
|
+
? chalk.yellow
|
|
710
|
+
: chalk.red;
|
|
711
|
+
logger.log(
|
|
712
|
+
chalk.bold(`Doctor: ${statusColor(advice.readiness.toUpperCase())}`),
|
|
713
|
+
);
|
|
714
|
+
for (const blocker of advice.blockers) {
|
|
715
|
+
logger.log(` ${chalk.red("✗")} ${blocker}`);
|
|
716
|
+
}
|
|
717
|
+
for (const w of advice.warnings) {
|
|
718
|
+
logger.log(` ${chalk.yellow("!")} ${w}`);
|
|
719
|
+
}
|
|
720
|
+
for (const step of advice.nextSteps) {
|
|
721
|
+
logger.log(` ${chalk.cyan("→")} ${step}`);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
if (advice.readiness !== "blocked") {
|
|
725
|
+
logger.log("");
|
|
726
|
+
logger.log(
|
|
727
|
+
chalk.bold("After `cc hub wechat register`, capture telemetry:"),
|
|
728
|
+
);
|
|
729
|
+
logger.log(
|
|
730
|
+
chalk.gray(
|
|
731
|
+
" cc hub wechat register --uin <UIN> --db ... --json | jq '.fridaTelemetry'",
|
|
732
|
+
),
|
|
733
|
+
);
|
|
734
|
+
logger.log(
|
|
735
|
+
chalk.gray(
|
|
736
|
+
" Expected fields: hooked / keySource / keySig / keyFormat / keyLength / keyAlt / errors / durationMs",
|
|
737
|
+
),
|
|
738
|
+
);
|
|
739
|
+
logger.log("");
|
|
740
|
+
logger.log(
|
|
741
|
+
chalk.bold("If hook fails, match telemetry against trap table:"),
|
|
742
|
+
);
|
|
743
|
+
logger.log(
|
|
744
|
+
chalk.gray(
|
|
745
|
+
" A — hooked:[] empty → libWCDB.so module name (try OEM custom names)",
|
|
746
|
+
),
|
|
747
|
+
);
|
|
748
|
+
logger.log(
|
|
749
|
+
chalk.gray(
|
|
750
|
+
" B — keySig:v2 but DB won't open → sqlite3_key_v2 args index wrong",
|
|
751
|
+
),
|
|
752
|
+
);
|
|
753
|
+
logger.log(
|
|
754
|
+
chalk.gray(
|
|
755
|
+
" C — keyFormat:raw-bytes but len=64 → ascii-hex path missed",
|
|
756
|
+
),
|
|
757
|
+
);
|
|
758
|
+
logger.log(
|
|
759
|
+
chalk.gray(
|
|
760
|
+
" Full table: docs/design/Personal_Data_Hub_Phase_12_9_*Runbook.md §5.1",
|
|
761
|
+
),
|
|
762
|
+
);
|
|
628
763
|
}
|
|
629
764
|
} catch (err) {
|
|
630
765
|
fail(null, err, options.json);
|
|
631
766
|
}
|
|
632
767
|
}
|
|
633
768
|
|
|
769
|
+
/**
|
|
770
|
+
* Interpret env-probe result into { readiness, blockers, warnings, nextSteps }.
|
|
771
|
+
* Pure function — testable without device.
|
|
772
|
+
*
|
|
773
|
+
* @param {object} probe output of hub.probeWechatEnv()
|
|
774
|
+
* @returns {{readiness: 'ready'|'partial'|'blocked', blockers: string[],
|
|
775
|
+
* warnings: string[], nextSteps: string[]}}
|
|
776
|
+
*/
|
|
777
|
+
function interpretWechatProbe(probe) {
|
|
778
|
+
const blockers = [];
|
|
779
|
+
const warnings = [];
|
|
780
|
+
const nextSteps = [];
|
|
781
|
+
|
|
782
|
+
if (!probe || !probe.device || !probe.device.reachable) {
|
|
783
|
+
blockers.push("adb 设备未连接 (USB 调试 / drivers / authorize?)");
|
|
784
|
+
nextSteps.push("`adb devices` 应列出至少一台 device 状态");
|
|
785
|
+
return { readiness: "blocked", blockers, warnings, nextSteps };
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
if (!probe.wechat || !probe.wechat.installed) {
|
|
789
|
+
blockers.push("WeChat (com.tencent.mm) 未安装");
|
|
790
|
+
nextSteps.push("先把 WeChat 装上 + 登一次产生 EnMicroMsg.db");
|
|
791
|
+
return { readiness: "blocked", blockers, warnings, nextSteps };
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
const ver = probe.wechat.majorVersion || 0;
|
|
795
|
+
const suggested = probe.suggestedKeyProvider;
|
|
796
|
+
|
|
797
|
+
if (ver < 8 && suggested === "md5") {
|
|
798
|
+
nextSteps.push(
|
|
799
|
+
"MD5 path: `adb pull /data/data/com.tencent.mm/ /tmp/wechat-data/`",
|
|
800
|
+
);
|
|
801
|
+
nextSteps.push(
|
|
802
|
+
"拉到本地后跑: `cc hub wechat register --uin <UIN> --db /tmp/wechat-data/MicroMsg/<md5-uin>/EnMicroMsg.db --wechat-data-path /tmp/wechat-data/`",
|
|
803
|
+
);
|
|
804
|
+
if (!probe.root.detected) {
|
|
805
|
+
warnings.push(
|
|
806
|
+
"非 root 设备只能 adb pull WeChat backup 子集 — 可能拿不到全部 db / 文件",
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
return { readiness: "ready", blockers, warnings, nextSteps };
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
if (ver >= 8 && suggested === "frida") {
|
|
813
|
+
if (!probe.root.detected) {
|
|
814
|
+
blockers.push("WeChat ≥ 8.0 必须 root + Frida hook,当前设备未 root");
|
|
815
|
+
nextSteps.push("Magisk 刷入 → 重启 → 重跑 doctor");
|
|
816
|
+
return { readiness: "blocked", blockers, warnings, nextSteps };
|
|
817
|
+
}
|
|
818
|
+
if (!probe.frida.serverRunning) {
|
|
819
|
+
blockers.push("Frida server 未运行");
|
|
820
|
+
nextSteps.push(
|
|
821
|
+
"见 docs/design/Adapter_WeChat_SQLCipher_Frida_Setup.md §2 启 frida-server",
|
|
822
|
+
);
|
|
823
|
+
return { readiness: "partial", blockers, warnings, nextSteps };
|
|
824
|
+
}
|
|
825
|
+
nextSteps.push(
|
|
826
|
+
"Frida path 就绪。register: `cc hub wechat register --uin <wxid>`(无需 --db / --wechat-data-path)",
|
|
827
|
+
);
|
|
828
|
+
nextSteps.push("WeChat 必须前台运行(已登录),register 期间不要切走");
|
|
829
|
+
return { readiness: "ready", blockers, warnings, nextSteps };
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
if (suggested === "unsupported") {
|
|
833
|
+
blockers.push("env-probe 判定为 unsupported");
|
|
834
|
+
for (const reason of probe.reasons || []) blockers.push(reason);
|
|
835
|
+
nextSteps.push(
|
|
836
|
+
"见 docs/design/Adapter_WeChat_SQLCipher.md §13 — 检查 WeChat 版本兼容矩阵",
|
|
837
|
+
);
|
|
838
|
+
return { readiness: "blocked", blockers, warnings, nextSteps };
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// Fallback — probe shape we don't recognize
|
|
842
|
+
warnings.push(
|
|
843
|
+
`未识别的 suggested='${suggested}' (version=${probe.wechat.versionName || "?"})`,
|
|
844
|
+
);
|
|
845
|
+
return { readiness: "partial", blockers, warnings, nextSteps };
|
|
846
|
+
}
|
|
847
|
+
|
|
634
848
|
async function cmdWechatUnregister(uin, options) {
|
|
635
849
|
try {
|
|
636
850
|
if (!uin) throw new Error("uin argument required");
|
|
@@ -644,8 +858,12 @@ async function cmdWechatUnregister(uin, options) {
|
|
|
644
858
|
logger.error(chalk.red(`✗ ${r.reason || "unregister failed"}`));
|
|
645
859
|
process.exit(1);
|
|
646
860
|
}
|
|
647
|
-
if (r.removed)
|
|
648
|
-
|
|
861
|
+
if (r.removed)
|
|
862
|
+
logger.log(chalk.green(`✓ removed wechat account (uin=${uin})`));
|
|
863
|
+
else
|
|
864
|
+
logger.log(
|
|
865
|
+
chalk.gray(`(uin=${uin} was not registered — nothing removed)`),
|
|
866
|
+
);
|
|
649
867
|
} catch (err) {
|
|
650
868
|
fail(null, err, options.json);
|
|
651
869
|
}
|
|
@@ -712,6 +930,10 @@ export function registerHubCommand(program) {
|
|
|
712
930
|
.option("--since <ms>", "Override watermark — sync from this unix-ms")
|
|
713
931
|
.option("--until <ms>", "Stop at this unix-ms")
|
|
714
932
|
.option("--limit <n>", "Cap ingested events")
|
|
933
|
+
.option(
|
|
934
|
+
"--input <path>",
|
|
935
|
+
"Path to a snapshot file produced by a UI layer (system-data-android, etc.)",
|
|
936
|
+
)
|
|
715
937
|
.option("--json", "Output JSON")
|
|
716
938
|
.action(cmdSyncAdapter);
|
|
717
939
|
|
|
@@ -833,7 +1055,9 @@ export function registerHubCommand(program) {
|
|
|
833
1055
|
|
|
834
1056
|
wechat
|
|
835
1057
|
.command("env-probe")
|
|
836
|
-
.description(
|
|
1058
|
+
.description(
|
|
1059
|
+
"Probe attached Android device for adb / root / frida-server / WeChat version",
|
|
1060
|
+
)
|
|
837
1061
|
.option("--json", "Output JSON")
|
|
838
1062
|
.action(cmdWechatEnvProbe);
|
|
839
1063
|
|
|
@@ -844,9 +1068,15 @@ export function registerHubCommand(program) {
|
|
|
844
1068
|
)
|
|
845
1069
|
.requiredOption("--uin <id>", "WeChat numeric UIN (≤ 8.0) or wxid (8.0+)")
|
|
846
1070
|
.option("--db <path>", "Local path to the already-pulled EnMicroMsg.db")
|
|
847
|
-
.option(
|
|
1071
|
+
.option(
|
|
1072
|
+
"--wechat-data-path <dir>",
|
|
1073
|
+
"Local pulled /data/data/com.tencent.mm/ tree (required for md5 path)",
|
|
1074
|
+
)
|
|
848
1075
|
.option("--force-provider <md5|frida>", "Override env-probe suggestion")
|
|
849
|
-
.option(
|
|
1076
|
+
.option(
|
|
1077
|
+
"--frida-device-id <id>",
|
|
1078
|
+
"Frida device id (defaults to first USB device)",
|
|
1079
|
+
)
|
|
850
1080
|
.option("--json", "Output JSON")
|
|
851
1081
|
.action(cmdWechatRegister);
|
|
852
1082
|
|
|
@@ -858,9 +1088,21 @@ export function registerHubCommand(program) {
|
|
|
858
1088
|
|
|
859
1089
|
wechat
|
|
860
1090
|
.command("unregister <uin>")
|
|
861
|
-
.description(
|
|
1091
|
+
.description(
|
|
1092
|
+
"Remove a registered WeChat account (does not touch vault data)",
|
|
1093
|
+
)
|
|
862
1094
|
.option("--json", "Output JSON")
|
|
863
1095
|
.action(cmdWechatUnregister);
|
|
1096
|
+
|
|
1097
|
+
// Phase 12.9 — diagnostic helper for real-device E2E. Combines env-probe
|
|
1098
|
+
// with actionable readiness checklist + inline §5.1 Frida trap reference.
|
|
1099
|
+
wechat
|
|
1100
|
+
.command("doctor")
|
|
1101
|
+
.description(
|
|
1102
|
+
"Diagnose WeChat setup — env-probe + readiness checklist + Phase 12.9 trap reference",
|
|
1103
|
+
)
|
|
1104
|
+
.option("--json", "Output JSON")
|
|
1105
|
+
.action(cmdWechatDoctor);
|
|
864
1106
|
}
|
|
865
1107
|
|
|
866
1108
|
// exported for tests — handler functions can be invoked directly with
|
|
@@ -877,5 +1119,7 @@ export const _internal = {
|
|
|
877
1119
|
cmdWechatRegister,
|
|
878
1120
|
cmdWechatList,
|
|
879
1121
|
cmdWechatUnregister,
|
|
1122
|
+
cmdWechatDoctor,
|
|
1123
|
+
interpretWechatProbe,
|
|
880
1124
|
_defaultKnownVendors,
|
|
881
1125
|
};
|