chainlesschain 0.162.12 → 0.162.14
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 +29 -24
- package/package.json +5 -2
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-C3TDNq29.js → AIOps-D34d_Nh1.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-C9fE18pE.js → ActionButton-Br7HxCnl.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-wnZF602C.js → Analytics-bVKq79Xd.js} +1 -1
- package/src/assets/web-panel/assets/{AppLayout-BjgTMK7O.js → AppLayout-CWSLIbAz.js} +2 -2
- package/src/assets/web-panel/assets/{Audit-BBL0BW5_.js → Audit-Cmnu1qqa.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BKLqYCWU.js → Backup-Rok20-TL.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BGSzMCZs.js → BaseInput-BJzs_ZtT.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CQWzZWEY.js → Chat-CSYapbcq.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BkTri12Q.js → Checkbox-BEa7Sr7e.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BH1m09EO.js → Codegen-C9M4e7ne.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BXnBuqIa.js → Col-DU9NoUIi.js} +1 -1
- package/src/assets/web-panel/assets/{Community-C_Nr4XCx.js → Community-DA9uz_jP.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Du6GwLrj.js → Compact-3_bEraVw.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-66M0oi1Q.js → Compliance-BtF8jWUQ.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DQrkZRNd.js → Cowork-BqvA7oaM.js} +1 -1
- package/src/assets/web-panel/assets/{Cron-CwdIFH_v.js → Cron-CxZy7Mzg.js} +1 -1
- package/src/assets/web-panel/assets/{Crosschain-DqlcrQ9L.js → Crosschain-1DB-XRGu.js} +1 -1
- package/src/assets/web-panel/assets/{DID-OmPLKf7L.js → DID-B6Ezp1pt.js} +1 -1
- package/src/assets/web-panel/assets/{Dashboard-D_dampTL.js → Dashboard-QDJ6VVsn.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CA1W7jAn.js → Dropdown-CovsWjxG.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-Chlk9a7s.js → Federation-DbRxS4Y4.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-t0UqYFLq.js → FormItemContext-9E9dNGtx.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CEq0raYm.js → Git-CqEpyxRZ.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-C06CX7Ge.js → Governance-On47KtGq.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-6VIFHxIP.js → Inference-RZcjcyaq.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BCJPjMBQ.js → KnowledgeGraph-C-1rRAM9.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BBpOYFct.js → Logs-BuunmG_r.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-BFH6jMWt.js → Marketplace-CromymyA.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-uCFvRqGs.js → McpTools-5XlFExh7.js} +1 -1
- package/src/assets/web-panel/assets/{Memory-B0Kux_KT.js → Memory-DjnUT7YM.js} +1 -1
- package/src/assets/web-panel/assets/{MobileBridge-DHow2jiK.js → MobileBridge-BrYIgLg6.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BFo9YQZp.js → MobileProjects-CL5V3fTm.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-riOh1G_F.js → Mtc-CHYJq6zK.js} +1 -1
- package/src/assets/web-panel/assets/{MtcAudit-Bm-hE2SP.js → MtcAudit-BZxUO0qt.js} +1 -1
- package/src/assets/web-panel/assets/{Multisig-DfUQxh5a.js → Multisig-FZTmJgW1.js} +2 -2
- package/src/assets/web-panel/assets/{NLProgramming-DuNvLBEq.js → NLProgramming-C9Mhefph.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DB20wd3c.js → Notes-W7usj-Ar.js} +1 -1
- package/src/assets/web-panel/assets/{NotificationSettings-CB-GkOWR.js → NotificationSettings-PBuYv_Bh.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-3bU7PZuG.js → Organization-CuYCE-rF.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BGCPP_0Y.js → Overflow-Dojx-kzE.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-BgIaSrLX.js} +1 -1
- package/src/assets/web-panel/assets/{Permissions-BuOD4xwc.js → Permissions-Byj2dkF_.js} +1 -1
- package/src/assets/web-panel/assets/PersonalDataHub-CMOOI13-.js +1 -0
- package/src/assets/web-panel/assets/PersonalDataHub-Dvaa8niQ.css +1 -0
- package/src/assets/web-panel/assets/{Pipeline-DBS5U4LB.js → Pipeline-CWwEOF09.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-UNjIc5El.js → Privacy-VT7gldcN.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CicqCJGy.js → ProjectInit-7UH3c3p7.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectSettings-CIxAbt4Y.js → ProjectSettings-DqLp-72a.js} +1 -1
- package/src/assets/web-panel/assets/{Projects-BJycZScO.js → Projects-B_54eDhH.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DxXvprme.js → Providers-BIrNfNpc.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-rrqjU8_Y.js → QuickAsk-BbYPwCso.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BEwHMhI7.js → Recommend-BF4qBssF.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-DoVKCCMn.js → Reputation-DPEzlC2V.js} +1 -1
- package/src/assets/web-panel/assets/{Row-F5XcDhHr.js → Row-DjHxhH1L.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-cZrRG7k8.js → RssFeed-D0_j678P.js} +1 -1
- package/src/assets/web-panel/assets/{Search-B9ctZjqx.js → Search-DctfGehu.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Z62hl1mc.js → Security-BFHggeYM.js} +1 -1
- package/src/assets/web-panel/assets/{Services-CQf5XqgZ.js → Services-CmrFMukV.js} +1 -1
- package/src/assets/web-panel/assets/{Skeleton-DuCKw2Eh.js → Skeleton-DR4vn_nS.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-qVkhva0s.js → Skills-DlXG2yyV.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BQbatr7s.js → Sla-4PPGL3SE.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DLFBzAgD.js → SpeechSettings-D9EhJOqm.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CrzETZMW.js → SyncSettings-Dasmbi0p.js} +1 -1
- package/src/assets/web-panel/assets/{Tasks-D_EQ1nJ7.js → Tasks-vilEiuPA.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-D4y-dGRc.js → Templates-Ca9Rvktn.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-2XI0jkPn.js → Tenant-CEZb9gfK.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-fUi5V2Z9.js → Terminal-DanCBdbD.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BuUNB2mg.js → Tokens-SPkClW2d.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-7DqLLuej.js → Trigger-B645yL7g.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CeACvTYx.js → Trust-D9sM_Ig0.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-mDP9EXHq.js → UkeySign-B_Nr2K-u.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-veWlKclv.js → VideoEditing-U01Lea8j.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Cd2Hheb8.js → Wallet-6xBySVV8.js} +1 -1
- package/src/assets/web-panel/assets/{WebAuthn-DyL7ZiHX.js → WebAuthn-DbgMoBu6.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-C7-7LJH9.js → WorkflowEditor-Bz-Y6IR2.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DXomZMuo.js → chat-BC_O9hag.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-ChlOGOvr.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-sBiTL8mX.js → compact-item-BSbAYGGF.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DZXEnzum.js → createContext-CFcZly5M.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-BomYwwYE.js} +1 -1
- package/src/assets/web-panel/assets/{icons-CLQTHa5-.js → icons-BOPtEWK4.js} +4 -4
- package/src/assets/web-panel/assets/{index-B0Qbxr57.js → index-5Ewm6KZA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CjXSvceY.js → index-B6LJHQoE.js} +1 -1
- package/src/assets/web-panel/assets/{index-CD3iljXs.js → index-BEJ6YiLI.js} +1 -1
- package/src/assets/web-panel/assets/{index-BK2AFy44.js → index-BGUbtM3R.js} +1 -1
- package/src/assets/web-panel/assets/{index-Di1_EQ-X.js → index-BHGsFwYW.js} +1 -1
- package/src/assets/web-panel/assets/{index-B23tuoo9.js → index-BHi69MHF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUlPMzoM.js → index-BI1jAWcc.js} +1 -1
- package/src/assets/web-panel/assets/index-BIRYt1of.js +1 -0
- package/src/assets/web-panel/assets/{index-B3k9UPHc.js → index-BYDvb1pi.js} +1 -1
- package/src/assets/web-panel/assets/{index-CwbWZubA.js → index-BZGdjNLA.js} +1 -1
- package/src/assets/web-panel/assets/{index-ThrAiEF9.js → index-BwFykZ5U.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUe5t5Aa.js → index-ByZQNO0A.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dn8m1d1f.js → index-C0rr1X9W.js} +2 -2
- package/src/assets/web-panel/assets/{index-C6SDf50u.js → index-CBhoZhCO.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClN_JuFa.js → index-CCRSz2cR.js} +1 -1
- package/src/assets/web-panel/assets/index-CZfySmWX.js +1 -0
- package/src/assets/web-panel/assets/{index-Dq5Rn5VS.js → index-Cj47XwJQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-ChahjdYE.js → index-Cmzh8gKL.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dyg6ikIL.js → index-CnxlKTDK.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dj9Nvz6S.js → index-CoF95pYK.js} +1 -1
- package/src/assets/web-panel/assets/{index-TwQZkVGh.js → index-Ctx97mH-.js} +1 -1
- package/src/assets/web-panel/assets/{index-s8tvk-fF.js → index-D0vX9jQA.js} +1 -1
- package/src/assets/web-panel/assets/{index-X48zYgZ6.js → index-DNkth8dM.js} +1 -1
- package/src/assets/web-panel/assets/{index-DygNvCeR.js → index-DRp5_Xns.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_MzScPM.js → index-DW-Ji07y.js} +1 -1
- package/src/assets/web-panel/assets/{index-BqnhEJls.js → index-DXgE2VW6.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDyzZ8_O.js → index-D_0B3CiU.js} +1 -1
- package/src/assets/web-panel/assets/{index-C59FgSkU.js → index-Dbf5YmDX.js} +1 -1
- package/src/assets/web-panel/assets/{index-_zyXBoS7.js → index-DsNQ2hqI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJ7XYa5K.js → index-EY733h9z.js} +1 -1
- package/src/assets/web-panel/assets/{index-ibFHnqHz.js → index-QD_n54XT.js} +1 -1
- package/src/assets/web-panel/assets/{index-CivbS-57.js → index-T5Y_9IPv.js} +1 -1
- package/src/assets/web-panel/assets/{index-C52udT0_.js → index-b8GbH2Yi.js} +4 -4
- package/src/assets/web-panel/assets/{index-XI6772AD.js → index-gUACAWbM.js} +1 -1
- package/src/assets/web-panel/assets/{index-F9cBucYf.js → index-onW325hZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKe9jmKG.js → index-ozVPr1gj.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_IgY63-.js → index-slYX2rCE.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_-RETt0.js → index-t9u2bHpH.js} +1 -1
- package/src/assets/web-panel/assets/{index-DeGnHcp5.js → index-za1GUJBG.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DEi92ZnZ.js → initDefaultProps-DnadEaxu.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BtYKzpOc.js → motion-CC_Na0Tl.js} +1 -1
- package/src/assets/web-panel/assets/{move-Cb3A1-v-.js → move-C2d9Mkk9.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B6qPDdOf.js → omit-QvpKbF8p.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DDyeQMUc.js → pickAttrs-Dm8r3X1_.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BPV6VO47.js → placementArrow-DaqaVfoX.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DJ1ra4dT.js → responsiveObserve-Iida9fIn.js} +1 -1
- package/src/assets/web-panel/assets/{slide-D6v8tHvB.js → slide-YqHexXQD.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DulKcQLZ.js → statusUtils-BGKLoeEt.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Bne7zwMt.js → styleChecker-aI-gsQO8.js} +1 -1
- package/src/assets/web-panel/assets/useFlexGapSupport-BiOsz4rc.js +1 -0
- package/src/assets/web-panel/assets/{useFs-CR-iLa4Z.js → useFs-CZy7Zo2X.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-B6WqjmE4.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-B-VCMXSD.js → zoom-DTeTrJ2z.js} +1 -1
- package/src/assets/web-panel/index.html +3 -3
- package/src/commands/__tests__/android.test.js +260 -0
- package/src/commands/__tests__/hub-aichat.test.js +277 -0
- package/src/commands/__tests__/hub-wechat.test.js +243 -0
- package/src/commands/android.js +284 -0
- package/src/commands/hub.js +457 -0
- package/src/commands/sync-providers.js +436 -0
- package/src/gateways/ws/personal-data-hub-protocol.js +88 -0
- package/src/index.js +6 -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/cc-android-bridge.js +162 -0
- package/src/lib/personal-data-hub-aichat-wizard.js +242 -0
- package/src/lib/personal-data-hub-wiring.js +258 -13
- 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/lib/web-ui-server.js +2 -1
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{K as o}from"./index-
|
|
1
|
+
import{K as o}from"./index-b8GbH2Yi.js";import{i as f}from"./motion-CC_Na0Tl.js";const c=new o("antZoomIn",{"0%":{transform:"scale(0.2)",opacity:0},"100%":{transform:"scale(1)",opacity:1}}),y=new o("antZoomOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0.2)",opacity:0}}),a=new o("antZoomBigIn",{"0%":{transform:"scale(0.8)",opacity:0},"100%":{transform:"scale(1)",opacity:1}}),s=new o("antZoomBigOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0.8)",opacity:0}}),g=new o("antZoomUpIn",{"0%":{transform:"scale(0.8)",transformOrigin:"50% 0%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"50% 0%"}}),O=new o("antZoomUpOut",{"0%":{transform:"scale(1)",transformOrigin:"50% 0%"},"100%":{transform:"scale(0.8)",transformOrigin:"50% 0%",opacity:0}}),l=new o("antZoomLeftIn",{"0%":{transform:"scale(0.8)",transformOrigin:"0% 50%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"0% 50%"}}),u=new o("antZoomLeftOut",{"0%":{transform:"scale(1)",transformOrigin:"0% 50%"},"100%":{transform:"scale(0.8)",transformOrigin:"0% 50%",opacity:0}}),p=new o("antZoomRightIn",{"0%":{transform:"scale(0.8)",transformOrigin:"100% 50%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"100% 50%"}}),z=new o("antZoomRightOut",{"0%":{transform:"scale(1)",transformOrigin:"100% 50%"},"100%":{transform:"scale(0.8)",transformOrigin:"100% 50%",opacity:0}}),K=new o("antZoomDownIn",{"0%":{transform:"scale(0.8)",transformOrigin:"50% 100%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"50% 100%"}}),w=new o("antZoomDownOut",{"0%":{transform:"scale(1)",transformOrigin:"50% 100%"},"100%":{transform:"scale(0.8)",transformOrigin:"50% 100%",opacity:0}}),I={zoom:{inKeyframes:c,outKeyframes:y},"zoom-big":{inKeyframes:a,outKeyframes:s},"zoom-big-fast":{inKeyframes:a,outKeyframes:s},"zoom-left":{inKeyframes:l,outKeyframes:u},"zoom-right":{inKeyframes:p,outKeyframes:z},"zoom-up":{inKeyframes:g,outKeyframes:O},"zoom-down":{inKeyframes:K,outKeyframes:w}},h=(n,r)=>{const{antCls:m}=n,t=`${m}-${r}`,{inKeyframes:i,outKeyframes:e}=I[r];return[f(t,i,e,r==="zoom-big-fast"?n.motionDurationFast:n.motionDurationMid),{[`
|
|
2
2
|
${t}-enter,
|
|
3
3
|
${t}-appear
|
|
4
4
|
`]:{transform:"scale(0)",opacity:0,animationTimingFunction:n.motionEaseOutCirc,"&-prepare":{transform:"none"}},[`${t}-leave`]:{animationTimingFunction:n.motionEaseInOutCirc}}]};export{h as i,c as z};
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
// Injected by web-ui-server.js at serve time
|
|
9
9
|
window.__CC_CONFIG__ = __CC_CONFIG_PLACEHOLDER__;
|
|
10
10
|
</script>
|
|
11
|
-
<script type="module" crossorigin src="./assets/index-
|
|
12
|
-
<link rel="modulepreload" crossorigin href="./assets/vendor-
|
|
13
|
-
<link rel="modulepreload" crossorigin href="./assets/icons-
|
|
11
|
+
<script type="module" crossorigin src="./assets/index-b8GbH2Yi.js"></script>
|
|
12
|
+
<link rel="modulepreload" crossorigin href="./assets/vendor-DhFY8mDK.js">
|
|
13
|
+
<link rel="modulepreload" crossorigin href="./assets/icons-BOPtEWK4.js">
|
|
14
14
|
<link rel="stylesheet" crossorigin href="./assets/index-CfX1DEtk.css">
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cc android` command + cc-android-bridge unit tests (Plan A A7 scaffold).
|
|
3
|
+
*
|
|
4
|
+
* These exercise the command routing without a real Android device. The
|
|
5
|
+
* `_deps` injection seam swaps the bridge module with a mock so we hit both
|
|
6
|
+
* the success path (bridge resolves) and error path (bridge throws
|
|
7
|
+
* AndroidBridgeUnavailableError, which on a real non-Android host is what
|
|
8
|
+
* actually happens).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
12
|
+
|
|
13
|
+
import * as androidCmd from "../android.js";
|
|
14
|
+
import * as bridge from "../../lib/cc-android-bridge.js";
|
|
15
|
+
|
|
16
|
+
let logSpy, errSpy, exitSpy, jsonSpy;
|
|
17
|
+
|
|
18
|
+
function withMockBridge(invokeResult) {
|
|
19
|
+
const mock = {
|
|
20
|
+
invoke: vi.fn(async (method, params) => {
|
|
21
|
+
if (invokeResult instanceof Error) throw invokeResult;
|
|
22
|
+
if (typeof invokeResult === "function")
|
|
23
|
+
return await invokeResult(method, params);
|
|
24
|
+
return invokeResult;
|
|
25
|
+
}),
|
|
26
|
+
caps: vi.fn(() => ({ available: true, reason: "mock" })),
|
|
27
|
+
AndroidBridgeUnavailableError: bridge.AndroidBridgeUnavailableError,
|
|
28
|
+
};
|
|
29
|
+
androidCmd._deps.bridge = mock;
|
|
30
|
+
return mock;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
35
|
+
errSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
36
|
+
exitSpy = vi.spyOn(process, "exit").mockImplementation((code) => {
|
|
37
|
+
throw new Error(`__exit:${code}`);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
afterEach(() => {
|
|
42
|
+
androidCmd._deps.bridge = bridge;
|
|
43
|
+
vi.restoreAllMocks();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// ─── cc-android-bridge ────────────────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
describe("cc-android-bridge", () => {
|
|
49
|
+
it("detectAndroid returns false on a vanilla non-Android host", () => {
|
|
50
|
+
// Test runs on win32 / linux / darwin — not android.
|
|
51
|
+
expect(bridge.detectAndroid()).toBe(false);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("detectAndroid returns true under CC_ANDROID_BRIDGE_OVERRIDE=1", () => {
|
|
55
|
+
process.env.CC_ANDROID_BRIDGE_OVERRIDE = "1";
|
|
56
|
+
try {
|
|
57
|
+
expect(bridge.detectAndroid()).toBe(true);
|
|
58
|
+
} finally {
|
|
59
|
+
delete process.env.CC_ANDROID_BRIDGE_OVERRIDE;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("invoke rejects with ANDROID_BRIDGE_NOT_AVAILABLE on non-Android host", async () => {
|
|
64
|
+
await expect(bridge.invoke("contacts.query", {})).rejects.toMatchObject({
|
|
65
|
+
code: "ANDROID_BRIDGE_NOT_AVAILABLE",
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("invoke routes through testInvoke when override is set", async () => {
|
|
70
|
+
process.env.CC_ANDROID_BRIDGE_OVERRIDE = "1";
|
|
71
|
+
const original = bridge._deps.testInvoke;
|
|
72
|
+
bridge._deps.testInvoke = vi.fn(async (m, p) => ({ echo: m, params: p }));
|
|
73
|
+
try {
|
|
74
|
+
const r = await bridge.invoke("foo.bar", { x: 1 });
|
|
75
|
+
expect(r).toEqual({ echo: "foo.bar", params: { x: 1 } });
|
|
76
|
+
expect(bridge._deps.testInvoke).toHaveBeenCalledWith("foo.bar", { x: 1 });
|
|
77
|
+
} finally {
|
|
78
|
+
bridge._deps.testInvoke = original;
|
|
79
|
+
delete process.env.CC_ANDROID_BRIDGE_OVERRIDE;
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("invoke rejects empty method", async () => {
|
|
84
|
+
await expect(bridge.invoke("")).rejects.toThrow(/non-empty string/);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("caps reports unavailable on non-Android host", () => {
|
|
88
|
+
const c = bridge.caps();
|
|
89
|
+
expect(c.available).toBe(false);
|
|
90
|
+
expect(c.reason).toMatch(/not-on-android/);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// ─── cmd routing — bridge success path ─────────────────────────────────
|
|
95
|
+
|
|
96
|
+
describe("cc android commands — success path (mocked bridge)", () => {
|
|
97
|
+
it("cmdCaps prints available when bridge.caps returns available", async () => {
|
|
98
|
+
withMockBridge({});
|
|
99
|
+
await androidCmd._cmds.cmdCaps({ json: true });
|
|
100
|
+
expect(logSpy).toHaveBeenCalled();
|
|
101
|
+
const out = logSpy.mock.calls[0][0];
|
|
102
|
+
expect(JSON.parse(out).available).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("cmdContactsPull invokes contacts.query with --since", async () => {
|
|
106
|
+
const mock = withMockBridge({ ingested: 42, events: [] });
|
|
107
|
+
await androidCmd._cmds.cmdContactsPull({
|
|
108
|
+
json: true,
|
|
109
|
+
since: "1700000000000",
|
|
110
|
+
});
|
|
111
|
+
expect(mock.invoke).toHaveBeenCalledWith("contacts.query", {
|
|
112
|
+
since: 1700000000000,
|
|
113
|
+
});
|
|
114
|
+
const out = JSON.parse(logSpy.mock.calls[0][0]);
|
|
115
|
+
expect(out.ingested).toBe(42);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("cmdSmsPull invokes sms.query", async () => {
|
|
119
|
+
const mock = withMockBridge({ ok: true });
|
|
120
|
+
await androidCmd._cmds.cmdSmsPull({ json: true });
|
|
121
|
+
expect(mock.invoke).toHaveBeenCalledWith("sms.query", { since: undefined });
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("cmdCallsPull invokes calls.query", async () => {
|
|
125
|
+
const mock = withMockBridge({ ok: true });
|
|
126
|
+
await androidCmd._cmds.cmdCallsPull({ json: true });
|
|
127
|
+
expect(mock.invoke).toHaveBeenCalledWith("calls.query", {
|
|
128
|
+
since: undefined,
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("cmdAppList passes includeSystem flag", async () => {
|
|
133
|
+
const mock = withMockBridge([{ pkg: "com.foo" }]);
|
|
134
|
+
await androidCmd._cmds.cmdAppList({ json: true, system: true });
|
|
135
|
+
expect(mock.invoke).toHaveBeenCalledWith("app.list", {
|
|
136
|
+
includeSystem: true,
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("cmdAppLaunch forwards pkg", async () => {
|
|
141
|
+
const mock = withMockBridge({ ok: true });
|
|
142
|
+
await androidCmd._cmds.cmdAppLaunch("com.tencent.mm", { json: true });
|
|
143
|
+
expect(mock.invoke).toHaveBeenCalledWith("app.launch", {
|
|
144
|
+
pkg: "com.tencent.mm",
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("cmdAppIntent parses --extra K=V repeatable", async () => {
|
|
149
|
+
const mock = withMockBridge({ ok: true });
|
|
150
|
+
await androidCmd._cmds.cmdAppIntent("com.foo", "VIEW", {
|
|
151
|
+
json: true,
|
|
152
|
+
extra: ["url=https://x", "id=42"],
|
|
153
|
+
});
|
|
154
|
+
expect(mock.invoke).toHaveBeenCalledWith("app.intent", {
|
|
155
|
+
pkg: "com.foo",
|
|
156
|
+
action: "VIEW",
|
|
157
|
+
extras: { url: "https://x", id: "42" },
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("cmdFsRead forwards SAF tree URI", async () => {
|
|
162
|
+
const mock = withMockBridge({ bytes: 100 });
|
|
163
|
+
await androidCmd._cmds.cmdFsRead(
|
|
164
|
+
"content://com.android.externalstorage.documents/tree/abc",
|
|
165
|
+
{
|
|
166
|
+
json: true,
|
|
167
|
+
},
|
|
168
|
+
);
|
|
169
|
+
expect(mock.invoke).toHaveBeenCalledWith("fs.read", {
|
|
170
|
+
target: "content://com.android.externalstorage.documents/tree/abc",
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("cmdFsList invokes fs.list", async () => {
|
|
175
|
+
const mock = withMockBridge([]);
|
|
176
|
+
await androidCmd._cmds.cmdFsList("/sdcard/Download/", { json: true });
|
|
177
|
+
expect(mock.invoke).toHaveBeenCalledWith("fs.list", {
|
|
178
|
+
target: "/sdcard/Download/",
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("cmdA11yQuery forwards --filter", async () => {
|
|
183
|
+
const mock = withMockBridge({ nodes: [] });
|
|
184
|
+
await androidCmd._cmds.cmdA11yQuery({ json: true, filter: "button" });
|
|
185
|
+
expect(mock.invoke).toHaveBeenCalledWith("a11y.query", {
|
|
186
|
+
filter: "button",
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it("cmdA11yClick forwards nodeId", async () => {
|
|
191
|
+
const mock = withMockBridge({ ok: true });
|
|
192
|
+
await androidCmd._cmds.cmdA11yClick("node-7", { json: true });
|
|
193
|
+
expect(mock.invoke).toHaveBeenCalledWith("a11y.click", {
|
|
194
|
+
nodeId: "node-7",
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("cmdA11yType forwards text", async () => {
|
|
199
|
+
const mock = withMockBridge({ ok: true });
|
|
200
|
+
await androidCmd._cmds.cmdA11yType("hello", { json: true });
|
|
201
|
+
expect(mock.invoke).toHaveBeenCalledWith("a11y.type", { text: "hello" });
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("cmdShizukuExec forwards cmd", async () => {
|
|
205
|
+
const mock = withMockBridge({ stdout: "ok" });
|
|
206
|
+
await androidCmd._cmds.cmdShizukuExec("pm list packages", { json: true });
|
|
207
|
+
expect(mock.invoke).toHaveBeenCalledWith("shizuku.exec", {
|
|
208
|
+
cmd: "pm list packages",
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it("cmdRootExec forwards cmd", async () => {
|
|
213
|
+
const mock = withMockBridge({ stdout: "" });
|
|
214
|
+
await androidCmd._cmds.cmdRootExec("ls /data/data", { json: true });
|
|
215
|
+
expect(mock.invoke).toHaveBeenCalledWith("root.exec", {
|
|
216
|
+
cmd: "ls /data/data",
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("cmdPerms forwards permission name", async () => {
|
|
221
|
+
const mock = withMockBridge({ granted: false });
|
|
222
|
+
await androidCmd._cmds.cmdPerms("READ_CONTACTS", { json: true });
|
|
223
|
+
expect(mock.invoke).toHaveBeenCalledWith("perms.check", {
|
|
224
|
+
name: "READ_CONTACTS",
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// ─── cmd routing — bridge error path ──────────────────────────────────
|
|
230
|
+
|
|
231
|
+
describe("cc android commands — error path", () => {
|
|
232
|
+
it("propagates ANDROID_BRIDGE_NOT_AVAILABLE as JSON when --json", async () => {
|
|
233
|
+
withMockBridge(
|
|
234
|
+
new bridge.AndroidBridgeUnavailableError("test-not-on-android"),
|
|
235
|
+
);
|
|
236
|
+
await expect(
|
|
237
|
+
androidCmd._cmds.cmdContactsPull({ json: true }),
|
|
238
|
+
).rejects.toThrow(/__exit:1/);
|
|
239
|
+
const out = JSON.parse(logSpy.mock.calls[0][0]);
|
|
240
|
+
expect(out.code).toBe("ANDROID_BRIDGE_NOT_AVAILABLE");
|
|
241
|
+
expect(out.error).toMatch(/test-not-on-android/);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it("propagates error human-readable on non-JSON", async () => {
|
|
245
|
+
withMockBridge(new bridge.AndroidBridgeUnavailableError("nope"));
|
|
246
|
+
await expect(androidCmd._cmds.cmdSmsPull({ json: false })).rejects.toThrow(
|
|
247
|
+
/__exit:1/,
|
|
248
|
+
);
|
|
249
|
+
expect(errSpy).toHaveBeenCalled();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it("non-bridge errors still surface", async () => {
|
|
253
|
+
withMockBridge(new Error("network timeout"));
|
|
254
|
+
await expect(androidCmd._cmds.cmdAppList({ json: true })).rejects.toThrow(
|
|
255
|
+
/__exit:1/,
|
|
256
|
+
);
|
|
257
|
+
const out = JSON.parse(logSpy.mock.calls[0][0]);
|
|
258
|
+
expect(out.error).toMatch(/network timeout/);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cc hub aichat <verb> CLI command unit tests (Phase 10.3.6 CLI surface).
|
|
3
|
+
*
|
|
4
|
+
* The command handlers accept `_wizard` / `_getHub` / `_factoryDeps` test
|
|
5
|
+
* seams so this suite never starts a real hub or fs. We invoke the handler
|
|
6
|
+
* functions directly via the `_internal` export.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, it, expect, beforeEach, vi, afterEach } from "vitest";
|
|
10
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
11
|
+
import { tmpdir } from "node:os";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
|
|
14
|
+
import { _internal } from "../hub.js";
|
|
15
|
+
|
|
16
|
+
let logSpy, errSpy, exitSpy;
|
|
17
|
+
|
|
18
|
+
function fakeWizard(overrides = {}) {
|
|
19
|
+
return {
|
|
20
|
+
openVendorLogin: vi.fn(async ({ vendor }) => ({
|
|
21
|
+
ok: true,
|
|
22
|
+
vendor,
|
|
23
|
+
fallbackMode: "paste",
|
|
24
|
+
loginUrl: "https://" + vendor + ".example/",
|
|
25
|
+
requiredCookies: ["theToken"],
|
|
26
|
+
helpText: "登录 " + vendor,
|
|
27
|
+
...overrides.openVendorLogin,
|
|
28
|
+
})),
|
|
29
|
+
probeCookies: vi.fn(async ({ vendor, cookieHeader }) => ({
|
|
30
|
+
ok: cookieHeader && cookieHeader.includes("theToken="),
|
|
31
|
+
source: "paste",
|
|
32
|
+
vendor,
|
|
33
|
+
cookies: { theToken: "v" },
|
|
34
|
+
foundRequired:
|
|
35
|
+
cookieHeader && cookieHeader.includes("theToken=") ? ["theToken"] : [],
|
|
36
|
+
missingRequired:
|
|
37
|
+
cookieHeader && cookieHeader.includes("theToken=") ? [] : ["theToken"],
|
|
38
|
+
foundOptional: [],
|
|
39
|
+
...overrides.probeCookies,
|
|
40
|
+
})),
|
|
41
|
+
registerVendor: vi.fn(async ({ vendor, cookies }) => {
|
|
42
|
+
if (!cookies || !cookies.includes("theToken=")) {
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
reason: "REQUIRED_COOKIES_MISSING",
|
|
46
|
+
missingRequired: ["theToken"],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return { ok: true, vendor, accountId: `${vendor}:u1` };
|
|
50
|
+
}),
|
|
51
|
+
rotateLoginPartition: vi.fn(async () => ({ ok: true })),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
57
|
+
errSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
58
|
+
exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => {
|
|
59
|
+
throw new Error("process.exit called");
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
afterEach(() => {
|
|
64
|
+
logSpy.mockRestore();
|
|
65
|
+
errSpy.mockRestore();
|
|
66
|
+
exitSpy.mockRestore();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// ─── cmdAIChatList ────────────────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
describe("cc hub aichat list", () => {
|
|
72
|
+
it("prints all 9 default vendors with login URLs (text mode)", async () => {
|
|
73
|
+
const wiz = fakeWizard();
|
|
74
|
+
await _internal.cmdAIChatList({ _wizard: wiz });
|
|
75
|
+
expect(wiz.openVendorLogin).toHaveBeenCalledTimes(9);
|
|
76
|
+
const calledVendors = wiz.openVendorLogin.mock.calls.map(
|
|
77
|
+
(c) => c[0].vendor,
|
|
78
|
+
);
|
|
79
|
+
expect(calledVendors).toEqual(_internal._defaultKnownVendors());
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("emits JSON with --json including the vendor array", async () => {
|
|
83
|
+
const wiz = fakeWizard();
|
|
84
|
+
await _internal.cmdAIChatList({ _wizard: wiz, json: true });
|
|
85
|
+
const printed = logSpy.mock.calls.map((c) => c[0]).join("\n");
|
|
86
|
+
const parsed = JSON.parse(printed);
|
|
87
|
+
expect(parsed.vendors.length).toBe(9);
|
|
88
|
+
expect(parsed.vendors[0]).toHaveProperty("vendor");
|
|
89
|
+
expect(parsed.vendors[0]).toHaveProperty("loginUrl");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("restricts to a custom vendor list via _knownVendors", async () => {
|
|
93
|
+
const wiz = fakeWizard();
|
|
94
|
+
await _internal.cmdAIChatList({
|
|
95
|
+
_wizard: wiz,
|
|
96
|
+
_knownVendors: ["kimi", "doubao"],
|
|
97
|
+
});
|
|
98
|
+
expect(wiz.openVendorLogin).toHaveBeenCalledTimes(2);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// ─── cmdAIChatLogin ───────────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
describe("cc hub aichat login <vendor>", () => {
|
|
105
|
+
it("prints loginUrl + helpText for the given vendor", async () => {
|
|
106
|
+
const wiz = fakeWizard();
|
|
107
|
+
await _internal.cmdAIChatLogin("deepseek", { _wizard: wiz });
|
|
108
|
+
expect(wiz.openVendorLogin).toHaveBeenCalledWith({ vendor: "deepseek" });
|
|
109
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
110
|
+
expect(out).toMatch(/deepseek\.example/);
|
|
111
|
+
expect(out).toMatch(/登录 deepseek/);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("--json passes the wizard return shape verbatim", async () => {
|
|
115
|
+
const wiz = fakeWizard();
|
|
116
|
+
await _internal.cmdAIChatLogin("kimi", { _wizard: wiz, json: true });
|
|
117
|
+
const printed = logSpy.mock.calls.map((c) => c[0]).join("\n");
|
|
118
|
+
const parsed = JSON.parse(printed);
|
|
119
|
+
expect(parsed.ok).toBe(true);
|
|
120
|
+
expect(parsed.fallbackMode).toBe("paste");
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("exits with code 1 when wizard returns ok=false", async () => {
|
|
124
|
+
const wiz = fakeWizard({
|
|
125
|
+
openVendorLogin: { ok: false, reason: "UNKNOWN_VENDOR" },
|
|
126
|
+
});
|
|
127
|
+
await expect(
|
|
128
|
+
_internal.cmdAIChatLogin("ghost", { _wizard: wiz }),
|
|
129
|
+
).rejects.toThrow(/process.exit/);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// ─── cmdAIChatProbe ───────────────────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
describe("cc hub aichat probe <vendor> --cookies", () => {
|
|
136
|
+
it("ok when --cookies contains required token", async () => {
|
|
137
|
+
const wiz = fakeWizard();
|
|
138
|
+
await _internal.cmdAIChatProbe("deepseek", {
|
|
139
|
+
_wizard: wiz,
|
|
140
|
+
cookies: "theToken=abc; other=1",
|
|
141
|
+
});
|
|
142
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
143
|
+
expect(out).toMatch(/cookies look valid/);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("exits 1 with reason when required missing", async () => {
|
|
147
|
+
const wiz = fakeWizard();
|
|
148
|
+
await expect(
|
|
149
|
+
_internal.cmdAIChatProbe("deepseek", { _wizard: wiz, cookies: "junk=x" }),
|
|
150
|
+
).rejects.toThrow(/process.exit/);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("throws when --cookies omitted", async () => {
|
|
154
|
+
const wiz = fakeWizard();
|
|
155
|
+
await expect(
|
|
156
|
+
_internal.cmdAIChatProbe("deepseek", { _wizard: wiz }),
|
|
157
|
+
).rejects.toThrow(/process.exit/);
|
|
158
|
+
expect(errSpy).toHaveBeenCalled();
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// ─── cmdAIChatRegister ────────────────────────────────────────────────────
|
|
163
|
+
|
|
164
|
+
describe("cc hub aichat register <vendor> --cookies", () => {
|
|
165
|
+
it("happy path: prints confirmation with accountId", async () => {
|
|
166
|
+
const wiz = fakeWizard();
|
|
167
|
+
await _internal.cmdAIChatRegister("doubao", {
|
|
168
|
+
_wizard: wiz,
|
|
169
|
+
cookies: "theToken=abc",
|
|
170
|
+
});
|
|
171
|
+
expect(wiz.registerVendor).toHaveBeenCalledWith({
|
|
172
|
+
vendor: "doubao",
|
|
173
|
+
cookies: "theToken=abc",
|
|
174
|
+
});
|
|
175
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
176
|
+
expect(out).toMatch(/registered doubao/);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("exits 1 when required cookies missing", async () => {
|
|
180
|
+
const wiz = fakeWizard();
|
|
181
|
+
await expect(
|
|
182
|
+
_internal.cmdAIChatRegister("doubao", {
|
|
183
|
+
_wizard: wiz,
|
|
184
|
+
cookies: "junk=1",
|
|
185
|
+
}),
|
|
186
|
+
).rejects.toThrow(/process.exit/);
|
|
187
|
+
const errs = errSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
188
|
+
expect(errs).toMatch(/REQUIRED_COOKIES_MISSING/);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// ─── cmdAIChatHealth ──────────────────────────────────────────────────────
|
|
193
|
+
|
|
194
|
+
describe("cc hub aichat health", () => {
|
|
195
|
+
let hubDir;
|
|
196
|
+
beforeEach(() => {
|
|
197
|
+
hubDir = mkdtempSync(join(tmpdir(), "aichat-cli-health-"));
|
|
198
|
+
});
|
|
199
|
+
afterEach(() => rmSync(hubDir, { recursive: true, force: true }));
|
|
200
|
+
|
|
201
|
+
it("returns zero counts on an empty accounts store", async () => {
|
|
202
|
+
const accountsStore = {
|
|
203
|
+
list: async () => [],
|
|
204
|
+
put: async () => {},
|
|
205
|
+
get: async () => null,
|
|
206
|
+
delete: async () => {},
|
|
207
|
+
};
|
|
208
|
+
const vendorAdapter = { registerVendor: async () => ({ ok: true }) };
|
|
209
|
+
await _internal.cmdAIChatHealth({
|
|
210
|
+
json: true,
|
|
211
|
+
_factoryDeps: { hubDir, accountsStore, vendorAdapter },
|
|
212
|
+
});
|
|
213
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
214
|
+
const parsed = JSON.parse(out);
|
|
215
|
+
expect(parsed).toMatchObject({ checked: 0, ok: 0, failed: 0, mismatch: 0 });
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("text output summarises checked / ok / failed / mismatch", async () => {
|
|
219
|
+
const accountsStore = {
|
|
220
|
+
list: async () => [
|
|
221
|
+
{ vendor: "deepseek", cookies: { x: "y" }, cookieSpecVersion: 1 },
|
|
222
|
+
],
|
|
223
|
+
put: async () => {},
|
|
224
|
+
get: async () => null,
|
|
225
|
+
delete: async () => {},
|
|
226
|
+
};
|
|
227
|
+
const vendorAdapter = { registerVendor: async () => ({ ok: true }) };
|
|
228
|
+
await _internal.cmdAIChatHealth({
|
|
229
|
+
_factoryDeps: { hubDir, accountsStore, vendorAdapter },
|
|
230
|
+
});
|
|
231
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
232
|
+
expect(out).toMatch(/checked=1/);
|
|
233
|
+
expect(out).toMatch(/ok=1/);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// ─── cmdAIChatUnregister ──────────────────────────────────────────────────
|
|
238
|
+
|
|
239
|
+
describe("cc hub aichat unregister <vendor>", () => {
|
|
240
|
+
let hubDir;
|
|
241
|
+
beforeEach(() => {
|
|
242
|
+
hubDir = mkdtempSync(join(tmpdir(), "aichat-cli-unreg-"));
|
|
243
|
+
});
|
|
244
|
+
afterEach(() => rmSync(hubDir, { recursive: true, force: true }));
|
|
245
|
+
|
|
246
|
+
it("removes a registered vendor", async () => {
|
|
247
|
+
const store = new Map([["deepseek", { vendor: "deepseek" }]]);
|
|
248
|
+
const accountsStore = {
|
|
249
|
+
list: async () => Array.from(store.values()),
|
|
250
|
+
get: async (v) => store.get(v) || null,
|
|
251
|
+
put: async (v, e) => store.set(v, e),
|
|
252
|
+
delete: async (v) => store.delete(v),
|
|
253
|
+
};
|
|
254
|
+
await _internal.cmdAIChatUnregister("deepseek", {
|
|
255
|
+
_factoryDeps: { hubDir, accountsStore },
|
|
256
|
+
});
|
|
257
|
+
expect(store.has("deepseek")).toBe(false);
|
|
258
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
259
|
+
expect(out).toMatch(/removed deepseek/);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
it("exits 1 when the vendor is not registered", async () => {
|
|
263
|
+
const accountsStore = {
|
|
264
|
+
list: async () => [],
|
|
265
|
+
get: async () => null,
|
|
266
|
+
put: async () => {},
|
|
267
|
+
delete: async () => {},
|
|
268
|
+
};
|
|
269
|
+
await expect(
|
|
270
|
+
_internal.cmdAIChatUnregister("kimi", {
|
|
271
|
+
_factoryDeps: { hubDir, accountsStore },
|
|
272
|
+
}),
|
|
273
|
+
).rejects.toThrow(/process.exit/);
|
|
274
|
+
const errs = errSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
275
|
+
expect(errs).toMatch(/not registered/);
|
|
276
|
+
});
|
|
277
|
+
});
|