@qwen-code/qwen-code 0.19.5 → 0.19.6-nightly.20260704.5dc2e1501
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/bundled/dataviz/SKILL.md +50 -0
- package/bundled/dataviz/references/anti-patterns.md +12 -0
- package/bundled/dataviz/references/choosing-a-form.md +16 -0
- package/bundled/dataviz/references/palette.md +57 -0
- package/bundled/dataviz/scripts/validate_palette.js +328 -0
- package/bundled/loop/SKILL.md +1 -1
- package/bundled/qc-helper/docs/configuration/settings.md +9 -8
- package/bundled/qc-helper/docs/features/headless.md +2 -2
- package/bundled/qc-helper/docs/features/scheduled-tasks.md +4 -2
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +1 -1
- package/bundled/review/DESIGN.md +23 -0
- package/bundled/review/SKILL.md +65 -8
- package/chunks/{MaxSizedBox-5JV77KRA.js → MaxSizedBox-44K34KSF.js} +14 -14
- package/chunks/{StandaloneSessionPicker-MGUGB6PH.js → StandaloneSessionPicker-6WZYYTZE.js} +25 -25
- package/chunks/{acpAgent-4F36XM3X.js → acpAgent-2CMYPFHV.js} +346 -131
- package/chunks/{agent-IWBUZI6A.js → agent-UOEAYBCX.js} +11 -11
- package/chunks/{agent-headless-JUTICAYO.js → agent-headless-7SCVZZGJ.js} +11 -11
- package/chunks/{anthropicContentGenerator-WL3LJOUB.js → anthropicContentGenerator-H5ZOEENQ.js} +2 -2
- package/chunks/{artifact-tool-W76WC2JX.js → artifact-tool-SLYPWG3C.js} +15 -2
- package/chunks/{askUserQuestion-J3P6TH3V.js → askUserQuestion-OKPTECON.js} +1 -1
- package/chunks/{bridge-DHZHQ4UV.js → bridge-IGX2XPWV.js} +17 -16
- package/chunks/{channel-worker-supervisor-EVPAYNZ5.js → channel-worker-supervisor-JUYQ5Z4R.js} +5 -5
- package/chunks/{chunk-EROWZQN7.js → chunk-2HK52TS2.js} +6 -6
- package/chunks/chunk-3RW4AZJV.js +5063 -0
- package/chunks/chunk-3VJ7MT3N.js +111 -0
- package/chunks/{chunk-JJ6B3ZD3.js → chunk-3ZSJDRNO.js} +2 -2
- package/chunks/{chunk-SJVPSHXU.js → chunk-4OIKNWUQ.js} +4 -4
- package/chunks/{chunk-PPFWEV7G.js → chunk-4RQIB5UZ.js} +62 -62
- package/chunks/{chunk-MDBNFHIO.js → chunk-4YMVQKCZ.js} +3 -3
- package/chunks/{chunk-2YH27UNF.js → chunk-4YXBDLX7.js} +1 -1
- package/chunks/{chunk-6QVQZAW6.js → chunk-537ZUZEH.js} +1 -1
- package/chunks/{chunk-L7OJ3ZO3.js → chunk-5ES5YPED.js} +1 -1
- package/chunks/{chunk-UJT42DB6.js → chunk-5QC7Y5TJ.js} +5 -5
- package/chunks/{chunk-BC4R5C5R.js → chunk-5WYLPENX.js} +32 -6
- package/chunks/{chunk-7DMQRPC7.js → chunk-6BEOH4KK.js} +1 -1
- package/chunks/{chunk-CXBG27SF.js → chunk-6IAWPIQ6.js} +3 -2
- package/chunks/{chunk-RM3PGSGL.js → chunk-6SHO7WFF.js} +15 -2
- package/chunks/{chunk-CBJE2PLG.js → chunk-777PHAJF.js} +2 -2
- package/chunks/{chunk-NSSVORTQ.js → chunk-7UU2AGR4.js} +16 -12
- package/chunks/{chunk-RNGAT2Y2.js → chunk-AGLMKJH5.js} +1 -1
- package/chunks/{chunk-J3ERRYYI.js → chunk-AWSTZHHZ.js} +2 -2
- package/chunks/{chunk-6QTCOQX7.js → chunk-B5ZACOMA.js} +1967 -1399
- package/chunks/{chunk-R6RI2HIC.js → chunk-CLQPBI4H.js} +40 -13
- package/chunks/{chunk-SJBIFVD2.js → chunk-DMSNJDWG.js} +5 -1
- package/chunks/{chunk-KKQWC6WS.js → chunk-DNV4FSN5.js} +1 -1
- package/chunks/{chunk-Z7XNVNPM.js → chunk-EMSRFDBD.js} +1 -1
- package/chunks/{chunk-HISPEX42.js → chunk-G645A66S.js} +7 -7
- package/chunks/{chunk-WALEWZ44.js → chunk-H3GBYW5M.js} +1 -1
- package/chunks/{chunk-2Z43HUXT.js → chunk-HLKG6CZN.js} +3 -2
- package/chunks/{chunk-XKZXGIRM.js → chunk-HNGXPBWR.js} +2 -2
- package/chunks/{chunk-QHYITL6P.js → chunk-HXX7S2AE.js} +5 -11
- package/chunks/{chunk-XKSCTXPK.js → chunk-J6ABRKAB.js} +2 -1
- package/chunks/{chunk-DX3TKXNT.js → chunk-JA5KWZTJ.js} +1 -1
- package/chunks/{chunk-4MCC4XHH.js → chunk-KBKWNEPS.js} +38 -37
- package/chunks/{chunk-MNOXKSM2.js → chunk-KEKV2TOO.js} +1 -1
- package/chunks/{chunk-R3UWLLRQ.js → chunk-KP6O77UN.js} +1 -1
- package/chunks/{chunk-YTFBURQD.js → chunk-KYTQOCDE.js} +1 -1
- package/chunks/{chunk-TN6RT6EJ.js → chunk-LJUWNRJH.js} +16 -4
- package/chunks/{chunk-BPFJQGY7.js → chunk-LM3YCCZJ.js} +164 -5
- package/chunks/{chunk-G4M7FPNY.js → chunk-M6IUEDXM.js} +1 -1
- package/chunks/{chunk-MTNTVOJR.js → chunk-MJKMIQMK.js} +5 -2
- package/chunks/{chunk-2CAII5HD.js → chunk-MWGIMAYM.js} +1 -1
- package/chunks/{chunk-NDY7OENU.js → chunk-N3QDCSLP.js} +2 -2
- package/chunks/{chunk-IMAMNLY6.js → chunk-N6AGVKMC.js} +3 -3
- package/chunks/{chunk-WZ724G6K.js → chunk-NGCPNXJC.js} +5 -5
- package/chunks/{chunk-YXK4GPYO.js → chunk-NVFJSIAX.js} +29 -0
- package/chunks/{chunk-6KPZJJ6U.js → chunk-P2OIJOKP.js} +9 -9
- package/chunks/{chunk-RSBQS6M4.js → chunk-P2RRV2UB.js} +1 -1
- package/chunks/{chunk-NNEJEBCF.js → chunk-PGMCFUZS.js} +30 -21
- package/chunks/{chunk-CSPSJU5R.js → chunk-PNGENHT7.js} +16 -16
- package/chunks/{chunk-Y4UQT3PM.js → chunk-QQXG2BL6.js} +1 -1
- package/chunks/{chunk-M5ITDKSM.js → chunk-RUM2UEL3.js} +1 -1
- package/chunks/{chunk-DG573EOO.js → chunk-RZORUN6X.js} +1 -1
- package/chunks/{chunk-LHMZCIKL.js → chunk-SZFYG244.js} +3 -1
- package/chunks/{chunk-CHY5C5T4.js → chunk-TDMIHT6B.js} +171 -79
- package/chunks/{chunk-DRS2HTNT.js → chunk-TE6JTKY5.js} +5 -5
- package/chunks/chunk-U7UXWKGG.js +949 -0
- package/chunks/{chunk-JKGCBO3O.js → chunk-UPYORLKQ.js} +3 -3
- package/chunks/{chunk-UY2TCIZS.js → chunk-V5VTULL5.js} +2 -2
- package/chunks/{chunk-ZISMVA6U.js → chunk-WGCLCXAN.js} +1371 -24
- package/chunks/chunk-WSOGYJMT.js +5630 -0
- package/chunks/{chunk-SBMHB6N5.js → chunk-WWGZJJRG.js} +12 -12
- package/chunks/{chunk-DM4E337C.js → chunk-X3UQVEBR.js} +4 -4
- package/chunks/{chunk-K4I4STSL.js → chunk-XPOO5OMB.js} +2 -2
- package/chunks/{chunk-5B2WNM6V.js → chunk-ZI4MGBB5.js} +1 -1
- package/chunks/{chunk-OQHLUA2Y.js → chunk-ZLJKZ57K.js} +3 -3
- package/chunks/{chunk-YCU7QV7Q.js → chunk-ZZDAIAA6.js} +32 -0
- package/chunks/{computer-use-ON3JQUHW.js → computer-use-TQWGUBPQ.js} +11 -11
- package/chunks/{contextCommand-OGCG7W6N.js → contextCommand-XDK5RNWI.js} +13 -13
- package/chunks/{cron-create-6YTCOX6P.js → cron-create-7JYUDTUY.js} +20 -5
- package/chunks/{cron-delete-E3NIFSUK.js → cron-delete-YPULQQAK.js} +2 -2
- package/chunks/{cron-list-Q64MNQNE.js → cron-list-HJIW5MHP.js} +2 -2
- package/chunks/{daemon-EEB2RYOL.js → daemon-7XYW4BC3.js} +102 -0
- package/chunks/{daemon-status-provider-P72STMLB.js → daemon-status-provider-6UEN56WN.js} +20 -19
- package/chunks/{dist-AP5V4WYU.js → dist-AAO65DPC.js} +2 -2
- package/chunks/{dist-X4ZDE726.js → dist-ABQ7VWRR.js} +3 -3
- package/chunks/{dist-SNXOUPYS.js → dist-AW5ZYMUI.js} +2 -2
- package/chunks/{dist-Z57Q4YF5.js → dist-BV56HW3W.js} +276 -95
- package/chunks/{dist-IZP2VV4C.js → dist-JPSVN367.js} +2 -2
- package/chunks/{earlyInputCapture-DAFHSGVW.js → earlyInputCapture-7MNFMUJE.js} +11 -11
- package/chunks/{edit-3QFNCSZH.js → edit-HOC63PHG.js} +12 -12
- package/chunks/{en-M4EBUBNU.js → en-XR3S5VWY.js} +1 -0
- package/chunks/{enter-worktree-62EQQMLD.js → enter-worktree-THXLMUX2.js} +11 -11
- package/chunks/{enterPlanMode-VUQSE4EG.js → enterPlanMode-TW4WQVEI.js} +11 -11
- package/chunks/{errors-PW75PZXE.js → errors-NTNVSC6G.js} +13 -13
- package/chunks/{exit-worktree-VVNH7OVY.js → exit-worktree-CLL7RGAT.js} +11 -11
- package/chunks/{exitPlanMode-RUYRCYZW.js → exitPlanMode-BTZZ3QEL.js} +11 -11
- package/chunks/{fast-path-TFRJRTTR.js → fast-path-RYXBU6AS.js} +3 -3
- package/chunks/{fast-path-settings-UQLRFDQP.js → fast-path-settings-RCRXH2JG.js} +2 -2
- package/chunks/{gemini-XW7ZDUVR.js → gemini-36FE3OHS.js} +69 -64
- package/chunks/{geminiContentGenerator-MZDVHVZH.js → geminiContentGenerator-JEG2PANG.js} +1 -1
- package/chunks/{glob-WAY2PUWA.js → glob-EYVHOFCY.js} +11 -11
- package/chunks/{grep-W6CBKSYC.js → grep-TZY5TDGH.js} +11 -11
- package/chunks/{initializer-HK2XE6P2.js → initializer-HPF2RBSB.js} +16 -16
- package/chunks/{list-RVLIIKKL.js → list-THUTQ7B5.js} +18 -18
- package/chunks/{loadedSettingsAdapter-C63OUYZC.js → loadedSettingsAdapter-CUMWJNWJ.js} +16 -16
- package/chunks/{loop-wakeup-G2EHBRGR.js → loop-wakeup-34YK7T7O.js} +3 -3
- package/chunks/{ls-IDHUVSAG.js → ls-MPD5OJUX.js} +1 -1
- package/chunks/{lsp-FSRYXGFT.js → lsp-72PWTDW7.js} +1 -1
- package/chunks/{workspace-skills-status-ONEPXJV6.js → mcp-NQD5MT2T.js} +20 -16
- package/chunks/{monitor-FOG36ABM.js → monitor-PB7NVSG2.js} +11 -11
- package/chunks/{nonInteractiveCli-6BYQSJTB.js → nonInteractiveCli-F5FJXYQR.js} +46 -44
- package/chunks/{notebook-edit-GC6NXRCX.js → notebook-edit-LAK6OHS6.js} +12 -12
- package/chunks/{openaiContentGenerator-EXR3ZL3Z.js → openaiContentGenerator-GMMEY5PG.js} +6 -6
- package/chunks/{pidfile-FNZM2DDH.js → pidfile-NQ2YUNKI.js} +11 -11
- package/chunks/{qwenContentGenerator-A7B6J4U7.js → qwenContentGenerator-7XCBMQBM.js} +13 -13
- package/chunks/{read-file-6JL4ULMY.js → read-file-KUROJDUQ.js} +3 -3
- package/chunks/{read-mcp-resource-PIJF24RO.js → read-mcp-resource-OWOBJY72.js} +1 -1
- package/chunks/record-artifact-URK3YUDJ.js +343 -0
- package/chunks/{ripGrep-DIUGLJE5.js → ripGrep-USDWBX4L.js} +11 -11
- package/chunks/{run-qwen-serve-CME3AKM4.js → run-qwen-serve-WKCKS23N.js} +72 -28
- package/chunks/{scheduler-L7F6GDDT.js → scheduler-QR4F5TAH.js} +11 -11
- package/chunks/{send-message-33PYFMCT.js → send-message-L7OLQEKH.js} +2 -2
- package/chunks/{serve-SRCBOJGP.js → serve-2EIPX62G.js} +18 -18
- package/chunks/{server-QSQ45QFR.js → server-UJ7ZF5D7.js} +1184 -490
- package/chunks/{session-5DG6NXHZ.js → session-XB3CFJ6R.js} +48 -46
- package/chunks/{settings-3EEQI4MN.js → settings-DYVJFW5H.js} +15 -15
- package/chunks/{shell-B7FNYF5S.js → shell-IG7KGPLR.js} +11 -11
- package/chunks/{skill-AAOGHD5O.js → skill-RWX646DC.js} +4 -4
- package/chunks/{spawnChannel-3CBN3ZLK.js → spawnChannel-GWIJHDZ5.js} +15 -15
- package/chunks/{src-T5A7P7FS.js → src-IYODJOVK.js} +47 -21
- package/chunks/{startInteractiveUI-2FGEQ6AS.js → startInteractiveUI-PLEZAI44.js} +354 -152
- package/chunks/{syntheticOutput-YOSWIHDJ.js → syntheticOutput-J3MLCQAR.js} +2 -2
- package/chunks/{task-create-NHS2NGB3.js → task-create-ELEBZ7H2.js} +3 -3
- package/chunks/{task-list-5UIB564R.js → task-list-IEUZLF3Y.js} +1 -1
- package/chunks/{task-stop-HGXZ2VZ3.js → task-stop-QEZW3UDY.js} +1 -1
- package/chunks/{task-update-IYYWUILG.js → task-update-DW36J5P5.js} +3 -3
- package/chunks/{team-create-KDF6W6PV.js → team-create-RXRE7FCH.js} +11 -11
- package/chunks/{team-delete-FEKJCU4P.js → team-delete-SVITIMBO.js} +1 -1
- package/chunks/{team-plan-approval-PSFKQX7M.js → team-plan-approval-OJDMQXOK.js} +11 -11
- package/chunks/{theme-manager-5XOA2AO7.js → theme-manager-QBK6PZOQ.js} +11 -11
- package/chunks/{todoWrite-TKMVZ2HT.js → todoWrite-SFFQHZYY.js} +2 -2
- package/chunks/{tool-search-LFRILZXC.js → tool-search-EZQYPVFF.js} +4 -4
- package/chunks/{trustedFolders-7HQY6T6X.js → trustedFolders-GZDMSATB.js} +12 -12
- package/chunks/{validateNonInterActiveAuth-UC27B7BA.js → validateNonInterActiveAuth-AHXCFAV6.js} +43 -41
- package/chunks/version-KQ5CA4C5.js +10 -0
- package/chunks/{web-fetch-J4PIW36Q.js → web-fetch-SXAXJHIO.js} +2 -2
- package/chunks/{workflow-KUTESS6L.js → workflow-KUBRBYWH.js} +20 -13
- package/chunks/{workspace-providers-status-LJT5AQDS.js → workspace-providers-status-LRMZ4KYI.js} +18 -18
- package/chunks/{workspace-service-YOBYVDXH.js → workspace-service-5UYFHP42.js} +23 -23
- package/chunks/workspace-skills-status-TKLU5O2X.js +68 -0
- package/chunks/{write-file-FJYBZUHP.js → write-file-37LNLFQC.js} +12 -12
- package/chunks/yargs-B64EYTCF.js +10 -0
- package/chunks/{zh-SLZNSSZB.js → zh-FSVJTXA4.js} +1 -0
- package/chunks/{zh-TW-P53C2SL5.js → zh-TW-66MG4LWL.js} +1 -0
- package/cli-entry.js +81 -8
- package/cli.js +348 -55
- package/locales/en.js +1 -0
- package/locales/zh-TW.js +1 -0
- package/locales/zh.js +1 -0
- package/node_modules/@qwen-code/audio-capture/package.json +1 -1
- package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-arm64/@qwen-code+audio-capture.node +0 -0
- package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-x64/@qwen-code+audio-capture.node +0 -0
- package/node_modules/@qwen-code/audio-capture/prebuilds/win32-x64/@qwen-code+audio-capture.node +0 -0
- package/package.json +3 -3
- package/web-shell/assets/{arc-D_rAuMDd.js → arc-CUpe0ibu.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-DUCzbHVo.js → architectureDiagram-3BPJPVTR-JvyrY_mK.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-BEEBt1LL.js → blockDiagram-GPEHLZMM-CK3Y_vom.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-5ZJ_DeFL.js → c4Diagram-AAUBKEIU-DprSnyrf.js} +1 -1
- package/web-shell/assets/channel-BAxQ2-aZ.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-Cfw7EiLn.js → chunk-2J33WTMH-DJtRJPmu.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-FGuZNCZY.js → chunk-4BX2VUAB-ON6Q2-BG.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-CaBwYPBF.js → chunk-55IACEB6-c60ou5HZ.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-BlR04OFz.js → chunk-727SXJPM-BamtPKxx.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-D3_mYJH5.js → chunk-AQP2D5EJ-CsVgpu-T.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-7D4q4SbB.js → chunk-FMBD7UC4-vZrpjAx4.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-BjX_Iwmr.js → chunk-ND2GUHAM-qxyNOd5t.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-C3Hz_ZQh.js → chunk-QZHKN3VN-BvTJSM_S.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-Cvd_xhZI.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-Cvd_xhZI.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-Ax4UycaT.js → cose-bilkent-S5V4N54A-1tXB4pju.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-C6hmPtGt.js → dagre-BM42HDAG-DglBzme8.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-tXZnxjmw.js → diagram-2AECGRRQ-DEJpqsWz.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-99dwIzQG.js → diagram-5GNKFQAL-CsQ1NrMG.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-Bqhn0-2s.js → diagram-KO2AKTUF-Z-3codAi.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-DzThVSvo.js → diagram-LMA3HP47-mBuPTA2i.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-DPE8vjln.js → diagram-OG6HWLK6-tcA3K3s9.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-KzUKgQCV.js → erDiagram-TEJ5UH35-D9bXFRyZ.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-DBN-DXw5.js → flowDiagram-I6XJVG4X-Ck0Py04s.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-DuBsP9u8.js → ganttDiagram-6RSMTGT7-rOevCekE.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-BjWHMyKR.js → gitGraphDiagram-PVQCEYII-CoPQaLj0.js} +1 -1
- package/web-shell/assets/index-Cr7MYW6T.css +5 -0
- package/web-shell/assets/index-DCHPAUp3.js +730 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-BVux0vP6.js → infoDiagram-5YYISTIA-a77CUKoI.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-2qzw7f--.js → ishikawaDiagram-YF4QCWOH-DlLgUAO-.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-Dnl65sxL.js → journeyDiagram-JHISSGLW-BXR5kVAZ.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-BElSQYtY.js → kanban-definition-UN3LZRKU-h5CoHZg7.js} +1 -1
- package/web-shell/assets/{linear-BjoycSSY.js → linear-BkaREbyD.js} +1 -1
- package/web-shell/assets/{mermaid.core-xe6bvMRz.js → mermaid.core-Bkagz0ng.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-D8DQgI4U.js → mindmap-definition-RKZ34NQL-D7EMKR_5.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-Dwh7Gp7c.js → pieDiagram-4H26LBE5-DAmPOjsL.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-BXKNBln2.js → quadrantDiagram-W4KKPZXB-e4WFQkQu.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-BzaC3cIA.js → requirementDiagram-4Y6WPE33-v1zo7OiV.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-DP2t7eZk.js → sankeyDiagram-5OEKKPKP-Bstm4aW_.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-XlFiWEYv.js → sequenceDiagram-3UESZ5HK-DzcZy6xN.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-CupgUMJO.js → stateDiagram-AJRCARHV-BEJH6YbH.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BopifCBI.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-DstuGywa.js → timeline-definition-PNZ67QCA-TI1wH-Pm.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-CnbNp6zu.js → vennDiagram-CIIHVFJN-YaH8VDMS.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-DnvoHq6R.js → wardley-L42UT6IY-B80co7OP.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-Cz0xHEWB.js → wardleyDiagram-YWT4CUSO-4fHNDEMl.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-p36gfo88.js → xychartDiagram-2RQKCTM6-DT3q4Z3J.js} +1 -1
- package/web-shell/index.html +2 -2
- package/bundled/loop/SKILL.test.ts +0 -119
- package/bundled/loop/autonomous-loop.test.ts +0 -59
- package/bundled/loop/loop-task-file.test.ts +0 -1064
- package/bundled/loop/loop-tick-resolver.test.ts +0 -906
- package/chunks/chunk-EJ7BN3EN.js +0 -11396
- package/web-shell/assets/channel-B5ynH0q8.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-CK3ibywp.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CK3ibywp.js +0 -1
- package/web-shell/assets/index-9qfvU0_r.css +0 -5
- package/web-shell/assets/index-CWzDaQT5.js +0 -717
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-By3E4QwN.js +0 -1
- package/chunks/{chunk-UFC57OYT.js → chunk-VRDMOSQS.js} +54 -54
|
@@ -11,12 +11,12 @@ import {
|
|
|
11
11
|
sendMessage,
|
|
12
12
|
sendTyping,
|
|
13
13
|
uploadToCdn
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-ZI4MGBB5.js";
|
|
15
15
|
import {
|
|
16
16
|
ChannelBase,
|
|
17
17
|
isTerminalTaskLifecycleType
|
|
18
|
-
} from "./chunk-
|
|
19
|
-
import "./chunk-
|
|
18
|
+
} from "./chunk-6BEOH4KK.js";
|
|
19
|
+
import "./chunk-VRDMOSQS.js";
|
|
20
20
|
import "./chunk-K5PGHDBN.js";
|
|
21
21
|
import {
|
|
22
22
|
init_esbuild_shims
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
isTerminalTaskLifecycleType,
|
|
12
12
|
sanitizeLogText,
|
|
13
13
|
sanitizeSenderName
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-6BEOH4KK.js";
|
|
15
|
+
import "./chunk-VRDMOSQS.js";
|
|
16
16
|
import "./chunk-K5PGHDBN.js";
|
|
17
17
|
import "./chunk-UWCTAVOD.js";
|
|
18
18
|
import {
|
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
sanitizeLogText,
|
|
8
8
|
sanitizePromptText,
|
|
9
9
|
sanitizeSenderName
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-6BEOH4KK.js";
|
|
11
|
+
import "./chunk-VRDMOSQS.js";
|
|
12
12
|
import "./chunk-K5PGHDBN.js";
|
|
13
13
|
import {
|
|
14
14
|
wrapper_default
|
|
@@ -1114,7 +1114,7 @@ init_esbuild_shims();
|
|
|
1114
1114
|
|
|
1115
1115
|
// packages/channels/qqbot/dist/QQChannel.js
|
|
1116
1116
|
init_esbuild_shims();
|
|
1117
|
-
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2 } from "node:fs";
|
|
1117
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, renameSync, unlinkSync } from "node:fs";
|
|
1118
1118
|
import { join as join2 } from "node:path";
|
|
1119
1119
|
|
|
1120
1120
|
// packages/channels/qqbot/dist/types.js
|
|
@@ -1351,8 +1351,11 @@ async function fetchAccessToken(appId, appSecret) {
|
|
|
1351
1351
|
signal: AbortSignal.timeout(FETCH_TIMEOUT)
|
|
1352
1352
|
});
|
|
1353
1353
|
if (!resp.ok) {
|
|
1354
|
-
|
|
1355
|
-
|
|
1354
|
+
await resp.body?.cancel().catch(() => {
|
|
1355
|
+
});
|
|
1356
|
+
process.stderr.write(`[QQ] Token request failed (HTTP ${resp.status})
|
|
1357
|
+
`);
|
|
1358
|
+
throw new Error(`QQ Bot token request failed (HTTP ${resp.status})`);
|
|
1356
1359
|
}
|
|
1357
1360
|
const data = await resp.json();
|
|
1358
1361
|
if (!data.access_token) {
|
|
@@ -1364,6 +1367,27 @@ async function fetchAccessToken(appId, appSecret) {
|
|
|
1364
1367
|
};
|
|
1365
1368
|
}
|
|
1366
1369
|
__name(fetchAccessToken, "fetchAccessToken");
|
|
1370
|
+
function validateGatewayUrl(url) {
|
|
1371
|
+
try {
|
|
1372
|
+
const parsed = new URL(url);
|
|
1373
|
+
if (parsed.protocol !== "wss:") {
|
|
1374
|
+
throw new Error(`QQ Bot gateway URL must use wss:// protocol, got: ${parsed.protocol}`);
|
|
1375
|
+
}
|
|
1376
|
+
if (!parsed.hostname.toLowerCase().endsWith(".qq.com")) {
|
|
1377
|
+
throw new Error(`QQ Bot gateway URL has unexpected hostname: ${parsed.hostname} (expected *.qq.com)`);
|
|
1378
|
+
}
|
|
1379
|
+
const clean = new URL(url);
|
|
1380
|
+
clean.username = "";
|
|
1381
|
+
clean.password = "";
|
|
1382
|
+
return clean.href;
|
|
1383
|
+
} catch (e) {
|
|
1384
|
+
if (e instanceof TypeError) {
|
|
1385
|
+
throw new Error("QQ Bot gateway URL is not a valid URL");
|
|
1386
|
+
}
|
|
1387
|
+
throw e;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
__name(validateGatewayUrl, "validateGatewayUrl");
|
|
1367
1391
|
async function fetchGatewayUrl(accessToken, sandbox) {
|
|
1368
1392
|
const gw = sandbox ? `${SANDBOX_HOST}/gateway` : `${API_HOST}/gateway`;
|
|
1369
1393
|
const resp = await fetch(gw, {
|
|
@@ -1371,13 +1395,15 @@ async function fetchGatewayUrl(accessToken, sandbox) {
|
|
|
1371
1395
|
signal: AbortSignal.timeout(FETCH_TIMEOUT)
|
|
1372
1396
|
});
|
|
1373
1397
|
if (!resp.ok) {
|
|
1398
|
+
await resp.body?.cancel().catch(() => {
|
|
1399
|
+
});
|
|
1374
1400
|
throw new Error(`QQ Bot gateway request failed (HTTP ${resp.status})`);
|
|
1375
1401
|
}
|
|
1376
1402
|
const data = await resp.json();
|
|
1377
1403
|
if (!data["url"]) {
|
|
1378
1404
|
throw new Error("QQ Bot gateway response missing WebSocket URL");
|
|
1379
1405
|
}
|
|
1380
|
-
return data["url"];
|
|
1406
|
+
return validateGatewayUrl(data["url"]);
|
|
1381
1407
|
}
|
|
1382
1408
|
__name(fetchGatewayUrl, "fetchGatewayUrl");
|
|
1383
1409
|
function getApiBase(sandbox) {
|
|
@@ -1402,32 +1428,7 @@ function isValidChatId(id) {
|
|
|
1402
1428
|
return /^[A-Za-z0-9_-]+$/.test(id) && id.length <= 128;
|
|
1403
1429
|
}
|
|
1404
1430
|
__name(isValidChatId, "isValidChatId");
|
|
1405
|
-
|
|
1406
|
-
const open = text.indexOf("[");
|
|
1407
|
-
if (open === -1)
|
|
1408
|
-
return false;
|
|
1409
|
-
const mid = text.indexOf("](", open + 1);
|
|
1410
|
-
if (mid === -1)
|
|
1411
|
-
return false;
|
|
1412
|
-
return text.indexOf(")", mid + 2) !== -1;
|
|
1413
|
-
}
|
|
1414
|
-
__name(hasLinkSyntax, "hasLinkSyntax");
|
|
1415
|
-
function hasMarkdownSyntax(text) {
|
|
1416
|
-
return /^#{1,6}\s/m.test(text) || text.includes("```") || /\*\*|__|~~/.test(text) || /`[^`]+`/.test(text) || hasLinkSyntax(text) || /^[-*+]\s/m.test(text) || /^\d+\.\s/m.test(text);
|
|
1417
|
-
}
|
|
1418
|
-
__name(hasMarkdownSyntax, "hasMarkdownSyntax");
|
|
1419
|
-
function splitText(text) {
|
|
1420
|
-
const MAX = 2e3;
|
|
1421
|
-
if (text.length <= MAX)
|
|
1422
|
-
return [text];
|
|
1423
|
-
const chunks = [];
|
|
1424
|
-
for (let i = 0; i < text.length; i += MAX) {
|
|
1425
|
-
chunks.push(text.slice(i, i + MAX));
|
|
1426
|
-
}
|
|
1427
|
-
return chunks;
|
|
1428
|
-
}
|
|
1429
|
-
__name(splitText, "splitText");
|
|
1430
|
-
var QQChannel = class extends ChannelBase {
|
|
1431
|
+
var QQChannel = class _QQChannel extends ChannelBase {
|
|
1431
1432
|
static {
|
|
1432
1433
|
__name(this, "QQChannel");
|
|
1433
1434
|
}
|
|
@@ -1459,6 +1460,8 @@ var QQChannel = class extends ChannelBase {
|
|
|
1459
1460
|
lastHeartbeatAck = 0;
|
|
1460
1461
|
/** Debounce timer for saveQQState to avoid blocking event loop. */
|
|
1461
1462
|
saveTimer = null;
|
|
1463
|
+
/** beforeExit hook to flush state when the event loop drains naturally. Does NOT fire for SIGKILL, OOM kills, or uncaughtException. */
|
|
1464
|
+
beforeExitHook = null;
|
|
1462
1465
|
/** Timer for reconnectWithRetry fallback (unref'd so it doesn't block exit). */
|
|
1463
1466
|
reconnectTimer = null;
|
|
1464
1467
|
/** Guard against parallel reconnectWithRetry chains from stale close events. */
|
|
@@ -1469,6 +1472,10 @@ var QQChannel = class extends ChannelBase {
|
|
|
1469
1472
|
replyMsgId = /* @__PURE__ */ new Map();
|
|
1470
1473
|
/** msg_seq counter per user messageId, for multi-block streaming. */
|
|
1471
1474
|
msgSeqMap = /* @__PURE__ */ new Map();
|
|
1475
|
+
/** Periodic cleanup timer for expired replyMsgId entries. */
|
|
1476
|
+
replyMsgIdCleanupTimer = null;
|
|
1477
|
+
/** 5-minute TTL for replyMsgId entries and seenMessages dedup. */
|
|
1478
|
+
static REPLY_MSG_ID_TTL_MS = 3e5;
|
|
1472
1479
|
/** Path to persisted QQ routing state: chatTypeMap, replyMsgId, msgSeqMap. */
|
|
1473
1480
|
qqStatePath;
|
|
1474
1481
|
/**
|
|
@@ -1504,71 +1511,145 @@ var QQChannel = class extends ChannelBase {
|
|
|
1504
1511
|
"## QQ Bot Channel",
|
|
1505
1512
|
"",
|
|
1506
1513
|
"\u4F60\u662F\u901A\u8FC7 QQ Bot \u4E0E\u7528\u6237\u5BF9\u8BDD\u7684 AI \u52A9\u624B\u3002",
|
|
1507
|
-
"\u56DE\u590D\u63A7\u5236\u5728 2000 \u5B57\u7B26\u4EE5\u5185\
|
|
1514
|
+
"\u56DE\u590D\u63A7\u5236\u5728 2000 \u5B57\u7B26\u4EE5\u5185\uFF0C\u652F\u6301 Markdown \u683C\u5F0F\u3002"
|
|
1508
1515
|
].join("\n");
|
|
1509
1516
|
}
|
|
1510
1517
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
1511
1518
|
try {
|
|
1512
1519
|
await this.fetchToken();
|
|
1513
1520
|
await this.connectGateway();
|
|
1521
|
+
if (this.beforeExitHook) {
|
|
1522
|
+
process.off("beforeExit", this.beforeExitHook);
|
|
1523
|
+
}
|
|
1524
|
+
this.beforeExitHook = () => this.flushQQState();
|
|
1525
|
+
process.on("beforeExit", this.beforeExitHook);
|
|
1526
|
+
this.startReplyMsgIdCleanup();
|
|
1514
1527
|
return;
|
|
1515
1528
|
} catch (e) {
|
|
1516
1529
|
if (attempt < 2) {
|
|
1517
1530
|
const msg = e instanceof Error ? e.message : String(e);
|
|
1518
|
-
process.stderr.write(`[QQ:${this.name}] Connect attempt ${attempt + 1} failed: ${msg}, retrying...
|
|
1531
|
+
process.stderr.write(`[QQ:${this.name}] Connect attempt ${attempt + 1} failed: ${sanitizeLogText(msg, 200)}, retrying...
|
|
1519
1532
|
`);
|
|
1520
1533
|
await this.sleep(2e3);
|
|
1521
1534
|
} else {
|
|
1522
|
-
throw e;
|
|
1535
|
+
throw new Error(sanitizeLogText(e instanceof Error ? e.message : String(e), 200), { cause: e });
|
|
1523
1536
|
}
|
|
1524
1537
|
}
|
|
1525
1538
|
}
|
|
1526
1539
|
}
|
|
1527
1540
|
async sendMessage(chatId, text) {
|
|
1541
|
+
if (text.trim() === "<noreply>") {
|
|
1542
|
+
process.stderr.write(`[QQ:${this.name}] <noreply> skipped for ${sanitizeLogText(chatId, 64)}
|
|
1543
|
+
`);
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1528
1546
|
const route = await this.resolveRoute(chatId);
|
|
1529
1547
|
if (!route)
|
|
1530
1548
|
return;
|
|
1531
|
-
const
|
|
1532
|
-
const
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1549
|
+
const entry = this.replyMsgId.get(chatId);
|
|
1550
|
+
const msgId = entry && Date.now() - entry.timestamp < _QQChannel.REPLY_MSG_ID_TTL_MS ? entry.msgId : void 0;
|
|
1551
|
+
if (entry && !msgId) {
|
|
1552
|
+
process.stderr.write(`[QQ:${this.name}] replyMsgId entry expired for ${sanitizeLogText(chatId, 64)}, reply context expired, sending without msg_id
|
|
1553
|
+
`);
|
|
1554
|
+
this.msgSeqMap.delete(entry.msgId);
|
|
1555
|
+
this.replyMsgId.delete(chatId);
|
|
1556
|
+
this.saveQQState();
|
|
1557
|
+
}
|
|
1558
|
+
let nextSeq = 0;
|
|
1559
|
+
let rollbackApplied = false;
|
|
1560
|
+
try {
|
|
1561
|
+
const body = {
|
|
1562
|
+
msg_type: 2,
|
|
1563
|
+
markdown: { content: text }
|
|
1564
|
+
};
|
|
1565
|
+
nextSeq = msgId ? (this.msgSeqMap.get(msgId) ?? 0) + 1 : 0;
|
|
1566
|
+
if (msgId) {
|
|
1567
|
+
this.msgSeqMap.set(msgId, nextSeq);
|
|
1568
|
+
body["msg_id"] = msgId;
|
|
1569
|
+
body["msg_seq"] = nextSeq;
|
|
1570
|
+
}
|
|
1571
|
+
const resp = await sendQQMessage(route.base, route.path, this.accessToken, body);
|
|
1572
|
+
if (!resp.ok) {
|
|
1573
|
+
const errBody = await resp.text().catch(() => "");
|
|
1574
|
+
process.stderr.write(`[QQ:${this.name}] Send failed (HTTP ${resp.status}: ${sanitizeLogText(errBody, 200)})
|
|
1575
|
+
`);
|
|
1576
|
+
if (resp.status === 429) {
|
|
1577
|
+
process.stderr.write(`[QQ:${this.name}] MESSAGE DROPPED: rate-limited (429) on markdown attempt for ${sanitizeLogText(chatId, 64)}
|
|
1545
1578
|
`);
|
|
1546
|
-
const plainBody = {
|
|
1547
|
-
content: chunk,
|
|
1548
|
-
msg_type: 0
|
|
1549
|
-
};
|
|
1550
1579
|
if (msgId) {
|
|
1551
|
-
|
|
1552
|
-
|
|
1580
|
+
this.msgSeqMap.set(msgId, nextSeq - 1);
|
|
1581
|
+
this.saveQQState();
|
|
1553
1582
|
}
|
|
1554
|
-
|
|
1583
|
+
return;
|
|
1555
1584
|
}
|
|
1556
|
-
if (
|
|
1557
|
-
|
|
1558
|
-
|
|
1585
|
+
if (msgId) {
|
|
1586
|
+
this.msgSeqMap.set(msgId, nextSeq - 1);
|
|
1587
|
+
rollbackApplied = true;
|
|
1588
|
+
const activeBody = {
|
|
1589
|
+
content: text,
|
|
1590
|
+
msg_type: 0,
|
|
1591
|
+
msg_id: msgId,
|
|
1592
|
+
msg_seq: nextSeq
|
|
1593
|
+
};
|
|
1594
|
+
const activeResp = await sendQQMessage(route.base, route.path, this.accessToken, activeBody);
|
|
1595
|
+
if (activeResp.ok) {
|
|
1596
|
+
process.stderr.write(`[QQ:${this.name}] Active retry succeeded for ${sanitizeLogText(chatId, 64)}
|
|
1559
1597
|
`);
|
|
1560
|
-
|
|
1598
|
+
const current = this.replyMsgId.get(chatId);
|
|
1599
|
+
if (current?.msgId === msgId) {
|
|
1600
|
+
this.msgSeqMap.set(msgId, nextSeq);
|
|
1601
|
+
}
|
|
1602
|
+
this.saveQQState();
|
|
1603
|
+
await activeResp.text().catch(() => "");
|
|
1604
|
+
return;
|
|
1605
|
+
}
|
|
1606
|
+
process.stderr.write(`[QQ:${this.name}] Active retry also failed (HTTP ${activeResp.status}: ${sanitizeLogText(await activeResp.text().catch(() => ""), 200)})
|
|
1607
|
+
`);
|
|
1608
|
+
if (activeResp.status === 429) {
|
|
1609
|
+
process.stderr.write(`[QQ:${this.name}] MESSAGE DROPPED: active retry rate-limited (HTTP 429) for ${sanitizeLogText(chatId, 64)}
|
|
1610
|
+
`);
|
|
1611
|
+
this.saveQQState();
|
|
1612
|
+
return;
|
|
1613
|
+
}
|
|
1614
|
+
process.stderr.write(`[QQ:${this.name}] MESSAGE DROPPED: both passive and active send failed for ${sanitizeLogText(chatId, 64)}
|
|
1615
|
+
`);
|
|
1616
|
+
this.saveQQState();
|
|
1617
|
+
return;
|
|
1561
1618
|
}
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1619
|
+
const plainBody = {
|
|
1620
|
+
content: text,
|
|
1621
|
+
msg_type: 0
|
|
1622
|
+
};
|
|
1623
|
+
const fallbackRes = await sendQQMessage(route.base, route.path, this.accessToken, plainBody);
|
|
1624
|
+
if (!fallbackRes.ok) {
|
|
1625
|
+
const fbErrBody = await fallbackRes.text().catch(() => "");
|
|
1626
|
+
if (fallbackRes.status === 429) {
|
|
1627
|
+
process.stderr.write(`[QQ:${this.name}] MESSAGE DROPPED: rate-limited (429) on plain-text fallback for ${sanitizeLogText(chatId, 64)}
|
|
1566
1628
|
`);
|
|
1567
|
-
|
|
1629
|
+
return;
|
|
1630
|
+
}
|
|
1631
|
+
process.stderr.write(`[QQ:${this.name}] MESSAGE DROPPED: plain-text fallback failed (HTTP ${fallbackRes.status}: ${sanitizeLogText(fbErrBody, 200)}) for ${sanitizeLogText(chatId, 64)}
|
|
1632
|
+
`);
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
process.stderr.write(`[QQ:${this.name}] Plain-text fallback succeeded for ${sanitizeLogText(chatId, 64)}
|
|
1636
|
+
`);
|
|
1637
|
+
await fallbackRes.text().catch(() => "");
|
|
1638
|
+
return;
|
|
1568
1639
|
}
|
|
1640
|
+
await resp.text().catch(() => "");
|
|
1641
|
+
if (msgId)
|
|
1642
|
+
this.saveQQState();
|
|
1643
|
+
} catch (e) {
|
|
1644
|
+
if (msgId && !rollbackApplied) {
|
|
1645
|
+
this.msgSeqMap.set(msgId, nextSeq - 1);
|
|
1646
|
+
}
|
|
1647
|
+
if (msgId)
|
|
1648
|
+
this.saveQQState();
|
|
1649
|
+
process.stderr.write(`[QQ:${this.name}] Send error: ${sanitizeLogText(e instanceof Error ? e.message : String(e), 200)}
|
|
1650
|
+
`);
|
|
1651
|
+
throw e;
|
|
1569
1652
|
}
|
|
1570
|
-
if (msgId)
|
|
1571
|
-
this.saveQQState();
|
|
1572
1653
|
}
|
|
1573
1654
|
/**
|
|
1574
1655
|
* Resolve API routing: handles disposed check, token refresh, chatId validation,
|
|
@@ -1594,6 +1675,7 @@ var QQChannel = class extends ChannelBase {
|
|
|
1594
1675
|
this.disposed = true;
|
|
1595
1676
|
this.stopHeartbeat();
|
|
1596
1677
|
this.stopTokenRefresh();
|
|
1678
|
+
this.stopReplyMsgIdCleanup();
|
|
1597
1679
|
if (this.seenCleanupTimer) {
|
|
1598
1680
|
clearInterval(this.seenCleanupTimer);
|
|
1599
1681
|
this.seenCleanupTimer = null;
|
|
@@ -1602,6 +1684,10 @@ var QQChannel = class extends ChannelBase {
|
|
|
1602
1684
|
clearTimeout(this.reconnectTimer);
|
|
1603
1685
|
this.reconnectTimer = null;
|
|
1604
1686
|
}
|
|
1687
|
+
if (this.beforeExitHook) {
|
|
1688
|
+
process.off("beforeExit", this.beforeExitHook);
|
|
1689
|
+
this.beforeExitHook = null;
|
|
1690
|
+
}
|
|
1605
1691
|
this.flushQQState();
|
|
1606
1692
|
this.backupGlobalSessions();
|
|
1607
1693
|
if (this.ws) {
|
|
@@ -1628,18 +1714,31 @@ var QQChannel = class extends ChannelBase {
|
|
|
1628
1714
|
// ── State Persistence (cross-server context continuation) ──────
|
|
1629
1715
|
/** Debounced state persistence to avoid blocking event loop. */
|
|
1630
1716
|
saveQQState() {
|
|
1717
|
+
if (this.disposed)
|
|
1718
|
+
return;
|
|
1631
1719
|
if (this.saveTimer)
|
|
1632
1720
|
clearTimeout(this.saveTimer);
|
|
1721
|
+
const tmpPath = this.qqStatePath + ".tmp";
|
|
1633
1722
|
this.saveTimer = setTimeout(() => {
|
|
1723
|
+
if (this.disposed)
|
|
1724
|
+
return;
|
|
1634
1725
|
try {
|
|
1635
|
-
writeFileSync2(
|
|
1726
|
+
writeFileSync2(tmpPath, JSON.stringify({
|
|
1636
1727
|
chatTypeMap: Array.from(this.chatTypeMap.entries()),
|
|
1637
1728
|
replyMsgId: Array.from(this.replyMsgId.entries()),
|
|
1638
1729
|
msgSeqMap: Array.from(this.msgSeqMap.entries())
|
|
1639
1730
|
}), { mode: 384 });
|
|
1640
|
-
|
|
1731
|
+
renameSync(tmpPath, this.qqStatePath);
|
|
1732
|
+
} catch (e) {
|
|
1733
|
+
try {
|
|
1734
|
+
unlinkSync(tmpPath);
|
|
1735
|
+
} catch {
|
|
1736
|
+
}
|
|
1737
|
+
process.stderr.write(`[QQ:${this.name}] saveQQState write failed: ${sanitizeLogText(e instanceof Error ? e.message : String(e), 200)}
|
|
1738
|
+
`);
|
|
1641
1739
|
}
|
|
1642
1740
|
}, 500);
|
|
1741
|
+
this.saveTimer.unref();
|
|
1643
1742
|
}
|
|
1644
1743
|
/** Flush pending state writes immediately (called on disconnect). */
|
|
1645
1744
|
flushQQState() {
|
|
@@ -1647,35 +1746,78 @@ var QQChannel = class extends ChannelBase {
|
|
|
1647
1746
|
clearTimeout(this.saveTimer);
|
|
1648
1747
|
this.saveTimer = null;
|
|
1649
1748
|
}
|
|
1749
|
+
const tmpPath = this.qqStatePath + ".tmp";
|
|
1650
1750
|
try {
|
|
1651
|
-
writeFileSync2(
|
|
1751
|
+
writeFileSync2(tmpPath, JSON.stringify({
|
|
1652
1752
|
chatTypeMap: Array.from(this.chatTypeMap.entries()),
|
|
1653
1753
|
replyMsgId: Array.from(this.replyMsgId.entries()),
|
|
1654
1754
|
msgSeqMap: Array.from(this.msgSeqMap.entries())
|
|
1655
|
-
}));
|
|
1656
|
-
|
|
1755
|
+
}), { mode: 384 });
|
|
1756
|
+
renameSync(tmpPath, this.qqStatePath);
|
|
1757
|
+
} catch (e) {
|
|
1758
|
+
try {
|
|
1759
|
+
unlinkSync(tmpPath);
|
|
1760
|
+
} catch {
|
|
1761
|
+
}
|
|
1762
|
+
process.stderr.write(`[QQ:${this.name}] flushQQState write failed: ${sanitizeLogText(e instanceof Error ? e.message : String(e), 200)}
|
|
1763
|
+
`);
|
|
1657
1764
|
}
|
|
1658
1765
|
}
|
|
1659
1766
|
/**
|
|
1660
1767
|
* Restore QQ routing state from disk.
|
|
1661
|
-
*
|
|
1662
|
-
* entries
|
|
1663
|
-
*
|
|
1768
|
+
* Validates and filters every entry on restore — corrupt or unexpected
|
|
1769
|
+
* entries (e.g. unknown chat types, oversized replyMsgIds, negative seqs)
|
|
1770
|
+
* are silently dropped so they don't propagate into runtime routing.
|
|
1664
1771
|
*/
|
|
1665
1772
|
restoreQQState() {
|
|
1666
1773
|
try {
|
|
1667
1774
|
if (!existsSync2(this.qqStatePath))
|
|
1668
1775
|
return false;
|
|
1669
1776
|
const raw = JSON.parse(readFileSync2(this.qqStatePath, "utf-8"));
|
|
1670
|
-
if (raw.
|
|
1671
|
-
this.
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1777
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
1778
|
+
process.stderr.write(`[QQ:${this.name}] Invalid QQ state file (not an object), ignoring
|
|
1779
|
+
`);
|
|
1780
|
+
return false;
|
|
1781
|
+
}
|
|
1782
|
+
if (raw.chatTypeMap && Array.isArray(raw.chatTypeMap)) {
|
|
1783
|
+
const rawCT = raw.chatTypeMap;
|
|
1784
|
+
this.chatTypeMap = new Map(rawCT.filter(([k, v]) => typeof k === "string" && k.length <= 256 && (v === "c2c" || v === "group")));
|
|
1785
|
+
const dropped = rawCT.length - this.chatTypeMap.size;
|
|
1786
|
+
if (dropped > 0)
|
|
1787
|
+
process.stderr.write(`[QQ:${this.name}] Dropped ${dropped} invalid chatTypeMap entries during restore
|
|
1788
|
+
`);
|
|
1789
|
+
}
|
|
1790
|
+
if (raw.replyMsgId && Array.isArray(raw.replyMsgId)) {
|
|
1791
|
+
const now = Date.now();
|
|
1792
|
+
const rawRM = raw.replyMsgId;
|
|
1793
|
+
this.replyMsgId = new Map(rawRM.map(([k, v]) => (
|
|
1794
|
+
// Old format: string -> { msgId: v, timestamp: now }
|
|
1795
|
+
// New format: { msgId, timestamp } -> pass through
|
|
1796
|
+
typeof v === "string" ? [k, { msgId: v, timestamp: now }] : [k, v]
|
|
1797
|
+
)).filter(([k, v]) => {
|
|
1798
|
+
if (typeof k !== "string" || k.length > 256)
|
|
1799
|
+
return false;
|
|
1800
|
+
if (typeof v !== "object" || v === null)
|
|
1801
|
+
return false;
|
|
1802
|
+
const entry = v;
|
|
1803
|
+
return typeof entry.msgId === "string" && entry.msgId.length <= 128 && typeof entry.timestamp === "number" && Number.isFinite(entry.timestamp) && entry.timestamp <= now + _QQChannel.REPLY_MSG_ID_TTL_MS;
|
|
1804
|
+
}));
|
|
1805
|
+
const dropped = rawRM.length - this.replyMsgId.size;
|
|
1806
|
+
if (dropped > 0)
|
|
1807
|
+
process.stderr.write(`[QQ:${this.name}] Dropped ${dropped} invalid replyMsgId entries during restore
|
|
1808
|
+
`);
|
|
1809
|
+
}
|
|
1810
|
+
if (raw.msgSeqMap && Array.isArray(raw.msgSeqMap)) {
|
|
1811
|
+
const rawMS = raw.msgSeqMap;
|
|
1812
|
+
this.msgSeqMap = new Map(rawMS.filter(([k, v]) => typeof k === "string" && k.length <= 256 && typeof v === "number" && Number.isSafeInteger(v) && v >= 0));
|
|
1813
|
+
const dropped = rawMS.length - this.msgSeqMap.size;
|
|
1814
|
+
if (dropped > 0)
|
|
1815
|
+
process.stderr.write(`[QQ:${this.name}] Dropped ${dropped} invalid msgSeqMap entries during restore
|
|
1816
|
+
`);
|
|
1817
|
+
}
|
|
1676
1818
|
return true;
|
|
1677
1819
|
} catch (e) {
|
|
1678
|
-
process.stderr.write(`[QQ:${this.name}] Failed to restore QQ state: ${e instanceof Error ? e.message : String(e)}
|
|
1820
|
+
process.stderr.write(`[QQ:${this.name}] Failed to restore QQ state: ${sanitizeLogText(e instanceof Error ? e.message : String(e), 200)}
|
|
1679
1821
|
`);
|
|
1680
1822
|
return false;
|
|
1681
1823
|
}
|
|
@@ -1744,6 +1886,47 @@ var QQChannel = class extends ChannelBase {
|
|
|
1744
1886
|
} catch {
|
|
1745
1887
|
}
|
|
1746
1888
|
}
|
|
1889
|
+
// ── ReplyMsgId helpers ────────────────────────────────────────
|
|
1890
|
+
/**
|
|
1891
|
+
* Set replyMsgId for a chat, cleaning up the previous entry's msgSeqMap
|
|
1892
|
+
* to prevent orphaned entries accumulating over time.
|
|
1893
|
+
*/
|
|
1894
|
+
setReplyMsgId(chatId, msgId) {
|
|
1895
|
+
const oldEntry = this.replyMsgId.get(chatId);
|
|
1896
|
+
if (oldEntry && oldEntry.msgId !== msgId) {
|
|
1897
|
+
this.msgSeqMap.delete(oldEntry.msgId);
|
|
1898
|
+
}
|
|
1899
|
+
this.replyMsgId.set(chatId, { msgId, timestamp: Date.now() });
|
|
1900
|
+
this.saveQQState();
|
|
1901
|
+
}
|
|
1902
|
+
/**
|
|
1903
|
+
* Start periodic cleanup of expired replyMsgId entries.
|
|
1904
|
+
* Evicts entries older than 5 minutes every 60 seconds, and cascades
|
|
1905
|
+
* to msgSeqMap.
|
|
1906
|
+
*/
|
|
1907
|
+
startReplyMsgIdCleanup() {
|
|
1908
|
+
this.stopReplyMsgIdCleanup();
|
|
1909
|
+
this.replyMsgIdCleanupTimer = setInterval(() => {
|
|
1910
|
+
const cutoff = Date.now() - _QQChannel.REPLY_MSG_ID_TTL_MS;
|
|
1911
|
+
let dirty = false;
|
|
1912
|
+
for (const [chatId, entry] of this.replyMsgId) {
|
|
1913
|
+
if (entry.timestamp < cutoff) {
|
|
1914
|
+
this.msgSeqMap.delete(entry.msgId);
|
|
1915
|
+
this.replyMsgId.delete(chatId);
|
|
1916
|
+
dirty = true;
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
if (dirty)
|
|
1920
|
+
this.saveQQState();
|
|
1921
|
+
}, 6e4);
|
|
1922
|
+
this.replyMsgIdCleanupTimer.unref();
|
|
1923
|
+
}
|
|
1924
|
+
stopReplyMsgIdCleanup() {
|
|
1925
|
+
if (this.replyMsgIdCleanupTimer) {
|
|
1926
|
+
clearInterval(this.replyMsgIdCleanupTimer);
|
|
1927
|
+
this.replyMsgIdCleanupTimer = null;
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1747
1930
|
// ── Token ──────────────────────────────────────────────────────
|
|
1748
1931
|
async fetchToken() {
|
|
1749
1932
|
const safeName = this.name.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
@@ -1785,7 +1968,7 @@ var QQChannel = class extends ChannelBase {
|
|
|
1785
1968
|
this.fetchToken().catch((e) => {
|
|
1786
1969
|
if (this.disposed)
|
|
1787
1970
|
return;
|
|
1788
|
-
process.stderr.write(`[QQ:${this.name}] Token refresh failed: ${e}, retrying in 60s
|
|
1971
|
+
process.stderr.write(`[QQ:${this.name}] Token refresh failed: ${sanitizeLogText(e instanceof Error ? e.message : String(e), 200)}, retrying in 60s
|
|
1789
1972
|
`);
|
|
1790
1973
|
this.scheduleTokenRefreshRetry();
|
|
1791
1974
|
});
|
|
@@ -1800,7 +1983,7 @@ var QQChannel = class extends ChannelBase {
|
|
|
1800
1983
|
this.fetchToken().catch((e) => {
|
|
1801
1984
|
if (this.disposed)
|
|
1802
1985
|
return;
|
|
1803
|
-
process.stderr.write(`[QQ:${this.name}] Token refresh failed: ${e}, retrying in 60s
|
|
1986
|
+
process.stderr.write(`[QQ:${this.name}] Token refresh failed: ${sanitizeLogText(e instanceof Error ? e.message : String(e), 200)}, retrying in 60s
|
|
1804
1987
|
`);
|
|
1805
1988
|
this.scheduleTokenRefreshRetry();
|
|
1806
1989
|
});
|
|
@@ -1834,7 +2017,7 @@ var QQChannel = class extends ChannelBase {
|
|
|
1834
2017
|
const msg = JSON.parse(data.toString());
|
|
1835
2018
|
this.handleGatewayMessage(msg, resolve);
|
|
1836
2019
|
} catch (e) {
|
|
1837
|
-
process.stderr.write(`[QQ:${this.name}] Malformed gateway message: ${e instanceof Error ? e.message : String(e)}
|
|
2020
|
+
process.stderr.write(`[QQ:${this.name}] Malformed gateway message: ${sanitizeLogText(e instanceof Error ? e.message : String(e), 200)}
|
|
1838
2021
|
`);
|
|
1839
2022
|
}
|
|
1840
2023
|
});
|
|
@@ -1874,7 +2057,7 @@ var QQChannel = class extends ChannelBase {
|
|
|
1874
2057
|
}
|
|
1875
2058
|
});
|
|
1876
2059
|
this.ws.on("error", (e) => {
|
|
1877
|
-
process.stderr.write(`[QQ:${this.name}] WebSocket error: ${e.message}
|
|
2060
|
+
process.stderr.write(`[QQ:${this.name}] WebSocket error: ${sanitizeLogText(e.message, 200)}
|
|
1878
2061
|
`);
|
|
1879
2062
|
if (!this.ws || this.ws.readyState !== wrapper_default.OPEN) {
|
|
1880
2063
|
reject(e);
|
|
@@ -2002,7 +2185,7 @@ var QQChannel = class extends ChannelBase {
|
|
|
2002
2185
|
} catch (e) {
|
|
2003
2186
|
const msg = e instanceof Error ? e.message : String(e);
|
|
2004
2187
|
const backoff = Math.min(1e3 * 2 ** (attempt + 1), 3e4);
|
|
2005
|
-
process.stderr.write(`[QQ:${this.name}] RC: ${msg} (retry in ${backoff}ms, attempt ${attempt + 1}/${maxGwRetries})
|
|
2188
|
+
process.stderr.write(`[QQ:${this.name}] RC: ${sanitizeLogText(msg, 200)} (retry in ${backoff}ms, attempt ${attempt + 1}/${maxGwRetries})
|
|
2006
2189
|
`);
|
|
2007
2190
|
if (attempt < maxGwRetries - 1)
|
|
2008
2191
|
await this.sleep(backoff);
|
|
@@ -2051,7 +2234,7 @@ var QQChannel = class extends ChannelBase {
|
|
|
2051
2234
|
this.seenMessages.set(eventId, now);
|
|
2052
2235
|
if (!this.seenCleanupTimer) {
|
|
2053
2236
|
this.seenCleanupTimer = setInterval(() => {
|
|
2054
|
-
const cutoff = Date.now() -
|
|
2237
|
+
const cutoff = Date.now() - _QQChannel.REPLY_MSG_ID_TTL_MS;
|
|
2055
2238
|
for (const [id, ts] of this.seenMessages) {
|
|
2056
2239
|
if (ts < cutoff)
|
|
2057
2240
|
this.seenMessages.delete(id);
|
|
@@ -2060,7 +2243,7 @@ var QQChannel = class extends ChannelBase {
|
|
|
2060
2243
|
clearInterval(this.seenCleanupTimer);
|
|
2061
2244
|
this.seenCleanupTimer = null;
|
|
2062
2245
|
}
|
|
2063
|
-
}, 6e4);
|
|
2246
|
+
}, 6e4).unref();
|
|
2064
2247
|
}
|
|
2065
2248
|
return false;
|
|
2066
2249
|
}
|
|
@@ -2071,8 +2254,7 @@ var QQChannel = class extends ChannelBase {
|
|
|
2071
2254
|
return;
|
|
2072
2255
|
const chatId = event.author.user_openid || event.author.id;
|
|
2073
2256
|
this.chatTypeMap.set(chatId, "c2c");
|
|
2074
|
-
this.
|
|
2075
|
-
this.saveQQState();
|
|
2257
|
+
this.setReplyMsgId(chatId, event.id);
|
|
2076
2258
|
this.handleInbound({
|
|
2077
2259
|
channelName: this.name,
|
|
2078
2260
|
senderId: chatId,
|
|
@@ -2083,7 +2265,7 @@ var QQChannel = class extends ChannelBase {
|
|
|
2083
2265
|
isGroup: false,
|
|
2084
2266
|
isMentioned: true,
|
|
2085
2267
|
isReplyToBot: false
|
|
2086
|
-
}).catch((e) => process.stderr.write(`[QQ:${this.name}] C2C handler error: ${e}
|
|
2268
|
+
}).catch((e) => process.stderr.write(`[QQ:${this.name}] C2C handler error: ${sanitizeLogText(e instanceof Error ? e.message : String(e), 200)}
|
|
2087
2269
|
`));
|
|
2088
2270
|
}
|
|
2089
2271
|
handleGroup(event) {
|
|
@@ -2096,8 +2278,7 @@ var QQChannel = class extends ChannelBase {
|
|
|
2096
2278
|
}
|
|
2097
2279
|
const chatId = event.group_openid;
|
|
2098
2280
|
this.chatTypeMap.set(chatId, "group");
|
|
2099
|
-
this.
|
|
2100
|
-
this.saveQQState();
|
|
2281
|
+
this.setReplyMsgId(chatId, event.id);
|
|
2101
2282
|
const senderName = event.author.username || event.author.id || "QQ User";
|
|
2102
2283
|
const cleanText = (event.content || "").replace(/<@[^>]{1,64}>/g, "").trim();
|
|
2103
2284
|
if (!cleanText)
|
|
@@ -2123,7 +2304,7 @@ var QQChannel = class extends ChannelBase {
|
|
|
2123
2304
|
// every group message is semantically a reply to the bot.
|
|
2124
2305
|
isReplyToBot: true,
|
|
2125
2306
|
...isSlash ? {} : { alreadyPrefixed: true }
|
|
2126
|
-
}).catch((e) => process.stderr.write(`[QQ:${this.name}] Group handler error: ${e}
|
|
2307
|
+
}).catch((e) => process.stderr.write(`[QQ:${this.name}] Group handler error: ${sanitizeLogText(e instanceof Error ? e.message : String(e), 200)}
|
|
2127
2308
|
`));
|
|
2128
2309
|
}
|
|
2129
2310
|
};
|
|
@@ -12,8 +12,8 @@ import "./chunk-7RYW5LQV.js";
|
|
|
12
12
|
import {
|
|
13
13
|
ChannelBase,
|
|
14
14
|
isTerminalTaskLifecycleType
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-
|
|
15
|
+
} from "./chunk-6BEOH4KK.js";
|
|
16
|
+
import "./chunk-VRDMOSQS.js";
|
|
17
17
|
import "./chunk-K5PGHDBN.js";
|
|
18
18
|
import {
|
|
19
19
|
require_minimal2 as require_minimal
|