clawdbot 2026.1.4-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +120 -0
- package/LICENSE +21 -0
- package/README-header.png +0 -0
- package/README.md +297 -0
- package/dist/agents/agent-paths.js +17 -0
- package/dist/agents/bash-process-registry.js +126 -0
- package/dist/agents/bash-tools.js +837 -0
- package/dist/agents/clawdbot-tools.js +30 -0
- package/dist/agents/clawdis-tools.js +27 -0
- package/dist/agents/context.js +34 -0
- package/dist/agents/defaults.js +6 -0
- package/dist/agents/model-auth.js +112 -0
- package/dist/agents/model-catalog.js +55 -0
- package/dist/agents/model-fallback.js +191 -0
- package/dist/agents/model-scan.js +263 -0
- package/dist/agents/model-selection.js +116 -0
- package/dist/agents/models-config.js +49 -0
- package/dist/agents/pi-embedded-helpers.js +74 -0
- package/dist/agents/pi-embedded-runner.js +407 -0
- package/dist/agents/pi-embedded-subscribe.js +568 -0
- package/dist/agents/pi-embedded-utils.js +20 -0
- package/dist/agents/pi-embedded.js +1 -0
- package/dist/agents/pi-oauth.js +88 -0
- package/dist/agents/pi-tools.js +433 -0
- package/dist/agents/sandbox-paths.js +68 -0
- package/dist/agents/sandbox.js +644 -0
- package/dist/agents/shell-utils.js +53 -0
- package/dist/agents/skills-install.js +244 -0
- package/dist/agents/skills-status.js +157 -0
- package/dist/agents/skills.js +470 -0
- package/dist/agents/steerable-agent-loop.js +338 -0
- package/dist/agents/steerable-provider-transport.js +48 -0
- package/dist/agents/system-prompt.js +104 -0
- package/dist/agents/tool-display.js +162 -0
- package/dist/agents/tool-images.js +138 -0
- package/dist/agents/tools/browser-tool.js +339 -0
- package/dist/agents/tools/canvas-tool.js +193 -0
- package/dist/agents/tools/common.js +88 -0
- package/dist/agents/tools/cron-tool.js +124 -0
- package/dist/agents/tools/discord-actions-guild.js +186 -0
- package/dist/agents/tools/discord-actions-messaging.js +285 -0
- package/dist/agents/tools/discord-actions-moderation.js +70 -0
- package/dist/agents/tools/discord-actions.js +56 -0
- package/dist/agents/tools/discord-schema.js +199 -0
- package/dist/agents/tools/discord-tool.js +16 -0
- package/dist/agents/tools/gateway-tool.js +46 -0
- package/dist/agents/tools/gateway.js +27 -0
- package/dist/agents/tools/image-tool.js +132 -0
- package/dist/agents/tools/nodes-tool.js +413 -0
- package/dist/agents/tools/nodes-utils.js +92 -0
- package/dist/agents/tools/sessions-helpers.js +88 -0
- package/dist/agents/tools/sessions-history-tool.js +53 -0
- package/dist/agents/tools/sessions-list-tool.js +143 -0
- package/dist/agents/tools/sessions-send-helpers.js +100 -0
- package/dist/agents/tools/sessions-send-tool.js +347 -0
- package/dist/agents/tools/slack-actions.js +129 -0
- package/dist/agents/tools/slack-schema.js +59 -0
- package/dist/agents/tools/slack-tool.js +16 -0
- package/dist/agents/usage.js +39 -0
- package/dist/agents/workspace.js +241 -0
- package/dist/auto-reply/chunk.js +76 -0
- package/dist/auto-reply/envelope.js +38 -0
- package/dist/auto-reply/group-activation.js +20 -0
- package/dist/auto-reply/heartbeat.js +57 -0
- package/dist/auto-reply/model.js +14 -0
- package/dist/auto-reply/reply/abort.js +14 -0
- package/dist/auto-reply/reply/agent-runner.js +371 -0
- package/dist/auto-reply/reply/block-streaming.js +34 -0
- package/dist/auto-reply/reply/body.js +29 -0
- package/dist/auto-reply/reply/commands.js +207 -0
- package/dist/auto-reply/reply/directive-handling.js +361 -0
- package/dist/auto-reply/reply/directives.js +47 -0
- package/dist/auto-reply/reply/followup-runner.js +149 -0
- package/dist/auto-reply/reply/groups.js +91 -0
- package/dist/auto-reply/reply/mentions.js +38 -0
- package/dist/auto-reply/reply/model-selection.js +114 -0
- package/dist/auto-reply/reply/queue.js +399 -0
- package/dist/auto-reply/reply/reply-tags.js +26 -0
- package/dist/auto-reply/reply/session-updates.js +87 -0
- package/dist/auto-reply/reply/session.js +160 -0
- package/dist/auto-reply/reply/typing.js +75 -0
- package/dist/auto-reply/reply.js +535 -0
- package/dist/auto-reply/send-policy.js +28 -0
- package/dist/auto-reply/status.js +158 -0
- package/dist/auto-reply/templating.js +9 -0
- package/dist/auto-reply/thinking.js +49 -0
- package/dist/auto-reply/tokens.js +2 -0
- package/dist/auto-reply/tool-meta.js +74 -0
- package/dist/auto-reply/transcription.js +57 -0
- package/dist/auto-reply/types.js +1 -0
- package/dist/browser/bridge-server.js +37 -0
- package/dist/browser/cdp.js +382 -0
- package/dist/browser/chrome.js +432 -0
- package/dist/browser/client-actions-core.js +67 -0
- package/dist/browser/client-actions-observe.js +24 -0
- package/dist/browser/client-actions-types.js +1 -0
- package/dist/browser/client-actions.js +3 -0
- package/dist/browser/client-fetch.js +43 -0
- package/dist/browser/client.js +105 -0
- package/dist/browser/config.js +140 -0
- package/dist/browser/constants.js +4 -0
- package/dist/browser/profiles-service.js +122 -0
- package/dist/browser/profiles.js +85 -0
- package/dist/browser/pw-ai.js +2 -0
- package/dist/browser/pw-session.js +144 -0
- package/dist/browser/pw-tools-core.js +363 -0
- package/dist/browser/routes/agent.js +535 -0
- package/dist/browser/routes/basic.js +155 -0
- package/dist/browser/routes/index.js +8 -0
- package/dist/browser/routes/tabs.js +105 -0
- package/dist/browser/routes/utils.js +62 -0
- package/dist/browser/screenshot.js +40 -0
- package/dist/browser/server-context.js +377 -0
- package/dist/browser/server.js +81 -0
- package/dist/browser/target-id.js +18 -0
- package/dist/browser/trash.js +21 -0
- package/dist/canvas-host/a2ui/.bundle.hash +1 -0
- package/dist/canvas-host/a2ui/a2ui.bundle.js +17768 -0
- package/dist/canvas-host/a2ui/index.html +246 -0
- package/dist/canvas-host/a2ui.js +187 -0
- package/dist/canvas-host/server.js +382 -0
- package/dist/cli/browser-cli-actions-input.js +459 -0
- package/dist/cli/browser-cli-actions-observe.js +56 -0
- package/dist/cli/browser-cli-examples.js +31 -0
- package/dist/cli/browser-cli-inspect.js +97 -0
- package/dist/cli/browser-cli-manage.js +286 -0
- package/dist/cli/browser-cli-shared.js +1 -0
- package/dist/cli/browser-cli.js +26 -0
- package/dist/cli/canvas-cli.js +416 -0
- package/dist/cli/cron-cli.js +454 -0
- package/dist/cli/deps.js +17 -0
- package/dist/cli/dns-cli.js +180 -0
- package/dist/cli/gateway-cli.js +489 -0
- package/dist/cli/gateway-rpc.js +20 -0
- package/dist/cli/hooks-cli.js +135 -0
- package/dist/cli/models-cli.js +248 -0
- package/dist/cli/nodes-camera.js +57 -0
- package/dist/cli/nodes-canvas.js +26 -0
- package/dist/cli/nodes-cli.js +946 -0
- package/dist/cli/nodes-screen.js +37 -0
- package/dist/cli/parse-duration.js +20 -0
- package/dist/cli/ports.js +97 -0
- package/dist/cli/program.js +406 -0
- package/dist/cli/prompt.js +19 -0
- package/dist/cli/tui-cli.js +35 -0
- package/dist/cli/wait.js +8 -0
- package/dist/commands/agent.js +645 -0
- package/dist/commands/antigravity-oauth.js +327 -0
- package/dist/commands/configure.js +480 -0
- package/dist/commands/doctor.js +484 -0
- package/dist/commands/health.js +108 -0
- package/dist/commands/models/aliases.js +64 -0
- package/dist/commands/models/fallbacks.js +99 -0
- package/dist/commands/models/image-fallbacks.js +99 -0
- package/dist/commands/models/list.js +323 -0
- package/dist/commands/models/scan.js +266 -0
- package/dist/commands/models/set-image.js +23 -0
- package/dist/commands/models/set.js +23 -0
- package/dist/commands/models/shared.js +72 -0
- package/dist/commands/models.js +7 -0
- package/dist/commands/onboard-auth.js +70 -0
- package/dist/commands/onboard-helpers.js +295 -0
- package/dist/commands/onboard-interactive.js +17 -0
- package/dist/commands/onboard-non-interactive.js +202 -0
- package/dist/commands/onboard-providers.js +634 -0
- package/dist/commands/onboard-remote.js +120 -0
- package/dist/commands/onboard-skills.js +148 -0
- package/dist/commands/onboard-types.js +1 -0
- package/dist/commands/onboard.js +12 -0
- package/dist/commands/send.js +124 -0
- package/dist/commands/sessions.js +212 -0
- package/dist/commands/setup.js +58 -0
- package/dist/commands/signal-install.js +135 -0
- package/dist/commands/status.js +207 -0
- package/dist/commands/update.js +16 -0
- package/dist/config/config.js +6 -0
- package/dist/config/defaults.js +61 -0
- package/dist/config/io.js +147 -0
- package/dist/config/legacy-migrate.js +13 -0
- package/dist/config/legacy.js +159 -0
- package/dist/config/paths.js +71 -0
- package/dist/config/schema.js +150 -0
- package/dist/config/sessions.js +282 -0
- package/dist/config/talk.js +31 -0
- package/dist/config/types.js +1 -0
- package/dist/config/validation.js +29 -0
- package/dist/config/zod-schema.js +831 -0
- package/dist/control-ui/assets/index-BFID3yAA.css +1 -0
- package/dist/control-ui/assets/index-CE_axlTS.js +2235 -0
- package/dist/control-ui/assets/index-CE_axlTS.js.map +1 -0
- package/dist/control-ui/index.html +15 -0
- package/dist/cron/isolated-agent.js +499 -0
- package/dist/cron/run-log.js +72 -0
- package/dist/cron/schedule.js +24 -0
- package/dist/cron/service.js +471 -0
- package/dist/cron/store.js +43 -0
- package/dist/cron/types.js +1 -0
- package/dist/daemon/constants.js +10 -0
- package/dist/daemon/launchd.js +276 -0
- package/dist/daemon/legacy.js +63 -0
- package/dist/daemon/program-args.js +76 -0
- package/dist/daemon/schtasks.js +257 -0
- package/dist/daemon/service.js +60 -0
- package/dist/daemon/systemd.js +266 -0
- package/dist/discord/index.js +2 -0
- package/dist/discord/monitor.js +1188 -0
- package/dist/discord/probe.js +54 -0
- package/dist/discord/send.js +577 -0
- package/dist/discord/token.js +8 -0
- package/dist/gateway/auth.js +121 -0
- package/dist/gateway/call.js +94 -0
- package/dist/gateway/chat-attachments.js +41 -0
- package/dist/gateway/client.js +180 -0
- package/dist/gateway/config-reload.js +274 -0
- package/dist/gateway/control-ui.js +184 -0
- package/dist/gateway/hooks-mapping.js +282 -0
- package/dist/gateway/hooks.js +168 -0
- package/dist/gateway/net.js +29 -0
- package/dist/gateway/protocol/index.js +61 -0
- package/dist/gateway/protocol/schema.js +560 -0
- package/dist/gateway/server-bridge-subscriptions.js +93 -0
- package/dist/gateway/server-bridge.js +1013 -0
- package/dist/gateway/server-browser.js +12 -0
- package/dist/gateway/server-chat.js +159 -0
- package/dist/gateway/server-constants.js +8 -0
- package/dist/gateway/server-discovery.js +62 -0
- package/dist/gateway/server-http.js +165 -0
- package/dist/gateway/server-methods/agent-job.js +125 -0
- package/dist/gateway/server-methods/agent.js +250 -0
- package/dist/gateway/server-methods/chat.js +200 -0
- package/dist/gateway/server-methods/config.js +50 -0
- package/dist/gateway/server-methods/connect.js +6 -0
- package/dist/gateway/server-methods/cron.js +83 -0
- package/dist/gateway/server-methods/health.js +28 -0
- package/dist/gateway/server-methods/models.js +16 -0
- package/dist/gateway/server-methods/nodes.js +294 -0
- package/dist/gateway/server-methods/providers.js +217 -0
- package/dist/gateway/server-methods/send.js +166 -0
- package/dist/gateway/server-methods/sessions.js +305 -0
- package/dist/gateway/server-methods/skills.js +83 -0
- package/dist/gateway/server-methods/system.js +118 -0
- package/dist/gateway/server-methods/talk.js +22 -0
- package/dist/gateway/server-methods/types.js +1 -0
- package/dist/gateway/server-methods/voicewake.js +30 -0
- package/dist/gateway/server-methods/web.js +58 -0
- package/dist/gateway/server-methods/wizard.js +100 -0
- package/dist/gateway/server-methods.js +53 -0
- package/dist/gateway/server-providers.js +644 -0
- package/dist/gateway/server-shared.js +1 -0
- package/dist/gateway/server-utils.js +35 -0
- package/dist/gateway/server.js +1437 -0
- package/dist/gateway/session-utils.js +216 -0
- package/dist/gateway/ws-log.js +349 -0
- package/dist/gateway/ws-logging.js +8 -0
- package/dist/globals.js +41 -0
- package/dist/hooks/gmail-ops.js +236 -0
- package/dist/hooks/gmail-setup-utils.js +278 -0
- package/dist/hooks/gmail-watcher.js +175 -0
- package/dist/hooks/gmail.js +177 -0
- package/dist/imessage/client.js +165 -0
- package/dist/imessage/index.js +3 -0
- package/dist/imessage/monitor.js +272 -0
- package/dist/imessage/probe.js +26 -0
- package/dist/imessage/send.js +83 -0
- package/dist/imessage/targets.js +176 -0
- package/dist/index.js +50 -0
- package/dist/infra/agent-events.js +46 -0
- package/dist/infra/binaries.js +9 -0
- package/dist/infra/bonjour-discovery.js +163 -0
- package/dist/infra/bonjour.js +200 -0
- package/dist/infra/bridge/server.js +562 -0
- package/dist/infra/canvas-host-url.js +54 -0
- package/dist/infra/env.js +8 -0
- package/dist/infra/errors.js +28 -0
- package/dist/infra/gateway-lock.js +8 -0
- package/dist/infra/heartbeat-events.js +21 -0
- package/dist/infra/heartbeat-runner.js +453 -0
- package/dist/infra/heartbeat-wake.js +61 -0
- package/dist/infra/is-main.js +37 -0
- package/dist/infra/machine-name.js +40 -0
- package/dist/infra/node-pairing.js +211 -0
- package/dist/infra/pam.js +42 -0
- package/dist/infra/path-env.js +92 -0
- package/dist/infra/ports.js +87 -0
- package/dist/infra/provider-summary.js +80 -0
- package/dist/infra/restart.js +29 -0
- package/dist/infra/retry.js +16 -0
- package/dist/infra/runtime-guard.js +59 -0
- package/dist/infra/system-events.js +44 -0
- package/dist/infra/system-presence.js +216 -0
- package/dist/infra/tailnet.js +46 -0
- package/dist/infra/tailscale.js +149 -0
- package/dist/infra/voicewake.js +77 -0
- package/dist/infra/widearea-dns.js +123 -0
- package/dist/infra/ws.js +13 -0
- package/dist/logger.js +52 -0
- package/dist/logging.js +490 -0
- package/dist/macos/gateway-daemon.js +141 -0
- package/dist/macos/relay.js +46 -0
- package/dist/media/constants.js +33 -0
- package/dist/media/host.js +42 -0
- package/dist/media/image-ops.js +121 -0
- package/dist/media/mime.js +115 -0
- package/dist/media/parse.js +81 -0
- package/dist/media/server.js +64 -0
- package/dist/media/store.js +139 -0
- package/dist/process/command-queue.js +97 -0
- package/dist/process/exec.js +75 -0
- package/dist/protocol.schema.json +2918 -0
- package/dist/provider-web.js +8 -0
- package/dist/providers/web/index.js +2 -0
- package/dist/runtime.js +8 -0
- package/dist/sessions/send-policy.js +68 -0
- package/dist/signal/client.js +134 -0
- package/dist/signal/daemon.js +69 -0
- package/dist/signal/index.js +3 -0
- package/dist/signal/monitor.js +336 -0
- package/dist/signal/probe.js +46 -0
- package/dist/signal/send.js +91 -0
- package/dist/slack/actions.js +97 -0
- package/dist/slack/index.js +5 -0
- package/dist/slack/monitor.js +1029 -0
- package/dist/slack/probe.js +47 -0
- package/dist/slack/send.js +131 -0
- package/dist/slack/token.js +10 -0
- package/dist/telegram/bot.js +394 -0
- package/dist/telegram/download.js +34 -0
- package/dist/telegram/index.js +4 -0
- package/dist/telegram/monitor.js +47 -0
- package/dist/telegram/probe.js +63 -0
- package/dist/telegram/proxy.js +9 -0
- package/dist/telegram/send.js +138 -0
- package/dist/telegram/token.js +30 -0
- package/dist/telegram/webhook-set.js +12 -0
- package/dist/telegram/webhook.js +56 -0
- package/dist/tui/commands.js +74 -0
- package/dist/tui/components/assistant-message.js +16 -0
- package/dist/tui/components/chat-log.js +92 -0
- package/dist/tui/components/custom-editor.js +53 -0
- package/dist/tui/components/selectors.js +8 -0
- package/dist/tui/components/tool-execution.js +111 -0
- package/dist/tui/components/user-message.js +17 -0
- package/dist/tui/gateway-chat.js +140 -0
- package/dist/tui/layout.js +41 -0
- package/dist/tui/message-list.js +57 -0
- package/dist/tui/theme/theme.js +80 -0
- package/dist/tui/theme.js +25 -0
- package/dist/tui/tui.js +708 -0
- package/dist/utils.js +133 -0
- package/dist/version.js +18 -0
- package/dist/web/active-listener.js +7 -0
- package/dist/web/auto-reply.js +1203 -0
- package/dist/web/inbound.js +481 -0
- package/dist/web/login-qr.js +204 -0
- package/dist/web/login.js +59 -0
- package/dist/web/media.js +148 -0
- package/dist/web/outbound.js +67 -0
- package/dist/web/qr-image.js +97 -0
- package/dist/web/reconnect.js +60 -0
- package/dist/web/reply-heartbeat-wake.js +61 -0
- package/dist/web/session.js +346 -0
- package/dist/wizard/clack-prompter.js +56 -0
- package/dist/wizard/onboarding.js +452 -0
- package/dist/wizard/prompts.js +6 -0
- package/dist/wizard/session.js +203 -0
- package/docs/AGENTS.default.md +116 -0
- package/docs/CNAME +1 -0
- package/docs/RELEASING.md +64 -0
- package/docs/_config.yml +51 -0
- package/docs/_layouts/default.html +145 -0
- package/docs/agent-send.md +21 -0
- package/docs/agent.md +104 -0
- package/docs/android/connect.md +131 -0
- package/docs/architecture.md +89 -0
- package/docs/assets/markdown.css +130 -0
- package/docs/assets/pixel-lobster.svg +60 -0
- package/docs/assets/terminal.css +497 -0
- package/docs/assets/theme.js +55 -0
- package/docs/audio.md +50 -0
- package/docs/background-process.md +74 -0
- package/docs/bash.md +32 -0
- package/docs/bonjour.md +159 -0
- package/docs/browser.md +289 -0
- package/docs/camera.md +152 -0
- package/docs/clawd.md +199 -0
- package/docs/clawdbot-mac.md +104 -0
- package/docs/configuration.md +1177 -0
- package/docs/control-api.md +49 -0
- package/docs/control-ui.md +83 -0
- package/docs/cron.md +374 -0
- package/docs/dashboard.md +17 -0
- package/docs/device-models.md +46 -0
- package/docs/discord.md +293 -0
- package/docs/discovery.md +112 -0
- package/docs/docker.md +251 -0
- package/docs/docs.json +86 -0
- package/docs/doctor.md +47 -0
- package/docs/elevated.md +31 -0
- package/docs/faq.md +640 -0
- package/docs/gateway/pairing.md +109 -0
- package/docs/gateway-lock.md +28 -0
- package/docs/gateway.md +174 -0
- package/docs/gmail-pubsub.md +191 -0
- package/docs/grammy.md +27 -0
- package/docs/group-messages.md +71 -0
- package/docs/groups.md +78 -0
- package/docs/health.md +28 -0
- package/docs/heartbeat.md +64 -0
- package/docs/images.md +52 -0
- package/docs/imessage.md +63 -0
- package/docs/index.md +182 -0
- package/docs/ios/connect.md +177 -0
- package/docs/ios/spec.md +236 -0
- package/docs/location-command.md +95 -0
- package/docs/logging.md +99 -0
- package/docs/lore.md +131 -0
- package/docs/mac/bun.md +133 -0
- package/docs/mac/canvas.md +161 -0
- package/docs/mac/child-process.md +72 -0
- package/docs/mac/dev-setup.md +81 -0
- package/docs/mac/health.md +28 -0
- package/docs/mac/icon.md +26 -0
- package/docs/mac/logging.md +51 -0
- package/docs/mac/menu-bar.md +69 -0
- package/docs/mac/peekaboo.md +170 -0
- package/docs/mac/permissions.md +40 -0
- package/docs/mac/release.md +76 -0
- package/docs/mac/remote.md +57 -0
- package/docs/mac/signing.md +41 -0
- package/docs/mac/skills.md +27 -0
- package/docs/mac/voice-overlay.md +52 -0
- package/docs/mac/voicewake.md +56 -0
- package/docs/mac/webchat.md +27 -0
- package/docs/mac/xpc.md +40 -0
- package/docs/models.md +90 -0
- package/docs/nix.md +49 -0
- package/docs/nodes.md +157 -0
- package/docs/onboarding-config-protocol.md +29 -0
- package/docs/onboarding.md +185 -0
- package/docs/presence.md +133 -0
- package/docs/queue.md +78 -0
- package/docs/refactor/browser-control-simplification.md +58 -0
- package/docs/refactor/canvas-a2ui.md +93 -0
- package/docs/refactor/cli-unification.md +64 -0
- package/docs/refactor/gateway-client.md +31 -0
- package/docs/refactor/gateway.md +99 -0
- package/docs/refactor/new-arch.md +171 -0
- package/docs/refactor/tui.md +26 -0
- package/docs/refactor/web-gateway-troubleshooting.md +37 -0
- package/docs/refactor/webagent-session.md +46 -0
- package/docs/remote-gateway-readme.md +148 -0
- package/docs/remote.md +66 -0
- package/docs/research/memory.md +227 -0
- package/docs/rpc.md +35 -0
- package/docs/security.md +168 -0
- package/docs/session-tool.md +119 -0
- package/docs/session.md +84 -0
- package/docs/sessions.md +8 -0
- package/docs/setup.md +118 -0
- package/docs/signal.md +113 -0
- package/docs/skills-config.md +58 -0
- package/docs/skills.md +149 -0
- package/docs/slack.md +158 -0
- package/docs/surface.md +20 -0
- package/docs/tailscale.md +71 -0
- package/docs/talk.md +79 -0
- package/docs/telegram.md +90 -0
- package/docs/templates/AGENTS.md +126 -0
- package/docs/templates/BOOTSTRAP.md +53 -0
- package/docs/templates/IDENTITY.md +17 -0
- package/docs/templates/SOUL.md +41 -0
- package/docs/templates/TOOLS.md +41 -0
- package/docs/templates/USER.md +22 -0
- package/docs/test.md +35 -0
- package/docs/thinking.md +46 -0
- package/docs/tools.md +248 -0
- package/docs/troubleshooting.md +227 -0
- package/docs/tui.md +69 -0
- package/docs/typebox.md +42 -0
- package/docs/voicewake.md +61 -0
- package/docs/web.md +115 -0
- package/docs/webchat.md +34 -0
- package/docs/webhook.md +132 -0
- package/docs/whatsapp-clawd.jpg +0 -0
- package/docs/whatsapp.md +142 -0
- package/docs/wizard.md +158 -0
- package/package.json +186 -0
- package/skills/apple-notes/SKILL.md +50 -0
- package/skills/apple-reminders/SKILL.md +67 -0
- package/skills/bear-notes/SKILL.md +79 -0
- package/skills/bird/SKILL.md +25 -0
- package/skills/blogwatcher/SKILL.md +46 -0
- package/skills/blucli/SKILL.md +27 -0
- package/skills/brave-search/SKILL.md +30 -0
- package/skills/brave-search/scripts/content.mjs +53 -0
- package/skills/brave-search/scripts/search.mjs +79 -0
- package/skills/camsnap/SKILL.md +25 -0
- package/skills/clawdhub/SKILL.md +53 -0
- package/skills/coding-agent/SKILL.md +275 -0
- package/skills/discord/SKILL.md +369 -0
- package/skills/eightctl/SKILL.md +29 -0
- package/skills/food-order/SKILL.md +41 -0
- package/skills/gemini/SKILL.md +23 -0
- package/skills/gifgrep/SKILL.md +47 -0
- package/skills/github/SKILL.md +47 -0
- package/skills/gog/SKILL.md +36 -0
- package/skills/goplaces/SKILL.md +30 -0
- package/skills/imsg/SKILL.md +25 -0
- package/skills/local-places/SERVER_README.md +101 -0
- package/skills/local-places/SKILL.md +91 -0
- package/skills/local-places/pyproject.toml +27 -0
- package/skills/local-places/src/local_places/__init__.py +2 -0
- package/skills/local-places/src/local_places/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/local-places/src/local_places/__pycache__/google_places.cpython-314.pyc +0 -0
- package/skills/local-places/src/local_places/__pycache__/main.cpython-314.pyc +0 -0
- package/skills/local-places/src/local_places/__pycache__/schemas.cpython-314.pyc +0 -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 +38 -0
- package/skills/nano-banana-pro/SKILL.md +29 -0
- package/skills/nano-banana-pro/scripts/generate_image.py +167 -0
- package/skills/nano-pdf/SKILL.md +20 -0
- package/skills/notion/SKILL.md +156 -0
- package/skills/obsidian/SKILL.md +55 -0
- package/skills/openai-image-gen/SKILL.md +31 -0
- package/skills/openai-image-gen/scripts/gen.py +173 -0
- package/skills/openai-whisper/SKILL.md +19 -0
- package/skills/openai-whisper-api/SKILL.md +43 -0
- package/skills/openai-whisper-api/scripts/transcribe.sh +85 -0
- package/skills/openhue/SKILL.md +30 -0
- package/skills/oracle/SKILL.md +105 -0
- package/skills/ordercli/SKILL.md +47 -0
- package/skills/peekaboo/SKILL.md +153 -0
- package/skills/qmd/SKILL.md +26 -0
- package/skills/sag/SKILL.md +62 -0
- package/skills/slack/SKILL.md +143 -0
- package/skills/songsee/SKILL.md +29 -0
- package/skills/sonoscli/SKILL.md +26 -0
- package/skills/spotify-player/SKILL.md +34 -0
- package/skills/summarize/SKILL.md +49 -0
- package/skills/things-mac/SKILL.md +61 -0
- package/skills/tmux/SKILL.md +121 -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 +84 -0
- package/skills/video-frames/SKILL.md +29 -0
- package/skills/video-frames/scripts/frame.sh +81 -0
- package/skills/wacli/SKILL.md +42 -0
- package/skills/weather/SKILL.md +49 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { normalizeDiscordToken } from "./token.js";
|
|
2
|
+
const DISCORD_API_BASE = "https://discord.com/api/v10";
|
|
3
|
+
async function fetchWithTimeout(url, timeoutMs, fetcher, headers) {
|
|
4
|
+
const controller = new AbortController();
|
|
5
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
6
|
+
try {
|
|
7
|
+
return await fetcher(url, { signal: controller.signal, headers });
|
|
8
|
+
}
|
|
9
|
+
finally {
|
|
10
|
+
clearTimeout(timer);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export async function probeDiscord(token, timeoutMs) {
|
|
14
|
+
const started = Date.now();
|
|
15
|
+
const normalized = normalizeDiscordToken(token);
|
|
16
|
+
const result = {
|
|
17
|
+
ok: false,
|
|
18
|
+
status: null,
|
|
19
|
+
error: null,
|
|
20
|
+
elapsedMs: 0,
|
|
21
|
+
};
|
|
22
|
+
if (!normalized) {
|
|
23
|
+
return {
|
|
24
|
+
...result,
|
|
25
|
+
error: "missing token",
|
|
26
|
+
elapsedMs: Date.now() - started,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const res = await fetchWithTimeout(`${DISCORD_API_BASE}/users/@me`, timeoutMs, fetch, {
|
|
31
|
+
Authorization: `Bot ${normalized}`,
|
|
32
|
+
});
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
result.status = res.status;
|
|
35
|
+
result.error = `getMe failed (${res.status})`;
|
|
36
|
+
return { ...result, elapsedMs: Date.now() - started };
|
|
37
|
+
}
|
|
38
|
+
const json = (await res.json());
|
|
39
|
+
result.ok = true;
|
|
40
|
+
result.bot = {
|
|
41
|
+
id: json.id ?? null,
|
|
42
|
+
username: json.username ?? null,
|
|
43
|
+
};
|
|
44
|
+
return { ...result, elapsedMs: Date.now() - started };
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
return {
|
|
48
|
+
...result,
|
|
49
|
+
status: err instanceof Response ? err.status : result.status,
|
|
50
|
+
error: err instanceof Error ? err.message : String(err),
|
|
51
|
+
elapsedMs: Date.now() - started,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
import { PermissionsBitField, REST, Routes } from "discord.js";
|
|
2
|
+
import { PollLayoutType } from "discord-api-types/payloads/v10";
|
|
3
|
+
import { chunkText } from "../auto-reply/chunk.js";
|
|
4
|
+
import { loadConfig } from "../config/config.js";
|
|
5
|
+
import { loadWebMedia, loadWebMediaRaw } from "../web/media.js";
|
|
6
|
+
import { normalizeDiscordToken } from "./token.js";
|
|
7
|
+
const DISCORD_TEXT_LIMIT = 2000;
|
|
8
|
+
const DISCORD_MAX_STICKERS = 3;
|
|
9
|
+
const DISCORD_MAX_EMOJI_BYTES = 256 * 1024;
|
|
10
|
+
const DISCORD_MAX_STICKER_BYTES = 512 * 1024;
|
|
11
|
+
const DISCORD_POLL_MIN_ANSWERS = 2;
|
|
12
|
+
const DISCORD_POLL_MAX_ANSWERS = 10;
|
|
13
|
+
const DISCORD_POLL_MAX_DURATION_HOURS = 32 * 24;
|
|
14
|
+
function resolveToken(explicit) {
|
|
15
|
+
const cfgToken = loadConfig().discord?.token;
|
|
16
|
+
const token = normalizeDiscordToken(explicit ?? process.env.DISCORD_BOT_TOKEN ?? cfgToken ?? undefined);
|
|
17
|
+
if (!token) {
|
|
18
|
+
throw new Error("DISCORD_BOT_TOKEN or discord.token is required for Discord sends");
|
|
19
|
+
}
|
|
20
|
+
return token;
|
|
21
|
+
}
|
|
22
|
+
function normalizeReactionEmoji(raw) {
|
|
23
|
+
const trimmed = raw.trim();
|
|
24
|
+
if (!trimmed) {
|
|
25
|
+
throw new Error("emoji required");
|
|
26
|
+
}
|
|
27
|
+
const customMatch = trimmed.match(/^<a?:([^:>]+):(\d+)>$/);
|
|
28
|
+
const identifier = customMatch
|
|
29
|
+
? `${customMatch[1]}:${customMatch[2]}`
|
|
30
|
+
: trimmed.replace(/[\uFE0E\uFE0F]/g, "");
|
|
31
|
+
return encodeURIComponent(identifier);
|
|
32
|
+
}
|
|
33
|
+
function parseRecipient(raw) {
|
|
34
|
+
const trimmed = raw.trim();
|
|
35
|
+
if (!trimmed) {
|
|
36
|
+
throw new Error("Recipient is required for Discord sends");
|
|
37
|
+
}
|
|
38
|
+
const mentionMatch = trimmed.match(/^<@!?(\d+)>$/);
|
|
39
|
+
if (mentionMatch) {
|
|
40
|
+
return { kind: "user", id: mentionMatch[1] };
|
|
41
|
+
}
|
|
42
|
+
if (trimmed.startsWith("user:")) {
|
|
43
|
+
return { kind: "user", id: trimmed.slice("user:".length) };
|
|
44
|
+
}
|
|
45
|
+
if (trimmed.startsWith("channel:")) {
|
|
46
|
+
return { kind: "channel", id: trimmed.slice("channel:".length) };
|
|
47
|
+
}
|
|
48
|
+
if (trimmed.startsWith("discord:")) {
|
|
49
|
+
return { kind: "user", id: trimmed.slice("discord:".length) };
|
|
50
|
+
}
|
|
51
|
+
if (trimmed.startsWith("@")) {
|
|
52
|
+
const candidate = trimmed.slice(1);
|
|
53
|
+
if (!/^\d+$/.test(candidate)) {
|
|
54
|
+
throw new Error("Discord DMs require a user id (use user:<id> or a <@id> mention)");
|
|
55
|
+
}
|
|
56
|
+
return { kind: "user", id: candidate };
|
|
57
|
+
}
|
|
58
|
+
return { kind: "channel", id: trimmed };
|
|
59
|
+
}
|
|
60
|
+
function normalizeStickerIds(raw) {
|
|
61
|
+
const ids = raw.map((entry) => entry.trim()).filter(Boolean);
|
|
62
|
+
if (ids.length === 0) {
|
|
63
|
+
throw new Error("At least one sticker id is required");
|
|
64
|
+
}
|
|
65
|
+
if (ids.length > DISCORD_MAX_STICKERS) {
|
|
66
|
+
throw new Error("Discord supports up to 3 stickers per message");
|
|
67
|
+
}
|
|
68
|
+
return ids;
|
|
69
|
+
}
|
|
70
|
+
function normalizeEmojiName(raw, label) {
|
|
71
|
+
const name = raw.trim();
|
|
72
|
+
if (!name) {
|
|
73
|
+
throw new Error(`${label} is required`);
|
|
74
|
+
}
|
|
75
|
+
return name;
|
|
76
|
+
}
|
|
77
|
+
function normalizePollInput(input) {
|
|
78
|
+
const question = input.question.trim();
|
|
79
|
+
if (!question) {
|
|
80
|
+
throw new Error("Poll question is required");
|
|
81
|
+
}
|
|
82
|
+
const answers = (input.answers ?? [])
|
|
83
|
+
.map((answer) => answer.trim())
|
|
84
|
+
.filter(Boolean);
|
|
85
|
+
if (answers.length < DISCORD_POLL_MIN_ANSWERS) {
|
|
86
|
+
throw new Error("Polls require at least 2 answers");
|
|
87
|
+
}
|
|
88
|
+
if (answers.length > DISCORD_POLL_MAX_ANSWERS) {
|
|
89
|
+
throw new Error("Polls support up to 10 answers");
|
|
90
|
+
}
|
|
91
|
+
const durationRaw = typeof input.durationHours === "number" &&
|
|
92
|
+
Number.isFinite(input.durationHours)
|
|
93
|
+
? Math.floor(input.durationHours)
|
|
94
|
+
: 24;
|
|
95
|
+
const duration = Math.min(Math.max(durationRaw, 1), DISCORD_POLL_MAX_DURATION_HOURS);
|
|
96
|
+
return {
|
|
97
|
+
question: { text: question },
|
|
98
|
+
answers: answers.map((answer) => ({ poll_media: { text: answer } })),
|
|
99
|
+
duration,
|
|
100
|
+
allow_multiselect: input.allowMultiselect ?? false,
|
|
101
|
+
layout_type: PollLayoutType.Default,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
async function resolveChannelId(rest, recipient) {
|
|
105
|
+
if (recipient.kind === "channel") {
|
|
106
|
+
return { channelId: recipient.id };
|
|
107
|
+
}
|
|
108
|
+
const dmChannel = (await rest.post(Routes.userChannels(), {
|
|
109
|
+
body: { recipient_id: recipient.id },
|
|
110
|
+
}));
|
|
111
|
+
if (!dmChannel?.id) {
|
|
112
|
+
throw new Error("Failed to create Discord DM channel");
|
|
113
|
+
}
|
|
114
|
+
return { channelId: dmChannel.id, dm: true };
|
|
115
|
+
}
|
|
116
|
+
async function sendDiscordText(rest, channelId, text, replyTo) {
|
|
117
|
+
if (!text.trim()) {
|
|
118
|
+
throw new Error("Message must be non-empty for Discord sends");
|
|
119
|
+
}
|
|
120
|
+
const messageReference = replyTo
|
|
121
|
+
? { message_id: replyTo, fail_if_not_exists: false }
|
|
122
|
+
: undefined;
|
|
123
|
+
if (text.length <= DISCORD_TEXT_LIMIT) {
|
|
124
|
+
const res = (await rest.post(Routes.channelMessages(channelId), {
|
|
125
|
+
body: { content: text, message_reference: messageReference },
|
|
126
|
+
}));
|
|
127
|
+
return res;
|
|
128
|
+
}
|
|
129
|
+
const chunks = chunkText(text, DISCORD_TEXT_LIMIT);
|
|
130
|
+
let last = null;
|
|
131
|
+
let isFirst = true;
|
|
132
|
+
for (const chunk of chunks) {
|
|
133
|
+
last = (await rest.post(Routes.channelMessages(channelId), {
|
|
134
|
+
body: {
|
|
135
|
+
content: chunk,
|
|
136
|
+
message_reference: isFirst ? messageReference : undefined,
|
|
137
|
+
},
|
|
138
|
+
}));
|
|
139
|
+
isFirst = false;
|
|
140
|
+
}
|
|
141
|
+
if (!last) {
|
|
142
|
+
throw new Error("Discord send failed (empty chunk result)");
|
|
143
|
+
}
|
|
144
|
+
return last;
|
|
145
|
+
}
|
|
146
|
+
async function sendDiscordMedia(rest, channelId, text, mediaUrl, replyTo) {
|
|
147
|
+
const media = await loadWebMedia(mediaUrl);
|
|
148
|
+
const caption = text.length > DISCORD_TEXT_LIMIT ? text.slice(0, DISCORD_TEXT_LIMIT) : text;
|
|
149
|
+
const messageReference = replyTo
|
|
150
|
+
? { message_id: replyTo, fail_if_not_exists: false }
|
|
151
|
+
: undefined;
|
|
152
|
+
const res = (await rest.post(Routes.channelMessages(channelId), {
|
|
153
|
+
body: {
|
|
154
|
+
content: caption || undefined,
|
|
155
|
+
message_reference: messageReference,
|
|
156
|
+
},
|
|
157
|
+
files: [
|
|
158
|
+
{
|
|
159
|
+
data: media.buffer,
|
|
160
|
+
name: media.fileName ?? "upload",
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
}));
|
|
164
|
+
if (text.length > DISCORD_TEXT_LIMIT) {
|
|
165
|
+
const remaining = text.slice(DISCORD_TEXT_LIMIT).trim();
|
|
166
|
+
if (remaining) {
|
|
167
|
+
await sendDiscordText(rest, channelId, remaining);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return res;
|
|
171
|
+
}
|
|
172
|
+
function buildReactionIdentifier(emoji) {
|
|
173
|
+
if (emoji.id && emoji.name) {
|
|
174
|
+
return `${emoji.name}:${emoji.id}`;
|
|
175
|
+
}
|
|
176
|
+
return emoji.name ?? "";
|
|
177
|
+
}
|
|
178
|
+
function formatReactionEmoji(emoji) {
|
|
179
|
+
return buildReactionIdentifier(emoji);
|
|
180
|
+
}
|
|
181
|
+
async function fetchBotUserId(rest) {
|
|
182
|
+
const me = (await rest.get(Routes.user("@me")));
|
|
183
|
+
if (!me?.id) {
|
|
184
|
+
throw new Error("Failed to resolve bot user id");
|
|
185
|
+
}
|
|
186
|
+
return me.id;
|
|
187
|
+
}
|
|
188
|
+
export async function sendMessageDiscord(to, text, opts = {}) {
|
|
189
|
+
const token = resolveToken(opts.token);
|
|
190
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
191
|
+
const recipient = parseRecipient(to);
|
|
192
|
+
const { channelId } = await resolveChannelId(rest, recipient);
|
|
193
|
+
let result;
|
|
194
|
+
if (opts.mediaUrl) {
|
|
195
|
+
result = await sendDiscordMedia(rest, channelId, text, opts.mediaUrl, opts.replyTo);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
result = await sendDiscordText(rest, channelId, text, opts.replyTo);
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
messageId: result.id ? String(result.id) : "unknown",
|
|
202
|
+
channelId: String(result.channel_id ?? channelId),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
export async function sendStickerDiscord(to, stickerIds, opts = {}) {
|
|
206
|
+
const token = resolveToken(opts.token);
|
|
207
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
208
|
+
const recipient = parseRecipient(to);
|
|
209
|
+
const { channelId } = await resolveChannelId(rest, recipient);
|
|
210
|
+
const content = opts.content?.trim();
|
|
211
|
+
const stickers = normalizeStickerIds(stickerIds);
|
|
212
|
+
const res = (await rest.post(Routes.channelMessages(channelId), {
|
|
213
|
+
body: {
|
|
214
|
+
content: content || undefined,
|
|
215
|
+
sticker_ids: stickers,
|
|
216
|
+
},
|
|
217
|
+
}));
|
|
218
|
+
return {
|
|
219
|
+
messageId: res.id ? String(res.id) : "unknown",
|
|
220
|
+
channelId: String(res.channel_id ?? channelId),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
export async function sendPollDiscord(to, poll, opts = {}) {
|
|
224
|
+
const token = resolveToken(opts.token);
|
|
225
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
226
|
+
const recipient = parseRecipient(to);
|
|
227
|
+
const { channelId } = await resolveChannelId(rest, recipient);
|
|
228
|
+
const content = opts.content?.trim();
|
|
229
|
+
const payload = normalizePollInput(poll);
|
|
230
|
+
const res = (await rest.post(Routes.channelMessages(channelId), {
|
|
231
|
+
body: {
|
|
232
|
+
content: content || undefined,
|
|
233
|
+
poll: payload,
|
|
234
|
+
},
|
|
235
|
+
}));
|
|
236
|
+
return {
|
|
237
|
+
messageId: res.id ? String(res.id) : "unknown",
|
|
238
|
+
channelId: String(res.channel_id ?? channelId),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
export async function reactMessageDiscord(channelId, messageId, emoji, opts = {}) {
|
|
242
|
+
const token = resolveToken(opts.token);
|
|
243
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
244
|
+
const encoded = normalizeReactionEmoji(emoji);
|
|
245
|
+
await rest.put(Routes.channelMessageOwnReaction(channelId, messageId, encoded));
|
|
246
|
+
return { ok: true };
|
|
247
|
+
}
|
|
248
|
+
export async function fetchReactionsDiscord(channelId, messageId, opts = {}) {
|
|
249
|
+
const token = resolveToken(opts.token);
|
|
250
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
251
|
+
const message = (await rest.get(Routes.channelMessage(channelId, messageId)));
|
|
252
|
+
const reactions = message.reactions ?? [];
|
|
253
|
+
if (reactions.length === 0)
|
|
254
|
+
return [];
|
|
255
|
+
const limit = typeof opts.limit === "number" && Number.isFinite(opts.limit)
|
|
256
|
+
? Math.min(Math.max(Math.floor(opts.limit), 1), 100)
|
|
257
|
+
: 100;
|
|
258
|
+
const summaries = [];
|
|
259
|
+
for (const reaction of reactions) {
|
|
260
|
+
const identifier = buildReactionIdentifier(reaction.emoji);
|
|
261
|
+
if (!identifier)
|
|
262
|
+
continue;
|
|
263
|
+
const encoded = encodeURIComponent(identifier);
|
|
264
|
+
const users = (await rest.get(Routes.channelMessageReaction(channelId, messageId, encoded), { query: new URLSearchParams({ limit: String(limit) }) }));
|
|
265
|
+
summaries.push({
|
|
266
|
+
emoji: {
|
|
267
|
+
id: reaction.emoji.id ?? null,
|
|
268
|
+
name: reaction.emoji.name ?? null,
|
|
269
|
+
raw: formatReactionEmoji(reaction.emoji),
|
|
270
|
+
},
|
|
271
|
+
count: reaction.count,
|
|
272
|
+
users: users.map((user) => ({
|
|
273
|
+
id: user.id,
|
|
274
|
+
username: user.username,
|
|
275
|
+
tag: user.username && user.discriminator
|
|
276
|
+
? `${user.username}#${user.discriminator}`
|
|
277
|
+
: user.username,
|
|
278
|
+
})),
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
return summaries;
|
|
282
|
+
}
|
|
283
|
+
export async function fetchChannelPermissionsDiscord(channelId, opts = {}) {
|
|
284
|
+
const token = resolveToken(opts.token);
|
|
285
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
286
|
+
const channel = (await rest.get(Routes.channel(channelId)));
|
|
287
|
+
const guildId = "guild_id" in channel ? channel.guild_id : undefined;
|
|
288
|
+
if (!guildId) {
|
|
289
|
+
return {
|
|
290
|
+
channelId,
|
|
291
|
+
permissions: [],
|
|
292
|
+
raw: "0",
|
|
293
|
+
isDm: true,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
const botId = await fetchBotUserId(rest);
|
|
297
|
+
const [guild, member] = await Promise.all([
|
|
298
|
+
rest.get(Routes.guild(guildId)),
|
|
299
|
+
rest.get(Routes.guildMember(guildId, botId)),
|
|
300
|
+
]);
|
|
301
|
+
const rolesById = new Map((guild.roles ?? []).map((role) => [role.id, role]));
|
|
302
|
+
const base = new PermissionsBitField();
|
|
303
|
+
const everyoneRole = rolesById.get(guildId);
|
|
304
|
+
if (everyoneRole?.permissions) {
|
|
305
|
+
base.add(BigInt(everyoneRole.permissions));
|
|
306
|
+
}
|
|
307
|
+
for (const roleId of member.roles ?? []) {
|
|
308
|
+
const role = rolesById.get(roleId);
|
|
309
|
+
if (role?.permissions) {
|
|
310
|
+
base.add(BigInt(role.permissions));
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const permissions = new PermissionsBitField(base);
|
|
314
|
+
const overwrites = "permission_overwrites" in channel
|
|
315
|
+
? (channel.permission_overwrites ?? [])
|
|
316
|
+
: [];
|
|
317
|
+
for (const overwrite of overwrites) {
|
|
318
|
+
if (overwrite.id === guildId) {
|
|
319
|
+
permissions.remove(BigInt(overwrite.deny ?? "0"));
|
|
320
|
+
permissions.add(BigInt(overwrite.allow ?? "0"));
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
for (const overwrite of overwrites) {
|
|
324
|
+
if (member.roles?.includes(overwrite.id)) {
|
|
325
|
+
permissions.remove(BigInt(overwrite.deny ?? "0"));
|
|
326
|
+
permissions.add(BigInt(overwrite.allow ?? "0"));
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
for (const overwrite of overwrites) {
|
|
330
|
+
if (overwrite.id === botId) {
|
|
331
|
+
permissions.remove(BigInt(overwrite.deny ?? "0"));
|
|
332
|
+
permissions.add(BigInt(overwrite.allow ?? "0"));
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return {
|
|
336
|
+
channelId,
|
|
337
|
+
guildId,
|
|
338
|
+
permissions: permissions.toArray(),
|
|
339
|
+
raw: permissions.bitfield.toString(),
|
|
340
|
+
isDm: false,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
export async function readMessagesDiscord(channelId, query = {}, opts = {}) {
|
|
344
|
+
const token = resolveToken(opts.token);
|
|
345
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
346
|
+
const limit = typeof query.limit === "number" && Number.isFinite(query.limit)
|
|
347
|
+
? Math.min(Math.max(Math.floor(query.limit), 1), 100)
|
|
348
|
+
: undefined;
|
|
349
|
+
const params = new URLSearchParams();
|
|
350
|
+
if (limit)
|
|
351
|
+
params.set("limit", String(limit));
|
|
352
|
+
if (query.before)
|
|
353
|
+
params.set("before", query.before);
|
|
354
|
+
if (query.after)
|
|
355
|
+
params.set("after", query.after);
|
|
356
|
+
if (query.around)
|
|
357
|
+
params.set("around", query.around);
|
|
358
|
+
return (await rest.get(Routes.channelMessages(channelId), {
|
|
359
|
+
query: params,
|
|
360
|
+
}));
|
|
361
|
+
}
|
|
362
|
+
export async function editMessageDiscord(channelId, messageId, payload, opts = {}) {
|
|
363
|
+
const token = resolveToken(opts.token);
|
|
364
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
365
|
+
return (await rest.patch(Routes.channelMessage(channelId, messageId), {
|
|
366
|
+
body: { content: payload.content },
|
|
367
|
+
}));
|
|
368
|
+
}
|
|
369
|
+
export async function deleteMessageDiscord(channelId, messageId, opts = {}) {
|
|
370
|
+
const token = resolveToken(opts.token);
|
|
371
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
372
|
+
await rest.delete(Routes.channelMessage(channelId, messageId));
|
|
373
|
+
return { ok: true };
|
|
374
|
+
}
|
|
375
|
+
export async function pinMessageDiscord(channelId, messageId, opts = {}) {
|
|
376
|
+
const token = resolveToken(opts.token);
|
|
377
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
378
|
+
await rest.put(Routes.channelPin(channelId, messageId));
|
|
379
|
+
return { ok: true };
|
|
380
|
+
}
|
|
381
|
+
export async function unpinMessageDiscord(channelId, messageId, opts = {}) {
|
|
382
|
+
const token = resolveToken(opts.token);
|
|
383
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
384
|
+
await rest.delete(Routes.channelPin(channelId, messageId));
|
|
385
|
+
return { ok: true };
|
|
386
|
+
}
|
|
387
|
+
export async function listPinsDiscord(channelId, opts = {}) {
|
|
388
|
+
const token = resolveToken(opts.token);
|
|
389
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
390
|
+
return (await rest.get(Routes.channelPins(channelId)));
|
|
391
|
+
}
|
|
392
|
+
export async function createThreadDiscord(channelId, payload, opts = {}) {
|
|
393
|
+
const token = resolveToken(opts.token);
|
|
394
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
395
|
+
const body = { name: payload.name };
|
|
396
|
+
if (payload.autoArchiveMinutes) {
|
|
397
|
+
body.auto_archive_duration = payload.autoArchiveMinutes;
|
|
398
|
+
}
|
|
399
|
+
const route = Routes.threads(channelId, payload.messageId);
|
|
400
|
+
return await rest.post(route, { body });
|
|
401
|
+
}
|
|
402
|
+
export async function listThreadsDiscord(payload, opts = {}) {
|
|
403
|
+
const token = resolveToken(opts.token);
|
|
404
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
405
|
+
if (payload.includeArchived) {
|
|
406
|
+
if (!payload.channelId) {
|
|
407
|
+
throw new Error("channelId required to list archived threads");
|
|
408
|
+
}
|
|
409
|
+
const params = new URLSearchParams();
|
|
410
|
+
if (payload.before)
|
|
411
|
+
params.set("before", payload.before);
|
|
412
|
+
if (payload.limit)
|
|
413
|
+
params.set("limit", String(payload.limit));
|
|
414
|
+
return await rest.get(Routes.channelThreads(payload.channelId, "public"), {
|
|
415
|
+
query: params,
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
return await rest.get(Routes.guildActiveThreads(payload.guildId));
|
|
419
|
+
}
|
|
420
|
+
export async function searchMessagesDiscord(query, opts = {}) {
|
|
421
|
+
const token = resolveToken(opts.token);
|
|
422
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
423
|
+
const params = new URLSearchParams();
|
|
424
|
+
params.set("content", query.content);
|
|
425
|
+
if (query.channelIds?.length) {
|
|
426
|
+
for (const channelId of query.channelIds) {
|
|
427
|
+
params.append("channel_id", channelId);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
if (query.authorIds?.length) {
|
|
431
|
+
for (const authorId of query.authorIds) {
|
|
432
|
+
params.append("author_id", authorId);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
if (query.limit) {
|
|
436
|
+
const limit = Math.min(Math.max(Math.floor(query.limit), 1), 25);
|
|
437
|
+
params.set("limit", String(limit));
|
|
438
|
+
}
|
|
439
|
+
return await rest.get(`/guilds/${query.guildId}/messages/search`, {
|
|
440
|
+
query: params,
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
export async function listGuildEmojisDiscord(guildId, opts = {}) {
|
|
444
|
+
const token = resolveToken(opts.token);
|
|
445
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
446
|
+
return await rest.get(Routes.guildEmojis(guildId));
|
|
447
|
+
}
|
|
448
|
+
export async function uploadEmojiDiscord(payload, opts = {}) {
|
|
449
|
+
const token = resolveToken(opts.token);
|
|
450
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
451
|
+
const media = await loadWebMediaRaw(payload.mediaUrl, DISCORD_MAX_EMOJI_BYTES);
|
|
452
|
+
const contentType = media.contentType?.toLowerCase();
|
|
453
|
+
if (!contentType ||
|
|
454
|
+
!["image/png", "image/jpeg", "image/jpg", "image/gif"].includes(contentType)) {
|
|
455
|
+
throw new Error("Discord emoji uploads require a PNG, JPG, or GIF image");
|
|
456
|
+
}
|
|
457
|
+
const image = `data:${contentType};base64,${media.buffer.toString("base64")}`;
|
|
458
|
+
const roleIds = (payload.roleIds ?? [])
|
|
459
|
+
.map((id) => id.trim())
|
|
460
|
+
.filter(Boolean);
|
|
461
|
+
return await rest.post(Routes.guildEmojis(payload.guildId), {
|
|
462
|
+
body: {
|
|
463
|
+
name: normalizeEmojiName(payload.name, "Emoji name"),
|
|
464
|
+
image,
|
|
465
|
+
roles: roleIds.length ? roleIds : undefined,
|
|
466
|
+
},
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
export async function uploadStickerDiscord(payload, opts = {}) {
|
|
470
|
+
const token = resolveToken(opts.token);
|
|
471
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
472
|
+
const media = await loadWebMediaRaw(payload.mediaUrl, DISCORD_MAX_STICKER_BYTES);
|
|
473
|
+
const contentType = media.contentType?.toLowerCase();
|
|
474
|
+
if (!contentType ||
|
|
475
|
+
!["image/png", "image/apng", "application/json"].includes(contentType)) {
|
|
476
|
+
throw new Error("Discord sticker uploads require a PNG, APNG, or Lottie JSON file");
|
|
477
|
+
}
|
|
478
|
+
return await rest.post(Routes.guildStickers(payload.guildId), {
|
|
479
|
+
body: {
|
|
480
|
+
name: normalizeEmojiName(payload.name, "Sticker name"),
|
|
481
|
+
description: normalizeEmojiName(payload.description, "Sticker description"),
|
|
482
|
+
tags: normalizeEmojiName(payload.tags, "Sticker tags"),
|
|
483
|
+
},
|
|
484
|
+
files: [
|
|
485
|
+
{
|
|
486
|
+
data: media.buffer,
|
|
487
|
+
name: media.fileName ?? "sticker",
|
|
488
|
+
contentType,
|
|
489
|
+
},
|
|
490
|
+
],
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
export async function fetchMemberInfoDiscord(guildId, userId, opts = {}) {
|
|
494
|
+
const token = resolveToken(opts.token);
|
|
495
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
496
|
+
return (await rest.get(Routes.guildMember(guildId, userId)));
|
|
497
|
+
}
|
|
498
|
+
export async function fetchRoleInfoDiscord(guildId, opts = {}) {
|
|
499
|
+
const token = resolveToken(opts.token);
|
|
500
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
501
|
+
return (await rest.get(Routes.guildRoles(guildId)));
|
|
502
|
+
}
|
|
503
|
+
export async function addRoleDiscord(payload, opts = {}) {
|
|
504
|
+
const token = resolveToken(opts.token);
|
|
505
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
506
|
+
await rest.put(Routes.guildMemberRole(payload.guildId, payload.userId, payload.roleId));
|
|
507
|
+
return { ok: true };
|
|
508
|
+
}
|
|
509
|
+
export async function removeRoleDiscord(payload, opts = {}) {
|
|
510
|
+
const token = resolveToken(opts.token);
|
|
511
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
512
|
+
await rest.delete(Routes.guildMemberRole(payload.guildId, payload.userId, payload.roleId));
|
|
513
|
+
return { ok: true };
|
|
514
|
+
}
|
|
515
|
+
export async function fetchChannelInfoDiscord(channelId, opts = {}) {
|
|
516
|
+
const token = resolveToken(opts.token);
|
|
517
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
518
|
+
return (await rest.get(Routes.channel(channelId)));
|
|
519
|
+
}
|
|
520
|
+
export async function listGuildChannelsDiscord(guildId, opts = {}) {
|
|
521
|
+
const token = resolveToken(opts.token);
|
|
522
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
523
|
+
return (await rest.get(Routes.guildChannels(guildId)));
|
|
524
|
+
}
|
|
525
|
+
export async function fetchVoiceStatusDiscord(guildId, userId, opts = {}) {
|
|
526
|
+
const token = resolveToken(opts.token);
|
|
527
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
528
|
+
return (await rest.get(Routes.guildVoiceState(guildId, userId)));
|
|
529
|
+
}
|
|
530
|
+
export async function listScheduledEventsDiscord(guildId, opts = {}) {
|
|
531
|
+
const token = resolveToken(opts.token);
|
|
532
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
533
|
+
return (await rest.get(Routes.guildScheduledEvents(guildId)));
|
|
534
|
+
}
|
|
535
|
+
export async function createScheduledEventDiscord(guildId, payload, opts = {}) {
|
|
536
|
+
const token = resolveToken(opts.token);
|
|
537
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
538
|
+
return (await rest.post(Routes.guildScheduledEvents(guildId), {
|
|
539
|
+
body: payload,
|
|
540
|
+
}));
|
|
541
|
+
}
|
|
542
|
+
export async function timeoutMemberDiscord(payload, opts = {}) {
|
|
543
|
+
const token = resolveToken(opts.token);
|
|
544
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
545
|
+
let until = payload.until;
|
|
546
|
+
if (!until && payload.durationMinutes) {
|
|
547
|
+
const ms = payload.durationMinutes * 60 * 1000;
|
|
548
|
+
until = new Date(Date.now() + ms).toISOString();
|
|
549
|
+
}
|
|
550
|
+
return (await rest.patch(Routes.guildMember(payload.guildId, payload.userId), {
|
|
551
|
+
body: { communication_disabled_until: until ?? null },
|
|
552
|
+
reason: payload.reason,
|
|
553
|
+
}));
|
|
554
|
+
}
|
|
555
|
+
export async function kickMemberDiscord(payload, opts = {}) {
|
|
556
|
+
const token = resolveToken(opts.token);
|
|
557
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
558
|
+
await rest.delete(Routes.guildMember(payload.guildId, payload.userId), {
|
|
559
|
+
reason: payload.reason,
|
|
560
|
+
});
|
|
561
|
+
return { ok: true };
|
|
562
|
+
}
|
|
563
|
+
export async function banMemberDiscord(payload, opts = {}) {
|
|
564
|
+
const token = resolveToken(opts.token);
|
|
565
|
+
const rest = opts.rest ?? new REST({ version: "10" }).setToken(token);
|
|
566
|
+
const deleteMessageDays = typeof payload.deleteMessageDays === "number" &&
|
|
567
|
+
Number.isFinite(payload.deleteMessageDays)
|
|
568
|
+
? Math.min(Math.max(Math.floor(payload.deleteMessageDays), 0), 7)
|
|
569
|
+
: undefined;
|
|
570
|
+
await rest.put(Routes.guildBan(payload.guildId, payload.userId), {
|
|
571
|
+
body: deleteMessageDays !== undefined
|
|
572
|
+
? { delete_message_days: deleteMessageDays }
|
|
573
|
+
: undefined,
|
|
574
|
+
reason: payload.reason,
|
|
575
|
+
});
|
|
576
|
+
return { ok: true };
|
|
577
|
+
}
|