chainlesschain 0.159.0 → 0.160.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/AIOps-BHiKMxFI.js +1 -0
- package/src/assets/web-panel/assets/AIOps-Cchx1iXI.css +1 -0
- package/src/assets/web-panel/assets/ActionButton-5QD5uzWP.js +1 -0
- package/src/assets/web-panel/assets/Analytics-C1-TXmTC.css +1 -0
- package/src/assets/web-panel/assets/Analytics-D1JxsGBN.js +3 -0
- package/src/assets/web-panel/assets/AppLayout-CtGprHSx.css +1 -0
- package/src/assets/web-panel/assets/AppLayout-DykU9tOE.js +1 -0
- package/src/assets/web-panel/assets/Audit-6ZMsXmrO.css +1 -0
- package/src/assets/web-panel/assets/Audit-TGBqld9c.js +1 -0
- package/src/assets/web-panel/assets/Backup-CY9QozR7.css +1 -0
- package/src/assets/web-panel/assets/Backup-DjpzIwA6.js +1 -0
- package/src/assets/web-panel/assets/BaseInput-joQlVauq.js +1 -0
- package/src/assets/web-panel/assets/Chat-9TYfosy-.js +2 -0
- package/src/assets/web-panel/assets/{Chat-DmX5bWvL.css → Chat-ByiYUboW.css} +1 -1
- package/src/assets/web-panel/assets/Checkbox-OEOFA9GM.js +1 -0
- package/src/assets/web-panel/assets/Codegen-5H5UgHJu.js +1 -0
- package/src/assets/web-panel/assets/Codegen-BLP7id2a.css +1 -0
- package/src/assets/web-panel/assets/Col-BnLUipDp.js +1 -0
- package/src/assets/web-panel/assets/Community-BF3R5GAl.js +1 -0
- package/src/assets/web-panel/assets/Community-C2RejeOY.css +1 -0
- package/src/assets/web-panel/assets/Compact-C1EkTFek.js +1 -0
- package/src/assets/web-panel/assets/Compliance-CpP-ODRU.js +1 -0
- package/src/assets/web-panel/assets/Compliance-DOys4Ov1.css +1 -0
- package/src/assets/web-panel/assets/{Cowork-CFkkMMDK.js → Cowork-CCgGSKVR.js} +4 -4
- package/src/assets/web-panel/assets/Cron-CZ5pjRxn.js +2 -0
- package/src/assets/web-panel/assets/Crosschain-C0P-5sm3.js +1 -0
- package/src/assets/web-panel/assets/Crosschain-C7Le4Pte.css +1 -0
- package/src/assets/web-panel/assets/DID-BX6k3jZi.css +1 -0
- package/src/assets/web-panel/assets/DID-DPZKMApP.js +2 -0
- package/src/assets/web-panel/assets/Dashboard-G-BDDAov.js +3 -0
- package/src/assets/web-panel/assets/Dashboard-MFDcsVcM.css +1 -0
- package/src/assets/web-panel/assets/Dropdown-CeywCcVQ.js +1 -0
- package/src/assets/web-panel/assets/Federation-CgmfLbx1.css +1 -0
- package/src/assets/web-panel/assets/Federation-DuFRY867.js +1 -0
- package/src/assets/web-panel/assets/{FormItemContext-Be6TSNxz.js → FormItemContext-CFSiPqbu.js} +1 -1
- package/src/assets/web-panel/assets/Git-CjVRJDLg.js +2 -0
- package/src/assets/web-panel/assets/{Git-DGcuBXST.css → Git-DPuaGtg7.css} +1 -1
- package/src/assets/web-panel/assets/Governance-BoipmXaM.css +1 -0
- package/src/assets/web-panel/assets/Governance-C0lyocJc.js +1 -0
- package/src/assets/web-panel/assets/Inference-BVSAexgk.js +1 -0
- package/src/assets/web-panel/assets/Inference-BWxYJF9-.css +1 -0
- package/src/assets/web-panel/assets/KnowledgeGraph-CztPDA96.css +1 -0
- package/src/assets/web-panel/assets/KnowledgeGraph-SE4jCwIn.js +1 -0
- package/src/assets/web-panel/assets/Logs-BD5C-wTx.js +2 -0
- package/src/assets/web-panel/assets/Marketplace-CL93dFBs.js +1 -0
- package/src/assets/web-panel/assets/Marketplace-Djp5q9dS.css +1 -0
- package/src/assets/web-panel/assets/McpTools-CDjHmzxH.css +1 -0
- package/src/assets/web-panel/assets/McpTools-x-Tibae-.js +5 -0
- package/src/assets/web-panel/assets/Memory-Bcc2hxOA.css +1 -0
- package/src/assets/web-panel/assets/Memory-CR8LXq37.js +2 -0
- package/src/assets/web-panel/assets/Mtc-C-PfF5B3.css +1 -0
- package/src/assets/web-panel/assets/Mtc-CEtRtMcc.js +1 -0
- package/src/assets/web-panel/assets/NLProgramming-B09F6gt2.js +1 -0
- package/src/assets/web-panel/assets/NLProgramming-CLOvy-35.css +1 -0
- package/src/assets/web-panel/assets/Notes-BYIn2GOe.js +7 -0
- package/src/assets/web-panel/assets/Organization-BX-cIO8M.css +1 -0
- package/src/assets/web-panel/assets/Organization-CybJTFN9.js +4 -0
- package/src/assets/web-panel/assets/Overflow-W4YLQ7yY.js +1 -0
- package/src/assets/web-panel/assets/{OverrideContext-GHsJf9ok.js → OverrideContext-Nubhv68k.js} +1 -1
- package/src/assets/web-panel/assets/P2P-Cx88UaiD.css +1 -0
- package/src/assets/web-panel/assets/P2P-kVj43R4j.js +2 -0
- package/src/assets/web-panel/assets/Permissions-CfYE4XFJ.js +4 -0
- package/src/assets/web-panel/assets/Pipeline-BVLo32Ak.js +1 -0
- package/src/assets/web-panel/assets/Pipeline-DxkXqrH2.css +1 -0
- package/src/assets/web-panel/assets/Privacy-CrsfSFKd.css +1 -0
- package/src/assets/web-panel/assets/Privacy-Efyb3xpJ.js +1 -0
- package/src/assets/web-panel/assets/ProjectSettings-cBqrIhNN.js +2 -0
- package/src/assets/web-panel/assets/Projects-B5IgXt-x.css +1 -0
- package/src/assets/web-panel/assets/Projects-BYY38oZd.js +2 -0
- package/src/assets/web-panel/assets/Providers-BsS27cWs.js +2 -0
- package/src/assets/web-panel/assets/QuickAsk-6FgX9DC6.js +1 -0
- package/src/assets/web-panel/assets/Recommend-BvMXwWFN.js +1 -0
- package/src/assets/web-panel/assets/Recommend-CH6wKzGo.css +1 -0
- package/src/assets/web-panel/assets/Reputation-D6VPNEd0.css +1 -0
- package/src/assets/web-panel/assets/Reputation-DmwTtBfl.js +1 -0
- package/src/assets/web-panel/assets/Row-N-X7EJ3w.js +1 -0
- package/src/assets/web-panel/assets/RssFeed-D9TjnwgF.js +3 -0
- package/src/assets/web-panel/assets/Search-B6RalzTB.css +1 -0
- package/src/assets/web-panel/assets/Search-Hapv-QkV.js +1 -0
- package/src/assets/web-panel/assets/Security-13K57V_v.css +1 -0
- package/src/assets/web-panel/assets/Security-DWbFJK10.js +4 -0
- package/src/assets/web-panel/assets/Services-BPUmhVoH.js +2 -0
- package/src/assets/web-panel/assets/Skeleton-Bo5qPHbE.js +8 -0
- package/src/assets/web-panel/assets/Skills-JJ8uInMW.js +1 -0
- package/src/assets/web-panel/assets/Sla-CEDF9zdV.js +1 -0
- package/src/assets/web-panel/assets/Sla-K19oOyQc.css +1 -0
- package/src/assets/web-panel/assets/SpeechSettings-DYPJTDKz.css +1 -0
- package/src/assets/web-panel/assets/SpeechSettings-oIoX_vCx.js +1 -0
- package/src/assets/web-panel/assets/Tasks-Cx5wgv5Z.js +1 -0
- package/src/assets/web-panel/assets/Templates-BWTV8-2E.css +1 -0
- package/src/assets/web-panel/assets/Templates-BomcBlkN.js +1 -0
- package/src/assets/web-panel/assets/Tenant-BxSQZUNh.js +1 -0
- package/src/assets/web-panel/assets/Tenant-D3zkSAV0.css +1 -0
- package/src/assets/web-panel/assets/Tokens-BBOdNRHQ.css +1 -0
- package/src/assets/web-panel/assets/Tokens-BlPPoB3C.js +1 -0
- package/src/assets/web-panel/assets/Trigger-Bhjmjsc5.js +1 -0
- package/src/assets/web-panel/assets/Trust-DeOo0xAh.css +1 -0
- package/src/assets/web-panel/assets/Trust-Dsjv7rkb.js +1 -0
- package/src/assets/web-panel/assets/UkeySign-Cux8_Ib_.js +1 -0
- package/src/assets/web-panel/assets/VideoEditing-BsVR1PN8.js +1 -0
- package/src/assets/web-panel/assets/VideoEditing-DksiizfS.css +1 -0
- package/src/assets/web-panel/assets/Wallet-dcRAYsdL.js +4 -0
- package/src/assets/web-panel/assets/Wallet-gR0ZvZbK.css +1 -0
- package/src/assets/web-panel/assets/WebAuthn-SSh5VhVO.css +1 -0
- package/src/assets/web-panel/assets/WebAuthn-oqIS5PCi.js +5 -0
- package/src/assets/web-panel/assets/WorkflowEditor-C_fYMBvB.js +1 -0
- package/src/assets/web-panel/assets/WorkflowEditor-IiwsD8Kh.css +1 -0
- package/src/assets/web-panel/assets/{chat-DY27mJje.js → chat-BQ-Nk2XY.js} +1 -1
- package/src/assets/web-panel/assets/{collapseMotion-CyadT_6x.js → collapseMotion-BIjDVXtT.js} +1 -1
- package/src/assets/web-panel/assets/{colors-B7fDvuJc.js → colors-D2P6CqS5.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DgthOVXi.js → compact-item-CG7qutT_.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Blw2vgkG.js → createContext-y4UPKgbA.js} +1 -1
- package/src/assets/web-panel/assets/echarts-DmBLM6YO.js +19 -0
- package/src/assets/web-panel/assets/{hasIn-BfL1HJZl.js → hasIn-Butbu9jZ.js} +1 -1
- package/src/assets/web-panel/assets/icons-DvZE-RKs.js +57 -0
- package/src/assets/web-panel/assets/index-38mVlGHc.js +1 -0
- package/src/assets/web-panel/assets/{index-x8iHfZRd.js → index-89HJLKZ-.js} +3 -3
- package/src/assets/web-panel/assets/index-B4Jfv4EB.js +1 -0
- package/src/assets/web-panel/assets/index-B5FRjJMb.js +1 -0
- package/src/assets/web-panel/assets/{index-00RNC3ZQ.js → index-B6U6cYUa.js} +8 -8
- package/src/assets/web-panel/assets/index-B7FV5EnN.js +1 -0
- package/src/assets/web-panel/assets/index-BCQ0WlB2.js +1 -0
- package/src/assets/web-panel/assets/index-BEfvpbz-.js +1 -0
- package/src/assets/web-panel/assets/index-BJN_3RTO.js +1 -0
- package/src/assets/web-panel/assets/index-BQfow_sh.js +1 -0
- package/src/assets/web-panel/assets/index-BQr8Y0o5.js +1 -0
- package/src/assets/web-panel/assets/index-BYZPJS7A.js +1 -0
- package/src/assets/web-panel/assets/index-Bs9aHxDD.js +13 -0
- package/src/assets/web-panel/assets/index-BtuwtDUE.js +1 -0
- package/src/assets/web-panel/assets/index-BvJgRWBq.js +3 -0
- package/src/assets/web-panel/assets/index-C1mK1Ga3.js +1 -0
- package/src/assets/web-panel/assets/index-C1ucrJLg.js +1 -0
- package/src/assets/web-panel/assets/index-C2K61jP8.js +55 -0
- package/src/assets/web-panel/assets/index-CAeKBs9n.js +1 -0
- package/src/assets/web-panel/assets/{index-CiN4NEAa.js → index-CWh3IxEh.js} +2 -2
- package/src/assets/web-panel/assets/{index-DyRzaN4b.js → index-CYlDKn3O.js} +3 -3
- package/src/assets/web-panel/assets/index-C_8hWf5_.js +6 -0
- package/src/assets/web-panel/assets/index-Cc77JZKd.js +1 -0
- package/src/assets/web-panel/assets/index-Ceaxjpqh.js +13 -0
- package/src/assets/web-panel/assets/index-CfX1DEtk.css +1 -0
- package/src/assets/web-panel/assets/index-Ci6jXp3l.js +7 -0
- package/src/assets/web-panel/assets/index-CyqU4Tck.js +65 -0
- package/src/assets/web-panel/assets/{index-BuEOhTAw.js → index-DLMJy9pE.js} +5 -5
- package/src/assets/web-panel/assets/index-DdgjeX4z.js +1 -0
- package/src/assets/web-panel/assets/index-DnI4Aq0q.js +3 -0
- package/src/assets/web-panel/assets/index-DrVnyYpX.js +1 -0
- package/src/assets/web-panel/assets/index-DtNHlrxp.js +1 -0
- package/src/assets/web-panel/assets/index-Dx_ZTZo_.js +1 -0
- package/src/assets/web-panel/assets/{index-BHnaIQEm.js → index-YmGOWX7h.js} +2 -2
- package/src/assets/web-panel/assets/index-gWmZm8_Q.js +21 -0
- package/src/assets/web-panel/assets/index-hSilB_Q-.js +12 -0
- package/src/assets/web-panel/assets/index-qXvwlbkq.js +3 -0
- package/src/assets/web-panel/assets/index-rIbVsjde.js +12 -0
- package/src/assets/web-panel/assets/{index-BsleJWGy.js → index-vC5cTycG.js} +2 -2
- package/src/assets/web-panel/assets/{initDefaultProps-BeWIEzBr.js → initDefaultProps-CZRZ-1bk.js} +1 -1
- package/src/assets/web-panel/assets/motion-CvU8SiWF.js +11 -0
- package/src/assets/web-panel/assets/move-ipAfWhya.js +4 -0
- package/src/assets/web-panel/assets/mtc-parser-pGMSt10g.js +1 -0
- package/src/assets/web-panel/assets/{omit-BS0H_YEP.js → omit-D6bJEjz9.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BOGgGau8.js → pickAttrs-Dpvzf7sL.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow--c5TQkDQ.js → placementArrow-D_tEolP1.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CrHOX7jp.js → responsiveObserve-BEFI7neO.js} +1 -1
- package/src/assets/web-panel/assets/slide-Bte_KOqM.js +4 -0
- package/src/assets/web-panel/assets/statusUtils-K4xaDRuO.js +1 -0
- package/src/assets/web-panel/assets/{styleChecker-CiDrXnbi.js → styleChecker-Cl9YgOVY.js} +1 -1
- package/src/assets/web-panel/assets/useFlexGapSupport-DNstl1wK.js +1 -0
- package/src/assets/web-panel/assets/useFs-BD-YRwbU.js +1 -0
- package/src/assets/web-panel/assets/{useMergedState-CLY-UHry.js → useMergedState-TP9VIF2K.js} +1 -1
- package/src/assets/web-panel/assets/{useRefs-HzOoMkZk.js → useRefs-BhIz_lC3.js} +1 -1
- package/src/assets/web-panel/assets/{useState-yWVBuz1S.js → useState-CpKsyozn.js} +1 -1
- package/src/assets/web-panel/assets/vendor-B6ToihkA.js +1 -0
- package/src/assets/web-panel/assets/vnode-ChB-8cXr.js +1 -0
- package/src/assets/web-panel/assets/{ws-4ur1fGsk.js → ws-D_5-FRIb.js} +1 -1
- package/src/assets/web-panel/assets/zoom-meTNBulL.js +4 -0
- package/src/assets/web-panel/index.html +4 -4
- package/src/commands/audit.js +296 -0
- package/src/commands/init.js +16 -1
- package/src/commands/mtc.js +1401 -86
- package/src/lib/audit-mtc.js +504 -0
- package/src/assets/web-panel/assets/AIOps-Bfzpnnlg.css +0 -1
- package/src/assets/web-panel/assets/AIOps-ztGJppiG.js +0 -1
- package/src/assets/web-panel/assets/ActionButton-DCuat-R-.js +0 -1
- package/src/assets/web-panel/assets/Analytics-BFI7jbwM.css +0 -1
- package/src/assets/web-panel/assets/Analytics-m_EtU-RR.js +0 -3
- package/src/assets/web-panel/assets/AppLayout-8HizVjee.css +0 -1
- package/src/assets/web-panel/assets/AppLayout-Crz8jbEC.js +0 -1
- package/src/assets/web-panel/assets/Audit-CNLWjMXN.js +0 -1
- package/src/assets/web-panel/assets/Audit-kU7vbN-D.css +0 -1
- package/src/assets/web-panel/assets/Backup-CggaSq9O.js +0 -1
- package/src/assets/web-panel/assets/Backup-DxLiJzmk.css +0 -1
- package/src/assets/web-panel/assets/BaseInput-BssiYvl6.js +0 -1
- package/src/assets/web-panel/assets/Chat-tuVfpQUO.js +0 -2
- package/src/assets/web-panel/assets/Checkbox-BUUkXdQg.js +0 -1
- package/src/assets/web-panel/assets/Codegen-AVAcL7NA.css +0 -1
- package/src/assets/web-panel/assets/Codegen-CHu-7YGr.js +0 -1
- package/src/assets/web-panel/assets/Col-2IaMFwmX.js +0 -1
- package/src/assets/web-panel/assets/Community-CYL7Fvjq.js +0 -1
- package/src/assets/web-panel/assets/Community-DqDfLQui.css +0 -1
- package/src/assets/web-panel/assets/Compact-5yRVELhA.js +0 -1
- package/src/assets/web-panel/assets/Compliance-CKuIDJHK.js +0 -1
- package/src/assets/web-panel/assets/Compliance-CKxw6vIq.css +0 -1
- package/src/assets/web-panel/assets/Cron-DIfkI7vf.js +0 -2
- package/src/assets/web-panel/assets/Crosschain-BkjY-lst.js +0 -1
- package/src/assets/web-panel/assets/Crosschain-DThGgQk8.css +0 -1
- package/src/assets/web-panel/assets/DID-BDvsVa08.css +0 -1
- package/src/assets/web-panel/assets/DID-ChzRkgNy.js +0 -2
- package/src/assets/web-panel/assets/Dashboard-Cviwdc26.css +0 -1
- package/src/assets/web-panel/assets/Dashboard-DKrbXVNn.js +0 -3
- package/src/assets/web-panel/assets/Dropdown-BYGoxH1z.js +0 -1
- package/src/assets/web-panel/assets/Federation-B8QX-IaA.js +0 -1
- package/src/assets/web-panel/assets/Federation-BftELHDw.css +0 -1
- package/src/assets/web-panel/assets/Git-BBnGgbBR.js +0 -2
- package/src/assets/web-panel/assets/Governance-BfmfQBGB.css +0 -1
- package/src/assets/web-panel/assets/Governance-CxUHZMsp.js +0 -1
- package/src/assets/web-panel/assets/Inference-BlnOG71q.js +0 -1
- package/src/assets/web-panel/assets/Inference-EFFc7eNZ.css +0 -1
- package/src/assets/web-panel/assets/Keyframes-C7fCrnlS.js +0 -1
- package/src/assets/web-panel/assets/KnowledgeGraph-U8ps3aGJ.css +0 -1
- package/src/assets/web-panel/assets/KnowledgeGraph-vkVq38kC.js +0 -19
- package/src/assets/web-panel/assets/Logs-Bxx7WARH.js +0 -2
- package/src/assets/web-panel/assets/Marketplace-B-4uYu_j.css +0 -1
- package/src/assets/web-panel/assets/Marketplace-Bh8ExT9_.js +0 -1
- package/src/assets/web-panel/assets/McpTools-CTQrNVAQ.css +0 -1
- package/src/assets/web-panel/assets/McpTools-Djj_a3ko.js +0 -5
- package/src/assets/web-panel/assets/Memory-DRghrGJr.css +0 -1
- package/src/assets/web-panel/assets/Memory-DlgNgAov.js +0 -2
- package/src/assets/web-panel/assets/NLProgramming-BN3jaoen.js +0 -1
- package/src/assets/web-panel/assets/NLProgramming-jURs-f-a.css +0 -1
- package/src/assets/web-panel/assets/Notes-De7mIkkV.js +0 -7
- package/src/assets/web-panel/assets/Organization-B-98mdK2.js +0 -4
- package/src/assets/web-panel/assets/Organization-DdOOM4ic.css +0 -1
- package/src/assets/web-panel/assets/Overflow-G0I8IlY3.js +0 -1
- package/src/assets/web-panel/assets/P2P-DIUgHZ1z.js +0 -2
- package/src/assets/web-panel/assets/P2P-OEzOeMZX.css +0 -1
- package/src/assets/web-panel/assets/Permissions-B8XycCVk.js +0 -4
- package/src/assets/web-panel/assets/Pipeline-DyqCLFVr.css +0 -1
- package/src/assets/web-panel/assets/Pipeline-cUpETlXS.js +0 -1
- package/src/assets/web-panel/assets/Portal-SsPhn64D.js +0 -1
- package/src/assets/web-panel/assets/Privacy-B6J89UBw.js +0 -1
- package/src/assets/web-panel/assets/Privacy-B_cAicd1.css +0 -1
- package/src/assets/web-panel/assets/ProjectSettings-2Ftw0zt_.js +0 -2
- package/src/assets/web-panel/assets/Projects-CcOdFpgr.js +0 -2
- package/src/assets/web-panel/assets/Projects-DxKelI5h.css +0 -1
- package/src/assets/web-panel/assets/Providers-D0r2qSf-.js +0 -2
- package/src/assets/web-panel/assets/QuickAsk-CwsPpfkq.js +0 -1
- package/src/assets/web-panel/assets/Recommend-BYEDetJm.js +0 -1
- package/src/assets/web-panel/assets/Recommend-DgNSCgRX.css +0 -1
- package/src/assets/web-panel/assets/Reputation-Bli4hBGH.js +0 -1
- package/src/assets/web-panel/assets/Reputation-y-46ThW8.css +0 -1
- package/src/assets/web-panel/assets/Row-DTW9_BYi.js +0 -1
- package/src/assets/web-panel/assets/RssFeed-kwj_himl.js +0 -3
- package/src/assets/web-panel/assets/Search-BTk9rglb.css +0 -1
- package/src/assets/web-panel/assets/Search-DymcqASO.js +0 -1
- package/src/assets/web-panel/assets/Security-Bh3yvyNN.js +0 -4
- package/src/assets/web-panel/assets/Security-Dwxw7rfP.css +0 -1
- package/src/assets/web-panel/assets/Services-O4UZaYur.js +0 -2
- package/src/assets/web-panel/assets/Skeleton-B82oQZTz.js +0 -8
- package/src/assets/web-panel/assets/Skills-BfkrC05g.js +0 -1
- package/src/assets/web-panel/assets/Sla-C1WYuQKf.css +0 -1
- package/src/assets/web-panel/assets/Sla-DEs5XCIf.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-BWMhb10j.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-CiKvsIyV.css +0 -1
- package/src/assets/web-panel/assets/Tasks-CIBUb9M1.js +0 -1
- package/src/assets/web-panel/assets/Templates-DAkzr0xS.css +0 -1
- package/src/assets/web-panel/assets/Templates-iqSuJY-O.js +0 -1
- package/src/assets/web-panel/assets/Tenant-BJr-h-_0.css +0 -1
- package/src/assets/web-panel/assets/Tenant-CLqZjkVq.js +0 -1
- package/src/assets/web-panel/assets/Tokens-Bwz8aQtK.js +0 -1
- package/src/assets/web-panel/assets/Tokens-KvJRHQcl.css +0 -1
- package/src/assets/web-panel/assets/Trigger-CxnChVoS.js +0 -1
- package/src/assets/web-panel/assets/Trust-BLI308Ik.css +0 -1
- package/src/assets/web-panel/assets/Trust-Bp23lyZl.js +0 -1
- package/src/assets/web-panel/assets/UkeySign-_VAMquoh.js +0 -1
- package/src/assets/web-panel/assets/VideoEditing-BA1N-5kq.css +0 -1
- package/src/assets/web-panel/assets/VideoEditing-Bxqwg4zW.js +0 -1
- package/src/assets/web-panel/assets/Wallet-Cvht6Yrh.js +0 -4
- package/src/assets/web-panel/assets/Wallet-DnIumafl.css +0 -1
- package/src/assets/web-panel/assets/WebAuthn-CNPl2VQR.css +0 -1
- package/src/assets/web-panel/assets/WebAuthn-DD4EomJu.js +0 -5
- package/src/assets/web-panel/assets/WorkflowEditor-CEKNTS5G.css +0 -1
- package/src/assets/web-panel/assets/WorkflowEditor-CJy5e0fl.js +0 -1
- package/src/assets/web-panel/assets/_plugin-vue_export-helper-DlAUqK2U.js +0 -1
- package/src/assets/web-panel/assets/icons-CJACPYXu.js +0 -57
- package/src/assets/web-panel/assets/index-B9B9Zbf3.js +0 -1
- package/src/assets/web-panel/assets/index-BAsMNMbh.js +0 -1
- package/src/assets/web-panel/assets/index-BB5y5Y0z.js +0 -14
- package/src/assets/web-panel/assets/index-BVjDIZQ4.js +0 -1
- package/src/assets/web-panel/assets/index-BZeRnzuY.js +0 -55
- package/src/assets/web-panel/assets/index-BZfoAtZC.js +0 -1
- package/src/assets/web-panel/assets/index-Bl2nXm2J.js +0 -13
- package/src/assets/web-panel/assets/index-Bw1dwHWm.js +0 -1
- package/src/assets/web-panel/assets/index-Bw_UV2ez.js +0 -13
- package/src/assets/web-panel/assets/index-C8GYpC65.js +0 -1
- package/src/assets/web-panel/assets/index-CBHlKa-J.js +0 -3
- package/src/assets/web-panel/assets/index-CL-7KCFI.js +0 -3
- package/src/assets/web-panel/assets/index-CqjUUbil.js +0 -12
- package/src/assets/web-panel/assets/index-Cqtt1N0F.js +0 -1
- package/src/assets/web-panel/assets/index-CyGyEIVX.css +0 -1
- package/src/assets/web-panel/assets/index-D1QP9Ue1.js +0 -1
- package/src/assets/web-panel/assets/index-D6BUjL6I.js +0 -1
- package/src/assets/web-panel/assets/index-DN7ywgBJ.js +0 -1
- package/src/assets/web-panel/assets/index-DasW8LIs.js +0 -1
- package/src/assets/web-panel/assets/index-Dd9McFt_.js +0 -1
- package/src/assets/web-panel/assets/index-DdzLEdL6.js +0 -7
- package/src/assets/web-panel/assets/index-DhML6F3z.js +0 -1
- package/src/assets/web-panel/assets/index-DjN0nHiV.js +0 -1
- package/src/assets/web-panel/assets/index-DjhWpiZW.js +0 -1
- package/src/assets/web-panel/assets/index-DouFuKIR.js +0 -1
- package/src/assets/web-panel/assets/index-DzWwjWYN.js +0 -21
- package/src/assets/web-panel/assets/index-Dza_w3kG.js +0 -1
- package/src/assets/web-panel/assets/index-Q4qgOtOe.js +0 -12
- package/src/assets/web-panel/assets/index-U4Zd5IK6.js +0 -8
- package/src/assets/web-panel/assets/index-Vit9TJBu.js +0 -36
- package/src/assets/web-panel/assets/index-lkJllVbJ.js +0 -6
- package/src/assets/web-panel/assets/index-uMWaXVtR.js +0 -3
- package/src/assets/web-panel/assets/index-uwh_ikIt.js +0 -1
- package/src/assets/web-panel/assets/motion-CIQOKmi6.js +0 -11
- package/src/assets/web-panel/assets/move-ZgRPlBji.js +0 -4
- package/src/assets/web-panel/assets/slide-Dd2mJUD0.js +0 -4
- package/src/assets/web-panel/assets/statusUtils-5QFvAofV.js +0 -1
- package/src/assets/web-panel/assets/transition-CVd2ueaJ.js +0 -1
- package/src/assets/web-panel/assets/useConfigInject-DIkkDpt1.js +0 -2
- package/src/assets/web-panel/assets/useFlexGapSupport-rrtj6f1h.js +0 -1
- package/src/assets/web-panel/assets/useFs-CK8VYPus.js +0 -1
- package/src/assets/web-panel/assets/vendor-D0Qjn73K.js +0 -1
- package/src/assets/web-panel/assets/vnode-xRp-KMjS.js +0 -1
- package/src/assets/web-panel/assets/zoom-CrI_kdTW.js +0 -4
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit MTC double-track scaffolding (Phase 2 audit, off-by-default).
|
|
3
|
+
*
|
|
4
|
+
* Design ref: docs/design/默克尔树证书_MTC_落地方案.md §6.3 + 评审清单 §7.
|
|
5
|
+
* Compliance status (2026-05-01): Q-COMP-1 (等保三级最终性窗口) + Q-COMP-2
|
|
6
|
+
* (T/ZGCMCA 023—2025 条款摘要) legal sign-off received. This module still
|
|
7
|
+
* ships `enabled=false` so each tenant decides when to switch on for their
|
|
8
|
+
* own org via explicit `cc audit mtc enable`. See landing plan §14.2.
|
|
9
|
+
*
|
|
10
|
+
* Layout under <configDir>/audit-mtc/:
|
|
11
|
+
* config.json enabled, batch_interval_seconds, namespace_prefix, issuer, ...
|
|
12
|
+
* keys/issuer.hex Ed25519 secret key (0o600)
|
|
13
|
+
* staging/<event-id>.json one Ed25519-signed event per file (track 1: realtime)
|
|
14
|
+
* batches/<batch-id>/ one closed batch:
|
|
15
|
+
* manifest.json schema=audit-batch-manifest/v1, batch_id, tree_head_id, event_ids, ...
|
|
16
|
+
* landmark.json MTC landmark (track 2: batch finality)
|
|
17
|
+
* envelope-<event-id>.json one per event with inclusion_proof
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import fs from "node:fs";
|
|
21
|
+
import path from "node:path";
|
|
22
|
+
import crypto from "node:crypto";
|
|
23
|
+
import { ed25519 as nobleEd25519 } from "@noble/curves/ed25519";
|
|
24
|
+
import mtcLib from "@chainlesschain/core-mtc";
|
|
25
|
+
|
|
26
|
+
const { sha256, jcs, encodeHashStr, ed25519, assembleBatch } = mtcLib;
|
|
27
|
+
|
|
28
|
+
const CONFIG_DEFAULTS = Object.freeze({
|
|
29
|
+
enabled: false,
|
|
30
|
+
// 3600 = Q-COMP-1 lenient path (approved unless legal requires sub-minute finality);
|
|
31
|
+
// 60 = strict path; both fully supported, just flip the number.
|
|
32
|
+
batch_interval_seconds: 3600,
|
|
33
|
+
namespace_prefix: "mtc/v1/audit/local",
|
|
34
|
+
issuer: "mtca:cc:audit-local",
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const SCHEMA_EVENT = "audit-event/v1";
|
|
38
|
+
const SCHEMA_MANIFEST = "audit-batch-manifest/v1";
|
|
39
|
+
|
|
40
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
41
|
+
// Path helpers
|
|
42
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
export function getAuditMtcDir(configDir) {
|
|
45
|
+
if (!configDir) throw new Error("getAuditMtcDir: configDir required");
|
|
46
|
+
return path.join(configDir, "audit-mtc");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function configPath(dir) {
|
|
50
|
+
return path.join(dir, "config.json");
|
|
51
|
+
}
|
|
52
|
+
function stagingDir(dir) {
|
|
53
|
+
return path.join(dir, "staging");
|
|
54
|
+
}
|
|
55
|
+
function batchesDir(dir) {
|
|
56
|
+
return path.join(dir, "batches");
|
|
57
|
+
}
|
|
58
|
+
function keyPath(dir) {
|
|
59
|
+
return path.join(dir, "keys", "issuer.hex");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function ensureDirs(dir) {
|
|
63
|
+
for (const p of [
|
|
64
|
+
dir,
|
|
65
|
+
stagingDir(dir),
|
|
66
|
+
batchesDir(dir),
|
|
67
|
+
path.dirname(keyPath(dir)),
|
|
68
|
+
]) {
|
|
69
|
+
if (!fs.existsSync(p)) fs.mkdirSync(p, { recursive: true });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
74
|
+
// Config
|
|
75
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
76
|
+
|
|
77
|
+
export function loadAuditMtcConfig(dir) {
|
|
78
|
+
ensureDirs(dir);
|
|
79
|
+
const p = configPath(dir);
|
|
80
|
+
if (!fs.existsSync(p)) return { ...CONFIG_DEFAULTS };
|
|
81
|
+
try {
|
|
82
|
+
const raw = JSON.parse(fs.readFileSync(p, "utf-8"));
|
|
83
|
+
return { ...CONFIG_DEFAULTS, ...raw };
|
|
84
|
+
} catch (err) {
|
|
85
|
+
throw new Error(`audit-mtc config malformed at ${p}: ${err.message}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function saveAuditMtcConfig(dir, patch) {
|
|
90
|
+
ensureDirs(dir);
|
|
91
|
+
const merged = { ...loadAuditMtcConfig(dir), ...patch };
|
|
92
|
+
// Validate
|
|
93
|
+
if (typeof merged.enabled !== "boolean") {
|
|
94
|
+
throw new TypeError("config.enabled must be boolean");
|
|
95
|
+
}
|
|
96
|
+
if (
|
|
97
|
+
!Number.isInteger(merged.batch_interval_seconds) ||
|
|
98
|
+
merged.batch_interval_seconds < 1
|
|
99
|
+
) {
|
|
100
|
+
throw new RangeError(
|
|
101
|
+
"config.batch_interval_seconds must be positive integer",
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
if (typeof merged.namespace_prefix !== "string" || !merged.namespace_prefix) {
|
|
105
|
+
throw new TypeError("config.namespace_prefix must be non-empty string");
|
|
106
|
+
}
|
|
107
|
+
if (typeof merged.issuer !== "string" || !merged.issuer) {
|
|
108
|
+
throw new TypeError("config.issuer must be non-empty string");
|
|
109
|
+
}
|
|
110
|
+
fs.writeFileSync(configPath(dir), JSON.stringify(merged, null, 2), "utf-8");
|
|
111
|
+
return merged;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
115
|
+
// Key management — Ed25519 issuer key for tree-head signing.
|
|
116
|
+
// SLH-DSA swap-out is a one-line change here when @noble/post-quantum lands.
|
|
117
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
function readIssuerKeyFile(p) {
|
|
120
|
+
const secretKey = Buffer.from(fs.readFileSync(p, "utf-8").trim(), "hex");
|
|
121
|
+
if (secretKey.length !== 32) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
`issuer key file ${p} must contain 32 bytes (64 hex chars)`,
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
const publicKey = Buffer.from(nobleEd25519.getPublicKey(secretKey));
|
|
127
|
+
return { secretKey, publicKey, pubkeyId: ed25519.pubkeyId(publicKey) };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function loadOrCreateIssuerKey(dir) {
|
|
131
|
+
ensureDirs(dir);
|
|
132
|
+
const p = keyPath(dir);
|
|
133
|
+
if (fs.existsSync(p)) {
|
|
134
|
+
return readIssuerKeyFile(p);
|
|
135
|
+
}
|
|
136
|
+
// Race-safe create: 'wx' flag fails with EEXIST if another writer beat us;
|
|
137
|
+
// in that case re-read what they wrote so all callers agree on one key.
|
|
138
|
+
// audit-mtc stays on Ed25519 for both realtime and tree-head signatures
|
|
139
|
+
// (small/fast sig is the realtime track's value prop). SLH-DSA opt-in
|
|
140
|
+
// is exposed at the cc mtc batch* / publish-skills surfaces only.
|
|
141
|
+
const keys = ed25519.generateKeyPair();
|
|
142
|
+
try {
|
|
143
|
+
fs.writeFileSync(p, keys.secretKey.toString("hex"), {
|
|
144
|
+
mode: 0o600,
|
|
145
|
+
flag: "wx",
|
|
146
|
+
});
|
|
147
|
+
return keys;
|
|
148
|
+
} catch (err) {
|
|
149
|
+
if (err.code !== "EEXIST") throw err;
|
|
150
|
+
return readIssuerKeyFile(p);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
155
|
+
// Track 1: emit — write event with realtime Ed25519 signature
|
|
156
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
157
|
+
|
|
158
|
+
function makeEventId() {
|
|
159
|
+
// Time-prefixed so listing by name = chronological order within a batch.
|
|
160
|
+
const ts = new Date().toISOString().replace(/[-:T]/g, "").slice(0, 14);
|
|
161
|
+
const rand = crypto.randomBytes(6).toString("hex");
|
|
162
|
+
return `${ts}-${rand}`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Submit one audit event. Always writes an Ed25519-signed staging file
|
|
167
|
+
* (so the event is queryable + cryptographically pinned within milliseconds).
|
|
168
|
+
* The event will land in a Merkle batch on the next reconcile() call.
|
|
169
|
+
*
|
|
170
|
+
* @param {string} dir - audit-mtc root
|
|
171
|
+
* @param {object} body - { event_type, operation, actor?, target?, details?, risk_level?, occurred_at? }
|
|
172
|
+
* @param {object} [opts]
|
|
173
|
+
* @param {boolean} [opts.requireEnabled=true] - when false, allow emit even if config.enabled=false (for tests/admin)
|
|
174
|
+
*/
|
|
175
|
+
export function emitEvent(dir, body, opts = {}) {
|
|
176
|
+
ensureDirs(dir);
|
|
177
|
+
const cfg = loadAuditMtcConfig(dir);
|
|
178
|
+
const requireEnabled = opts.requireEnabled !== false;
|
|
179
|
+
if (requireEnabled && !cfg.enabled) {
|
|
180
|
+
const e = new Error(
|
|
181
|
+
"audit-mtc disabled: run `cc audit mtc enable` to activate (or pass --force for one-off admin/CI use)",
|
|
182
|
+
);
|
|
183
|
+
e.code = "AUDIT_MTC_DISABLED";
|
|
184
|
+
throw e;
|
|
185
|
+
}
|
|
186
|
+
if (!body || typeof body !== "object") {
|
|
187
|
+
throw new TypeError("emitEvent: body must be an object");
|
|
188
|
+
}
|
|
189
|
+
if (!body.event_type || !body.operation) {
|
|
190
|
+
throw new TypeError(
|
|
191
|
+
"emitEvent: body.event_type and body.operation required",
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const keys = loadOrCreateIssuerKey(dir);
|
|
196
|
+
const eventId = makeEventId();
|
|
197
|
+
const occurredAt = body.occurred_at || new Date().toISOString();
|
|
198
|
+
|
|
199
|
+
const normalizedBody = {
|
|
200
|
+
event_type: body.event_type,
|
|
201
|
+
operation: body.operation,
|
|
202
|
+
actor: body.actor || null,
|
|
203
|
+
target: body.target || null,
|
|
204
|
+
details: body.details || null,
|
|
205
|
+
risk_level: body.risk_level || "low",
|
|
206
|
+
occurred_at: occurredAt,
|
|
207
|
+
};
|
|
208
|
+
const contentHash = encodeHashStr(sha256(jcs(normalizedBody)));
|
|
209
|
+
|
|
210
|
+
const signingInput = Buffer.concat([
|
|
211
|
+
Buffer.from("audit-event/v1\n", "utf-8"),
|
|
212
|
+
Buffer.from(contentHash, "utf-8"),
|
|
213
|
+
]);
|
|
214
|
+
const sig = ed25519.signRaw(signingInput, keys.secretKey);
|
|
215
|
+
|
|
216
|
+
const record = {
|
|
217
|
+
schema: SCHEMA_EVENT,
|
|
218
|
+
event_id: eventId,
|
|
219
|
+
body: normalizedBody,
|
|
220
|
+
content_hash: contentHash,
|
|
221
|
+
ed25519_sig: {
|
|
222
|
+
alg: "Ed25519",
|
|
223
|
+
pubkey_id: ed25519.pubkeyId(keys.publicKey),
|
|
224
|
+
sig: sig.toString("base64url"),
|
|
225
|
+
},
|
|
226
|
+
queued_at: new Date().toISOString(),
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const filePath = path.join(stagingDir(dir), `${eventId}.json`);
|
|
230
|
+
fs.writeFileSync(filePath, JSON.stringify(record, null, 2), "utf-8");
|
|
231
|
+
return { eventId, path: filePath, record };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
235
|
+
// Track 2: reconcile — close current batch, build tree, write envelopes.
|
|
236
|
+
// Idempotent: re-running with no staging events is a no-op; caller can
|
|
237
|
+
// drive it on a timer (config.batch_interval_seconds) without coordination.
|
|
238
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
239
|
+
|
|
240
|
+
function nextBatchId(dir) {
|
|
241
|
+
const existing = fs.existsSync(batchesDir(dir))
|
|
242
|
+
? fs.readdirSync(batchesDir(dir)).filter((n) => /^\d{6}$/.test(n))
|
|
243
|
+
: [];
|
|
244
|
+
if (existing.length === 0) return "000001";
|
|
245
|
+
const max = existing
|
|
246
|
+
.map((n) => parseInt(n, 10))
|
|
247
|
+
.reduce((a, b) => Math.max(a, b), 0);
|
|
248
|
+
return String(max + 1).padStart(6, "0");
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function listStagingEvents(dir) {
|
|
252
|
+
const sd = stagingDir(dir);
|
|
253
|
+
if (!fs.existsSync(sd)) return [];
|
|
254
|
+
return fs
|
|
255
|
+
.readdirSync(sd)
|
|
256
|
+
.filter((n) => n.endsWith(".json"))
|
|
257
|
+
.sort() // event_id is time-prefixed → sort = chronological
|
|
258
|
+
.map((n) => {
|
|
259
|
+
const full = path.join(sd, n);
|
|
260
|
+
const expectedId = n.slice(0, -".json".length);
|
|
261
|
+
try {
|
|
262
|
+
const obj = JSON.parse(fs.readFileSync(full, "utf-8"));
|
|
263
|
+
if (obj.schema !== SCHEMA_EVENT) {
|
|
264
|
+
return {
|
|
265
|
+
eventId: null,
|
|
266
|
+
file: full,
|
|
267
|
+
error: `unexpected schema: ${obj.schema}`,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
if (obj.event_id !== expectedId) {
|
|
271
|
+
return {
|
|
272
|
+
eventId: null,
|
|
273
|
+
file: full,
|
|
274
|
+
error: `filename/event_id mismatch (file=${expectedId}, body=${obj.event_id})`,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
return { eventId: obj.event_id, file: full, record: obj };
|
|
278
|
+
} catch (err) {
|
|
279
|
+
return { eventId: null, file: full, error: err.message };
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Close the current batch: scan staging, build Merkle tree, emit landmark +
|
|
286
|
+
* one envelope per event, write manifest, and remove staging files.
|
|
287
|
+
*
|
|
288
|
+
* Returns `{ skipped: true }` when staging is empty (Q-OPS-1 idempotency).
|
|
289
|
+
*
|
|
290
|
+
* @param {string} dir
|
|
291
|
+
* @param {object} [opts]
|
|
292
|
+
* @param {string} [opts.namespace] - override config.namespace_prefix
|
|
293
|
+
* @param {string} [opts.issuer] - override config.issuer
|
|
294
|
+
*/
|
|
295
|
+
export function closeBatch(dir, opts = {}) {
|
|
296
|
+
ensureDirs(dir);
|
|
297
|
+
const cfg = loadAuditMtcConfig(dir);
|
|
298
|
+
const events = listStagingEvents(dir);
|
|
299
|
+
|
|
300
|
+
// Skip malformed entries — collected so caller can surface them
|
|
301
|
+
const malformed = events.filter((e) => e.error);
|
|
302
|
+
const valid = events.filter((e) => !e.error);
|
|
303
|
+
|
|
304
|
+
if (valid.length === 0) {
|
|
305
|
+
return { skipped: true, reason: "no staged events", malformed };
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const batchId = nextBatchId(dir);
|
|
309
|
+
const namespacePrefix = opts.namespace || cfg.namespace_prefix;
|
|
310
|
+
const namespace = `${namespacePrefix}/${batchId}`;
|
|
311
|
+
const issuer = opts.issuer || cfg.issuer;
|
|
312
|
+
const keys = loadOrCreateIssuerKey(dir);
|
|
313
|
+
|
|
314
|
+
// Leaves: hash the realtime event record (already Ed25519-signed) so the
|
|
315
|
+
// inclusion proof simultaneously proves "this event existed" + "in this batch".
|
|
316
|
+
const rawLeaves = valid.map((e) => ({
|
|
317
|
+
kind: "audit-event",
|
|
318
|
+
subject: e.eventId,
|
|
319
|
+
content_hash: e.record.content_hash,
|
|
320
|
+
queued_at: e.record.queued_at,
|
|
321
|
+
realtime_sig: e.record.ed25519_sig,
|
|
322
|
+
}));
|
|
323
|
+
|
|
324
|
+
const { landmark, envelopes, treeHeadId } = assembleBatch(rawLeaves, keys, {
|
|
325
|
+
namespace,
|
|
326
|
+
issuer,
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
// Atomic-ish write: stage in tmp dir under batches/, rename in.
|
|
330
|
+
const finalDir = path.join(batchesDir(dir), batchId);
|
|
331
|
+
if (fs.existsSync(finalDir)) {
|
|
332
|
+
// Defensive: nextBatchId already ensures this is a fresh number;
|
|
333
|
+
// if we're here it means a previous close crashed mid-rename — clean up.
|
|
334
|
+
fs.rmSync(finalDir, { recursive: true, force: true });
|
|
335
|
+
}
|
|
336
|
+
const tmpDir = path.join(batchesDir(dir), `.${batchId}.tmp`);
|
|
337
|
+
if (fs.existsSync(tmpDir))
|
|
338
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
339
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
340
|
+
|
|
341
|
+
fs.writeFileSync(
|
|
342
|
+
path.join(tmpDir, "landmark.json"),
|
|
343
|
+
JSON.stringify(landmark, null, 2),
|
|
344
|
+
"utf-8",
|
|
345
|
+
);
|
|
346
|
+
for (let i = 0; i < envelopes.length; i++) {
|
|
347
|
+
const env = envelopes[i];
|
|
348
|
+
const eventId = valid[i].eventId;
|
|
349
|
+
fs.writeFileSync(
|
|
350
|
+
path.join(tmpDir, `envelope-${eventId}.json`),
|
|
351
|
+
JSON.stringify(env, null, 2),
|
|
352
|
+
"utf-8",
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const manifest = {
|
|
357
|
+
schema: SCHEMA_MANIFEST,
|
|
358
|
+
batch_id: batchId,
|
|
359
|
+
namespace,
|
|
360
|
+
issuer,
|
|
361
|
+
tree_head_id: treeHeadId,
|
|
362
|
+
tree_size: valid.length,
|
|
363
|
+
closed_at: new Date().toISOString(),
|
|
364
|
+
event_ids: valid.map((e) => e.eventId),
|
|
365
|
+
envelope_files: valid.map((e) => `envelope-${e.eventId}.json`),
|
|
366
|
+
malformed_skipped: malformed.map((m) => ({ file: m.file, error: m.error })),
|
|
367
|
+
};
|
|
368
|
+
fs.writeFileSync(
|
|
369
|
+
path.join(tmpDir, "manifest.json"),
|
|
370
|
+
JSON.stringify(manifest, null, 2),
|
|
371
|
+
"utf-8",
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
fs.renameSync(tmpDir, finalDir);
|
|
375
|
+
|
|
376
|
+
// Remove staging files only AFTER the rename succeeds (so a crash before
|
|
377
|
+
// rename leaves staging intact and the next reconcile can retry).
|
|
378
|
+
for (const e of valid) {
|
|
379
|
+
try {
|
|
380
|
+
fs.unlinkSync(e.file);
|
|
381
|
+
} catch (_err) {
|
|
382
|
+
/* file may have been removed concurrently — non-fatal */
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return {
|
|
387
|
+
skipped: false,
|
|
388
|
+
batchId,
|
|
389
|
+
namespace,
|
|
390
|
+
treeHeadId,
|
|
391
|
+
treeSize: valid.length,
|
|
392
|
+
eventIds: valid.map((e) => e.eventId),
|
|
393
|
+
batchDir: finalDir,
|
|
394
|
+
malformed: manifest.malformed_skipped,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Find which closed batch contains the given event id.
|
|
400
|
+
* Returns { found: false } if event is still in staging or unknown.
|
|
401
|
+
*
|
|
402
|
+
* @param {string} dir
|
|
403
|
+
* @param {string} eventId
|
|
404
|
+
* @returns {{ found: boolean, batchId?: string, treeHeadId?: string, namespace?: string, leafIndex?: number, envelopePath?: string, staging?: boolean }}
|
|
405
|
+
*/
|
|
406
|
+
export function reconcileCheck(dir, eventId) {
|
|
407
|
+
ensureDirs(dir);
|
|
408
|
+
if (!eventId || typeof eventId !== "string") {
|
|
409
|
+
throw new TypeError("reconcileCheck: eventId required");
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Still in staging?
|
|
413
|
+
const stagingFile = path.join(stagingDir(dir), `${eventId}.json`);
|
|
414
|
+
if (fs.existsSync(stagingFile)) {
|
|
415
|
+
return { found: false, staging: true };
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const bd = batchesDir(dir);
|
|
419
|
+
if (!fs.existsSync(bd)) return { found: false };
|
|
420
|
+
const batches = fs
|
|
421
|
+
.readdirSync(bd)
|
|
422
|
+
.filter((n) => /^\d{6}$/.test(n))
|
|
423
|
+
.sort();
|
|
424
|
+
for (const batchId of batches) {
|
|
425
|
+
const manifestPath = path.join(bd, batchId, "manifest.json");
|
|
426
|
+
if (!fs.existsSync(manifestPath)) continue;
|
|
427
|
+
let manifest;
|
|
428
|
+
try {
|
|
429
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
430
|
+
} catch (_err) {
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
const idx = (manifest.event_ids || []).indexOf(eventId);
|
|
434
|
+
if (idx >= 0) {
|
|
435
|
+
return {
|
|
436
|
+
found: true,
|
|
437
|
+
batchId,
|
|
438
|
+
treeHeadId: manifest.tree_head_id,
|
|
439
|
+
namespace: manifest.namespace,
|
|
440
|
+
leafIndex: idx,
|
|
441
|
+
envelopePath: path.join(bd, batchId, `envelope-${eventId}.json`),
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return { found: false };
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Snapshot of queue + last-batch state. Cheap to compute, suitable for `cc audit mtc status`.
|
|
450
|
+
*/
|
|
451
|
+
export function getStatus(dir) {
|
|
452
|
+
ensureDirs(dir);
|
|
453
|
+
const cfg = loadAuditMtcConfig(dir);
|
|
454
|
+
const staging = listStagingEvents(dir);
|
|
455
|
+
const bd = batchesDir(dir);
|
|
456
|
+
const batches = fs.existsSync(bd)
|
|
457
|
+
? fs
|
|
458
|
+
.readdirSync(bd)
|
|
459
|
+
.filter((n) => /^\d{6}$/.test(n))
|
|
460
|
+
.sort()
|
|
461
|
+
: [];
|
|
462
|
+
let lastBatch = null;
|
|
463
|
+
if (batches.length > 0) {
|
|
464
|
+
const lastId = batches[batches.length - 1];
|
|
465
|
+
const manifestPath = path.join(bd, lastId, "manifest.json");
|
|
466
|
+
if (fs.existsSync(manifestPath)) {
|
|
467
|
+
try {
|
|
468
|
+
lastBatch = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
469
|
+
} catch (_err) {
|
|
470
|
+
/* malformed — treat as no-last-batch */
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
// Find oldest queued_at across valid records — guard against the
|
|
475
|
+
// alphabetically-first staging entry being malformed.
|
|
476
|
+
const oldestValid = staging.find((e) => e.record && e.record.queued_at);
|
|
477
|
+
return {
|
|
478
|
+
config: cfg,
|
|
479
|
+
staging: {
|
|
480
|
+
count: staging.length,
|
|
481
|
+
malformed: staging.filter((e) => e.error).length,
|
|
482
|
+
oldest_queued_at: oldestValid ? oldestValid.record.queued_at : null,
|
|
483
|
+
},
|
|
484
|
+
batches: {
|
|
485
|
+
count: batches.length,
|
|
486
|
+
last_batch_id: batches.length ? batches[batches.length - 1] : null,
|
|
487
|
+
last_closed_at: lastBatch ? lastBatch.closed_at : null,
|
|
488
|
+
last_tree_size: lastBatch ? lastBatch.tree_size : null,
|
|
489
|
+
last_tree_head_id: lastBatch ? lastBatch.tree_head_id : null,
|
|
490
|
+
},
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
export const _internals = {
|
|
495
|
+
CONFIG_DEFAULTS,
|
|
496
|
+
SCHEMA_EVENT,
|
|
497
|
+
SCHEMA_MANIFEST,
|
|
498
|
+
configPath,
|
|
499
|
+
stagingDir,
|
|
500
|
+
batchesDir,
|
|
501
|
+
keyPath,
|
|
502
|
+
nextBatchId,
|
|
503
|
+
listStagingEvents,
|
|
504
|
+
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.page-title[data-v-4713e815]{margin:0;color:var(--text-primary);font-size:22px;font-weight:600}.page-sub[data-v-4713e815]{margin:4px 0 0;color:var(--text-secondary);font-size:13px}.aiops-tabs[data-v-4713e815] .ant-tabs-nav{margin-bottom:16px}.filter-bar[data-v-4713e815]{display:flex;align-items:center;gap:12px;margin-bottom:12px;flex-wrap:wrap}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{u as Ke}from"./ws-4ur1fGsk.js";import{s as Ge}from"./community-parser-CO25nZFt.js";import{_ as He}from"./_plugin-vue_export-helper-DlAUqK2U.js";import{a as y}from"./index-BB5y5Y0z.js";import{_ as We,ah as Ze,A as se,R as ie,aJ as re,aQ as Xe,aA as Ye,a9 as et}from"./icons-CJACPYXu.js";import tt from"./index-x8iHfZRd.js";import{l as at,F as v,D as h,c as t,x as a,m as C,G as m,q as b,r as w,v as r,J as p,u as _,H as j,L as B,I as c,j as Se,h as ot,a as Z}from"./vendor-D0Qjn73K.js";import"./index-Vit9TJBu.js";import"./useConfigInject-DIkkDpt1.js";import"./transition-CVd2ueaJ.js";import"./Keyframes-C7fCrnlS.js";import"./Portal-SsPhn64D.js";import"./index-U4Zd5IK6.js";import"./KeyCode-D63Tfrq7.js";import"./omit-BS0H_YEP.js";import"./pickAttrs-BOGgGau8.js";import"./initDefaultProps-BeWIEzBr.js";import"./motion-CIQOKmi6.js";import"./raf-Deuc0E8-.js";import"./index-DhML6F3z.js";import"./index-Dd9McFt_.js";import"./isVisible-C7tPsqfj.js";import"./useState-yWVBuz1S.js";import"./devWarning-CNIS3FrJ.js";import"./warning-Pq00owYb.js";import"./compact-item-DgthOVXi.js";import"./createContext-Blw2vgkG.js";import"./Compact-5yRVELhA.js";import"./_getTag-CWA3v-Ds.js";import"./styleChecker-CiDrXnbi.js";import"./zoom-CrI_kdTW.js";import"./ActionButton-DCuat-R-.js";import"./vnode-xRp-KMjS.js";function E(l){const s=Ge(l);if(!s)return null;try{return JSON.parse(s)}catch{}const i=s.match(/\{[\s\S]*\}|\[[\s\S]*\]/);if(!i)return null;try{return JSON.parse(i[0])}catch{return null}}const ue=Object.freeze(["P0","P1","P2","P3"]),nt=Object.freeze(["open","acknowledged","resolved","closed"]);function k(l,s=0){return typeof l=="number"&&Number.isFinite(l)?l:s}function lt(l,s=0){if(!l||typeof l!="object")return null;const i=l.id||"";return i?{key:i,id:i,anomalyMetric:l.anomalyMetric??l.anomaly_metric??"",severity:String(l.severity||"P3"),status:String(l.status||"open").toLowerCase(),description:String(l.description||""),anomalyData:l.anomalyData??l.anomaly_data??null,remediationId:l.remediationId??l.remediation_id??null,postmortem:l.postmortem||"",acknowledgedAt:l.acknowledgedAt??l.acknowledged_at??null,resolvedAt:l.resolvedAt??l.resolved_at??null,createdAt:l.createdAt??l.created_at??null,_idx:s}:null}function st(l){const s=E(l);return Array.isArray(s)?s.map(lt).filter(Boolean):[]}function it(l,s=0){if(!l||typeof l!="object")return null;const i=l.id||"";if(!i)return null;const g=l.enabled;let O=!1;return g===!0||g===1||g==="1"?O=!0:g===!1||g===0||g==="0"?O=!1:O=!!g,{key:i,id:i,name:String(l.name||""),triggerCondition:l.triggerCondition??l.trigger_condition??"",steps:l.steps||"",enabled:O,successCount:k(l.successCount??l.success_count,0),failureCount:k(l.failureCount??l.failure_count,0),createdAt:l.createdAt??l.created_at??null,_idx:s}}function rt(l){const s=E(l);return Array.isArray(s)?s.map(it).filter(Boolean):[]}function ut(l,s=0){if(!l||typeof l!="object")return null;const i=l.metricName??l.metric_name??"";return i?{key:i,metricName:i,mean:k(l.mean,0),stdDev:k(l.stdDev??l.std_dev,0),q1:k(l.q1,0),q3:k(l.q3,0),sampleCount:k(l.sampleCount??l.sample_count,0),updatedAt:l.updatedAt??l.updated_at??null,_idx:s}:null}function dt(l){const s=E(l);return Array.isArray(s)?s.map(ut).filter(Boolean):[]}function ct(l){const s=E(l);return!s||typeof s!="object"||Array.isArray(s)?null:{anomaly:!!s.anomaly,reason:s.reason||null,metricName:s.metricName??s.metric_name??"",value:k(s.value,0),algorithm:String(s.algorithm||""),score:k(s.score,0),threshold:k(s.threshold,0),baseline:s.baseline?{mean:k(s.baseline.mean,0),stdDev:k(s.baseline.stdDev??s.baseline.std_dev,0),q1:k(s.baseline.q1,0),q3:k(s.baseline.q3,0)}:null,incidentId:s.incidentId??s.incident_id??null,severity:s.severity||null}}const pt={incidents:{total:0,bySeverity:{P0:0,P1:0,P2:0,P3:0},byStatus:{open:0,acknowledged:0,resolved:0,closed:0},avgResolveMs:0},playbooks:{total:0,enabled:0,totalSuccess:0,totalFailure:0},baselines:{total:0,metrics:[]}};function yt(l){const s=JSON.parse(JSON.stringify(pt)),i=E(l);if(!i||typeof i!="object"||Array.isArray(i))return s;if(i.incidents&&typeof i.incidents=="object"){if(s.incidents.total=k(i.incidents.total,0),s.incidents.avgResolveMs=k(i.incidents.avgResolveMs??i.incidents.avg_resolve_ms,0),i.incidents.bySeverity&&typeof i.incidents.bySeverity=="object")for(const g of Object.keys(s.incidents.bySeverity))s.incidents.bySeverity[g]=k(i.incidents.bySeverity[g],0);if(i.incidents.byStatus&&typeof i.incidents.byStatus=="object")for(const g of Object.keys(s.incidents.byStatus))s.incidents.byStatus[g]=k(i.incidents.byStatus[g],0)}return i.playbooks&&typeof i.playbooks=="object"&&(s.playbooks.total=k(i.playbooks.total,0),s.playbooks.enabled=k(i.playbooks.enabled,0),s.playbooks.totalSuccess=k(i.playbooks.totalSuccess??i.playbooks.total_success,0),s.playbooks.totalFailure=k(i.playbooks.totalFailure??i.playbooks.total_failure,0)),i.baselines&&typeof i.baselines=="object"&&(s.baselines.total=k(i.baselines.total,0),Array.isArray(i.baselines.metrics)&&(s.baselines.metrics=[...i.baselines.metrics])),s}function de(l){if(l==null||l==="")return"—";const s=typeof l=="number"?new Date(l):new Date(String(l));return isNaN(s.getTime())?String(l):s.toLocaleString("zh-CN",{hour12:!1})}const mt={style:{display:"flex","align-items":"center","justify-content":"space-between","margin-bottom":"24px"}},ft={style:{color:"var(--text-secondary)","font-size":"12px","margin-left":"8px"}},vt={class:"filter-bar"},bt={key:0,style:{color:"var(--text-primary)","font-family":"monospace","font-size":"12px"}},gt={key:1,style:{color:"var(--text-muted)"}},kt={key:2,style:{color:"var(--text-secondary)","font-size":"12px"}},_t={key:4,style:{color:"var(--text-secondary)","font-size":"11px"}},xt={style:{padding:"40px",color:"var(--text-muted)","text-align":"center"}},St={style:{color:"var(--text-primary)","font-weight":"500"}},Ct={key:0,style:{color:"var(--text-secondary)","font-size":"11px","margin-top":"2px","font-family":"monospace"}},wt={key:3,style:{color:"var(--text-secondary)","font-size":"11px"}},zt={style:{padding:"40px",color:"var(--text-muted)","text-align":"center"}},ht={key:0,style:{color:"var(--text-primary)","font-family":"monospace","font-weight":"500"}},At={style:{color:"#1677ff"}},Pt={style:{color:"var(--text-secondary)","margin-left":"4px","font-size":"11px"}},$t={key:2,style:{color:"var(--text-secondary)","font-size":"12px"}},jt={key:4,style:{color:"var(--text-secondary)","font-size":"11px"}},Nt={style:{padding:"40px",color:"var(--text-muted)","text-align":"center"}},Ot={key:0,style:{color:"var(--text-secondary)","font-size":"12px","margin-top":"8px"}},It={key:1,style:{"margin-top":"12px","font-size":"12px",color:"var(--text-secondary)"}},Jt={key:2,style:{"margin-top":"8px"}},Rt={__name:"AIOps",setup(l){const s=Ke(),i=w(!1),g=w(!1),O=w(!1),ce=w([]),pe=w([]),X=w([]),A=w({incidents:{total:0,bySeverity:{P0:0,P1:0,P2:0,P3:0},byStatus:{open:0,acknowledged:0,resolved:0,closed:0},avgResolveMs:0},playbooks:{total:0,enabled:0,totalSuccess:0,totalFailure:0},baselines:{total:0,metrics:[]}}),L=w("incidents"),T=w(""),D=w(""),V=w(!1),Q=w(!1),K=w(!1),Y=w(!1),z=Z({severity:"P3",metric:"",description:""}),x=Z({name:"",triggerJson:"",stepsJson:""}),I=Z({metric:"",values:""}),P=Z({metric:"",value:null,algorithm:"z_score"}),S=w(null),Ce=[{title:"严重度",key:"severity",width:"90px"},{title:"指标",key:"metric",width:"160px"},{title:"描述",key:"description"},{title:"状态",key:"status",width:"100px"},{title:"创建时间",key:"createdAt",width:"160px"},{title:"操作",key:"action",width:"220px"}],we=[{title:"名称",key:"name"},{title:"启用",key:"enabled",width:"80px"},{title:"执行统计",key:"stats",width:"180px"},{title:"创建时间",key:"createdAt",width:"160px"},{title:"操作",key:"action",width:"160px"}],ze=[{title:"指标",key:"metric"},{title:"均值 / σ",key:"mean",width:"180px"},{title:"四分位",key:"iqr",width:"180px"},{title:"样本数",key:"sampleCount",width:"90px"},{title:"更新时间",key:"updatedAt",width:"160px"}],he=Se(()=>A.value.incidents.byStatus.open+A.value.incidents.byStatus.acknowledged),Ae=Se(()=>{let o=ce.value;return T.value&&(o=o.filter(e=>e.severity===T.value)),D.value&&(o=o.filter(e=>e.status===D.value)),o});function ye(o){return{open:"待处理",acknowledged:"已确认",resolved:"已解决",closed:"已关闭"}[o]||o}function Pe(o){return{open:"red",acknowledged:"orange",resolved:"cyan",closed:"default"}[o]||"default"}function ee(o){return{P0:"red",P1:"volcano",P2:"orange",P3:"gold"}[o]||"default"}function $e(o){return{no_baseline:'该指标尚无基线,请先"更新基线"',zero_stddev:"基线方差为零(样本完全相同)",missing_metric_name:"缺少指标名",missing_value:"缺少测试值",unknown_algorithm:"未知算法"}[o]||o}function me(o,e){return o?o.length>e?o.slice(0,e)+"...":o:""}function je(o){return!o||o<=0?"—":o<1e3?`${o}ms`:o<6e4?`${(o/1e3).toFixed(1)}s`:o<36e5?`${(o/6e4).toFixed(1)}min`:`${(o/36e5).toFixed(1)}h`}function Ne({key:o}){o==="incident"?V.value=!0:o==="playbook"?Q.value=!0:o==="baseline"?K.value=!0:o==="detect"&&(S.value=null,Y.value=!0)}async function N(){i.value=!0;try{const[o,e,d,f]=await Promise.all([s.execute("ops incidents --limit 200 --json",1e4).catch(()=>({output:""})),s.execute("ops playbooks --limit 200 --json",1e4).catch(()=>({output:""})),s.execute("ops baselines --json",1e4).catch(()=>({output:""})),s.execute("ops stats --json",8e3).catch(()=>({output:""}))]);ce.value=st(o.output),pe.value=rt(e.output),X.value=dt(d.output),A.value=yt(f.output)}catch(o){y.error("加载 AIOps 数据失败: "+(o?.message||o))}finally{i.value=!1}}async function Oe(){if(!z.description.trim()){y.warning("请填写事件描述");return}g.value=!0;try{const o=[`ops incident-create --severity ${z.severity}`];z.metric.trim()&&o.push(`--metric "${z.metric.trim().replace(/"/g,'\\"')}"`),o.push(`--description "${z.description.trim().replace(/"/g,'\\"')}"`),o.push("--json");const{output:e}=await s.execute(o.join(" "),1e4);if(/error|失败/i.test(e)&&!/"incidentId"/.test(e)){y.error("创建失败: "+e.slice(0,120));return}y.success("事件已创建"),V.value=!1,ve(),await N()}catch(o){y.error("创建失败: "+(o?.message||o))}finally{g.value=!1}}async function Ie(){if(!x.name.trim()){y.warning("请填写 Playbook 名称");return}for(const[o,e]of[[x.triggerJson,"触发条件"],[x.stepsJson,"步骤"]])if(o.trim())try{JSON.parse(o)}catch{y.warning(`${e} JSON 格式错误`);return}g.value=!0;try{const o=[`ops playbook-create --name "${x.name.trim().replace(/"/g,'\\"')}"`];x.triggerJson.trim()&&o.push(`--trigger '${x.triggerJson.trim().replace(/'/g,"'\\''")}'`),x.stepsJson.trim()&&o.push(`--steps '${x.stepsJson.trim().replace(/'/g,"'\\''")}'`),o.push("--json");const{output:e}=await s.execute(o.join(" "),1e4);if(/error|失败/i.test(e)&&!/"playbookId"/.test(e)){y.error("创建失败: "+e.slice(0,120));return}y.success("Playbook 已创建"),Q.value=!1,be(),L.value="playbooks",await N()}catch(o){y.error("创建失败: "+(o?.message||o))}finally{g.value=!1}}async function Je(){const o=I.metric.trim();if(!o){y.warning("请填写指标名");return}const e=I.values.split(/[\s,]+/).map(d=>d.trim()).filter(Boolean).map(d=>Number(d));if(e.length===0||e.some(d=>!Number.isFinite(d))){y.warning("请输入至少一个有效数值(逗号或空白分隔)");return}g.value=!0;try{const d=`ops baseline-update "${o.replace(/"/g,'\\"')}" --values ${e.join(",")} --json`,{output:f}=await s.execute(d,1e4);if(/error|失败/i.test(f)&&!/"updated"/.test(f)){y.error("更新失败: "+f.slice(0,120));return}y.success(`基线已更新(n=${e.length})`),K.value=!1,ge(),L.value="baselines",await N()}catch(d){y.error("更新失败: "+(d?.message||d))}finally{g.value=!1}}async function Re(){if(!P.metric||P.value==null){y.warning("请选择指标并填写测试值");return}O.value=!0,S.value=null;try{const o=`ops detect "${P.metric.replace(/"/g,'\\"')}" ${P.value} --algorithm ${P.algorithm} --json`,{output:e}=await s.execute(o,8e3),d=ct(e);if(!d){y.error("检测失败: "+e.slice(0,120));return}S.value=d,d.anomaly&&(y.warning(`检测到异常 (${d.severity||"P3"})`),N())}catch(o){y.error("检测失败: "+(o?.message||o))}finally{O.value=!1}}async function Fe(o){await te(o,"incident-ack","事件已确认")}async function qe(o){await te(o,"incident-resolve","事件已解决")}async function Ue(o){await te(o,"incident-close","事件已关闭")}async function te(o,e,d){try{const{output:f}=await s.execute(`ops ${e} ${o.id} --json`,8e3);if(/error|失败|invalid/i.test(f)&&!/"acknowledged"|"resolved"|"closed"/.test(f)){y.error("转换失败: "+f.slice(0,120));return}y.success(d),await N()}catch(f){y.error("转换失败: "+(f?.message||f))}}async function Te(o){try{const{output:e}=await s.execute(`ops postmortem ${o.id}`,12e3);tt.info({title:`事件 ${o.id.slice(0,8)} 复盘`,width:720,content:()=>ot("pre",{style:"white-space: pre-wrap; max-height: 60vh; overflow: auto; font-size: 12px; padding: 8px; background: rgba(0,0,0,.04); border-radius: 4px;"},e||"(无内容)")})}catch(e){y.error("生成复盘失败: "+(e?.message||e))}}async function De(o,e){const d=e?"on":"off";try{const{output:f}=await s.execute(`ops playbook-toggle ${o.id} ${d} --json`,8e3);if(/error|失败/i.test(f)&&!/"enabled"/.test(f)){y.error("切换失败: "+f.slice(0,120));return}y.success(e?"Playbook 已启用":"Playbook 已禁用"),await N()}catch(f){y.error("切换失败: "+(f?.message||f))}}async function fe(o,e){try{const{output:d}=await s.execute(`ops playbook-record ${o.id} ${e} --json`,8e3);if(/error|失败/i.test(d)&&!/"recorded"/.test(d)){y.error("记录失败: "+d.slice(0,120));return}y.success(e==="success"?"已记录成功执行":"已记录失败执行"),await N()}catch(d){y.error("记录失败: "+(d?.message||d))}}function ve(){z.severity="P3",z.metric="",z.description=""}function be(){x.name="",x.triggerJson="",x.stepsJson=""}function ge(){I.metric="",I.values=""}return at(N),(o,e)=>{const d=b("a-button"),f=b("a-menu-item"),Me=b("a-menu"),Be=b("a-dropdown"),ke=b("a-space"),q=b("a-statistic"),J=b("a-card"),M=b("a-col"),Ee=b("a-row"),R=b("a-tag"),U=b("a-radio-button"),ae=b("a-radio-group"),oe=b("a-table"),ne=b("a-tab-pane"),Le=b("a-switch"),Ve=b("a-tabs"),_e=b("a-select-option"),xe=b("a-select"),$=b("a-form-item"),le=b("a-input"),G=b("a-textarea"),H=b("a-form"),W=b("a-modal"),Qe=b("a-input-number");return r(),v("div",null,[h("div",mt,[e[24]||(e[24]=h("div",null,[h("h2",{class:"page-title"},"AIOps 自治运维"),h("p",{class:"page-sub"},"异常检测 · 事件管理 · 自动化 Playbook")],-1)),t(ke,null,{default:a(()=>[t(d,{loading:i.value,onClick:N},{icon:a(()=>[t(_(We))]),default:a(()=>[e[18]||(e[18]=p(" 刷新 ",-1))]),_:1},8,["loading"]),t(Be,{trigger:["click"]},{overlay:a(()=>[t(Me,{onClick:Ne},{default:a(()=>[t(f,{key:"incident"},{default:a(()=>[t(_(se)),e[20]||(e[20]=p(" 创建事件",-1))]),_:1}),t(f,{key:"playbook"},{default:a(()=>[t(_(ie)),e[21]||(e[21]=p(" 创建 Playbook",-1))]),_:1}),t(f,{key:"baseline"},{default:a(()=>[t(_(re)),e[22]||(e[22]=p(" 更新基线",-1))]),_:1}),t(f,{key:"detect"},{default:a(()=>[t(_(Xe)),e[23]||(e[23]=p(" 异常检测",-1))]),_:1})]),_:1})]),default:a(()=>[t(d,{type:"primary"},{icon:a(()=>[t(_(Ze))]),default:a(()=>[e[19]||(e[19]=p(" 新建 ▼ ",-1))]),_:1})]),_:1})]),_:1})]),t(Ee,{gutter:[16,16],style:{"margin-bottom":"20px"}},{default:a(()=>[t(M,{xs:12,sm:8,lg:5},{default:a(()=>[t(J,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(q,{title:"事件总数",value:A.value.incidents.total,"value-style":{color:"#1677ff",fontSize:"20px"}},{prefix:a(()=>[t(_(se))]),_:1},8,["value"])]),_:1})]),_:1}),t(M,{xs:12,sm:8,lg:5},{default:a(()=>[t(J,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(q,{title:"待处理",value:A.value.incidents.byStatus.open+A.value.incidents.byStatus.acknowledged,"value-style":{color:he.value>0?"#ff4d4f":"#52c41a",fontSize:"20px"}},{prefix:a(()=>[t(_(Ye))]),_:1},8,["value","value-style"])]),_:1})]),_:1}),t(M,{xs:12,sm:8,lg:5},{default:a(()=>[t(J,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(q,{title:"Playbook",value:A.value.playbooks.total,"value-style":{color:"#722ed1",fontSize:"20px"}},{prefix:a(()=>[t(_(ie))]),_:1},8,["value"])]),_:1})]),_:1}),t(M,{xs:12,sm:8,lg:5},{default:a(()=>[t(J,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(q,{title:"启用 Playbook",value:A.value.playbooks.enabled,"value-style":{color:"#52c41a",fontSize:"20px"}},{prefix:a(()=>[t(_(et))]),_:1},8,["value"])]),_:1})]),_:1}),t(M,{xs:24,sm:8,lg:4},{default:a(()=>[t(J,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(q,{title:"基线指标",value:A.value.baselines.total,"value-style":{color:"#13c2c2",fontSize:"20px"}},{prefix:a(()=>[t(_(re))]),_:1},8,["value"])]),_:1})]),_:1})]),_:1}),A.value.incidents.total>0?(r(),C(J,{key:0,title:"严重度分布",size:"small",style:{background:"var(--bg-card)","border-color":"var(--border-color)","margin-bottom":"20px"},"body-style":{padding:"12px 16px"}},{default:a(()=>[t(ke,{size:[12,8],wrap:""},{default:a(()=>[(r(!0),v(j,null,B(_(ue),n=>(r(),C(R,{key:n,color:ee(n),style:{"font-size":"13px",padding:"2px 10px"}},{default:a(()=>[p(c(n)+": "+c(A.value.incidents.bySeverity[n]||0),1)]),_:2},1032,["color"]))),128)),h("span",ft," 平均解决时间: "+c(je(A.value.incidents.avgResolveMs)),1)]),_:1})]),_:1})):m("",!0),t(Ve,{activeKey:L.value,"onUpdate:activeKey":e[2]||(e[2]=n=>L.value=n),class:"aiops-tabs"},{default:a(()=>[t(ne,{key:"incidents",tab:"事件"},{default:a(()=>[h("div",vt,[t(ae,{value:T.value,"onUpdate:value":e[0]||(e[0]=n=>T.value=n),size:"small","button-style":"solid"},{default:a(()=>[t(U,{value:""},{default:a(()=>[...e[25]||(e[25]=[p("全部",-1)])]),_:1}),(r(!0),v(j,null,B(_(ue),n=>(r(),C(U,{key:n,value:n},{default:a(()=>[p(c(n),1)]),_:2},1032,["value"]))),128))]),_:1},8,["value"]),t(ae,{value:D.value,"onUpdate:value":e[1]||(e[1]=n=>D.value=n),size:"small"},{default:a(()=>[t(U,{value:""},{default:a(()=>[...e[26]||(e[26]=[p("全部状态",-1)])]),_:1}),(r(!0),v(j,null,B(_(nt),n=>(r(),C(U,{key:n,value:n},{default:a(()=>[p(c(ye(n)),1)]),_:2},1032,["value"]))),128))]),_:1},8,["value"])]),t(oe,{columns:Ce,"data-source":Ae.value,pagination:{pageSize:20,showTotal:n=>`共 ${n} 条`},size:"small",loading:i.value,style:{background:"var(--bg-card)"}},{bodyCell:a(({column:n,record:u})=>[n.key==="severity"?(r(),C(R,{key:0,color:ee(u.severity),style:{"font-weight":"600"}},{default:a(()=>[p(c(u.severity),1)]),_:2},1032,["color"])):m("",!0),n.key==="metric"?(r(),v(j,{key:1},[u.anomalyMetric?(r(),v("span",bt,c(u.anomalyMetric),1)):(r(),v("span",gt,"—"))],64)):m("",!0),n.key==="description"?(r(),v("span",kt,c(me(u.description,80)||"—"),1)):m("",!0),n.key==="status"?(r(),C(R,{key:3,color:Pe(u.status)},{default:a(()=>[p(c(ye(u.status)),1)]),_:2},1032,["color"])):m("",!0),n.key==="createdAt"?(r(),v("span",_t,c(_(de)(u.createdAt)),1)):m("",!0),n.key==="action"?(r(),v(j,{key:5},[u.status==="open"?(r(),C(d,{key:0,size:"small",type:"link",onClick:F=>Fe(u)},{default:a(()=>[...e[27]||(e[27]=[p("确认",-1)])]),_:1},8,["onClick"])):m("",!0),u.status==="open"||u.status==="acknowledged"?(r(),C(d,{key:1,size:"small",type:"link",onClick:F=>qe(u)},{default:a(()=>[...e[28]||(e[28]=[p("解决",-1)])]),_:1},8,["onClick"])):m("",!0),u.status==="resolved"?(r(),C(d,{key:2,size:"small",type:"link",onClick:F=>Ue(u)},{default:a(()=>[...e[29]||(e[29]=[p("关闭",-1)])]),_:1},8,["onClick"])):m("",!0),u.status==="resolved"||u.status==="closed"?(r(),C(d,{key:3,size:"small",type:"link",onClick:F=>Te(u)},{default:a(()=>[...e[30]||(e[30]=[p("复盘",-1)])]),_:1},8,["onClick"])):m("",!0)],64)):m("",!0)]),emptyText:a(()=>[h("div",xt,[t(_(se),{style:{"font-size":"36px","margin-bottom":"10px",display:"block"}}),p(" "+c(T.value||D.value?"没有符合条件的事件":'暂无事件,可点"新建 → 创建事件"或运行"异常检测"自动触发'),1)])]),_:1},8,["data-source","pagination","loading"])]),_:1}),t(ne,{key:"playbooks",tab:"Playbook"},{default:a(()=>[t(oe,{columns:we,"data-source":pe.value,pagination:{pageSize:20,showTotal:n=>`共 ${n} 条`},size:"small",loading:i.value,style:{background:"var(--bg-card)"}},{bodyCell:a(({column:n,record:u})=>[n.key==="name"?(r(),v(j,{key:0},[h("span",St,c(u.name),1),u.triggerCondition?(r(),v("div",Ct,c(me(u.triggerCondition,80)),1)):m("",!0)],64)):m("",!0),n.key==="enabled"?(r(),C(Le,{key:1,checked:u.enabled,size:"small",onChange:F=>De(u,F)},null,8,["checked","onChange"])):m("",!0),n.key==="stats"?(r(),v(j,{key:2},[t(R,{color:"green",style:{"font-size":"11px"}},{default:a(()=>[p("成功 "+c(u.successCount),1)]),_:2},1024),u.failureCount>0?(r(),C(R,{key:0,color:"red",style:{"font-size":"11px","margin-left":"4px"}},{default:a(()=>[p(" 失败 "+c(u.failureCount),1)]),_:2},1024)):m("",!0)],64)):m("",!0),n.key==="createdAt"?(r(),v("span",wt,c(_(de)(u.createdAt)),1)):m("",!0),n.key==="action"?(r(),v(j,{key:4},[t(d,{size:"small",type:"link",onClick:F=>fe(u,"success")},{default:a(()=>[...e[31]||(e[31]=[p("+ 成功",-1)])]),_:1},8,["onClick"]),t(d,{size:"small",type:"link",danger:"",onClick:F=>fe(u,"failure")},{default:a(()=>[...e[32]||(e[32]=[p("+ 失败",-1)])]),_:1},8,["onClick"])],64)):m("",!0)]),emptyText:a(()=>[h("div",zt,[t(_(ie),{style:{"font-size":"36px","margin-bottom":"10px",display:"block"}}),e[33]||(e[33]=p(' 暂无 Playbook,点"新建 → 创建 Playbook"创建第一个 ',-1))])]),_:1},8,["data-source","pagination","loading"])]),_:1}),t(ne,{key:"baselines",tab:"基线"},{default:a(()=>[t(oe,{columns:ze,"data-source":X.value,pagination:{pageSize:20,showTotal:n=>`共 ${n} 条`},size:"small",loading:i.value,style:{background:"var(--bg-card)"}},{bodyCell:a(({column:n,record:u})=>[n.key==="metric"?(r(),v("span",ht,c(u.metricName),1)):m("",!0),n.key==="mean"?(r(),v(j,{key:1},[h("span",At,c(u.mean),1),h("span",Pt,"σ "+c(u.stdDev),1)],64)):m("",!0),n.key==="iqr"?(r(),v("span",$t," Q1 "+c(u.q1)+" / Q3 "+c(u.q3),1)):m("",!0),n.key==="sampleCount"?(r(),C(R,{key:3,color:"blue",style:{"font-size":"11px"}},{default:a(()=>[p(c(u.sampleCount),1)]),_:2},1024)):m("",!0),n.key==="updatedAt"?(r(),v("span",jt,c(_(de)(u.updatedAt)),1)):m("",!0)]),emptyText:a(()=>[h("div",Nt,[t(_(re),{style:{"font-size":"36px","margin-bottom":"10px",display:"block"}}),e[34]||(e[34]=p(' 暂无基线,点"新建 → 更新基线"喂入指标样本 ',-1))])]),_:1},8,["data-source","pagination","loading"])]),_:1})]),_:1},8,["activeKey"]),t(W,{open:V.value,"onUpdate:open":e[6]||(e[6]=n=>V.value=n),title:"创建事件","confirm-loading":g.value,width:520,"ok-text":"创建","cancel-text":"取消",onOk:Oe,onCancel:ve},{default:a(()=>[t(H,{"label-col":{span:5},"wrapper-col":{span:19},style:{"margin-top":"16px"}},{default:a(()=>[t($,{label:"严重度"},{default:a(()=>[t(xe,{value:z.severity,"onUpdate:value":e[3]||(e[3]=n=>z.severity=n)},{default:a(()=>[(r(!0),v(j,null,B(_(ue),n=>(r(),C(_e,{key:n,value:n},{default:a(()=>[p(c(n),1)]),_:2},1032,["value"]))),128))]),_:1},8,["value"])]),_:1}),t($,{label:"指标"},{default:a(()=>[t(le,{value:z.metric,"onUpdate:value":e[4]||(e[4]=n=>z.metric=n),placeholder:"例如: cpu_usage(可选)"},null,8,["value"])]),_:1}),t($,{label:"描述",required:""},{default:a(()=>[t(G,{value:z.description,"onUpdate:value":e[5]||(e[5]=n=>z.description=n),"auto-size":{minRows:3,maxRows:6}},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"]),t(W,{open:Q.value,"onUpdate:open":e[10]||(e[10]=n=>Q.value=n),title:"创建 Playbook","confirm-loading":g.value,width:540,"ok-text":"创建","cancel-text":"取消",onOk:Ie,onCancel:be},{default:a(()=>[t(H,{"label-col":{span:5},"wrapper-col":{span:19},style:{"margin-top":"16px"}},{default:a(()=>[t($,{label:"名称",required:""},{default:a(()=>[t(le,{value:x.name,"onUpdate:value":e[7]||(e[7]=n=>x.name=n),placeholder:"restart-pod"},null,8,["value"])]),_:1}),t($,{label:"触发条件 (JSON)"},{default:a(()=>[t(G,{value:x.triggerJson,"onUpdate:value":e[8]||(e[8]=n=>x.triggerJson=n),placeholder:'{"metric":"cpu","threshold":90}',"auto-size":{minRows:2,maxRows:4}},null,8,["value"])]),_:1}),t($,{label:"步骤 (JSON)"},{default:a(()=>[t(G,{value:x.stepsJson,"onUpdate:value":e[9]||(e[9]=n=>x.stepsJson=n),placeholder:'[{"action":"restart","target":"pod-1"}]',"auto-size":{minRows:3,maxRows:6}},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"]),t(W,{open:K.value,"onUpdate:open":e[13]||(e[13]=n=>K.value=n),title:"更新基线","confirm-loading":g.value,width:500,"ok-text":"更新","cancel-text":"取消",onOk:Je,onCancel:ge},{default:a(()=>[t(H,{"label-col":{span:5},"wrapper-col":{span:19},style:{"margin-top":"16px"}},{default:a(()=>[t($,{label:"指标名",required:""},{default:a(()=>[t(le,{value:I.metric,"onUpdate:value":e[11]||(e[11]=n=>I.metric=n),placeholder:"cpu_usage"},null,8,["value"])]),_:1}),t($,{label:"样本值",required:""},{default:a(()=>[t(G,{value:I.values,"onUpdate:value":e[12]||(e[12]=n=>I.values=n),placeholder:"逗号分隔的数值,例如: 45.2, 47.1, 50.8, 49.3","auto-size":{minRows:3,maxRows:8}},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"]),t(W,{open:Y.value,"onUpdate:open":e[17]||(e[17]=n=>Y.value=n),title:"异常检测","confirm-loading":O.value,width:500,"ok-text":"检测","cancel-text":"关闭",onOk:Re},{default:a(()=>[t(H,{"label-col":{span:5},"wrapper-col":{span:19},style:{"margin-top":"16px"}},{default:a(()=>[t($,{label:"指标名",required:""},{default:a(()=>[t(xe,{value:P.metric,"onUpdate:value":e[14]||(e[14]=n=>P.metric=n),"show-search":"",placeholder:"选择已建立基线的指标"},{default:a(()=>[(r(!0),v(j,null,B(X.value,n=>(r(),C(_e,{key:n.metricName,value:n.metricName},{default:a(()=>[p(c(n.metricName)+"(n="+c(n.sampleCount)+") ",1)]),_:2},1032,["value"]))),128))]),_:1},8,["value"])]),_:1}),t($,{label:"测试值",required:""},{default:a(()=>[t(Qe,{value:P.value,"onUpdate:value":e[15]||(e[15]=n=>P.value=n),style:{width:"100%"}},null,8,["value"])]),_:1}),t($,{label:"算法"},{default:a(()=>[t(ae,{value:P.algorithm,"onUpdate:value":e[16]||(e[16]=n=>P.algorithm=n)},{default:a(()=>[t(U,{value:"z_score"},{default:a(()=>[...e[35]||(e[35]=[p("Z-Score (3σ)",-1)])]),_:1}),t(U,{value:"iqr"},{default:a(()=>[...e[36]||(e[36]=[p("IQR (1.5×)",-1)])]),_:1})]),_:1},8,["value"])]),_:1})]),_:1}),S.value?(r(),C(J,{key:0,size:"small",style:{background:"var(--bg-base)","margin-top":"8px"}},{default:a(()=>[t(q,{title:"检测结果",value:S.value.anomaly?"异常":"正常","value-style":{color:S.value.anomaly?"#ff4d4f":"#52c41a"}},null,8,["value","value-style"]),S.value.reason&&!S.value.anomaly?(r(),v("div",Ot," 原因: "+c($e(S.value.reason)),1)):m("",!0),S.value.baseline?(r(),v("div",It,[h("div",null,"得分: "+c(S.value.score)+" (阈值 "+c(S.value.threshold)+")",1),h("div",null,"基线: 均值 "+c(S.value.baseline.mean)+", σ "+c(S.value.baseline.stdDev),1)])):m("",!0),S.value.incidentId?(r(),v("div",Jt,[t(R,{color:ee(S.value.severity)},{default:a(()=>[p("已自动创建 "+c(S.value.severity)+" 事件",1)]),_:1},8,["color"])])):m("",!0)]),_:1})):m("",!0)]),_:1},8,["open","confirm-loading"])])}}},fa=He(Rt,[["__scopeId","data-v-4713e815"]]);export{fa as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{y as C,_ as i}from"./useConfigInject-DIkkDpt1.js";import{B as b,c as y}from"./index-DhML6F3z.js";import{o as m,s as r,d as O,l as P,c as R}from"./vendor-D0Qjn73K.js";import{o as x}from"./index-Vit9TJBu.js";const A=()=>{const n=r(!1);return m(()=>{n.value=!0}),n},D={type:{type:String},actionFn:Function,close:Function,autofocus:Boolean,prefixCls:String,buttonProps:x(),emitEvent:Boolean,quitOnNullishReturnValue:Boolean};function d(n){return!!(n&&n.then)}const E=O({compatConfig:{MODE:3},name:"ActionButton",props:D,setup(n,g){let{slots:B}=g;const l=r(!1),c=r(),a=r(!1);let f;const v=A();P(()=>{n.autofocus&&(f=setTimeout(()=>{var e,t;return(t=(e=C(c.value))===null||e===void 0?void 0:e.focus)===null||t===void 0?void 0:t.call(e)}))}),m(()=>{clearTimeout(f)});const u=function(){for(var e,t=arguments.length,o=new Array(t),s=0;s<t;s++)o[s]=arguments[s];(e=n.close)===null||e===void 0||e.call(n,...o)},h=e=>{d(e)&&(a.value=!0,e.then(function(){v.value||(a.value=!1),u(...arguments),l.value=!1},t=>(v.value||(a.value=!1),l.value=!1,Promise.reject(t))))},p=e=>{const{actionFn:t}=n;if(l.value)return;if(l.value=!0,!t){u();return}let o;if(n.emitEvent){if(o=t(e),n.quitOnNullishReturnValue&&!d(o)){l.value=!1,u(e);return}}else if(t.length)o=t(n.close),l.value=!1;else if(o=t(),!o){u();return}h(o)};return()=>{const{type:e,prefixCls:t,buttonProps:o}=n;return R(b,i(i(i({},y(e)),{},{onClick:p,loading:a.value,prefixCls:t},o),{},{ref:c}),B)}}});export{E as A};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
[data-v-bfaf911e] .analytics-row:hover td{background:var(--bg-card-hover)!important}[data-v-bfaf911e] .ant-card-head{border-color:var(--border-color)!important;color:var(--text-primary)!important}[data-v-bfaf911e] .ant-radio-button-wrapper{background:var(--bg-card)!important;border-color:var(--border-color)!important;color:var(--text-secondary)!important}[data-v-bfaf911e] .ant-radio-button-wrapper-checked{background:#1677ff!important;border-color:#1677ff!important;color:#fff!important}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{u as fe}from"./ws-4ur1fGsk.js";import{_ as ye}from"./_plugin-vue_export-helper-DlAUqK2U.js";import{_ as Y,z as Z,a as ee,as as me,at as xe,au as te}from"./icons-CJACPYXu.js";import{a as C}from"./index-BB5y5Y0z.js";import{w as ge,l as _e,F as p,D as z,c as o,x as s,r as y,q as m,a as E,v as n,J as d,u as T,m as I,I as x,G as g,H as Te}from"./vendor-D0Qjn73K.js";import"./index-Vit9TJBu.js";import"./useConfigInject-DIkkDpt1.js";import"./transition-CVd2ueaJ.js";import"./Keyframes-C7fCrnlS.js";import"./Portal-SsPhn64D.js";import"./index-U4Zd5IK6.js";const be={style:{display:"flex","align-items":"center","justify-content":"space-between","margin-bottom":"24px"}},he={style:{display:"flex","align-items":"center",gap:"12px"}},we={key:0,style:{"text-align":"center",padding:"60px"}},Se={key:1,style:{color:"#e0e0e0","font-family":"monospace","font-size":"12px"}},Ce={key:2,style:{color:"#faad14"}},Ie={key:3,style:{color:"var(--text-secondary)"}},ze={key:0,style:{"text-align":"center",padding:"60px"}},Re={key:0,style:{color:"var(--text-secondary)","font-size":"12px","font-family":"monospace"}},Oe={key:2,style:{color:"#e0e0e0","font-family":"monospace","font-size":"12px"}},je={key:3,style:{color:"#faad14"}},Me={key:4,style:{color:"var(--text-secondary)"}},Ue={key:0,style:{"text-align":"center",padding:"40px"}},Ne={key:1,style:{color:"#e0e0e0","font-family":"monospace","font-size":"12px"}},Be={key:0,style:{"text-align":"center",padding:"40px"}},De={__name:"Analytics",setup(Le){const w=fe(),R=y("all"),N=y(!1),B=y(!1),D=y(!1),L=y(!1),A=y(!1),J=y(!1),$=y(20),v=E({totalCalls:0,totalTokens:0,totalCost:0,avgResponseTime:0}),O=y([]),j=y([]),f=E({entries:0,hits:0,tokensSaved:0,expired:0}),M=y(!1),b=E({totalCalls:0,inputTokens:0,outputTokens:0,totalTokens:0}),G=y([]),oe=[{title:"Provider",key:"provider",dataIndex:"provider",width:"120px"},{title:"Model",key:"model",dataIndex:"model",ellipsis:!0},{title:"调用次数",key:"calls",dataIndex:"calls",width:"100px",sorter:(e,t)=>(e.calls||0)-(t.calls||0)},{title:"Input",key:"inputTokens",dataIndex:"inputTokens",width:"110px",sorter:(e,t)=>(e.inputTokens||0)-(t.inputTokens||0)},{title:"Output",key:"outputTokens",dataIndex:"outputTokens",width:"110px",sorter:(e,t)=>(e.outputTokens||0)-(t.outputTokens||0)},{title:"Total",key:"totalTokens",dataIndex:"totalTokens",width:"110px",sorter:(e,t)=>(e.totalTokens||0)-(t.totalTokens||0)}],se=[{title:"Provider",key:"provider",dataIndex:"provider",width:"120px",sorter:(e,t)=>(e.provider||"").localeCompare(t.provider||"")},{title:"Model",key:"model",dataIndex:"model",ellipsis:!0,sorter:(e,t)=>(e.model||"").localeCompare(t.model||"")},{title:"调用次数",key:"calls",dataIndex:"calls",width:"100px",sorter:(e,t)=>(e.calls||0)-(t.calls||0)},{title:"Input Tokens",key:"inputTokens",dataIndex:"inputTokens",width:"120px",sorter:(e,t)=>(e.inputTokens||0)-(t.inputTokens||0)},{title:"Output Tokens",key:"outputTokens",dataIndex:"outputTokens",width:"130px",sorter:(e,t)=>(e.outputTokens||0)-(t.outputTokens||0)},{title:"Total Tokens",key:"totalTokens",dataIndex:"totalTokens",width:"120px",sorter:(e,t)=>(e.totalTokens||0)-(t.totalTokens||0)},{title:"费用 (USD)",key:"cost",dataIndex:"cost",width:"110px",sorter:(e,t)=>(e.cost||0)-(t.cost||0)},{title:"平均响应",key:"avgResponseTime",dataIndex:"avgResponseTime",width:"110px",sorter:(e,t)=>(e.avgResponseTime||0)-(t.avgResponseTime||0)}],ae=[{title:"时间",key:"timestamp",dataIndex:"timestamp",width:"180px"},{title:"Provider",key:"provider",dataIndex:"provider",width:"110px"},{title:"Model",key:"model",dataIndex:"model",ellipsis:!0},{title:"Input",key:"inputTokens",dataIndex:"inputTokens",width:"90px"},{title:"Output",key:"outputTokens",dataIndex:"outputTokens",width:"90px"},{title:"费用",key:"cost",dataIndex:"cost",width:"100px"},{title:"响应时间",key:"responseTime",dataIndex:"responseTime",width:"100px"}];function h(e){return(e||"").replace(/,/g,"")}function S(e){try{const t=(e||"").trim(),a=t.search(/[{[]/);return a>=0?JSON.parse(t.slice(a)):null}catch{return null}}function le(e){const t=(e||"").split(`
|
|
2
|
-
`);for(const a of t){const r=a.trim(),_=r.match(/total\s*calls?\s*[::]\s*([\d,]+)/i);_&&(v.totalCalls=parseInt(h(_[1]),10)||0);const i=r.match(/total\s*tokens?\s*[::]\s*([\d,]+)/i);i&&(v.totalTokens=parseInt(h(i[1]),10)||0);const c=r.match(/cost\s*[::]\s*\$?([\d,.]+)/i);c&&(v.totalCost=parseFloat(h(c[1]))||0);const u=r.match(/(?:avg|average)\s*(?:response\s*)?time\s*[::]\s*([\d,.]+)/i);u&&(v.avgResponseTime=parseFloat(h(u[1]))||0)}}function ne(e){v.totalCalls=e.totalCalls??e.total_calls??e.calls??0,v.totalTokens=e.totalTokens??e.total_tokens??e.tokens??0,v.totalCost=e.totalCost??e.total_cost??e.cost??0,v.avgResponseTime=e.avgResponseTime??e.avg_response_time??e.avgTime??0}function re(e){return(Array.isArray(e)?e:e.breakdown||e.providers||e.rows||[]).map((a,r)=>({key:r,provider:a.provider||"-",model:a.model||"-",calls:a.calls||a.count||0,inputTokens:a.inputTokens??a.input_tokens??0,outputTokens:a.outputTokens??a.output_tokens??0,totalTokens:a.totalTokens??a.total_tokens??(a.inputTokens??0)+(a.outputTokens??0),cost:a.cost??a.total_cost??0,avgResponseTime:a.avgResponseTime??a.avg_response_time??0}))}function ie(e){return(Array.isArray(e)?e:e.recent||e.records||e.rows||[]).map((a,r)=>({key:r,timestamp:a.timestamp||a.time||a.created_at||"-",provider:a.provider||"-",model:a.model||"-",inputTokens:a.inputTokens??a.input_tokens??0,outputTokens:a.outputTokens??a.output_tokens??0,cost:a.cost??0,responseTime:a.responseTime??a.response_time??0}))}function ue(e){f.entries=e.entries??e.count??e.size??0,f.hits=e.hits??e.cacheHits??e.cache_hits??0,f.tokensSaved=e.tokensSaved??e.tokens_saved??0,f.expired=e.expired??e.expiredCount??e.expired_count??0}function de(e){const t=(e||"").split(`
|
|
3
|
-
`);for(const a of t){const r=a.trim(),_=r.match(/entries?\s*[::]\s*([\d,]+)/i);_&&(f.entries=parseInt(h(_[1]),10)||0);const i=r.match(/hits?\s*[::]\s*([\d,]+)/i);i&&(f.hits=parseInt(h(i[1]),10)||0);const c=r.match(/(?:tokens?\s*)?saved\s*[::]\s*([\d,]+)/i);c&&(f.tokensSaved=parseInt(h(c[1]),10)||0);const u=r.match(/expired?\s*[::]\s*([\d,]+)/i);u&&(f.expired=parseInt(h(u[1]),10)||0)}}async function W(){N.value=!0;try{const{output:e}=await w.execute(`tokens show --period ${R.value} --json`,15e3),t=S(e);t?ne(t):le(e)}catch(e){console.error("loadSummary failed:",e)}finally{N.value=!1}}async function ce(){B.value=!0;try{const{output:e}=await w.execute("tokens breakdown --json",15e3),t=S(e);t?O.value=re(t):O.value=[]}catch(e){console.error("loadBreakdown failed:",e),O.value=[]}finally{B.value=!1}}async function K(){D.value=!0;try{const{output:e}=await w.execute(`tokens recent --limit ${$.value} --json`,15e3),t=S(e);t?j.value=ie(t):j.value=[]}catch(e){console.error("loadRecent failed:",e),j.value=[]}finally{D.value=!1}}async function F(){L.value=!0;try{const{output:e}=await w.execute("tokens cache --json",15e3),t=S(e);t?ue(t):de(e)}catch(e){console.error("loadCache failed:",e)}finally{L.value=!1}}async function pe(){A.value=!0;try{const{output:e}=await w.execute("tokens cache --clear --json",15e3),t=S(e);t&&t.error?C.error("清理缓存失败: "+t.error):(C.success("缓存已清理"),await F())}catch(e){C.error("清理缓存失败: "+e.message)}finally{A.value=!1}}async function ke(){J.value=!0;try{const{output:e}=await w.execute("tokens cache --cleanup --json",15e3),t=S(e);t&&t.error?C.error("清理过期失败: "+t.error):(C.success("过期缓存已清理"),await F())}catch(e){C.error("清理过期失败: "+e.message)}finally{J.value=!1}}async function Q(){M.value=!0;try{const e=await w.sendRaw({type:"usage.global",limit:1e3},15e3);if(e.ok&&e.usage){const t=e.usage.total||{};b.totalCalls=t.calls??0,b.inputTokens=t.inputTokens??t.input_tokens??0,b.outputTokens=t.outputTokens??t.output_tokens??0,b.totalTokens=t.totalTokens??t.total_tokens??0,G.value=(e.usage.byModel||[]).map((a,r)=>({key:r,provider:a.provider||"-",model:a.model||"-",calls:a.calls??0,inputTokens:a.inputTokens??a.input_tokens??0,outputTokens:a.outputTokens??a.output_tokens??0,totalTokens:a.totalTokens??a.total_tokens??0}))}}catch(e){console.warn("loadSessionUsage failed (route may not be available):",e.message)}finally{M.value=!1}}async function X(){await Promise.all([W(),ce(),K(),F(),Q()])}return ge(R,()=>{W()}),_e(X),(e,t)=>{const a=m("a-radio-button"),r=m("a-radio-group"),_=m("a-button"),i=m("a-statistic"),c=m("a-card"),u=m("a-col"),P=m("a-row"),U=m("a-spin"),V=m("a-tag"),H=m("a-empty"),q=m("a-table"),ve=m("a-space");return n(),p("div",null,[z("div",be,[t[7]||(t[7]=z("div",null,[z("h2",{class:"page-title"},"使用分析"),z("p",{class:"page-sub"},"Token 用量 / 成本 / 缓存")],-1)),z("div",he,[o(r,{value:R.value,"onUpdate:value":t[0]||(t[0]=l=>R.value=l),"button-style":"solid",size:"small"},{default:s(()=>[o(a,{value:"today"},{default:s(()=>[...t[2]||(t[2]=[d("今天",-1)])]),_:1}),o(a,{value:"week"},{default:s(()=>[...t[3]||(t[3]=[d("本周",-1)])]),_:1}),o(a,{value:"month"},{default:s(()=>[...t[4]||(t[4]=[d("本月",-1)])]),_:1}),o(a,{value:"all"},{default:s(()=>[...t[5]||(t[5]=[d("全部",-1)])]),_:1})]),_:1},8,["value"]),o(_,{type:"primary",ghost:"",loading:N.value,onClick:X},{icon:s(()=>[o(T(Y))]),default:s(()=>[t[6]||(t[6]=d(" 刷新 ",-1))]),_:1},8,["loading"])])]),o(P,{gutter:[16,16],style:{"margin-bottom":"20px"}},{default:s(()=>[o(u,{xs:24,sm:12,lg:6},{default:s(()=>[o(c,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:s(()=>[o(i,{title:"总调用次数",value:v.totalCalls,"value-style":{color:"#1677ff",fontSize:"20px"}},{prefix:s(()=>[o(T(Z))]),suffix:s(()=>[...t[8]||(t[8]=[d("次",-1)])]),_:1},8,["value"])]),_:1})]),_:1}),o(u,{xs:24,sm:12,lg:6},{default:s(()=>[o(c,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:s(()=>[o(i,{title:"总 Token 数",value:v.totalTokens,"value-style":{color:"#52c41a",fontSize:"20px"}},{prefix:s(()=>[o(T(ee))]),_:1},8,["value"])]),_:1})]),_:1}),o(u,{xs:24,sm:12,lg:6},{default:s(()=>[o(c,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:s(()=>[o(i,{title:"总费用",value:v.totalCost,precision:4,"value-style":{color:"#faad14",fontSize:"20px"}},{prefix:s(()=>[o(T(me))]),suffix:s(()=>[...t[9]||(t[9]=[d("USD",-1)])]),_:1},8,["value"])]),_:1})]),_:1}),o(u,{xs:24,sm:12,lg:6},{default:s(()=>[o(c,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:s(()=>[o(i,{title:"平均响应时间",value:v.avgResponseTime,"value-style":{color:"#722ed1",fontSize:"20px"}},{prefix:s(()=>[o(T(ee))]),suffix:s(()=>[...t[10]||(t[10]=[d("ms",-1)])]),_:1},8,["value"])]),_:1})]),_:1})]),_:1}),o(c,{title:"Provider 分布",style:{background:"var(--bg-card)","border-color":"var(--border-color)","margin-bottom":"20px"}},{default:s(()=>[B.value?(n(),p("div",we,[o(U,{size:"large"})])):(n(),I(q,{key:1,columns:se,"data-source":O.value,pagination:{pageSize:20,showTotal:l=>`共 ${l} 条`},size:"small",style:{background:"var(--bg-card)"},"row-class-name":()=>"analytics-row"},{bodyCell:s(({column:l,record:k})=>[l.key==="provider"?(n(),I(V,{key:0,color:"blue"},{default:s(()=>[d(x(k.provider),1)]),_:2},1024)):g("",!0),l.key==="model"?(n(),p("span",Se,x(k.model),1)):g("",!0),l.key==="cost"?(n(),p("span",Ce,"$"+x((k.cost||0).toFixed(4)),1)):g("",!0),l.key==="avgResponseTime"?(n(),p("span",Ie,x(k.avgResponseTime||0)+" ms",1)):g("",!0)]),emptyText:s(()=>[o(H,{description:"暂无调用记录"})]),_:1},8,["data-source","pagination"]))]),_:1}),o(c,{title:"最近调用记录",style:{background:"var(--bg-card)","border-color":"var(--border-color)","margin-bottom":"20px"}},{extra:s(()=>[o(r,{value:$.value,"onUpdate:value":t[1]||(t[1]=l=>$.value=l),size:"small",onChange:K},{default:s(()=>[o(a,{value:10},{default:s(()=>[...t[11]||(t[11]=[d("10",-1)])]),_:1}),o(a,{value:20},{default:s(()=>[...t[12]||(t[12]=[d("20",-1)])]),_:1}),o(a,{value:50},{default:s(()=>[...t[13]||(t[13]=[d("50",-1)])]),_:1})]),_:1},8,["value"])]),default:s(()=>[D.value?(n(),p("div",ze,[o(U,{size:"large"})])):(n(),I(q,{key:1,columns:ae,"data-source":j.value,pagination:{pageSize:20,showTotal:l=>`共 ${l} 条`},size:"small",style:{background:"var(--bg-card)"},"row-class-name":()=>"analytics-row"},{bodyCell:s(({column:l,record:k})=>[l.key==="timestamp"?(n(),p("span",Re,x(k.timestamp),1)):g("",!0),l.key==="provider"?(n(),I(V,{key:1,color:"blue"},{default:s(()=>[d(x(k.provider),1)]),_:2},1024)):g("",!0),l.key==="model"?(n(),p("span",Oe,x(k.model),1)):g("",!0),l.key==="cost"?(n(),p("span",je,"$"+x((k.cost||0).toFixed(4)),1)):g("",!0),l.key==="responseTime"?(n(),p("span",Me,x(k.responseTime||0)+" ms",1)):g("",!0)]),emptyText:s(()=>[o(H,{description:"暂无调用记录"})]),_:1},8,["data-source","pagination"]))]),_:1}),o(c,{title:"Session Token Usage",style:{background:"var(--bg-card)","border-color":"var(--border-color)","margin-bottom":"20px"}},{extra:s(()=>[o(_,{size:"small",loading:M.value,onClick:Q,style:{background:"var(--bg-card-hover)","border-color":"var(--border-color)"}},{icon:s(()=>[o(T(Y))]),default:s(()=>[t[14]||(t[14]=d(" 刷新 ",-1))]),_:1},8,["loading"])]),default:s(()=>[M.value?(n(),p("div",Ue,[o(U)])):(n(),p(Te,{key:1},[o(P,{gutter:[16,16],style:{"margin-bottom":"16px"}},{default:s(()=>[o(u,{xs:12,sm:6},{default:s(()=>[o(i,{title:"Session 调用总次数",value:b.totalCalls,"value-style":{color:"#1677ff",fontSize:"18px"}},{prefix:s(()=>[o(T(Z))]),_:1},8,["value"])]),_:1}),o(u,{xs:12,sm:6},{default:s(()=>[o(i,{title:"Input Tokens",value:b.inputTokens,"value-style":{color:"#52c41a",fontSize:"18px"}},null,8,["value"])]),_:1}),o(u,{xs:12,sm:6},{default:s(()=>[o(i,{title:"Output Tokens",value:b.outputTokens,"value-style":{color:"#faad14",fontSize:"18px"}},null,8,["value"])]),_:1}),o(u,{xs:12,sm:6},{default:s(()=>[o(i,{title:"Total Tokens",value:b.totalTokens,"value-style":{color:"#722ed1",fontSize:"18px"}},null,8,["value"])]),_:1})]),_:1}),o(q,{columns:oe,"data-source":G.value,pagination:!1,size:"small",style:{background:"var(--bg-card)"},"row-class-name":()=>"analytics-row"},{bodyCell:s(({column:l,record:k})=>[l.key==="provider"?(n(),I(V,{key:0,color:"blue"},{default:s(()=>[d(x(k.provider),1)]),_:2},1024)):g("",!0),l.key==="model"?(n(),p("span",Ne,x(k.model),1)):g("",!0)]),emptyText:s(()=>[o(H,{description:"暂无 Session 用量数据 — 使用 cc chat 后刷新"})]),_:1},8,["data-source"])],64))]),_:1}),o(c,{title:"缓存状态",style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{extra:s(()=>[o(ve,null,{default:s(()=>[o(_,{size:"small",loading:J.value,onClick:ke,style:{background:"var(--bg-card-hover)","border-color":"var(--border-color)"}},{icon:s(()=>[o(T(te))]),default:s(()=>[t[15]||(t[15]=d(" 清理过期 ",-1))]),_:1},8,["loading"]),o(_,{size:"small",danger:"",loading:A.value,onClick:pe,style:{"border-color":"var(--border-color)"}},{icon:s(()=>[o(T(te))]),default:s(()=>[t[16]||(t[16]=d(" 清理缓存 ",-1))]),_:1},8,["loading"])]),_:1})]),default:s(()=>[L.value?(n(),p("div",Be,[o(U)])):(n(),I(P,{key:1,gutter:[16,16]},{default:s(()=>[o(u,{xs:12,sm:6},{default:s(()=>[o(i,{title:"缓存条目",value:f.entries,"value-style":{color:"#1677ff",fontSize:"18px"}},{prefix:s(()=>[o(T(xe))]),_:1},8,["value"])]),_:1}),o(u,{xs:12,sm:6},{default:s(()=>[o(i,{title:"命中次数",value:f.hits,"value-style":{color:"#52c41a",fontSize:"18px"}},null,8,["value"])]),_:1}),o(u,{xs:12,sm:6},{default:s(()=>[o(i,{title:"节省 Token",value:f.tokensSaved,"value-style":{color:"#faad14",fontSize:"18px"}},null,8,["value"])]),_:1}),o(u,{xs:12,sm:6},{default:s(()=>[o(i,{title:"已过期",value:f.expired,"value-style":{color:"#ff4d4f",fontSize:"18px"}},null,8,["value"])]),_:1})]),_:1}))]),_:1})])}}},Ke=ye(De,[["__scopeId","data-v-bfaf911e"]]);export{Ke as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.app-root[data-v-54c0cd71]{height:100vh;background:var(--bg-base);overflow:hidden}.sidebar[data-v-54c0cd71]{background:var(--bg-sidebar)!important;border-right:1px solid var(--border-color);transition:background .25s;height:100vh}[data-v-54c0cd71] .ant-layout-sider-children{display:flex;flex-direction:column;overflow:hidden;height:100%}.main-area[data-v-54c0cd71]{background:var(--bg-base);height:100vh;display:flex;flex-direction:column}.logo[data-v-54c0cd71]{height:52px;display:flex;align-items:center;padding:0 18px;gap:10px;border-bottom:1px solid var(--border-color);overflow:hidden;white-space:nowrap;flex-shrink:0}.logo.collapsed[data-v-54c0cd71]{padding:0;justify-content:center}.logo-icon[data-v-54c0cd71]{width:24px;height:24px;flex-shrink:0;object-fit:contain}.logo-text[data-v-54c0cd71]{color:var(--logo-text);font-weight:700;font-size:14px;letter-spacing:.01em}.mode-banner[data-v-54c0cd71]{display:flex;align-items:center;gap:8px;padding:7px 10px;margin:8px 8px 4px;border-radius:7px;overflow:hidden}.mode-banner.project[data-v-54c0cd71]{background:#1677ff1a;border:1px solid rgba(22,119,255,.2)}.mode-banner.global[data-v-54c0cd71]{background:#722ed11a;border:1px solid rgba(114,46,209,.2)}.banner-icon[data-v-54c0cd71]{font-size:13px;flex-shrink:0;color:#1677ff}.mode-banner.global .banner-icon[data-v-54c0cd71]{color:#722ed1}.banner-info[data-v-54c0cd71]{flex:1;min-width:0}.banner-name[data-v-54c0cd71]{font-size:12px;font-weight:600;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.banner-sub[data-v-54c0cd71]{font-size:10px;color:#1677ff;margin-top:1px}.mode-banner.global .banner-name[data-v-54c0cd71]{color:#c084fc}.mode-icon-sm[data-v-54c0cd71]{display:flex;justify-content:center;padding:8px 0;font-size:14px}.side-menu[data-v-54c0cd71]{border:none!important;margin-top:2px;-webkit-user-select:none;user-select:none;background:transparent!important;flex:1;overflow-y:auto;overflow-x:hidden}.group-label[data-v-54c0cd71]{color:var(--group-title);font-size:10px;font-weight:700;letter-spacing:.12em;padding-left:6px}[data-v-54c0cd71] .ant-menu-item-group-title{padding:8px 16px 2px!important}[data-v-54c0cd71] .ant-menu-item{height:38px!important;line-height:38px!important;margin:1px 4px!important;border-radius:6px!important}.divider-sm[data-v-54c0cd71]{margin:4px 0!important}.sidebar-footer[data-v-54c0cd71]{flex-shrink:0;padding:8px 18px;display:flex;align-items:center;gap:8px;border-top:1px solid var(--border-color)}.sidebar-footer.collapsed[data-v-54c0cd71]{justify-content:center;padding:8px 0}.footer-text[data-v-54c0cd71]{color:var(--text-secondary);font-size:11px}.app-header[data-v-54c0cd71]{background:var(--bg-header)!important;padding:0 20px!important;border-bottom:1px solid var(--border-color);height:50px!important;line-height:50px!important;display:flex!important;align-items:center!important;justify-content:space-between!important;box-shadow:0 1px 4px #0000000f}.header-left[data-v-54c0cd71],.header-right[data-v-54c0cd71]{display:flex;align-items:center;gap:10px}.scope-tag[data-v-54c0cd71]{display:flex;align-items:center;gap:5px;padding:3px 10px;border-radius:5px;font-size:12px;font-weight:500}.scope-tag.project[data-v-54c0cd71]{background:#1677ff1a;color:#1677ff;border:1px solid rgba(22,119,255,.2)}.scope-tag.global[data-v-54c0cd71]{background:#722ed11a;color:#722ed1;border:1px solid rgba(114,46,209,.2)}.info-icon[data-v-54c0cd71]{opacity:.45;cursor:help;margin-left:2px}.theme-switcher[data-v-54c0cd71]{display:flex;align-items:center;gap:4px;background:var(--bg-card);border:1px solid var(--border-color);border-radius:20px;padding:3px 6px}.theme-btn[data-v-54c0cd71]{width:26px;height:26px;border:none;border-radius:50%;cursor:pointer;background:transparent;font-size:14px;line-height:1;display:flex;align-items:center;justify-content:center;transition:background .15s,transform .15s;opacity:.55}.theme-btn[data-v-54c0cd71]:hover{opacity:.9;transform:scale(1.15);background:var(--bg-card-hover)}.theme-btn.active[data-v-54c0cd71]{opacity:1;transform:scale(1.1);background:var(--bg-card-hover);outline:2px solid var(--text-secondary)}.version-tag[data-v-54c0cd71]{color:var(--text-muted);font-size:11px}.ws-tag[data-v-54c0cd71]{margin:0!important;font-size:11px}.shell-switch-btn[data-v-54c0cd71]{width:26px;height:26px;border:none;border-radius:50%;cursor:pointer;background:transparent;font-size:14px;line-height:1;display:flex;align-items:center;justify-content:center;color:var(--text-secondary);transition:background .15s,transform .15s,color .15s;opacity:.6}.shell-switch-btn[data-v-54c0cd71]:hover{opacity:1;transform:scale(1.15);background:var(--bg-card-hover);color:var(--text-primary)}.page-content[data-v-54c0cd71]{padding:24px;overflow:auto;background:var(--bg-base);flex:1;min-height:0}
|