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,433 @@
|
|
|
1
|
+
import { codingTools, createEditTool, createReadTool, createWriteTool, readTool, } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
import { detectMime } from "../media/mime.js";
|
|
4
|
+
import { startWebLoginWithQr, waitForWebLogin } from "../web/login-qr.js";
|
|
5
|
+
import { createBashTool, createProcessTool, } from "./bash-tools.js";
|
|
6
|
+
import { createClawdbotTools } from "./clawdbot-tools.js";
|
|
7
|
+
import { assertSandboxPath } from "./sandbox-paths.js";
|
|
8
|
+
import { sanitizeToolResultImages } from "./tool-images.js";
|
|
9
|
+
async function sniffMimeFromBase64(base64) {
|
|
10
|
+
const trimmed = base64.trim();
|
|
11
|
+
if (!trimmed)
|
|
12
|
+
return undefined;
|
|
13
|
+
const take = Math.min(256, trimmed.length);
|
|
14
|
+
const sliceLen = take - (take % 4);
|
|
15
|
+
if (sliceLen < 8)
|
|
16
|
+
return undefined;
|
|
17
|
+
try {
|
|
18
|
+
const head = Buffer.from(trimmed.slice(0, sliceLen), "base64");
|
|
19
|
+
return await detectMime({ buffer: head });
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function rewriteReadImageHeader(text, mimeType) {
|
|
26
|
+
// pi-coding-agent uses: "Read image file [image/png]"
|
|
27
|
+
if (text.startsWith("Read image file [") && text.endsWith("]")) {
|
|
28
|
+
return `Read image file [${mimeType}]`;
|
|
29
|
+
}
|
|
30
|
+
return text;
|
|
31
|
+
}
|
|
32
|
+
async function normalizeReadImageResult(result, filePath) {
|
|
33
|
+
const content = Array.isArray(result.content) ? result.content : [];
|
|
34
|
+
const image = content.find((b) => !!b &&
|
|
35
|
+
typeof b === "object" &&
|
|
36
|
+
b.type === "image" &&
|
|
37
|
+
typeof b.data === "string" &&
|
|
38
|
+
typeof b.mimeType === "string");
|
|
39
|
+
if (!image)
|
|
40
|
+
return result;
|
|
41
|
+
if (!image.data.trim()) {
|
|
42
|
+
throw new Error(`read: image payload is empty (${filePath})`);
|
|
43
|
+
}
|
|
44
|
+
const sniffed = await sniffMimeFromBase64(image.data);
|
|
45
|
+
if (!sniffed)
|
|
46
|
+
return result;
|
|
47
|
+
if (!sniffed.startsWith("image/")) {
|
|
48
|
+
throw new Error(`read: file looks like ${sniffed} but was treated as ${image.mimeType} (${filePath})`);
|
|
49
|
+
}
|
|
50
|
+
if (sniffed === image.mimeType)
|
|
51
|
+
return result;
|
|
52
|
+
const nextContent = content.map((block) => {
|
|
53
|
+
if (block &&
|
|
54
|
+
typeof block === "object" &&
|
|
55
|
+
block.type === "image") {
|
|
56
|
+
const b = block;
|
|
57
|
+
return { ...b, mimeType: sniffed };
|
|
58
|
+
}
|
|
59
|
+
if (block &&
|
|
60
|
+
typeof block === "object" &&
|
|
61
|
+
block.type === "text" &&
|
|
62
|
+
typeof block.text === "string") {
|
|
63
|
+
const b = block;
|
|
64
|
+
return {
|
|
65
|
+
...b,
|
|
66
|
+
text: rewriteReadImageHeader(b.text, sniffed),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return block;
|
|
70
|
+
});
|
|
71
|
+
return { ...result, content: nextContent };
|
|
72
|
+
}
|
|
73
|
+
function extractEnumValues(schema) {
|
|
74
|
+
if (!schema || typeof schema !== "object")
|
|
75
|
+
return undefined;
|
|
76
|
+
const record = schema;
|
|
77
|
+
if (Array.isArray(record.enum))
|
|
78
|
+
return record.enum;
|
|
79
|
+
if ("const" in record)
|
|
80
|
+
return [record.const];
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
function mergePropertySchemas(existing, incoming) {
|
|
84
|
+
if (!existing)
|
|
85
|
+
return incoming;
|
|
86
|
+
if (!incoming)
|
|
87
|
+
return existing;
|
|
88
|
+
const existingEnum = extractEnumValues(existing);
|
|
89
|
+
const incomingEnum = extractEnumValues(incoming);
|
|
90
|
+
if (existingEnum || incomingEnum) {
|
|
91
|
+
const values = Array.from(new Set([...(existingEnum ?? []), ...(incomingEnum ?? [])]));
|
|
92
|
+
const merged = {};
|
|
93
|
+
for (const source of [existing, incoming]) {
|
|
94
|
+
if (!source || typeof source !== "object")
|
|
95
|
+
continue;
|
|
96
|
+
const record = source;
|
|
97
|
+
for (const key of ["title", "description", "default"]) {
|
|
98
|
+
if (!(key in merged) && key in record)
|
|
99
|
+
merged[key] = record[key];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const types = new Set(values.map((value) => typeof value));
|
|
103
|
+
if (types.size === 1)
|
|
104
|
+
merged.type = Array.from(types)[0];
|
|
105
|
+
merged.enum = values;
|
|
106
|
+
return merged;
|
|
107
|
+
}
|
|
108
|
+
return existing;
|
|
109
|
+
}
|
|
110
|
+
function cleanSchemaForGemini(schema) {
|
|
111
|
+
if (!schema || typeof schema !== "object")
|
|
112
|
+
return schema;
|
|
113
|
+
if (Array.isArray(schema))
|
|
114
|
+
return schema.map(cleanSchemaForGemini);
|
|
115
|
+
const obj = schema;
|
|
116
|
+
const hasAnyOf = "anyOf" in obj && Array.isArray(obj.anyOf);
|
|
117
|
+
const cleaned = {};
|
|
118
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
119
|
+
// Skip unsupported schema features for Gemini:
|
|
120
|
+
// - patternProperties: not in OpenAPI 3.0 subset
|
|
121
|
+
// - const: convert to enum with single value instead
|
|
122
|
+
if (key === "patternProperties") {
|
|
123
|
+
// Gemini doesn't support patternProperties - skip it
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
// Convert const to enum (Gemini doesn't support const)
|
|
127
|
+
if (key === "const") {
|
|
128
|
+
cleaned.enum = [value];
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
// Skip 'type' if we have 'anyOf' — Gemini doesn't allow both
|
|
132
|
+
if (key === "type" && hasAnyOf) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (key === "properties" && value && typeof value === "object") {
|
|
136
|
+
// Recursively clean nested properties
|
|
137
|
+
const props = value;
|
|
138
|
+
cleaned[key] = Object.fromEntries(Object.entries(props).map(([k, v]) => [k, cleanSchemaForGemini(v)]));
|
|
139
|
+
}
|
|
140
|
+
else if (key === "items" && value && typeof value === "object") {
|
|
141
|
+
// Recursively clean array items schema
|
|
142
|
+
cleaned[key] = cleanSchemaForGemini(value);
|
|
143
|
+
}
|
|
144
|
+
else if (key === "anyOf" && Array.isArray(value)) {
|
|
145
|
+
// Clean each anyOf variant
|
|
146
|
+
cleaned[key] = value.map((variant) => cleanSchemaForGemini(variant));
|
|
147
|
+
}
|
|
148
|
+
else if (key === "oneOf" && Array.isArray(value)) {
|
|
149
|
+
// Clean each oneOf variant
|
|
150
|
+
cleaned[key] = value.map((variant) => cleanSchemaForGemini(variant));
|
|
151
|
+
}
|
|
152
|
+
else if (key === "allOf" && Array.isArray(value)) {
|
|
153
|
+
// Clean each allOf variant
|
|
154
|
+
cleaned[key] = value.map((variant) => cleanSchemaForGemini(variant));
|
|
155
|
+
}
|
|
156
|
+
else if (key === "additionalProperties" &&
|
|
157
|
+
value &&
|
|
158
|
+
typeof value === "object") {
|
|
159
|
+
// Recursively clean additionalProperties schema
|
|
160
|
+
cleaned[key] = cleanSchemaForGemini(value);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
cleaned[key] = value;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return cleaned;
|
|
167
|
+
}
|
|
168
|
+
function normalizeToolParameters(tool) {
|
|
169
|
+
const schema = tool.parameters && typeof tool.parameters === "object"
|
|
170
|
+
? tool.parameters
|
|
171
|
+
: undefined;
|
|
172
|
+
if (!schema)
|
|
173
|
+
return tool;
|
|
174
|
+
// If schema already has type + properties (no top-level anyOf to merge),
|
|
175
|
+
// still clean it for Gemini compatibility
|
|
176
|
+
if ("type" in schema &&
|
|
177
|
+
"properties" in schema &&
|
|
178
|
+
!Array.isArray(schema.anyOf)) {
|
|
179
|
+
return {
|
|
180
|
+
...tool,
|
|
181
|
+
parameters: cleanSchemaForGemini(schema),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
if (!Array.isArray(schema.anyOf))
|
|
185
|
+
return tool;
|
|
186
|
+
const mergedProperties = {};
|
|
187
|
+
const requiredCounts = new Map();
|
|
188
|
+
let objectVariants = 0;
|
|
189
|
+
for (const entry of schema.anyOf) {
|
|
190
|
+
if (!entry || typeof entry !== "object")
|
|
191
|
+
continue;
|
|
192
|
+
const props = entry.properties;
|
|
193
|
+
if (!props || typeof props !== "object")
|
|
194
|
+
continue;
|
|
195
|
+
objectVariants += 1;
|
|
196
|
+
for (const [key, value] of Object.entries(props)) {
|
|
197
|
+
if (!(key in mergedProperties)) {
|
|
198
|
+
mergedProperties[key] = value;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
mergedProperties[key] = mergePropertySchemas(mergedProperties[key], value);
|
|
202
|
+
}
|
|
203
|
+
const required = Array.isArray(entry.required)
|
|
204
|
+
? entry.required
|
|
205
|
+
: [];
|
|
206
|
+
for (const key of required) {
|
|
207
|
+
if (typeof key !== "string")
|
|
208
|
+
continue;
|
|
209
|
+
requiredCounts.set(key, (requiredCounts.get(key) ?? 0) + 1);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const baseRequired = Array.isArray(schema.required)
|
|
213
|
+
? schema.required.filter((key) => typeof key === "string")
|
|
214
|
+
: undefined;
|
|
215
|
+
const mergedRequired = baseRequired && baseRequired.length > 0
|
|
216
|
+
? baseRequired
|
|
217
|
+
: objectVariants > 0
|
|
218
|
+
? Array.from(requiredCounts.entries())
|
|
219
|
+
.filter(([, count]) => count === objectVariants)
|
|
220
|
+
.map(([key]) => key)
|
|
221
|
+
: undefined;
|
|
222
|
+
const nextSchema = { ...schema };
|
|
223
|
+
return {
|
|
224
|
+
...tool,
|
|
225
|
+
parameters: cleanSchemaForGemini({
|
|
226
|
+
...nextSchema,
|
|
227
|
+
type: nextSchema.type ?? "object",
|
|
228
|
+
properties: Object.keys(mergedProperties).length > 0
|
|
229
|
+
? mergedProperties
|
|
230
|
+
: (schema.properties ?? {}),
|
|
231
|
+
...(mergedRequired && mergedRequired.length > 0
|
|
232
|
+
? { required: mergedRequired }
|
|
233
|
+
: {}),
|
|
234
|
+
additionalProperties: "additionalProperties" in schema ? schema.additionalProperties : true,
|
|
235
|
+
}),
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
function normalizeToolNames(list) {
|
|
239
|
+
if (!list)
|
|
240
|
+
return [];
|
|
241
|
+
return list.map((entry) => entry.trim().toLowerCase()).filter(Boolean);
|
|
242
|
+
}
|
|
243
|
+
function filterToolsByPolicy(tools, policy) {
|
|
244
|
+
if (!policy)
|
|
245
|
+
return tools;
|
|
246
|
+
const deny = new Set(normalizeToolNames(policy.deny));
|
|
247
|
+
const allowRaw = normalizeToolNames(policy.allow);
|
|
248
|
+
const allow = allowRaw.length > 0 ? new Set(allowRaw) : null;
|
|
249
|
+
return tools.filter((tool) => {
|
|
250
|
+
const name = tool.name.toLowerCase();
|
|
251
|
+
if (deny.has(name))
|
|
252
|
+
return false;
|
|
253
|
+
if (allow)
|
|
254
|
+
return allow.has(name);
|
|
255
|
+
return true;
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
function wrapSandboxPathGuard(tool, root) {
|
|
259
|
+
return {
|
|
260
|
+
...tool,
|
|
261
|
+
execute: async (toolCallId, args, signal, onUpdate) => {
|
|
262
|
+
const record = args && typeof args === "object"
|
|
263
|
+
? args
|
|
264
|
+
: undefined;
|
|
265
|
+
const filePath = record?.path;
|
|
266
|
+
if (typeof filePath === "string" && filePath.trim()) {
|
|
267
|
+
await assertSandboxPath({ filePath, cwd: root, root });
|
|
268
|
+
}
|
|
269
|
+
return tool.execute(toolCallId, args, signal, onUpdate);
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
function createSandboxedReadTool(root) {
|
|
274
|
+
const base = createReadTool(root);
|
|
275
|
+
return wrapSandboxPathGuard(createClawdbotReadTool(base), root);
|
|
276
|
+
}
|
|
277
|
+
function createSandboxedWriteTool(root) {
|
|
278
|
+
const base = createWriteTool(root);
|
|
279
|
+
return wrapSandboxPathGuard(base, root);
|
|
280
|
+
}
|
|
281
|
+
function createSandboxedEditTool(root) {
|
|
282
|
+
const base = createEditTool(root);
|
|
283
|
+
return wrapSandboxPathGuard(base, root);
|
|
284
|
+
}
|
|
285
|
+
function createWhatsAppLoginTool() {
|
|
286
|
+
return {
|
|
287
|
+
label: "WhatsApp Login",
|
|
288
|
+
name: "whatsapp_login",
|
|
289
|
+
description: "Generate a WhatsApp QR code for linking, or wait for the scan to complete.",
|
|
290
|
+
parameters: Type.Object({
|
|
291
|
+
action: Type.Union([Type.Literal("start"), Type.Literal("wait")]),
|
|
292
|
+
timeoutMs: Type.Optional(Type.Number()),
|
|
293
|
+
force: Type.Optional(Type.Boolean()),
|
|
294
|
+
}),
|
|
295
|
+
execute: async (_toolCallId, args) => {
|
|
296
|
+
const action = args?.action ?? "start";
|
|
297
|
+
if (action === "wait") {
|
|
298
|
+
const result = await waitForWebLogin({
|
|
299
|
+
timeoutMs: typeof args.timeoutMs === "number"
|
|
300
|
+
? args.timeoutMs
|
|
301
|
+
: undefined,
|
|
302
|
+
});
|
|
303
|
+
return {
|
|
304
|
+
content: [{ type: "text", text: result.message }],
|
|
305
|
+
details: { connected: result.connected },
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
const result = await startWebLoginWithQr({
|
|
309
|
+
timeoutMs: typeof args.timeoutMs === "number"
|
|
310
|
+
? args.timeoutMs
|
|
311
|
+
: undefined,
|
|
312
|
+
force: typeof args.force === "boolean"
|
|
313
|
+
? args.force
|
|
314
|
+
: false,
|
|
315
|
+
});
|
|
316
|
+
if (!result.qrDataUrl) {
|
|
317
|
+
return {
|
|
318
|
+
content: [
|
|
319
|
+
{
|
|
320
|
+
type: "text",
|
|
321
|
+
text: result.message,
|
|
322
|
+
},
|
|
323
|
+
],
|
|
324
|
+
details: { qr: false },
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
const text = [
|
|
328
|
+
result.message,
|
|
329
|
+
"",
|
|
330
|
+
"Open WhatsApp → Linked Devices and scan:",
|
|
331
|
+
"",
|
|
332
|
+
``,
|
|
333
|
+
].join("\n");
|
|
334
|
+
return {
|
|
335
|
+
content: [{ type: "text", text }],
|
|
336
|
+
details: { qr: true },
|
|
337
|
+
};
|
|
338
|
+
},
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
function createClawdbotReadTool(base) {
|
|
342
|
+
return {
|
|
343
|
+
...base,
|
|
344
|
+
execute: async (toolCallId, params, signal) => {
|
|
345
|
+
const result = (await base.execute(toolCallId, params, signal));
|
|
346
|
+
const record = params && typeof params === "object"
|
|
347
|
+
? params
|
|
348
|
+
: undefined;
|
|
349
|
+
const filePath = typeof record?.path === "string" ? String(record.path) : "<unknown>";
|
|
350
|
+
const normalized = await normalizeReadImageResult(result, filePath);
|
|
351
|
+
return sanitizeToolResultImages(normalized, `read:${filePath}`);
|
|
352
|
+
},
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
function normalizeSurface(surface) {
|
|
356
|
+
const trimmed = surface?.trim().toLowerCase();
|
|
357
|
+
return trimmed ? trimmed : undefined;
|
|
358
|
+
}
|
|
359
|
+
function shouldIncludeDiscordTool(surface) {
|
|
360
|
+
const normalized = normalizeSurface(surface);
|
|
361
|
+
if (!normalized)
|
|
362
|
+
return false;
|
|
363
|
+
return normalized === "discord" || normalized.startsWith("discord:");
|
|
364
|
+
}
|
|
365
|
+
function shouldIncludeSlackTool(surface) {
|
|
366
|
+
const normalized = normalizeSurface(surface);
|
|
367
|
+
if (!normalized)
|
|
368
|
+
return false;
|
|
369
|
+
return normalized === "slack" || normalized.startsWith("slack:");
|
|
370
|
+
}
|
|
371
|
+
export function createClawdbotCodingTools(options) {
|
|
372
|
+
const bashToolName = "bash";
|
|
373
|
+
const sandbox = options?.sandbox?.enabled ? options.sandbox : undefined;
|
|
374
|
+
const sandboxRoot = sandbox?.workspaceDir;
|
|
375
|
+
const base = codingTools.flatMap((tool) => {
|
|
376
|
+
if (tool.name === readTool.name) {
|
|
377
|
+
return sandboxRoot
|
|
378
|
+
? [createSandboxedReadTool(sandboxRoot)]
|
|
379
|
+
: [createClawdbotReadTool(tool)];
|
|
380
|
+
}
|
|
381
|
+
if (tool.name === bashToolName)
|
|
382
|
+
return [];
|
|
383
|
+
if (sandboxRoot && (tool.name === "write" || tool.name === "edit")) {
|
|
384
|
+
return [];
|
|
385
|
+
}
|
|
386
|
+
return [tool];
|
|
387
|
+
});
|
|
388
|
+
const bashTool = createBashTool({
|
|
389
|
+
...options?.bash,
|
|
390
|
+
sandbox: sandbox
|
|
391
|
+
? {
|
|
392
|
+
containerName: sandbox.containerName,
|
|
393
|
+
workspaceDir: sandbox.workspaceDir,
|
|
394
|
+
containerWorkdir: sandbox.containerWorkdir,
|
|
395
|
+
env: sandbox.docker.env,
|
|
396
|
+
}
|
|
397
|
+
: undefined,
|
|
398
|
+
});
|
|
399
|
+
const processTool = createProcessTool({
|
|
400
|
+
cleanupMs: options?.bash?.cleanupMs,
|
|
401
|
+
});
|
|
402
|
+
const tools = [
|
|
403
|
+
...base,
|
|
404
|
+
...(sandboxRoot
|
|
405
|
+
? [
|
|
406
|
+
createSandboxedEditTool(sandboxRoot),
|
|
407
|
+
createSandboxedWriteTool(sandboxRoot),
|
|
408
|
+
]
|
|
409
|
+
: []),
|
|
410
|
+
bashTool,
|
|
411
|
+
processTool,
|
|
412
|
+
createWhatsAppLoginTool(),
|
|
413
|
+
...createClawdbotTools({
|
|
414
|
+
browserControlUrl: sandbox?.browser?.controlUrl,
|
|
415
|
+
agentSessionKey: options?.sessionKey,
|
|
416
|
+
agentSurface: options?.surface,
|
|
417
|
+
config: options?.config,
|
|
418
|
+
}),
|
|
419
|
+
];
|
|
420
|
+
const allowDiscord = shouldIncludeDiscordTool(options?.surface);
|
|
421
|
+
const allowSlack = shouldIncludeSlackTool(options?.surface);
|
|
422
|
+
const filtered = tools.filter((tool) => {
|
|
423
|
+
if (tool.name === "discord")
|
|
424
|
+
return allowDiscord;
|
|
425
|
+
if (tool.name === "slack")
|
|
426
|
+
return allowSlack;
|
|
427
|
+
return true;
|
|
428
|
+
});
|
|
429
|
+
const sandboxed = sandbox
|
|
430
|
+
? filterToolsByPolicy(filtered, sandbox.tools)
|
|
431
|
+
: filtered;
|
|
432
|
+
return sandboxed.map(normalizeToolParameters);
|
|
433
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
const UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
|
|
5
|
+
function normalizeUnicodeSpaces(str) {
|
|
6
|
+
return str.replace(UNICODE_SPACES, " ");
|
|
7
|
+
}
|
|
8
|
+
function expandPath(filePath) {
|
|
9
|
+
const normalized = normalizeUnicodeSpaces(filePath);
|
|
10
|
+
if (normalized === "~") {
|
|
11
|
+
return os.homedir();
|
|
12
|
+
}
|
|
13
|
+
if (normalized.startsWith("~/")) {
|
|
14
|
+
return os.homedir() + normalized.slice(1);
|
|
15
|
+
}
|
|
16
|
+
return normalized;
|
|
17
|
+
}
|
|
18
|
+
function resolveToCwd(filePath, cwd) {
|
|
19
|
+
const expanded = expandPath(filePath);
|
|
20
|
+
if (path.isAbsolute(expanded))
|
|
21
|
+
return expanded;
|
|
22
|
+
return path.resolve(cwd, expanded);
|
|
23
|
+
}
|
|
24
|
+
export function resolveSandboxPath(params) {
|
|
25
|
+
const resolved = resolveToCwd(params.filePath, params.cwd);
|
|
26
|
+
const rootResolved = path.resolve(params.root);
|
|
27
|
+
const relative = path.relative(rootResolved, resolved);
|
|
28
|
+
if (!relative || relative === "") {
|
|
29
|
+
return { resolved, relative: "" };
|
|
30
|
+
}
|
|
31
|
+
if (relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
32
|
+
throw new Error(`Path escapes sandbox root (${shortPath(rootResolved)}): ${params.filePath}`);
|
|
33
|
+
}
|
|
34
|
+
return { resolved, relative };
|
|
35
|
+
}
|
|
36
|
+
export async function assertSandboxPath(params) {
|
|
37
|
+
const resolved = resolveSandboxPath(params);
|
|
38
|
+
await assertNoSymlink(resolved.relative, path.resolve(params.root));
|
|
39
|
+
return resolved;
|
|
40
|
+
}
|
|
41
|
+
async function assertNoSymlink(relative, root) {
|
|
42
|
+
if (!relative)
|
|
43
|
+
return;
|
|
44
|
+
const parts = relative.split(path.sep).filter(Boolean);
|
|
45
|
+
let current = root;
|
|
46
|
+
for (const part of parts) {
|
|
47
|
+
current = path.join(current, part);
|
|
48
|
+
try {
|
|
49
|
+
const stat = await fs.lstat(current);
|
|
50
|
+
if (stat.isSymbolicLink()) {
|
|
51
|
+
throw new Error(`Symlink not allowed in sandbox path: ${current}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
const anyErr = err;
|
|
56
|
+
if (anyErr.code === "ENOENT") {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
throw err;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function shortPath(value) {
|
|
64
|
+
if (value.startsWith(os.homedir())) {
|
|
65
|
+
return `~${value.slice(os.homedir().length)}`;
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
}
|