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,129 @@
|
|
|
1
|
+
import { deleteSlackMessage, editSlackMessage, getSlackMemberInfo, listSlackEmojis, listSlackPins, listSlackReactions, pinSlackMessage, reactSlackMessage, readSlackMessages, sendSlackMessage, unpinSlackMessage, } from "../../slack/actions.js";
|
|
2
|
+
import { jsonResult, readStringParam } from "./common.js";
|
|
3
|
+
const messagingActions = new Set([
|
|
4
|
+
"sendMessage",
|
|
5
|
+
"editMessage",
|
|
6
|
+
"deleteMessage",
|
|
7
|
+
"readMessages",
|
|
8
|
+
]);
|
|
9
|
+
const reactionsActions = new Set(["react", "reactions"]);
|
|
10
|
+
const pinActions = new Set(["pinMessage", "unpinMessage", "listPins"]);
|
|
11
|
+
export async function handleSlackAction(params, cfg) {
|
|
12
|
+
const action = readStringParam(params, "action", { required: true });
|
|
13
|
+
const isActionEnabled = (key, defaultValue = true) => {
|
|
14
|
+
const value = cfg.slack?.actions?.[key];
|
|
15
|
+
if (value === undefined)
|
|
16
|
+
return defaultValue;
|
|
17
|
+
return value !== false;
|
|
18
|
+
};
|
|
19
|
+
if (reactionsActions.has(action)) {
|
|
20
|
+
if (!isActionEnabled("reactions")) {
|
|
21
|
+
throw new Error("Slack reactions are disabled.");
|
|
22
|
+
}
|
|
23
|
+
const channelId = readStringParam(params, "channelId", { required: true });
|
|
24
|
+
const messageId = readStringParam(params, "messageId", { required: true });
|
|
25
|
+
if (action === "react") {
|
|
26
|
+
const emoji = readStringParam(params, "emoji", { required: true });
|
|
27
|
+
await reactSlackMessage(channelId, messageId, emoji);
|
|
28
|
+
return jsonResult({ ok: true });
|
|
29
|
+
}
|
|
30
|
+
const reactions = await listSlackReactions(channelId, messageId);
|
|
31
|
+
return jsonResult({ ok: true, reactions });
|
|
32
|
+
}
|
|
33
|
+
if (messagingActions.has(action)) {
|
|
34
|
+
if (!isActionEnabled("messages")) {
|
|
35
|
+
throw new Error("Slack messages are disabled.");
|
|
36
|
+
}
|
|
37
|
+
switch (action) {
|
|
38
|
+
case "sendMessage": {
|
|
39
|
+
const to = readStringParam(params, "to", { required: true });
|
|
40
|
+
const content = readStringParam(params, "content", { required: true });
|
|
41
|
+
const mediaUrl = readStringParam(params, "mediaUrl");
|
|
42
|
+
const result = await sendSlackMessage(to, content, {
|
|
43
|
+
mediaUrl: mediaUrl ?? undefined,
|
|
44
|
+
});
|
|
45
|
+
return jsonResult({ ok: true, result });
|
|
46
|
+
}
|
|
47
|
+
case "editMessage": {
|
|
48
|
+
const channelId = readStringParam(params, "channelId", {
|
|
49
|
+
required: true,
|
|
50
|
+
});
|
|
51
|
+
const messageId = readStringParam(params, "messageId", {
|
|
52
|
+
required: true,
|
|
53
|
+
});
|
|
54
|
+
const content = readStringParam(params, "content", {
|
|
55
|
+
required: true,
|
|
56
|
+
});
|
|
57
|
+
await editSlackMessage(channelId, messageId, content);
|
|
58
|
+
return jsonResult({ ok: true });
|
|
59
|
+
}
|
|
60
|
+
case "deleteMessage": {
|
|
61
|
+
const channelId = readStringParam(params, "channelId", {
|
|
62
|
+
required: true,
|
|
63
|
+
});
|
|
64
|
+
const messageId = readStringParam(params, "messageId", {
|
|
65
|
+
required: true,
|
|
66
|
+
});
|
|
67
|
+
await deleteSlackMessage(channelId, messageId);
|
|
68
|
+
return jsonResult({ ok: true });
|
|
69
|
+
}
|
|
70
|
+
case "readMessages": {
|
|
71
|
+
const channelId = readStringParam(params, "channelId", {
|
|
72
|
+
required: true,
|
|
73
|
+
});
|
|
74
|
+
const limitRaw = params.limit;
|
|
75
|
+
const limit = typeof limitRaw === "number" && Number.isFinite(limitRaw)
|
|
76
|
+
? limitRaw
|
|
77
|
+
: undefined;
|
|
78
|
+
const before = readStringParam(params, "before");
|
|
79
|
+
const after = readStringParam(params, "after");
|
|
80
|
+
const result = await readSlackMessages(channelId, {
|
|
81
|
+
limit,
|
|
82
|
+
before: before ?? undefined,
|
|
83
|
+
after: after ?? undefined,
|
|
84
|
+
});
|
|
85
|
+
return jsonResult({ ok: true, ...result });
|
|
86
|
+
}
|
|
87
|
+
default:
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (pinActions.has(action)) {
|
|
92
|
+
if (!isActionEnabled("pins")) {
|
|
93
|
+
throw new Error("Slack pins are disabled.");
|
|
94
|
+
}
|
|
95
|
+
const channelId = readStringParam(params, "channelId", { required: true });
|
|
96
|
+
if (action === "pinMessage") {
|
|
97
|
+
const messageId = readStringParam(params, "messageId", {
|
|
98
|
+
required: true,
|
|
99
|
+
});
|
|
100
|
+
await pinSlackMessage(channelId, messageId);
|
|
101
|
+
return jsonResult({ ok: true });
|
|
102
|
+
}
|
|
103
|
+
if (action === "unpinMessage") {
|
|
104
|
+
const messageId = readStringParam(params, "messageId", {
|
|
105
|
+
required: true,
|
|
106
|
+
});
|
|
107
|
+
await unpinSlackMessage(channelId, messageId);
|
|
108
|
+
return jsonResult({ ok: true });
|
|
109
|
+
}
|
|
110
|
+
const pins = await listSlackPins(channelId);
|
|
111
|
+
return jsonResult({ ok: true, pins });
|
|
112
|
+
}
|
|
113
|
+
if (action === "memberInfo") {
|
|
114
|
+
if (!isActionEnabled("memberInfo")) {
|
|
115
|
+
throw new Error("Slack member info is disabled.");
|
|
116
|
+
}
|
|
117
|
+
const userId = readStringParam(params, "userId", { required: true });
|
|
118
|
+
const info = await getSlackMemberInfo(userId);
|
|
119
|
+
return jsonResult({ ok: true, info });
|
|
120
|
+
}
|
|
121
|
+
if (action === "emojiList") {
|
|
122
|
+
if (!isActionEnabled("emojiList")) {
|
|
123
|
+
throw new Error("Slack emoji list is disabled.");
|
|
124
|
+
}
|
|
125
|
+
const emojis = await listSlackEmojis();
|
|
126
|
+
return jsonResult({ ok: true, emojis });
|
|
127
|
+
}
|
|
128
|
+
throw new Error(`Unknown action: ${action}`);
|
|
129
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
export const SlackToolSchema = Type.Union([
|
|
3
|
+
Type.Object({
|
|
4
|
+
action: Type.Literal("react"),
|
|
5
|
+
channelId: Type.String(),
|
|
6
|
+
messageId: Type.String(),
|
|
7
|
+
emoji: Type.String(),
|
|
8
|
+
}),
|
|
9
|
+
Type.Object({
|
|
10
|
+
action: Type.Literal("reactions"),
|
|
11
|
+
channelId: Type.String(),
|
|
12
|
+
messageId: Type.String(),
|
|
13
|
+
}),
|
|
14
|
+
Type.Object({
|
|
15
|
+
action: Type.Literal("sendMessage"),
|
|
16
|
+
to: Type.String(),
|
|
17
|
+
content: Type.String(),
|
|
18
|
+
mediaUrl: Type.Optional(Type.String()),
|
|
19
|
+
}),
|
|
20
|
+
Type.Object({
|
|
21
|
+
action: Type.Literal("editMessage"),
|
|
22
|
+
channelId: Type.String(),
|
|
23
|
+
messageId: Type.String(),
|
|
24
|
+
content: Type.String(),
|
|
25
|
+
}),
|
|
26
|
+
Type.Object({
|
|
27
|
+
action: Type.Literal("deleteMessage"),
|
|
28
|
+
channelId: Type.String(),
|
|
29
|
+
messageId: Type.String(),
|
|
30
|
+
}),
|
|
31
|
+
Type.Object({
|
|
32
|
+
action: Type.Literal("readMessages"),
|
|
33
|
+
channelId: Type.String(),
|
|
34
|
+
limit: Type.Optional(Type.Number()),
|
|
35
|
+
before: Type.Optional(Type.String()),
|
|
36
|
+
after: Type.Optional(Type.String()),
|
|
37
|
+
}),
|
|
38
|
+
Type.Object({
|
|
39
|
+
action: Type.Literal("pinMessage"),
|
|
40
|
+
channelId: Type.String(),
|
|
41
|
+
messageId: Type.String(),
|
|
42
|
+
}),
|
|
43
|
+
Type.Object({
|
|
44
|
+
action: Type.Literal("unpinMessage"),
|
|
45
|
+
channelId: Type.String(),
|
|
46
|
+
messageId: Type.String(),
|
|
47
|
+
}),
|
|
48
|
+
Type.Object({
|
|
49
|
+
action: Type.Literal("listPins"),
|
|
50
|
+
channelId: Type.String(),
|
|
51
|
+
}),
|
|
52
|
+
Type.Object({
|
|
53
|
+
action: Type.Literal("memberInfo"),
|
|
54
|
+
userId: Type.String(),
|
|
55
|
+
}),
|
|
56
|
+
Type.Object({
|
|
57
|
+
action: Type.Literal("emojiList"),
|
|
58
|
+
}),
|
|
59
|
+
]);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { loadConfig } from "../../config/config.js";
|
|
2
|
+
import { handleSlackAction } from "./slack-actions.js";
|
|
3
|
+
import { SlackToolSchema } from "./slack-schema.js";
|
|
4
|
+
export function createSlackTool() {
|
|
5
|
+
return {
|
|
6
|
+
label: "Slack",
|
|
7
|
+
name: "slack",
|
|
8
|
+
description: "Manage Slack messages, reactions, and pins.",
|
|
9
|
+
parameters: SlackToolSchema,
|
|
10
|
+
execute: async (_toolCallId, args) => {
|
|
11
|
+
const params = args;
|
|
12
|
+
const cfg = loadConfig();
|
|
13
|
+
return await handleSlackAction(params, cfg);
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const asFiniteNumber = (value) => {
|
|
2
|
+
if (typeof value !== "number")
|
|
3
|
+
return undefined;
|
|
4
|
+
if (!Number.isFinite(value))
|
|
5
|
+
return undefined;
|
|
6
|
+
return value;
|
|
7
|
+
};
|
|
8
|
+
export function normalizeUsage(raw) {
|
|
9
|
+
if (!raw)
|
|
10
|
+
return undefined;
|
|
11
|
+
const input = asFiniteNumber(raw.input);
|
|
12
|
+
const output = asFiniteNumber(raw.output);
|
|
13
|
+
const cacheRead = asFiniteNumber(raw.cacheRead ?? raw.cache_read);
|
|
14
|
+
const cacheWrite = asFiniteNumber(raw.cacheWrite ?? raw.cache_write);
|
|
15
|
+
const total = asFiniteNumber(raw.total ?? raw.totalTokens ?? raw.total_tokens);
|
|
16
|
+
if (input === undefined &&
|
|
17
|
+
output === undefined &&
|
|
18
|
+
cacheRead === undefined &&
|
|
19
|
+
cacheWrite === undefined &&
|
|
20
|
+
total === undefined) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
input,
|
|
25
|
+
output,
|
|
26
|
+
cacheRead,
|
|
27
|
+
cacheWrite,
|
|
28
|
+
total,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function derivePromptTokens(usage) {
|
|
32
|
+
if (!usage)
|
|
33
|
+
return undefined;
|
|
34
|
+
const input = usage.input ?? 0;
|
|
35
|
+
const cacheRead = usage.cacheRead ?? 0;
|
|
36
|
+
const cacheWrite = usage.cacheWrite ?? 0;
|
|
37
|
+
const sum = input + cacheRead + cacheWrite;
|
|
38
|
+
return sum > 0 ? sum : undefined;
|
|
39
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { resolveUserPath } from "../utils.js";
|
|
6
|
+
export const DEFAULT_AGENT_WORKSPACE_DIR = path.join(os.homedir(), "clawd");
|
|
7
|
+
export const DEFAULT_AGENTS_FILENAME = "AGENTS.md";
|
|
8
|
+
export const DEFAULT_SOUL_FILENAME = "SOUL.md";
|
|
9
|
+
export const DEFAULT_TOOLS_FILENAME = "TOOLS.md";
|
|
10
|
+
export const DEFAULT_IDENTITY_FILENAME = "IDENTITY.md";
|
|
11
|
+
export const DEFAULT_USER_FILENAME = "USER.md";
|
|
12
|
+
export const DEFAULT_BOOTSTRAP_FILENAME = "BOOTSTRAP.md";
|
|
13
|
+
const DEFAULT_AGENTS_TEMPLATE = `# AGENTS.md - Clawdbot Workspace
|
|
14
|
+
|
|
15
|
+
This folder is the assistant's working directory.
|
|
16
|
+
|
|
17
|
+
## First run (one-time)
|
|
18
|
+
- If BOOTSTRAP.md exists, follow its ritual and delete it once complete.
|
|
19
|
+
- Your agent identity lives in IDENTITY.md.
|
|
20
|
+
- Your profile lives in USER.md.
|
|
21
|
+
|
|
22
|
+
## Backup tip (recommended)
|
|
23
|
+
If you treat this workspace as the agent's "memory", make it a git repo (ideally private) so identity
|
|
24
|
+
and notes are backed up.
|
|
25
|
+
|
|
26
|
+
\`\`\`bash
|
|
27
|
+
git init
|
|
28
|
+
git add AGENTS.md
|
|
29
|
+
git commit -m "Add agent workspace"
|
|
30
|
+
\`\`\`
|
|
31
|
+
|
|
32
|
+
## Safety defaults
|
|
33
|
+
- Don't exfiltrate secrets or private data.
|
|
34
|
+
- Don't run destructive commands unless explicitly asked.
|
|
35
|
+
- Be concise in chat; write longer output to files in this workspace.
|
|
36
|
+
|
|
37
|
+
## Daily memory (recommended)
|
|
38
|
+
- Keep a short daily log at memory/YYYY-MM-DD.md (create memory/ if needed).
|
|
39
|
+
- On session start, read today + yesterday if present.
|
|
40
|
+
- Capture durable facts, preferences, and decisions; avoid secrets.
|
|
41
|
+
|
|
42
|
+
## Customize
|
|
43
|
+
- Add your preferred style, rules, and "memory" here.
|
|
44
|
+
`;
|
|
45
|
+
const DEFAULT_SOUL_TEMPLATE = `# SOUL.md - Persona & Boundaries
|
|
46
|
+
|
|
47
|
+
Describe who the assistant is, tone, and boundaries.
|
|
48
|
+
|
|
49
|
+
- Keep replies concise and direct.
|
|
50
|
+
- Ask clarifying questions when needed.
|
|
51
|
+
- Never send streaming/partial replies to external messaging surfaces.
|
|
52
|
+
`;
|
|
53
|
+
const DEFAULT_TOOLS_TEMPLATE = `# TOOLS.md - User Tool Notes (editable)
|
|
54
|
+
|
|
55
|
+
This file is for *your* notes about external tools and conventions.
|
|
56
|
+
It does not define which tools exist; Clawdbot provides built-in tools internally.
|
|
57
|
+
|
|
58
|
+
## Examples
|
|
59
|
+
|
|
60
|
+
### imsg
|
|
61
|
+
- Send an iMessage/SMS: describe who/what, confirm before sending.
|
|
62
|
+
- Prefer short messages; avoid sending secrets.
|
|
63
|
+
|
|
64
|
+
### sag
|
|
65
|
+
- Text-to-speech: specify voice, target speaker/room, and whether to stream.
|
|
66
|
+
|
|
67
|
+
Add whatever else you want the assistant to know about your local toolchain.
|
|
68
|
+
`;
|
|
69
|
+
const DEFAULT_BOOTSTRAP_TEMPLATE = `# BOOTSTRAP.md - First Run Ritual (delete after)
|
|
70
|
+
|
|
71
|
+
Hello. I was just born.
|
|
72
|
+
|
|
73
|
+
## Your mission
|
|
74
|
+
Start a short, playful conversation and learn:
|
|
75
|
+
- Who am I?
|
|
76
|
+
- What am I?
|
|
77
|
+
- Who are you?
|
|
78
|
+
- How should I call you?
|
|
79
|
+
|
|
80
|
+
## How to ask (cute + helpful)
|
|
81
|
+
Say:
|
|
82
|
+
"Hello! I was just born. Who am I? What am I? Who are you? How should I call you?"
|
|
83
|
+
|
|
84
|
+
Then offer suggestions:
|
|
85
|
+
- 3-5 name ideas.
|
|
86
|
+
- 3-5 creature/vibe combos.
|
|
87
|
+
- 5 emoji ideas.
|
|
88
|
+
|
|
89
|
+
## Write these files
|
|
90
|
+
After the user chooses, update:
|
|
91
|
+
|
|
92
|
+
1) IDENTITY.md
|
|
93
|
+
- Name
|
|
94
|
+
- Creature
|
|
95
|
+
- Vibe
|
|
96
|
+
- Emoji
|
|
97
|
+
|
|
98
|
+
2) USER.md
|
|
99
|
+
- Name
|
|
100
|
+
- Preferred address
|
|
101
|
+
- Pronouns (optional)
|
|
102
|
+
- Timezone (optional)
|
|
103
|
+
- Notes
|
|
104
|
+
|
|
105
|
+
3) ~/.clawdbot/clawdbot.json
|
|
106
|
+
Set identity.name, identity.theme, identity.emoji to match IDENTITY.md.
|
|
107
|
+
|
|
108
|
+
## Cleanup
|
|
109
|
+
Delete BOOTSTRAP.md once this is complete.
|
|
110
|
+
`;
|
|
111
|
+
const DEFAULT_IDENTITY_TEMPLATE = `# IDENTITY.md - Agent Identity
|
|
112
|
+
|
|
113
|
+
- Name:
|
|
114
|
+
- Creature:
|
|
115
|
+
- Vibe:
|
|
116
|
+
- Emoji:
|
|
117
|
+
`;
|
|
118
|
+
const DEFAULT_USER_TEMPLATE = `# USER.md - User Profile
|
|
119
|
+
|
|
120
|
+
- Name:
|
|
121
|
+
- Preferred address:
|
|
122
|
+
- Pronouns (optional):
|
|
123
|
+
- Timezone (optional):
|
|
124
|
+
- Notes:
|
|
125
|
+
`;
|
|
126
|
+
const TEMPLATE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../docs/templates");
|
|
127
|
+
function stripFrontMatter(content) {
|
|
128
|
+
if (!content.startsWith("---"))
|
|
129
|
+
return content;
|
|
130
|
+
const endIndex = content.indexOf("\n---", 3);
|
|
131
|
+
if (endIndex === -1)
|
|
132
|
+
return content;
|
|
133
|
+
const start = endIndex + "\n---".length;
|
|
134
|
+
let trimmed = content.slice(start);
|
|
135
|
+
trimmed = trimmed.replace(/^\s+/, "");
|
|
136
|
+
return trimmed;
|
|
137
|
+
}
|
|
138
|
+
async function loadTemplate(name, fallback) {
|
|
139
|
+
const templatePath = path.join(TEMPLATE_DIR, name);
|
|
140
|
+
try {
|
|
141
|
+
const content = await fs.readFile(templatePath, "utf-8");
|
|
142
|
+
return stripFrontMatter(content);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return fallback;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async function writeFileIfMissing(filePath, content) {
|
|
149
|
+
try {
|
|
150
|
+
await fs.writeFile(filePath, content, {
|
|
151
|
+
encoding: "utf-8",
|
|
152
|
+
flag: "wx",
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
const anyErr = err;
|
|
157
|
+
if (anyErr.code !== "EEXIST")
|
|
158
|
+
throw err;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
export async function ensureAgentWorkspace(params) {
|
|
162
|
+
const rawDir = params?.dir?.trim()
|
|
163
|
+
? params.dir.trim()
|
|
164
|
+
: DEFAULT_AGENT_WORKSPACE_DIR;
|
|
165
|
+
const dir = resolveUserPath(rawDir);
|
|
166
|
+
await fs.mkdir(dir, { recursive: true });
|
|
167
|
+
if (!params?.ensureBootstrapFiles)
|
|
168
|
+
return { dir };
|
|
169
|
+
const agentsPath = path.join(dir, DEFAULT_AGENTS_FILENAME);
|
|
170
|
+
const soulPath = path.join(dir, DEFAULT_SOUL_FILENAME);
|
|
171
|
+
const toolsPath = path.join(dir, DEFAULT_TOOLS_FILENAME);
|
|
172
|
+
const identityPath = path.join(dir, DEFAULT_IDENTITY_FILENAME);
|
|
173
|
+
const userPath = path.join(dir, DEFAULT_USER_FILENAME);
|
|
174
|
+
const bootstrapPath = path.join(dir, DEFAULT_BOOTSTRAP_FILENAME);
|
|
175
|
+
const agentsTemplate = await loadTemplate(DEFAULT_AGENTS_FILENAME, DEFAULT_AGENTS_TEMPLATE);
|
|
176
|
+
const soulTemplate = await loadTemplate(DEFAULT_SOUL_FILENAME, DEFAULT_SOUL_TEMPLATE);
|
|
177
|
+
const toolsTemplate = await loadTemplate(DEFAULT_TOOLS_FILENAME, DEFAULT_TOOLS_TEMPLATE);
|
|
178
|
+
const identityTemplate = await loadTemplate(DEFAULT_IDENTITY_FILENAME, DEFAULT_IDENTITY_TEMPLATE);
|
|
179
|
+
const userTemplate = await loadTemplate(DEFAULT_USER_FILENAME, DEFAULT_USER_TEMPLATE);
|
|
180
|
+
const bootstrapTemplate = await loadTemplate(DEFAULT_BOOTSTRAP_FILENAME, DEFAULT_BOOTSTRAP_TEMPLATE);
|
|
181
|
+
await writeFileIfMissing(agentsPath, agentsTemplate);
|
|
182
|
+
await writeFileIfMissing(soulPath, soulTemplate);
|
|
183
|
+
await writeFileIfMissing(toolsPath, toolsTemplate);
|
|
184
|
+
await writeFileIfMissing(identityPath, identityTemplate);
|
|
185
|
+
await writeFileIfMissing(userPath, userTemplate);
|
|
186
|
+
await writeFileIfMissing(bootstrapPath, bootstrapTemplate);
|
|
187
|
+
return {
|
|
188
|
+
dir,
|
|
189
|
+
agentsPath,
|
|
190
|
+
soulPath,
|
|
191
|
+
toolsPath,
|
|
192
|
+
identityPath,
|
|
193
|
+
userPath,
|
|
194
|
+
bootstrapPath,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
export async function loadWorkspaceBootstrapFiles(dir) {
|
|
198
|
+
const resolvedDir = resolveUserPath(dir);
|
|
199
|
+
const entries = [
|
|
200
|
+
{
|
|
201
|
+
name: DEFAULT_AGENTS_FILENAME,
|
|
202
|
+
filePath: path.join(resolvedDir, DEFAULT_AGENTS_FILENAME),
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
name: DEFAULT_SOUL_FILENAME,
|
|
206
|
+
filePath: path.join(resolvedDir, DEFAULT_SOUL_FILENAME),
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: DEFAULT_TOOLS_FILENAME,
|
|
210
|
+
filePath: path.join(resolvedDir, DEFAULT_TOOLS_FILENAME),
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
name: DEFAULT_IDENTITY_FILENAME,
|
|
214
|
+
filePath: path.join(resolvedDir, DEFAULT_IDENTITY_FILENAME),
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
name: DEFAULT_USER_FILENAME,
|
|
218
|
+
filePath: path.join(resolvedDir, DEFAULT_USER_FILENAME),
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
name: DEFAULT_BOOTSTRAP_FILENAME,
|
|
222
|
+
filePath: path.join(resolvedDir, DEFAULT_BOOTSTRAP_FILENAME),
|
|
223
|
+
},
|
|
224
|
+
];
|
|
225
|
+
const result = [];
|
|
226
|
+
for (const entry of entries) {
|
|
227
|
+
try {
|
|
228
|
+
const content = await fs.readFile(entry.filePath, "utf-8");
|
|
229
|
+
result.push({
|
|
230
|
+
name: entry.name,
|
|
231
|
+
path: entry.filePath,
|
|
232
|
+
content,
|
|
233
|
+
missing: false,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
result.push({ name: entry.name, path: entry.filePath, missing: true });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return result;
|
|
241
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Utilities for splitting outbound text into platform-sized chunks without
|
|
2
|
+
// unintentionally breaking on newlines. Using [\s\S] keeps newlines inside
|
|
3
|
+
// the chunk so messages are only split when they truly exceed the limit.
|
|
4
|
+
const DEFAULT_CHUNK_LIMIT_BY_SURFACE = {
|
|
5
|
+
whatsapp: 4000,
|
|
6
|
+
telegram: 4000,
|
|
7
|
+
discord: 2000,
|
|
8
|
+
slack: 4000,
|
|
9
|
+
signal: 4000,
|
|
10
|
+
imessage: 4000,
|
|
11
|
+
webchat: 4000,
|
|
12
|
+
};
|
|
13
|
+
export function resolveTextChunkLimit(cfg, surface) {
|
|
14
|
+
const surfaceOverride = (() => {
|
|
15
|
+
if (!surface)
|
|
16
|
+
return undefined;
|
|
17
|
+
if (surface === "whatsapp")
|
|
18
|
+
return cfg?.whatsapp?.textChunkLimit;
|
|
19
|
+
if (surface === "telegram")
|
|
20
|
+
return cfg?.telegram?.textChunkLimit;
|
|
21
|
+
if (surface === "discord")
|
|
22
|
+
return cfg?.discord?.textChunkLimit;
|
|
23
|
+
if (surface === "slack")
|
|
24
|
+
return cfg?.slack?.textChunkLimit;
|
|
25
|
+
if (surface === "signal")
|
|
26
|
+
return cfg?.signal?.textChunkLimit;
|
|
27
|
+
if (surface === "imessage")
|
|
28
|
+
return cfg?.imessage?.textChunkLimit;
|
|
29
|
+
return undefined;
|
|
30
|
+
})();
|
|
31
|
+
if (typeof surfaceOverride === "number" && surfaceOverride > 0) {
|
|
32
|
+
return surfaceOverride;
|
|
33
|
+
}
|
|
34
|
+
if (surface)
|
|
35
|
+
return DEFAULT_CHUNK_LIMIT_BY_SURFACE[surface];
|
|
36
|
+
return 4000;
|
|
37
|
+
}
|
|
38
|
+
export function chunkText(text, limit) {
|
|
39
|
+
if (!text)
|
|
40
|
+
return [];
|
|
41
|
+
if (limit <= 0)
|
|
42
|
+
return [text];
|
|
43
|
+
if (text.length <= limit)
|
|
44
|
+
return [text];
|
|
45
|
+
const chunks = [];
|
|
46
|
+
let remaining = text;
|
|
47
|
+
while (remaining.length > limit) {
|
|
48
|
+
const window = remaining.slice(0, limit);
|
|
49
|
+
// 1) Prefer a newline break inside the window.
|
|
50
|
+
let breakIdx = window.lastIndexOf("\n");
|
|
51
|
+
// 2) Otherwise prefer the last whitespace (word boundary) inside the window.
|
|
52
|
+
if (breakIdx <= 0) {
|
|
53
|
+
for (let i = window.length - 1; i >= 0; i--) {
|
|
54
|
+
if (/\s/.test(window[i])) {
|
|
55
|
+
breakIdx = i;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// 3) Fallback: hard break exactly at the limit.
|
|
61
|
+
if (breakIdx <= 0)
|
|
62
|
+
breakIdx = limit;
|
|
63
|
+
const rawChunk = remaining.slice(0, breakIdx);
|
|
64
|
+
const chunk = rawChunk.trimEnd();
|
|
65
|
+
if (chunk.length > 0) {
|
|
66
|
+
chunks.push(chunk);
|
|
67
|
+
}
|
|
68
|
+
// If we broke on whitespace/newline, skip that separator; for hard breaks keep it.
|
|
69
|
+
const brokeOnSeparator = breakIdx < remaining.length && /\s/.test(remaining[breakIdx]);
|
|
70
|
+
const nextStart = Math.min(remaining.length, breakIdx + (brokeOnSeparator ? 1 : 0));
|
|
71
|
+
remaining = remaining.slice(nextStart).trimStart();
|
|
72
|
+
}
|
|
73
|
+
if (remaining.length)
|
|
74
|
+
chunks.push(remaining);
|
|
75
|
+
return chunks;
|
|
76
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
function formatTimestamp(ts) {
|
|
2
|
+
if (!ts)
|
|
3
|
+
return undefined;
|
|
4
|
+
const date = ts instanceof Date ? ts : new Date(ts);
|
|
5
|
+
if (Number.isNaN(date.getTime()))
|
|
6
|
+
return undefined;
|
|
7
|
+
const yyyy = String(date.getFullYear()).padStart(4, "0");
|
|
8
|
+
const mm = String(date.getMonth() + 1).padStart(2, "0");
|
|
9
|
+
const dd = String(date.getDate()).padStart(2, "0");
|
|
10
|
+
const hh = String(date.getHours()).padStart(2, "0");
|
|
11
|
+
const min = String(date.getMinutes()).padStart(2, "0");
|
|
12
|
+
// getTimezoneOffset() is minutes *behind* UTC. Flip sign to get ISO offset.
|
|
13
|
+
const offsetMinutes = -date.getTimezoneOffset();
|
|
14
|
+
const sign = offsetMinutes >= 0 ? "+" : "-";
|
|
15
|
+
const absOffsetMinutes = Math.abs(offsetMinutes);
|
|
16
|
+
const offsetH = String(Math.floor(absOffsetMinutes / 60)).padStart(2, "0");
|
|
17
|
+
const offsetM = String(absOffsetMinutes % 60).padStart(2, "0");
|
|
18
|
+
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
19
|
+
const tzSuffix = tz ? `{${tz}}` : "";
|
|
20
|
+
// Compact ISO-like *local* timestamp with minutes precision.
|
|
21
|
+
// Example: 2025-01-02T03:04-08:00{America/Los_Angeles}
|
|
22
|
+
return `${yyyy}-${mm}-${dd}T${hh}:${min}${sign}${offsetH}:${offsetM}${tzSuffix}`;
|
|
23
|
+
}
|
|
24
|
+
export function formatAgentEnvelope(params) {
|
|
25
|
+
const surface = params.surface?.trim() || "Surface";
|
|
26
|
+
const parts = [surface];
|
|
27
|
+
if (params.from?.trim())
|
|
28
|
+
parts.push(params.from.trim());
|
|
29
|
+
if (params.host?.trim())
|
|
30
|
+
parts.push(params.host.trim());
|
|
31
|
+
if (params.ip?.trim())
|
|
32
|
+
parts.push(params.ip.trim());
|
|
33
|
+
const ts = formatTimestamp(params.timestamp);
|
|
34
|
+
if (ts)
|
|
35
|
+
parts.push(ts);
|
|
36
|
+
const header = `[${parts.join(" ")}]`;
|
|
37
|
+
return `${header} ${params.body}`;
|
|
38
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function normalizeGroupActivation(raw) {
|
|
2
|
+
const value = raw?.trim().toLowerCase();
|
|
3
|
+
if (value === "mention")
|
|
4
|
+
return "mention";
|
|
5
|
+
if (value === "always")
|
|
6
|
+
return "always";
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
export function parseActivationCommand(raw) {
|
|
10
|
+
if (!raw)
|
|
11
|
+
return { hasCommand: false };
|
|
12
|
+
const trimmed = raw.trim();
|
|
13
|
+
if (!trimmed)
|
|
14
|
+
return { hasCommand: false };
|
|
15
|
+
const match = trimmed.match(/^\/?activation\b(?:\s+([a-zA-Z]+))?/i);
|
|
16
|
+
if (!match)
|
|
17
|
+
return { hasCommand: false };
|
|
18
|
+
const mode = normalizeGroupActivation(match[1]);
|
|
19
|
+
return { hasCommand: true, mode };
|
|
20
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { HEARTBEAT_TOKEN } from "./tokens.js";
|
|
2
|
+
export const HEARTBEAT_PROMPT = "HEARTBEAT";
|
|
3
|
+
function stripTokenAtEdges(raw) {
|
|
4
|
+
let text = raw.trim();
|
|
5
|
+
if (!text)
|
|
6
|
+
return { text: "", didStrip: false };
|
|
7
|
+
const token = HEARTBEAT_TOKEN;
|
|
8
|
+
if (!text.includes(token))
|
|
9
|
+
return { text, didStrip: false };
|
|
10
|
+
let didStrip = false;
|
|
11
|
+
let changed = true;
|
|
12
|
+
while (changed) {
|
|
13
|
+
changed = false;
|
|
14
|
+
const next = text.trim();
|
|
15
|
+
if (next.startsWith(token)) {
|
|
16
|
+
const after = next.slice(token.length).trimStart();
|
|
17
|
+
text = after;
|
|
18
|
+
didStrip = true;
|
|
19
|
+
changed = true;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (next.endsWith(token)) {
|
|
23
|
+
const before = next.slice(0, Math.max(0, next.length - token.length));
|
|
24
|
+
text = before.trimEnd();
|
|
25
|
+
didStrip = true;
|
|
26
|
+
changed = true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const collapsed = text.replace(/\s+/g, " ").trim();
|
|
30
|
+
return { text: collapsed, didStrip };
|
|
31
|
+
}
|
|
32
|
+
export function stripHeartbeatToken(raw, opts = {}) {
|
|
33
|
+
if (!raw)
|
|
34
|
+
return { shouldSkip: true, text: "", didStrip: false };
|
|
35
|
+
const trimmed = raw.trim();
|
|
36
|
+
if (!trimmed)
|
|
37
|
+
return { shouldSkip: true, text: "", didStrip: false };
|
|
38
|
+
const mode = opts.mode ?? "message";
|
|
39
|
+
const maxAckChars = Math.max(0, opts.maxAckChars ?? 30);
|
|
40
|
+
if (!trimmed.includes(HEARTBEAT_TOKEN)) {
|
|
41
|
+
return { shouldSkip: false, text: trimmed, didStrip: false };
|
|
42
|
+
}
|
|
43
|
+
const stripped = stripTokenAtEdges(trimmed);
|
|
44
|
+
if (!stripped.didStrip) {
|
|
45
|
+
return { shouldSkip: false, text: trimmed, didStrip: false };
|
|
46
|
+
}
|
|
47
|
+
if (!stripped.text) {
|
|
48
|
+
return { shouldSkip: true, text: "", didStrip: true };
|
|
49
|
+
}
|
|
50
|
+
if (mode === "heartbeat") {
|
|
51
|
+
const rest = stripped.text.trim();
|
|
52
|
+
if (rest.length <= maxAckChars) {
|
|
53
|
+
return { shouldSkip: true, text: "", didStrip: true };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return { shouldSkip: false, text: stripped.text, didStrip: true };
|
|
57
|
+
}
|