chainlesschain 0.162.12 → 0.162.13
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 +30 -25
- package/package.json +4 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-C3TDNq29.js → AIOps-Bq_zxhCr.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-C9fE18pE.js → ActionButton-CaevDm9t.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-wnZF602C.js → Analytics-B0gOmwPw.js} +1 -1
- package/src/assets/web-panel/assets/{AppLayout-BjgTMK7O.js → AppLayout-DWhZiV0Q.js} +2 -2
- package/src/assets/web-panel/assets/{Audit-BBL0BW5_.js → Audit-ZuZJBCxo.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BKLqYCWU.js → Backup-CX7jhH5l.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BGSzMCZs.js → BaseInput-CVLx7HVq.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CQWzZWEY.js → Chat-C6yL5tRD.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BkTri12Q.js → Checkbox-BePhbqVq.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BH1m09EO.js → Codegen-B5E4x1Lm.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BXnBuqIa.js → Col-CWhNU6A7.js} +1 -1
- package/src/assets/web-panel/assets/{Community-C_Nr4XCx.js → Community-mSEAuJhp.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Du6GwLrj.js → Compact-DSudHzX3.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-66M0oi1Q.js → Compliance-CxJLYjyn.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DQrkZRNd.js → Cowork-C-trppQj.js} +1 -1
- package/src/assets/web-panel/assets/{Cron-CwdIFH_v.js → Cron-_Ij4v5fY.js} +1 -1
- package/src/assets/web-panel/assets/{Crosschain-DqlcrQ9L.js → Crosschain-eLHXzp5T.js} +1 -1
- package/src/assets/web-panel/assets/{DID-OmPLKf7L.js → DID-BP04AUUB.js} +1 -1
- package/src/assets/web-panel/assets/{Dashboard-D_dampTL.js → Dashboard-CzEeQv62.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CA1W7jAn.js → Dropdown-C_SGOB22.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-Chlk9a7s.js → Federation-BgaP4BOv.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-t0UqYFLq.js → FormItemContext-BxGLLt9r.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CEq0raYm.js → Git-Bt_uM_Gw.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-C06CX7Ge.js → Governance-N2-0RG_o.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-6VIFHxIP.js → Inference-eS3g-CzP.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BCJPjMBQ.js → KnowledgeGraph-CUuvNVah.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BBpOYFct.js → Logs-wPbwEt2r.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-BFH6jMWt.js → Marketplace-DH91kTwo.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-uCFvRqGs.js → McpTools-D-GyyBrI.js} +1 -1
- package/src/assets/web-panel/assets/{Memory-B0Kux_KT.js → Memory-BOtUy-tw.js} +1 -1
- package/src/assets/web-panel/assets/{MobileBridge-DHow2jiK.js → MobileBridge-DIP__XQd.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BFo9YQZp.js → MobileProjects-1nqr1UsU.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-riOh1G_F.js → Mtc-CCE0x7h2.js} +1 -1
- package/src/assets/web-panel/assets/{MtcAudit-Bm-hE2SP.js → MtcAudit-BBkz0XUO.js} +1 -1
- package/src/assets/web-panel/assets/{Multisig-DfUQxh5a.js → Multisig-CIKSJvTY.js} +2 -2
- package/src/assets/web-panel/assets/{NLProgramming-DuNvLBEq.js → NLProgramming-BDkgeFcq.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DB20wd3c.js → Notes-ONiUxfN1.js} +1 -1
- package/src/assets/web-panel/assets/{NotificationSettings-CB-GkOWR.js → NotificationSettings-CGcyKEIe.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-3bU7PZuG.js → Organization-BZtMYBJt.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BGCPP_0Y.js → Overflow-C4LfFZAI.js} +1 -1
- package/src/assets/web-panel/assets/{OverrideContext-x9ZzjLwk.js → OverrideContext-C_4H9tGA.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BHgAe1oC.js → P2P-D71Cpk-m.js} +1 -1
- package/src/assets/web-panel/assets/{Permissions-BuOD4xwc.js → Permissions-DRGYF29v.js} +1 -1
- package/src/assets/web-panel/assets/PersonalDataHub-CfRYoIua.js +1 -0
- package/src/assets/web-panel/assets/PersonalDataHub-Dvaa8niQ.css +1 -0
- package/src/assets/web-panel/assets/{Pipeline-DBS5U4LB.js → Pipeline-BOyp0_Qo.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-UNjIc5El.js → Privacy-a_AcphvF.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CicqCJGy.js → ProjectInit-CFu1grYt.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectSettings-CIxAbt4Y.js → ProjectSettings-p54Eivhh.js} +1 -1
- package/src/assets/web-panel/assets/{Projects-BJycZScO.js → Projects-DkB88XAu.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DxXvprme.js → Providers-EK7f8DEd.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-rrqjU8_Y.js → QuickAsk-CpO0w3iP.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BEwHMhI7.js → Recommend-BUJVQdv9.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-DoVKCCMn.js → Reputation-kU2fOuZt.js} +1 -1
- package/src/assets/web-panel/assets/{Row-F5XcDhHr.js → Row-oGWRbk6g.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-cZrRG7k8.js → RssFeed-saC_46Yo.js} +1 -1
- package/src/assets/web-panel/assets/{Search-B9ctZjqx.js → Search-CjtRqFUu.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Z62hl1mc.js → Security-BX0NBVfQ.js} +1 -1
- package/src/assets/web-panel/assets/{Services-CQf5XqgZ.js → Services-Bgxsnei_.js} +1 -1
- package/src/assets/web-panel/assets/{Skeleton-DuCKw2Eh.js → Skeleton-CwBb3k2a.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-qVkhva0s.js → Skills-CZCMYH6Z.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BQbatr7s.js → Sla-Djy1uHnZ.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DLFBzAgD.js → SpeechSettings-CGUI_Uyh.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CrzETZMW.js → SyncSettings-DK2CKHRD.js} +1 -1
- package/src/assets/web-panel/assets/{Tasks-D_EQ1nJ7.js → Tasks-BKiOzeIO.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-D4y-dGRc.js → Templates-CnQpleXj.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-2XI0jkPn.js → Tenant-DwKz0cjm.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-fUi5V2Z9.js → Terminal-A7t_wsR8.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BuUNB2mg.js → Tokens-BqYY9l44.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-7DqLLuej.js → Trigger-BI4bXFmi.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CeACvTYx.js → Trust-yMynKTRG.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-mDP9EXHq.js → UkeySign-Br4IScM6.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-veWlKclv.js → VideoEditing-CWcThGsP.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Cd2Hheb8.js → Wallet-CZcAtjxj.js} +1 -1
- package/src/assets/web-panel/assets/{WebAuthn-DyL7ZiHX.js → WebAuthn-BnTZFMA0.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-C7-7LJH9.js → WorkflowEditor-N7gGz3_n.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DXomZMuo.js → chat-D175ZIO0.js} +1 -1
- package/src/assets/web-panel/assets/{collapseMotion-CjFH_Jop.js → collapseMotion-DfnRZex1.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DlU92QNs.js → colors-LKhZyttv.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-sBiTL8mX.js → compact-item-CsJSebxT.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DZXEnzum.js → createContext-BJ_CPYFC.js} +1 -1
- package/src/assets/web-panel/assets/{echarts-Bq-n0MtJ.js → echarts-Dj_pBaVI.js} +1 -1
- package/src/assets/web-panel/assets/{hasIn-CpCHBZ2M.js → hasIn-CzD3IqH8.js} +1 -1
- package/src/assets/web-panel/assets/{icons-CLQTHa5-.js → icons-BOPtEWK4.js} +4 -4
- package/src/assets/web-panel/assets/{index-ClN_JuFa.js → index-6qPbrYF7.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDyzZ8_O.js → index-B7UYymse.js} +1 -1
- package/src/assets/web-panel/assets/{index-C52udT0_.js → index-BDSZDDb2.js} +4 -4
- package/src/assets/web-panel/assets/{index-s8tvk-fF.js → index-BEDFHKO3.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_IgY63-.js → index-BMvdoiFr.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dyg6ikIL.js → index-BNVLVzN5.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0Qbxr57.js → index-BSNibAqz.js} +1 -1
- package/src/assets/web-panel/assets/{index-DeGnHcp5.js → index-BV-__mlC.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_-RETt0.js → index-BXH9ujMW.js} +1 -1
- package/src/assets/web-panel/assets/{index-XI6772AD.js → index-BZluCuTH.js} +1 -1
- package/src/assets/web-panel/assets/{index-BqnhEJls.js → index-BhiZDGg7.js} +1 -1
- package/src/assets/web-panel/assets/{index-BK2AFy44.js → index-BjOrt4vw.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dn8m1d1f.js → index-BmJdof_c.js} +2 -2
- package/src/assets/web-panel/assets/{index-C6SDf50u.js → index-BsirlkJ0.js} +1 -1
- package/src/assets/web-panel/assets/{index-CD3iljXs.js → index-BvF2tC6C.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJ7XYa5K.js → index-C2HBKw07.js} +1 -1
- package/src/assets/web-panel/assets/{index-_zyXBoS7.js → index-CKjBAdm0.js} +1 -1
- package/src/assets/web-panel/assets/{index-X48zYgZ6.js → index-CRGNuUIM.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dj9Nvz6S.js → index-CTIkCKav.js} +1 -1
- package/src/assets/web-panel/assets/index-CY1mQA2I.js +1 -0
- package/src/assets/web-panel/assets/{index-C59FgSkU.js → index-CyHdYUeZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-B23tuoo9.js → index-D401L3yx.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKe9jmKG.js → index-D5IZCkZG.js} +1 -1
- package/src/assets/web-panel/assets/{index-F9cBucYf.js → index-D7ZcBI5s.js} +1 -1
- package/src/assets/web-panel/assets/{index-CjXSvceY.js → index-D8kltMTW.js} +1 -1
- package/src/assets/web-panel/assets/index-D9nXHfUB.js +1 -0
- package/src/assets/web-panel/assets/{index-Dq5Rn5VS.js → index-DJVkBmSc.js} +1 -1
- package/src/assets/web-panel/assets/{index-ibFHnqHz.js → index-DM3uBEWD.js} +1 -1
- package/src/assets/web-panel/assets/{index-ChahjdYE.js → index-DOO73rHE.js} +1 -1
- package/src/assets/web-panel/assets/{index-CivbS-57.js → index-DXp1jVsK.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3k9UPHc.js → index-Dd7dICwB.js} +1 -1
- package/src/assets/web-panel/assets/{index-Di1_EQ-X.js → index-Dm-3kvtD.js} +1 -1
- package/src/assets/web-panel/assets/{index-DygNvCeR.js → index-DnPt5OdD.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_MzScPM.js → index-E7t1hAnk.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUe5t5Aa.js → index-JTX9A7w0.js} +1 -1
- package/src/assets/web-panel/assets/{index-CwbWZubA.js → index-Kn-Of5ew.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUlPMzoM.js → index-R1cFADfk.js} +1 -1
- package/src/assets/web-panel/assets/{index-TwQZkVGh.js → index-RIO4JKMP.js} +1 -1
- package/src/assets/web-panel/assets/{index-ThrAiEF9.js → index-uTEVWPYA.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DEi92ZnZ.js → initDefaultProps-CBW0okek.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BtYKzpOc.js → motion-DGAffQ0Z.js} +1 -1
- package/src/assets/web-panel/assets/{move-Cb3A1-v-.js → move-DFJ0-5IW.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B6qPDdOf.js → omit-AvrDghg1.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DDyeQMUc.js → pickAttrs-D7csw9i1.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BPV6VO47.js → placementArrow-hZ6Lg6kG.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DJ1ra4dT.js → responsiveObserve-DLLx5VvS.js} +1 -1
- package/src/assets/web-panel/assets/{slide-D6v8tHvB.js → slide-BaRIT3ev.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DulKcQLZ.js → statusUtils-Cdjyuhrz.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Bne7zwMt.js → styleChecker-CbrNybTt.js} +1 -1
- package/src/assets/web-panel/assets/useFlexGapSupport-B8gAhiRC.js +1 -0
- package/src/assets/web-panel/assets/{useFs-CR-iLa4Z.js → useFs-BZPy4ICP.js} +1 -1
- package/src/assets/web-panel/assets/{useMergedState-O7QXt4P5.js → useMergedState-WwedrFR0.js} +1 -1
- package/src/assets/web-panel/assets/{useRefs-0J6m8UWN.js → useRefs-Cdq8EWeF.js} +1 -1
- package/src/assets/web-panel/assets/{useState-CSzR8F8O.js → useState-DGS1NOyn.js} +1 -1
- package/src/assets/web-panel/assets/{vendor-M5lGV-wr.js → vendor-DhFY8mDK.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-yL9axxBy.js → vnode-6Y0NDMVv.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-B-VCMXSD.js → zoom-DTbMGsSH.js} +1 -1
- package/src/assets/web-panel/index.html +3 -3
- package/src/commands/__tests__/hub-aichat.test.js +277 -0
- package/src/commands/__tests__/hub-wechat.test.js +243 -0
- package/src/commands/hub.js +417 -0
- package/src/commands/sync-providers.js +436 -0
- package/src/gateways/ws/personal-data-hub-protocol.js +68 -0
- package/src/index.js +4 -0
- package/src/lib/__tests__/personal-data-hub-aichat-wizard.test.js +209 -0
- package/src/lib/__tests__/sync-credentials.test.js +265 -0
- package/src/lib/__tests__/sync-engine-cli.test.js +293 -0
- package/src/lib/personal-data-hub-aichat-wizard.js +242 -0
- package/src/lib/personal-data-hub-wiring.js +189 -0
- package/src/lib/sync-cli-db.js +194 -0
- package/src/lib/sync-credentials.js +225 -0
- package/src/lib/sync-engine-cli.js +406 -0
- package/src/lib/sync-oss-client.js +273 -0
- package/src/lib/sync-webdav-client.js +194 -0
- package/src/assets/web-panel/assets/PersonalDataHub--WA-aZAJ.js +0 -1
- package/src/assets/web-panel/assets/PersonalDataHub-BK7I0Rsb.css +0 -1
- package/src/assets/web-panel/assets/index-CcRX6BlT.js +0 -1
- package/src/assets/web-panel/assets/index-z6h6tqP3.js +0 -1
- package/src/assets/web-panel/assets/useFlexGapSupport-C1miTomM.js +0 -1
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cc sync webdav / cc sync oss subcommand groups — Phase 3c follow-up.
|
|
3
|
+
*
|
|
4
|
+
* v0.1 (Phase 1):configure / status / clear — 凭据落 ~/.chainlesschain/
|
|
5
|
+
* sync-credentials.enc (AES-256-GCM),与 desktop secure-config 同 shape。
|
|
6
|
+
*
|
|
7
|
+
* v0.2 (Phase 2):test (real connectivity probe) + run (本机 vault 同步)
|
|
8
|
+
* — 需 @aws-sdk/client-s3 + webdav npm dep + better-sqlite3 vault wiring,
|
|
9
|
+
* 工程更大;本 commit 不含。
|
|
10
|
+
*
|
|
11
|
+
* 命令树:
|
|
12
|
+
* cc sync webdav configure --url ... --username ... --password ... [--remote-path]
|
|
13
|
+
* cc sync webdav status 显示 mask 后凭据 + configured 标记
|
|
14
|
+
* cc sync webdav clear 擦除凭据 + 在 vault 内移除该 provider
|
|
15
|
+
* cc sync oss configure --endpoint --region --bucket --access-key-id
|
|
16
|
+
* --secret-access-key [--remote-path] [--force-path-style]
|
|
17
|
+
* cc sync oss status
|
|
18
|
+
* cc sync oss clear
|
|
19
|
+
*
|
|
20
|
+
* password / secretAccessKey 走 stdin 提示也支持(避免 shell history 留痕)—
|
|
21
|
+
* 留 v0.2 加 prompts;v0.1 仅 flag。
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
"use strict";
|
|
25
|
+
|
|
26
|
+
import chalk from "chalk";
|
|
27
|
+
import {
|
|
28
|
+
ALLOWED_PROVIDER_IDS,
|
|
29
|
+
getCredentials,
|
|
30
|
+
getCredentialsSanitized,
|
|
31
|
+
hasCredentials,
|
|
32
|
+
setCredentials,
|
|
33
|
+
clearCredentials,
|
|
34
|
+
} from "../lib/sync-credentials.js";
|
|
35
|
+
import { WebDAVClient } from "../lib/sync-webdav-client.js";
|
|
36
|
+
import { OSSClient } from "../lib/sync-oss-client.js";
|
|
37
|
+
import { runSync } from "../lib/sync-engine-cli.js";
|
|
38
|
+
import { openCliVault } from "../lib/sync-cli-db.js";
|
|
39
|
+
|
|
40
|
+
function _ensureValidProvider(name) {
|
|
41
|
+
if (!ALLOWED_PROVIDER_IDS.includes(name)) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
`Unknown sync provider '${name}' (allowed: ${ALLOWED_PROVIDER_IDS.join(", ")})`,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function _printStatus(providerId) {
|
|
49
|
+
_ensureValidProvider(providerId);
|
|
50
|
+
const masked = getCredentialsSanitized(providerId);
|
|
51
|
+
const configured = hasCredentials(providerId);
|
|
52
|
+
console.log(
|
|
53
|
+
JSON.stringify(
|
|
54
|
+
{
|
|
55
|
+
provider: providerId,
|
|
56
|
+
configured,
|
|
57
|
+
credentials: masked,
|
|
58
|
+
notes: configured
|
|
59
|
+
? [
|
|
60
|
+
"secrets are masked; raw values stored encrypted at ~/.chainlesschain/sync-credentials.enc",
|
|
61
|
+
]
|
|
62
|
+
: ["not configured; run `cc sync <provider> configure --<flags>`"],
|
|
63
|
+
},
|
|
64
|
+
null,
|
|
65
|
+
2,
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function _configureWebDAV(opts) {
|
|
71
|
+
const url = (opts.url || "").trim();
|
|
72
|
+
if (!url) throw new Error("--url required");
|
|
73
|
+
const username = (opts.username || "").trim();
|
|
74
|
+
const password = opts.password;
|
|
75
|
+
if (!password)
|
|
76
|
+
throw new Error("--password required (use stdin or env in v0.2)");
|
|
77
|
+
const remotePath = (opts.remotePath || "/").trim();
|
|
78
|
+
setCredentials("webdav", { url, username, password, remotePath });
|
|
79
|
+
console.log(chalk.green("✓ WebDAV credentials saved"));
|
|
80
|
+
console.log(chalk.dim(` url: ${url}`));
|
|
81
|
+
console.log(chalk.dim(` username: ${username}`));
|
|
82
|
+
console.log(chalk.dim(` password: ********`));
|
|
83
|
+
console.log(chalk.dim(` remotePath: ${remotePath}`));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function _configureOSS(opts) {
|
|
87
|
+
const endpoint = (opts.endpoint || "").trim();
|
|
88
|
+
if (!endpoint) throw new Error("--endpoint required");
|
|
89
|
+
const bucket = (opts.bucket || "").trim();
|
|
90
|
+
if (!bucket) throw new Error("--bucket required");
|
|
91
|
+
const accessKeyId = (opts.accessKeyId || "").trim();
|
|
92
|
+
if (!accessKeyId) throw new Error("--access-key-id required");
|
|
93
|
+
const secretAccessKey = opts.secretAccessKey;
|
|
94
|
+
if (!secretAccessKey) {
|
|
95
|
+
throw new Error("--secret-access-key required (use stdin or env in v0.2)");
|
|
96
|
+
}
|
|
97
|
+
const region = (opts.region || "auto").trim();
|
|
98
|
+
const remotePath = (opts.remotePath || "").trim();
|
|
99
|
+
const forcePathStyle = opts.forcePathStyle === true;
|
|
100
|
+
setCredentials("oss", {
|
|
101
|
+
endpoint,
|
|
102
|
+
region,
|
|
103
|
+
bucket,
|
|
104
|
+
accessKeyId,
|
|
105
|
+
secretAccessKey,
|
|
106
|
+
remotePath,
|
|
107
|
+
forcePathStyle,
|
|
108
|
+
});
|
|
109
|
+
console.log(chalk.green("✓ OSS / S3 credentials saved"));
|
|
110
|
+
console.log(chalk.dim(` endpoint: ${endpoint}`));
|
|
111
|
+
console.log(chalk.dim(` region: ${region}`));
|
|
112
|
+
console.log(chalk.dim(` bucket: ${bucket}`));
|
|
113
|
+
console.log(chalk.dim(` accessKeyId: ${accessKeyId}`));
|
|
114
|
+
console.log(chalk.dim(` secretAccessKey: ********`));
|
|
115
|
+
console.log(chalk.dim(` remotePath: ${remotePath}`));
|
|
116
|
+
console.log(chalk.dim(` forcePathStyle: ${forcePathStyle}`));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function _clearProvider(providerId) {
|
|
120
|
+
_ensureValidProvider(providerId);
|
|
121
|
+
if (!hasCredentials(providerId)) {
|
|
122
|
+
console.log(chalk.dim(`(${providerId} was already empty)`));
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
clearCredentials(providerId);
|
|
126
|
+
console.log(chalk.green(`✓ ${providerId} credentials cleared`));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function _loadWebDAVCreds() {
|
|
130
|
+
const c = getCredentials("webdav");
|
|
131
|
+
if (!c.url || !c.password) return null;
|
|
132
|
+
return {
|
|
133
|
+
url: c.url,
|
|
134
|
+
username: c.username || "",
|
|
135
|
+
password: c.password,
|
|
136
|
+
remotePath: c.remotePath || "/",
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function _loadOSSCreds() {
|
|
141
|
+
const c = getCredentials("oss");
|
|
142
|
+
if (!c.endpoint || !c.bucket || !c.accessKeyId || !c.secretAccessKey)
|
|
143
|
+
return null;
|
|
144
|
+
return {
|
|
145
|
+
endpoint: c.endpoint,
|
|
146
|
+
region: c.region || "auto",
|
|
147
|
+
bucket: c.bucket,
|
|
148
|
+
accessKeyId: c.accessKeyId,
|
|
149
|
+
secretAccessKey: c.secretAccessKey,
|
|
150
|
+
remotePath: c.remotePath || "",
|
|
151
|
+
forcePathStyle: c.forcePathStyle === true,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function _testProvider(providerId) {
|
|
156
|
+
_ensureValidProvider(providerId);
|
|
157
|
+
const creds = providerId === "webdav" ? _loadWebDAVCreds() : _loadOSSCreds();
|
|
158
|
+
if (!creds) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
`${providerId} 凭据未配置,先跑 \`cc sync ${providerId} configure --...\``,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
const client =
|
|
164
|
+
providerId === "webdav" ? new WebDAVClient(creds) : new OSSClient(creds);
|
|
165
|
+
const res = await client.testConnection();
|
|
166
|
+
if (res.ok) {
|
|
167
|
+
console.log(chalk.green(`✓ ${providerId} 连接 OK`));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
console.error(
|
|
171
|
+
chalk.red(
|
|
172
|
+
`✗ ${providerId} 连接失败 (${res.status || "n/a"}): ${res.error}`,
|
|
173
|
+
),
|
|
174
|
+
);
|
|
175
|
+
process.exitCode = 2;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function _runProvider(providerId, opts = {}) {
|
|
179
|
+
_ensureValidProvider(providerId);
|
|
180
|
+
const creds = providerId === "webdav" ? _loadWebDAVCreds() : _loadOSSCreds();
|
|
181
|
+
if (!creds) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`${providerId} 凭据未配置,先跑 \`cc sync ${providerId} configure --...\``,
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let vault;
|
|
188
|
+
try {
|
|
189
|
+
vault = await openCliVault();
|
|
190
|
+
} catch (err) {
|
|
191
|
+
if (err.code === "BETTER_SQLITE3_MISSING") {
|
|
192
|
+
console.error(chalk.red(`✗ ${err.message}`));
|
|
193
|
+
process.exitCode = 2;
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
throw err;
|
|
197
|
+
}
|
|
198
|
+
const { dbManager, vaultPath } = vault;
|
|
199
|
+
if (opts.verbose) console.log(chalk.dim(`vault: ${vaultPath}`));
|
|
200
|
+
|
|
201
|
+
const client =
|
|
202
|
+
providerId === "webdav" ? new WebDAVClient(creds) : new OSSClient(creds);
|
|
203
|
+
let lastPrint = 0;
|
|
204
|
+
const onProgress = (e) => {
|
|
205
|
+
// Throttle stdout to avoid TTY thrash (engine already 5/500ms)
|
|
206
|
+
const now = Date.now();
|
|
207
|
+
if (
|
|
208
|
+
e.phase === "start" ||
|
|
209
|
+
["success", "conflict", "failed"].includes(e.phase) ||
|
|
210
|
+
now - lastPrint >= 1000
|
|
211
|
+
) {
|
|
212
|
+
lastPrint = now;
|
|
213
|
+
const parts = [`[${e.phase}]`];
|
|
214
|
+
if (e.totalPending != null) parts.push(`total=${e.totalPending}`);
|
|
215
|
+
parts.push(
|
|
216
|
+
`pushed=${e.pushed}`,
|
|
217
|
+
`skipped=${e.skipped}`,
|
|
218
|
+
`deleted=${e.deleted}`,
|
|
219
|
+
);
|
|
220
|
+
console.log(chalk.dim(parts.join(" ")));
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
const result = await runSync({
|
|
226
|
+
dbManager,
|
|
227
|
+
client,
|
|
228
|
+
providerId,
|
|
229
|
+
accountKey: "",
|
|
230
|
+
onProgress,
|
|
231
|
+
});
|
|
232
|
+
if (result.success) {
|
|
233
|
+
console.log(
|
|
234
|
+
chalk.green(`✓ ${providerId} sync done (${result.status})`) +
|
|
235
|
+
` — pushed=${result.pushed} skipped=${result.skipped} deleted=${result.deleted} duration=${result.durationMs}ms`,
|
|
236
|
+
);
|
|
237
|
+
} else {
|
|
238
|
+
console.error(
|
|
239
|
+
chalk.red(`✗ ${providerId} sync failed`) +
|
|
240
|
+
` — pushed=${result.pushed} skipped=${result.skipped} deleted=${result.deleted}`,
|
|
241
|
+
);
|
|
242
|
+
if (result.error) console.error(chalk.red(` error: ${result.error}`));
|
|
243
|
+
process.exitCode = 2;
|
|
244
|
+
}
|
|
245
|
+
} finally {
|
|
246
|
+
try {
|
|
247
|
+
dbManager.close();
|
|
248
|
+
} catch (_e) {
|
|
249
|
+
/* cleanup */
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Attach `cc sync webdav *` and `cc sync oss *` subcommands to the existing
|
|
256
|
+
* `cc sync` parent command. Caller passes the program; we find the sync
|
|
257
|
+
* parent and add children.
|
|
258
|
+
*/
|
|
259
|
+
export function registerSyncProviderCommands(program) {
|
|
260
|
+
const parent = program.commands.find((c) => c.name() === "sync");
|
|
261
|
+
if (!parent) {
|
|
262
|
+
throw new Error(
|
|
263
|
+
"registerSyncProviderCommands: parent `sync` command not registered yet — call after registerSyncCommand",
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// ── webdav subgroup ────────────────────────────────────────────
|
|
268
|
+
const webdav = parent
|
|
269
|
+
.command("webdav")
|
|
270
|
+
.description(
|
|
271
|
+
"WebDAV (Nextcloud / 坚果云 / 群晖) sync provider — credential management",
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
webdav
|
|
275
|
+
.command("configure")
|
|
276
|
+
.description(
|
|
277
|
+
"Save WebDAV credentials to ~/.chainlesschain/sync-credentials.enc",
|
|
278
|
+
)
|
|
279
|
+
.requiredOption("--url <url>", "WebDAV endpoint URL")
|
|
280
|
+
.option("--username <name>", "WebDAV username", "")
|
|
281
|
+
.requiredOption(
|
|
282
|
+
"--password <pw>",
|
|
283
|
+
"WebDAV password (use stdin in v0.2 — for now this WILL hit shell history)",
|
|
284
|
+
)
|
|
285
|
+
.option("--remote-path <p>", "remote directory path", "/")
|
|
286
|
+
.action(async (opts) => {
|
|
287
|
+
try {
|
|
288
|
+
_configureWebDAV(opts);
|
|
289
|
+
} catch (err) {
|
|
290
|
+
console.error(chalk.red(`✗ ${err?.message || err}`));
|
|
291
|
+
process.exitCode = 2;
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
webdav
|
|
296
|
+
.command("status")
|
|
297
|
+
.description("Show sanitized WebDAV credentials + configured flag")
|
|
298
|
+
.action(() => {
|
|
299
|
+
try {
|
|
300
|
+
_printStatus("webdav");
|
|
301
|
+
} catch (err) {
|
|
302
|
+
console.error(chalk.red(`✗ ${err?.message || err}`));
|
|
303
|
+
process.exitCode = 2;
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
webdav
|
|
308
|
+
.command("clear")
|
|
309
|
+
.description("Remove WebDAV credentials from vault")
|
|
310
|
+
.action(() => {
|
|
311
|
+
try {
|
|
312
|
+
_clearProvider("webdav");
|
|
313
|
+
} catch (err) {
|
|
314
|
+
console.error(chalk.red(`✗ ${err?.message || err}`));
|
|
315
|
+
process.exitCode = 2;
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
webdav
|
|
320
|
+
.command("test")
|
|
321
|
+
.description("Probe WebDAV connectivity (PROPFIND on remotePath)")
|
|
322
|
+
.action(async () => {
|
|
323
|
+
try {
|
|
324
|
+
await _testProvider("webdav");
|
|
325
|
+
} catch (err) {
|
|
326
|
+
console.error(chalk.red(`✗ ${err?.message || err}`));
|
|
327
|
+
process.exitCode = 2;
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
webdav
|
|
332
|
+
.command("run")
|
|
333
|
+
.description(
|
|
334
|
+
"Run one full WebDAV sync against ~/.chainlesschain/cli-vault.db",
|
|
335
|
+
)
|
|
336
|
+
.option("-v, --verbose", "show vault path + verbose progress", false)
|
|
337
|
+
.action(async (opts) => {
|
|
338
|
+
try {
|
|
339
|
+
await _runProvider("webdav", opts);
|
|
340
|
+
} catch (err) {
|
|
341
|
+
console.error(chalk.red(`✗ ${err?.message || err}`));
|
|
342
|
+
process.exitCode = 2;
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// ── oss subgroup ───────────────────────────────────────────────
|
|
347
|
+
const oss = parent
|
|
348
|
+
.command("oss")
|
|
349
|
+
.description(
|
|
350
|
+
"S3 / OSS (AWS / 阿里云 / R2 / B2) sync provider — credential management",
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
oss
|
|
354
|
+
.command("configure")
|
|
355
|
+
.description(
|
|
356
|
+
"Save OSS credentials to ~/.chainlesschain/sync-credentials.enc",
|
|
357
|
+
)
|
|
358
|
+
.requiredOption(
|
|
359
|
+
"--endpoint <url>",
|
|
360
|
+
"S3-compat endpoint URL (e.g. https://oss-cn-hangzhou.aliyuncs.com)",
|
|
361
|
+
)
|
|
362
|
+
.option(
|
|
363
|
+
"--region <r>",
|
|
364
|
+
"region (default: auto for R2 / explicit for AWS+aliyun)",
|
|
365
|
+
"auto",
|
|
366
|
+
)
|
|
367
|
+
.requiredOption("--bucket <name>", "target bucket name")
|
|
368
|
+
.requiredOption("--access-key-id <id>", "access key id")
|
|
369
|
+
.requiredOption(
|
|
370
|
+
"--secret-access-key <secret>",
|
|
371
|
+
"secret access key (use stdin in v0.2 — hits shell history now)",
|
|
372
|
+
)
|
|
373
|
+
.option("--remote-path <p>", "object key prefix", "")
|
|
374
|
+
.option(
|
|
375
|
+
"--force-path-style",
|
|
376
|
+
"use path-style URLs (R2 / MinIO need true)",
|
|
377
|
+
false,
|
|
378
|
+
)
|
|
379
|
+
.action(async (opts) => {
|
|
380
|
+
try {
|
|
381
|
+
_configureOSS(opts);
|
|
382
|
+
} catch (err) {
|
|
383
|
+
console.error(chalk.red(`✗ ${err?.message || err}`));
|
|
384
|
+
process.exitCode = 2;
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
oss
|
|
389
|
+
.command("status")
|
|
390
|
+
.description("Show sanitized OSS credentials + configured flag")
|
|
391
|
+
.action(() => {
|
|
392
|
+
try {
|
|
393
|
+
_printStatus("oss");
|
|
394
|
+
} catch (err) {
|
|
395
|
+
console.error(chalk.red(`✗ ${err?.message || err}`));
|
|
396
|
+
process.exitCode = 2;
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
oss
|
|
401
|
+
.command("clear")
|
|
402
|
+
.description("Remove OSS credentials from vault")
|
|
403
|
+
.action(() => {
|
|
404
|
+
try {
|
|
405
|
+
_clearProvider("oss");
|
|
406
|
+
} catch (err) {
|
|
407
|
+
console.error(chalk.red(`✗ ${err?.message || err}`));
|
|
408
|
+
process.exitCode = 2;
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
oss
|
|
413
|
+
.command("test")
|
|
414
|
+
.description("Probe S3 / OSS connectivity (HeadBucket)")
|
|
415
|
+
.action(async () => {
|
|
416
|
+
try {
|
|
417
|
+
await _testProvider("oss");
|
|
418
|
+
} catch (err) {
|
|
419
|
+
console.error(chalk.red(`✗ ${err?.message || err}`));
|
|
420
|
+
process.exitCode = 2;
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
oss
|
|
425
|
+
.command("run")
|
|
426
|
+
.description("Run one full OSS sync against ~/.chainlesschain/cli-vault.db")
|
|
427
|
+
.option("-v, --verbose", "show vault path + verbose progress", false)
|
|
428
|
+
.action(async (opts) => {
|
|
429
|
+
try {
|
|
430
|
+
await _runProvider("oss", opts);
|
|
431
|
+
} catch (err) {
|
|
432
|
+
console.error(chalk.red(`✗ ${err?.message || err}`));
|
|
433
|
+
process.exitCode = 2;
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
}
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
getHub,
|
|
22
22
|
close as closeHub,
|
|
23
23
|
} from "../../lib/personal-data-hub-wiring.js";
|
|
24
|
+
import { getAIChatWizard } from "../../lib/personal-data-hub-aichat-wizard.js";
|
|
24
25
|
import { existsSync, unlinkSync, readdirSync } from "node:fs";
|
|
25
26
|
import { join } from "node:path";
|
|
26
27
|
|
|
@@ -212,6 +213,28 @@ export const PERSONAL_DATA_HUB_HANDLERS = {
|
|
|
212
213
|
}),
|
|
213
214
|
),
|
|
214
215
|
|
|
216
|
+
// ─── Phase 12.6.8 — WeChat env-probe + register / unregister / list ──
|
|
217
|
+
|
|
218
|
+
"personal-data-hub.wechat-env-probe": async () =>
|
|
219
|
+
withHub(async (hub) => await hub.probeWechatEnv()),
|
|
220
|
+
|
|
221
|
+
"personal-data-hub.register-wechat": async (msg) =>
|
|
222
|
+
withHub(async (hub) =>
|
|
223
|
+
await hub.registerWechatAdapter({
|
|
224
|
+
account: msg.account,
|
|
225
|
+
dbPath: msg.dbPath,
|
|
226
|
+
wechatDataPath: msg.wechatDataPath,
|
|
227
|
+
fridaOpts: msg.fridaOpts,
|
|
228
|
+
keyProviderOverride: msg.keyProviderOverride,
|
|
229
|
+
}),
|
|
230
|
+
),
|
|
231
|
+
|
|
232
|
+
"personal-data-hub.unregister-wechat": async (msg) =>
|
|
233
|
+
withHub(async (hub) => await hub.unregisterWechatAdapter(msg.uin)),
|
|
234
|
+
|
|
235
|
+
"personal-data-hub.list-wechat-accounts": async () =>
|
|
236
|
+
withHub((hub) => hub.listWechatAccounts()),
|
|
237
|
+
|
|
215
238
|
// ─── Phase 8 — EntityResolver review / merge / unmerge ───────────────
|
|
216
239
|
|
|
217
240
|
"personal-data-hub.review-queue-list": async (msg) =>
|
|
@@ -264,6 +287,51 @@ export const PERSONAL_DATA_HUB_HANDLERS = {
|
|
|
264
287
|
|
|
265
288
|
"personal-data-hub.run-skill": async (msg) =>
|
|
266
289
|
withHub(async (hub) => await hub.runSkill(msg.name, msg.options || {})),
|
|
290
|
+
|
|
291
|
+
// ─── Phase 10.3 — AIChat WebView 鉴权向导 (paste-mode on cc ui) ────────
|
|
292
|
+
|
|
293
|
+
"personal-data-hub.aichat-open-login": async (msg) =>
|
|
294
|
+
withHub(async (hub) => {
|
|
295
|
+
const wiz = getAIChatWizard({ hubDir: hub.hubDir });
|
|
296
|
+
return await wiz.openVendorLogin({
|
|
297
|
+
vendor: msg.vendor,
|
|
298
|
+
opts: msg.opts || {},
|
|
299
|
+
});
|
|
300
|
+
}),
|
|
301
|
+
|
|
302
|
+
"personal-data-hub.aichat-probe-cookies": async (msg) =>
|
|
303
|
+
withHub(async (hub) => {
|
|
304
|
+
const wiz = getAIChatWizard({ hubDir: hub.hubDir });
|
|
305
|
+
return await wiz.probeCookies({
|
|
306
|
+
vendor: msg.vendor,
|
|
307
|
+
cookieHeader: msg.cookieHeader,
|
|
308
|
+
});
|
|
309
|
+
}),
|
|
310
|
+
|
|
311
|
+
"personal-data-hub.aichat-register-vendor": async (msg) =>
|
|
312
|
+
withHub(async (hub) => {
|
|
313
|
+
const wiz = getAIChatWizard({ hubDir: hub.hubDir });
|
|
314
|
+
return await wiz.registerVendor({
|
|
315
|
+
vendor: msg.vendor,
|
|
316
|
+
cookies: msg.cookies,
|
|
317
|
+
opts: msg.opts || {},
|
|
318
|
+
});
|
|
319
|
+
}),
|
|
320
|
+
|
|
321
|
+
"personal-data-hub.aichat-rotate-login": async (msg) =>
|
|
322
|
+
withHub(async (hub) => {
|
|
323
|
+
const wiz = getAIChatWizard({ hubDir: hub.hubDir });
|
|
324
|
+
return await wiz.rotateLoginPartition({ vendor: msg.vendor });
|
|
325
|
+
}),
|
|
326
|
+
|
|
327
|
+
"personal-data-hub.list-aichat-accounts": async () =>
|
|
328
|
+
withHub(async (hub) => await hub.listAIChatAccounts()),
|
|
329
|
+
|
|
330
|
+
"personal-data-hub.unregister-aichat": async (msg) =>
|
|
331
|
+
withHub(async (hub) => await hub.unregisterAIChatVendor(msg.vendor)),
|
|
332
|
+
|
|
333
|
+
"personal-data-hub.aichat-health-check-once": async () =>
|
|
334
|
+
withHub(async (hub) => await hub.runAIChatHealthCheckOnce()),
|
|
267
335
|
};
|
|
268
336
|
|
|
269
337
|
/**
|
package/src/index.js
CHANGED
|
@@ -68,6 +68,7 @@ import { registerAuthCommand } from "./commands/auth.js";
|
|
|
68
68
|
import { registerAuditCommand } from "./commands/audit.js";
|
|
69
69
|
import { registerP2pCommand } from "./commands/p2p.js";
|
|
70
70
|
import { registerSyncCommand } from "./commands/sync.js";
|
|
71
|
+
import { registerSyncProviderCommands } from "./commands/sync-providers.js";
|
|
71
72
|
import { registerWalletCommand } from "./commands/wallet.js";
|
|
72
73
|
import { registerOrgCommand } from "./commands/org.js";
|
|
73
74
|
import { registerPluginCommand } from "./commands/plugin.js";
|
|
@@ -466,6 +467,9 @@ export function createProgram(opts = {}) {
|
|
|
466
467
|
// Phase 5: P2P, blockchain & enterprise
|
|
467
468
|
registerP2pCommand(program);
|
|
468
469
|
registerSyncCommand(program);
|
|
470
|
+
// Phase 3c follow-up — cc sync webdav / cc sync oss subgroups (credential mgmt).
|
|
471
|
+
// Must come AFTER registerSyncCommand so the `sync` parent exists.
|
|
472
|
+
registerSyncProviderCommands(program);
|
|
469
473
|
registerWalletCommand(program);
|
|
470
474
|
registerOrgCommand(program);
|
|
471
475
|
registerPluginCommand(program);
|