@poolzin/pool-bot 2026.2.17 → 2026.2.19
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 +25 -0
- package/dist/agents/agent-scope.js +4 -0
- package/dist/agents/announce-idempotency.js +14 -0
- package/dist/agents/auth-profiles.resolve-auth-profile-order.fixtures.js +23 -0
- package/dist/agents/bash-tools.exec-runtime.js +438 -0
- package/dist/agents/bash-tools.shared.js +6 -0
- package/dist/agents/cli-runner/reliability.js +61 -0
- package/dist/agents/cli-watchdog-defaults.js +11 -0
- package/dist/agents/command-poll-backoff.js +63 -0
- package/dist/agents/current-time.js +16 -0
- package/dist/agents/model-alias-lines.js +18 -0
- package/dist/agents/model-auth-label.js +61 -0
- package/dist/agents/models-config.e2e-harness.js +115 -0
- package/dist/agents/ollama-stream.js +11 -3
- package/dist/agents/openclaw-tools.js +135 -0
- package/dist/agents/pi-auth-json.js +118 -0
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +147 -0
- package/dist/agents/pi-embedded-subscribe.e2e-harness.js +90 -0
- package/dist/agents/pi-embedded-subscribe.handlers.compaction.js +63 -0
- package/dist/agents/pi-embedded-subscribe.handlers.tools.media.test-helpers.js +30 -0
- package/dist/agents/pi-extensions/session-manager-runtime-registry.js +23 -0
- package/dist/agents/pi-tools.js +2 -0
- package/dist/agents/queued-file-writer.js +22 -0
- package/dist/agents/sandbox/docker.js +133 -40
- package/dist/agents/sandbox/fs-bridge.js +146 -0
- package/dist/agents/sandbox/fs-paths.js +205 -0
- package/dist/agents/sandbox/hash.js +4 -0
- package/dist/agents/sandbox-paths.js +3 -0
- package/dist/agents/session-dirs.js +20 -0
- package/dist/agents/skills/filter.js +24 -0
- package/dist/agents/skills/tools-dir.js +9 -0
- package/dist/agents/skills-install-download.js +290 -0
- package/dist/agents/skills-install-output.js +30 -0
- package/dist/agents/skills-install.download-test-utils.js +36 -0
- package/dist/agents/skills.e2e-test-helpers.js +13 -0
- package/dist/agents/subagent-announce-queue.js +59 -15
- package/dist/agents/subagent-depth.js +137 -0
- package/dist/agents/subagent-registry.js +448 -96
- package/dist/agents/subagent-spawn.js +262 -0
- package/dist/agents/test-helpers/fast-tool-stubs.js +18 -0
- package/dist/agents/test-helpers/host-sandbox-fs-bridge.js +74 -0
- package/dist/agents/tool-display-common.js +782 -0
- package/dist/agents/tools/image-tool.js +1 -1
- package/dist/agents/tools/sessions-access.js +178 -0
- package/dist/agents/tools/sessions-resolution.js +206 -0
- package/dist/agents/tools/subagents-tool.js +616 -0
- package/dist/agents/workspace-dir.js +18 -0
- package/dist/agents/workspace-dirs.js +14 -0
- package/dist/agents/workspace.js +70 -0
- package/dist/auto-reply/heartbeat-reply-payload.js +18 -0
- package/dist/auto-reply/reply/commands-export-session.js +163 -0
- package/dist/auto-reply/reply/commands-mesh.js +245 -0
- package/dist/auto-reply/reply/commands-setunset.js +28 -0
- package/dist/auto-reply/reply/commands-slash-parse.js +31 -0
- package/dist/auto-reply/reply/commands-system-prompt.js +117 -0
- package/dist/auto-reply/reply/directive-handling.levels.js +17 -0
- package/dist/auto-reply/reply/directive-handling.params.js +1 -0
- package/dist/auto-reply/reply/directive-parsing.js +36 -0
- package/dist/auto-reply/reply/dispatcher-registry.js +43 -0
- package/dist/auto-reply/reply/elevated-unavailable.js +20 -0
- package/dist/auto-reply/reply/reply-delivery.js +92 -0
- package/dist/auto-reply/reply/session-reset-prompt.js +1 -0
- package/dist/auto-reply/reply/session-run-accounting.js +33 -0
- package/dist/auto-reply/reply.directive.directive-behavior.e2e-harness.js +115 -0
- package/dist/auto-reply/reply.directive.directive-behavior.e2e-mocks.js +12 -0
- package/dist/browser/bridge-auth-registry.js +26 -0
- package/dist/browser/client-actions-url.js +10 -0
- package/dist/browser/control-auth.js +73 -0
- package/dist/browser/csrf.js +64 -0
- package/dist/browser/http-auth.js +52 -0
- package/dist/browser/paths.js +37 -0
- package/dist/browser/proxy-files.js +32 -0
- package/dist/browser/pw-ai-state.js +7 -0
- package/dist/browser/resolved-config-refresh.js +42 -0
- package/dist/browser/routes/path-output.js +1 -0
- package/dist/browser/server-context.chrome-test-harness.js +20 -0
- package/dist/browser/server-middleware.js +31 -0
- package/dist/browser/test-port.js +16 -0
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/file-resolver.js +43 -0
- package/dist/channels/account-summary.js +19 -0
- package/dist/channels/draft-stream-loop.js +77 -0
- package/dist/channels/plugins/account-helpers.js +26 -0
- package/dist/channels/telegram/allow-from.js +10 -0
- package/dist/cli/browser-cli-resize.js +22 -0
- package/dist/cli/browser-cli-shared.js +8 -0
- package/dist/cli/clawbot-cli.js +5 -0
- package/dist/cli/completion-cli.js +566 -0
- package/dist/cli/config-cli.js +63 -5
- package/dist/cli/daemon-cli/lifecycle-core.js +256 -0
- package/dist/cli/daemon-cli/register-service-commands.js +60 -0
- package/dist/cli/daemon-cli-compat.js +80 -0
- package/dist/cli/nodes-cli/pairing-render.js +26 -0
- package/dist/cli/program/action-reparse.js +17 -0
- package/dist/cli/program/command-registry.js +17 -0
- package/dist/cli/program/program-context.js +8 -0
- package/dist/cli/program/register.subclis.js +7 -0
- package/dist/cli/program/routes.js +233 -0
- package/dist/cli/qr-cli.js +132 -0
- package/dist/cli/requirements-test-fixtures.js +17 -0
- package/dist/cli/respawn-policy.js +4 -0
- package/dist/cli/shared/parse-port.js +18 -0
- package/dist/cli/skills-cli.format.js +241 -0
- package/dist/cli/update-cli/progress.js +121 -0
- package/dist/cli/update-cli/restart-helper.js +108 -0
- package/dist/cli/update-cli/shared.js +196 -0
- package/dist/cli/update-cli/status.js +97 -0
- package/dist/cli/update-cli/suppress-deprecations.js +17 -0
- package/dist/cli/update-cli/update-command.js +506 -0
- package/dist/cli/update-cli/wizard.js +130 -0
- package/dist/cli/update-cli.js +3 -9
- package/dist/cli/windows-argv.js +69 -0
- package/dist/commands/auth-choice-legacy.js +20 -0
- package/dist/commands/auth-choice.apply-helpers.js +8 -0
- package/dist/commands/channel-test-helpers.js +19 -0
- package/dist/commands/cleanup-plan.js +10 -0
- package/dist/commands/cleanup-utils.js +7 -0
- package/dist/commands/config-validation.js +15 -0
- package/dist/commands/doctor-completion.js +112 -0
- package/dist/commands/doctor-memory-search.js +119 -0
- package/dist/commands/doctor-session-locks.js +73 -0
- package/dist/commands/doctor.e2e-harness.js +364 -0
- package/dist/commands/gateway-presence.js +19 -0
- package/dist/commands/model-default.js +35 -0
- package/dist/commands/models/fallbacks-shared.js +102 -0
- package/dist/commands/models/shared.js +24 -0
- package/dist/commands/onboard-auth.config-gateways.js +64 -0
- package/dist/commands/onboard-auth.config-litellm.js +45 -0
- package/dist/commands/onboard-auth.config-shared.js +116 -0
- package/dist/commands/onboard-config.js +16 -0
- package/dist/commands/onboard-non-interactive.test-helpers.js +31 -0
- package/dist/commands/onboard-provider-auth-flags.js +136 -0
- package/dist/commands/openai-codex-oauth.js +40 -0
- package/dist/commands/test-runtime-config-helpers.js +21 -0
- package/dist/commands/test-wizard-helpers.js +68 -0
- package/dist/commands/vllm-setup.js +66 -0
- package/dist/compat/legacy-names.js +2 -0
- package/dist/config/backup-rotation.js +19 -0
- package/dist/config/env-preserve.js +122 -0
- package/dist/config/includes-scan.js +78 -0
- package/dist/config/plugins-allowlist.js +13 -0
- package/dist/config/schema.help.js +256 -0
- package/dist/config/schema.hints.js +189 -0
- package/dist/config/schema.irc.js +20 -0
- package/dist/config/schema.labels.js +317 -0
- package/dist/config/sessions/delivery-info.js +40 -0
- package/dist/config/types.irc.js +1 -0
- package/dist/config/zod-schema.agent-model.js +10 -0
- package/dist/config/zod-schema.allowdeny.js +35 -0
- package/dist/config/zod-schema.sensitive.js +4 -0
- package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
- package/dist/cron/isolated-agent/skills-snapshot.js +26 -0
- package/dist/cron/isolated-agent/subagent-followup.js +127 -0
- package/dist/cron/isolated-agent.mocks.js +12 -0
- package/dist/cron/isolated-agent.test-setup.js +22 -0
- package/dist/cron/legacy-delivery.js +43 -0
- package/dist/cron/webhook-url.js +22 -0
- package/dist/daemon/arg-split.js +40 -0
- package/dist/daemon/exec-file.js +23 -0
- package/dist/daemon/output.js +6 -0
- package/dist/daemon/runtime-format.js +31 -0
- package/dist/daemon/schtasks-exec.js +4 -0
- package/dist/daemon/service-audit.js +22 -0
- package/dist/discord/client.js +41 -0
- package/dist/discord/components-registry.js +57 -0
- package/dist/discord/components.js +816 -0
- package/dist/discord/guilds.js +12 -0
- package/dist/discord/monitor/gateway-plugin.js +48 -0
- package/dist/discord/monitor/presence.js +30 -0
- package/dist/discord/send.components.js +115 -0
- package/dist/discord/send.shared.js +4 -0
- package/dist/discord/ui.js +26 -0
- package/dist/discord/voice-message.js +254 -0
- package/dist/gateway/agent-event-assistant-text.js +5 -0
- package/dist/gateway/agent-prompt.js +33 -0
- package/dist/gateway/auth-rate-limit.js +136 -0
- package/dist/gateway/channel-health-monitor.js +114 -0
- package/dist/gateway/control-ui-contract.js +1 -0
- package/dist/gateway/control-ui-csp.js +15 -0
- package/dist/gateway/gateway-config-prompts.shared.js +25 -0
- package/dist/gateway/http-auth-helpers.js +18 -0
- package/dist/gateway/http-common.js +18 -0
- package/dist/gateway/http-endpoint-helpers.js +27 -0
- package/dist/gateway/node-invoke-sanitize.js +11 -0
- package/dist/gateway/node-invoke-system-run-approval.js +205 -0
- package/dist/gateway/probe-auth.js +21 -0
- package/dist/gateway/protocol/index.js +7 -2
- package/dist/gateway/protocol/schema/mesh.js +54 -0
- package/dist/gateway/protocol/schema/protocol-schemas.js +7 -0
- package/dist/gateway/protocol/schema.js +1 -0
- package/dist/gateway/server/ws-connection/auth-messages.js +54 -0
- package/dist/gateway/server-channels.js +11 -0
- package/dist/gateway/server-methods/attachment-normalize.js +16 -0
- package/dist/gateway/server-methods/base-hash.js +8 -0
- package/dist/gateway/server-methods/mesh.js +700 -0
- package/dist/gateway/server-methods/nodes.handlers.invoke-result.js +55 -0
- package/dist/gateway/server-methods/restart-request.js +13 -0
- package/dist/gateway/server-methods/validation.js +8 -0
- package/dist/gateway/server.agent.gateway-server-agent.mocks.js +35 -0
- package/dist/gateway/server.e2e-registry-helpers.js +1 -0
- package/dist/gateway/server.e2e-ws-harness.js +20 -0
- package/dist/gateway/test-helpers.js +2 -0
- package/dist/gateway/test-helpers.server.js +3 -1
- package/dist/gateway/test-http-response.js +12 -0
- package/dist/gateway/test-openai-responses-model.js +20 -0
- package/dist/gateway/test-temp-config.js +30 -0
- package/dist/gateway/test-with-server.js +32 -0
- package/dist/hooks/bundled/bootstrap-extra-files/handler.js +46 -0
- package/dist/imessage/monitor/abort-handler.js +23 -0
- package/dist/imessage/monitor/inbound-processing.js +346 -0
- package/dist/imessage/monitor/parse-notification.js +64 -0
- package/dist/imessage/target-parsing-helpers.js +92 -0
- package/dist/infra/archive.js +244 -20
- package/dist/infra/detect-package-manager.js +26 -0
- package/dist/infra/exec-approvals-allowlist.js +257 -0
- package/dist/infra/exec-approvals-analysis.js +770 -0
- package/dist/infra/exec-approvals.js +13 -0
- package/dist/infra/file-lock.js +1 -0
- package/dist/infra/gemini-auth.js +39 -0
- package/dist/infra/heartbeat-active-hours.js +85 -0
- package/dist/infra/heartbeat-events-filter.js +50 -0
- package/dist/infra/heartbeat-runner.test-utils.js +39 -0
- package/dist/infra/http-body.js +265 -0
- package/dist/infra/install-package-dir.js +50 -0
- package/dist/infra/install-safe-path.js +49 -0
- package/dist/infra/json-files.js +49 -0
- package/dist/infra/jsonl-socket.js +52 -0
- package/dist/infra/map-size.js +14 -0
- package/dist/infra/net/hostname.js +7 -0
- package/dist/infra/npm-registry-spec.js +39 -0
- package/dist/infra/openclaw-root.js +109 -0
- package/dist/infra/outbound/delivery-queue.js +214 -0
- package/dist/infra/outbound/identity.js +23 -0
- package/dist/infra/outbound/message-action-params.js +307 -0
- package/dist/infra/outbound/tool-payload.js +21 -0
- package/dist/infra/package-json.js +23 -0
- package/dist/infra/pairing-files.js +19 -0
- package/dist/infra/pairing-token.js +9 -0
- package/dist/infra/path-prepend.js +51 -0
- package/dist/infra/process-respawn.js +49 -0
- package/dist/infra/runtime-status.js +16 -0
- package/dist/infra/session-cost-usage.types.js +1 -0
- package/dist/infra/session-maintenance-warning.js +89 -0
- package/dist/infra/system-run-command.js +78 -0
- package/dist/infra/tmp-openclaw-dir.js +81 -0
- package/dist/infra/tmp-poolbot-dir.js +2 -0
- package/dist/infra/update-channels.js +19 -0
- package/dist/line/actions.js +45 -0
- package/dist/line/channel-access-token.js +9 -0
- package/dist/line/flex-templates/basic-cards.js +332 -0
- package/dist/line/flex-templates/common.js +18 -0
- package/dist/line/flex-templates/media-control-cards.js +453 -0
- package/dist/line/flex-templates/message.js +10 -0
- package/dist/line/flex-templates/schedule-cards.js +399 -0
- package/dist/line/flex-templates/types.js +1 -0
- package/dist/line/webhook-node.js +100 -0
- package/dist/line/webhook-utils.js +11 -0
- package/dist/logging/timestamps.js +14 -0
- package/dist/markdown/whatsapp.js +62 -0
- package/dist/media/base64.js +34 -0
- package/dist/media/local-roots.js +32 -0
- package/dist/media/outbound-attachment.js +10 -0
- package/dist/media/read-response-with-limit.js +41 -0
- package/dist/media/sniff-mime-from-base64.js +19 -0
- package/dist/media-understanding/audio-preflight.js +67 -0
- package/dist/media-understanding/fs.js +13 -0
- package/dist/media-understanding/output-extract.js +26 -0
- package/dist/media-understanding/providers/audio.test-helpers.js +34 -0
- package/dist/media-understanding/providers/google/inline-data.js +64 -0
- package/dist/media-understanding/providers/shared.js +7 -0
- package/dist/media-understanding/runner.entries.js +459 -0
- package/dist/memory/batch-error-utils.js +11 -0
- package/dist/memory/batch-http.js +27 -0
- package/dist/memory/batch-output.js +29 -0
- package/dist/memory/batch-runner.js +22 -0
- package/dist/memory/batch-upload.js +23 -0
- package/dist/memory/batch-utils.js +26 -0
- package/dist/memory/embeddings-debug.js +11 -0
- package/dist/memory/embeddings-remote-client.js +22 -0
- package/dist/memory/embeddings-remote-fetch.js +14 -0
- package/dist/memory/manager-embedding-ops.js +616 -0
- package/dist/memory/manager-sync-ops.js +953 -0
- package/dist/memory/qmd-manager.js +1061 -0
- package/dist/memory/qmd-query-parser.js +107 -0
- package/dist/memory/qmd-scope.js +93 -0
- package/dist/memory/search-manager.js +0 -1
- package/dist/memory/sync-index.js +21 -0
- package/dist/memory/sync-progress.js +22 -0
- package/dist/memory/sync-stale.js +30 -0
- package/dist/memory/test-embeddings-mock.js +16 -0
- package/dist/memory/test-manager-helpers.js +14 -0
- package/dist/memory/test-runtime-mocks.js +11 -0
- package/dist/node-host/invoke-browser.js +177 -0
- package/dist/node-host/invoke.js +685 -0
- package/dist/pairing/setup-code.js +285 -0
- package/dist/plugin-sdk/account-id.js +1 -0
- package/dist/plugin-sdk/agent-media-payload.js +13 -0
- package/dist/plugin-sdk/allow-from.js +47 -0
- package/dist/plugin-sdk/command-auth.js +23 -0
- package/dist/plugin-sdk/config-paths.js +9 -0
- package/dist/plugin-sdk/file-lock.js +116 -0
- package/dist/plugin-sdk/json-store.js +31 -0
- package/dist/plugin-sdk/onboarding.js +28 -0
- package/dist/plugin-sdk/provider-auth-result.js +29 -0
- package/dist/plugin-sdk/slack-message-actions.js +133 -0
- package/dist/plugin-sdk/status-helpers.js +35 -0
- package/dist/plugin-sdk/text-chunking.js +31 -0
- package/dist/plugin-sdk/tool-send.js +12 -0
- package/dist/plugin-sdk/webhook-path.js +27 -0
- package/dist/plugin-sdk/webhook-targets.js +34 -0
- package/dist/plugins/hooks.test-helpers.js +21 -0
- package/dist/plugins/uninstall.js +171 -0
- package/dist/process/supervisor/adapters/child.js +143 -0
- package/dist/process/supervisor/adapters/env.js +13 -0
- package/dist/process/supervisor/adapters/pty.js +148 -0
- package/dist/process/supervisor/index.js +10 -0
- package/dist/process/supervisor/registry.js +117 -0
- package/dist/process/supervisor/supervisor.js +244 -0
- package/dist/process/supervisor/types.js +1 -0
- package/dist/providers/google-shared.test-helpers.js +75 -0
- package/dist/security/audit-channel.js +419 -0
- package/dist/security/audit-tool-policy.js +1 -0
- package/dist/security/scan-paths.js +12 -0
- package/dist/sessions/input-provenance.js +55 -0
- package/dist/sessions/session-key-utils.js +7 -0
- package/dist/shared/chat-content.js +31 -0
- package/dist/shared/chat-envelope.js +45 -0
- package/dist/shared/config-eval.js +117 -0
- package/dist/shared/device-auth.js +16 -0
- package/dist/shared/entry-metadata.js +9 -0
- package/dist/shared/entry-status.js +25 -0
- package/dist/shared/frontmatter.js +98 -0
- package/dist/shared/model-param-b.js +19 -0
- package/dist/shared/net/ipv4.js +17 -0
- package/dist/shared/node-match.js +53 -0
- package/dist/shared/requirements.js +128 -0
- package/dist/shared/subagents-format.js +84 -0
- package/dist/shared/usage-aggregates.js +28 -0
- package/dist/signal/monitor/mentions.js +45 -0
- package/dist/signal/rpc-context.js +19 -0
- package/dist/slack/blocks-fallback.js +76 -0
- package/dist/slack/blocks-input.js +40 -0
- package/dist/slack/draft-stream.js +106 -0
- package/dist/slack/message-actions.js +51 -0
- package/dist/slack/modal-metadata.js +32 -0
- package/dist/slack/monitor/events/interactions.js +462 -0
- package/dist/slack/monitor/room-context.js +17 -0
- package/dist/slack/stream-mode.js +41 -0
- package/dist/telegram/bot-native-command-menu.js +64 -0
- package/dist/telegram/bot.media.e2e-harness.js +81 -0
- package/dist/telegram/button-types.js +1 -0
- package/dist/telegram/group-access.js +65 -0
- package/dist/telegram/outbound-params.js +21 -0
- package/dist/telegram/poll-vote-cache.js +21 -0
- package/dist/terminal/health-style.js +36 -0
- package/dist/test-utils/chunk-test-helpers.js +21 -0
- package/dist/test-utils/env.js +72 -0
- package/dist/test-utils/exec-assertions.js +12 -0
- package/dist/test-utils/imessage-test-plugin.js +54 -0
- package/dist/test-utils/mock-http-response.js +17 -0
- package/dist/test-utils/vitest-mock-fn.js +1 -0
- package/dist/tts/tts-core.js +550 -0
- package/dist/utils/chunk-items.js +10 -0
- package/dist/utils/reaction-level.js +52 -0
- package/dist/utils/safe-json.js +22 -0
- package/dist/utils/with-timeout.js +14 -0
- package/dist/web/media.js +17 -5
- package/dist/whatsapp/resolve-outbound-target.js +42 -0
- package/dist/wizard/onboarding.completion.js +74 -0
- package/extensions/bluebubbles/src/account-resolve.ts +29 -0
- package/extensions/bluebubbles/src/monitor-normalize.ts +796 -0
- package/extensions/bluebubbles/src/monitor-processing.ts +1007 -0
- package/extensions/bluebubbles/src/monitor-reply-cache.ts +185 -0
- package/extensions/bluebubbles/src/monitor-shared.ts +51 -0
- package/extensions/bluebubbles/src/multipart.ts +32 -0
- package/extensions/bluebubbles/src/send-helpers.ts +53 -0
- package/extensions/bluebubbles/src/test-harness.ts +50 -0
- package/extensions/bluebubbles/src/test-mocks.ts +11 -0
- package/extensions/device-pair/index.ts +554 -0
- package/extensions/device-pair/poolbot.plugin.json +20 -0
- package/extensions/discord/src/channel.js +366 -0
- package/extensions/discord/src/runtime.js +10 -0
- package/extensions/feishu/index.ts +63 -0
- package/extensions/feishu/package.json +37 -0
- package/extensions/feishu/poolbot.plugin.json +10 -0
- package/extensions/feishu/skills/feishu-doc/SKILL.md +105 -0
- package/extensions/feishu/skills/feishu-doc/references/block-types.md +103 -0
- package/extensions/feishu/skills/feishu-drive/SKILL.md +97 -0
- package/extensions/feishu/skills/feishu-perm/SKILL.md +119 -0
- package/extensions/feishu/skills/feishu-wiki/SKILL.md +111 -0
- package/extensions/feishu/src/accounts.ts +114 -0
- package/extensions/feishu/src/bitable.ts +739 -0
- package/extensions/feishu/src/bot.ts +965 -0
- package/extensions/feishu/src/channel.ts +351 -0
- package/extensions/feishu/src/client.ts +118 -0
- package/extensions/feishu/src/config-schema.ts +206 -0
- package/extensions/feishu/src/dedup.ts +33 -0
- package/extensions/feishu/src/directory.ts +177 -0
- package/extensions/feishu/src/doc-schema.ts +47 -0
- package/extensions/feishu/src/docx.ts +536 -0
- package/extensions/feishu/src/drive-schema.ts +46 -0
- package/extensions/feishu/src/drive.ts +227 -0
- package/extensions/feishu/src/dynamic-agent.ts +131 -0
- package/extensions/feishu/src/media.ts +449 -0
- package/extensions/feishu/src/mention.ts +126 -0
- package/extensions/feishu/src/monitor.ts +330 -0
- package/extensions/feishu/src/onboarding.ts +359 -0
- package/extensions/feishu/src/outbound.ts +55 -0
- package/extensions/feishu/src/perm-schema.ts +52 -0
- package/extensions/feishu/src/perm.ts +173 -0
- package/extensions/feishu/src/policy.ts +84 -0
- package/extensions/feishu/src/probe.ts +44 -0
- package/extensions/feishu/src/reactions.ts +160 -0
- package/extensions/feishu/src/reply-dispatcher.ts +239 -0
- package/extensions/feishu/src/runtime.ts +14 -0
- package/extensions/feishu/src/send-result.ts +29 -0
- package/extensions/feishu/src/send.ts +335 -0
- package/extensions/feishu/src/streaming-card.ts +223 -0
- package/extensions/feishu/src/targets.ts +78 -0
- package/extensions/feishu/src/tools-config.ts +21 -0
- package/extensions/feishu/src/types.ts +81 -0
- package/extensions/feishu/src/typing.ts +80 -0
- package/extensions/feishu/src/wiki-schema.ts +55 -0
- package/extensions/feishu/src/wiki.ts +232 -0
- package/extensions/imessage/src/channel.js +253 -0
- package/extensions/imessage/src/runtime.js +10 -0
- package/extensions/irc/index.ts +17 -0
- package/extensions/irc/package.json +14 -0
- package/extensions/irc/poolbot.plugin.json +9 -0
- package/extensions/irc/src/accounts.ts +268 -0
- package/extensions/irc/src/channel.ts +367 -0
- package/extensions/irc/src/client.ts +439 -0
- package/extensions/irc/src/config-schema.ts +97 -0
- package/extensions/irc/src/connect-options.ts +30 -0
- package/extensions/irc/src/control-chars.ts +22 -0
- package/extensions/irc/src/inbound.ts +334 -0
- package/extensions/irc/src/monitor.ts +147 -0
- package/extensions/irc/src/normalize.ts +117 -0
- package/extensions/irc/src/onboarding.ts +479 -0
- package/extensions/irc/src/policy.ts +157 -0
- package/extensions/irc/src/probe.ts +53 -0
- package/extensions/irc/src/protocol.ts +169 -0
- package/extensions/irc/src/runtime.ts +14 -0
- package/extensions/irc/src/send.ts +88 -0
- package/extensions/irc/src/types.ts +93 -0
- package/extensions/matrix/src/matrix/client-bootstrap.ts +39 -0
- package/extensions/mattermost/src/mattermost/monitor-onchar.ts +25 -0
- package/extensions/mattermost/src/mattermost/monitor-websocket.ts +221 -0
- package/extensions/mattermost/src/mattermost/reactions.ts +130 -0
- package/extensions/mattermost/src/mattermost/reconnect.ts +103 -0
- package/extensions/minimax-portal-auth/README.md +33 -0
- package/extensions/minimax-portal-auth/index.ts +161 -0
- package/extensions/minimax-portal-auth/oauth.ts +247 -0
- package/extensions/minimax-portal-auth/package.json +15 -0
- package/extensions/minimax-portal-auth/poolbot.plugin.json +9 -0
- package/extensions/msteams/src/file-lock.ts +1 -0
- package/extensions/msteams/src/graph.ts +92 -0
- package/extensions/msteams/src/mentions.ts +114 -0
- package/extensions/msteams/src/test-runtime.ts +16 -0
- package/extensions/openai-codex-auth/README.md +82 -0
- package/extensions/openai-codex-auth/index.ts +177 -0
- package/extensions/openai-codex-auth/package.json +15 -0
- package/extensions/openai-codex-auth/poolbot.plugin.json +9 -0
- package/extensions/phone-control/index.ts +421 -0
- package/extensions/phone-control/poolbot.plugin.json +10 -0
- package/extensions/shared/resolve-target-test-helpers.ts +66 -0
- package/extensions/signal/src/channel.js +273 -0
- package/extensions/signal/src/runtime.js +10 -0
- package/extensions/slack/src/channel.js +489 -0
- package/extensions/slack/src/runtime.js +10 -0
- package/extensions/talk-voice/index.ts +150 -0
- package/extensions/talk-voice/poolbot.plugin.json +10 -0
- package/extensions/telegram/src/channel.js +424 -0
- package/extensions/telegram/src/runtime.js +10 -0
- package/extensions/thread-ownership/index.ts +133 -0
- package/extensions/thread-ownership/poolbot.plugin.json +28 -0
- package/extensions/tlon/src/account-fields.ts +25 -0
- package/extensions/tlon/src/urbit/base-url.ts +57 -0
- package/extensions/tlon/src/urbit/channel-client.ts +157 -0
- package/extensions/tlon/src/urbit/channel-ops.ts +164 -0
- package/extensions/tlon/src/urbit/context.ts +47 -0
- package/extensions/tlon/src/urbit/errors.ts +51 -0
- package/extensions/tlon/src/urbit/fetch.ts +39 -0
- package/extensions/twitch/src/test-fixtures.ts +30 -0
- package/extensions/voice-call/src/allowlist.ts +19 -0
- package/extensions/whatsapp/src/channel.js +429 -0
- package/extensions/whatsapp/src/runtime.js +10 -0
- package/package.json +1 -1
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
import { resolveChannelDefaultAccountId } from "../channels/plugins/helpers.js";
|
|
2
|
+
import { isNumericTelegramUserId, normalizeTelegramAllowFromEntry, } from "../channels/telegram/allow-from.js";
|
|
3
|
+
import { formatCliCommand } from "../cli/command-format.js";
|
|
4
|
+
import { resolveNativeCommandsEnabled, resolveNativeSkillsEnabled } from "../config/commands.js";
|
|
5
|
+
import { readChannelAllowFromStore } from "../pairing/pairing-store.js";
|
|
6
|
+
function normalizeAllowFromList(list) {
|
|
7
|
+
if (!Array.isArray(list)) {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
return list.map((v) => String(v).trim()).filter(Boolean);
|
|
11
|
+
}
|
|
12
|
+
function classifyChannelWarningSeverity(message) {
|
|
13
|
+
const s = message.toLowerCase();
|
|
14
|
+
if (s.includes("dms: open") ||
|
|
15
|
+
s.includes('grouppolicy="open"') ||
|
|
16
|
+
s.includes('dmpolicy="open"')) {
|
|
17
|
+
return "critical";
|
|
18
|
+
}
|
|
19
|
+
if (s.includes("allows any") || s.includes("anyone can dm") || s.includes("public")) {
|
|
20
|
+
return "critical";
|
|
21
|
+
}
|
|
22
|
+
if (s.includes("locked") || s.includes("disabled")) {
|
|
23
|
+
return "info";
|
|
24
|
+
}
|
|
25
|
+
return "warn";
|
|
26
|
+
}
|
|
27
|
+
export async function collectChannelSecurityFindings(params) {
|
|
28
|
+
const findings = [];
|
|
29
|
+
const coerceNativeSetting = (value) => {
|
|
30
|
+
if (value === true) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
if (value === false) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
if (value === "auto") {
|
|
37
|
+
return "auto";
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
};
|
|
41
|
+
const warnDmPolicy = async (input) => {
|
|
42
|
+
const policyPath = input.policyPath ?? `${input.allowFromPath}policy`;
|
|
43
|
+
const configAllowFrom = normalizeAllowFromList(input.allowFrom);
|
|
44
|
+
const hasWildcard = configAllowFrom.includes("*");
|
|
45
|
+
const dmScope = params.cfg.session?.dmScope ?? "main";
|
|
46
|
+
const storeAllowFrom = await readChannelAllowFromStore(input.provider).catch(() => []);
|
|
47
|
+
const normalizeEntry = input.normalizeEntry ?? ((value) => value);
|
|
48
|
+
const normalizedCfg = configAllowFrom
|
|
49
|
+
.filter((value) => value !== "*")
|
|
50
|
+
.map((value) => normalizeEntry(value))
|
|
51
|
+
.map((value) => value.trim())
|
|
52
|
+
.filter(Boolean);
|
|
53
|
+
const normalizedStore = storeAllowFrom
|
|
54
|
+
.map((value) => normalizeEntry(value))
|
|
55
|
+
.map((value) => value.trim())
|
|
56
|
+
.filter(Boolean);
|
|
57
|
+
const allowCount = Array.from(new Set([...normalizedCfg, ...normalizedStore])).length;
|
|
58
|
+
const isMultiUserDm = hasWildcard || allowCount > 1;
|
|
59
|
+
if (input.dmPolicy === "open") {
|
|
60
|
+
const allowFromKey = `${input.allowFromPath}allowFrom`;
|
|
61
|
+
findings.push({
|
|
62
|
+
checkId: `channels.${input.provider}.dm.open`,
|
|
63
|
+
severity: "critical",
|
|
64
|
+
title: `${input.label} DMs are open`,
|
|
65
|
+
detail: `${policyPath}="open" allows anyone to DM the bot.`,
|
|
66
|
+
remediation: `Use pairing/allowlist; if you really need open DMs, ensure ${allowFromKey} includes "*".`,
|
|
67
|
+
});
|
|
68
|
+
if (!hasWildcard) {
|
|
69
|
+
findings.push({
|
|
70
|
+
checkId: `channels.${input.provider}.dm.open_invalid`,
|
|
71
|
+
severity: "warn",
|
|
72
|
+
title: `${input.label} DM config looks inconsistent`,
|
|
73
|
+
detail: `"open" requires ${allowFromKey} to include "*".`,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (input.dmPolicy === "disabled") {
|
|
78
|
+
findings.push({
|
|
79
|
+
checkId: `channels.${input.provider}.dm.disabled`,
|
|
80
|
+
severity: "info",
|
|
81
|
+
title: `${input.label} DMs are disabled`,
|
|
82
|
+
detail: `${policyPath}="disabled" ignores inbound DMs.`,
|
|
83
|
+
});
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (dmScope === "main" && isMultiUserDm) {
|
|
87
|
+
findings.push({
|
|
88
|
+
checkId: `channels.${input.provider}.dm.scope_main_multiuser`,
|
|
89
|
+
severity: "warn",
|
|
90
|
+
title: `${input.label} DMs share the main session`,
|
|
91
|
+
detail: "Multiple DM senders currently share the main session, which can leak context across users.",
|
|
92
|
+
remediation: "Run: " +
|
|
93
|
+
formatCliCommand('openclaw config set session.dmScope "per-channel-peer"') +
|
|
94
|
+
' (or "per-account-channel-peer" for multi-account channels) to isolate DM sessions per sender.',
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
for (const plugin of params.plugins) {
|
|
99
|
+
if (!plugin.security) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const accountIds = plugin.config.listAccountIds(params.cfg);
|
|
103
|
+
const defaultAccountId = resolveChannelDefaultAccountId({
|
|
104
|
+
plugin,
|
|
105
|
+
cfg: params.cfg,
|
|
106
|
+
accountIds,
|
|
107
|
+
});
|
|
108
|
+
const account = plugin.config.resolveAccount(params.cfg, defaultAccountId);
|
|
109
|
+
const enabled = plugin.config.isEnabled ? plugin.config.isEnabled(account, params.cfg) : true;
|
|
110
|
+
if (!enabled) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const configured = plugin.config.isConfigured
|
|
114
|
+
? await plugin.config.isConfigured(account, params.cfg)
|
|
115
|
+
: true;
|
|
116
|
+
if (!configured) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (plugin.id === "discord") {
|
|
120
|
+
const discordCfg = account?.config ??
|
|
121
|
+
{};
|
|
122
|
+
const nativeEnabled = resolveNativeCommandsEnabled({
|
|
123
|
+
providerId: "discord",
|
|
124
|
+
providerSetting: coerceNativeSetting(discordCfg.commands?.native),
|
|
125
|
+
globalSetting: params.cfg.commands?.native,
|
|
126
|
+
});
|
|
127
|
+
const nativeSkillsEnabled = resolveNativeSkillsEnabled({
|
|
128
|
+
providerId: "discord",
|
|
129
|
+
providerSetting: coerceNativeSetting(discordCfg.commands?.nativeSkills),
|
|
130
|
+
globalSetting: params.cfg.commands?.nativeSkills,
|
|
131
|
+
});
|
|
132
|
+
const slashEnabled = nativeEnabled || nativeSkillsEnabled;
|
|
133
|
+
if (slashEnabled) {
|
|
134
|
+
const defaultGroupPolicy = params.cfg.channels?.defaults?.groupPolicy;
|
|
135
|
+
const groupPolicy = discordCfg.groupPolicy ?? defaultGroupPolicy ?? "allowlist";
|
|
136
|
+
const guildEntries = discordCfg.guilds ?? {};
|
|
137
|
+
const guildsConfigured = Object.keys(guildEntries).length > 0;
|
|
138
|
+
const hasAnyUserAllowlist = Object.values(guildEntries).some((guild) => {
|
|
139
|
+
if (!guild || typeof guild !== "object") {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
const g = guild;
|
|
143
|
+
if (Array.isArray(g.users) && g.users.length > 0) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
const channels = g.channels;
|
|
147
|
+
if (!channels || typeof channels !== "object") {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
return Object.values(channels).some((channel) => {
|
|
151
|
+
if (!channel || typeof channel !== "object") {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
const c = channel;
|
|
155
|
+
return Array.isArray(c.users) && c.users.length > 0;
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
const dmAllowFromRaw = discordCfg.dm?.allowFrom;
|
|
159
|
+
const dmAllowFrom = Array.isArray(dmAllowFromRaw) ? dmAllowFromRaw : [];
|
|
160
|
+
const storeAllowFrom = await readChannelAllowFromStore("discord").catch(() => []);
|
|
161
|
+
const ownerAllowFromConfigured = normalizeAllowFromList([...dmAllowFrom, ...storeAllowFrom]).length > 0;
|
|
162
|
+
const useAccessGroups = params.cfg.commands?.useAccessGroups !== false;
|
|
163
|
+
if (!useAccessGroups &&
|
|
164
|
+
groupPolicy !== "disabled" &&
|
|
165
|
+
guildsConfigured &&
|
|
166
|
+
!hasAnyUserAllowlist) {
|
|
167
|
+
findings.push({
|
|
168
|
+
checkId: "channels.discord.commands.native.unrestricted",
|
|
169
|
+
severity: "critical",
|
|
170
|
+
title: "Discord slash commands are unrestricted",
|
|
171
|
+
detail: "commands.useAccessGroups=false disables sender allowlists for Discord slash commands unless a per-guild/channel users allowlist is configured; with no users allowlist, any user in allowed guild channels can invoke /… commands.",
|
|
172
|
+
remediation: "Set commands.useAccessGroups=true (recommended), or configure channels.discord.guilds.<id>.users (or channels.discord.guilds.<id>.channels.<channel>.users).",
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
else if (useAccessGroups &&
|
|
176
|
+
groupPolicy !== "disabled" &&
|
|
177
|
+
guildsConfigured &&
|
|
178
|
+
!ownerAllowFromConfigured &&
|
|
179
|
+
!hasAnyUserAllowlist) {
|
|
180
|
+
findings.push({
|
|
181
|
+
checkId: "channels.discord.commands.native.no_allowlists",
|
|
182
|
+
severity: "warn",
|
|
183
|
+
title: "Discord slash commands have no allowlists",
|
|
184
|
+
detail: "Discord slash commands are enabled, but neither an owner allowFrom list nor any per-guild/channel users allowlist is configured; /… commands will be rejected for everyone.",
|
|
185
|
+
remediation: "Add your user id to channels.discord.allowFrom (or approve yourself via pairing), or configure channels.discord.guilds.<id>.users.",
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (plugin.id === "slack") {
|
|
191
|
+
const slackCfg = account
|
|
192
|
+
?.config ?? {};
|
|
193
|
+
const nativeEnabled = resolveNativeCommandsEnabled({
|
|
194
|
+
providerId: "slack",
|
|
195
|
+
providerSetting: coerceNativeSetting(slackCfg.commands?.native),
|
|
196
|
+
globalSetting: params.cfg.commands?.native,
|
|
197
|
+
});
|
|
198
|
+
const nativeSkillsEnabled = resolveNativeSkillsEnabled({
|
|
199
|
+
providerId: "slack",
|
|
200
|
+
providerSetting: coerceNativeSetting(slackCfg.commands?.nativeSkills),
|
|
201
|
+
globalSetting: params.cfg.commands?.nativeSkills,
|
|
202
|
+
});
|
|
203
|
+
const slashCommandEnabled = nativeEnabled ||
|
|
204
|
+
nativeSkillsEnabled ||
|
|
205
|
+
slackCfg.slashCommand?.enabled === true;
|
|
206
|
+
if (slashCommandEnabled) {
|
|
207
|
+
const useAccessGroups = params.cfg.commands?.useAccessGroups !== false;
|
|
208
|
+
if (!useAccessGroups) {
|
|
209
|
+
findings.push({
|
|
210
|
+
checkId: "channels.slack.commands.slash.useAccessGroups_off",
|
|
211
|
+
severity: "critical",
|
|
212
|
+
title: "Slack slash commands bypass access groups",
|
|
213
|
+
detail: "Slack slash/native commands are enabled while commands.useAccessGroups=false; this can allow unrestricted /… command execution from channels/users you didn't explicitly authorize.",
|
|
214
|
+
remediation: "Set commands.useAccessGroups=true (recommended).",
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
const allowFromRaw = account?.config?.allowFrom;
|
|
219
|
+
const legacyAllowFromRaw = account?.dm?.allowFrom;
|
|
220
|
+
const allowFrom = Array.isArray(allowFromRaw)
|
|
221
|
+
? allowFromRaw
|
|
222
|
+
: Array.isArray(legacyAllowFromRaw)
|
|
223
|
+
? legacyAllowFromRaw
|
|
224
|
+
: [];
|
|
225
|
+
const storeAllowFrom = await readChannelAllowFromStore("slack").catch(() => []);
|
|
226
|
+
const ownerAllowFromConfigured = normalizeAllowFromList([...allowFrom, ...storeAllowFrom]).length > 0;
|
|
227
|
+
const channels = slackCfg.channels ?? {};
|
|
228
|
+
const hasAnyChannelUsersAllowlist = Object.values(channels).some((value) => {
|
|
229
|
+
if (!value || typeof value !== "object") {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
const channel = value;
|
|
233
|
+
return Array.isArray(channel.users) && channel.users.length > 0;
|
|
234
|
+
});
|
|
235
|
+
if (!ownerAllowFromConfigured && !hasAnyChannelUsersAllowlist) {
|
|
236
|
+
findings.push({
|
|
237
|
+
checkId: "channels.slack.commands.slash.no_allowlists",
|
|
238
|
+
severity: "warn",
|
|
239
|
+
title: "Slack slash commands have no allowlists",
|
|
240
|
+
detail: "Slack slash/native commands are enabled, but neither an owner allowFrom list nor any channels.<id>.users allowlist is configured; /… commands will be rejected for everyone.",
|
|
241
|
+
remediation: "Approve yourself via pairing (recommended), or set channels.slack.allowFrom and/or channels.slack.channels.<id>.users.",
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const dmPolicy = plugin.security.resolveDmPolicy?.({
|
|
248
|
+
cfg: params.cfg,
|
|
249
|
+
accountId: defaultAccountId,
|
|
250
|
+
account,
|
|
251
|
+
});
|
|
252
|
+
if (dmPolicy) {
|
|
253
|
+
await warnDmPolicy({
|
|
254
|
+
label: plugin.meta.label ?? plugin.id,
|
|
255
|
+
provider: plugin.id,
|
|
256
|
+
dmPolicy: dmPolicy.policy,
|
|
257
|
+
allowFrom: dmPolicy.allowFrom,
|
|
258
|
+
policyPath: dmPolicy.policyPath,
|
|
259
|
+
allowFromPath: dmPolicy.allowFromPath,
|
|
260
|
+
normalizeEntry: dmPolicy.normalizeEntry,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
if (plugin.security.collectWarnings) {
|
|
264
|
+
const warnings = await plugin.security.collectWarnings({
|
|
265
|
+
cfg: params.cfg,
|
|
266
|
+
accountId: defaultAccountId,
|
|
267
|
+
account,
|
|
268
|
+
});
|
|
269
|
+
for (const message of warnings ?? []) {
|
|
270
|
+
const trimmed = String(message).trim();
|
|
271
|
+
if (!trimmed) {
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
findings.push({
|
|
275
|
+
checkId: `channels.${plugin.id}.warning.${findings.length + 1}`,
|
|
276
|
+
severity: classifyChannelWarningSeverity(trimmed),
|
|
277
|
+
title: `${plugin.meta.label ?? plugin.id} security warning`,
|
|
278
|
+
detail: trimmed.replace(/^-\s*/, ""),
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (plugin.id === "telegram") {
|
|
283
|
+
const allowTextCommands = params.cfg.commands?.text !== false;
|
|
284
|
+
if (!allowTextCommands) {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
const telegramCfg = account?.config ??
|
|
288
|
+
{};
|
|
289
|
+
const defaultGroupPolicy = params.cfg.channels?.defaults?.groupPolicy;
|
|
290
|
+
const groupPolicy = telegramCfg.groupPolicy ?? defaultGroupPolicy ?? "allowlist";
|
|
291
|
+
const groups = telegramCfg.groups;
|
|
292
|
+
const groupsConfigured = Boolean(groups) && Object.keys(groups ?? {}).length > 0;
|
|
293
|
+
const groupAccessPossible = groupPolicy === "open" || (groupPolicy === "allowlist" && groupsConfigured);
|
|
294
|
+
if (!groupAccessPossible) {
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
const storeAllowFrom = await readChannelAllowFromStore("telegram").catch(() => []);
|
|
298
|
+
const storeHasWildcard = storeAllowFrom.some((v) => String(v).trim() === "*");
|
|
299
|
+
const invalidTelegramAllowFromEntries = new Set();
|
|
300
|
+
for (const entry of storeAllowFrom) {
|
|
301
|
+
const normalized = normalizeTelegramAllowFromEntry(entry);
|
|
302
|
+
if (!normalized || normalized === "*") {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
if (!isNumericTelegramUserId(normalized)) {
|
|
306
|
+
invalidTelegramAllowFromEntries.add(normalized);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const groupAllowFrom = Array.isArray(telegramCfg.groupAllowFrom)
|
|
310
|
+
? telegramCfg.groupAllowFrom
|
|
311
|
+
: [];
|
|
312
|
+
const groupAllowFromHasWildcard = groupAllowFrom.some((v) => String(v).trim() === "*");
|
|
313
|
+
for (const entry of groupAllowFrom) {
|
|
314
|
+
const normalized = normalizeTelegramAllowFromEntry(entry);
|
|
315
|
+
if (!normalized || normalized === "*") {
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
if (!isNumericTelegramUserId(normalized)) {
|
|
319
|
+
invalidTelegramAllowFromEntries.add(normalized);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
const dmAllowFrom = Array.isArray(telegramCfg.allowFrom) ? telegramCfg.allowFrom : [];
|
|
323
|
+
for (const entry of dmAllowFrom) {
|
|
324
|
+
const normalized = normalizeTelegramAllowFromEntry(entry);
|
|
325
|
+
if (!normalized || normalized === "*") {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (!isNumericTelegramUserId(normalized)) {
|
|
329
|
+
invalidTelegramAllowFromEntries.add(normalized);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
const anyGroupOverride = Boolean(groups &&
|
|
333
|
+
Object.values(groups).some((value) => {
|
|
334
|
+
if (!value || typeof value !== "object") {
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
const group = value;
|
|
338
|
+
const allowFrom = Array.isArray(group.allowFrom) ? group.allowFrom : [];
|
|
339
|
+
if (allowFrom.length > 0) {
|
|
340
|
+
for (const entry of allowFrom) {
|
|
341
|
+
const normalized = normalizeTelegramAllowFromEntry(entry);
|
|
342
|
+
if (!normalized || normalized === "*") {
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
if (!isNumericTelegramUserId(normalized)) {
|
|
346
|
+
invalidTelegramAllowFromEntries.add(normalized);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
const topics = group.topics;
|
|
352
|
+
if (!topics || typeof topics !== "object") {
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
return Object.values(topics).some((topicValue) => {
|
|
356
|
+
if (!topicValue || typeof topicValue !== "object") {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
const topic = topicValue;
|
|
360
|
+
const topicAllow = Array.isArray(topic.allowFrom) ? topic.allowFrom : [];
|
|
361
|
+
for (const entry of topicAllow) {
|
|
362
|
+
const normalized = normalizeTelegramAllowFromEntry(entry);
|
|
363
|
+
if (!normalized || normalized === "*") {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
if (!isNumericTelegramUserId(normalized)) {
|
|
367
|
+
invalidTelegramAllowFromEntries.add(normalized);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return topicAllow.length > 0;
|
|
371
|
+
});
|
|
372
|
+
}));
|
|
373
|
+
const hasAnySenderAllowlist = storeAllowFrom.length > 0 || groupAllowFrom.length > 0 || anyGroupOverride;
|
|
374
|
+
if (invalidTelegramAllowFromEntries.size > 0) {
|
|
375
|
+
const examples = Array.from(invalidTelegramAllowFromEntries).slice(0, 5);
|
|
376
|
+
const more = invalidTelegramAllowFromEntries.size > examples.length
|
|
377
|
+
? ` (+${invalidTelegramAllowFromEntries.size - examples.length} more)`
|
|
378
|
+
: "";
|
|
379
|
+
findings.push({
|
|
380
|
+
checkId: "channels.telegram.allowFrom.invalid_entries",
|
|
381
|
+
severity: "warn",
|
|
382
|
+
title: "Telegram allowlist contains non-numeric entries",
|
|
383
|
+
detail: "Telegram sender authorization requires numeric Telegram user IDs. " +
|
|
384
|
+
`Found non-numeric allowFrom entries: ${examples.join(", ")}${more}.`,
|
|
385
|
+
remediation: "Replace @username entries with numeric Telegram user IDs (use onboarding to resolve), then re-run the audit.",
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
if (storeHasWildcard || groupAllowFromHasWildcard) {
|
|
389
|
+
findings.push({
|
|
390
|
+
checkId: "channels.telegram.groups.allowFrom.wildcard",
|
|
391
|
+
severity: "critical",
|
|
392
|
+
title: "Telegram group allowlist contains wildcard",
|
|
393
|
+
detail: 'Telegram group sender allowlist contains "*", which allows any group member to run /… commands and control directives.',
|
|
394
|
+
remediation: 'Remove "*" from channels.telegram.groupAllowFrom and pairing store; prefer explicit numeric Telegram user IDs.',
|
|
395
|
+
});
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
if (!hasAnySenderAllowlist) {
|
|
399
|
+
const providerSetting = telegramCfg.commands
|
|
400
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
401
|
+
?.nativeSkills;
|
|
402
|
+
const skillsEnabled = resolveNativeSkillsEnabled({
|
|
403
|
+
providerId: "telegram",
|
|
404
|
+
providerSetting,
|
|
405
|
+
globalSetting: params.cfg.commands?.nativeSkills,
|
|
406
|
+
});
|
|
407
|
+
findings.push({
|
|
408
|
+
checkId: "channels.telegram.groups.allowFrom.missing",
|
|
409
|
+
severity: "critical",
|
|
410
|
+
title: "Telegram group commands have no sender allowlist",
|
|
411
|
+
detail: `Telegram group access is enabled but no sender allowlist is configured; this allows any group member to invoke /… commands` +
|
|
412
|
+
(skillsEnabled ? " (including skill commands)." : "."),
|
|
413
|
+
remediation: "Approve yourself via pairing (recommended), or set channels.telegram.groupAllowFrom (or per-group groups.<id>.allowFrom).",
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return findings;
|
|
419
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { pickSandboxToolPolicy } from "../agents/sandbox-tool-policy.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
export function isPathInside(basePath, candidatePath) {
|
|
3
|
+
const base = path.resolve(basePath);
|
|
4
|
+
const candidate = path.resolve(candidatePath);
|
|
5
|
+
const rel = path.relative(base, candidate);
|
|
6
|
+
return rel === "" || (!rel.startsWith(`..${path.sep}`) && rel !== ".." && !path.isAbsolute(rel));
|
|
7
|
+
}
|
|
8
|
+
export function extensionUsesSkippedScannerPath(entry) {
|
|
9
|
+
const segments = entry.split(/[\\/]+/).filter(Boolean);
|
|
10
|
+
return segments.some((segment) => segment === "node_modules" ||
|
|
11
|
+
(segment.startsWith(".") && segment !== "." && segment !== ".."));
|
|
12
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export const INPUT_PROVENANCE_KIND_VALUES = [
|
|
2
|
+
"external_user",
|
|
3
|
+
"inter_session",
|
|
4
|
+
"internal_system",
|
|
5
|
+
];
|
|
6
|
+
function normalizeOptionalString(value) {
|
|
7
|
+
if (typeof value !== "string") {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
const trimmed = value.trim();
|
|
11
|
+
return trimmed ? trimmed : undefined;
|
|
12
|
+
}
|
|
13
|
+
function isInputProvenanceKind(value) {
|
|
14
|
+
return (typeof value === "string" && INPUT_PROVENANCE_KIND_VALUES.includes(value));
|
|
15
|
+
}
|
|
16
|
+
export function normalizeInputProvenance(value) {
|
|
17
|
+
if (!value || typeof value !== "object") {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
const record = value;
|
|
21
|
+
if (!isInputProvenanceKind(record.kind)) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
kind: record.kind,
|
|
26
|
+
sourceSessionKey: normalizeOptionalString(record.sourceSessionKey),
|
|
27
|
+
sourceChannel: normalizeOptionalString(record.sourceChannel),
|
|
28
|
+
sourceTool: normalizeOptionalString(record.sourceTool),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function applyInputProvenanceToUserMessage(message, inputProvenance) {
|
|
32
|
+
if (!inputProvenance) {
|
|
33
|
+
return message;
|
|
34
|
+
}
|
|
35
|
+
if (message.role !== "user") {
|
|
36
|
+
return message;
|
|
37
|
+
}
|
|
38
|
+
const existing = normalizeInputProvenance(message.provenance);
|
|
39
|
+
if (existing) {
|
|
40
|
+
return message;
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
...message,
|
|
44
|
+
provenance: inputProvenance,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export function isInterSessionInputProvenance(value) {
|
|
48
|
+
return normalizeInputProvenance(value)?.kind === "inter_session";
|
|
49
|
+
}
|
|
50
|
+
export function hasInterSessionUserProvenance(message) {
|
|
51
|
+
if (!message || message.role !== "user") {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return isInterSessionInputProvenance(message.provenance);
|
|
55
|
+
}
|
|
@@ -29,6 +29,13 @@ export function isSubagentSessionKey(sessionKey) {
|
|
|
29
29
|
const parsed = parseAgentSessionKey(raw);
|
|
30
30
|
return Boolean((parsed?.rest ?? "").toLowerCase().startsWith("subagent:"));
|
|
31
31
|
}
|
|
32
|
+
export function getSubagentDepth(sessionKey) {
|
|
33
|
+
const raw = (sessionKey ?? "").trim().toLowerCase();
|
|
34
|
+
if (!raw) {
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
return raw.split(":subagent:").length - 1;
|
|
38
|
+
}
|
|
32
39
|
export function isAcpSessionKey(sessionKey) {
|
|
33
40
|
const raw = (sessionKey ?? "").trim();
|
|
34
41
|
if (!raw)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export function extractTextFromChatContent(content, opts) {
|
|
2
|
+
const normalize = opts?.normalizeText ?? ((text) => text.replace(/\s+/g, " ").trim());
|
|
3
|
+
const joinWith = opts?.joinWith ?? " ";
|
|
4
|
+
if (typeof content === "string") {
|
|
5
|
+
const value = opts?.sanitizeText ? opts.sanitizeText(content) : content;
|
|
6
|
+
const normalized = normalize(value);
|
|
7
|
+
return normalized ? normalized : null;
|
|
8
|
+
}
|
|
9
|
+
if (!Array.isArray(content)) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const chunks = [];
|
|
13
|
+
for (const block of content) {
|
|
14
|
+
if (!block || typeof block !== "object") {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (block.type !== "text") {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const text = block.text;
|
|
21
|
+
if (typeof text !== "string") {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const value = opts?.sanitizeText ? opts.sanitizeText(text) : text;
|
|
25
|
+
if (value.trim()) {
|
|
26
|
+
chunks.push(value);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const joined = normalize(chunks.join(joinWith));
|
|
30
|
+
return joined ? joined : null;
|
|
31
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const ENVELOPE_PREFIX = /^\[([^\]]+)\]\s*/;
|
|
2
|
+
const ENVELOPE_CHANNELS = [
|
|
3
|
+
"WebChat",
|
|
4
|
+
"WhatsApp",
|
|
5
|
+
"Telegram",
|
|
6
|
+
"Signal",
|
|
7
|
+
"Slack",
|
|
8
|
+
"Discord",
|
|
9
|
+
"Google Chat",
|
|
10
|
+
"iMessage",
|
|
11
|
+
"Teams",
|
|
12
|
+
"Matrix",
|
|
13
|
+
"Zalo",
|
|
14
|
+
"Zalo Personal",
|
|
15
|
+
"BlueBubbles",
|
|
16
|
+
];
|
|
17
|
+
const MESSAGE_ID_LINE = /^\s*\[message_id:\s*[^\]]+\]\s*$/i;
|
|
18
|
+
function looksLikeEnvelopeHeader(header) {
|
|
19
|
+
if (/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}Z\b/.test(header)) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
if (/\d{4}-\d{2}-\d{2} \d{2}:\d{2}\b/.test(header)) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
return ENVELOPE_CHANNELS.some((label) => header.startsWith(`${label} `));
|
|
26
|
+
}
|
|
27
|
+
export function stripEnvelope(text) {
|
|
28
|
+
const match = text.match(ENVELOPE_PREFIX);
|
|
29
|
+
if (!match) {
|
|
30
|
+
return text;
|
|
31
|
+
}
|
|
32
|
+
const header = match[1] ?? "";
|
|
33
|
+
if (!looksLikeEnvelopeHeader(header)) {
|
|
34
|
+
return text;
|
|
35
|
+
}
|
|
36
|
+
return text.slice(match[0].length);
|
|
37
|
+
}
|
|
38
|
+
export function stripMessageIdHints(text) {
|
|
39
|
+
if (!text.includes("[message_id:")) {
|
|
40
|
+
return text;
|
|
41
|
+
}
|
|
42
|
+
const lines = text.split(/\r?\n/);
|
|
43
|
+
const filtered = lines.filter((line) => !MESSAGE_ID_LINE.test(line));
|
|
44
|
+
return filtered.length === lines.length ? text : filtered.join("\n");
|
|
45
|
+
}
|