@poolzin/pool-bot 2026.2.21 → 2026.2.23
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/api-key-rotation.js +47 -0
- package/dist/agents/apply-patch-update.js +19 -9
- package/dist/agents/apply-patch.js +72 -47
- package/dist/agents/bash-tools.exec.js +141 -559
- package/dist/agents/cli-backends.js +49 -6
- package/dist/agents/cli-runner/helpers.js +69 -152
- package/dist/agents/cli-runner.js +70 -19
- package/dist/agents/identity.js +20 -1
- package/dist/agents/image-sanitization.js +9 -0
- package/dist/agents/live-auth-keys.js +123 -26
- package/dist/agents/live-model-filter.js +13 -4
- package/dist/agents/model-catalog.js +40 -9
- package/dist/agents/model-forward-compat.js +60 -23
- package/dist/agents/model-selection.js +134 -41
- package/dist/agents/pi-auth-json.js +2 -2
- package/dist/agents/pi-embedded-helpers/bootstrap.js +65 -15
- package/dist/agents/pi-embedded-helpers/errors.js +140 -15
- package/dist/agents/pi-embedded-helpers/images.js +22 -12
- package/dist/agents/pi-embedded-helpers.js +2 -2
- package/dist/agents/pi-embedded-runner/abort.js +10 -3
- package/dist/agents/pi-embedded-runner/compact.js +230 -32
- package/dist/agents/pi-embedded-runner/extra-params.js +203 -12
- package/dist/agents/pi-embedded-runner/google.js +109 -19
- package/dist/agents/pi-embedded-runner/history.js +35 -17
- package/dist/agents/pi-embedded-runner/run/attempt.js +386 -95
- package/dist/agents/pi-embedded-runner/run/images.js +81 -55
- package/dist/agents/pi-embedded-runner/run/payloads.js +89 -39
- package/dist/agents/pi-embedded-runner/run.js +193 -25
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +2 -2
- package/dist/agents/pi-embedded-runner/runs.js +17 -8
- package/dist/agents/pi-embedded-runner/tool-result-context-guard.js +262 -0
- package/dist/agents/pi-embedded-runner.js +1 -1
- package/dist/agents/pi-embedded-subscribe.handlers.tools.js +180 -10
- package/dist/agents/pi-embedded-subscribe.js +37 -0
- package/dist/agents/pi-embedded-subscribe.tools.js +127 -30
- package/dist/agents/pi-model-discovery.js +9 -2
- package/dist/agents/pi-tool-definition-adapter.js +60 -8
- package/dist/agents/pi-tools.before-tool-call.js +1 -1
- package/dist/agents/pi-tools.js +113 -94
- package/dist/agents/pi-tools.read.js +337 -38
- package/dist/agents/poolbot-tools.js +14 -5
- package/dist/agents/sandbox/docker.js +10 -5
- package/dist/agents/sandbox/registry.js +96 -46
- package/dist/agents/sandbox/sanitize-env-vars.js +82 -0
- package/dist/agents/sandbox-paths.js +43 -10
- package/dist/agents/session-tool-result-guard-wrapper.js +23 -11
- package/dist/agents/session-tool-result-guard.js +39 -39
- package/dist/agents/session-transcript-repair.js +36 -33
- package/dist/agents/session-write-lock.js +62 -44
- package/dist/agents/skills/frontmatter.js +49 -88
- package/dist/agents/skills/workspace.js +335 -28
- package/dist/agents/subagent-announce.js +508 -174
- package/dist/agents/subagent-registry.js +45 -4
- package/dist/agents/subagent-spawn.js +16 -33
- package/dist/agents/system-prompt-report.js +27 -10
- package/dist/agents/system-prompt.js +26 -32
- package/dist/agents/tool-call-id.js +69 -17
- package/dist/agents/tool-display-common.js +1 -1
- package/dist/agents/tool-images.js +64 -31
- package/dist/agents/tools/canvas-tool.js +17 -11
- package/dist/agents/tools/common.js +37 -19
- package/dist/agents/tools/cron-tool.js +40 -38
- package/dist/agents/tools/gateway.js +70 -2
- package/dist/agents/tools/message-tool.js +181 -40
- package/dist/agents/tools/nodes-tool.js +128 -36
- package/dist/agents/tools/nodes-utils.js +12 -38
- package/dist/agents/tools/session-status-tool.js +24 -71
- package/dist/agents/tools/sessions-helpers.js +38 -210
- package/dist/agents/tools/sessions-spawn-tool.js +28 -198
- package/dist/agents/tools/telegram-actions.js +58 -7
- package/dist/agents/tools/web-fetch-utils.js +112 -7
- package/dist/agents/tools/web-fetch.js +279 -175
- package/dist/agents/tools/web-shared.js +71 -8
- package/dist/agents/usage.js +25 -16
- package/dist/auto-reply/commands-registry.data.js +85 -11
- package/dist/auto-reply/dispatch.js +40 -21
- package/dist/auto-reply/reply/abort.js +102 -33
- package/dist/auto-reply/reply/commands-core.js +82 -33
- package/dist/auto-reply/reply/commands-export-session.js +1 -1
- package/dist/auto-reply/reply/commands-info.js +41 -12
- package/dist/auto-reply/reply/commands-subagents.js +352 -100
- package/dist/auto-reply/reply/commands-system-prompt.js +2 -2
- package/dist/auto-reply/reply/dispatch-from-config.js +100 -29
- package/dist/auto-reply/reply/elevated-unavailable.js +1 -1
- package/dist/auto-reply/reply/inbound-meta.js +12 -1
- package/dist/auto-reply/reply/mentions.js +18 -11
- package/dist/auto-reply/reply/normalize-reply.js +17 -8
- package/dist/auto-reply/reply/reply-dispatcher.js +62 -10
- package/dist/auto-reply/reply/session.js +102 -21
- package/dist/auto-reply/reply/streaming-directives.js +16 -5
- package/dist/auto-reply/status.js +73 -50
- package/dist/browser/extension-relay.js +3 -3
- package/dist/browser/http-auth.js +1 -1
- package/dist/browser/paths.js +2 -2
- package/dist/build-info.json +3 -3
- package/dist/channels/allowlist-match.js +20 -0
- package/dist/channels/allowlists/resolve-utils.js +65 -2
- package/dist/channels/chat-type.js +8 -4
- package/dist/channels/dock.js +127 -35
- package/dist/channels/draft-stream-loop.js +6 -2
- package/dist/channels/plugins/actions/telegram.js +42 -18
- package/dist/channels/plugins/allowlist-match.js +1 -1
- package/dist/channels/plugins/group-mentions.js +51 -41
- package/dist/channels/plugins/message-action-names.js +2 -0
- package/dist/channels/plugins/message-actions.js +24 -5
- package/dist/channels/plugins/normalize/discord.js +26 -4
- package/dist/channels/plugins/normalize/signal.js +35 -22
- package/dist/channels/plugins/onboarding/helpers.js +8 -26
- package/dist/channels/plugins/outbound/imessage.js +15 -14
- package/dist/channels/registry.js +20 -7
- package/dist/cli/acp-cli.js +7 -5
- package/dist/cli/browser-cli-extension.js +25 -12
- package/dist/cli/browser-cli-state.cookies-storage.js +25 -6
- package/dist/cli/browser-cli-state.js +101 -145
- package/dist/cli/command-options.js +28 -0
- package/dist/cli/completion-cli.js +6 -6
- package/dist/cli/cron-cli/register.cron-add.js +25 -1
- package/dist/cli/cron-cli/register.cron-edit.js +44 -0
- package/dist/cli/cron-cli/shared.js +7 -1
- package/dist/cli/daemon-cli/lifecycle-core.js +23 -21
- package/dist/cli/daemon-cli/lifecycle.js +23 -247
- package/dist/cli/daemon-cli/register-service-commands.js +25 -4
- package/dist/cli/daemon-cli.js +1 -0
- package/dist/cli/devices-cli.js +33 -20
- package/dist/cli/gateway-cli/register.js +37 -105
- package/dist/cli/gateway-cli/run.js +49 -11
- package/dist/cli/nodes-camera.js +59 -4
- package/dist/cli/nodes-cli/register.camera.js +27 -24
- package/dist/cli/nodes-cli/rpc.js +21 -38
- package/dist/cli/qr-cli.js +2 -2
- package/dist/cli/skills-cli.format.js +2 -2
- package/dist/cli/update-cli/progress.js +2 -2
- package/dist/cli/update-cli/restart-helper.js +28 -7
- package/dist/cli/update-cli/shared.js +7 -7
- package/dist/cli/update-cli/status.js +1 -1
- package/dist/cli/update-cli/update-command.js +14 -8
- package/dist/cli/update-cli/wizard.js +2 -2
- package/dist/cli/update-cli.js +21 -1027
- package/dist/commands/auth-choice.apply.anthropic.js +10 -2
- package/dist/commands/channels/add-mutators.js +3 -35
- package/dist/commands/channels/add.js +39 -51
- package/dist/commands/config-validation.js +1 -1
- package/dist/commands/configure.gateway-auth.js +52 -15
- package/dist/commands/configure.gateway.js +84 -40
- package/dist/commands/doctor-completion.js +3 -3
- package/dist/commands/doctor-config-flow.js +536 -16
- package/dist/commands/doctor-gateway-services.js +103 -79
- package/dist/commands/doctor-memory-search.js +9 -9
- package/dist/commands/doctor-platform-notes.js +57 -30
- package/dist/commands/doctor-prompter.js +26 -15
- package/dist/commands/doctor-session-locks.js +1 -1
- package/dist/commands/doctor.js +21 -9
- package/dist/commands/model-picker.js +120 -95
- package/dist/commands/models/set.js +2 -21
- package/dist/commands/models/shared.js +65 -37
- package/dist/commands/onboard-helpers.js +81 -39
- package/dist/commands/openai-codex-oauth.js +1 -1
- package/dist/commands/sessions.js +52 -53
- package/dist/commands/status.summary.js +52 -34
- package/dist/commands/test-wizard-helpers.js +2 -2
- package/dist/config/defaults.js +79 -42
- package/dist/config/group-policy.js +50 -18
- package/dist/config/includes.js +37 -10
- package/dist/config/schema.help.js +5 -4
- package/dist/config/schema.hints.js +2 -2
- package/dist/config/schema.labels.js +1 -0
- package/dist/config/sessions/group.js +12 -11
- package/dist/config/sessions/paths.js +137 -11
- package/dist/config/sessions/store.js +185 -65
- package/dist/config/sessions/types.js +15 -1
- package/dist/config/sessions.js +1 -0
- package/dist/config/telegram-custom-commands.js +3 -2
- package/dist/config/types.js +2 -0
- package/dist/config/zod-schema.agent-defaults.js +6 -27
- package/dist/config/zod-schema.agent-runtime.js +171 -79
- package/dist/config/zod-schema.providers-core.js +138 -65
- package/dist/config/zod-schema.session.js +49 -22
- package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
- package/dist/cron/isolated-agent/run.js +224 -57
- package/dist/cron/normalize.js +48 -45
- package/dist/cron/run-log.js +14 -0
- package/dist/cron/service/jobs.js +190 -28
- package/dist/cron/service/normalize.js +29 -11
- package/dist/cron/service/store.js +30 -44
- package/dist/cron/service/timer.js +182 -96
- package/dist/cron/service.js +3 -0
- package/dist/cron/stagger.js +37 -0
- package/dist/daemon/inspect.js +132 -92
- package/dist/daemon/runtime-paths.js +25 -4
- package/dist/daemon/service-audit.js +47 -16
- package/dist/discord/accounts.js +23 -20
- package/dist/discord/monitor/agent-components.js +1115 -219
- package/dist/discord/monitor/allow-list.js +114 -34
- package/dist/discord/monitor/listeners.js +204 -97
- package/dist/discord/monitor/message-handler.js +21 -10
- package/dist/discord/monitor/message-handler.preflight.js +195 -101
- package/dist/discord/monitor/message-handler.process.js +384 -123
- package/dist/discord/monitor/message-utils.js +86 -23
- package/dist/discord/monitor/native-command.js +77 -57
- package/dist/discord/monitor/provider.js +122 -117
- package/dist/discord/monitor/reply-context.js +20 -16
- package/dist/discord/monitor/reply-delivery.js +40 -8
- package/dist/discord/monitor/rest-fetch.js +22 -0
- package/dist/discord/monitor/threading.js +117 -24
- package/dist/discord/send.js +2 -1
- package/dist/discord/send.outbound.js +124 -11
- package/dist/discord/send.shared.js +112 -72
- package/dist/discord/voice-message.js +3 -3
- package/dist/gateway/auth.js +119 -44
- package/dist/gateway/call.js +76 -34
- package/dist/gateway/channel-health-monitor.js +57 -50
- package/dist/gateway/client.js +63 -29
- package/dist/gateway/control-ui-contract.js +1 -1
- package/dist/gateway/gateway-config-prompts.shared.js +2 -2
- package/dist/gateway/net.js +109 -1
- package/dist/gateway/protocol/index.js +5 -8
- package/dist/gateway/protocol/schema/agent.js +19 -1
- package/dist/gateway/protocol/schema/channels.js +21 -0
- package/dist/gateway/protocol/schema/cron.js +43 -30
- package/dist/gateway/protocol/schema/protocol-schemas.js +6 -11
- package/dist/gateway/protocol/schema/sessions.js +5 -1
- package/dist/gateway/protocol/schema.js +0 -1
- package/dist/gateway/server/presence-events.js +12 -0
- package/dist/gateway/server/ws-connection/message-handler.js +203 -212
- package/dist/gateway/server/ws-connection.js +58 -21
- package/dist/gateway/server-broadcast.js +18 -13
- package/dist/gateway/server-cron.js +177 -10
- package/dist/gateway/server-methods/agent-job.js +131 -38
- package/dist/gateway/server-methods/send.js +60 -14
- package/dist/gateway/server-methods/sessions.js +160 -96
- package/dist/gateway/server-methods/system.js +5 -7
- package/dist/gateway/server-methods-list.js +8 -0
- package/dist/gateway/server-methods.js +24 -8
- package/dist/gateway/server-node-events.js +278 -68
- package/dist/gateway/session-utils.fs.js +316 -75
- package/dist/gateway/session-utils.js +224 -70
- package/dist/gateway/sessions-patch.js +63 -20
- package/dist/gateway/test-temp-config.js +1 -1
- package/dist/gateway/tools-invoke-http.js +118 -70
- package/dist/gateway/ws-log.js +135 -107
- package/dist/hooks/frontmatter.js +36 -82
- package/dist/hooks/install.js +149 -139
- package/dist/hooks/internal-hooks.js +29 -4
- package/dist/hooks/plugin-hooks.js +2 -1
- package/dist/imessage/monitor/deliver.js +10 -4
- package/dist/imessage/monitor/monitor-provider.js +138 -375
- package/dist/imessage/monitor/runtime.js +4 -8
- package/dist/imessage/send.js +65 -19
- package/dist/infra/exec-approvals-allowlist.js +7 -0
- package/dist/infra/exec-approvals.js +35 -920
- package/dist/infra/exec-safe-bin-trust.js +64 -0
- package/dist/infra/heartbeat-runner.js +207 -134
- package/dist/infra/heartbeat-wake.js +183 -22
- package/dist/infra/install-source-utils.js +47 -0
- package/dist/infra/net/ssrf.js +170 -36
- package/dist/infra/outbound/deliver.js +224 -58
- package/dist/infra/outbound/message-action-spec.js +12 -5
- package/dist/infra/outbound/outbound-session.js +27 -25
- package/dist/infra/poolbot-root.js +32 -22
- package/dist/infra/ports.js +14 -11
- package/dist/infra/skills-remote.js +48 -37
- package/dist/infra/system-events.js +25 -11
- package/dist/infra/system-presence.js +26 -33
- package/dist/infra/tmp-poolbot-dir.js +81 -2
- package/dist/infra/wsl.js +37 -1
- package/dist/line/bot-message-context.js +163 -191
- package/dist/logging/subsystem.js +59 -22
- package/dist/markdown/ir.js +124 -50
- package/dist/media/store.js +1 -1
- package/dist/media-understanding/runner.entries.js +42 -25
- package/dist/media-understanding/runner.js +53 -488
- package/dist/memory/embeddings-gemini.js +53 -38
- package/dist/memory/manager-embedding-ops.js +48 -69
- package/dist/pairing/pairing-store.js +178 -119
- package/dist/plugin-sdk/index.js +34 -6
- package/dist/plugins/hooks.js +135 -14
- package/dist/plugins/install.js +190 -152
- package/dist/polls.js +11 -0
- package/dist/routing/resolve-route.js +190 -56
- package/dist/routing/session-key.js +38 -22
- package/dist/runtime.js +35 -9
- package/dist/security/audit-channel.js +1 -1
- package/dist/sessions/session-key-utils.js +29 -11
- package/dist/shared/frontmatter.js +5 -5
- package/dist/shared/node-list-types.js +1 -0
- package/dist/shared/string-normalization.js +15 -0
- package/dist/signal/monitor/event-handler.js +68 -36
- package/dist/signal/send.js +29 -37
- package/dist/slack/monitor/allow-list.js +10 -11
- package/dist/slack/monitor/commands.js +14 -3
- package/dist/slack/monitor/events/interactions.js +4 -4
- package/dist/slack/monitor/media.js +224 -16
- package/dist/slack/monitor/message-handler/dispatch.js +247 -13
- package/dist/slack/monitor/message-handler/prepare.js +128 -45
- package/dist/slack/monitor/slash.js +357 -144
- package/dist/slack/streaming.js +77 -0
- package/dist/telegram/accounts.js +40 -13
- package/dist/telegram/allowed-updates.js +3 -0
- package/dist/telegram/bot/delivery.js +129 -66
- package/dist/telegram/bot/helpers.js +136 -122
- package/dist/telegram/bot-handlers.js +600 -339
- package/dist/telegram/bot-message-context.js +115 -73
- package/dist/telegram/bot-message-dispatch.js +235 -104
- package/dist/telegram/bot-native-command-menu.js +3 -1
- package/dist/telegram/bot-native-commands.js +213 -193
- package/dist/telegram/bot.js +24 -132
- package/dist/telegram/draft-stream.js +84 -75
- package/dist/telegram/format.js +150 -6
- package/dist/telegram/send.js +415 -255
- package/dist/telegram/targets.js +21 -2
- package/dist/telegram/update-offset-store.js +19 -3
- package/dist/terminal/restore.js +5 -2
- package/dist/test-utils/fetch-mock.js +5 -0
- package/dist/version.js +18 -5
- package/dist/web/auto-reply/monitor/broadcast.js +7 -3
- package/dist/web/auto-reply/monitor/on-message.js +6 -3
- package/dist/web/inbound/media.js +34 -8
- package/dist/web/inbound/monitor.js +34 -17
- package/dist/web/inbound/send-api.js +18 -17
- package/dist/web/outbound.js +12 -5
- package/dist/wizard/clack-prompter.js +40 -7
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/device-pair/index.ts +2 -2
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/discord/package.json +1 -1
- package/extensions/feishu/package.json +1 -1
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/irc/src/accounts.ts +1 -1
- package/extensions/irc/src/onboarding.ts +4 -4
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +10 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +10 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +10 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/openai-codex-auth/package.json +1 -1
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +10 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +10 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +10 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +10 -0
- package/extensions/zalouser/package.json +1 -1
- package/package.json +1 -1
- package/skills/apple-reminders/SKILL.md +100 -49
- package/skills/coding-agent/SKILL.md +34 -28
- package/skills/github/SKILL.md +131 -16
- package/skills/imsg/SKILL.md +112 -15
- package/skills/openhue/SKILL.md +101 -19
- package/skills/tmux/SKILL.md +111 -79
- package/skills/weather/SKILL.md +88 -25
- package/dist/agents/openclaw-tools.js +0 -151
- package/dist/agents/tool-security.js +0 -96
- package/dist/gateway/url-validation.js +0 -94
- package/dist/infra/openclaw-root.js +0 -109
- package/dist/infra/tmp-openclaw-dir.js +0 -81
- package/dist/media/path-sanitization.js +0 -78
package/dist/telegram/targets.js
CHANGED
|
@@ -13,8 +13,9 @@ export function stripTelegramInternalPrefixes(to) {
|
|
|
13
13
|
}
|
|
14
14
|
return trimmed;
|
|
15
15
|
})();
|
|
16
|
-
if (next === trimmed)
|
|
16
|
+
if (next === trimmed) {
|
|
17
17
|
return trimmed;
|
|
18
|
+
}
|
|
18
19
|
trimmed = next;
|
|
19
20
|
}
|
|
20
21
|
}
|
|
@@ -26,6 +27,16 @@ export function stripTelegramInternalPrefixes(to) {
|
|
|
26
27
|
* - `chatId:topicId` (numeric topic/thread ID)
|
|
27
28
|
* - `chatId:topic:topicId` (explicit topic marker; preferred)
|
|
28
29
|
*/
|
|
30
|
+
function resolveTelegramChatType(chatId) {
|
|
31
|
+
const trimmed = chatId.trim();
|
|
32
|
+
if (!trimmed) {
|
|
33
|
+
return "unknown";
|
|
34
|
+
}
|
|
35
|
+
if (/^-?\d+$/.test(trimmed)) {
|
|
36
|
+
return trimmed.startsWith("-") ? "group" : "direct";
|
|
37
|
+
}
|
|
38
|
+
return "unknown";
|
|
39
|
+
}
|
|
29
40
|
export function parseTelegramTarget(to) {
|
|
30
41
|
const normalized = stripTelegramInternalPrefixes(to);
|
|
31
42
|
const topicMatch = /^(.+?):topic:(\d+)$/.exec(normalized);
|
|
@@ -33,6 +44,7 @@ export function parseTelegramTarget(to) {
|
|
|
33
44
|
return {
|
|
34
45
|
chatId: topicMatch[1],
|
|
35
46
|
messageThreadId: Number.parseInt(topicMatch[2], 10),
|
|
47
|
+
chatType: resolveTelegramChatType(topicMatch[1]),
|
|
36
48
|
};
|
|
37
49
|
}
|
|
38
50
|
const colonMatch = /^(.+):(\d+)$/.exec(normalized);
|
|
@@ -40,7 +52,14 @@ export function parseTelegramTarget(to) {
|
|
|
40
52
|
return {
|
|
41
53
|
chatId: colonMatch[1],
|
|
42
54
|
messageThreadId: Number.parseInt(colonMatch[2], 10),
|
|
55
|
+
chatType: resolveTelegramChatType(colonMatch[1]),
|
|
43
56
|
};
|
|
44
57
|
}
|
|
45
|
-
return {
|
|
58
|
+
return {
|
|
59
|
+
chatId: normalized,
|
|
60
|
+
chatType: resolveTelegramChatType(normalized),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export function resolveTelegramTargetChatType(target) {
|
|
64
|
+
return parseTelegramTarget(target).chatType;
|
|
46
65
|
}
|
|
@@ -6,8 +6,9 @@ import { resolveStateDir } from "../config/paths.js";
|
|
|
6
6
|
const STORE_VERSION = 1;
|
|
7
7
|
function normalizeAccountId(accountId) {
|
|
8
8
|
const trimmed = accountId?.trim();
|
|
9
|
-
if (!trimmed)
|
|
9
|
+
if (!trimmed) {
|
|
10
10
|
return "default";
|
|
11
|
+
}
|
|
11
12
|
return trimmed.replace(/[^a-z0-9._-]+/gi, "_");
|
|
12
13
|
}
|
|
13
14
|
function resolveTelegramUpdateOffsetPath(accountId, env = process.env) {
|
|
@@ -18,8 +19,9 @@ function resolveTelegramUpdateOffsetPath(accountId, env = process.env) {
|
|
|
18
19
|
function safeParseState(raw) {
|
|
19
20
|
try {
|
|
20
21
|
const parsed = JSON.parse(raw);
|
|
21
|
-
if (parsed?.version !== STORE_VERSION)
|
|
22
|
+
if (parsed?.version !== STORE_VERSION) {
|
|
22
23
|
return null;
|
|
24
|
+
}
|
|
23
25
|
if (parsed.lastUpdateId !== null && typeof parsed.lastUpdateId !== "number") {
|
|
24
26
|
return null;
|
|
25
27
|
}
|
|
@@ -38,8 +40,9 @@ export async function readTelegramUpdateOffset(params) {
|
|
|
38
40
|
}
|
|
39
41
|
catch (err) {
|
|
40
42
|
const code = err.code;
|
|
41
|
-
if (code === "ENOENT")
|
|
43
|
+
if (code === "ENOENT") {
|
|
42
44
|
return null;
|
|
45
|
+
}
|
|
43
46
|
return null;
|
|
44
47
|
}
|
|
45
48
|
}
|
|
@@ -58,3 +61,16 @@ export async function writeTelegramUpdateOffset(params) {
|
|
|
58
61
|
await fs.chmod(tmp, 0o600);
|
|
59
62
|
await fs.rename(tmp, filePath);
|
|
60
63
|
}
|
|
64
|
+
export async function deleteTelegramUpdateOffset(params) {
|
|
65
|
+
const filePath = resolveTelegramUpdateOffsetPath(params.accountId, params.env);
|
|
66
|
+
try {
|
|
67
|
+
await fs.unlink(filePath);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
const code = err.code;
|
|
71
|
+
if (code === "ENOENT") {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
throw err;
|
|
75
|
+
}
|
|
76
|
+
}
|
package/dist/terminal/restore.js
CHANGED
|
@@ -10,7 +10,10 @@ function reportRestoreFailure(scope, err, reason) {
|
|
|
10
10
|
console.error(`[terminal] restore reporting failed${suffix}: ${String(writeErr)}`);
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
-
export function restoreTerminalState(reason) {
|
|
13
|
+
export function restoreTerminalState(reason, options = {}) {
|
|
14
|
+
// Docker TTY note: resuming stdin can keep a container process alive even
|
|
15
|
+
// after the wizard is "done" (stdin_open: true), making installers appear hung.
|
|
16
|
+
const resumeStdin = options.resumeStdinIfPaused ?? options.resumeStdin ?? false;
|
|
14
17
|
try {
|
|
15
18
|
clearActiveProgressLine();
|
|
16
19
|
}
|
|
@@ -25,7 +28,7 @@ export function restoreTerminalState(reason) {
|
|
|
25
28
|
catch (err) {
|
|
26
29
|
reportRestoreFailure("raw mode", err, reason);
|
|
27
30
|
}
|
|
28
|
-
if (typeof stdin.isPaused === "function" && stdin.isPaused()) {
|
|
31
|
+
if (resumeStdin && typeof stdin.isPaused === "function" && stdin.isPaused()) {
|
|
29
32
|
try {
|
|
30
33
|
stdin.resume();
|
|
31
34
|
}
|
package/dist/version.js
CHANGED
|
@@ -18,10 +18,12 @@ function readVersionFromJsonCandidates(moduleUrl, candidates, opts = {}) {
|
|
|
18
18
|
try {
|
|
19
19
|
const parsed = require(candidate);
|
|
20
20
|
const version = parsed.version?.trim();
|
|
21
|
-
if (!version)
|
|
21
|
+
if (!version) {
|
|
22
22
|
continue;
|
|
23
|
-
|
|
23
|
+
}
|
|
24
|
+
if (opts.requirePackageName && parsed.name !== CORE_PACKAGE_NAME) {
|
|
24
25
|
continue;
|
|
26
|
+
}
|
|
25
27
|
return version;
|
|
26
28
|
}
|
|
27
29
|
catch {
|
|
@@ -34,6 +36,15 @@ function readVersionFromJsonCandidates(moduleUrl, candidates, opts = {}) {
|
|
|
34
36
|
return null;
|
|
35
37
|
}
|
|
36
38
|
}
|
|
39
|
+
function firstNonEmpty(...values) {
|
|
40
|
+
for (const value of values) {
|
|
41
|
+
const trimmed = value?.trim();
|
|
42
|
+
if (trimmed) {
|
|
43
|
+
return trimmed;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
37
48
|
export function readVersionFromPackageJsonForModuleUrl(moduleUrl) {
|
|
38
49
|
return readVersionFromJsonCandidates(moduleUrl, PACKAGE_JSON_CANDIDATES, {
|
|
39
50
|
requirePackageName: true,
|
|
@@ -46,11 +57,13 @@ export function resolveVersionFromModuleUrl(moduleUrl) {
|
|
|
46
57
|
return (readVersionFromPackageJsonForModuleUrl(moduleUrl) ||
|
|
47
58
|
readVersionFromBuildInfoForModuleUrl(moduleUrl));
|
|
48
59
|
}
|
|
49
|
-
|
|
60
|
+
export function resolveRuntimeServiceVersion(env = process.env, fallback = "dev") {
|
|
61
|
+
return (firstNonEmpty(env["POOLBOT_VERSION"], env["POOLBOT_SERVICE_VERSION"], env["npm_package_version"]) ?? fallback);
|
|
62
|
+
}
|
|
63
|
+
// Single source of truth for the current Pool Bot version.
|
|
50
64
|
// - Embedded/bundled builds: injected define or env var.
|
|
51
65
|
// - Dev/npm builds: package.json.
|
|
52
|
-
export const VERSION = (typeof
|
|
66
|
+
export const VERSION = (typeof __POOLBOT_VERSION__ === "string" && __POOLBOT_VERSION__) ||
|
|
53
67
|
process.env.POOLBOT_BUNDLED_VERSION ||
|
|
54
|
-
process.env.CLAWDBOT_BUNDLED_VERSION ||
|
|
55
68
|
resolveVersionFromModuleUrl(import.meta.url) ||
|
|
56
69
|
"0.0.0";
|
|
@@ -4,10 +4,12 @@ import { formatError } from "../../session.js";
|
|
|
4
4
|
import { whatsappInboundLog } from "../loggers.js";
|
|
5
5
|
export async function maybeBroadcastMessage(params) {
|
|
6
6
|
const broadcastAgents = params.cfg.broadcast?.[params.peerId];
|
|
7
|
-
if (!broadcastAgents || !Array.isArray(broadcastAgents))
|
|
7
|
+
if (!broadcastAgents || !Array.isArray(broadcastAgents)) {
|
|
8
8
|
return false;
|
|
9
|
-
|
|
9
|
+
}
|
|
10
|
+
if (broadcastAgents.length === 0) {
|
|
10
11
|
return false;
|
|
12
|
+
}
|
|
11
13
|
const strategy = params.cfg.broadcast?.strategy || "parallel";
|
|
12
14
|
whatsappInboundLog.info(`Broadcasting message to ${broadcastAgents.length} agents (${strategy})`);
|
|
13
15
|
const agentIds = params.cfg.agents?.list?.map((agent) => normalizeAgentId(agent.id));
|
|
@@ -27,11 +29,13 @@ export async function maybeBroadcastMessage(params) {
|
|
|
27
29
|
sessionKey: buildAgentSessionKey({
|
|
28
30
|
agentId: normalizedAgentId,
|
|
29
31
|
channel: "whatsapp",
|
|
32
|
+
accountId: params.route.accountId,
|
|
30
33
|
peer: {
|
|
31
|
-
kind: params.msg.chatType === "group" ? "group" : "
|
|
34
|
+
kind: params.msg.chatType === "group" ? "group" : "direct",
|
|
32
35
|
id: params.peerId,
|
|
33
36
|
},
|
|
34
37
|
dmScope: params.cfg.session?.dmScope,
|
|
38
|
+
identityLinks: params.cfg.session?.identityLinks,
|
|
35
39
|
}),
|
|
36
40
|
mainSessionKey: buildAgentMainSessionKey({
|
|
37
41
|
agentId: normalizedAgentId,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { loadConfig } from "../../../config/config.js";
|
|
1
2
|
import { logVerbose } from "../../../globals.js";
|
|
2
3
|
import { resolveAgentRoute } from "../../../routing/resolve-route.js";
|
|
3
4
|
import { buildGroupHistoryKey } from "../../../routing/session-key.js";
|
|
@@ -31,12 +32,13 @@ export function createWebOnMessageHandler(params) {
|
|
|
31
32
|
return async (msg) => {
|
|
32
33
|
const conversationId = msg.conversationId ?? msg.from;
|
|
33
34
|
const peerId = resolvePeerId(msg);
|
|
35
|
+
// Fresh config for bindings lookup; other routing inputs are payload-derived.
|
|
34
36
|
const route = resolveAgentRoute({
|
|
35
|
-
cfg:
|
|
37
|
+
cfg: loadConfig(),
|
|
36
38
|
channel: "whatsapp",
|
|
37
39
|
accountId: msg.accountId,
|
|
38
40
|
peer: {
|
|
39
|
-
kind: msg.chatType === "group" ? "group" : "
|
|
41
|
+
kind: msg.chatType === "group" ? "group" : "direct",
|
|
40
42
|
id: peerId,
|
|
41
43
|
},
|
|
42
44
|
});
|
|
@@ -101,8 +103,9 @@ export function createWebOnMessageHandler(params) {
|
|
|
101
103
|
logVerbose,
|
|
102
104
|
replyLogger: params.replyLogger,
|
|
103
105
|
});
|
|
104
|
-
if (!gating.shouldProcess)
|
|
106
|
+
if (!gating.shouldProcess) {
|
|
105
107
|
return;
|
|
108
|
+
}
|
|
106
109
|
}
|
|
107
110
|
else {
|
|
108
111
|
// Ensure `peerId` for DMs is stable and stored as E.164 when possible.
|
|
@@ -4,16 +4,42 @@ function unwrapMessage(message) {
|
|
|
4
4
|
const normalized = normalizeMessageContent(message);
|
|
5
5
|
return normalized;
|
|
6
6
|
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Resolve the MIME type for an inbound media message.
|
|
9
|
+
* Falls back to WhatsApp's standard formats when Baileys omits the MIME.
|
|
10
|
+
*/
|
|
11
|
+
function resolveMediaMimetype(message) {
|
|
12
|
+
const explicit = message.imageMessage?.mimetype ??
|
|
12
13
|
message.videoMessage?.mimetype ??
|
|
13
14
|
message.documentMessage?.mimetype ??
|
|
14
15
|
message.audioMessage?.mimetype ??
|
|
15
16
|
message.stickerMessage?.mimetype ??
|
|
16
17
|
undefined;
|
|
18
|
+
if (explicit) {
|
|
19
|
+
return explicit;
|
|
20
|
+
}
|
|
21
|
+
// WhatsApp voice messages (PTT) and audio use OGG Opus by default
|
|
22
|
+
if (message.audioMessage) {
|
|
23
|
+
return "audio/ogg; codecs=opus";
|
|
24
|
+
}
|
|
25
|
+
if (message.imageMessage) {
|
|
26
|
+
return "image/jpeg";
|
|
27
|
+
}
|
|
28
|
+
if (message.videoMessage) {
|
|
29
|
+
return "video/mp4";
|
|
30
|
+
}
|
|
31
|
+
if (message.stickerMessage) {
|
|
32
|
+
return "image/webp";
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
export async function downloadInboundMedia(msg, sock) {
|
|
37
|
+
const message = unwrapMessage(msg.message);
|
|
38
|
+
if (!message) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
const mimetype = resolveMediaMimetype(message);
|
|
42
|
+
const fileName = message.documentMessage?.fileName ?? undefined;
|
|
17
43
|
if (!message.imageMessage &&
|
|
18
44
|
!message.videoMessage &&
|
|
19
45
|
!message.documentMessage &&
|
|
@@ -22,11 +48,11 @@ export async function downloadInboundMedia(msg, sock) {
|
|
|
22
48
|
return undefined;
|
|
23
49
|
}
|
|
24
50
|
try {
|
|
25
|
-
const buffer =
|
|
51
|
+
const buffer = await downloadMediaMessage(msg, "buffer", {}, {
|
|
26
52
|
reuploadRequest: sock.updateMediaMessage,
|
|
27
53
|
logger: sock.logger,
|
|
28
|
-
})
|
|
29
|
-
return { buffer, mimetype };
|
|
54
|
+
});
|
|
55
|
+
return { buffer, mimetype, fileName };
|
|
30
56
|
}
|
|
31
57
|
catch (err) {
|
|
32
58
|
logVerbose(`downloadMediaMessage failed: ${String(err)}`);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { DisconnectReason, isJidGroup } from "@whiskeysockets/baileys";
|
|
2
|
+
import { createInboundDebouncer } from "../../auto-reply/inbound-debounce.js";
|
|
2
3
|
import { formatLocationText } from "../../channels/location.js";
|
|
3
4
|
import { logVerbose, shouldLogVerbose } from "../../globals.js";
|
|
4
5
|
import { recordChannelActivity } from "../../infra/channel-activity.js";
|
|
5
6
|
import { getChildLogger } from "../../logging/logger.js";
|
|
6
7
|
import { createSubsystemLogger } from "../../logging/subsystem.js";
|
|
7
8
|
import { saveMediaBuffer } from "../../media/store.js";
|
|
8
|
-
import { createInboundDebouncer } from "../../auto-reply/inbound-debounce.js";
|
|
9
9
|
import { jidToE164, resolveJidToE164 } from "../../utils.js";
|
|
10
10
|
import { createWaSocket, getStatusCode, waitForWaConnection } from "../session.js";
|
|
11
11
|
import { checkInboundAccessControl } from "./access-control.js";
|
|
@@ -26,16 +26,18 @@ export async function monitorWebInbox(options) {
|
|
|
26
26
|
onCloseResolve = resolve;
|
|
27
27
|
});
|
|
28
28
|
const resolveClose = (reason) => {
|
|
29
|
-
if (!onCloseResolve)
|
|
29
|
+
if (!onCloseResolve) {
|
|
30
30
|
return;
|
|
31
|
+
}
|
|
31
32
|
const resolver = onCloseResolve;
|
|
32
33
|
onCloseResolve = null;
|
|
33
34
|
resolver(reason);
|
|
34
35
|
};
|
|
35
36
|
try {
|
|
36
37
|
await sock.sendPresenceUpdate("available");
|
|
37
|
-
if (shouldLogVerbose())
|
|
38
|
+
if (shouldLogVerbose()) {
|
|
38
39
|
logVerbose("Sent global 'available' presence on connect");
|
|
40
|
+
}
|
|
39
41
|
}
|
|
40
42
|
catch (err) {
|
|
41
43
|
logVerbose(`Failed to send 'available' presence on connect: ${String(err)}`);
|
|
@@ -48,24 +50,27 @@ export async function monitorWebInbox(options) {
|
|
|
48
50
|
const senderKey = msg.chatType === "group"
|
|
49
51
|
? (msg.senderJid ?? msg.senderE164 ?? msg.senderName ?? msg.from)
|
|
50
52
|
: msg.from;
|
|
51
|
-
if (!senderKey)
|
|
53
|
+
if (!senderKey) {
|
|
52
54
|
return null;
|
|
55
|
+
}
|
|
53
56
|
const conversationKey = msg.chatType === "group" ? msg.chatId : msg.from;
|
|
54
57
|
return `${msg.accountId}:${conversationKey}:${senderKey}`;
|
|
55
58
|
},
|
|
56
59
|
shouldDebounce: options.shouldDebounce,
|
|
57
60
|
onFlush: async (entries) => {
|
|
58
61
|
const last = entries.at(-1);
|
|
59
|
-
if (!last)
|
|
62
|
+
if (!last) {
|
|
60
63
|
return;
|
|
64
|
+
}
|
|
61
65
|
if (entries.length === 1) {
|
|
62
66
|
await options.onMessage(last);
|
|
63
67
|
return;
|
|
64
68
|
}
|
|
65
69
|
const mentioned = new Set();
|
|
66
70
|
for (const entry of entries) {
|
|
67
|
-
for (const jid of entry.mentionedJids ?? [])
|
|
71
|
+
for (const jid of entry.mentionedJids ?? []) {
|
|
68
72
|
mentioned.add(jid);
|
|
73
|
+
}
|
|
69
74
|
}
|
|
70
75
|
const combinedBody = entries
|
|
71
76
|
.map((entry) => entry.body)
|
|
@@ -89,8 +94,9 @@ export async function monitorWebInbox(options) {
|
|
|
89
94
|
const resolveInboundJid = async (jid) => resolveJidToE164(jid, { authDir: options.authDir, lidLookup });
|
|
90
95
|
const getGroupMeta = async (jid) => {
|
|
91
96
|
const cached = groupMetaCache.get(jid);
|
|
92
|
-
if (cached && cached.expires > Date.now())
|
|
97
|
+
if (cached && cached.expires > Date.now()) {
|
|
93
98
|
return cached;
|
|
99
|
+
}
|
|
94
100
|
try {
|
|
95
101
|
const meta = await sock.groupMetadata(jid);
|
|
96
102
|
const participants = (await Promise.all(meta.participants?.map(async (p) => {
|
|
@@ -111,8 +117,9 @@ export async function monitorWebInbox(options) {
|
|
|
111
117
|
}
|
|
112
118
|
};
|
|
113
119
|
const handleMessagesUpsert = async (upsert) => {
|
|
114
|
-
if (upsert.type !== "notify" && upsert.type !== "append")
|
|
120
|
+
if (upsert.type !== "notify" && upsert.type !== "append") {
|
|
115
121
|
return;
|
|
122
|
+
}
|
|
116
123
|
for (const msg of upsert.messages ?? []) {
|
|
117
124
|
recordChannelActivity({
|
|
118
125
|
channel: "whatsapp",
|
|
@@ -121,20 +128,24 @@ export async function monitorWebInbox(options) {
|
|
|
121
128
|
});
|
|
122
129
|
const id = msg.key?.id ?? undefined;
|
|
123
130
|
const remoteJid = msg.key?.remoteJid;
|
|
124
|
-
if (!remoteJid)
|
|
131
|
+
if (!remoteJid) {
|
|
125
132
|
continue;
|
|
126
|
-
|
|
133
|
+
}
|
|
134
|
+
if (remoteJid.endsWith("@status") || remoteJid.endsWith("@broadcast")) {
|
|
127
135
|
continue;
|
|
136
|
+
}
|
|
128
137
|
const group = isJidGroup(remoteJid) === true;
|
|
129
138
|
if (id) {
|
|
130
139
|
const dedupeKey = `${options.accountId}:${remoteJid}:${id}`;
|
|
131
|
-
if (isRecentInboundMessage(dedupeKey))
|
|
140
|
+
if (isRecentInboundMessage(dedupeKey)) {
|
|
132
141
|
continue;
|
|
142
|
+
}
|
|
133
143
|
}
|
|
134
144
|
const participantJid = msg.key?.participant ?? undefined;
|
|
135
145
|
const from = group ? remoteJid : await resolveInboundJid(remoteJid);
|
|
136
|
-
if (!from)
|
|
146
|
+
if (!from) {
|
|
137
147
|
continue;
|
|
148
|
+
}
|
|
138
149
|
const senderE164 = group
|
|
139
150
|
? participantJid
|
|
140
151
|
? await resolveInboundJid(participantJid)
|
|
@@ -163,8 +174,9 @@ export async function monitorWebInbox(options) {
|
|
|
163
174
|
sock: { sendMessage: (jid, content) => sock.sendMessage(jid, content) },
|
|
164
175
|
remoteJid,
|
|
165
176
|
});
|
|
166
|
-
if (!access.allowed)
|
|
177
|
+
if (!access.allowed) {
|
|
167
178
|
continue;
|
|
179
|
+
}
|
|
168
180
|
if (id && !access.isSelfChat && options.sendReadReceipts !== false) {
|
|
169
181
|
const participant = msg.key?.participant;
|
|
170
182
|
try {
|
|
@@ -183,8 +195,9 @@ export async function monitorWebInbox(options) {
|
|
|
183
195
|
logVerbose(`Self-chat mode: skipping read receipt for ${id}`);
|
|
184
196
|
}
|
|
185
197
|
// If this is history/offline catch-up, mark read above but skip auto-reply.
|
|
186
|
-
if (upsert.type === "append")
|
|
198
|
+
if (upsert.type === "append") {
|
|
187
199
|
continue;
|
|
200
|
+
}
|
|
188
201
|
const location = extractLocationData(msg.message ?? undefined);
|
|
189
202
|
const locationText = location ? formatLocationText(location) : undefined;
|
|
190
203
|
let body = extractText(msg.message ?? undefined);
|
|
@@ -193,12 +206,14 @@ export async function monitorWebInbox(options) {
|
|
|
193
206
|
}
|
|
194
207
|
if (!body) {
|
|
195
208
|
body = extractMediaPlaceholder(msg.message ?? undefined);
|
|
196
|
-
if (!body)
|
|
209
|
+
if (!body) {
|
|
197
210
|
continue;
|
|
211
|
+
}
|
|
198
212
|
}
|
|
199
213
|
const replyContext = describeReplyContext(msg.message);
|
|
200
214
|
let mediaPath;
|
|
201
215
|
let mediaType;
|
|
216
|
+
let mediaFileName;
|
|
202
217
|
try {
|
|
203
218
|
const inboundMedia = await downloadInboundMedia(msg, sock);
|
|
204
219
|
if (inboundMedia) {
|
|
@@ -206,9 +221,10 @@ export async function monitorWebInbox(options) {
|
|
|
206
221
|
? options.mediaMaxMb
|
|
207
222
|
: 50;
|
|
208
223
|
const maxBytes = maxMb * 1024 * 1024;
|
|
209
|
-
const saved = await saveMediaBuffer(inboundMedia.buffer, inboundMedia.mimetype, "inbound", maxBytes);
|
|
224
|
+
const saved = await saveMediaBuffer(inboundMedia.buffer, inboundMedia.mimetype, "inbound", maxBytes, inboundMedia.fileName);
|
|
210
225
|
mediaPath = saved.path;
|
|
211
226
|
mediaType = inboundMedia.mimetype;
|
|
227
|
+
mediaFileName = inboundMedia.fileName;
|
|
212
228
|
}
|
|
213
229
|
}
|
|
214
230
|
catch (err) {
|
|
@@ -232,7 +248,7 @@ export async function monitorWebInbox(options) {
|
|
|
232
248
|
const timestamp = messageTimestampMs;
|
|
233
249
|
const mentionedJids = extractMentionedJids(msg.message);
|
|
234
250
|
const senderName = msg.pushName ?? undefined;
|
|
235
|
-
inboundLogger.info({ from, to: selfE164 ?? "me", body, mediaPath, mediaType, timestamp }, "inbound message");
|
|
251
|
+
inboundLogger.info({ from, to: selfE164 ?? "me", body, mediaPath, mediaType, mediaFileName, timestamp }, "inbound message");
|
|
236
252
|
const inboundMessage = {
|
|
237
253
|
id,
|
|
238
254
|
from,
|
|
@@ -263,6 +279,7 @@ export async function monitorWebInbox(options) {
|
|
|
263
279
|
sendMedia,
|
|
264
280
|
mediaPath,
|
|
265
281
|
mediaType,
|
|
282
|
+
mediaFileName,
|
|
266
283
|
};
|
|
267
284
|
try {
|
|
268
285
|
const task = Promise.resolve(debouncer.enqueue(inboundMessage));
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { recordChannelActivity } from "../../infra/channel-activity.js";
|
|
2
2
|
import { toWhatsappJid } from "../../utils.js";
|
|
3
|
+
function recordWhatsAppOutbound(accountId) {
|
|
4
|
+
recordChannelActivity({
|
|
5
|
+
channel: "whatsapp",
|
|
6
|
+
accountId,
|
|
7
|
+
direction: "outbound",
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
function resolveOutboundMessageId(result) {
|
|
11
|
+
return typeof result === "object" && result && "key" in result
|
|
12
|
+
? String(result.key?.id ?? "unknown")
|
|
13
|
+
: "unknown";
|
|
14
|
+
}
|
|
3
15
|
export function createWebSendApi(params) {
|
|
4
16
|
return {
|
|
5
17
|
sendMessage: async (to, text, mediaBuffer, mediaType, sendOptions) => {
|
|
@@ -26,9 +38,10 @@ export function createWebSendApi(params) {
|
|
|
26
38
|
};
|
|
27
39
|
}
|
|
28
40
|
else {
|
|
41
|
+
const fileName = sendOptions?.fileName?.trim() || "file";
|
|
29
42
|
payload = {
|
|
30
43
|
document: mediaBuffer,
|
|
31
|
-
fileName
|
|
44
|
+
fileName,
|
|
32
45
|
caption: text || undefined,
|
|
33
46
|
mimetype: mediaType,
|
|
34
47
|
};
|
|
@@ -39,14 +52,8 @@ export function createWebSendApi(params) {
|
|
|
39
52
|
}
|
|
40
53
|
const result = await params.sock.sendMessage(jid, payload);
|
|
41
54
|
const accountId = sendOptions?.accountId ?? params.defaultAccountId;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
accountId,
|
|
45
|
-
direction: "outbound",
|
|
46
|
-
});
|
|
47
|
-
const messageId = typeof result === "object" && result && "key" in result
|
|
48
|
-
? String(result.key?.id ?? "unknown")
|
|
49
|
-
: "unknown";
|
|
55
|
+
recordWhatsAppOutbound(accountId);
|
|
56
|
+
const messageId = resolveOutboundMessageId(result);
|
|
50
57
|
return { messageId };
|
|
51
58
|
},
|
|
52
59
|
sendPoll: async (to, poll) => {
|
|
@@ -58,14 +65,8 @@ export function createWebSendApi(params) {
|
|
|
58
65
|
selectableCount: poll.maxSelections ?? 1,
|
|
59
66
|
},
|
|
60
67
|
});
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
accountId: params.defaultAccountId,
|
|
64
|
-
direction: "outbound",
|
|
65
|
-
});
|
|
66
|
-
const messageId = typeof result === "object" && result && "key" in result
|
|
67
|
-
? String(result.key?.id ?? "unknown")
|
|
68
|
-
: "unknown";
|
|
68
|
+
recordWhatsAppOutbound(params.defaultAccountId);
|
|
69
|
+
const messageId = resolveOutboundMessageId(result);
|
|
69
70
|
return { messageId };
|
|
70
71
|
},
|
|
71
72
|
sendReaction: async (chatJid, messageId, emoji, fromMe, participant) => {
|
package/dist/web/outbound.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { loadConfig } from "../config/config.js";
|
|
3
|
+
import { resolveMarkdownTableMode } from "../config/markdown-tables.js";
|
|
2
4
|
import { getChildLogger } from "../logging/logger.js";
|
|
3
5
|
import { createSubsystemLogger } from "../logging/subsystem.js";
|
|
6
|
+
import { convertMarkdownTables } from "../markdown/tables.js";
|
|
7
|
+
import { markdownToWhatsApp } from "../markdown/whatsapp.js";
|
|
4
8
|
import { normalizePollInput } from "../polls.js";
|
|
5
9
|
import { toWhatsappJid } from "../utils.js";
|
|
6
|
-
import { loadConfig } from "../config/config.js";
|
|
7
|
-
import { resolveMarkdownTableMode } from "../config/markdown-tables.js";
|
|
8
|
-
import { convertMarkdownTables } from "../markdown/tables.js";
|
|
9
10
|
import { requireActiveWebListener } from "./active-listener.js";
|
|
10
11
|
import { loadWebMedia } from "./media.js";
|
|
11
12
|
const outboundLog = createSubsystemLogger("gateway/channels/whatsapp").child("outbound");
|
|
@@ -21,6 +22,7 @@ export async function sendMessageWhatsApp(to, body, options) {
|
|
|
21
22
|
accountId: resolvedAccountId ?? options.accountId,
|
|
22
23
|
});
|
|
23
24
|
text = convertMarkdownTables(text ?? "", tableMode);
|
|
25
|
+
text = markdownToWhatsApp(text);
|
|
24
26
|
const logger = getChildLogger({
|
|
25
27
|
module: "web-outbound",
|
|
26
28
|
correlationId,
|
|
@@ -30,8 +32,11 @@ export async function sendMessageWhatsApp(to, body, options) {
|
|
|
30
32
|
const jid = toWhatsappJid(to);
|
|
31
33
|
let mediaBuffer;
|
|
32
34
|
let mediaType;
|
|
35
|
+
let documentFileName;
|
|
33
36
|
if (options.mediaUrl) {
|
|
34
|
-
const media = await loadWebMedia(options.mediaUrl
|
|
37
|
+
const media = await loadWebMedia(options.mediaUrl, {
|
|
38
|
+
localRoots: options.mediaLocalRoots,
|
|
39
|
+
});
|
|
35
40
|
const caption = text || undefined;
|
|
36
41
|
mediaBuffer = media.buffer;
|
|
37
42
|
mediaType = media.contentType;
|
|
@@ -50,6 +55,7 @@ export async function sendMessageWhatsApp(to, body, options) {
|
|
|
50
55
|
}
|
|
51
56
|
else {
|
|
52
57
|
text = caption ?? "";
|
|
58
|
+
documentFileName = media.fileName;
|
|
53
59
|
}
|
|
54
60
|
}
|
|
55
61
|
outboundLog.info(`Sending message -> ${jid}${options.mediaUrl ? " (media)" : ""}`);
|
|
@@ -57,9 +63,10 @@ export async function sendMessageWhatsApp(to, body, options) {
|
|
|
57
63
|
await active.sendComposingTo(to);
|
|
58
64
|
const hasExplicitAccountId = Boolean(options.accountId?.trim());
|
|
59
65
|
const accountId = hasExplicitAccountId ? resolvedAccountId : undefined;
|
|
60
|
-
const sendOptions = options.gifPlayback || accountId
|
|
66
|
+
const sendOptions = options.gifPlayback || accountId || documentFileName
|
|
61
67
|
? {
|
|
62
68
|
...(options.gifPlayback ? { gifPlayback: true } : {}),
|
|
69
|
+
...(documentFileName ? { fileName: documentFileName } : {}),
|
|
63
70
|
accountId,
|
|
64
71
|
}
|
|
65
72
|
: undefined;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { cancel, confirm, intro, isCancel, multiselect, outro, select, spinner, text, } from "@clack/prompts";
|
|
1
|
+
import { autocompleteMultiselect, cancel, confirm, intro, isCancel, multiselect, outro, select, spinner, text, } from "@clack/prompts";
|
|
2
2
|
import { createCliProgress } from "../cli/progress.js";
|
|
3
|
+
import { stripAnsi } from "../terminal/ansi.js";
|
|
3
4
|
import { note as emitNote } from "../terminal/note.js";
|
|
4
5
|
import { stylePromptHint, stylePromptMessage, stylePromptTitle } from "../terminal/prompt-style.js";
|
|
5
6
|
import { theme } from "../terminal/theme.js";
|
|
@@ -11,6 +12,27 @@ function guardCancel(value) {
|
|
|
11
12
|
}
|
|
12
13
|
return value;
|
|
13
14
|
}
|
|
15
|
+
function normalizeSearchTokens(search) {
|
|
16
|
+
return search
|
|
17
|
+
.toLowerCase()
|
|
18
|
+
.split(/\s+/)
|
|
19
|
+
.map((token) => token.trim())
|
|
20
|
+
.filter((token) => token.length > 0);
|
|
21
|
+
}
|
|
22
|
+
function buildOptionSearchText(option) {
|
|
23
|
+
const label = stripAnsi(option.label ?? "");
|
|
24
|
+
const hint = stripAnsi(option.hint ?? "");
|
|
25
|
+
const value = String(option.value ?? "");
|
|
26
|
+
return `${label} ${hint} ${value}`.toLowerCase();
|
|
27
|
+
}
|
|
28
|
+
export function tokenizedOptionFilter(search, option) {
|
|
29
|
+
const tokens = normalizeSearchTokens(search);
|
|
30
|
+
if (tokens.length === 0) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
const haystack = buildOptionSearchText(option);
|
|
34
|
+
return tokens.every((token) => haystack.includes(token));
|
|
35
|
+
}
|
|
14
36
|
export function createClackPrompter() {
|
|
15
37
|
return {
|
|
16
38
|
intro: async (title) => {
|
|
@@ -30,14 +52,25 @@ export function createClackPrompter() {
|
|
|
30
52
|
}),
|
|
31
53
|
initialValue: params.initialValue,
|
|
32
54
|
})),
|
|
33
|
-
multiselect: async (params) =>
|
|
34
|
-
|
|
35
|
-
options: params.options.map((opt) => {
|
|
55
|
+
multiselect: async (params) => {
|
|
56
|
+
const options = params.options.map((opt) => {
|
|
36
57
|
const base = { value: opt.value, label: opt.label };
|
|
37
58
|
return opt.hint === undefined ? base : { ...base, hint: stylePromptHint(opt.hint) };
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
|
|
59
|
+
});
|
|
60
|
+
if (params.searchable) {
|
|
61
|
+
return guardCancel(await autocompleteMultiselect({
|
|
62
|
+
message: stylePromptMessage(params.message),
|
|
63
|
+
options,
|
|
64
|
+
initialValues: params.initialValues,
|
|
65
|
+
filter: tokenizedOptionFilter,
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
return guardCancel(await multiselect({
|
|
69
|
+
message: stylePromptMessage(params.message),
|
|
70
|
+
options,
|
|
71
|
+
initialValues: params.initialValues,
|
|
72
|
+
}));
|
|
73
|
+
},
|
|
41
74
|
text: async (params) => {
|
|
42
75
|
const validate = params.validate;
|
|
43
76
|
return guardCancel(await text({
|