@captain-app/openclaw 2026.2.4
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/CHANGELOG.md +1528 -0
- package/LICENSE +21 -0
- package/README-header.png +0 -0
- package/README.md +539 -0
- package/assets/avatar-placeholder.svg +19 -0
- package/assets/chrome-extension/README.md +22 -0
- package/assets/chrome-extension/background.js +438 -0
- package/assets/chrome-extension/icons/icon128.png +0 -0
- package/assets/chrome-extension/icons/icon16.png +0 -0
- package/assets/chrome-extension/icons/icon32.png +0 -0
- package/assets/chrome-extension/icons/icon48.png +0 -0
- package/assets/chrome-extension/manifest.json +25 -0
- package/assets/chrome-extension/options.html +196 -0
- package/assets/chrome-extension/options.js +59 -0
- package/assets/dmg-background-small.png +0 -0
- package/assets/dmg-background.png +0 -0
- package/dist/accounts-ClnuDahN.js +250 -0
- package/dist/accounts-DzBgAM3C.js +251 -0
- package/dist/acp-cli-BEDDkzXH.js +926 -0
- package/dist/acp-cli-CwV4mdnW.js +923 -0
- package/dist/agent-CArjbSeE.js +695 -0
- package/dist/agent-CB7x5HLT.js +695 -0
- package/dist/agent-scope-BbT4OG2N.js +545 -0
- package/dist/agent-scope-C_O6Vpl0.js +545 -0
- package/dist/agent-scope-Csu2B6AM.js +606 -0
- package/dist/archive-CWrnG1CH.js +85 -0
- package/dist/archive-ccN9aDgq.js +85 -0
- package/dist/audit-DXPkQ275.js +1686 -0
- package/dist/audit-eH7nwgsM.js +1686 -0
- package/dist/auth-health-Bj7Gjbv0.js +149 -0
- package/dist/auth-health-CjjJhHey.js +149 -0
- package/dist/auth-nnRYiqpH.js +192 -0
- package/dist/auth-profiles-DVLfuixr.js +2954 -0
- package/dist/auth-y1BLPUhX.js +192 -0
- package/dist/boolean-Wzu0-e0P.js +30 -0
- package/dist/brew-Cqi8b49_.js +46 -0
- package/dist/brew-DyBGNK8A.js +46 -0
- package/dist/build-info.json +5 -0
- package/dist/call-B7EveN4V.js +252 -0
- package/dist/call-vuUQIjOj.js +252 -0
- package/dist/canvas-host/a2ui/.bundle.hash +1 -0
- package/dist/canvas-host/a2ui/a2ui.bundle.js +17780 -0
- package/dist/canvas-host/a2ui/index.html +307 -0
- package/dist/channel-options-CJfmOkol.js +32 -0
- package/dist/channel-options-lFguMTz1.js +62 -0
- package/dist/channel-selection-BmND9mWj.js +51 -0
- package/dist/channel-selection-cGhL9G0c.js +51 -0
- package/dist/channel-summary-B4G513Eb.js +1154 -0
- package/dist/channel-summary-MCwBCa5y.js +1154 -0
- package/dist/channels-cli-C2Of1mZG.js +1411 -0
- package/dist/channels-cli-DFynrP1H.js +1413 -0
- package/dist/channels-status-issues-YohTjZ-I.js +18 -0
- package/dist/channels-status-issues-ZcR1U-m5.js +18 -0
- package/dist/chrome-B3IuUad-.js +1953 -0
- package/dist/chrome-BZ9K48w9.js +1973 -0
- package/dist/clack-prompter-B9yLhyOm.js +92 -0
- package/dist/clack-prompter-BybM9xdL.js +92 -0
- package/dist/cli/daemon-cli.js +2 -0
- package/dist/cli-BJZdJwug.js +89 -0
- package/dist/cli-BQSoKu3d.js +86 -0
- package/dist/cli-utils-CO4jEMn0.js +43 -0
- package/dist/cli-utils-gtE-0a0D.js +43 -0
- package/dist/client-DPqNOpK3.js +1609 -0
- package/dist/client-DySXIFCA.js +1609 -0
- package/dist/command-format-CFzL448l.js +52 -0
- package/dist/command-format-DELazozB.js +52 -0
- package/dist/command-format-ayFsmwwz.js +38 -0
- package/dist/command-options-CsjxK4cZ.js +33 -0
- package/dist/commands-BRe9VTyU.js +229 -0
- package/dist/completion-cli-DlkjK0iC.js +390 -0
- package/dist/completion-cli-E6Pt41AL.js +387 -0
- package/dist/config-BtSTwPcH.js +4882 -0
- package/dist/config-DfMIMT-f.js +4881 -0
- package/dist/config-_d7_WcRv.js +5623 -0
- package/dist/config-guard-wSnm-U8a.js +5628 -0
- package/dist/configure-CPHAFKlg.js +895 -0
- package/dist/configure-DK1XgXYx.js +894 -0
- package/dist/constants-CNTiY-ZN.js +65 -0
- package/dist/constants-hpmbslG7.js +65 -0
- package/dist/control-service-CqX5g_ko.js +61 -0
- package/dist/control-service-o6xe3hEb.js +61 -0
- package/dist/control-ui/apple-touch-icon.png +0 -0
- package/dist/control-ui/assets/index-RwcW4Xl0.css +1 -0
- package/dist/control-ui/assets/index-ryaCcbyp.js +4584 -0
- package/dist/control-ui/assets/index-ryaCcbyp.js.map +1 -0
- package/dist/control-ui/favicon-32.png +0 -0
- package/dist/control-ui/favicon.ico +0 -0
- package/dist/control-ui/favicon.svg +22 -0
- package/dist/control-ui/index.html +17 -0
- package/dist/cron-cli-BoSaDgvH.js +453 -0
- package/dist/cron-cli-qVandvsD.js +456 -0
- package/dist/daemon-cli-C4gGWa15.js +760 -0
- package/dist/daemon-cli-DV_X0Krf.js +761 -0
- package/dist/daemon-runtime-D5hbSrdO.js +460 -0
- package/dist/daemon-runtime-DXUfrXBC.js +460 -0
- package/dist/deliver-BxK5nI2P.js +2587 -0
- package/dist/deliver-Dwzg9LUd.js +2557 -0
- package/dist/deliver-qpYZp20m.js +2587 -0
- package/dist/deps-CUXtMV9d.js +27 -0
- package/dist/deps-WBvZpFV_.js +27 -0
- package/dist/devices-cli-B2s18Qrh.js +207 -0
- package/dist/devices-cli-D1UEtMUJ.js +204 -0
- package/dist/directory-cli-BXQbrkfM.js +247 -0
- package/dist/directory-cli-CqA7tRbq.js +244 -0
- package/dist/dispatcher-Dyv7T-1r.js +160 -0
- package/dist/dns-cli-CWxKD22D.js +198 -0
- package/dist/dns-cli-CzKr_Fxj.js +201 -0
- package/dist/docs-cli-BNyxUbWr.js +159 -0
- package/dist/docs-cli-DYpTbo3i.js +161 -0
- package/dist/doctor-C8fDYZLq.js +2583 -0
- package/dist/doctor-hYcqp7c0.js +2585 -0
- package/dist/entry.js +1326 -0
- package/dist/env-l7QVNj6j.js +32 -0
- package/dist/errors-CMCg46fK.js +1952 -0
- package/dist/exec-B8JKbXKW.js +246 -0
- package/dist/exec-BMnoMcZW.js +1099 -0
- package/dist/exec-HEWTMJ7j.js +246 -0
- package/dist/exec-approvals-DtrnHx6M.js +1026 -0
- package/dist/exec-approvals-Y42bE8ud.js +1026 -0
- package/dist/exec-approvals-cli-CIedYxP3.js +385 -0
- package/dist/exec-approvals-cli-xpbxnj4O.js +388 -0
- package/dist/extensionAPI.js +66572 -0
- package/dist/format-Dzy9uRLE.js +34 -0
- package/dist/format-sj0fELBK.js +34 -0
- package/dist/gateway-cli-5A-KNLEC.js +16635 -0
- package/dist/gateway-cli-B8kS4chb.js +16637 -0
- package/dist/gateway-rpc-15n38Ize.js +28 -0
- package/dist/gateway-rpc-TMVRgGfj.js +28 -0
- package/dist/github-copilot-auth-DVZj4Zgh.js +1104 -0
- package/dist/github-copilot-auth-DeGYyLY9.js +1104 -0
- package/dist/github-copilot-token-B3SA95yo.js +103 -0
- package/dist/github-copilot-token-C8XFYz0i.js +103 -0
- package/dist/github-copilot-token-CnxakiSC.js +103 -0
- package/dist/gmail-setup-utils-CWPC386a.js +428 -0
- package/dist/gmail-setup-utils-eJVB5Ewp.js +428 -0
- package/dist/health-format-B0tMTk3C.js +1189 -0
- package/dist/health-format-DaURVaUn.js +1188 -0
- package/dist/help-format-CEsRHU2f.js +17 -0
- package/dist/help-format-GuCWws6r.js +17 -0
- package/dist/helpers-BEJ-phFf.js +25 -0
- package/dist/helpers-BtbBZVKZ.js +10 -0
- package/dist/helpers-C12w9zxf.js +10 -0
- package/dist/helpers-CzjGJZmJ.js +25 -0
- package/dist/hooks/bundled/boot-md/HOOK.md +19 -0
- package/dist/hooks/bundled/command-logger/HOOK.md +122 -0
- package/dist/hooks/bundled/session-memory/HOOK.md +109 -0
- package/dist/hooks/bundled/soul-evil/HOOK.md +71 -0
- package/dist/hooks-cli-BZCMAnW2.js +1058 -0
- package/dist/hooks-cli-D0CEFg3P.js +1061 -0
- package/dist/hooks-status-Bn7_O8PM.js +443 -0
- package/dist/hooks-status-BrWVfIn0.js +443 -0
- package/dist/image-BS022pvv.js +1421 -0
- package/dist/image-BzJtY34J.js +629 -0
- package/dist/image-CBqmIbQQ.js +629 -0
- package/dist/index.js +5809 -0
- package/dist/installs-BP4K5L33.js +388 -0
- package/dist/installs-DOpTt7VZ.js +388 -0
- package/dist/is-main-B4o72sqg.js +25 -0
- package/dist/is-main-PYGa3tDA.js +25 -0
- package/dist/links-B4nk2iDf.js +15 -0
- package/dist/links-DwjRqxgR.js +15 -0
- package/dist/loader-Cn4EV_pf.js +63690 -0
- package/dist/logging-CS3tbYDj.js +15 -0
- package/dist/logging-CY-Q5cwf.js +1 -0
- package/dist/logging-DhiLkhLw.js +15 -0
- package/dist/logging-pqyrk15z.js +1 -0
- package/dist/login-qr-CD164Aw1.js +478 -0
- package/dist/login-qr-D7Zdgji2.js +478 -0
- package/dist/login-qr-YgILJ4VC.js +475 -0
- package/dist/logs-cli-BdS0Uv0I.js +227 -0
- package/dist/logs-cli-CqSN1GzB.js +230 -0
- package/dist/manager-CfGY5zND.js +2870 -0
- package/dist/manager-CjuBqFRL.js +2870 -0
- package/dist/manager-CoBEAQKm.js +2872 -0
- package/dist/manifest-registry-Bwjq9Iev.js +668 -0
- package/dist/manifest-registry-D2Yntqcb.js +668 -0
- package/dist/message-channel-Cjsiqxok.js +105 -0
- package/dist/message-channel-D6v_oPAg.js +105 -0
- package/dist/model-selection-Cv5Ox_tY.js +2956 -0
- package/dist/model-selection-Dr-5U5-l.js +2708 -0
- package/dist/models-cli-B39ckynD.js +2541 -0
- package/dist/models-cli-DoiYsBYw.js +2544 -0
- package/dist/net-CFCxaipF.js +137 -0
- package/dist/net-DKJPqXuW.js +137 -0
- package/dist/node-cli-C_FYF-RA.js +1456 -0
- package/dist/node-cli-DWPoNsQS.js +1459 -0
- package/dist/node-service-DcJREOww.js +67 -0
- package/dist/node-service-DuZ9Us9h.js +67 -0
- package/dist/nodes-cli-Elo6tlen.js +1210 -0
- package/dist/nodes-cli-zqryRUWB.js +1207 -0
- package/dist/nodes-screen-C4aCrxie.js +157 -0
- package/dist/nodes-screen-D4PSynkR.js +157 -0
- package/dist/note-CQhSvgQv.js +73 -0
- package/dist/note-_C44YfAQ.js +73 -0
- package/dist/onboard-channels-CHBDi-ZA.js +670 -0
- package/dist/onboard-channels-DOEKyxaL.js +670 -0
- package/dist/onboard-skills-BUTXREDZ.js +3327 -0
- package/dist/onboard-skills-CSLYZmZA.js +3327 -0
- package/dist/onboarding-CgKb8b39.js +3232 -0
- package/dist/openclaw-root-9ILYSmJ9.js +84 -0
- package/dist/openclaw-root-Cvotktkd.js +84 -0
- package/dist/pairing-cli-B4UGR2at.js +114 -0
- package/dist/pairing-cli-BWDDl8cf.js +117 -0
- package/dist/pairing-labels-ClZ-fTWT.js +9 -0
- package/dist/pairing-labels-Ds7BPOkj.js +9 -0
- package/dist/pairing-store-DDLNuzmx.js +391 -0
- package/dist/pairing-store-DRn08lZD.js +391 -0
- package/dist/parse-87ybtYW1.js +23 -0
- package/dist/parse-OCFfznr3.js +23 -0
- package/dist/parse-log-line-C9aL5PUL.js +44 -0
- package/dist/parse-log-line-DxRaGzQb.js +44 -0
- package/dist/parse-timeout-CFqNj7No.js +16 -0
- package/dist/parse-timeout-DV8NQQWk.js +16 -0
- package/dist/path-env-C7kiJUgG.js +77 -0
- package/dist/path-env-DEj4CiFN.js +77 -0
- package/dist/paths-B-q1nXdY.js +43 -0
- package/dist/paths-B1kfl4h5.js +164 -0
- package/dist/paths-B4kigINg.js +40 -0
- package/dist/paths-CHGbP1-A.js +43 -0
- package/dist/paths-scjhy7N2.js +180 -0
- package/dist/pi-embedded-helpers-C19wUpMB.js +8451 -0
- package/dist/pi-embedded-helpers-CT5VuLCb.js +1293 -0
- package/dist/pi-embedded-helpers-Dl8e5Rf8.js +1293 -0
- package/dist/pi-model-discovery-B6CsmK6Y.js +20 -0
- package/dist/pi-model-discovery-DsRqYJLy.js +20 -0
- package/dist/pi-model-discovery-EhM2JAQo.js +20 -0
- package/dist/pi-tools.policy-BvkSDFDN.js +229 -0
- package/dist/plugin-auto-enable-Bd_StZzz.js +461 -0
- package/dist/plugin-auto-enable-DBhXb_0x.js +461 -0
- package/dist/plugin-sdk/agent-scope-DdwUKIOe.js +606 -0
- package/dist/plugin-sdk/chrome-G8apFa5p.js +1953 -0
- package/dist/plugin-sdk/command-format-qUVxzqYm.js +52 -0
- package/dist/plugin-sdk/config-Cm1M7tgH.js +5623 -0
- package/dist/plugin-sdk/deliver-Cl8uowiO.js +2557 -0
- package/dist/plugin-sdk/exec-Cm9b2r9Q.js +1107 -0
- package/dist/plugin-sdk/github-copilot-token-BHNcM4_B.js +103 -0
- package/dist/plugin-sdk/image-7PgoS2VD.js +1421 -0
- package/dist/plugin-sdk/index.d.ts +8908 -0
- package/dist/plugin-sdk/index.js +70888 -0
- package/dist/plugin-sdk/login-qr-qTALvWi2.js +475 -0
- package/dist/plugin-sdk/manager-Cs3EQZCb.js +2870 -0
- package/dist/plugin-sdk/model-selection-BgC1E1a7.js +2708 -0
- package/dist/plugin-sdk/paths-BYpoyRv5.js +164 -0
- package/dist/plugin-sdk/paths-DNQE-bvr.js +40 -0
- package/dist/plugin-sdk/pi-embedded-helpers-5jNqW_dE.js +8755 -0
- package/dist/plugin-sdk/pi-model-discovery-BUGEht9A.js +20 -0
- package/dist/plugin-sdk/pw-ai-COTtei4a.js +1649 -0
- package/dist/plugin-sdk/qmd-manager-ClSwiAJl.js +615 -0
- package/dist/plugin-sdk/redact-2AzjOfk2.js +94 -0
- package/dist/plugin-sdk/rolldown-runtime-Cbj13DAv.js +20 -0
- package/dist/plugin-sdk/sqlite-gCW7MlLs.js +215 -0
- package/dist/plugin-sdk/transcript-events-DGF257vD.js +17 -0
- package/dist/plugins-C3Bm-HQV.js +494 -0
- package/dist/plugins-QJjTXliB.js +495 -0
- package/dist/plugins-cli-DTci0JQb.js +443 -0
- package/dist/plugins-cli-wJsN1HHK.js +440 -0
- package/dist/ports-CiW9dmMq.js +96 -0
- package/dist/program-BWpTHh1I.js +188 -0
- package/dist/progress-Bcjniu7m.js +133 -0
- package/dist/progress-CvaSPjS9.js +133 -0
- package/dist/prompt-style-CFsleyxV.js +9 -0
- package/dist/prompt-style-DYJdrXyV.js +9 -0
- package/dist/prompts-Bt9fwsg2.js +10 -0
- package/dist/prompts-CudpZgTI.js +10 -0
- package/dist/pw-ai-08F3GD-3.js +1649 -0
- package/dist/pw-ai-ZmHxHQnx.js +1651 -0
- package/dist/pw-ai-tNPuRNn3.js +1649 -0
- package/dist/qmd-manager-2r-4n3sP.js +617 -0
- package/dist/qmd-manager-CF52nuBg.js +615 -0
- package/dist/qmd-manager-HEm5H2mk.js +616 -0
- package/dist/redact-BICFkpn7.js +97 -0
- package/dist/redact-BIMJ3ntQ.js +94 -0
- package/dist/redact-KzWHRS5J.js +97 -0
- package/dist/register.subclis-D2K25c84.js +348 -0
- package/dist/register.subclis-Dd8LbOLi.js +342 -0
- package/dist/reply-5UNWRwMn.js +63693 -0
- package/dist/restart-sentinel-Cr0vUxB8.js +65 -0
- package/dist/restart-sentinel-DUemCjgU.js +65 -0
- package/dist/rolldown-runtime-Cbj13DAv.js +20 -0
- package/dist/routes-C6UpTPas.js +2410 -0
- package/dist/routes-ClNyEvlm.js +2410 -0
- package/dist/rpc-D0mf7DIw.js +95 -0
- package/dist/rpc-DYdOrgd9.js +95 -0
- package/dist/run-main-CojI7gWx.js +194 -0
- package/dist/runtime-guard-68M_evhb.js +60 -0
- package/dist/runtime-guard-DkjmhnBD.js +60 -0
- package/dist/sandbox-Ca81z3Tw.js +2924 -0
- package/dist/sandbox-cli-D75GApgp.js +459 -0
- package/dist/sandbox-cli-E4SJsC1C.js +462 -0
- package/dist/sandbox-knontqD9.js +2925 -0
- package/dist/security-cli-BLihvXO-.js +503 -0
- package/dist/security-cli-IGQCsK4g.js +506 -0
- package/dist/server-context-B9GX5GOI.js +740 -0
- package/dist/server-context-BFH7HB_M.js +740 -0
- package/dist/server-node-events-CTdHBiEA.js +218 -0
- package/dist/server-node-events-DAV14qPr.js +215 -0
- package/dist/service-BZNBq9hq.js +680 -0
- package/dist/service-C-BLXx9U.js +680 -0
- package/dist/service-audit-BfJv4NqZ.js +542 -0
- package/dist/service-audit-Bw3M2OEI.js +542 -0
- package/dist/shared-5SH-45AX.js +74 -0
- package/dist/shared-BxRm5uLU.js +74 -0
- package/dist/shared-C80Rmxsd.js +150 -0
- package/dist/shared-fGK6_D2v.js +150 -0
- package/dist/skills-Bhp0l6UK.js +693 -0
- package/dist/skills-Tky2kCMO.js +694 -0
- package/dist/skills-cli-6rCClAE4.js +287 -0
- package/dist/skills-cli-C4nLCrLw.js +290 -0
- package/dist/skills-status-CENcKr3I.js +187 -0
- package/dist/skills-status-DX1eUYvk.js +187 -0
- package/dist/sqlite-CmdZSZRx.js +197 -0
- package/dist/sqlite-Dnmf3LS7.js +215 -0
- package/dist/sqlite-QDf0yuU0.js +215 -0
- package/dist/status-BSfGAp2D.js +27 -0
- package/dist/status-Bp_2NMjt.js +27 -0
- package/dist/status-C0ANDr0T.js +3140 -0
- package/dist/status-CCHBIZnm.js +21 -0
- package/dist/status-Vuqbw2Bb.js +21 -0
- package/dist/status.update-BZW5r8Su.js +79 -0
- package/dist/status.update-BnD93_O8.js +79 -0
- package/dist/subsystem-CAq3uyo7.js +834 -0
- package/dist/system-cli-Bb9zmCO1.js +83 -0
- package/dist/system-cli-TIIQ04ls.js +80 -0
- package/dist/systemd-0Qa_nGqe.js +438 -0
- package/dist/systemd-Czb0Xsm7.js +438 -0
- package/dist/systemd-hints-CWoEOQRb.js +19 -0
- package/dist/systemd-hints-Cv3RN_mZ.js +19 -0
- package/dist/systemd-linger-CsdvcIoS.js +75 -0
- package/dist/systemd-linger-DKUFHcLn.js +75 -0
- package/dist/table-DNPESyNj.js +279 -0
- package/dist/table-DS4-gmkV.js +279 -0
- package/dist/tailnet-Bg_vE5qi.js +42 -0
- package/dist/tailnet-CrNWlQRJ.js +42 -0
- package/dist/tailscale-CBv58toW.js +252 -0
- package/dist/tailscale-DCnMs7_q.js +225 -0
- package/dist/tool-display-BEACy9rK.js +795 -0
- package/dist/tool-display-NYQnSpdo.js +795 -0
- package/dist/transcript-events-CsB1Saa6.js +17 -0
- package/dist/transcript-events-DDYvbmRV.js +17 -0
- package/dist/transcript-events-JLH5W4He.js +17 -0
- package/dist/tui--NY0rnjr.js +2542 -0
- package/dist/tui-DqJfGtvM.js +2543 -0
- package/dist/tui-cli-BuHNY6wF.js +54 -0
- package/dist/tui-cli-LMFV982e.js +57 -0
- package/dist/update-CRpHtCgz.js +317 -0
- package/dist/update-D3qruxhj.js +317 -0
- package/dist/update-cli-CFF-pslM.js +948 -0
- package/dist/update-cli-cn9pEMX7.js +951 -0
- package/dist/update-runner-CxGU142L.js +1221 -0
- package/dist/update-runner-DNobz_ft.js +1221 -0
- package/dist/utils-CKSrBNwq.js +192 -0
- package/dist/utils-DX85MiPR.js +188 -0
- package/dist/webhooks-cli-BGtt2HAR.js +312 -0
- package/dist/webhooks-cli-DHLZrEO_.js +309 -0
- package/dist/widearea-dns-BpG7ATO8.js +127 -0
- package/dist/widearea-dns-D4wkCJly.js +127 -0
- package/dist/ws-3zr8WUwL.js +13 -0
- package/dist/ws-log-BXcT2xQk.js +267 -0
- package/dist/ws-log-DbDIUsgz.js +267 -0
- package/dist/ws-lzrgabja.js +13 -0
- package/dist/wsl-D2O2qOrl.js +160 -0
- package/docs/.i18n/README.md +31 -0
- package/docs/.i18n/glossary.zh-CN.json +190 -0
- package/docs/.i18n/zh-CN.tm.jsonl +1329 -0
- package/docs/CNAME +1 -0
- package/docs/_config.yml +53 -0
- package/docs/_layouts/default.html +145 -0
- package/docs/assets/markdown.css +179 -0
- package/docs/assets/openclaw-logo-text-dark.png +0 -0
- package/docs/assets/openclaw-logo-text.png +0 -0
- package/docs/assets/pixel-lobster.svg +60 -0
- package/docs/assets/showcase/agents-ui.jpg +0 -0
- package/docs/assets/showcase/bambu-cli.png +0 -0
- package/docs/assets/showcase/codexmonitor.png +0 -0
- package/docs/assets/showcase/gohome-grafana.png +0 -0
- package/docs/assets/showcase/ios-testflight.jpg +0 -0
- package/docs/assets/showcase/oura-health.png +0 -0
- package/docs/assets/showcase/padel-cli.svg +11 -0
- package/docs/assets/showcase/padel-screenshot.jpg +0 -0
- package/docs/assets/showcase/papla-tts.jpg +0 -0
- package/docs/assets/showcase/pr-review-telegram.jpg +0 -0
- package/docs/assets/showcase/roborock-screenshot.jpg +0 -0
- package/docs/assets/showcase/roborock-status.svg +13 -0
- package/docs/assets/showcase/roof-camera-sky.jpg +0 -0
- package/docs/assets/showcase/snag.png +0 -0
- package/docs/assets/showcase/tesco-shop.jpg +0 -0
- package/docs/assets/showcase/wienerlinien.png +0 -0
- package/docs/assets/showcase/wine-cellar-skill.jpg +0 -0
- package/docs/assets/showcase/winix-air-purifier.jpg +0 -0
- package/docs/assets/showcase/xuezh-pronunciation.jpeg +0 -0
- package/docs/assets/terminal.css +473 -0
- package/docs/assets/theme.js +55 -0
- package/docs/automation/auth-monitoring.md +44 -0
- package/docs/automation/cron-jobs.md +468 -0
- package/docs/automation/cron-vs-heartbeat.md +282 -0
- package/docs/automation/gmail-pubsub.md +256 -0
- package/docs/automation/poll.md +69 -0
- package/docs/automation/webhook.md +163 -0
- package/docs/bedrock.md +176 -0
- package/docs/brave-search.md +41 -0
- package/docs/broadcast-groups.md +442 -0
- package/docs/channels/bluebubbles.md +338 -0
- package/docs/channels/discord.md +475 -0
- package/docs/channels/feishu.md +507 -0
- package/docs/channels/googlechat.md +250 -0
- package/docs/channels/grammy.md +31 -0
- package/docs/channels/imessage.md +299 -0
- package/docs/channels/index.md +46 -0
- package/docs/channels/line.md +186 -0
- package/docs/channels/location.md +56 -0
- package/docs/channels/matrix.md +233 -0
- package/docs/channels/mattermost.md +138 -0
- package/docs/channels/msteams.md +768 -0
- package/docs/channels/nextcloud-talk.md +136 -0
- package/docs/channels/nostr.md +233 -0
- package/docs/channels/signal.md +202 -0
- package/docs/channels/slack.md +548 -0
- package/docs/channels/telegram.md +750 -0
- package/docs/channels/tlon.md +132 -0
- package/docs/channels/troubleshooting.md +29 -0
- package/docs/channels/twitch.md +379 -0
- package/docs/channels/whatsapp.md +404 -0
- package/docs/channels/zalo.md +189 -0
- package/docs/channels/zalouser.md +140 -0
- package/docs/cli/acp.md +170 -0
- package/docs/cli/agent.md +24 -0
- package/docs/cli/agents.md +75 -0
- package/docs/cli/approvals.md +50 -0
- package/docs/cli/browser.md +107 -0
- package/docs/cli/channels.md +79 -0
- package/docs/cli/config.md +50 -0
- package/docs/cli/configure.md +33 -0
- package/docs/cli/cron.md +42 -0
- package/docs/cli/dashboard.md +16 -0
- package/docs/cli/devices.md +67 -0
- package/docs/cli/directory.md +63 -0
- package/docs/cli/dns.md +23 -0
- package/docs/cli/docs.md +15 -0
- package/docs/cli/doctor.md +41 -0
- package/docs/cli/gateway.md +199 -0
- package/docs/cli/health.md +21 -0
- package/docs/cli/hooks.md +304 -0
- package/docs/cli/index.md +1029 -0
- package/docs/cli/logs.md +24 -0
- package/docs/cli/memory.md +45 -0
- package/docs/cli/message.md +239 -0
- package/docs/cli/models.md +79 -0
- package/docs/cli/node.md +112 -0
- package/docs/cli/nodes.md +73 -0
- package/docs/cli/onboard.md +29 -0
- package/docs/cli/pairing.md +21 -0
- package/docs/cli/plugins.md +62 -0
- package/docs/cli/reset.md +17 -0
- package/docs/cli/sandbox.md +152 -0
- package/docs/cli/security.md +26 -0
- package/docs/cli/sessions.md +16 -0
- package/docs/cli/setup.md +29 -0
- package/docs/cli/skills.md +26 -0
- package/docs/cli/status.md +26 -0
- package/docs/cli/system.md +60 -0
- package/docs/cli/tui.md +23 -0
- package/docs/cli/uninstall.md +17 -0
- package/docs/cli/update.md +98 -0
- package/docs/cli/voicecall.md +34 -0
- package/docs/cli/webhooks.md +25 -0
- package/docs/concepts/agent-loop.md +146 -0
- package/docs/concepts/agent-workspace.md +233 -0
- package/docs/concepts/agent.md +123 -0
- package/docs/concepts/architecture.md +129 -0
- package/docs/concepts/channel-routing.md +114 -0
- package/docs/concepts/compaction.md +61 -0
- package/docs/concepts/context.md +161 -0
- package/docs/concepts/group-messages.md +84 -0
- package/docs/concepts/groups.md +373 -0
- package/docs/concepts/markdown-formatting.md +130 -0
- package/docs/concepts/memory.md +546 -0
- package/docs/concepts/messages.md +154 -0
- package/docs/concepts/model-failover.md +149 -0
- package/docs/concepts/model-providers.md +316 -0
- package/docs/concepts/models.md +208 -0
- package/docs/concepts/multi-agent.md +376 -0
- package/docs/concepts/oauth.md +145 -0
- package/docs/concepts/presence.md +102 -0
- package/docs/concepts/queue.md +89 -0
- package/docs/concepts/retry.md +69 -0
- package/docs/concepts/session-pruning.md +122 -0
- package/docs/concepts/session-tool.md +193 -0
- package/docs/concepts/session.md +188 -0
- package/docs/concepts/sessions.md +10 -0
- package/docs/concepts/streaming.md +135 -0
- package/docs/concepts/system-prompt.md +115 -0
- package/docs/concepts/timezone.md +91 -0
- package/docs/concepts/typebox.md +289 -0
- package/docs/concepts/typing-indicators.md +68 -0
- package/docs/concepts/usage-tracking.md +35 -0
- package/docs/date-time.md +128 -0
- package/docs/debug/node-issue.md +83 -0
- package/docs/debugging.md +162 -0
- package/docs/diagnostics/flags.md +91 -0
- package/docs/docs.json +1587 -0
- package/docs/environment.md +81 -0
- package/docs/experiments/onboarding-config-protocol.md +40 -0
- package/docs/experiments/plans/cron-add-hardening.md +63 -0
- package/docs/experiments/plans/group-policy-hardening.md +40 -0
- package/docs/experiments/plans/openresponses-gateway.md +123 -0
- package/docs/experiments/proposals/model-config.md +36 -0
- package/docs/experiments/research/memory.md +228 -0
- package/docs/gateway/authentication.md +145 -0
- package/docs/gateway/background-process.md +93 -0
- package/docs/gateway/bonjour.md +167 -0
- package/docs/gateway/bridge-protocol.md +89 -0
- package/docs/gateway/cli-backends.md +223 -0
- package/docs/gateway/configuration-examples.md +606 -0
- package/docs/gateway/configuration.md +3393 -0
- package/docs/gateway/discovery.md +116 -0
- package/docs/gateway/doctor.md +282 -0
- package/docs/gateway/gateway-lock.md +34 -0
- package/docs/gateway/health.md +35 -0
- package/docs/gateway/heartbeat.md +302 -0
- package/docs/gateway/index.md +328 -0
- package/docs/gateway/local-models.md +150 -0
- package/docs/gateway/logging.md +113 -0
- package/docs/gateway/multiple-gateways.md +112 -0
- package/docs/gateway/openai-http-api.md +118 -0
- package/docs/gateway/openresponses-http-api.md +317 -0
- package/docs/gateway/pairing.md +99 -0
- package/docs/gateway/protocol.md +221 -0
- package/docs/gateway/remote-gateway-readme.md +157 -0
- package/docs/gateway/remote.md +127 -0
- package/docs/gateway/sandbox-vs-tool-policy-vs-elevated.md +128 -0
- package/docs/gateway/sandboxing.md +193 -0
- package/docs/gateway/security/formal-verification.md +164 -0
- package/docs/gateway/security/index.md +825 -0
- package/docs/gateway/tailscale.md +127 -0
- package/docs/gateway/tools-invoke-http-api.md +85 -0
- package/docs/gateway/troubleshooting.md +767 -0
- package/docs/help/faq.md +2830 -0
- package/docs/help/index.md +21 -0
- package/docs/help/troubleshooting.md +98 -0
- package/docs/hooks/soul-evil.md +69 -0
- package/docs/hooks.md +913 -0
- package/docs/images/feishu-step2-create-app.png +0 -0
- package/docs/images/feishu-step3-credentials.png +0 -0
- package/docs/images/feishu-step4-permissions.png +0 -0
- package/docs/images/feishu-step5-bot-capability.png +0 -0
- package/docs/images/feishu-step6-event-subscription.png +0 -0
- package/docs/images/groups-flow.svg +52 -0
- package/docs/images/mobile-ui-screenshot.png +0 -0
- package/docs/index.md +258 -0
- package/docs/install/ansible.md +208 -0
- package/docs/install/bun.md +59 -0
- package/docs/install/development-channels.md +75 -0
- package/docs/install/docker.md +567 -0
- package/docs/install/index.md +185 -0
- package/docs/install/installer.md +123 -0
- package/docs/install/migrating.md +192 -0
- package/docs/install/nix.md +96 -0
- package/docs/install/node.md +78 -0
- package/docs/install/uninstall.md +128 -0
- package/docs/install/updating.md +228 -0
- package/docs/logging.md +350 -0
- package/docs/multi-agent-sandbox-tools.md +395 -0
- package/docs/network.md +54 -0
- package/docs/nodes/audio.md +114 -0
- package/docs/nodes/camera.md +156 -0
- package/docs/nodes/images.md +72 -0
- package/docs/nodes/index.md +341 -0
- package/docs/nodes/location-command.md +113 -0
- package/docs/nodes/media-understanding.md +379 -0
- package/docs/nodes/talk.md +90 -0
- package/docs/nodes/voicewake.md +65 -0
- package/docs/northflank.mdx +53 -0
- package/docs/perplexity.md +80 -0
- package/docs/pi-dev.md +70 -0
- package/docs/pi.md +612 -0
- package/docs/platforms/android.md +148 -0
- package/docs/platforms/digitalocean.md +262 -0
- package/docs/platforms/exe-dev.md +125 -0
- package/docs/platforms/fly.md +486 -0
- package/docs/platforms/gcp.md +503 -0
- package/docs/platforms/hetzner.md +330 -0
- package/docs/platforms/index.md +53 -0
- package/docs/platforms/ios.md +107 -0
- package/docs/platforms/linux.md +94 -0
- package/docs/platforms/mac/bundled-gateway.md +73 -0
- package/docs/platforms/mac/canvas.md +125 -0
- package/docs/platforms/mac/child-process.md +69 -0
- package/docs/platforms/mac/dev-setup.md +102 -0
- package/docs/platforms/mac/health.md +34 -0
- package/docs/platforms/mac/icon.md +31 -0
- package/docs/platforms/mac/logging.md +57 -0
- package/docs/platforms/mac/menu-bar.md +81 -0
- package/docs/platforms/mac/peekaboo.md +65 -0
- package/docs/platforms/mac/permissions.md +44 -0
- package/docs/platforms/mac/release.md +85 -0
- package/docs/platforms/mac/remote.md +83 -0
- package/docs/platforms/mac/signing.md +47 -0
- package/docs/platforms/mac/skills.md +33 -0
- package/docs/platforms/mac/voice-overlay.md +60 -0
- package/docs/platforms/mac/voicewake.md +67 -0
- package/docs/platforms/mac/webchat.md +41 -0
- package/docs/platforms/mac/xpc.md +61 -0
- package/docs/platforms/macos-vm.md +281 -0
- package/docs/platforms/macos.md +203 -0
- package/docs/platforms/oracle.md +303 -0
- package/docs/platforms/raspberry-pi.md +358 -0
- package/docs/platforms/windows.md +159 -0
- package/docs/plugin.md +664 -0
- package/docs/plugins/agent-tools.md +99 -0
- package/docs/plugins/manifest.md +71 -0
- package/docs/plugins/voice-call.md +284 -0
- package/docs/plugins/zalouser.md +81 -0
- package/docs/prose.md +134 -0
- package/docs/providers/anthropic.md +152 -0
- package/docs/providers/claude-max-api-proxy.md +148 -0
- package/docs/providers/cloudflare-ai-gateway.md +71 -0
- package/docs/providers/deepgram.md +93 -0
- package/docs/providers/github-copilot.md +72 -0
- package/docs/providers/glm.md +33 -0
- package/docs/providers/index.md +63 -0
- package/docs/providers/minimax.md +208 -0
- package/docs/providers/models.md +51 -0
- package/docs/providers/moonshot.md +142 -0
- package/docs/providers/ollama.md +223 -0
- package/docs/providers/openai.md +62 -0
- package/docs/providers/opencode.md +36 -0
- package/docs/providers/openrouter.md +37 -0
- package/docs/providers/qwen.md +53 -0
- package/docs/providers/synthetic.md +99 -0
- package/docs/providers/venice.md +267 -0
- package/docs/providers/vercel-ai-gateway.md +50 -0
- package/docs/providers/xiaomi.md +64 -0
- package/docs/providers/zai.md +36 -0
- package/docs/railway.mdx +99 -0
- package/docs/refactor/clawnet.md +417 -0
- package/docs/refactor/exec-host.md +316 -0
- package/docs/refactor/outbound-session-mirroring.md +85 -0
- package/docs/refactor/plugin-sdk.md +214 -0
- package/docs/refactor/strict-config.md +93 -0
- package/docs/reference/AGENTS.default.md +124 -0
- package/docs/reference/RELEASING.md +120 -0
- package/docs/reference/api-usage-costs.md +137 -0
- package/docs/reference/device-models.md +47 -0
- package/docs/reference/rpc.md +43 -0
- package/docs/reference/session-management-compaction.md +285 -0
- package/docs/reference/templates/AGENTS.dev.md +83 -0
- package/docs/reference/templates/AGENTS.md +218 -0
- package/docs/reference/templates/BOOT.md +10 -0
- package/docs/reference/templates/BOOTSTRAP.md +61 -0
- package/docs/reference/templates/HEARTBEAT.md +11 -0
- package/docs/reference/templates/IDENTITY.dev.md +47 -0
- package/docs/reference/templates/IDENTITY.md +27 -0
- package/docs/reference/templates/SOUL.dev.md +76 -0
- package/docs/reference/templates/SOUL.md +42 -0
- package/docs/reference/templates/TOOLS.dev.md +24 -0
- package/docs/reference/templates/TOOLS.md +46 -0
- package/docs/reference/templates/USER.dev.md +18 -0
- package/docs/reference/templates/USER.md +22 -0
- package/docs/reference/test.md +50 -0
- package/docs/reference/transcript-hygiene.md +129 -0
- package/docs/render.mdx +165 -0
- package/docs/scripts.md +28 -0
- package/docs/security/formal-verification.md +164 -0
- package/docs/start/getting-started.md +208 -0
- package/docs/start/hubs.md +185 -0
- package/docs/start/lore.md +219 -0
- package/docs/start/onboarding.md +110 -0
- package/docs/start/openclaw.md +241 -0
- package/docs/start/pairing.md +86 -0
- package/docs/start/setup.md +149 -0
- package/docs/start/showcase.md +416 -0
- package/docs/start/wizard.md +349 -0
- package/docs/testing.md +368 -0
- package/docs/token-use.md +112 -0
- package/docs/tools/agent-send.md +53 -0
- package/docs/tools/apply-patch.md +50 -0
- package/docs/tools/browser-linux-troubleshooting.md +139 -0
- package/docs/tools/browser-login.md +68 -0
- package/docs/tools/browser.md +576 -0
- package/docs/tools/chrome-extension.md +178 -0
- package/docs/tools/clawhub.md +257 -0
- package/docs/tools/creating-skills.md +54 -0
- package/docs/tools/elevated.md +57 -0
- package/docs/tools/exec-approvals.md +246 -0
- package/docs/tools/exec.md +179 -0
- package/docs/tools/firecrawl.md +61 -0
- package/docs/tools/index.md +509 -0
- package/docs/tools/llm-task.md +115 -0
- package/docs/tools/lobster.md +342 -0
- package/docs/tools/reactions.md +22 -0
- package/docs/tools/skills-config.md +76 -0
- package/docs/tools/skills.md +300 -0
- package/docs/tools/slash-commands.md +198 -0
- package/docs/tools/subagents.md +151 -0
- package/docs/tools/thinking.md +73 -0
- package/docs/tools/web.md +261 -0
- package/docs/tts.md +396 -0
- package/docs/tui.md +159 -0
- package/docs/vps.md +43 -0
- package/docs/web/control-ui.md +221 -0
- package/docs/web/dashboard.md +46 -0
- package/docs/web/index.md +116 -0
- package/docs/web/webchat.md +49 -0
- package/docs/whatsapp-openclaw-ai-zh.jpg +0 -0
- package/docs/whatsapp-openclaw.jpg +0 -0
- package/docs/zh-CN/AGENTS.md +59 -0
- package/docs/zh-CN/automation/auth-monitoring.md +47 -0
- package/docs/zh-CN/automation/cron-jobs.md +424 -0
- package/docs/zh-CN/automation/cron-vs-heartbeat.md +286 -0
- package/docs/zh-CN/automation/gmail-pubsub.md +249 -0
- package/docs/zh-CN/automation/poll.md +76 -0
- package/docs/zh-CN/automation/webhook.md +163 -0
- package/docs/zh-CN/bedrock.md +170 -0
- package/docs/zh-CN/brave-search.md +48 -0
- package/docs/zh-CN/broadcast-groups.md +449 -0
- package/docs/zh-CN/channels/bluebubbles.md +271 -0
- package/docs/zh-CN/channels/discord.md +468 -0
- package/docs/zh-CN/channels/feishu.md +513 -0
- package/docs/zh-CN/channels/googlechat.md +257 -0
- package/docs/zh-CN/channels/grammy.md +38 -0
- package/docs/zh-CN/channels/imessage.md +302 -0
- package/docs/zh-CN/channels/index.md +53 -0
- package/docs/zh-CN/channels/line.md +180 -0
- package/docs/zh-CN/channels/location.md +63 -0
- package/docs/zh-CN/channels/matrix.md +221 -0
- package/docs/zh-CN/channels/mattermost.md +144 -0
- package/docs/zh-CN/channels/msteams.md +775 -0
- package/docs/zh-CN/channels/nextcloud-talk.md +142 -0
- package/docs/zh-CN/channels/nostr.md +240 -0
- package/docs/zh-CN/channels/signal.md +209 -0
- package/docs/zh-CN/channels/slack.md +531 -0
- package/docs/zh-CN/channels/telegram.md +751 -0
- package/docs/zh-CN/channels/tlon.md +136 -0
- package/docs/zh-CN/channels/troubleshooting.md +36 -0
- package/docs/zh-CN/channels/twitch.md +385 -0
- package/docs/zh-CN/channels/whatsapp.md +411 -0
- package/docs/zh-CN/channels/zalo.md +196 -0
- package/docs/zh-CN/channels/zalouser.md +147 -0
- package/docs/zh-CN/cli/acp.md +173 -0
- package/docs/zh-CN/cli/agent.md +30 -0
- package/docs/zh-CN/cli/agents.md +82 -0
- package/docs/zh-CN/cli/approvals.md +57 -0
- package/docs/zh-CN/cli/browser.md +114 -0
- package/docs/zh-CN/cli/channels.md +86 -0
- package/docs/zh-CN/cli/config.md +57 -0
- package/docs/zh-CN/cli/configure.md +38 -0
- package/docs/zh-CN/cli/cron.md +43 -0
- package/docs/zh-CN/cli/dashboard.md +23 -0
- package/docs/zh-CN/cli/devices.md +74 -0
- package/docs/zh-CN/cli/directory.md +70 -0
- package/docs/zh-CN/cli/dns.md +30 -0
- package/docs/zh-CN/cli/docs.md +22 -0
- package/docs/zh-CN/cli/doctor.md +48 -0
- package/docs/zh-CN/cli/gateway.md +206 -0
- package/docs/zh-CN/cli/health.md +28 -0
- package/docs/zh-CN/cli/hooks.md +311 -0
- package/docs/zh-CN/cli/index.md +1032 -0
- package/docs/zh-CN/cli/logs.md +31 -0
- package/docs/zh-CN/cli/memory.md +52 -0
- package/docs/zh-CN/cli/message.md +246 -0
- package/docs/zh-CN/cli/models.md +85 -0
- package/docs/zh-CN/cli/node.md +115 -0
- package/docs/zh-CN/cli/nodes.md +80 -0
- package/docs/zh-CN/cli/onboard.md +36 -0
- package/docs/zh-CN/cli/pairing.md +28 -0
- package/docs/zh-CN/cli/plugins.md +66 -0
- package/docs/zh-CN/cli/reset.md +24 -0
- package/docs/zh-CN/cli/sandbox.md +158 -0
- package/docs/zh-CN/cli/security.md +33 -0
- package/docs/zh-CN/cli/sessions.md +23 -0
- package/docs/zh-CN/cli/setup.md +36 -0
- package/docs/zh-CN/cli/skills.md +33 -0
- package/docs/zh-CN/cli/status.md +33 -0
- package/docs/zh-CN/cli/system.md +63 -0
- package/docs/zh-CN/cli/tui.md +30 -0
- package/docs/zh-CN/cli/uninstall.md +24 -0
- package/docs/zh-CN/cli/update.md +101 -0
- package/docs/zh-CN/cli/voicecall.md +41 -0
- package/docs/zh-CN/cli/webhooks.md +32 -0
- package/docs/zh-CN/concepts/agent-loop.md +146 -0
- package/docs/zh-CN/concepts/agent-workspace.md +219 -0
- package/docs/zh-CN/concepts/agent.md +115 -0
- package/docs/zh-CN/concepts/architecture.md +123 -0
- package/docs/zh-CN/concepts/channel-routing.md +117 -0
- package/docs/zh-CN/concepts/compaction.md +67 -0
- package/docs/zh-CN/concepts/context.md +168 -0
- package/docs/zh-CN/concepts/group-messages.md +91 -0
- package/docs/zh-CN/concepts/groups.md +379 -0
- package/docs/zh-CN/concepts/markdown-formatting.md +117 -0
- package/docs/zh-CN/concepts/memory.md +412 -0
- package/docs/zh-CN/concepts/messages.md +141 -0
- package/docs/zh-CN/concepts/model-failover.md +145 -0
- package/docs/zh-CN/concepts/model-providers.md +320 -0
- package/docs/zh-CN/concepts/models.md +196 -0
- package/docs/zh-CN/concepts/multi-agent.md +372 -0
- package/docs/zh-CN/concepts/oauth.md +151 -0
- package/docs/zh-CN/concepts/presence.md +99 -0
- package/docs/zh-CN/concepts/queue.md +94 -0
- package/docs/zh-CN/concepts/retry.md +76 -0
- package/docs/zh-CN/concepts/session-pruning.md +129 -0
- package/docs/zh-CN/concepts/session-tool.md +200 -0
- package/docs/zh-CN/concepts/session.md +166 -0
- package/docs/zh-CN/concepts/sessions.md +17 -0
- package/docs/zh-CN/concepts/streaming.md +133 -0
- package/docs/zh-CN/concepts/system-prompt.md +101 -0
- package/docs/zh-CN/concepts/timezone.md +96 -0
- package/docs/zh-CN/concepts/typebox.md +284 -0
- package/docs/zh-CN/concepts/typing-indicators.md +74 -0
- package/docs/zh-CN/concepts/usage-tracking.md +42 -0
- package/docs/zh-CN/date-time.md +129 -0
- package/docs/zh-CN/debug/node-issue.md +90 -0
- package/docs/zh-CN/debugging.md +160 -0
- package/docs/zh-CN/diagnostics/flags.md +98 -0
- package/docs/zh-CN/environment.md +88 -0
- package/docs/zh-CN/experiments/onboarding-config-protocol.md +47 -0
- package/docs/zh-CN/experiments/plans/cron-add-hardening.md +70 -0
- package/docs/zh-CN/experiments/plans/group-policy-hardening.md +45 -0
- package/docs/zh-CN/experiments/plans/openresponses-gateway.md +121 -0
- package/docs/zh-CN/experiments/proposals/model-config.md +42 -0
- package/docs/zh-CN/experiments/research/memory.md +235 -0
- package/docs/zh-CN/gateway/authentication.md +142 -0
- package/docs/zh-CN/gateway/background-process.md +100 -0
- package/docs/zh-CN/gateway/bonjour.md +174 -0
- package/docs/zh-CN/gateway/bridge-protocol.md +86 -0
- package/docs/zh-CN/gateway/cli-backends.md +213 -0
- package/docs/zh-CN/gateway/configuration-examples.md +587 -0
- package/docs/zh-CN/gateway/configuration.md +3332 -0
- package/docs/zh-CN/gateway/discovery.md +123 -0
- package/docs/zh-CN/gateway/doctor.md +238 -0
- package/docs/zh-CN/gateway/gateway-lock.md +41 -0
- package/docs/zh-CN/gateway/health.md +42 -0
- package/docs/zh-CN/gateway/heartbeat.md +274 -0
- package/docs/zh-CN/gateway/index.md +335 -0
- package/docs/zh-CN/gateway/local-models.md +157 -0
- package/docs/zh-CN/gateway/logging.md +114 -0
- package/docs/zh-CN/gateway/multiple-gateways.md +119 -0
- package/docs/zh-CN/gateway/openai-http-api.md +125 -0
- package/docs/zh-CN/gateway/openresponses-http-api.md +317 -0
- package/docs/zh-CN/gateway/pairing.md +99 -0
- package/docs/zh-CN/gateway/protocol.md +220 -0
- package/docs/zh-CN/gateway/remote-gateway-readme.md +164 -0
- package/docs/zh-CN/gateway/remote.md +133 -0
- package/docs/zh-CN/gateway/sandbox-vs-tool-policy-vs-elevated.md +135 -0
- package/docs/zh-CN/gateway/sandboxing.md +188 -0
- package/docs/zh-CN/gateway/security/formal-verification.md +169 -0
- package/docs/zh-CN/gateway/security/index.md +777 -0
- package/docs/zh-CN/gateway/tailscale.md +124 -0
- package/docs/zh-CN/gateway/tools-invoke-http-api.md +92 -0
- package/docs/zh-CN/gateway/troubleshooting.md +771 -0
- package/docs/zh-CN/help/faq.md +2628 -0
- package/docs/zh-CN/help/index.md +28 -0
- package/docs/zh-CN/help/troubleshooting.md +104 -0
- package/docs/zh-CN/hooks/soul-evil.md +72 -0
- package/docs/zh-CN/hooks.md +919 -0
- package/docs/zh-CN/index.md +264 -0
- package/docs/zh-CN/install/ansible.md +215 -0
- package/docs/zh-CN/install/bun.md +65 -0
- package/docs/zh-CN/install/development-channels.md +81 -0
- package/docs/zh-CN/install/docker.md +532 -0
- package/docs/zh-CN/install/index.md +193 -0
- package/docs/zh-CN/install/installer.md +128 -0
- package/docs/zh-CN/install/migrating.md +199 -0
- package/docs/zh-CN/install/nix.md +99 -0
- package/docs/zh-CN/install/node.md +85 -0
- package/docs/zh-CN/install/uninstall.md +135 -0
- package/docs/zh-CN/install/updating.md +233 -0
- package/docs/zh-CN/logging.md +329 -0
- package/docs/zh-CN/multi-agent-sandbox-tools.md +401 -0
- package/docs/zh-CN/network.md +59 -0
- package/docs/zh-CN/nodes/audio.md +120 -0
- package/docs/zh-CN/nodes/camera.md +162 -0
- package/docs/zh-CN/nodes/images.md +79 -0
- package/docs/zh-CN/nodes/index.md +348 -0
- package/docs/zh-CN/nodes/location-command.md +120 -0
- package/docs/zh-CN/nodes/media-understanding.md +380 -0
- package/docs/zh-CN/nodes/talk.md +97 -0
- package/docs/zh-CN/nodes/voicewake.md +72 -0
- package/docs/zh-CN/northflank.mdx +60 -0
- package/docs/zh-CN/perplexity.md +84 -0
- package/docs/zh-CN/pi-dev.md +77 -0
- package/docs/zh-CN/pi.md +619 -0
- package/docs/zh-CN/platforms/android.md +155 -0
- package/docs/zh-CN/platforms/digitalocean.md +269 -0
- package/docs/zh-CN/platforms/exe-dev.md +127 -0
- package/docs/zh-CN/platforms/fly.md +490 -0
- package/docs/zh-CN/platforms/gcp.md +510 -0
- package/docs/zh-CN/platforms/hetzner.md +337 -0
- package/docs/zh-CN/platforms/index.md +60 -0
- package/docs/zh-CN/platforms/ios.md +114 -0
- package/docs/zh-CN/platforms/linux.md +101 -0
- package/docs/zh-CN/platforms/mac/bundled-gateway.md +75 -0
- package/docs/zh-CN/platforms/mac/canvas.md +128 -0
- package/docs/zh-CN/platforms/mac/child-process.md +73 -0
- package/docs/zh-CN/platforms/mac/dev-setup.md +109 -0
- package/docs/zh-CN/platforms/mac/health.md +41 -0
- package/docs/zh-CN/platforms/mac/icon.md +38 -0
- package/docs/zh-CN/platforms/mac/logging.md +64 -0
- package/docs/zh-CN/platforms/mac/menu-bar.md +88 -0
- package/docs/zh-CN/platforms/mac/peekaboo.md +62 -0
- package/docs/zh-CN/platforms/mac/permissions.md +46 -0
- package/docs/zh-CN/platforms/mac/release.md +92 -0
- package/docs/zh-CN/platforms/mac/remote.md +90 -0
- package/docs/zh-CN/platforms/mac/signing.md +54 -0
- package/docs/zh-CN/platforms/mac/skills.md +40 -0
- package/docs/zh-CN/platforms/mac/voice-overlay.md +67 -0
- package/docs/zh-CN/platforms/mac/voicewake.md +74 -0
- package/docs/zh-CN/platforms/mac/webchat.md +43 -0
- package/docs/zh-CN/platforms/mac/xpc.md +68 -0
- package/docs/zh-CN/platforms/macos-vm.md +288 -0
- package/docs/zh-CN/platforms/macos.md +193 -0
- package/docs/zh-CN/platforms/oracle.md +310 -0
- package/docs/zh-CN/platforms/raspberry-pi.md +365 -0
- package/docs/zh-CN/platforms/windows.md +156 -0
- package/docs/zh-CN/plugin.md +639 -0
- package/docs/zh-CN/plugins/agent-tools.md +99 -0
- package/docs/zh-CN/plugins/manifest.md +68 -0
- package/docs/zh-CN/plugins/voice-call.md +250 -0
- package/docs/zh-CN/plugins/zalouser.md +88 -0
- package/docs/zh-CN/prose.md +141 -0
- package/docs/zh-CN/providers/anthropic.md +159 -0
- package/docs/zh-CN/providers/claude-max-api-proxy.md +155 -0
- package/docs/zh-CN/providers/deepgram.md +97 -0
- package/docs/zh-CN/providers/github-copilot.md +67 -0
- package/docs/zh-CN/providers/glm.md +39 -0
- package/docs/zh-CN/providers/index.md +68 -0
- package/docs/zh-CN/providers/minimax.md +206 -0
- package/docs/zh-CN/providers/models.md +55 -0
- package/docs/zh-CN/providers/moonshot.md +145 -0
- package/docs/zh-CN/providers/ollama.md +230 -0
- package/docs/zh-CN/providers/openai.md +68 -0
- package/docs/zh-CN/providers/opencode.md +41 -0
- package/docs/zh-CN/providers/openrouter.md +43 -0
- package/docs/zh-CN/providers/qwen.md +55 -0
- package/docs/zh-CN/providers/synthetic.md +102 -0
- package/docs/zh-CN/providers/venice.md +274 -0
- package/docs/zh-CN/providers/vercel-ai-gateway.md +57 -0
- package/docs/zh-CN/providers/xiaomi.md +68 -0
- package/docs/zh-CN/providers/zai.md +41 -0
- package/docs/zh-CN/railway.mdx +106 -0
- package/docs/zh-CN/refactor/clawnet.md +424 -0
- package/docs/zh-CN/refactor/exec-host.md +323 -0
- package/docs/zh-CN/refactor/outbound-session-mirroring.md +92 -0
- package/docs/zh-CN/refactor/plugin-sdk.md +221 -0
- package/docs/zh-CN/refactor/strict-config.md +100 -0
- package/docs/zh-CN/reference/AGENTS.default.md +131 -0
- package/docs/zh-CN/reference/RELEASING.md +123 -0
- package/docs/zh-CN/reference/api-usage-costs.md +136 -0
- package/docs/zh-CN/reference/device-models.md +54 -0
- package/docs/zh-CN/reference/rpc.md +48 -0
- package/docs/zh-CN/reference/session-management-compaction.md +287 -0
- package/docs/zh-CN/reference/templates/AGENTS.dev.md +89 -0
- package/docs/zh-CN/reference/templates/AGENTS.md +225 -0
- package/docs/zh-CN/reference/templates/BOOT.md +17 -0
- package/docs/zh-CN/reference/templates/BOOTSTRAP.md +68 -0
- package/docs/zh-CN/reference/templates/HEARTBEAT.md +18 -0
- package/docs/zh-CN/reference/templates/IDENTITY.dev.md +54 -0
- package/docs/zh-CN/reference/templates/IDENTITY.md +35 -0
- package/docs/zh-CN/reference/templates/SOUL.dev.md +83 -0
- package/docs/zh-CN/reference/templates/SOUL.md +49 -0
- package/docs/zh-CN/reference/templates/TOOLS.dev.md +31 -0
- package/docs/zh-CN/reference/templates/TOOLS.md +53 -0
- package/docs/zh-CN/reference/templates/USER.dev.md +25 -0
- package/docs/zh-CN/reference/templates/USER.md +30 -0
- package/docs/zh-CN/reference/test.md +57 -0
- package/docs/zh-CN/reference/transcript-hygiene.md +109 -0
- package/docs/zh-CN/render.mdx +169 -0
- package/docs/zh-CN/scripts.md +35 -0
- package/docs/zh-CN/security/formal-verification.md +171 -0
- package/docs/zh-CN/start/getting-started.md +206 -0
- package/docs/zh-CN/start/hubs.md +191 -0
- package/docs/zh-CN/start/lore.md +226 -0
- package/docs/zh-CN/start/onboarding.md +105 -0
- package/docs/zh-CN/start/openclaw.md +248 -0
- package/docs/zh-CN/start/pairing.md +89 -0
- package/docs/zh-CN/start/setup.md +153 -0
- package/docs/zh-CN/start/showcase.md +423 -0
- package/docs/zh-CN/start/wizard.md +331 -0
- package/docs/zh-CN/testing.md +375 -0
- package/docs/zh-CN/token-use.md +119 -0
- package/docs/zh-CN/tools/agent-send.md +59 -0
- package/docs/zh-CN/tools/apply-patch.md +57 -0
- package/docs/zh-CN/tools/browser-linux-troubleshooting.md +144 -0
- package/docs/zh-CN/tools/browser-login.md +75 -0
- package/docs/zh-CN/tools/browser.md +553 -0
- package/docs/zh-CN/tools/chrome-extension.md +183 -0
- package/docs/zh-CN/tools/clawhub.md +209 -0
- package/docs/zh-CN/tools/creating-skills.md +61 -0
- package/docs/zh-CN/tools/elevated.md +64 -0
- package/docs/zh-CN/tools/exec-approvals.md +234 -0
- package/docs/zh-CN/tools/exec.md +169 -0
- package/docs/zh-CN/tools/firecrawl.md +68 -0
- package/docs/zh-CN/tools/index.md +515 -0
- package/docs/zh-CN/tools/llm-task.md +117 -0
- package/docs/zh-CN/tools/lobster.md +349 -0
- package/docs/zh-CN/tools/reactions.md +29 -0
- package/docs/zh-CN/tools/skills-config.md +78 -0
- package/docs/zh-CN/tools/skills.md +279 -0
- package/docs/zh-CN/tools/slash-commands.md +205 -0
- package/docs/zh-CN/tools/subagents.md +156 -0
- package/docs/zh-CN/tools/thinking.md +80 -0
- package/docs/zh-CN/tools/web.md +257 -0
- package/docs/zh-CN/tts.md +375 -0
- package/docs/zh-CN/tui.md +166 -0
- package/docs/zh-CN/vps.md +47 -0
- package/docs/zh-CN/web/control-ui.md +191 -0
- package/docs/zh-CN/web/dashboard.md +53 -0
- package/docs/zh-CN/web/index.md +118 -0
- package/docs/zh-CN/web/webchat.md +56 -0
- package/extensions/bluebubbles/README.md +45 -0
- package/extensions/bluebubbles/index.ts +19 -0
- package/extensions/bluebubbles/node_modules/.bin/openclaw +21 -0
- package/extensions/bluebubbles/openclaw.plugin.json +9 -0
- package/extensions/bluebubbles/package.json +36 -0
- package/extensions/bluebubbles/src/accounts.ts +88 -0
- package/extensions/bluebubbles/src/actions.test.ts +650 -0
- package/extensions/bluebubbles/src/actions.ts +438 -0
- package/extensions/bluebubbles/src/attachments.test.ts +345 -0
- package/extensions/bluebubbles/src/attachments.ts +300 -0
- package/extensions/bluebubbles/src/channel.ts +414 -0
- package/extensions/bluebubbles/src/chat.test.ts +461 -0
- package/extensions/bluebubbles/src/chat.ts +378 -0
- package/extensions/bluebubbles/src/config-schema.ts +51 -0
- package/extensions/bluebubbles/src/media-send.ts +174 -0
- package/extensions/bluebubbles/src/monitor.test.ts +2342 -0
- package/extensions/bluebubbles/src/monitor.ts +2490 -0
- package/extensions/bluebubbles/src/onboarding.ts +352 -0
- package/extensions/bluebubbles/src/probe.ts +135 -0
- package/extensions/bluebubbles/src/reactions.test.ts +392 -0
- package/extensions/bluebubbles/src/reactions.ts +188 -0
- package/extensions/bluebubbles/src/runtime.ts +14 -0
- package/extensions/bluebubbles/src/send.test.ts +808 -0
- package/extensions/bluebubbles/src/send.ts +467 -0
- package/extensions/bluebubbles/src/targets.test.ts +183 -0
- package/extensions/bluebubbles/src/targets.ts +422 -0
- package/extensions/bluebubbles/src/types.ts +127 -0
- package/extensions/copilot-proxy/README.md +24 -0
- package/extensions/copilot-proxy/index.ts +148 -0
- package/extensions/copilot-proxy/node_modules/.bin/openclaw +21 -0
- package/extensions/copilot-proxy/openclaw.plugin.json +9 -0
- package/extensions/copilot-proxy/package.json +14 -0
- package/extensions/diagnostics-otel/index.ts +15 -0
- package/extensions/diagnostics-otel/node_modules/.bin/openclaw +21 -0
- package/extensions/diagnostics-otel/openclaw.plugin.json +8 -0
- package/extensions/diagnostics-otel/package.json +27 -0
- package/extensions/diagnostics-otel/src/service.test.ts +226 -0
- package/extensions/diagnostics-otel/src/service.ts +635 -0
- package/extensions/discord/index.ts +17 -0
- package/extensions/discord/node_modules/.bin/openclaw +21 -0
- package/extensions/discord/openclaw.plugin.json +9 -0
- package/extensions/discord/package.json +14 -0
- package/extensions/discord/src/channel.ts +422 -0
- package/extensions/discord/src/runtime.ts +14 -0
- package/extensions/feishu/README.md +47 -0
- package/extensions/feishu/index.ts +15 -0
- package/extensions/feishu/node_modules/.bin/openclaw +21 -0
- package/extensions/feishu/openclaw.plugin.json +9 -0
- package/extensions/feishu/package.json +33 -0
- package/extensions/feishu/src/channel.ts +276 -0
- package/extensions/feishu/src/config-schema.ts +46 -0
- package/extensions/feishu/src/onboarding.ts +278 -0
- package/extensions/google-antigravity-auth/README.md +24 -0
- package/extensions/google-antigravity-auth/index.ts +461 -0
- package/extensions/google-antigravity-auth/node_modules/.bin/openclaw +21 -0
- package/extensions/google-antigravity-auth/openclaw.plugin.json +9 -0
- package/extensions/google-antigravity-auth/package.json +14 -0
- package/extensions/google-gemini-cli-auth/README.md +35 -0
- package/extensions/google-gemini-cli-auth/index.ts +88 -0
- package/extensions/google-gemini-cli-auth/node_modules/.bin/openclaw +21 -0
- package/extensions/google-gemini-cli-auth/oauth.test.ts +240 -0
- package/extensions/google-gemini-cli-auth/oauth.ts +662 -0
- package/extensions/google-gemini-cli-auth/openclaw.plugin.json +9 -0
- package/extensions/google-gemini-cli-auth/package.json +14 -0
- package/extensions/googlechat/index.ts +19 -0
- package/extensions/googlechat/node_modules/.bin/openclaw +21 -0
- package/extensions/googlechat/openclaw.plugin.json +9 -0
- package/extensions/googlechat/package.json +39 -0
- package/extensions/googlechat/src/accounts.ts +147 -0
- package/extensions/googlechat/src/actions.ts +181 -0
- package/extensions/googlechat/src/api.test.ts +61 -0
- package/extensions/googlechat/src/api.ts +282 -0
- package/extensions/googlechat/src/auth.ts +123 -0
- package/extensions/googlechat/src/channel.ts +583 -0
- package/extensions/googlechat/src/monitor.test.ts +22 -0
- package/extensions/googlechat/src/monitor.ts +949 -0
- package/extensions/googlechat/src/onboarding.ts +269 -0
- package/extensions/googlechat/src/runtime.ts +14 -0
- package/extensions/googlechat/src/targets.test.ts +32 -0
- package/extensions/googlechat/src/targets.ts +65 -0
- package/extensions/googlechat/src/types.config.ts +3 -0
- package/extensions/googlechat/src/types.ts +73 -0
- package/extensions/imessage/index.ts +17 -0
- package/extensions/imessage/node_modules/.bin/openclaw +21 -0
- package/extensions/imessage/openclaw.plugin.json +9 -0
- package/extensions/imessage/package.json +14 -0
- package/extensions/imessage/src/channel.ts +294 -0
- package/extensions/imessage/src/runtime.ts +14 -0
- package/extensions/line/index.ts +19 -0
- package/extensions/line/node_modules/.bin/openclaw +21 -0
- package/extensions/line/openclaw.plugin.json +9 -0
- package/extensions/line/package.json +29 -0
- package/extensions/line/src/card-command.ts +344 -0
- package/extensions/line/src/channel.logout.test.ts +99 -0
- package/extensions/line/src/channel.sendPayload.test.ts +306 -0
- package/extensions/line/src/channel.ts +780 -0
- package/extensions/line/src/runtime.ts +14 -0
- package/extensions/llm-task/README.md +97 -0
- package/extensions/llm-task/index.ts +6 -0
- package/extensions/llm-task/node_modules/.bin/openclaw +21 -0
- package/extensions/llm-task/openclaw.plugin.json +21 -0
- package/extensions/llm-task/package.json +14 -0
- package/extensions/llm-task/src/llm-task-tool.test.ts +138 -0
- package/extensions/llm-task/src/llm-task-tool.ts +245 -0
- package/extensions/lobster/README.md +75 -0
- package/extensions/lobster/SKILL.md +97 -0
- package/extensions/lobster/index.ts +14 -0
- package/extensions/lobster/node_modules/.bin/openclaw +21 -0
- package/extensions/lobster/openclaw.plugin.json +10 -0
- package/extensions/lobster/package.json +14 -0
- package/extensions/lobster/src/lobster-tool.test.ts +247 -0
- package/extensions/lobster/src/lobster-tool.ts +328 -0
- package/extensions/matrix/CHANGELOG.md +87 -0
- package/extensions/matrix/index.ts +17 -0
- package/extensions/matrix/node_modules/.bin/markdown-it +21 -0
- package/extensions/matrix/node_modules/.bin/openclaw +21 -0
- package/extensions/matrix/openclaw.plugin.json +9 -0
- package/extensions/matrix/package.json +36 -0
- package/extensions/matrix/src/actions.ts +195 -0
- package/extensions/matrix/src/channel.directory.test.ts +64 -0
- package/extensions/matrix/src/channel.ts +439 -0
- package/extensions/matrix/src/config-schema.ts +62 -0
- package/extensions/matrix/src/directory-live.ts +188 -0
- package/extensions/matrix/src/group-mentions.ts +66 -0
- package/extensions/matrix/src/matrix/accounts.test.ts +82 -0
- package/extensions/matrix/src/matrix/accounts.ts +65 -0
- package/extensions/matrix/src/matrix/actions/client.ts +57 -0
- package/extensions/matrix/src/matrix/actions/messages.ts +128 -0
- package/extensions/matrix/src/matrix/actions/pins.ts +76 -0
- package/extensions/matrix/src/matrix/actions/reactions.ts +96 -0
- package/extensions/matrix/src/matrix/actions/room.ts +85 -0
- package/extensions/matrix/src/matrix/actions/summary.ts +75 -0
- package/extensions/matrix/src/matrix/actions/types.ts +84 -0
- package/extensions/matrix/src/matrix/actions.ts +15 -0
- package/extensions/matrix/src/matrix/active-client.ts +11 -0
- package/extensions/matrix/src/matrix/client/config.ts +160 -0
- package/extensions/matrix/src/matrix/client/create-client.ts +123 -0
- package/extensions/matrix/src/matrix/client/logging.ts +36 -0
- package/extensions/matrix/src/matrix/client/runtime.ts +4 -0
- package/extensions/matrix/src/matrix/client/shared.ts +170 -0
- package/extensions/matrix/src/matrix/client/storage.ts +131 -0
- package/extensions/matrix/src/matrix/client/types.ts +34 -0
- package/extensions/matrix/src/matrix/client.test.ts +56 -0
- package/extensions/matrix/src/matrix/client.ts +5 -0
- package/extensions/matrix/src/matrix/credentials.ts +105 -0
- package/extensions/matrix/src/matrix/deps.ts +60 -0
- package/extensions/matrix/src/matrix/format.test.ts +33 -0
- package/extensions/matrix/src/matrix/format.ts +22 -0
- package/extensions/matrix/src/matrix/index.ts +11 -0
- package/extensions/matrix/src/matrix/monitor/allowlist.test.ts +45 -0
- package/extensions/matrix/src/matrix/monitor/allowlist.ts +103 -0
- package/extensions/matrix/src/matrix/monitor/auto-join.ts +71 -0
- package/extensions/matrix/src/matrix/monitor/direct.ts +104 -0
- package/extensions/matrix/src/matrix/monitor/events.ts +101 -0
- package/extensions/matrix/src/matrix/monitor/handler.ts +661 -0
- package/extensions/matrix/src/matrix/monitor/index.ts +338 -0
- package/extensions/matrix/src/matrix/monitor/location.ts +100 -0
- package/extensions/matrix/src/matrix/monitor/media.test.ts +102 -0
- package/extensions/matrix/src/matrix/monitor/media.ts +113 -0
- package/extensions/matrix/src/matrix/monitor/mentions.ts +31 -0
- package/extensions/matrix/src/matrix/monitor/replies.ts +97 -0
- package/extensions/matrix/src/matrix/monitor/room-info.ts +55 -0
- package/extensions/matrix/src/matrix/monitor/rooms.test.ts +39 -0
- package/extensions/matrix/src/matrix/monitor/rooms.ts +47 -0
- package/extensions/matrix/src/matrix/monitor/threads.ts +68 -0
- package/extensions/matrix/src/matrix/monitor/types.ts +39 -0
- package/extensions/matrix/src/matrix/poll-types.test.ts +21 -0
- package/extensions/matrix/src/matrix/poll-types.ts +166 -0
- package/extensions/matrix/src/matrix/probe.ts +70 -0
- package/extensions/matrix/src/matrix/send/client.ts +66 -0
- package/extensions/matrix/src/matrix/send/formatting.ts +89 -0
- package/extensions/matrix/src/matrix/send/media.ts +229 -0
- package/extensions/matrix/src/matrix/send/targets.test.ts +98 -0
- package/extensions/matrix/src/matrix/send/targets.ts +136 -0
- package/extensions/matrix/src/matrix/send/types.ts +109 -0
- package/extensions/matrix/src/matrix/send.test.ts +171 -0
- package/extensions/matrix/src/matrix/send.ts +260 -0
- package/extensions/matrix/src/onboarding.ts +449 -0
- package/extensions/matrix/src/outbound.ts +52 -0
- package/extensions/matrix/src/resolve-targets.test.ts +48 -0
- package/extensions/matrix/src/resolve-targets.ts +135 -0
- package/extensions/matrix/src/runtime.ts +14 -0
- package/extensions/matrix/src/tool-actions.ts +164 -0
- package/extensions/matrix/src/types.ts +95 -0
- package/extensions/mattermost/index.ts +17 -0
- package/extensions/mattermost/node_modules/.bin/openclaw +21 -0
- package/extensions/mattermost/openclaw.plugin.json +9 -0
- package/extensions/mattermost/package.json +28 -0
- package/extensions/mattermost/src/channel.test.ts +48 -0
- package/extensions/mattermost/src/channel.ts +337 -0
- package/extensions/mattermost/src/config-schema.ts +55 -0
- package/extensions/mattermost/src/group-mentions.ts +15 -0
- package/extensions/mattermost/src/mattermost/accounts.ts +128 -0
- package/extensions/mattermost/src/mattermost/client.ts +220 -0
- package/extensions/mattermost/src/mattermost/index.ts +9 -0
- package/extensions/mattermost/src/mattermost/monitor-helpers.ts +166 -0
- package/extensions/mattermost/src/mattermost/monitor.ts +987 -0
- package/extensions/mattermost/src/mattermost/probe.ts +74 -0
- package/extensions/mattermost/src/mattermost/send.ts +231 -0
- package/extensions/mattermost/src/normalize.ts +46 -0
- package/extensions/mattermost/src/onboarding-helpers.ts +44 -0
- package/extensions/mattermost/src/onboarding.ts +186 -0
- package/extensions/mattermost/src/runtime.ts +14 -0
- package/extensions/mattermost/src/types.ts +50 -0
- package/extensions/memory-core/index.ts +38 -0
- package/extensions/memory-core/node_modules/.bin/openclaw +21 -0
- package/extensions/memory-core/openclaw.plugin.json +9 -0
- package/extensions/memory-core/package.json +17 -0
- package/extensions/memory-lancedb/config.ts +139 -0
- package/extensions/memory-lancedb/index.test.ts +295 -0
- package/extensions/memory-lancedb/index.ts +608 -0
- package/extensions/memory-lancedb/node_modules/.bin/openai +21 -0
- package/extensions/memory-lancedb/node_modules/.bin/openclaw +21 -0
- package/extensions/memory-lancedb/openclaw.plugin.json +60 -0
- package/extensions/memory-lancedb/package.json +19 -0
- package/extensions/minimax-portal-auth/README.md +33 -0
- package/extensions/minimax-portal-auth/index.ts +155 -0
- package/extensions/minimax-portal-auth/node_modules/.bin/openclaw +21 -0
- package/extensions/minimax-portal-auth/oauth.ts +247 -0
- package/extensions/minimax-portal-auth/openclaw.plugin.json +9 -0
- package/extensions/minimax-portal-auth/package.json +14 -0
- package/extensions/msteams/CHANGELOG.md +83 -0
- package/extensions/msteams/index.ts +17 -0
- package/extensions/msteams/node_modules/.bin/openclaw +21 -0
- package/extensions/msteams/openclaw.plugin.json +9 -0
- package/extensions/msteams/package.json +39 -0
- package/extensions/msteams/src/attachments/download.ts +283 -0
- package/extensions/msteams/src/attachments/graph.ts +353 -0
- package/extensions/msteams/src/attachments/html.ts +90 -0
- package/extensions/msteams/src/attachments/payload.ts +22 -0
- package/extensions/msteams/src/attachments/shared.ts +291 -0
- package/extensions/msteams/src/attachments/types.ts +37 -0
- package/extensions/msteams/src/attachments.test.ts +459 -0
- package/extensions/msteams/src/attachments.ts +18 -0
- package/extensions/msteams/src/channel.directory.test.ts +48 -0
- package/extensions/msteams/src/channel.ts +459 -0
- package/extensions/msteams/src/conversation-store-fs.test.ts +88 -0
- package/extensions/msteams/src/conversation-store-fs.ts +165 -0
- package/extensions/msteams/src/conversation-store-memory.ts +47 -0
- package/extensions/msteams/src/conversation-store.ts +41 -0
- package/extensions/msteams/src/directory-live.ts +205 -0
- package/extensions/msteams/src/errors.test.ts +45 -0
- package/extensions/msteams/src/errors.ts +190 -0
- package/extensions/msteams/src/file-consent-helpers.test.ts +243 -0
- package/extensions/msteams/src/file-consent-helpers.ts +73 -0
- package/extensions/msteams/src/file-consent.ts +126 -0
- package/extensions/msteams/src/graph-chat.ts +53 -0
- package/extensions/msteams/src/graph-upload.ts +453 -0
- package/extensions/msteams/src/inbound.test.ts +66 -0
- package/extensions/msteams/src/inbound.ts +48 -0
- package/extensions/msteams/src/index.ts +4 -0
- package/extensions/msteams/src/media-helpers.test.ts +189 -0
- package/extensions/msteams/src/media-helpers.ts +86 -0
- package/extensions/msteams/src/messenger.test.ts +248 -0
- package/extensions/msteams/src/messenger.ts +495 -0
- package/extensions/msteams/src/monitor-handler/inbound-media.ts +128 -0
- package/extensions/msteams/src/monitor-handler/message-handler.ts +640 -0
- package/extensions/msteams/src/monitor-handler.ts +162 -0
- package/extensions/msteams/src/monitor-types.ts +5 -0
- package/extensions/msteams/src/monitor.ts +295 -0
- package/extensions/msteams/src/onboarding.ts +431 -0
- package/extensions/msteams/src/outbound.ts +46 -0
- package/extensions/msteams/src/pending-uploads.ts +89 -0
- package/extensions/msteams/src/policy.test.ts +209 -0
- package/extensions/msteams/src/policy.ts +273 -0
- package/extensions/msteams/src/polls-store-memory.ts +32 -0
- package/extensions/msteams/src/polls-store.test.ts +38 -0
- package/extensions/msteams/src/polls.test.ts +72 -0
- package/extensions/msteams/src/polls.ts +315 -0
- package/extensions/msteams/src/probe.test.ts +58 -0
- package/extensions/msteams/src/probe.ts +107 -0
- package/extensions/msteams/src/reply-dispatcher.ts +130 -0
- package/extensions/msteams/src/resolve-allowlist.ts +297 -0
- package/extensions/msteams/src/runtime.ts +14 -0
- package/extensions/msteams/src/sdk-types.ts +19 -0
- package/extensions/msteams/src/sdk.ts +33 -0
- package/extensions/msteams/src/send-context.ts +164 -0
- package/extensions/msteams/src/send.ts +519 -0
- package/extensions/msteams/src/sent-message-cache.test.ts +15 -0
- package/extensions/msteams/src/sent-message-cache.ts +47 -0
- package/extensions/msteams/src/storage.ts +25 -0
- package/extensions/msteams/src/store-fs.ts +83 -0
- package/extensions/msteams/src/token.ts +19 -0
- package/extensions/nextcloud-talk/index.ts +17 -0
- package/extensions/nextcloud-talk/node_modules/.bin/openclaw +21 -0
- package/extensions/nextcloud-talk/openclaw.plugin.json +9 -0
- package/extensions/nextcloud-talk/package.json +33 -0
- package/extensions/nextcloud-talk/src/accounts.ts +174 -0
- package/extensions/nextcloud-talk/src/channel.ts +409 -0
- package/extensions/nextcloud-talk/src/config-schema.ts +78 -0
- package/extensions/nextcloud-talk/src/format.ts +79 -0
- package/extensions/nextcloud-talk/src/inbound.ts +317 -0
- package/extensions/nextcloud-talk/src/monitor.ts +246 -0
- package/extensions/nextcloud-talk/src/normalize.ts +39 -0
- package/extensions/nextcloud-talk/src/onboarding.ts +343 -0
- package/extensions/nextcloud-talk/src/policy.test.ts +33 -0
- package/extensions/nextcloud-talk/src/policy.ts +180 -0
- package/extensions/nextcloud-talk/src/room-info.ts +125 -0
- package/extensions/nextcloud-talk/src/runtime.ts +14 -0
- package/extensions/nextcloud-talk/src/send.ts +210 -0
- package/extensions/nextcloud-talk/src/signature.ts +72 -0
- package/extensions/nextcloud-talk/src/types.ts +179 -0
- package/extensions/nostr/CHANGELOG.md +74 -0
- package/extensions/nostr/README.md +136 -0
- package/extensions/nostr/index.ts +68 -0
- package/extensions/nostr/node_modules/.bin/openclaw +21 -0
- package/extensions/nostr/openclaw.plugin.json +9 -0
- package/extensions/nostr/package.json +34 -0
- package/extensions/nostr/src/channel.test.ts +151 -0
- package/extensions/nostr/src/channel.ts +353 -0
- package/extensions/nostr/src/config-schema.ts +90 -0
- package/extensions/nostr/src/metrics.ts +478 -0
- package/extensions/nostr/src/nostr-bus.fuzz.test.ts +533 -0
- package/extensions/nostr/src/nostr-bus.integration.test.ts +448 -0
- package/extensions/nostr/src/nostr-bus.test.ts +199 -0
- package/extensions/nostr/src/nostr-bus.ts +715 -0
- package/extensions/nostr/src/nostr-profile-http.test.ts +378 -0
- package/extensions/nostr/src/nostr-profile-http.ts +519 -0
- package/extensions/nostr/src/nostr-profile-import.test.ts +119 -0
- package/extensions/nostr/src/nostr-profile-import.ts +262 -0
- package/extensions/nostr/src/nostr-profile.fuzz.test.ts +477 -0
- package/extensions/nostr/src/nostr-profile.test.ts +410 -0
- package/extensions/nostr/src/nostr-profile.ts +277 -0
- package/extensions/nostr/src/nostr-state-store.test.ts +131 -0
- package/extensions/nostr/src/nostr-state-store.ts +226 -0
- package/extensions/nostr/src/runtime.ts +14 -0
- package/extensions/nostr/src/seen-tracker.ts +303 -0
- package/extensions/nostr/src/types.test.ts +157 -0
- package/extensions/nostr/src/types.ts +101 -0
- package/extensions/nostr/test/setup.ts +5 -0
- package/extensions/open-prose/README.md +25 -0
- package/extensions/open-prose/index.ts +5 -0
- package/extensions/open-prose/node_modules/.bin/openclaw +21 -0
- package/extensions/open-prose/openclaw.plugin.json +11 -0
- package/extensions/open-prose/package.json +14 -0
- package/extensions/open-prose/skills/prose/LICENSE +21 -0
- package/extensions/open-prose/skills/prose/SKILL.md +323 -0
- package/extensions/open-prose/skills/prose/alt-borges.md +141 -0
- package/extensions/open-prose/skills/prose/alts/arabian-nights.md +358 -0
- package/extensions/open-prose/skills/prose/alts/borges.md +360 -0
- package/extensions/open-prose/skills/prose/alts/folk.md +322 -0
- package/extensions/open-prose/skills/prose/alts/homer.md +346 -0
- package/extensions/open-prose/skills/prose/alts/kafka.md +373 -0
- package/extensions/open-prose/skills/prose/compiler.md +2971 -0
- package/extensions/open-prose/skills/prose/examples/01-hello-world.prose +4 -0
- package/extensions/open-prose/skills/prose/examples/02-research-and-summarize.prose +6 -0
- package/extensions/open-prose/skills/prose/examples/03-code-review.prose +17 -0
- package/extensions/open-prose/skills/prose/examples/04-write-and-refine.prose +14 -0
- package/extensions/open-prose/skills/prose/examples/05-debug-issue.prose +20 -0
- package/extensions/open-prose/skills/prose/examples/06-explain-codebase.prose +17 -0
- package/extensions/open-prose/skills/prose/examples/07-refactor.prose +20 -0
- package/extensions/open-prose/skills/prose/examples/08-blog-post.prose +20 -0
- package/extensions/open-prose/skills/prose/examples/09-research-with-agents.prose +25 -0
- package/extensions/open-prose/skills/prose/examples/10-code-review-agents.prose +32 -0
- package/extensions/open-prose/skills/prose/examples/11-skills-and-imports.prose +27 -0
- package/extensions/open-prose/skills/prose/examples/12-secure-agent-permissions.prose +43 -0
- package/extensions/open-prose/skills/prose/examples/13-variables-and-context.prose +51 -0
- package/extensions/open-prose/skills/prose/examples/14-composition-blocks.prose +48 -0
- package/extensions/open-prose/skills/prose/examples/15-inline-sequences.prose +23 -0
- package/extensions/open-prose/skills/prose/examples/16-parallel-reviews.prose +19 -0
- package/extensions/open-prose/skills/prose/examples/17-parallel-research.prose +19 -0
- package/extensions/open-prose/skills/prose/examples/18-mixed-parallel-sequential.prose +36 -0
- package/extensions/open-prose/skills/prose/examples/19-advanced-parallel.prose +71 -0
- package/extensions/open-prose/skills/prose/examples/20-fixed-loops.prose +20 -0
- package/extensions/open-prose/skills/prose/examples/21-pipeline-operations.prose +35 -0
- package/extensions/open-prose/skills/prose/examples/22-error-handling.prose +51 -0
- package/extensions/open-prose/skills/prose/examples/23-retry-with-backoff.prose +63 -0
- package/extensions/open-prose/skills/prose/examples/24-choice-blocks.prose +86 -0
- package/extensions/open-prose/skills/prose/examples/25-conditionals.prose +114 -0
- package/extensions/open-prose/skills/prose/examples/26-parameterized-blocks.prose +100 -0
- package/extensions/open-prose/skills/prose/examples/27-string-interpolation.prose +105 -0
- package/extensions/open-prose/skills/prose/examples/28-automated-pr-review.prose +37 -0
- package/extensions/open-prose/skills/prose/examples/28-gas-town.prose +1572 -0
- package/extensions/open-prose/skills/prose/examples/29-captains-chair.prose +218 -0
- package/extensions/open-prose/skills/prose/examples/30-captains-chair-simple.prose +42 -0
- package/extensions/open-prose/skills/prose/examples/31-captains-chair-with-memory.prose +145 -0
- package/extensions/open-prose/skills/prose/examples/33-pr-review-autofix.prose +168 -0
- package/extensions/open-prose/skills/prose/examples/34-content-pipeline.prose +204 -0
- package/extensions/open-prose/skills/prose/examples/35-feature-factory.prose +296 -0
- package/extensions/open-prose/skills/prose/examples/36-bug-hunter.prose +237 -0
- package/extensions/open-prose/skills/prose/examples/37-the-forge.prose +1474 -0
- package/extensions/open-prose/skills/prose/examples/38-skill-scan.prose +455 -0
- package/extensions/open-prose/skills/prose/examples/39-architect-by-simulation.prose +277 -0
- package/extensions/open-prose/skills/prose/examples/40-rlm-self-refine.prose +32 -0
- package/extensions/open-prose/skills/prose/examples/41-rlm-divide-conquer.prose +38 -0
- package/extensions/open-prose/skills/prose/examples/42-rlm-filter-recurse.prose +46 -0
- package/extensions/open-prose/skills/prose/examples/43-rlm-pairwise.prose +50 -0
- package/extensions/open-prose/skills/prose/examples/44-run-endpoint-ux-test.prose +261 -0
- package/extensions/open-prose/skills/prose/examples/45-plugin-release.prose +159 -0
- package/extensions/open-prose/skills/prose/examples/45-run-endpoint-ux-test-with-remediation.prose +637 -0
- package/extensions/open-prose/skills/prose/examples/46-run-endpoint-ux-test-fast.prose +148 -0
- package/extensions/open-prose/skills/prose/examples/46-workflow-crystallizer.prose +225 -0
- package/extensions/open-prose/skills/prose/examples/47-language-self-improvement.prose +356 -0
- package/extensions/open-prose/skills/prose/examples/48-habit-miner.prose +445 -0
- package/extensions/open-prose/skills/prose/examples/49-prose-run-retrospective.prose +210 -0
- package/extensions/open-prose/skills/prose/examples/README.md +391 -0
- package/extensions/open-prose/skills/prose/examples/roadmap/README.md +22 -0
- package/extensions/open-prose/skills/prose/examples/roadmap/iterative-refinement.prose +20 -0
- package/extensions/open-prose/skills/prose/examples/roadmap/parallel-review.prose +18 -0
- package/extensions/open-prose/skills/prose/examples/roadmap/simple-pipeline.prose +17 -0
- package/extensions/open-prose/skills/prose/examples/roadmap/syntax/open-prose-syntax.prose +223 -0
- package/extensions/open-prose/skills/prose/guidance/antipatterns.md +951 -0
- package/extensions/open-prose/skills/prose/guidance/patterns.md +700 -0
- package/extensions/open-prose/skills/prose/guidance/system-prompt.md +180 -0
- package/extensions/open-prose/skills/prose/help.md +144 -0
- package/extensions/open-prose/skills/prose/lib/README.md +108 -0
- package/extensions/open-prose/skills/prose/lib/calibrator.prose +215 -0
- package/extensions/open-prose/skills/prose/lib/cost-analyzer.prose +174 -0
- package/extensions/open-prose/skills/prose/lib/error-forensics.prose +250 -0
- package/extensions/open-prose/skills/prose/lib/inspector.prose +196 -0
- package/extensions/open-prose/skills/prose/lib/profiler.prose +460 -0
- package/extensions/open-prose/skills/prose/lib/program-improver.prose +275 -0
- package/extensions/open-prose/skills/prose/lib/project-memory.prose +118 -0
- package/extensions/open-prose/skills/prose/lib/user-memory.prose +93 -0
- package/extensions/open-prose/skills/prose/lib/vm-improver.prose +243 -0
- package/extensions/open-prose/skills/prose/primitives/session.md +593 -0
- package/extensions/open-prose/skills/prose/prose.md +1237 -0
- package/extensions/open-prose/skills/prose/state/filesystem.md +498 -0
- package/extensions/open-prose/skills/prose/state/in-context.md +384 -0
- package/extensions/open-prose/skills/prose/state/postgres.md +880 -0
- package/extensions/open-prose/skills/prose/state/sqlite.md +574 -0
- package/extensions/qwen-portal-auth/README.md +24 -0
- package/extensions/qwen-portal-auth/index.ts +130 -0
- package/extensions/qwen-portal-auth/oauth.ts +190 -0
- package/extensions/qwen-portal-auth/openclaw.plugin.json +9 -0
- package/extensions/signal/index.ts +17 -0
- package/extensions/signal/node_modules/.bin/openclaw +21 -0
- package/extensions/signal/openclaw.plugin.json +9 -0
- package/extensions/signal/package.json +14 -0
- package/extensions/signal/src/channel.ts +315 -0
- package/extensions/signal/src/runtime.ts +14 -0
- package/extensions/slack/index.ts +17 -0
- package/extensions/slack/node_modules/.bin/openclaw +21 -0
- package/extensions/slack/openclaw.plugin.json +9 -0
- package/extensions/slack/package.json +14 -0
- package/extensions/slack/src/channel.ts +604 -0
- package/extensions/slack/src/runtime.ts +14 -0
- package/extensions/telegram/index.ts +17 -0
- package/extensions/telegram/node_modules/.bin/openclaw +21 -0
- package/extensions/telegram/openclaw.plugin.json +9 -0
- package/extensions/telegram/package.json +14 -0
- package/extensions/telegram/src/channel.ts +482 -0
- package/extensions/telegram/src/runtime.ts +14 -0
- package/extensions/tlon/README.md +5 -0
- package/extensions/tlon/index.ts +17 -0
- package/extensions/tlon/node_modules/.bin/openclaw +21 -0
- package/extensions/tlon/openclaw.plugin.json +9 -0
- package/extensions/tlon/package.json +33 -0
- package/extensions/tlon/src/channel.ts +392 -0
- package/extensions/tlon/src/config-schema.test.ts +31 -0
- package/extensions/tlon/src/config-schema.ts +43 -0
- package/extensions/tlon/src/monitor/discovery.ts +76 -0
- package/extensions/tlon/src/monitor/history.ts +90 -0
- package/extensions/tlon/src/monitor/index.ts +553 -0
- package/extensions/tlon/src/monitor/processed-messages.test.ts +23 -0
- package/extensions/tlon/src/monitor/processed-messages.ts +46 -0
- package/extensions/tlon/src/monitor/utils.ts +105 -0
- package/extensions/tlon/src/onboarding.ts +214 -0
- package/extensions/tlon/src/runtime.ts +14 -0
- package/extensions/tlon/src/targets.ts +89 -0
- package/extensions/tlon/src/types.ts +92 -0
- package/extensions/tlon/src/urbit/auth.ts +18 -0
- package/extensions/tlon/src/urbit/http-api.ts +38 -0
- package/extensions/tlon/src/urbit/send.test.ts +38 -0
- package/extensions/tlon/src/urbit/send.ts +131 -0
- package/extensions/tlon/src/urbit/sse-client.test.ts +40 -0
- package/extensions/tlon/src/urbit/sse-client.ts +395 -0
- package/extensions/twitch/CHANGELOG.md +45 -0
- package/extensions/twitch/README.md +89 -0
- package/extensions/twitch/index.ts +20 -0
- package/extensions/twitch/node_modules/.bin/openclaw +21 -0
- package/extensions/twitch/openclaw.plugin.json +9 -0
- package/extensions/twitch/package.json +20 -0
- package/extensions/twitch/src/access-control.test.ts +489 -0
- package/extensions/twitch/src/access-control.ts +166 -0
- package/extensions/twitch/src/actions.ts +173 -0
- package/extensions/twitch/src/client-manager-registry.ts +115 -0
- package/extensions/twitch/src/config-schema.ts +82 -0
- package/extensions/twitch/src/config.test.ts +87 -0
- package/extensions/twitch/src/config.ts +116 -0
- package/extensions/twitch/src/monitor.ts +261 -0
- package/extensions/twitch/src/onboarding.test.ts +311 -0
- package/extensions/twitch/src/onboarding.ts +417 -0
- package/extensions/twitch/src/outbound.test.ts +373 -0
- package/extensions/twitch/src/outbound.ts +184 -0
- package/extensions/twitch/src/plugin.test.ts +39 -0
- package/extensions/twitch/src/plugin.ts +274 -0
- package/extensions/twitch/src/probe.test.ts +195 -0
- package/extensions/twitch/src/probe.ts +120 -0
- package/extensions/twitch/src/resolver.ts +137 -0
- package/extensions/twitch/src/runtime.ts +14 -0
- package/extensions/twitch/src/send.test.ts +289 -0
- package/extensions/twitch/src/send.ts +136 -0
- package/extensions/twitch/src/status.test.ts +270 -0
- package/extensions/twitch/src/status.ts +178 -0
- package/extensions/twitch/src/token.test.ts +171 -0
- package/extensions/twitch/src/token.ts +91 -0
- package/extensions/twitch/src/twitch-client.test.ts +589 -0
- package/extensions/twitch/src/twitch-client.ts +277 -0
- package/extensions/twitch/src/types.ts +141 -0
- package/extensions/twitch/src/utils/markdown.ts +98 -0
- package/extensions/twitch/src/utils/twitch.ts +78 -0
- package/extensions/twitch/test/setup.ts +7 -0
- package/extensions/voice-call/CHANGELOG.md +109 -0
- package/extensions/voice-call/README.md +139 -0
- package/extensions/voice-call/index.ts +493 -0
- package/extensions/voice-call/node_modules/.bin/openclaw +21 -0
- package/extensions/voice-call/openclaw.plugin.json +559 -0
- package/extensions/voice-call/package.json +19 -0
- package/extensions/voice-call/src/allowlist.ts +19 -0
- package/extensions/voice-call/src/cli.ts +279 -0
- package/extensions/voice-call/src/config.test.ts +234 -0
- package/extensions/voice-call/src/config.ts +523 -0
- package/extensions/voice-call/src/core-bridge.ts +159 -0
- package/extensions/voice-call/src/manager/context.ts +21 -0
- package/extensions/voice-call/src/manager/events.ts +188 -0
- package/extensions/voice-call/src/manager/lookup.ts +35 -0
- package/extensions/voice-call/src/manager/outbound.ts +275 -0
- package/extensions/voice-call/src/manager/state.ts +48 -0
- package/extensions/voice-call/src/manager/store.ts +91 -0
- package/extensions/voice-call/src/manager/timers.ts +89 -0
- package/extensions/voice-call/src/manager/twiml.ts +9 -0
- package/extensions/voice-call/src/manager.test.ts +194 -0
- package/extensions/voice-call/src/manager.ts +887 -0
- package/extensions/voice-call/src/media-stream.test.ts +96 -0
- package/extensions/voice-call/src/media-stream.ts +411 -0
- package/extensions/voice-call/src/providers/base.ts +67 -0
- package/extensions/voice-call/src/providers/index.ts +10 -0
- package/extensions/voice-call/src/providers/mock.ts +165 -0
- package/extensions/voice-call/src/providers/plivo.test.ts +27 -0
- package/extensions/voice-call/src/providers/plivo.ts +515 -0
- package/extensions/voice-call/src/providers/stt-openai-realtime.ts +311 -0
- package/extensions/voice-call/src/providers/telnyx.ts +371 -0
- package/extensions/voice-call/src/providers/tts-openai.ts +259 -0
- package/extensions/voice-call/src/providers/twilio/api.ts +42 -0
- package/extensions/voice-call/src/providers/twilio/webhook.ts +32 -0
- package/extensions/voice-call/src/providers/twilio.test.ts +60 -0
- package/extensions/voice-call/src/providers/twilio.ts +626 -0
- package/extensions/voice-call/src/response-generator.ts +158 -0
- package/extensions/voice-call/src/runtime.ts +212 -0
- package/extensions/voice-call/src/telephony-audio.ts +90 -0
- package/extensions/voice-call/src/telephony-tts.ts +104 -0
- package/extensions/voice-call/src/tunnel.ts +314 -0
- package/extensions/voice-call/src/types.ts +272 -0
- package/extensions/voice-call/src/utils.ts +14 -0
- package/extensions/voice-call/src/voice-mapping.ts +67 -0
- package/extensions/voice-call/src/webhook-security.test.ts +377 -0
- package/extensions/voice-call/src/webhook-security.ts +689 -0
- package/extensions/voice-call/src/webhook.ts +491 -0
- package/extensions/whatsapp/index.ts +17 -0
- package/extensions/whatsapp/node_modules/.bin/openclaw +21 -0
- package/extensions/whatsapp/openclaw.plugin.json +9 -0
- package/extensions/whatsapp/package.json +14 -0
- package/extensions/whatsapp/src/channel.ts +508 -0
- package/extensions/whatsapp/src/runtime.ts +14 -0
- package/extensions/zalo/CHANGELOG.md +89 -0
- package/extensions/zalo/README.md +50 -0
- package/extensions/zalo/index.ts +19 -0
- package/extensions/zalo/node_modules/.bin/openclaw +21 -0
- package/extensions/zalo/openclaw.plugin.json +9 -0
- package/extensions/zalo/package.json +36 -0
- package/extensions/zalo/src/accounts.ts +80 -0
- package/extensions/zalo/src/actions.ts +67 -0
- package/extensions/zalo/src/api.ts +208 -0
- package/extensions/zalo/src/channel.directory.test.ts +43 -0
- package/extensions/zalo/src/channel.ts +414 -0
- package/extensions/zalo/src/config-schema.ts +24 -0
- package/extensions/zalo/src/monitor.ts +753 -0
- package/extensions/zalo/src/monitor.webhook.test.ts +73 -0
- package/extensions/zalo/src/onboarding.ts +401 -0
- package/extensions/zalo/src/probe.ts +46 -0
- package/extensions/zalo/src/proxy.ts +21 -0
- package/extensions/zalo/src/runtime.ts +14 -0
- package/extensions/zalo/src/send.ts +124 -0
- package/extensions/zalo/src/status-issues.ts +53 -0
- package/extensions/zalo/src/token.ts +63 -0
- package/extensions/zalo/src/types.ts +42 -0
- package/extensions/zalouser/CHANGELOG.md +61 -0
- package/extensions/zalouser/README.md +225 -0
- package/extensions/zalouser/index.ts +31 -0
- package/extensions/zalouser/node_modules/.bin/openclaw +21 -0
- package/extensions/zalouser/openclaw.plugin.json +9 -0
- package/extensions/zalouser/package.json +36 -0
- package/extensions/zalouser/src/accounts.ts +135 -0
- package/extensions/zalouser/src/channel.test.ts +18 -0
- package/extensions/zalouser/src/channel.ts +686 -0
- package/extensions/zalouser/src/config-schema.ts +27 -0
- package/extensions/zalouser/src/monitor.ts +590 -0
- package/extensions/zalouser/src/onboarding.ts +504 -0
- package/extensions/zalouser/src/probe.ts +28 -0
- package/extensions/zalouser/src/runtime.ts +14 -0
- package/extensions/zalouser/src/send.ts +160 -0
- package/extensions/zalouser/src/status-issues.test.ts +57 -0
- package/extensions/zalouser/src/status-issues.ts +89 -0
- package/extensions/zalouser/src/tool.ts +164 -0
- package/extensions/zalouser/src/types.ts +108 -0
- package/extensions/zalouser/src/zca.ts +202 -0
- package/openclaw.mjs +14 -0
- package/package.json +245 -0
- package/skills/1password/SKILL.md +70 -0
- package/skills/1password/references/cli-examples.md +29 -0
- package/skills/1password/references/get-started.md +17 -0
- package/skills/apple-notes/SKILL.md +77 -0
- package/skills/apple-reminders/SKILL.md +96 -0
- package/skills/bear-notes/SKILL.md +107 -0
- package/skills/bird/SKILL.md +224 -0
- package/skills/blogwatcher/SKILL.md +69 -0
- package/skills/blucli/SKILL.md +47 -0
- package/skills/bluebubbles/SKILL.md +131 -0
- package/skills/camsnap/SKILL.md +45 -0
- package/skills/canvas/SKILL.md +198 -0
- package/skills/clawhub/SKILL.md +77 -0
- package/skills/coding-agent/SKILL.md +284 -0
- package/skills/discord/SKILL.md +578 -0
- package/skills/eightctl/SKILL.md +50 -0
- package/skills/food-order/SKILL.md +48 -0
- package/skills/gemini/SKILL.md +43 -0
- package/skills/ghostly-projects/SKILL.md +160 -0
- package/skills/gifgrep/SKILL.md +79 -0
- package/skills/github/SKILL.md +77 -0
- package/skills/gog/SKILL.md +116 -0
- package/skills/goplaces/SKILL.md +52 -0
- package/skills/healthcheck/SKILL.md +245 -0
- package/skills/himalaya/SKILL.md +257 -0
- package/skills/himalaya/references/configuration.md +184 -0
- package/skills/himalaya/references/message-composition.md +199 -0
- package/skills/imsg/SKILL.md +74 -0
- package/skills/linear/SKILL.md +111 -0
- package/skills/linear/linear.sh +204 -0
- package/skills/local-places/SERVER_README.md +101 -0
- package/skills/local-places/SKILL.md +102 -0
- package/skills/local-places/pyproject.toml +21 -0
- package/skills/local-places/src/local_places/__init__.py +2 -0
- package/skills/local-places/src/local_places/google_places.py +314 -0
- package/skills/local-places/src/local_places/main.py +65 -0
- package/skills/local-places/src/local_places/schemas.py +107 -0
- package/skills/mcporter/SKILL.md +61 -0
- package/skills/model-usage/SKILL.md +69 -0
- package/skills/model-usage/references/codexbar-cli.md +33 -0
- package/skills/model-usage/scripts/model_usage.py +310 -0
- package/skills/nano-banana-pro/SKILL.md +58 -0
- package/skills/nano-banana-pro/scripts/generate_image.py +184 -0
- package/skills/nano-pdf/SKILL.md +38 -0
- package/skills/notion/SKILL.md +172 -0
- package/skills/obsidian/SKILL.md +81 -0
- package/skills/openai-image-gen/SKILL.md +89 -0
- package/skills/openai-image-gen/scripts/gen.py +240 -0
- package/skills/openai-whisper/SKILL.md +38 -0
- package/skills/openai-whisper-api/SKILL.md +52 -0
- package/skills/openai-whisper-api/scripts/transcribe.sh +85 -0
- package/skills/openhue/SKILL.md +51 -0
- package/skills/oracle/SKILL.md +125 -0
- package/skills/ordercli/SKILL.md +78 -0
- package/skills/peekaboo/SKILL.md +190 -0
- package/skills/sag/SKILL.md +87 -0
- package/skills/session-logs/SKILL.md +115 -0
- package/skills/sherpa-onnx-tts/SKILL.md +103 -0
- package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +178 -0
- package/skills/skill-creator/SKILL.md +370 -0
- package/skills/skill-creator/license.txt +202 -0
- package/skills/skill-creator/scripts/init_skill.py +378 -0
- package/skills/skill-creator/scripts/package_skill.py +111 -0
- package/skills/skill-creator/scripts/quick_validate.py +101 -0
- package/skills/slack/SKILL.md +144 -0
- package/skills/songsee/SKILL.md +49 -0
- package/skills/sonoscli/SKILL.md +46 -0
- package/skills/spotify-player/SKILL.md +64 -0
- package/skills/summarize/SKILL.md +87 -0
- package/skills/things-mac/SKILL.md +86 -0
- package/skills/tmux/SKILL.md +135 -0
- package/skills/tmux/scripts/find-sessions.sh +112 -0
- package/skills/tmux/scripts/wait-for-text.sh +83 -0
- package/skills/trello/SKILL.md +95 -0
- package/skills/video-frames/SKILL.md +46 -0
- package/skills/video-frames/scripts/frame.sh +81 -0
- package/skills/voice-call/SKILL.md +45 -0
- package/skills/wacli/SKILL.md +72 -0
- package/skills/weather/SKILL.md +54 -0
|
@@ -0,0 +1,1686 @@
|
|
|
1
|
+
import { g as resolveStateDir, m as resolveOAuthDir, o as resolveConfigPath } from "./paths-scjhy7N2.js";
|
|
2
|
+
import { N as normalizeAgentId, c as resolveDefaultAgentId } from "./agent-scope-BbT4OG2N.js";
|
|
3
|
+
import { n as runExec } from "./exec-HEWTMJ7j.js";
|
|
4
|
+
import { t as formatCliCommand } from "./command-format-DELazozB.js";
|
|
5
|
+
import { D as MAX_INCLUDE_DEPTH, E as INCLUDE_KEY, r as createConfigIO } from "./config-BtSTwPcH.js";
|
|
6
|
+
import { n as listChannelPlugins } from "./plugins-QJjTXliB.js";
|
|
7
|
+
import { $ as resolveSandboxToolPolicyForAgent, Z as resolveSandboxConfigForAgent, at as resolveToolProfilePolicy } from "./sandbox-knontqD9.js";
|
|
8
|
+
import { a as resolveProfile, i as resolveBrowserConfig } from "./server-context-B9GX5GOI.js";
|
|
9
|
+
import { m as GATEWAY_CLIENT_NAMES, p as GATEWAY_CLIENT_MODES } from "./message-channel-D6v_oPAg.js";
|
|
10
|
+
import { t as GatewayClient } from "./client-DySXIFCA.js";
|
|
11
|
+
import { t as buildGatewayConnectionDetails } from "./call-B7EveN4V.js";
|
|
12
|
+
import { i as readChannelAllowFromStore } from "./pairing-store-DDLNuzmx.js";
|
|
13
|
+
import { c as resolveNativeSkillsEnabled, n as isToolAllowedByPolicies, s as resolveNativeCommandsEnabled } from "./pi-tools.policy-BvkSDFDN.js";
|
|
14
|
+
import { t as resolveChannelDefaultAccountId } from "./helpers-BtbBZVKZ.js";
|
|
15
|
+
import { i as resolveGatewayAuth } from "./auth-y1BLPUhX.js";
|
|
16
|
+
import os from "node:os";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
import JSON5 from "json5";
|
|
19
|
+
import fs from "node:fs/promises";
|
|
20
|
+
import { randomUUID } from "node:crypto";
|
|
21
|
+
|
|
22
|
+
//#region src/gateway/probe.ts
|
|
23
|
+
function formatError(err) {
|
|
24
|
+
if (err instanceof Error) return err.message;
|
|
25
|
+
return String(err);
|
|
26
|
+
}
|
|
27
|
+
async function probeGateway(opts) {
|
|
28
|
+
const startedAt = Date.now();
|
|
29
|
+
const instanceId = randomUUID();
|
|
30
|
+
let connectLatencyMs = null;
|
|
31
|
+
let connectError = null;
|
|
32
|
+
let close = null;
|
|
33
|
+
return await new Promise((resolve) => {
|
|
34
|
+
let settled = false;
|
|
35
|
+
const settle = (result) => {
|
|
36
|
+
if (settled) return;
|
|
37
|
+
settled = true;
|
|
38
|
+
clearTimeout(timer);
|
|
39
|
+
client.stop();
|
|
40
|
+
resolve({
|
|
41
|
+
url: opts.url,
|
|
42
|
+
...result
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
const client = new GatewayClient({
|
|
46
|
+
url: opts.url,
|
|
47
|
+
token: opts.auth?.token,
|
|
48
|
+
password: opts.auth?.password,
|
|
49
|
+
clientName: GATEWAY_CLIENT_NAMES.CLI,
|
|
50
|
+
clientVersion: "dev",
|
|
51
|
+
mode: GATEWAY_CLIENT_MODES.PROBE,
|
|
52
|
+
instanceId,
|
|
53
|
+
onConnectError: (err) => {
|
|
54
|
+
connectError = formatError(err);
|
|
55
|
+
},
|
|
56
|
+
onClose: (code, reason) => {
|
|
57
|
+
close = {
|
|
58
|
+
code,
|
|
59
|
+
reason
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
onHelloOk: async () => {
|
|
63
|
+
connectLatencyMs = Date.now() - startedAt;
|
|
64
|
+
try {
|
|
65
|
+
const [health, status, presence, configSnapshot] = await Promise.all([
|
|
66
|
+
client.request("health"),
|
|
67
|
+
client.request("status"),
|
|
68
|
+
client.request("system-presence"),
|
|
69
|
+
client.request("config.get", {})
|
|
70
|
+
]);
|
|
71
|
+
settle({
|
|
72
|
+
ok: true,
|
|
73
|
+
connectLatencyMs,
|
|
74
|
+
error: null,
|
|
75
|
+
close,
|
|
76
|
+
health,
|
|
77
|
+
status,
|
|
78
|
+
presence: Array.isArray(presence) ? presence : null,
|
|
79
|
+
configSnapshot
|
|
80
|
+
});
|
|
81
|
+
} catch (err) {
|
|
82
|
+
settle({
|
|
83
|
+
ok: false,
|
|
84
|
+
connectLatencyMs,
|
|
85
|
+
error: formatError(err),
|
|
86
|
+
close,
|
|
87
|
+
health: null,
|
|
88
|
+
status: null,
|
|
89
|
+
presence: null,
|
|
90
|
+
configSnapshot: null
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
const timer = setTimeout(() => {
|
|
96
|
+
settle({
|
|
97
|
+
ok: false,
|
|
98
|
+
connectLatencyMs,
|
|
99
|
+
error: connectError ? `connect failed: ${connectError}` : "timeout",
|
|
100
|
+
close,
|
|
101
|
+
health: null,
|
|
102
|
+
status: null,
|
|
103
|
+
presence: null,
|
|
104
|
+
configSnapshot: null
|
|
105
|
+
});
|
|
106
|
+
}, Math.max(250, opts.timeoutMs));
|
|
107
|
+
client.start();
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region src/security/windows-acl.ts
|
|
113
|
+
const INHERIT_FLAGS = new Set([
|
|
114
|
+
"I",
|
|
115
|
+
"OI",
|
|
116
|
+
"CI",
|
|
117
|
+
"IO",
|
|
118
|
+
"NP"
|
|
119
|
+
]);
|
|
120
|
+
const WORLD_PRINCIPALS = new Set([
|
|
121
|
+
"everyone",
|
|
122
|
+
"users",
|
|
123
|
+
"builtin\\users",
|
|
124
|
+
"authenticated users",
|
|
125
|
+
"nt authority\\authenticated users"
|
|
126
|
+
]);
|
|
127
|
+
const TRUSTED_BASE = new Set([
|
|
128
|
+
"nt authority\\system",
|
|
129
|
+
"system",
|
|
130
|
+
"builtin\\administrators",
|
|
131
|
+
"creator owner"
|
|
132
|
+
]);
|
|
133
|
+
const WORLD_SUFFIXES = ["\\users", "\\authenticated users"];
|
|
134
|
+
const TRUSTED_SUFFIXES = ["\\administrators", "\\system"];
|
|
135
|
+
const normalize = (value) => value.trim().toLowerCase();
|
|
136
|
+
function resolveWindowsUserPrincipal(env) {
|
|
137
|
+
const username = env?.USERNAME?.trim() || os.userInfo().username?.trim();
|
|
138
|
+
if (!username) return null;
|
|
139
|
+
const domain = env?.USERDOMAIN?.trim();
|
|
140
|
+
return domain ? `${domain}\\${username}` : username;
|
|
141
|
+
}
|
|
142
|
+
function buildTrustedPrincipals(env) {
|
|
143
|
+
const trusted = new Set(TRUSTED_BASE);
|
|
144
|
+
const principal = resolveWindowsUserPrincipal(env);
|
|
145
|
+
if (principal) {
|
|
146
|
+
trusted.add(normalize(principal));
|
|
147
|
+
const userOnly = principal.split("\\").at(-1);
|
|
148
|
+
if (userOnly) trusted.add(normalize(userOnly));
|
|
149
|
+
}
|
|
150
|
+
return trusted;
|
|
151
|
+
}
|
|
152
|
+
function classifyPrincipal(principal, env) {
|
|
153
|
+
const normalized = normalize(principal);
|
|
154
|
+
if (buildTrustedPrincipals(env).has(normalized) || TRUSTED_SUFFIXES.some((s) => normalized.endsWith(s))) return "trusted";
|
|
155
|
+
if (WORLD_PRINCIPALS.has(normalized) || WORLD_SUFFIXES.some((s) => normalized.endsWith(s))) return "world";
|
|
156
|
+
return "group";
|
|
157
|
+
}
|
|
158
|
+
function rightsFromTokens(tokens) {
|
|
159
|
+
const upper = tokens.join("").toUpperCase();
|
|
160
|
+
const canWrite = upper.includes("F") || upper.includes("M") || upper.includes("W") || upper.includes("D");
|
|
161
|
+
return {
|
|
162
|
+
canRead: upper.includes("F") || upper.includes("M") || upper.includes("R"),
|
|
163
|
+
canWrite
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function parseIcaclsOutput(output, targetPath) {
|
|
167
|
+
const entries = [];
|
|
168
|
+
const normalizedTarget = targetPath.trim();
|
|
169
|
+
const lowerTarget = normalizedTarget.toLowerCase();
|
|
170
|
+
const quotedTarget = `"${normalizedTarget}"`;
|
|
171
|
+
const quotedLower = quotedTarget.toLowerCase();
|
|
172
|
+
for (const rawLine of output.split(/\r?\n/)) {
|
|
173
|
+
const line = rawLine.trimEnd();
|
|
174
|
+
if (!line.trim()) continue;
|
|
175
|
+
const trimmed = line.trim();
|
|
176
|
+
const lower = trimmed.toLowerCase();
|
|
177
|
+
if (lower.startsWith("successfully processed") || lower.startsWith("processed") || lower.startsWith("failed processing") || lower.startsWith("no mapping between account names")) continue;
|
|
178
|
+
let entry = trimmed;
|
|
179
|
+
if (lower.startsWith(lowerTarget)) entry = trimmed.slice(normalizedTarget.length).trim();
|
|
180
|
+
else if (lower.startsWith(quotedLower)) entry = trimmed.slice(quotedTarget.length).trim();
|
|
181
|
+
if (!entry) continue;
|
|
182
|
+
const idx = entry.indexOf(":");
|
|
183
|
+
if (idx === -1) continue;
|
|
184
|
+
const principal = entry.slice(0, idx).trim();
|
|
185
|
+
const rawRights = entry.slice(idx + 1).trim();
|
|
186
|
+
const tokens = rawRights.match(/\(([^)]+)\)/g)?.map((token) => token.slice(1, -1).trim()).filter(Boolean) ?? [];
|
|
187
|
+
if (tokens.some((token) => token.toUpperCase() === "DENY")) continue;
|
|
188
|
+
const rights = tokens.filter((token) => !INHERIT_FLAGS.has(token.toUpperCase()));
|
|
189
|
+
if (rights.length === 0) continue;
|
|
190
|
+
const { canRead, canWrite } = rightsFromTokens(rights);
|
|
191
|
+
entries.push({
|
|
192
|
+
principal,
|
|
193
|
+
rights,
|
|
194
|
+
rawRights,
|
|
195
|
+
canRead,
|
|
196
|
+
canWrite
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
return entries;
|
|
200
|
+
}
|
|
201
|
+
function summarizeWindowsAcl(entries, env) {
|
|
202
|
+
const trusted = [];
|
|
203
|
+
const untrustedWorld = [];
|
|
204
|
+
const untrustedGroup = [];
|
|
205
|
+
for (const entry of entries) {
|
|
206
|
+
const classification = classifyPrincipal(entry.principal, env);
|
|
207
|
+
if (classification === "trusted") trusted.push(entry);
|
|
208
|
+
else if (classification === "world") untrustedWorld.push(entry);
|
|
209
|
+
else untrustedGroup.push(entry);
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
trusted,
|
|
213
|
+
untrustedWorld,
|
|
214
|
+
untrustedGroup
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
async function inspectWindowsAcl(targetPath, opts) {
|
|
218
|
+
const exec = opts?.exec ?? runExec;
|
|
219
|
+
try {
|
|
220
|
+
const { stdout, stderr } = await exec("icacls", [targetPath]);
|
|
221
|
+
const entries = parseIcaclsOutput(`${stdout}\n${stderr}`.trim(), targetPath);
|
|
222
|
+
const { trusted, untrustedWorld, untrustedGroup } = summarizeWindowsAcl(entries, opts?.env);
|
|
223
|
+
return {
|
|
224
|
+
ok: true,
|
|
225
|
+
entries,
|
|
226
|
+
trusted,
|
|
227
|
+
untrustedWorld,
|
|
228
|
+
untrustedGroup
|
|
229
|
+
};
|
|
230
|
+
} catch (err) {
|
|
231
|
+
return {
|
|
232
|
+
ok: false,
|
|
233
|
+
entries: [],
|
|
234
|
+
trusted: [],
|
|
235
|
+
untrustedWorld: [],
|
|
236
|
+
untrustedGroup: [],
|
|
237
|
+
error: String(err)
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function formatWindowsAclSummary(summary) {
|
|
242
|
+
if (!summary.ok) return "unknown";
|
|
243
|
+
const untrusted = [...summary.untrustedWorld, ...summary.untrustedGroup];
|
|
244
|
+
if (untrusted.length === 0) return "trusted-only";
|
|
245
|
+
return untrusted.map((entry) => `${entry.principal}:${entry.rawRights}`).join(", ");
|
|
246
|
+
}
|
|
247
|
+
function formatIcaclsResetCommand(targetPath, opts) {
|
|
248
|
+
const user = resolveWindowsUserPrincipal(opts.env) ?? "%USERNAME%";
|
|
249
|
+
const grant = opts.isDir ? "(OI)(CI)F" : "F";
|
|
250
|
+
return `icacls "${targetPath}" /inheritance:r /grant:r "${user}:${grant}" /grant:r "SYSTEM:${grant}"`;
|
|
251
|
+
}
|
|
252
|
+
function createIcaclsResetCommand(targetPath, opts) {
|
|
253
|
+
const user = resolveWindowsUserPrincipal(opts.env);
|
|
254
|
+
if (!user) return null;
|
|
255
|
+
const grant = opts.isDir ? "(OI)(CI)F" : "F";
|
|
256
|
+
return {
|
|
257
|
+
command: "icacls",
|
|
258
|
+
args: [
|
|
259
|
+
targetPath,
|
|
260
|
+
"/inheritance:r",
|
|
261
|
+
"/grant:r",
|
|
262
|
+
`${user}:${grant}`,
|
|
263
|
+
"/grant:r",
|
|
264
|
+
`SYSTEM:${grant}`
|
|
265
|
+
],
|
|
266
|
+
display: formatIcaclsResetCommand(targetPath, opts)
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
//#endregion
|
|
271
|
+
//#region src/security/audit-fs.ts
|
|
272
|
+
async function safeStat(targetPath) {
|
|
273
|
+
try {
|
|
274
|
+
const lst = await fs.lstat(targetPath);
|
|
275
|
+
return {
|
|
276
|
+
ok: true,
|
|
277
|
+
isSymlink: lst.isSymbolicLink(),
|
|
278
|
+
isDir: lst.isDirectory(),
|
|
279
|
+
mode: typeof lst.mode === "number" ? lst.mode : null,
|
|
280
|
+
uid: typeof lst.uid === "number" ? lst.uid : null,
|
|
281
|
+
gid: typeof lst.gid === "number" ? lst.gid : null
|
|
282
|
+
};
|
|
283
|
+
} catch (err) {
|
|
284
|
+
return {
|
|
285
|
+
ok: false,
|
|
286
|
+
isSymlink: false,
|
|
287
|
+
isDir: false,
|
|
288
|
+
mode: null,
|
|
289
|
+
uid: null,
|
|
290
|
+
gid: null,
|
|
291
|
+
error: String(err)
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
async function inspectPathPermissions(targetPath, opts) {
|
|
296
|
+
const st = await safeStat(targetPath);
|
|
297
|
+
if (!st.ok) return {
|
|
298
|
+
ok: false,
|
|
299
|
+
isSymlink: false,
|
|
300
|
+
isDir: false,
|
|
301
|
+
mode: null,
|
|
302
|
+
bits: null,
|
|
303
|
+
source: "unknown",
|
|
304
|
+
worldWritable: false,
|
|
305
|
+
groupWritable: false,
|
|
306
|
+
worldReadable: false,
|
|
307
|
+
groupReadable: false,
|
|
308
|
+
error: st.error
|
|
309
|
+
};
|
|
310
|
+
const bits = modeBits(st.mode);
|
|
311
|
+
if ((opts?.platform ?? process.platform) === "win32") {
|
|
312
|
+
const acl = await inspectWindowsAcl(targetPath, {
|
|
313
|
+
env: opts?.env,
|
|
314
|
+
exec: opts?.exec
|
|
315
|
+
});
|
|
316
|
+
if (!acl.ok) return {
|
|
317
|
+
ok: true,
|
|
318
|
+
isSymlink: st.isSymlink,
|
|
319
|
+
isDir: st.isDir,
|
|
320
|
+
mode: st.mode,
|
|
321
|
+
bits,
|
|
322
|
+
source: "unknown",
|
|
323
|
+
worldWritable: false,
|
|
324
|
+
groupWritable: false,
|
|
325
|
+
worldReadable: false,
|
|
326
|
+
groupReadable: false,
|
|
327
|
+
error: acl.error
|
|
328
|
+
};
|
|
329
|
+
return {
|
|
330
|
+
ok: true,
|
|
331
|
+
isSymlink: st.isSymlink,
|
|
332
|
+
isDir: st.isDir,
|
|
333
|
+
mode: st.mode,
|
|
334
|
+
bits,
|
|
335
|
+
source: "windows-acl",
|
|
336
|
+
worldWritable: acl.untrustedWorld.some((entry) => entry.canWrite),
|
|
337
|
+
groupWritable: acl.untrustedGroup.some((entry) => entry.canWrite),
|
|
338
|
+
worldReadable: acl.untrustedWorld.some((entry) => entry.canRead),
|
|
339
|
+
groupReadable: acl.untrustedGroup.some((entry) => entry.canRead),
|
|
340
|
+
aclSummary: formatWindowsAclSummary(acl)
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
return {
|
|
344
|
+
ok: true,
|
|
345
|
+
isSymlink: st.isSymlink,
|
|
346
|
+
isDir: st.isDir,
|
|
347
|
+
mode: st.mode,
|
|
348
|
+
bits,
|
|
349
|
+
source: "posix",
|
|
350
|
+
worldWritable: isWorldWritable(bits),
|
|
351
|
+
groupWritable: isGroupWritable(bits),
|
|
352
|
+
worldReadable: isWorldReadable(bits),
|
|
353
|
+
groupReadable: isGroupReadable(bits)
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
function formatPermissionDetail(targetPath, perms) {
|
|
357
|
+
if (perms.source === "windows-acl") return `${targetPath} acl=${perms.aclSummary ?? "unknown"}`;
|
|
358
|
+
return `${targetPath} mode=${formatOctal(perms.bits)}`;
|
|
359
|
+
}
|
|
360
|
+
function formatPermissionRemediation(params) {
|
|
361
|
+
if (params.perms.source === "windows-acl") return formatIcaclsResetCommand(params.targetPath, {
|
|
362
|
+
isDir: params.isDir,
|
|
363
|
+
env: params.env
|
|
364
|
+
});
|
|
365
|
+
return `chmod ${params.posixMode.toString(8).padStart(3, "0")} ${params.targetPath}`;
|
|
366
|
+
}
|
|
367
|
+
function modeBits(mode) {
|
|
368
|
+
if (mode == null) return null;
|
|
369
|
+
return mode & 511;
|
|
370
|
+
}
|
|
371
|
+
function formatOctal(bits) {
|
|
372
|
+
if (bits == null) return "unknown";
|
|
373
|
+
return bits.toString(8).padStart(3, "0");
|
|
374
|
+
}
|
|
375
|
+
function isWorldWritable(bits) {
|
|
376
|
+
if (bits == null) return false;
|
|
377
|
+
return (bits & 2) !== 0;
|
|
378
|
+
}
|
|
379
|
+
function isGroupWritable(bits) {
|
|
380
|
+
if (bits == null) return false;
|
|
381
|
+
return (bits & 16) !== 0;
|
|
382
|
+
}
|
|
383
|
+
function isWorldReadable(bits) {
|
|
384
|
+
if (bits == null) return false;
|
|
385
|
+
return (bits & 4) !== 0;
|
|
386
|
+
}
|
|
387
|
+
function isGroupReadable(bits) {
|
|
388
|
+
if (bits == null) return false;
|
|
389
|
+
return (bits & 32) !== 0;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
//#endregion
|
|
393
|
+
//#region src/security/audit-extra.ts
|
|
394
|
+
const SMALL_MODEL_PARAM_B_MAX = 300;
|
|
395
|
+
function expandTilde(p, env) {
|
|
396
|
+
if (!p.startsWith("~")) return p;
|
|
397
|
+
const home = typeof env.HOME === "string" && env.HOME.trim() ? env.HOME.trim() : null;
|
|
398
|
+
if (!home) return null;
|
|
399
|
+
if (p === "~") return home;
|
|
400
|
+
if (p.startsWith("~/") || p.startsWith("~\\")) return path.join(home, p.slice(2));
|
|
401
|
+
return null;
|
|
402
|
+
}
|
|
403
|
+
function summarizeGroupPolicy(cfg) {
|
|
404
|
+
const channels = cfg.channels;
|
|
405
|
+
if (!channels || typeof channels !== "object") return {
|
|
406
|
+
open: 0,
|
|
407
|
+
allowlist: 0,
|
|
408
|
+
other: 0
|
|
409
|
+
};
|
|
410
|
+
let open = 0;
|
|
411
|
+
let allowlist = 0;
|
|
412
|
+
let other = 0;
|
|
413
|
+
for (const value of Object.values(channels)) {
|
|
414
|
+
if (!value || typeof value !== "object") continue;
|
|
415
|
+
const policy = value.groupPolicy;
|
|
416
|
+
if (policy === "open") open += 1;
|
|
417
|
+
else if (policy === "allowlist") allowlist += 1;
|
|
418
|
+
else other += 1;
|
|
419
|
+
}
|
|
420
|
+
return {
|
|
421
|
+
open,
|
|
422
|
+
allowlist,
|
|
423
|
+
other
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
function collectAttackSurfaceSummaryFindings(cfg) {
|
|
427
|
+
const group = summarizeGroupPolicy(cfg);
|
|
428
|
+
const elevated = cfg.tools?.elevated?.enabled !== false;
|
|
429
|
+
const hooksEnabled = cfg.hooks?.enabled === true;
|
|
430
|
+
const browserEnabled = cfg.browser?.enabled ?? true;
|
|
431
|
+
return [{
|
|
432
|
+
checkId: "summary.attack_surface",
|
|
433
|
+
severity: "info",
|
|
434
|
+
title: "Attack surface summary",
|
|
435
|
+
detail: `groups: open=${group.open}, allowlist=${group.allowlist}\ntools.elevated: ${elevated ? "enabled" : "disabled"}\nhooks: ${hooksEnabled ? "enabled" : "disabled"}\nbrowser control: ${browserEnabled ? "enabled" : "disabled"}`
|
|
436
|
+
}];
|
|
437
|
+
}
|
|
438
|
+
function isProbablySyncedPath(p) {
|
|
439
|
+
const s = p.toLowerCase();
|
|
440
|
+
return s.includes("icloud") || s.includes("dropbox") || s.includes("google drive") || s.includes("googledrive") || s.includes("onedrive");
|
|
441
|
+
}
|
|
442
|
+
function collectSyncedFolderFindings(params) {
|
|
443
|
+
const findings = [];
|
|
444
|
+
if (isProbablySyncedPath(params.stateDir) || isProbablySyncedPath(params.configPath)) findings.push({
|
|
445
|
+
checkId: "fs.synced_dir",
|
|
446
|
+
severity: "warn",
|
|
447
|
+
title: "State/config path looks like a synced folder",
|
|
448
|
+
detail: `stateDir=${params.stateDir}, configPath=${params.configPath}. Synced folders (iCloud/Dropbox/OneDrive/Google Drive) can leak tokens and transcripts onto other devices.`,
|
|
449
|
+
remediation: `Keep OPENCLAW_STATE_DIR on a local-only volume and re-run "${formatCliCommand("openclaw security audit --fix")}".`
|
|
450
|
+
});
|
|
451
|
+
return findings;
|
|
452
|
+
}
|
|
453
|
+
function looksLikeEnvRef(value) {
|
|
454
|
+
const v = value.trim();
|
|
455
|
+
return v.startsWith("${") && v.endsWith("}");
|
|
456
|
+
}
|
|
457
|
+
function collectSecretsInConfigFindings(cfg) {
|
|
458
|
+
const findings = [];
|
|
459
|
+
const password = typeof cfg.gateway?.auth?.password === "string" ? cfg.gateway.auth.password.trim() : "";
|
|
460
|
+
if (password && !looksLikeEnvRef(password)) findings.push({
|
|
461
|
+
checkId: "config.secrets.gateway_password_in_config",
|
|
462
|
+
severity: "warn",
|
|
463
|
+
title: "Gateway password is stored in config",
|
|
464
|
+
detail: "gateway.auth.password is set in the config file; prefer environment variables for secrets when possible.",
|
|
465
|
+
remediation: "Prefer OPENCLAW_GATEWAY_PASSWORD (env) and remove gateway.auth.password from disk."
|
|
466
|
+
});
|
|
467
|
+
const hooksToken = typeof cfg.hooks?.token === "string" ? cfg.hooks.token.trim() : "";
|
|
468
|
+
if (cfg.hooks?.enabled === true && hooksToken && !looksLikeEnvRef(hooksToken)) findings.push({
|
|
469
|
+
checkId: "config.secrets.hooks_token_in_config",
|
|
470
|
+
severity: "info",
|
|
471
|
+
title: "Hooks token is stored in config",
|
|
472
|
+
detail: "hooks.token is set in the config file; keep config perms tight and treat it like an API secret."
|
|
473
|
+
});
|
|
474
|
+
return findings;
|
|
475
|
+
}
|
|
476
|
+
function collectHooksHardeningFindings(cfg) {
|
|
477
|
+
const findings = [];
|
|
478
|
+
if (cfg.hooks?.enabled !== true) return findings;
|
|
479
|
+
const token = typeof cfg.hooks?.token === "string" ? cfg.hooks.token.trim() : "";
|
|
480
|
+
if (token && token.length < 24) findings.push({
|
|
481
|
+
checkId: "hooks.token_too_short",
|
|
482
|
+
severity: "warn",
|
|
483
|
+
title: "Hooks token looks short",
|
|
484
|
+
detail: `hooks.token is ${token.length} chars; prefer a long random token.`
|
|
485
|
+
});
|
|
486
|
+
const gatewayAuth = resolveGatewayAuth({
|
|
487
|
+
authConfig: cfg.gateway?.auth,
|
|
488
|
+
tailscaleMode: cfg.gateway?.tailscale?.mode ?? "off"
|
|
489
|
+
});
|
|
490
|
+
const gatewayToken = gatewayAuth.mode === "token" && typeof gatewayAuth.token === "string" && gatewayAuth.token.trim() ? gatewayAuth.token.trim() : null;
|
|
491
|
+
if (token && gatewayToken && token === gatewayToken) findings.push({
|
|
492
|
+
checkId: "hooks.token_reuse_gateway_token",
|
|
493
|
+
severity: "warn",
|
|
494
|
+
title: "Hooks token reuses the Gateway token",
|
|
495
|
+
detail: "hooks.token matches gateway.auth token; compromise of hooks expands blast radius to the Gateway API.",
|
|
496
|
+
remediation: "Use a separate hooks.token dedicated to hook ingress."
|
|
497
|
+
});
|
|
498
|
+
if ((typeof cfg.hooks?.path === "string" ? cfg.hooks.path.trim() : "") === "/") findings.push({
|
|
499
|
+
checkId: "hooks.path_root",
|
|
500
|
+
severity: "critical",
|
|
501
|
+
title: "Hooks base path is '/'",
|
|
502
|
+
detail: "hooks.path='/' would shadow other HTTP endpoints and is unsafe.",
|
|
503
|
+
remediation: "Use a dedicated path like '/hooks'."
|
|
504
|
+
});
|
|
505
|
+
return findings;
|
|
506
|
+
}
|
|
507
|
+
function addModel(models, raw, source) {
|
|
508
|
+
if (typeof raw !== "string") return;
|
|
509
|
+
const id = raw.trim();
|
|
510
|
+
if (!id) return;
|
|
511
|
+
models.push({
|
|
512
|
+
id,
|
|
513
|
+
source
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
function collectModels(cfg) {
|
|
517
|
+
const out = [];
|
|
518
|
+
addModel(out, cfg.agents?.defaults?.model?.primary, "agents.defaults.model.primary");
|
|
519
|
+
for (const f of cfg.agents?.defaults?.model?.fallbacks ?? []) addModel(out, f, "agents.defaults.model.fallbacks");
|
|
520
|
+
addModel(out, cfg.agents?.defaults?.imageModel?.primary, "agents.defaults.imageModel.primary");
|
|
521
|
+
for (const f of cfg.agents?.defaults?.imageModel?.fallbacks ?? []) addModel(out, f, "agents.defaults.imageModel.fallbacks");
|
|
522
|
+
const list = Array.isArray(cfg.agents?.list) ? cfg.agents?.list : [];
|
|
523
|
+
for (const agent of list ?? []) {
|
|
524
|
+
if (!agent || typeof agent !== "object") continue;
|
|
525
|
+
const id = typeof agent.id === "string" ? agent.id : "";
|
|
526
|
+
const model = agent.model;
|
|
527
|
+
if (typeof model === "string") addModel(out, model, `agents.list.${id}.model`);
|
|
528
|
+
else if (model && typeof model === "object") {
|
|
529
|
+
addModel(out, model.primary, `agents.list.${id}.model.primary`);
|
|
530
|
+
const fallbacks = model.fallbacks;
|
|
531
|
+
if (Array.isArray(fallbacks)) for (const f of fallbacks) addModel(out, f, `agents.list.${id}.model.fallbacks`);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
return out;
|
|
535
|
+
}
|
|
536
|
+
const LEGACY_MODEL_PATTERNS = [
|
|
537
|
+
{
|
|
538
|
+
id: "openai.gpt35",
|
|
539
|
+
re: /\bgpt-3\.5\b/i,
|
|
540
|
+
label: "GPT-3.5 family"
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
id: "anthropic.claude2",
|
|
544
|
+
re: /\bclaude-(instant|2)\b/i,
|
|
545
|
+
label: "Claude 2/Instant family"
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
id: "openai.gpt4_legacy",
|
|
549
|
+
re: /\bgpt-4-(0314|0613)\b/i,
|
|
550
|
+
label: "Legacy GPT-4 snapshots"
|
|
551
|
+
}
|
|
552
|
+
];
|
|
553
|
+
const WEAK_TIER_MODEL_PATTERNS = [{
|
|
554
|
+
id: "anthropic.haiku",
|
|
555
|
+
re: /\bhaiku\b/i,
|
|
556
|
+
label: "Haiku tier (smaller model)"
|
|
557
|
+
}];
|
|
558
|
+
function inferParamBFromIdOrName(text) {
|
|
559
|
+
const matches = text.toLowerCase().matchAll(/(?:^|[^a-z0-9])[a-z]?(\d+(?:\.\d+)?)b(?:[^a-z0-9]|$)/g);
|
|
560
|
+
let best = null;
|
|
561
|
+
for (const match of matches) {
|
|
562
|
+
const numRaw = match[1];
|
|
563
|
+
if (!numRaw) continue;
|
|
564
|
+
const value = Number(numRaw);
|
|
565
|
+
if (!Number.isFinite(value) || value <= 0) continue;
|
|
566
|
+
if (best === null || value > best) best = value;
|
|
567
|
+
}
|
|
568
|
+
return best;
|
|
569
|
+
}
|
|
570
|
+
function isGptModel(id) {
|
|
571
|
+
return /\bgpt-/i.test(id);
|
|
572
|
+
}
|
|
573
|
+
function isGpt5OrHigher(id) {
|
|
574
|
+
return /\bgpt-5(?:\b|[.-])/i.test(id);
|
|
575
|
+
}
|
|
576
|
+
function isClaudeModel(id) {
|
|
577
|
+
return /\bclaude-/i.test(id);
|
|
578
|
+
}
|
|
579
|
+
function isClaude45OrHigher(id) {
|
|
580
|
+
return /\bclaude-[^\s/]*?(?:-4-?5\b|4\.5\b)/i.test(id);
|
|
581
|
+
}
|
|
582
|
+
function collectModelHygieneFindings(cfg) {
|
|
583
|
+
const findings = [];
|
|
584
|
+
const models = collectModels(cfg);
|
|
585
|
+
if (models.length === 0) return findings;
|
|
586
|
+
const weakMatches = /* @__PURE__ */ new Map();
|
|
587
|
+
const addWeakMatch = (model, source, reason) => {
|
|
588
|
+
const key = `${model}@@${source}`;
|
|
589
|
+
const existing = weakMatches.get(key);
|
|
590
|
+
if (!existing) {
|
|
591
|
+
weakMatches.set(key, {
|
|
592
|
+
model,
|
|
593
|
+
source,
|
|
594
|
+
reasons: [reason]
|
|
595
|
+
});
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
if (!existing.reasons.includes(reason)) existing.reasons.push(reason);
|
|
599
|
+
};
|
|
600
|
+
for (const entry of models) {
|
|
601
|
+
for (const pat of WEAK_TIER_MODEL_PATTERNS) if (pat.re.test(entry.id)) {
|
|
602
|
+
addWeakMatch(entry.id, entry.source, pat.label);
|
|
603
|
+
break;
|
|
604
|
+
}
|
|
605
|
+
if (isGptModel(entry.id) && !isGpt5OrHigher(entry.id)) addWeakMatch(entry.id, entry.source, "Below GPT-5 family");
|
|
606
|
+
if (isClaudeModel(entry.id) && !isClaude45OrHigher(entry.id)) addWeakMatch(entry.id, entry.source, "Below Claude 4.5");
|
|
607
|
+
}
|
|
608
|
+
const matches = [];
|
|
609
|
+
for (const entry of models) for (const pat of LEGACY_MODEL_PATTERNS) if (pat.re.test(entry.id)) {
|
|
610
|
+
matches.push({
|
|
611
|
+
model: entry.id,
|
|
612
|
+
source: entry.source,
|
|
613
|
+
reason: pat.label
|
|
614
|
+
});
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
if (matches.length > 0) {
|
|
618
|
+
const lines = matches.slice(0, 12).map((m) => `- ${m.model} (${m.reason}) @ ${m.source}`).join("\n");
|
|
619
|
+
const more = matches.length > 12 ? `\n…${matches.length - 12} more` : "";
|
|
620
|
+
findings.push({
|
|
621
|
+
checkId: "models.legacy",
|
|
622
|
+
severity: "warn",
|
|
623
|
+
title: "Some configured models look legacy",
|
|
624
|
+
detail: "Older/legacy models can be less robust against prompt injection and tool misuse.\n" + lines + more,
|
|
625
|
+
remediation: "Prefer modern, instruction-hardened models for any bot that can run tools."
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
if (weakMatches.size > 0) {
|
|
629
|
+
const lines = Array.from(weakMatches.values()).slice(0, 12).map((m) => `- ${m.model} (${m.reasons.join("; ")}) @ ${m.source}`).join("\n");
|
|
630
|
+
const more = weakMatches.size > 12 ? `\n…${weakMatches.size - 12} more` : "";
|
|
631
|
+
findings.push({
|
|
632
|
+
checkId: "models.weak_tier",
|
|
633
|
+
severity: "warn",
|
|
634
|
+
title: "Some configured models are below recommended tiers",
|
|
635
|
+
detail: "Smaller/older models are generally more susceptible to prompt injection and tool misuse.\n" + lines + more,
|
|
636
|
+
remediation: "Use the latest, top-tier model for any bot with tools or untrusted inboxes. Avoid Haiku tiers; prefer GPT-5+ and Claude 4.5+."
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
return findings;
|
|
640
|
+
}
|
|
641
|
+
function extractAgentIdFromSource(source) {
|
|
642
|
+
return source.match(/^agents\.list\.([^.]*)\./)?.[1] ?? null;
|
|
643
|
+
}
|
|
644
|
+
function pickToolPolicy(config) {
|
|
645
|
+
if (!config) return null;
|
|
646
|
+
const allow = Array.isArray(config.allow) ? config.allow : void 0;
|
|
647
|
+
const deny = Array.isArray(config.deny) ? config.deny : void 0;
|
|
648
|
+
if (!allow && !deny) return null;
|
|
649
|
+
return {
|
|
650
|
+
allow,
|
|
651
|
+
deny
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
function resolveToolPolicies(params) {
|
|
655
|
+
const policies = [];
|
|
656
|
+
const profilePolicy = resolveToolProfilePolicy(params.agentTools?.profile ?? params.cfg.tools?.profile);
|
|
657
|
+
if (profilePolicy) policies.push(profilePolicy);
|
|
658
|
+
const globalPolicy = pickToolPolicy(params.cfg.tools ?? void 0);
|
|
659
|
+
if (globalPolicy) policies.push(globalPolicy);
|
|
660
|
+
const agentPolicy = pickToolPolicy(params.agentTools);
|
|
661
|
+
if (agentPolicy) policies.push(agentPolicy);
|
|
662
|
+
if (params.sandboxMode === "all") {
|
|
663
|
+
const sandboxPolicy = resolveSandboxToolPolicyForAgent(params.cfg, params.agentId ?? void 0);
|
|
664
|
+
policies.push(sandboxPolicy);
|
|
665
|
+
}
|
|
666
|
+
return policies;
|
|
667
|
+
}
|
|
668
|
+
function hasWebSearchKey(cfg, env) {
|
|
669
|
+
const search = cfg.tools?.web?.search;
|
|
670
|
+
return Boolean(search?.apiKey || search?.perplexity?.apiKey || env.BRAVE_API_KEY || env.PERPLEXITY_API_KEY || env.OPENROUTER_API_KEY);
|
|
671
|
+
}
|
|
672
|
+
function isWebSearchEnabled(cfg, env) {
|
|
673
|
+
const enabled = cfg.tools?.web?.search?.enabled;
|
|
674
|
+
if (enabled === false) return false;
|
|
675
|
+
if (enabled === true) return true;
|
|
676
|
+
return hasWebSearchKey(cfg, env);
|
|
677
|
+
}
|
|
678
|
+
function isWebFetchEnabled(cfg) {
|
|
679
|
+
if (cfg.tools?.web?.fetch?.enabled === false) return false;
|
|
680
|
+
return true;
|
|
681
|
+
}
|
|
682
|
+
function isBrowserEnabled(cfg) {
|
|
683
|
+
try {
|
|
684
|
+
return resolveBrowserConfig(cfg.browser, cfg).enabled;
|
|
685
|
+
} catch {
|
|
686
|
+
return true;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
function collectSmallModelRiskFindings(params) {
|
|
690
|
+
const findings = [];
|
|
691
|
+
const models = collectModels(params.cfg).filter((entry) => !entry.source.includes("imageModel"));
|
|
692
|
+
if (models.length === 0) return findings;
|
|
693
|
+
const smallModels = models.map((entry) => {
|
|
694
|
+
const paramB = inferParamBFromIdOrName(entry.id);
|
|
695
|
+
if (!paramB || paramB > SMALL_MODEL_PARAM_B_MAX) return null;
|
|
696
|
+
return {
|
|
697
|
+
...entry,
|
|
698
|
+
paramB
|
|
699
|
+
};
|
|
700
|
+
}).filter((entry) => Boolean(entry));
|
|
701
|
+
if (smallModels.length === 0) return findings;
|
|
702
|
+
let hasUnsafe = false;
|
|
703
|
+
const modelLines = [];
|
|
704
|
+
const exposureSet = /* @__PURE__ */ new Set();
|
|
705
|
+
for (const entry of smallModels) {
|
|
706
|
+
const agentId = extractAgentIdFromSource(entry.source);
|
|
707
|
+
const sandboxMode = resolveSandboxConfigForAgent(params.cfg, agentId ?? void 0).mode;
|
|
708
|
+
const agentTools = agentId && params.cfg.agents?.list ? params.cfg.agents.list.find((agent) => agent?.id === agentId)?.tools : void 0;
|
|
709
|
+
const policies = resolveToolPolicies({
|
|
710
|
+
cfg: params.cfg,
|
|
711
|
+
agentTools,
|
|
712
|
+
sandboxMode,
|
|
713
|
+
agentId
|
|
714
|
+
});
|
|
715
|
+
const exposed = [];
|
|
716
|
+
if (isWebSearchEnabled(params.cfg, params.env)) {
|
|
717
|
+
if (isToolAllowedByPolicies("web_search", policies)) exposed.push("web_search");
|
|
718
|
+
}
|
|
719
|
+
if (isWebFetchEnabled(params.cfg)) {
|
|
720
|
+
if (isToolAllowedByPolicies("web_fetch", policies)) exposed.push("web_fetch");
|
|
721
|
+
}
|
|
722
|
+
if (isBrowserEnabled(params.cfg)) {
|
|
723
|
+
if (isToolAllowedByPolicies("browser", policies)) exposed.push("browser");
|
|
724
|
+
}
|
|
725
|
+
for (const tool of exposed) exposureSet.add(tool);
|
|
726
|
+
const sandboxLabel = sandboxMode === "all" ? "sandbox=all" : `sandbox=${sandboxMode}`;
|
|
727
|
+
const exposureLabel = exposed.length > 0 ? ` web=[${exposed.join(", ")}]` : " web=[off]";
|
|
728
|
+
const safe = sandboxMode === "all" && exposed.length === 0;
|
|
729
|
+
if (!safe) hasUnsafe = true;
|
|
730
|
+
const statusLabel = safe ? "ok" : "unsafe";
|
|
731
|
+
modelLines.push(`- ${entry.id} (${entry.paramB}B) @ ${entry.source} (${statusLabel}; ${sandboxLabel};${exposureLabel})`);
|
|
732
|
+
}
|
|
733
|
+
const exposureList = Array.from(exposureSet);
|
|
734
|
+
const exposureDetail = exposureList.length > 0 ? `Uncontrolled input tools allowed: ${exposureList.join(", ")}.` : "No web/browser tools detected for these models.";
|
|
735
|
+
findings.push({
|
|
736
|
+
checkId: "models.small_params",
|
|
737
|
+
severity: hasUnsafe ? "critical" : "info",
|
|
738
|
+
title: "Small models require sandboxing and web tools disabled",
|
|
739
|
+
detail: `Small models (<=${SMALL_MODEL_PARAM_B_MAX}B params) detected:\n` + modelLines.join("\n") + `\n` + exposureDetail + "\nSmall models are not recommended for untrusted inputs.",
|
|
740
|
+
remediation: "If you must use small models, enable sandboxing for all sessions (agents.defaults.sandbox.mode=\"all\") and disable web_search/web_fetch/browser (tools.deny=[\"group:web\",\"browser\"])."
|
|
741
|
+
});
|
|
742
|
+
return findings;
|
|
743
|
+
}
|
|
744
|
+
async function collectPluginsTrustFindings(params) {
|
|
745
|
+
const findings = [];
|
|
746
|
+
const extensionsDir = path.join(params.stateDir, "extensions");
|
|
747
|
+
const st = await safeStat(extensionsDir);
|
|
748
|
+
if (!st.ok || !st.isDir) return findings;
|
|
749
|
+
const pluginDirs = (await fs.readdir(extensionsDir, { withFileTypes: true }).catch(() => [])).filter((e) => e.isDirectory()).map((e) => e.name).filter(Boolean);
|
|
750
|
+
if (pluginDirs.length === 0) return findings;
|
|
751
|
+
const allow = params.cfg.plugins?.allow;
|
|
752
|
+
if (!(Array.isArray(allow) && allow.length > 0)) {
|
|
753
|
+
const hasString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
754
|
+
const hasAccountStringKey = (account, key) => Boolean(account && typeof account === "object" && hasString(account[key]));
|
|
755
|
+
const discordConfigured = hasString(params.cfg.channels?.discord?.token) || Boolean(params.cfg.channels?.discord?.accounts && Object.values(params.cfg.channels.discord.accounts).some((a) => hasAccountStringKey(a, "token"))) || hasString(process.env.DISCORD_BOT_TOKEN);
|
|
756
|
+
const telegramConfigured = hasString(params.cfg.channels?.telegram?.botToken) || hasString(params.cfg.channels?.telegram?.tokenFile) || Boolean(params.cfg.channels?.telegram?.accounts && Object.values(params.cfg.channels.telegram.accounts).some((a) => hasAccountStringKey(a, "botToken") || hasAccountStringKey(a, "tokenFile"))) || hasString(process.env.TELEGRAM_BOT_TOKEN);
|
|
757
|
+
const slackConfigured = hasString(params.cfg.channels?.slack?.botToken) || hasString(params.cfg.channels?.slack?.appToken) || Boolean(params.cfg.channels?.slack?.accounts && Object.values(params.cfg.channels.slack.accounts).some((a) => hasAccountStringKey(a, "botToken") || hasAccountStringKey(a, "appToken"))) || hasString(process.env.SLACK_BOT_TOKEN) || hasString(process.env.SLACK_APP_TOKEN);
|
|
758
|
+
const skillCommandsLikelyExposed = discordConfigured && resolveNativeSkillsEnabled({
|
|
759
|
+
providerId: "discord",
|
|
760
|
+
providerSetting: params.cfg.channels?.discord?.commands?.nativeSkills,
|
|
761
|
+
globalSetting: params.cfg.commands?.nativeSkills
|
|
762
|
+
}) || telegramConfigured && resolveNativeSkillsEnabled({
|
|
763
|
+
providerId: "telegram",
|
|
764
|
+
providerSetting: params.cfg.channels?.telegram?.commands?.nativeSkills,
|
|
765
|
+
globalSetting: params.cfg.commands?.nativeSkills
|
|
766
|
+
}) || slackConfigured && resolveNativeSkillsEnabled({
|
|
767
|
+
providerId: "slack",
|
|
768
|
+
providerSetting: params.cfg.channels?.slack?.commands?.nativeSkills,
|
|
769
|
+
globalSetting: params.cfg.commands?.nativeSkills
|
|
770
|
+
});
|
|
771
|
+
findings.push({
|
|
772
|
+
checkId: "plugins.extensions_no_allowlist",
|
|
773
|
+
severity: skillCommandsLikelyExposed ? "critical" : "warn",
|
|
774
|
+
title: "Extensions exist but plugins.allow is not set",
|
|
775
|
+
detail: `Found ${pluginDirs.length} extension(s) under ${extensionsDir}. Without plugins.allow, any discovered plugin id may load (depending on config and plugin behavior).` + (skillCommandsLikelyExposed ? "\nNative skill commands are enabled on at least one configured chat surface; treat unpinned/unallowlisted extensions as high risk." : ""),
|
|
776
|
+
remediation: "Set plugins.allow to an explicit list of plugin ids you trust."
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
return findings;
|
|
780
|
+
}
|
|
781
|
+
function resolveIncludePath(baseConfigPath, includePath) {
|
|
782
|
+
return path.normalize(path.isAbsolute(includePath) ? includePath : path.resolve(path.dirname(baseConfigPath), includePath));
|
|
783
|
+
}
|
|
784
|
+
function listDirectIncludes(parsed) {
|
|
785
|
+
const out = [];
|
|
786
|
+
const visit = (value) => {
|
|
787
|
+
if (!value) return;
|
|
788
|
+
if (Array.isArray(value)) {
|
|
789
|
+
for (const item of value) visit(item);
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
if (typeof value !== "object") return;
|
|
793
|
+
const rec = value;
|
|
794
|
+
const includeVal = rec[INCLUDE_KEY];
|
|
795
|
+
if (typeof includeVal === "string") out.push(includeVal);
|
|
796
|
+
else if (Array.isArray(includeVal)) {
|
|
797
|
+
for (const item of includeVal) if (typeof item === "string") out.push(item);
|
|
798
|
+
}
|
|
799
|
+
for (const v of Object.values(rec)) visit(v);
|
|
800
|
+
};
|
|
801
|
+
visit(parsed);
|
|
802
|
+
return out;
|
|
803
|
+
}
|
|
804
|
+
async function collectIncludePathsRecursive(params) {
|
|
805
|
+
const visited = /* @__PURE__ */ new Set();
|
|
806
|
+
const result = [];
|
|
807
|
+
const walk = async (basePath, parsed, depth) => {
|
|
808
|
+
if (depth > MAX_INCLUDE_DEPTH) return;
|
|
809
|
+
for (const raw of listDirectIncludes(parsed)) {
|
|
810
|
+
const resolved = resolveIncludePath(basePath, raw);
|
|
811
|
+
if (visited.has(resolved)) continue;
|
|
812
|
+
visited.add(resolved);
|
|
813
|
+
result.push(resolved);
|
|
814
|
+
const rawText = await fs.readFile(resolved, "utf-8").catch(() => null);
|
|
815
|
+
if (!rawText) continue;
|
|
816
|
+
const nestedParsed = (() => {
|
|
817
|
+
try {
|
|
818
|
+
return JSON5.parse(rawText);
|
|
819
|
+
} catch {
|
|
820
|
+
return null;
|
|
821
|
+
}
|
|
822
|
+
})();
|
|
823
|
+
if (nestedParsed) await walk(resolved, nestedParsed, depth + 1);
|
|
824
|
+
}
|
|
825
|
+
};
|
|
826
|
+
await walk(params.configPath, params.parsed, 0);
|
|
827
|
+
return result;
|
|
828
|
+
}
|
|
829
|
+
async function collectIncludeFilePermFindings(params) {
|
|
830
|
+
const findings = [];
|
|
831
|
+
if (!params.configSnapshot.exists) return findings;
|
|
832
|
+
const configPath = params.configSnapshot.path;
|
|
833
|
+
const includePaths = await collectIncludePathsRecursive({
|
|
834
|
+
configPath,
|
|
835
|
+
parsed: params.configSnapshot.parsed
|
|
836
|
+
});
|
|
837
|
+
if (includePaths.length === 0) return findings;
|
|
838
|
+
for (const p of includePaths) {
|
|
839
|
+
const perms = await inspectPathPermissions(p, {
|
|
840
|
+
env: params.env,
|
|
841
|
+
platform: params.platform,
|
|
842
|
+
exec: params.execIcacls
|
|
843
|
+
});
|
|
844
|
+
if (!perms.ok) continue;
|
|
845
|
+
if (perms.worldWritable || perms.groupWritable) findings.push({
|
|
846
|
+
checkId: "fs.config_include.perms_writable",
|
|
847
|
+
severity: "critical",
|
|
848
|
+
title: "Config include file is writable by others",
|
|
849
|
+
detail: `${formatPermissionDetail(p, perms)}; another user could influence your effective config.`,
|
|
850
|
+
remediation: formatPermissionRemediation({
|
|
851
|
+
targetPath: p,
|
|
852
|
+
perms,
|
|
853
|
+
isDir: false,
|
|
854
|
+
posixMode: 384,
|
|
855
|
+
env: params.env
|
|
856
|
+
})
|
|
857
|
+
});
|
|
858
|
+
else if (perms.worldReadable) findings.push({
|
|
859
|
+
checkId: "fs.config_include.perms_world_readable",
|
|
860
|
+
severity: "critical",
|
|
861
|
+
title: "Config include file is world-readable",
|
|
862
|
+
detail: `${formatPermissionDetail(p, perms)}; include files can contain tokens and private settings.`,
|
|
863
|
+
remediation: formatPermissionRemediation({
|
|
864
|
+
targetPath: p,
|
|
865
|
+
perms,
|
|
866
|
+
isDir: false,
|
|
867
|
+
posixMode: 384,
|
|
868
|
+
env: params.env
|
|
869
|
+
})
|
|
870
|
+
});
|
|
871
|
+
else if (perms.groupReadable) findings.push({
|
|
872
|
+
checkId: "fs.config_include.perms_group_readable",
|
|
873
|
+
severity: "warn",
|
|
874
|
+
title: "Config include file is group-readable",
|
|
875
|
+
detail: `${formatPermissionDetail(p, perms)}; include files can contain tokens and private settings.`,
|
|
876
|
+
remediation: formatPermissionRemediation({
|
|
877
|
+
targetPath: p,
|
|
878
|
+
perms,
|
|
879
|
+
isDir: false,
|
|
880
|
+
posixMode: 384,
|
|
881
|
+
env: params.env
|
|
882
|
+
})
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
return findings;
|
|
886
|
+
}
|
|
887
|
+
async function collectStateDeepFilesystemFindings(params) {
|
|
888
|
+
const findings = [];
|
|
889
|
+
const oauthDir = resolveOAuthDir(params.env, params.stateDir);
|
|
890
|
+
const oauthPerms = await inspectPathPermissions(oauthDir, {
|
|
891
|
+
env: params.env,
|
|
892
|
+
platform: params.platform,
|
|
893
|
+
exec: params.execIcacls
|
|
894
|
+
});
|
|
895
|
+
if (oauthPerms.ok && oauthPerms.isDir) {
|
|
896
|
+
if (oauthPerms.worldWritable || oauthPerms.groupWritable) findings.push({
|
|
897
|
+
checkId: "fs.credentials_dir.perms_writable",
|
|
898
|
+
severity: "critical",
|
|
899
|
+
title: "Credentials dir is writable by others",
|
|
900
|
+
detail: `${formatPermissionDetail(oauthDir, oauthPerms)}; another user could drop/modify credential files.`,
|
|
901
|
+
remediation: formatPermissionRemediation({
|
|
902
|
+
targetPath: oauthDir,
|
|
903
|
+
perms: oauthPerms,
|
|
904
|
+
isDir: true,
|
|
905
|
+
posixMode: 448,
|
|
906
|
+
env: params.env
|
|
907
|
+
})
|
|
908
|
+
});
|
|
909
|
+
else if (oauthPerms.groupReadable || oauthPerms.worldReadable) findings.push({
|
|
910
|
+
checkId: "fs.credentials_dir.perms_readable",
|
|
911
|
+
severity: "warn",
|
|
912
|
+
title: "Credentials dir is readable by others",
|
|
913
|
+
detail: `${formatPermissionDetail(oauthDir, oauthPerms)}; credentials and allowlists can be sensitive.`,
|
|
914
|
+
remediation: formatPermissionRemediation({
|
|
915
|
+
targetPath: oauthDir,
|
|
916
|
+
perms: oauthPerms,
|
|
917
|
+
isDir: true,
|
|
918
|
+
posixMode: 448,
|
|
919
|
+
env: params.env
|
|
920
|
+
})
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
const agentIds = Array.isArray(params.cfg.agents?.list) ? params.cfg.agents?.list.map((a) => a && typeof a === "object" && typeof a.id === "string" ? a.id.trim() : "").filter(Boolean) : [];
|
|
924
|
+
const defaultAgentId = resolveDefaultAgentId(params.cfg);
|
|
925
|
+
const ids = Array.from(new Set([defaultAgentId, ...agentIds])).map((id) => normalizeAgentId(id));
|
|
926
|
+
for (const agentId of ids) {
|
|
927
|
+
const agentDir = path.join(params.stateDir, "agents", agentId, "agent");
|
|
928
|
+
const authPath = path.join(agentDir, "auth-profiles.json");
|
|
929
|
+
const authPerms = await inspectPathPermissions(authPath, {
|
|
930
|
+
env: params.env,
|
|
931
|
+
platform: params.platform,
|
|
932
|
+
exec: params.execIcacls
|
|
933
|
+
});
|
|
934
|
+
if (authPerms.ok) {
|
|
935
|
+
if (authPerms.worldWritable || authPerms.groupWritable) findings.push({
|
|
936
|
+
checkId: "fs.auth_profiles.perms_writable",
|
|
937
|
+
severity: "critical",
|
|
938
|
+
title: "auth-profiles.json is writable by others",
|
|
939
|
+
detail: `${formatPermissionDetail(authPath, authPerms)}; another user could inject credentials.`,
|
|
940
|
+
remediation: formatPermissionRemediation({
|
|
941
|
+
targetPath: authPath,
|
|
942
|
+
perms: authPerms,
|
|
943
|
+
isDir: false,
|
|
944
|
+
posixMode: 384,
|
|
945
|
+
env: params.env
|
|
946
|
+
})
|
|
947
|
+
});
|
|
948
|
+
else if (authPerms.worldReadable || authPerms.groupReadable) findings.push({
|
|
949
|
+
checkId: "fs.auth_profiles.perms_readable",
|
|
950
|
+
severity: "warn",
|
|
951
|
+
title: "auth-profiles.json is readable by others",
|
|
952
|
+
detail: `${formatPermissionDetail(authPath, authPerms)}; auth-profiles.json contains API keys and OAuth tokens.`,
|
|
953
|
+
remediation: formatPermissionRemediation({
|
|
954
|
+
targetPath: authPath,
|
|
955
|
+
perms: authPerms,
|
|
956
|
+
isDir: false,
|
|
957
|
+
posixMode: 384,
|
|
958
|
+
env: params.env
|
|
959
|
+
})
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
const storePath = path.join(params.stateDir, "agents", agentId, "sessions", "sessions.json");
|
|
963
|
+
const storePerms = await inspectPathPermissions(storePath, {
|
|
964
|
+
env: params.env,
|
|
965
|
+
platform: params.platform,
|
|
966
|
+
exec: params.execIcacls
|
|
967
|
+
});
|
|
968
|
+
if (storePerms.ok) {
|
|
969
|
+
if (storePerms.worldReadable || storePerms.groupReadable) findings.push({
|
|
970
|
+
checkId: "fs.sessions_store.perms_readable",
|
|
971
|
+
severity: "warn",
|
|
972
|
+
title: "sessions.json is readable by others",
|
|
973
|
+
detail: `${formatPermissionDetail(storePath, storePerms)}; routing and transcript metadata can be sensitive.`,
|
|
974
|
+
remediation: formatPermissionRemediation({
|
|
975
|
+
targetPath: storePath,
|
|
976
|
+
perms: storePerms,
|
|
977
|
+
isDir: false,
|
|
978
|
+
posixMode: 384,
|
|
979
|
+
env: params.env
|
|
980
|
+
})
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
const logFile = typeof params.cfg.logging?.file === "string" ? params.cfg.logging.file.trim() : "";
|
|
985
|
+
if (logFile) {
|
|
986
|
+
const expanded = logFile.startsWith("~") ? expandTilde(logFile, params.env) : logFile;
|
|
987
|
+
if (expanded) {
|
|
988
|
+
const logPath = path.resolve(expanded);
|
|
989
|
+
const logPerms = await inspectPathPermissions(logPath, {
|
|
990
|
+
env: params.env,
|
|
991
|
+
platform: params.platform,
|
|
992
|
+
exec: params.execIcacls
|
|
993
|
+
});
|
|
994
|
+
if (logPerms.ok) {
|
|
995
|
+
if (logPerms.worldReadable || logPerms.groupReadable) findings.push({
|
|
996
|
+
checkId: "fs.log_file.perms_readable",
|
|
997
|
+
severity: "warn",
|
|
998
|
+
title: "Log file is readable by others",
|
|
999
|
+
detail: `${formatPermissionDetail(logPath, logPerms)}; logs can contain private messages and tool output.`,
|
|
1000
|
+
remediation: formatPermissionRemediation({
|
|
1001
|
+
targetPath: logPath,
|
|
1002
|
+
perms: logPerms,
|
|
1003
|
+
isDir: false,
|
|
1004
|
+
posixMode: 384,
|
|
1005
|
+
env: params.env
|
|
1006
|
+
})
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
return findings;
|
|
1012
|
+
}
|
|
1013
|
+
function listGroupPolicyOpen(cfg) {
|
|
1014
|
+
const out = [];
|
|
1015
|
+
const channels = cfg.channels;
|
|
1016
|
+
if (!channels || typeof channels !== "object") return out;
|
|
1017
|
+
for (const [channelId, value] of Object.entries(channels)) {
|
|
1018
|
+
if (!value || typeof value !== "object") continue;
|
|
1019
|
+
const section = value;
|
|
1020
|
+
if (section.groupPolicy === "open") out.push(`channels.${channelId}.groupPolicy`);
|
|
1021
|
+
const accounts = section.accounts;
|
|
1022
|
+
if (accounts && typeof accounts === "object") for (const [accountId, accountVal] of Object.entries(accounts)) {
|
|
1023
|
+
if (!accountVal || typeof accountVal !== "object") continue;
|
|
1024
|
+
if (accountVal.groupPolicy === "open") out.push(`channels.${channelId}.accounts.${accountId}.groupPolicy`);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
return out;
|
|
1028
|
+
}
|
|
1029
|
+
function collectExposureMatrixFindings(cfg) {
|
|
1030
|
+
const findings = [];
|
|
1031
|
+
const openGroups = listGroupPolicyOpen(cfg);
|
|
1032
|
+
if (openGroups.length === 0) return findings;
|
|
1033
|
+
if (cfg.tools?.elevated?.enabled !== false) findings.push({
|
|
1034
|
+
checkId: "security.exposure.open_groups_with_elevated",
|
|
1035
|
+
severity: "critical",
|
|
1036
|
+
title: "Open groupPolicy with elevated tools enabled",
|
|
1037
|
+
detail: `Found groupPolicy="open" at:\n${openGroups.map((p) => `- ${p}`).join("\n")}\nWith tools.elevated enabled, a prompt injection in those rooms can become a high-impact incident.`,
|
|
1038
|
+
remediation: `Set groupPolicy="allowlist" and keep elevated allowlists extremely tight.`
|
|
1039
|
+
});
|
|
1040
|
+
return findings;
|
|
1041
|
+
}
|
|
1042
|
+
async function readConfigSnapshotForAudit(params) {
|
|
1043
|
+
return await createConfigIO({
|
|
1044
|
+
env: params.env,
|
|
1045
|
+
configPath: params.configPath
|
|
1046
|
+
}).readConfigFileSnapshot();
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
//#endregion
|
|
1050
|
+
//#region src/security/audit.ts
|
|
1051
|
+
function countBySeverity(findings) {
|
|
1052
|
+
let critical = 0;
|
|
1053
|
+
let warn = 0;
|
|
1054
|
+
let info = 0;
|
|
1055
|
+
for (const f of findings) if (f.severity === "critical") critical += 1;
|
|
1056
|
+
else if (f.severity === "warn") warn += 1;
|
|
1057
|
+
else info += 1;
|
|
1058
|
+
return {
|
|
1059
|
+
critical,
|
|
1060
|
+
warn,
|
|
1061
|
+
info
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
function normalizeAllowFromList(list) {
|
|
1065
|
+
if (!Array.isArray(list)) return [];
|
|
1066
|
+
return list.map((v) => String(v).trim()).filter(Boolean);
|
|
1067
|
+
}
|
|
1068
|
+
function classifyChannelWarningSeverity(message) {
|
|
1069
|
+
const s = message.toLowerCase();
|
|
1070
|
+
if (s.includes("dms: open") || s.includes("grouppolicy=\"open\"") || s.includes("dmpolicy=\"open\"")) return "critical";
|
|
1071
|
+
if (s.includes("allows any") || s.includes("anyone can dm") || s.includes("public")) return "critical";
|
|
1072
|
+
if (s.includes("locked") || s.includes("disabled")) return "info";
|
|
1073
|
+
return "warn";
|
|
1074
|
+
}
|
|
1075
|
+
async function collectFilesystemFindings(params) {
|
|
1076
|
+
const findings = [];
|
|
1077
|
+
const stateDirPerms = await inspectPathPermissions(params.stateDir, {
|
|
1078
|
+
env: params.env,
|
|
1079
|
+
platform: params.platform,
|
|
1080
|
+
exec: params.execIcacls
|
|
1081
|
+
});
|
|
1082
|
+
if (stateDirPerms.ok) {
|
|
1083
|
+
if (stateDirPerms.isSymlink) findings.push({
|
|
1084
|
+
checkId: "fs.state_dir.symlink",
|
|
1085
|
+
severity: "warn",
|
|
1086
|
+
title: "State dir is a symlink",
|
|
1087
|
+
detail: `${params.stateDir} is a symlink; treat this as an extra trust boundary.`
|
|
1088
|
+
});
|
|
1089
|
+
if (stateDirPerms.worldWritable) findings.push({
|
|
1090
|
+
checkId: "fs.state_dir.perms_world_writable",
|
|
1091
|
+
severity: "critical",
|
|
1092
|
+
title: "State dir is world-writable",
|
|
1093
|
+
detail: `${formatPermissionDetail(params.stateDir, stateDirPerms)}; other users can write into your OpenClaw state.`,
|
|
1094
|
+
remediation: formatPermissionRemediation({
|
|
1095
|
+
targetPath: params.stateDir,
|
|
1096
|
+
perms: stateDirPerms,
|
|
1097
|
+
isDir: true,
|
|
1098
|
+
posixMode: 448,
|
|
1099
|
+
env: params.env
|
|
1100
|
+
})
|
|
1101
|
+
});
|
|
1102
|
+
else if (stateDirPerms.groupWritable) findings.push({
|
|
1103
|
+
checkId: "fs.state_dir.perms_group_writable",
|
|
1104
|
+
severity: "warn",
|
|
1105
|
+
title: "State dir is group-writable",
|
|
1106
|
+
detail: `${formatPermissionDetail(params.stateDir, stateDirPerms)}; group users can write into your OpenClaw state.`,
|
|
1107
|
+
remediation: formatPermissionRemediation({
|
|
1108
|
+
targetPath: params.stateDir,
|
|
1109
|
+
perms: stateDirPerms,
|
|
1110
|
+
isDir: true,
|
|
1111
|
+
posixMode: 448,
|
|
1112
|
+
env: params.env
|
|
1113
|
+
})
|
|
1114
|
+
});
|
|
1115
|
+
else if (stateDirPerms.groupReadable || stateDirPerms.worldReadable) findings.push({
|
|
1116
|
+
checkId: "fs.state_dir.perms_readable",
|
|
1117
|
+
severity: "warn",
|
|
1118
|
+
title: "State dir is readable by others",
|
|
1119
|
+
detail: `${formatPermissionDetail(params.stateDir, stateDirPerms)}; consider restricting to 700.`,
|
|
1120
|
+
remediation: formatPermissionRemediation({
|
|
1121
|
+
targetPath: params.stateDir,
|
|
1122
|
+
perms: stateDirPerms,
|
|
1123
|
+
isDir: true,
|
|
1124
|
+
posixMode: 448,
|
|
1125
|
+
env: params.env
|
|
1126
|
+
})
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
const configPerms = await inspectPathPermissions(params.configPath, {
|
|
1130
|
+
env: params.env,
|
|
1131
|
+
platform: params.platform,
|
|
1132
|
+
exec: params.execIcacls
|
|
1133
|
+
});
|
|
1134
|
+
if (configPerms.ok) {
|
|
1135
|
+
if (configPerms.isSymlink) findings.push({
|
|
1136
|
+
checkId: "fs.config.symlink",
|
|
1137
|
+
severity: "warn",
|
|
1138
|
+
title: "Config file is a symlink",
|
|
1139
|
+
detail: `${params.configPath} is a symlink; make sure you trust its target.`
|
|
1140
|
+
});
|
|
1141
|
+
if (configPerms.worldWritable || configPerms.groupWritable) findings.push({
|
|
1142
|
+
checkId: "fs.config.perms_writable",
|
|
1143
|
+
severity: "critical",
|
|
1144
|
+
title: "Config file is writable by others",
|
|
1145
|
+
detail: `${formatPermissionDetail(params.configPath, configPerms)}; another user could change gateway/auth/tool policies.`,
|
|
1146
|
+
remediation: formatPermissionRemediation({
|
|
1147
|
+
targetPath: params.configPath,
|
|
1148
|
+
perms: configPerms,
|
|
1149
|
+
isDir: false,
|
|
1150
|
+
posixMode: 384,
|
|
1151
|
+
env: params.env
|
|
1152
|
+
})
|
|
1153
|
+
});
|
|
1154
|
+
else if (configPerms.worldReadable) findings.push({
|
|
1155
|
+
checkId: "fs.config.perms_world_readable",
|
|
1156
|
+
severity: "critical",
|
|
1157
|
+
title: "Config file is world-readable",
|
|
1158
|
+
detail: `${formatPermissionDetail(params.configPath, configPerms)}; config can contain tokens and private settings.`,
|
|
1159
|
+
remediation: formatPermissionRemediation({
|
|
1160
|
+
targetPath: params.configPath,
|
|
1161
|
+
perms: configPerms,
|
|
1162
|
+
isDir: false,
|
|
1163
|
+
posixMode: 384,
|
|
1164
|
+
env: params.env
|
|
1165
|
+
})
|
|
1166
|
+
});
|
|
1167
|
+
else if (configPerms.groupReadable) findings.push({
|
|
1168
|
+
checkId: "fs.config.perms_group_readable",
|
|
1169
|
+
severity: "warn",
|
|
1170
|
+
title: "Config file is group-readable",
|
|
1171
|
+
detail: `${formatPermissionDetail(params.configPath, configPerms)}; config can contain tokens and private settings.`,
|
|
1172
|
+
remediation: formatPermissionRemediation({
|
|
1173
|
+
targetPath: params.configPath,
|
|
1174
|
+
perms: configPerms,
|
|
1175
|
+
isDir: false,
|
|
1176
|
+
posixMode: 384,
|
|
1177
|
+
env: params.env
|
|
1178
|
+
})
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
return findings;
|
|
1182
|
+
}
|
|
1183
|
+
function collectGatewayConfigFindings(cfg, env) {
|
|
1184
|
+
const findings = [];
|
|
1185
|
+
const bind = typeof cfg.gateway?.bind === "string" ? cfg.gateway.bind : "loopback";
|
|
1186
|
+
const tailscaleMode = cfg.gateway?.tailscale?.mode ?? "off";
|
|
1187
|
+
const auth = resolveGatewayAuth({
|
|
1188
|
+
authConfig: cfg.gateway?.auth,
|
|
1189
|
+
tailscaleMode,
|
|
1190
|
+
env
|
|
1191
|
+
});
|
|
1192
|
+
const controlUiEnabled = cfg.gateway?.controlUi?.enabled !== false;
|
|
1193
|
+
const trustedProxies = Array.isArray(cfg.gateway?.trustedProxies) ? cfg.gateway.trustedProxies : [];
|
|
1194
|
+
const hasToken = typeof auth.token === "string" && auth.token.trim().length > 0;
|
|
1195
|
+
const hasPassword = typeof auth.password === "string" && auth.password.trim().length > 0;
|
|
1196
|
+
const hasSharedSecret = auth.mode === "token" && hasToken || auth.mode === "password" && hasPassword;
|
|
1197
|
+
const hasTailscaleAuth = auth.allowTailscale && tailscaleMode === "serve";
|
|
1198
|
+
const hasGatewayAuth = hasSharedSecret || hasTailscaleAuth;
|
|
1199
|
+
if (bind !== "loopback" && !hasSharedSecret) findings.push({
|
|
1200
|
+
checkId: "gateway.bind_no_auth",
|
|
1201
|
+
severity: "critical",
|
|
1202
|
+
title: "Gateway binds beyond loopback without auth",
|
|
1203
|
+
detail: `gateway.bind="${bind}" but no gateway.auth token/password is configured.`,
|
|
1204
|
+
remediation: `Set gateway.auth (token recommended) or bind to loopback.`
|
|
1205
|
+
});
|
|
1206
|
+
if (bind === "loopback" && controlUiEnabled && trustedProxies.length === 0) findings.push({
|
|
1207
|
+
checkId: "gateway.trusted_proxies_missing",
|
|
1208
|
+
severity: "warn",
|
|
1209
|
+
title: "Reverse proxy headers are not trusted",
|
|
1210
|
+
detail: "gateway.bind is loopback and gateway.trustedProxies is empty. If you expose the Control UI through a reverse proxy, configure trusted proxies so local-client checks cannot be spoofed.",
|
|
1211
|
+
remediation: "Set gateway.trustedProxies to your proxy IPs or keep the Control UI local-only."
|
|
1212
|
+
});
|
|
1213
|
+
if (bind === "loopback" && controlUiEnabled && !hasGatewayAuth) findings.push({
|
|
1214
|
+
checkId: "gateway.loopback_no_auth",
|
|
1215
|
+
severity: "critical",
|
|
1216
|
+
title: "Gateway auth missing on loopback",
|
|
1217
|
+
detail: "gateway.bind is loopback but no gateway auth secret is configured. If the Control UI is exposed through a reverse proxy, unauthenticated access is possible.",
|
|
1218
|
+
remediation: "Set gateway.auth (token recommended) or keep the Control UI local-only."
|
|
1219
|
+
});
|
|
1220
|
+
if (tailscaleMode === "funnel") findings.push({
|
|
1221
|
+
checkId: "gateway.tailscale_funnel",
|
|
1222
|
+
severity: "critical",
|
|
1223
|
+
title: "Tailscale Funnel exposure enabled",
|
|
1224
|
+
detail: `gateway.tailscale.mode="funnel" exposes the Gateway publicly; keep auth strict and treat it as internet-facing.`,
|
|
1225
|
+
remediation: `Prefer tailscale.mode="serve" (tailnet-only) or set tailscale.mode="off".`
|
|
1226
|
+
});
|
|
1227
|
+
else if (tailscaleMode === "serve") findings.push({
|
|
1228
|
+
checkId: "gateway.tailscale_serve",
|
|
1229
|
+
severity: "info",
|
|
1230
|
+
title: "Tailscale Serve exposure enabled",
|
|
1231
|
+
detail: `gateway.tailscale.mode="serve" exposes the Gateway to your tailnet (loopback behind Tailscale).`
|
|
1232
|
+
});
|
|
1233
|
+
if (cfg.gateway?.controlUi?.allowInsecureAuth === true) findings.push({
|
|
1234
|
+
checkId: "gateway.control_ui.insecure_auth",
|
|
1235
|
+
severity: "critical",
|
|
1236
|
+
title: "Control UI allows insecure HTTP auth",
|
|
1237
|
+
detail: "gateway.controlUi.allowInsecureAuth=true allows token-only auth over HTTP and skips device identity.",
|
|
1238
|
+
remediation: "Disable it or switch to HTTPS (Tailscale Serve) or localhost."
|
|
1239
|
+
});
|
|
1240
|
+
if (cfg.gateway?.controlUi?.dangerouslyDisableDeviceAuth === true) findings.push({
|
|
1241
|
+
checkId: "gateway.control_ui.device_auth_disabled",
|
|
1242
|
+
severity: "critical",
|
|
1243
|
+
title: "DANGEROUS: Control UI device auth disabled",
|
|
1244
|
+
detail: "gateway.controlUi.dangerouslyDisableDeviceAuth=true disables device identity checks for the Control UI.",
|
|
1245
|
+
remediation: "Disable it unless you are in a short-lived break-glass scenario."
|
|
1246
|
+
});
|
|
1247
|
+
const token = typeof auth.token === "string" && auth.token.trim().length > 0 ? auth.token.trim() : null;
|
|
1248
|
+
if (auth.mode === "token" && token && token.length < 24) findings.push({
|
|
1249
|
+
checkId: "gateway.token_too_short",
|
|
1250
|
+
severity: "warn",
|
|
1251
|
+
title: "Gateway token looks short",
|
|
1252
|
+
detail: `gateway auth token is ${token.length} chars; prefer a long random token.`
|
|
1253
|
+
});
|
|
1254
|
+
return findings;
|
|
1255
|
+
}
|
|
1256
|
+
function collectBrowserControlFindings(cfg) {
|
|
1257
|
+
const findings = [];
|
|
1258
|
+
let resolved;
|
|
1259
|
+
try {
|
|
1260
|
+
resolved = resolveBrowserConfig(cfg.browser, cfg);
|
|
1261
|
+
} catch (err) {
|
|
1262
|
+
findings.push({
|
|
1263
|
+
checkId: "browser.control_invalid_config",
|
|
1264
|
+
severity: "warn",
|
|
1265
|
+
title: "Browser control config looks invalid",
|
|
1266
|
+
detail: String(err),
|
|
1267
|
+
remediation: `Fix browser.cdpUrl in ${resolveConfigPath()} and re-run "${formatCliCommand("openclaw security audit --deep")}".`
|
|
1268
|
+
});
|
|
1269
|
+
return findings;
|
|
1270
|
+
}
|
|
1271
|
+
if (!resolved.enabled) return findings;
|
|
1272
|
+
for (const name of Object.keys(resolved.profiles)) {
|
|
1273
|
+
const profile = resolveProfile(resolved, name);
|
|
1274
|
+
if (!profile || profile.cdpIsLoopback) continue;
|
|
1275
|
+
let url;
|
|
1276
|
+
try {
|
|
1277
|
+
url = new URL(profile.cdpUrl);
|
|
1278
|
+
} catch {
|
|
1279
|
+
continue;
|
|
1280
|
+
}
|
|
1281
|
+
if (url.protocol === "http:") findings.push({
|
|
1282
|
+
checkId: "browser.remote_cdp_http",
|
|
1283
|
+
severity: "warn",
|
|
1284
|
+
title: "Remote CDP uses HTTP",
|
|
1285
|
+
detail: `browser profile "${name}" uses http CDP (${profile.cdpUrl}); this is OK only if it's tailnet-only or behind an encrypted tunnel.`,
|
|
1286
|
+
remediation: `Prefer HTTPS/TLS or a tailnet-only endpoint for remote CDP.`
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1289
|
+
return findings;
|
|
1290
|
+
}
|
|
1291
|
+
function collectLoggingFindings(cfg) {
|
|
1292
|
+
if (cfg.logging?.redactSensitive !== "off") return [];
|
|
1293
|
+
return [{
|
|
1294
|
+
checkId: "logging.redact_off",
|
|
1295
|
+
severity: "warn",
|
|
1296
|
+
title: "Tool summary redaction is disabled",
|
|
1297
|
+
detail: `logging.redactSensitive="off" can leak secrets into logs and status output.`,
|
|
1298
|
+
remediation: `Set logging.redactSensitive="tools".`
|
|
1299
|
+
}];
|
|
1300
|
+
}
|
|
1301
|
+
function collectElevatedFindings(cfg) {
|
|
1302
|
+
const findings = [];
|
|
1303
|
+
const enabled = cfg.tools?.elevated?.enabled;
|
|
1304
|
+
const allowFrom = cfg.tools?.elevated?.allowFrom ?? {};
|
|
1305
|
+
const anyAllowFromKeys = Object.keys(allowFrom).length > 0;
|
|
1306
|
+
if (enabled === false) return findings;
|
|
1307
|
+
if (!anyAllowFromKeys) return findings;
|
|
1308
|
+
for (const [provider, list] of Object.entries(allowFrom)) {
|
|
1309
|
+
const normalized = normalizeAllowFromList(list);
|
|
1310
|
+
if (normalized.includes("*")) findings.push({
|
|
1311
|
+
checkId: `tools.elevated.allowFrom.${provider}.wildcard`,
|
|
1312
|
+
severity: "critical",
|
|
1313
|
+
title: "Elevated exec allowlist contains wildcard",
|
|
1314
|
+
detail: `tools.elevated.allowFrom.${provider} includes "*" which effectively approves everyone on that channel for elevated mode.`
|
|
1315
|
+
});
|
|
1316
|
+
else if (normalized.length > 25) findings.push({
|
|
1317
|
+
checkId: `tools.elevated.allowFrom.${provider}.large`,
|
|
1318
|
+
severity: "warn",
|
|
1319
|
+
title: "Elevated exec allowlist is large",
|
|
1320
|
+
detail: `tools.elevated.allowFrom.${provider} has ${normalized.length} entries; consider tightening elevated access.`
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
return findings;
|
|
1324
|
+
}
|
|
1325
|
+
async function collectChannelSecurityFindings(params) {
|
|
1326
|
+
const findings = [];
|
|
1327
|
+
const coerceNativeSetting = (value) => {
|
|
1328
|
+
if (value === true) return true;
|
|
1329
|
+
if (value === false) return false;
|
|
1330
|
+
if (value === "auto") return "auto";
|
|
1331
|
+
};
|
|
1332
|
+
const warnDmPolicy = async (input) => {
|
|
1333
|
+
const policyPath = input.policyPath ?? `${input.allowFromPath}policy`;
|
|
1334
|
+
const configAllowFrom = normalizeAllowFromList(input.allowFrom);
|
|
1335
|
+
const hasWildcard = configAllowFrom.includes("*");
|
|
1336
|
+
const dmScope = params.cfg.session?.dmScope ?? "main";
|
|
1337
|
+
const storeAllowFrom = await readChannelAllowFromStore(input.provider).catch(() => []);
|
|
1338
|
+
const normalizeEntry = input.normalizeEntry ?? ((value) => value);
|
|
1339
|
+
const normalizedCfg = configAllowFrom.filter((value) => value !== "*").map((value) => normalizeEntry(value)).map((value) => value.trim()).filter(Boolean);
|
|
1340
|
+
const normalizedStore = storeAllowFrom.map((value) => normalizeEntry(value)).map((value) => value.trim()).filter(Boolean);
|
|
1341
|
+
const allowCount = Array.from(new Set([...normalizedCfg, ...normalizedStore])).length;
|
|
1342
|
+
const isMultiUserDm = hasWildcard || allowCount > 1;
|
|
1343
|
+
if (input.dmPolicy === "open") {
|
|
1344
|
+
const allowFromKey = `${input.allowFromPath}allowFrom`;
|
|
1345
|
+
findings.push({
|
|
1346
|
+
checkId: `channels.${input.provider}.dm.open`,
|
|
1347
|
+
severity: "critical",
|
|
1348
|
+
title: `${input.label} DMs are open`,
|
|
1349
|
+
detail: `${policyPath}="open" allows anyone to DM the bot.`,
|
|
1350
|
+
remediation: `Use pairing/allowlist; if you really need open DMs, ensure ${allowFromKey} includes "*".`
|
|
1351
|
+
});
|
|
1352
|
+
if (!hasWildcard) findings.push({
|
|
1353
|
+
checkId: `channels.${input.provider}.dm.open_invalid`,
|
|
1354
|
+
severity: "warn",
|
|
1355
|
+
title: `${input.label} DM config looks inconsistent`,
|
|
1356
|
+
detail: `"open" requires ${allowFromKey} to include "*".`
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
if (input.dmPolicy === "disabled") {
|
|
1360
|
+
findings.push({
|
|
1361
|
+
checkId: `channels.${input.provider}.dm.disabled`,
|
|
1362
|
+
severity: "info",
|
|
1363
|
+
title: `${input.label} DMs are disabled`,
|
|
1364
|
+
detail: `${policyPath}="disabled" ignores inbound DMs.`
|
|
1365
|
+
});
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1368
|
+
if (dmScope === "main" && isMultiUserDm) findings.push({
|
|
1369
|
+
checkId: `channels.${input.provider}.dm.scope_main_multiuser`,
|
|
1370
|
+
severity: "warn",
|
|
1371
|
+
title: `${input.label} DMs share the main session`,
|
|
1372
|
+
detail: "Multiple DM senders currently share the main session, which can leak context across users.",
|
|
1373
|
+
remediation: "Set session.dmScope=\"per-channel-peer\" (or \"per-account-channel-peer\" for multi-account channels) to isolate DM sessions per sender."
|
|
1374
|
+
});
|
|
1375
|
+
};
|
|
1376
|
+
for (const plugin of params.plugins) {
|
|
1377
|
+
if (!plugin.security) continue;
|
|
1378
|
+
const accountIds = plugin.config.listAccountIds(params.cfg);
|
|
1379
|
+
const defaultAccountId = resolveChannelDefaultAccountId({
|
|
1380
|
+
plugin,
|
|
1381
|
+
cfg: params.cfg,
|
|
1382
|
+
accountIds
|
|
1383
|
+
});
|
|
1384
|
+
const account = plugin.config.resolveAccount(params.cfg, defaultAccountId);
|
|
1385
|
+
if (!(plugin.config.isEnabled ? plugin.config.isEnabled(account, params.cfg) : true)) continue;
|
|
1386
|
+
if (!(plugin.config.isConfigured ? await plugin.config.isConfigured(account, params.cfg) : true)) continue;
|
|
1387
|
+
if (plugin.id === "discord") {
|
|
1388
|
+
const discordCfg = account?.config ?? {};
|
|
1389
|
+
const nativeEnabled = resolveNativeCommandsEnabled({
|
|
1390
|
+
providerId: "discord",
|
|
1391
|
+
providerSetting: coerceNativeSetting(discordCfg.commands?.native),
|
|
1392
|
+
globalSetting: params.cfg.commands?.native
|
|
1393
|
+
});
|
|
1394
|
+
const nativeSkillsEnabled = resolveNativeSkillsEnabled({
|
|
1395
|
+
providerId: "discord",
|
|
1396
|
+
providerSetting: coerceNativeSetting(discordCfg.commands?.nativeSkills),
|
|
1397
|
+
globalSetting: params.cfg.commands?.nativeSkills
|
|
1398
|
+
});
|
|
1399
|
+
if (nativeEnabled || nativeSkillsEnabled) {
|
|
1400
|
+
const defaultGroupPolicy = params.cfg.channels?.defaults?.groupPolicy;
|
|
1401
|
+
const groupPolicy = discordCfg.groupPolicy ?? defaultGroupPolicy ?? "allowlist";
|
|
1402
|
+
const guildEntries = discordCfg.guilds ?? {};
|
|
1403
|
+
const guildsConfigured = Object.keys(guildEntries).length > 0;
|
|
1404
|
+
const hasAnyUserAllowlist = Object.values(guildEntries).some((guild) => {
|
|
1405
|
+
if (!guild || typeof guild !== "object") return false;
|
|
1406
|
+
const g = guild;
|
|
1407
|
+
if (Array.isArray(g.users) && g.users.length > 0) return true;
|
|
1408
|
+
const channels = g.channels;
|
|
1409
|
+
if (!channels || typeof channels !== "object") return false;
|
|
1410
|
+
return Object.values(channels).some((channel) => {
|
|
1411
|
+
if (!channel || typeof channel !== "object") return false;
|
|
1412
|
+
const c = channel;
|
|
1413
|
+
return Array.isArray(c.users) && c.users.length > 0;
|
|
1414
|
+
});
|
|
1415
|
+
});
|
|
1416
|
+
const dmAllowFromRaw = discordCfg.dm?.allowFrom;
|
|
1417
|
+
const dmAllowFrom = Array.isArray(dmAllowFromRaw) ? dmAllowFromRaw : [];
|
|
1418
|
+
const storeAllowFrom = await readChannelAllowFromStore("discord").catch(() => []);
|
|
1419
|
+
const ownerAllowFromConfigured = normalizeAllowFromList([...dmAllowFrom, ...storeAllowFrom]).length > 0;
|
|
1420
|
+
const useAccessGroups = params.cfg.commands?.useAccessGroups !== false;
|
|
1421
|
+
if (!useAccessGroups && groupPolicy !== "disabled" && guildsConfigured && !hasAnyUserAllowlist) findings.push({
|
|
1422
|
+
checkId: "channels.discord.commands.native.unrestricted",
|
|
1423
|
+
severity: "critical",
|
|
1424
|
+
title: "Discord slash commands are unrestricted",
|
|
1425
|
+
detail: "commands.useAccessGroups=false disables sender allowlists for Discord slash commands unless a per-guild/channel users allowlist is configured; with no users allowlist, any user in allowed guild channels can invoke /… commands.",
|
|
1426
|
+
remediation: "Set commands.useAccessGroups=true (recommended), or configure channels.discord.guilds.<id>.users (or channels.discord.guilds.<id>.channels.<channel>.users)."
|
|
1427
|
+
});
|
|
1428
|
+
else if (useAccessGroups && groupPolicy !== "disabled" && guildsConfigured && !ownerAllowFromConfigured && !hasAnyUserAllowlist) findings.push({
|
|
1429
|
+
checkId: "channels.discord.commands.native.no_allowlists",
|
|
1430
|
+
severity: "warn",
|
|
1431
|
+
title: "Discord slash commands have no allowlists",
|
|
1432
|
+
detail: "Discord slash commands are enabled, but neither an owner allowFrom list nor any per-guild/channel users allowlist is configured; /… commands will be rejected for everyone.",
|
|
1433
|
+
remediation: "Add your user id to channels.discord.dm.allowFrom (or approve yourself via pairing), or configure channels.discord.guilds.<id>.users."
|
|
1434
|
+
});
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
if (plugin.id === "slack") {
|
|
1438
|
+
const slackCfg = account?.config ?? {};
|
|
1439
|
+
const nativeEnabled = resolveNativeCommandsEnabled({
|
|
1440
|
+
providerId: "slack",
|
|
1441
|
+
providerSetting: coerceNativeSetting(slackCfg.commands?.native),
|
|
1442
|
+
globalSetting: params.cfg.commands?.native
|
|
1443
|
+
});
|
|
1444
|
+
const nativeSkillsEnabled = resolveNativeSkillsEnabled({
|
|
1445
|
+
providerId: "slack",
|
|
1446
|
+
providerSetting: coerceNativeSetting(slackCfg.commands?.nativeSkills),
|
|
1447
|
+
globalSetting: params.cfg.commands?.nativeSkills
|
|
1448
|
+
});
|
|
1449
|
+
if (nativeEnabled || nativeSkillsEnabled || slackCfg.slashCommand?.enabled === true) if (!(params.cfg.commands?.useAccessGroups !== false)) findings.push({
|
|
1450
|
+
checkId: "channels.slack.commands.slash.useAccessGroups_off",
|
|
1451
|
+
severity: "critical",
|
|
1452
|
+
title: "Slack slash commands bypass access groups",
|
|
1453
|
+
detail: "Slack slash/native commands are enabled while commands.useAccessGroups=false; this can allow unrestricted /… command execution from channels/users you didn't explicitly authorize.",
|
|
1454
|
+
remediation: "Set commands.useAccessGroups=true (recommended)."
|
|
1455
|
+
});
|
|
1456
|
+
else {
|
|
1457
|
+
const dmAllowFromRaw = account?.dm?.allowFrom;
|
|
1458
|
+
const dmAllowFrom = Array.isArray(dmAllowFromRaw) ? dmAllowFromRaw : [];
|
|
1459
|
+
const storeAllowFrom = await readChannelAllowFromStore("slack").catch(() => []);
|
|
1460
|
+
const ownerAllowFromConfigured = normalizeAllowFromList([...dmAllowFrom, ...storeAllowFrom]).length > 0;
|
|
1461
|
+
const channels = slackCfg.channels ?? {};
|
|
1462
|
+
const hasAnyChannelUsersAllowlist = Object.values(channels).some((value) => {
|
|
1463
|
+
if (!value || typeof value !== "object") return false;
|
|
1464
|
+
const channel = value;
|
|
1465
|
+
return Array.isArray(channel.users) && channel.users.length > 0;
|
|
1466
|
+
});
|
|
1467
|
+
if (!ownerAllowFromConfigured && !hasAnyChannelUsersAllowlist) findings.push({
|
|
1468
|
+
checkId: "channels.slack.commands.slash.no_allowlists",
|
|
1469
|
+
severity: "warn",
|
|
1470
|
+
title: "Slack slash commands have no allowlists",
|
|
1471
|
+
detail: "Slack slash/native commands are enabled, but neither an owner allowFrom list nor any channels.<id>.users allowlist is configured; /… commands will be rejected for everyone.",
|
|
1472
|
+
remediation: "Approve yourself via pairing (recommended), or set channels.slack.dm.allowFrom and/or channels.slack.channels.<id>.users."
|
|
1473
|
+
});
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
const dmPolicy = plugin.security.resolveDmPolicy?.({
|
|
1477
|
+
cfg: params.cfg,
|
|
1478
|
+
accountId: defaultAccountId,
|
|
1479
|
+
account
|
|
1480
|
+
});
|
|
1481
|
+
if (dmPolicy) await warnDmPolicy({
|
|
1482
|
+
label: plugin.meta.label ?? plugin.id,
|
|
1483
|
+
provider: plugin.id,
|
|
1484
|
+
dmPolicy: dmPolicy.policy,
|
|
1485
|
+
allowFrom: dmPolicy.allowFrom,
|
|
1486
|
+
policyPath: dmPolicy.policyPath,
|
|
1487
|
+
allowFromPath: dmPolicy.allowFromPath,
|
|
1488
|
+
normalizeEntry: dmPolicy.normalizeEntry
|
|
1489
|
+
});
|
|
1490
|
+
if (plugin.security.collectWarnings) {
|
|
1491
|
+
const warnings = await plugin.security.collectWarnings({
|
|
1492
|
+
cfg: params.cfg,
|
|
1493
|
+
accountId: defaultAccountId,
|
|
1494
|
+
account
|
|
1495
|
+
});
|
|
1496
|
+
for (const message of warnings ?? []) {
|
|
1497
|
+
const trimmed = String(message).trim();
|
|
1498
|
+
if (!trimmed) continue;
|
|
1499
|
+
findings.push({
|
|
1500
|
+
checkId: `channels.${plugin.id}.warning.${findings.length + 1}`,
|
|
1501
|
+
severity: classifyChannelWarningSeverity(trimmed),
|
|
1502
|
+
title: `${plugin.meta.label ?? plugin.id} security warning`,
|
|
1503
|
+
detail: trimmed.replace(/^-\s*/, "")
|
|
1504
|
+
});
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
if (plugin.id === "telegram") {
|
|
1508
|
+
if (!(params.cfg.commands?.text !== false)) continue;
|
|
1509
|
+
const telegramCfg = account?.config ?? {};
|
|
1510
|
+
const defaultGroupPolicy = params.cfg.channels?.defaults?.groupPolicy;
|
|
1511
|
+
const groupPolicy = telegramCfg.groupPolicy ?? defaultGroupPolicy ?? "allowlist";
|
|
1512
|
+
const groups = telegramCfg.groups;
|
|
1513
|
+
const groupsConfigured = Boolean(groups) && Object.keys(groups ?? {}).length > 0;
|
|
1514
|
+
if (!(groupPolicy === "open" || groupPolicy === "allowlist" && groupsConfigured)) continue;
|
|
1515
|
+
const storeAllowFrom = await readChannelAllowFromStore("telegram").catch(() => []);
|
|
1516
|
+
const storeHasWildcard = storeAllowFrom.some((v) => String(v).trim() === "*");
|
|
1517
|
+
const groupAllowFrom = Array.isArray(telegramCfg.groupAllowFrom) ? telegramCfg.groupAllowFrom : [];
|
|
1518
|
+
const groupAllowFromHasWildcard = groupAllowFrom.some((v) => String(v).trim() === "*");
|
|
1519
|
+
const anyGroupOverride = Boolean(groups && Object.values(groups).some((value) => {
|
|
1520
|
+
if (!value || typeof value !== "object") return false;
|
|
1521
|
+
const group = value;
|
|
1522
|
+
if ((Array.isArray(group.allowFrom) ? group.allowFrom : []).length > 0) return true;
|
|
1523
|
+
const topics = group.topics;
|
|
1524
|
+
if (!topics || typeof topics !== "object") return false;
|
|
1525
|
+
return Object.values(topics).some((topicValue) => {
|
|
1526
|
+
if (!topicValue || typeof topicValue !== "object") return false;
|
|
1527
|
+
const topic = topicValue;
|
|
1528
|
+
return (Array.isArray(topic.allowFrom) ? topic.allowFrom : []).length > 0;
|
|
1529
|
+
});
|
|
1530
|
+
}));
|
|
1531
|
+
const hasAnySenderAllowlist = storeAllowFrom.length > 0 || groupAllowFrom.length > 0 || anyGroupOverride;
|
|
1532
|
+
if (storeHasWildcard || groupAllowFromHasWildcard) {
|
|
1533
|
+
findings.push({
|
|
1534
|
+
checkId: "channels.telegram.groups.allowFrom.wildcard",
|
|
1535
|
+
severity: "critical",
|
|
1536
|
+
title: "Telegram group allowlist contains wildcard",
|
|
1537
|
+
detail: "Telegram group sender allowlist contains \"*\", which allows any group member to run /… commands and control directives.",
|
|
1538
|
+
remediation: "Remove \"*\" from channels.telegram.groupAllowFrom and pairing store; prefer explicit user ids/usernames."
|
|
1539
|
+
});
|
|
1540
|
+
continue;
|
|
1541
|
+
}
|
|
1542
|
+
if (!hasAnySenderAllowlist) {
|
|
1543
|
+
const providerSetting = telegramCfg.commands?.nativeSkills;
|
|
1544
|
+
const skillsEnabled = resolveNativeSkillsEnabled({
|
|
1545
|
+
providerId: "telegram",
|
|
1546
|
+
providerSetting,
|
|
1547
|
+
globalSetting: params.cfg.commands?.nativeSkills
|
|
1548
|
+
});
|
|
1549
|
+
findings.push({
|
|
1550
|
+
checkId: "channels.telegram.groups.allowFrom.missing",
|
|
1551
|
+
severity: "critical",
|
|
1552
|
+
title: "Telegram group commands have no sender allowlist",
|
|
1553
|
+
detail: `Telegram group access is enabled but no sender allowlist is configured; this allows any group member to invoke /… commands` + (skillsEnabled ? " (including skill commands)." : "."),
|
|
1554
|
+
remediation: "Approve yourself via pairing (recommended), or set channels.telegram.groupAllowFrom (or per-group groups.<id>.allowFrom)."
|
|
1555
|
+
});
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
return findings;
|
|
1560
|
+
}
|
|
1561
|
+
async function maybeProbeGateway(params) {
|
|
1562
|
+
const url = buildGatewayConnectionDetails({ config: params.cfg }).url;
|
|
1563
|
+
const isRemoteMode = params.cfg.gateway?.mode === "remote";
|
|
1564
|
+
const remoteUrlRaw = typeof params.cfg.gateway?.remote?.url === "string" ? params.cfg.gateway.remote.url.trim() : "";
|
|
1565
|
+
const remoteUrlMissing = isRemoteMode && !remoteUrlRaw;
|
|
1566
|
+
const resolveAuth = (mode) => {
|
|
1567
|
+
const authToken = params.cfg.gateway?.auth?.token;
|
|
1568
|
+
const authPassword = params.cfg.gateway?.auth?.password;
|
|
1569
|
+
const remote = params.cfg.gateway?.remote;
|
|
1570
|
+
return {
|
|
1571
|
+
token: mode === "remote" ? typeof remote?.token === "string" && remote.token.trim() ? remote.token.trim() : void 0 : process.env.OPENCLAW_GATEWAY_TOKEN?.trim() || (typeof authToken === "string" && authToken.trim() ? authToken.trim() : void 0),
|
|
1572
|
+
password: process.env.OPENCLAW_GATEWAY_PASSWORD?.trim() || (mode === "remote" ? typeof remote?.password === "string" && remote.password.trim() ? remote.password.trim() : void 0 : typeof authPassword === "string" && authPassword.trim() ? authPassword.trim() : void 0)
|
|
1573
|
+
};
|
|
1574
|
+
};
|
|
1575
|
+
const auth = !isRemoteMode || remoteUrlMissing ? resolveAuth("local") : resolveAuth("remote");
|
|
1576
|
+
const res = await params.probe({
|
|
1577
|
+
url,
|
|
1578
|
+
auth,
|
|
1579
|
+
timeoutMs: params.timeoutMs
|
|
1580
|
+
}).catch((err) => ({
|
|
1581
|
+
ok: false,
|
|
1582
|
+
url,
|
|
1583
|
+
connectLatencyMs: null,
|
|
1584
|
+
error: String(err),
|
|
1585
|
+
close: null,
|
|
1586
|
+
health: null,
|
|
1587
|
+
status: null,
|
|
1588
|
+
presence: null,
|
|
1589
|
+
configSnapshot: null
|
|
1590
|
+
}));
|
|
1591
|
+
return { gateway: {
|
|
1592
|
+
attempted: true,
|
|
1593
|
+
url,
|
|
1594
|
+
ok: res.ok,
|
|
1595
|
+
error: res.ok ? null : res.error,
|
|
1596
|
+
close: res.close ? {
|
|
1597
|
+
code: res.close.code,
|
|
1598
|
+
reason: res.close.reason
|
|
1599
|
+
} : null
|
|
1600
|
+
} };
|
|
1601
|
+
}
|
|
1602
|
+
async function runSecurityAudit(opts) {
|
|
1603
|
+
const findings = [];
|
|
1604
|
+
const cfg = opts.config;
|
|
1605
|
+
const env = opts.env ?? process.env;
|
|
1606
|
+
const platform = opts.platform ?? process.platform;
|
|
1607
|
+
const execIcacls = opts.execIcacls;
|
|
1608
|
+
const stateDir = opts.stateDir ?? resolveStateDir(env);
|
|
1609
|
+
const configPath = opts.configPath ?? resolveConfigPath(env, stateDir);
|
|
1610
|
+
findings.push(...collectAttackSurfaceSummaryFindings(cfg));
|
|
1611
|
+
findings.push(...collectSyncedFolderFindings({
|
|
1612
|
+
stateDir,
|
|
1613
|
+
configPath
|
|
1614
|
+
}));
|
|
1615
|
+
findings.push(...collectGatewayConfigFindings(cfg, env));
|
|
1616
|
+
findings.push(...collectBrowserControlFindings(cfg));
|
|
1617
|
+
findings.push(...collectLoggingFindings(cfg));
|
|
1618
|
+
findings.push(...collectElevatedFindings(cfg));
|
|
1619
|
+
findings.push(...collectHooksHardeningFindings(cfg));
|
|
1620
|
+
findings.push(...collectSecretsInConfigFindings(cfg));
|
|
1621
|
+
findings.push(...collectModelHygieneFindings(cfg));
|
|
1622
|
+
findings.push(...collectSmallModelRiskFindings({
|
|
1623
|
+
cfg,
|
|
1624
|
+
env
|
|
1625
|
+
}));
|
|
1626
|
+
findings.push(...collectExposureMatrixFindings(cfg));
|
|
1627
|
+
const configSnapshot = opts.includeFilesystem !== false ? await readConfigSnapshotForAudit({
|
|
1628
|
+
env,
|
|
1629
|
+
configPath
|
|
1630
|
+
}).catch(() => null) : null;
|
|
1631
|
+
if (opts.includeFilesystem !== false) {
|
|
1632
|
+
findings.push(...await collectFilesystemFindings({
|
|
1633
|
+
stateDir,
|
|
1634
|
+
configPath,
|
|
1635
|
+
env,
|
|
1636
|
+
platform,
|
|
1637
|
+
execIcacls
|
|
1638
|
+
}));
|
|
1639
|
+
if (configSnapshot) findings.push(...await collectIncludeFilePermFindings({
|
|
1640
|
+
configSnapshot,
|
|
1641
|
+
env,
|
|
1642
|
+
platform,
|
|
1643
|
+
execIcacls
|
|
1644
|
+
}));
|
|
1645
|
+
findings.push(...await collectStateDeepFilesystemFindings({
|
|
1646
|
+
cfg,
|
|
1647
|
+
env,
|
|
1648
|
+
stateDir,
|
|
1649
|
+
platform,
|
|
1650
|
+
execIcacls
|
|
1651
|
+
}));
|
|
1652
|
+
findings.push(...await collectPluginsTrustFindings({
|
|
1653
|
+
cfg,
|
|
1654
|
+
stateDir
|
|
1655
|
+
}));
|
|
1656
|
+
}
|
|
1657
|
+
if (opts.includeChannelSecurity !== false) {
|
|
1658
|
+
const plugins = opts.plugins ?? listChannelPlugins();
|
|
1659
|
+
findings.push(...await collectChannelSecurityFindings({
|
|
1660
|
+
cfg,
|
|
1661
|
+
plugins
|
|
1662
|
+
}));
|
|
1663
|
+
}
|
|
1664
|
+
const deep = opts.deep === true ? await maybeProbeGateway({
|
|
1665
|
+
cfg,
|
|
1666
|
+
timeoutMs: Math.max(250, opts.deepTimeoutMs ?? 5e3),
|
|
1667
|
+
probe: opts.probeGatewayFn ?? probeGateway
|
|
1668
|
+
}) : void 0;
|
|
1669
|
+
if (deep?.gateway?.attempted && !deep.gateway.ok) findings.push({
|
|
1670
|
+
checkId: "gateway.probe_failed",
|
|
1671
|
+
severity: "warn",
|
|
1672
|
+
title: "Gateway probe failed (deep)",
|
|
1673
|
+
detail: deep.gateway.error ?? "gateway unreachable",
|
|
1674
|
+
remediation: `Run "${formatCliCommand("openclaw status --all")}" to debug connectivity/auth, then re-run "${formatCliCommand("openclaw security audit --deep")}".`
|
|
1675
|
+
});
|
|
1676
|
+
const summary = countBySeverity(findings);
|
|
1677
|
+
return {
|
|
1678
|
+
ts: Date.now(),
|
|
1679
|
+
summary,
|
|
1680
|
+
findings,
|
|
1681
|
+
deep
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
//#endregion
|
|
1686
|
+
export { probeGateway as i, createIcaclsResetCommand as n, formatIcaclsResetCommand as r, runSecurityAudit as t };
|