@poolzin/pool-bot 2026.1.39 → 2026.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/chrome-extension/README.md +3 -3
- package/assets/chrome-extension/background.js +5 -5
- package/assets/chrome-extension/manifest.json +3 -3
- package/assets/chrome-extension/options.html +4 -4
- package/assets/chrome-extension/options.js +1 -1
- package/dist/acp/client.js +3 -3
- package/dist/acp/types.js +1 -1
- package/dist/agents/agent-paths.js +3 -3
- package/dist/agents/auth-profiles/paths.js +3 -3
- package/dist/agents/bash-tools.exec.js +76 -25
- package/dist/agents/cli-runner/helpers.js +10 -12
- package/dist/agents/cli-runner.js +2 -2
- package/dist/agents/cloudflare-ai-gateway.js +31 -0
- package/dist/agents/compaction.js +16 -2
- package/dist/agents/context-window-guard.js +13 -10
- package/dist/agents/context.js +4 -4
- package/dist/agents/docs-path.js +1 -1
- package/dist/agents/identity.js +47 -7
- package/dist/agents/memory-search.js +25 -8
- package/dist/agents/minimax-vlm.js +1 -1
- package/dist/agents/model-auth.js +12 -1
- package/dist/agents/model-catalog.js +4 -4
- package/dist/agents/model-selection.js +31 -4
- package/dist/agents/models-config.js +3 -3
- package/dist/agents/models-config.providers.js +147 -39
- package/dist/agents/pi-embedded-block-chunker.js +117 -42
- package/dist/agents/pi-embedded-helpers/errors.js +183 -78
- package/dist/agents/pi-embedded-helpers/openai.js +1 -1
- package/dist/agents/pi-embedded-helpers.js +1 -1
- package/dist/agents/pi-embedded-runner/compact.js +9 -8
- package/dist/agents/pi-embedded-runner/model.js +63 -4
- package/dist/agents/pi-embedded-runner/run/attempt.js +27 -17
- package/dist/agents/pi-embedded-runner/run.js +203 -50
- package/dist/agents/pi-embedded-runner/system-prompt.js +10 -2
- package/dist/agents/pi-embedded-runner/tool-result-truncation.js +275 -0
- package/dist/agents/pi-embedded-runner/utils.js +1 -1
- package/dist/agents/pi-embedded-subscribe.js +118 -29
- package/dist/agents/pi-model-discovery.js +10 -0
- package/dist/agents/pi-tool-definition-adapter.js +50 -9
- package/dist/agents/pi-tools.before-tool-call.js +67 -0
- package/dist/agents/pi-tools.js +20 -10
- package/dist/agents/pi-tools.read.js +2 -2
- package/dist/agents/poolbot-tools.js +15 -10
- package/dist/agents/sandbox-paths.js +31 -0
- package/dist/agents/session-file-repair.js +83 -0
- package/dist/agents/session-tool-result-guard.js +94 -15
- package/dist/agents/session-transcript-repair.js +68 -0
- package/dist/agents/shell-utils.js +51 -0
- package/dist/agents/skills/bundled-context.js +23 -0
- package/dist/agents/skills/bundled-dir.js +41 -7
- package/dist/agents/skills/frontmatter.js +1 -1
- package/dist/agents/skills/workspace.js +2 -2
- package/dist/agents/skills-install.js +60 -23
- package/dist/agents/subagent-announce.js +79 -34
- package/dist/agents/system-prompt.js +28 -4
- package/dist/agents/together-models.js +127 -0
- package/dist/agents/tool-images.js +1 -1
- package/dist/agents/tool-policy.conformance.js +14 -0
- package/dist/agents/tool-policy.js +25 -1
- package/dist/agents/tools/browser-tool.js +3 -3
- package/dist/agents/tools/cron-tool.js +166 -19
- package/dist/agents/tools/discord-actions-presence.js +78 -0
- package/dist/agents/tools/image-tool.js +2 -2
- package/dist/agents/tools/memory-tool.js +93 -5
- package/dist/agents/tools/message-tool.js +56 -2
- package/dist/agents/tools/sessions-history-tool.js +69 -1
- package/dist/agents/tools/web-search.js +211 -42
- package/dist/agents/usage.js +23 -1
- package/dist/agents/workspace-run.js +67 -0
- package/dist/agents/workspace-templates.js +44 -0
- package/dist/auto-reply/command-auth.js +121 -6
- package/dist/auto-reply/commands-registry.data.js +1 -1
- package/dist/auto-reply/envelope.js +50 -72
- package/dist/auto-reply/reply/commands-compact.js +1 -0
- package/dist/auto-reply/reply/commands-context-report.js +3 -2
- package/dist/auto-reply/reply/commands-context.js +1 -0
- package/dist/auto-reply/reply/commands-models.js +107 -60
- package/dist/auto-reply/reply/commands-ptt.js +171 -0
- package/dist/auto-reply/reply/commands-session.js +2 -2
- package/dist/auto-reply/reply/get-reply-run.js +16 -5
- package/dist/auto-reply/reply/groups.js +1 -1
- package/dist/auto-reply/reply/inbound-context.js +9 -1
- package/dist/auto-reply/reply/inbound-meta.js +130 -0
- package/dist/auto-reply/reply/model-selection.js +3 -3
- package/dist/auto-reply/reply/untrusted-context.js +15 -0
- package/dist/auto-reply/status.js +1 -1
- package/dist/auto-reply/thinking.js +88 -43
- package/dist/browser/bridge-server.js +13 -0
- package/dist/browser/cdp.helpers.js +38 -24
- package/dist/browser/client-fetch.js +51 -8
- package/dist/browser/config.js +2 -11
- package/dist/browser/extension-relay.js +104 -43
- package/dist/browser/pw-ai.js +1 -1
- package/dist/browser/pw-session.js +143 -8
- package/dist/browser/pw-tools-core.interactions.js +125 -27
- package/dist/browser/pw-tools-core.responses.js +1 -1
- package/dist/browser/pw-tools-core.state.js +1 -1
- package/dist/browser/routes/agent.act.js +86 -41
- package/dist/browser/routes/dispatcher.js +4 -4
- package/dist/browser/screenshot.js +1 -1
- package/dist/browser/server-context.js +2 -2
- package/dist/browser/server.js +13 -0
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui.js +3 -3
- package/dist/channels/plugins/catalog.js +2 -2
- package/dist/channels/plugins/onboarding/imessage.js +1 -1
- package/dist/channels/plugins/onboarding/signal.js +1 -1
- package/dist/channels/plugins/onboarding/slack.js +4 -4
- package/dist/channels/plugins/onboarding/whatsapp.js +3 -3
- package/dist/channels/plugins/pairing-message.js +1 -1
- package/dist/channels/reply-prefix.js +8 -1
- package/dist/cli/browser-cli-extension.js +2 -2
- package/dist/cli/cron-cli/register.cron-add.js +61 -40
- package/dist/cli/cron-cli/register.cron-edit.js +60 -34
- package/dist/cli/cron-cli/shared.js +56 -41
- package/dist/cli/dns-cli.js +26 -14
- package/dist/cli/docs-cli.js +1 -1
- package/dist/cli/gateway-cli/dev.js +1 -1
- package/dist/cli/gateway-cli/register.js +37 -19
- package/dist/cli/memory-cli.js +30 -20
- package/dist/cli/nodes-cli/register.canvas.js +1 -1
- package/dist/cli/parse-bytes.js +37 -0
- package/dist/cli/plugins-cli.js +1 -1
- package/dist/cli/run-main.js +2 -2
- package/dist/cli/security-cli.js +1 -1
- package/dist/cli/tagline.js +1 -1
- package/dist/cli/update-cli.js +173 -52
- package/dist/cli/webhooks-cli.js +5 -5
- package/dist/commands/agent.js +1 -0
- package/dist/commands/agents.commands.add.js +1 -1
- package/dist/commands/auth-choice.apply.api-providers.js +305 -17
- package/dist/commands/auth-choice.apply.js +4 -1
- package/dist/commands/auth-choice.apply.plugin-provider.js +2 -2
- package/dist/commands/auth-choice.apply.xai.js +63 -0
- package/dist/commands/auth-choice.preferred-provider.js +7 -1
- package/dist/commands/configure.wizard.js +1 -1
- package/dist/commands/dashboard.js +1 -1
- package/dist/commands/docs.js +1 -1
- package/dist/commands/doctor-config-flow.js +61 -5
- package/dist/commands/doctor-gateway-services.js +3 -3
- package/dist/commands/doctor-state-migrations.js +1 -1
- package/dist/commands/doctor-update.js +3 -3
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/health.js +1 -1
- package/dist/commands/model-allowlist.js +29 -0
- package/dist/commands/model-picker.js +2 -1
- package/dist/commands/models/list.probe.js +2 -2
- package/dist/commands/models/list.registry.js +4 -4
- package/dist/commands/models/list.status-command.js +44 -24
- package/dist/commands/models/shared.js +15 -0
- package/dist/commands/onboard-auth.config-core.js +366 -28
- package/dist/commands/onboard-auth.credentials.js +71 -9
- package/dist/commands/onboard-auth.js +3 -3
- package/dist/commands/onboard-auth.models.js +26 -24
- package/dist/commands/onboard-custom.js +384 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice-inference.js +35 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +146 -9
- package/dist/commands/onboard-skills.js +63 -38
- package/dist/commands/openai-model-default.js +41 -0
- package/dist/commands/status-all/report-lines.js +1 -1
- package/dist/commands/status.command.js +1 -1
- package/dist/commands/uninstall.js +3 -3
- package/dist/compat/legacy-names.js +1 -1
- package/dist/config/defaults.js +3 -2
- package/dist/config/io.js +3 -3
- package/dist/config/paths.js +136 -35
- package/dist/config/plugin-auto-enable.js +21 -5
- package/dist/config/redact-snapshot.js +153 -0
- package/dist/config/schema.field-metadata.js +590 -0
- package/dist/config/schema.js +3 -3
- package/dist/config/sessions/store.js +291 -23
- package/dist/config/types.memory.js +1 -0
- package/dist/config/version.js +4 -4
- package/dist/config/zod-schema.agent-defaults.js +3 -0
- package/dist/config/zod-schema.agent-runtime.js +13 -2
- package/dist/config/zod-schema.providers-core.js +142 -0
- package/dist/config/zod-schema.session.js +3 -0
- package/dist/cron/delivery.js +57 -0
- package/dist/cron/isolated-agent/delivery-target.js +18 -3
- package/dist/cron/isolated-agent/helpers.js +22 -5
- package/dist/cron/isolated-agent/run.js +171 -63
- package/dist/cron/isolated-agent/session.js +2 -0
- package/dist/cron/normalize.js +356 -28
- package/dist/cron/parse.js +10 -5
- package/dist/cron/run-log.js +35 -10
- package/dist/cron/schedule.js +41 -6
- package/dist/cron/service/jobs.js +208 -35
- package/dist/cron/service/ops.js +72 -16
- package/dist/cron/service/state.js +2 -0
- package/dist/cron/service/store.js +386 -14
- package/dist/cron/service/timer.js +390 -147
- package/dist/cron/session-reaper.js +86 -0
- package/dist/cron/store.js +23 -8
- package/dist/cron/validate-timestamp.js +43 -0
- package/dist/daemon/constants.js +7 -7
- package/dist/daemon/inspect.js +6 -6
- package/dist/daemon/systemd-unit.js +1 -1
- package/dist/discord/monitor/agent-components.js +438 -0
- package/dist/discord/monitor/allow-list.js +28 -5
- package/dist/discord/monitor/gateway-registry.js +29 -0
- package/dist/discord/monitor/native-command.js +44 -23
- package/dist/discord/monitor/sender-identity.js +45 -0
- package/dist/discord/pluralkit.js +27 -0
- package/dist/discord/send.outbound.js +92 -5
- package/dist/discord/send.shared.js +60 -23
- package/dist/discord/targets.js +84 -1
- package/dist/entry.js +15 -9
- package/dist/extensionAPI.js +8 -0
- package/dist/gateway/control-ui.js +8 -1
- package/dist/gateway/hooks-mapping.js +3 -0
- package/dist/gateway/hooks.js +65 -0
- package/dist/gateway/live-image-probe.js +1 -66
- package/dist/gateway/net.js +96 -31
- package/dist/gateway/node-command-policy.js +50 -15
- package/dist/gateway/openai-http.js +2 -2
- package/dist/gateway/openresponses-http.js +4 -4
- package/dist/gateway/origin-check.js +56 -0
- package/dist/gateway/protocol/client-info.js +9 -0
- package/dist/gateway/protocol/index.js +9 -2
- package/dist/gateway/protocol/schema/agents-models-skills.js +71 -1
- package/dist/gateway/protocol/schema/cron.js +22 -10
- package/dist/gateway/protocol/schema/protocol-schemas.js +16 -2
- package/dist/gateway/protocol/schema/sessions.js +12 -0
- package/dist/gateway/server/hooks.js +1 -1
- package/dist/gateway/server-broadcast.js +26 -9
- package/dist/gateway/server-chat.js +112 -23
- package/dist/gateway/server-discovery-runtime.js +10 -2
- package/dist/gateway/server-discovery.js +2 -2
- package/dist/gateway/server-http.js +110 -12
- package/dist/gateway/server-methods/agent-timestamp.js +60 -0
- package/dist/gateway/server-methods/agents.js +321 -2
- package/dist/gateway/server-methods/usage.js +559 -16
- package/dist/gateway/server-runtime-state.js +22 -8
- package/dist/gateway/server-startup-memory.js +16 -0
- package/dist/gateway/server.impl.js +7 -3
- package/dist/gateway/session-utils.fs.js +23 -25
- package/dist/gateway/session-utils.js +20 -10
- package/dist/gateway/sessions-patch.js +7 -22
- package/dist/gateway/test-helpers.server.js +35 -2
- package/dist/hooks/frontmatter.js +1 -1
- package/dist/hooks/hooks-status.js +1 -1
- package/dist/hooks/install.js +2 -2
- package/dist/hooks/loader.js +1 -1
- package/dist/hooks/workspace.js +3 -3
- package/dist/imessage/constants.js +2 -0
- package/dist/imessage/monitor/deliver.js +4 -1
- package/dist/imessage/monitor/monitor-provider.js +51 -1
- package/dist/index.js +2 -2
- package/dist/infra/bonjour-discovery.js +131 -70
- package/dist/infra/bonjour.js +3 -3
- package/dist/infra/control-ui-assets.js +134 -12
- package/dist/infra/errors.js +12 -0
- package/dist/infra/exec-approvals.js +266 -57
- package/dist/infra/format-time/format-datetime.js +79 -0
- package/dist/infra/format-time/format-duration.js +81 -0
- package/dist/infra/format-time/format-relative.js +80 -0
- package/dist/infra/heartbeat-runner.js +140 -49
- package/dist/infra/home-dir.js +54 -0
- package/dist/infra/net/fetch-guard.js +122 -0
- package/dist/infra/net/ssrf.js +65 -29
- package/dist/infra/outbound/abort.js +14 -0
- package/dist/infra/outbound/message-action-runner.js +77 -13
- package/dist/infra/outbound/outbound-session.js +143 -37
- package/dist/infra/path-env.js +3 -3
- package/dist/infra/poolbot-root.js +43 -1
- package/dist/infra/provider-usage.fetch.minimax.js +1 -1
- package/dist/infra/restart.js +1 -1
- package/dist/infra/session-cost-usage.js +631 -41
- package/dist/infra/state-migrations.js +317 -47
- package/dist/infra/tailscale.js +1 -1
- package/dist/infra/update-global.js +35 -0
- package/dist/infra/update-runner.js +149 -43
- package/dist/infra/warning-filter.js +65 -0
- package/dist/infra/widearea-dns.js +30 -9
- package/dist/logging/redact-identifier.js +12 -0
- package/dist/macos/relay.js +2 -2
- package/dist/media/fetch.js +81 -58
- package/dist/media/input-files.js +1 -1
- package/dist/media/mime.js +4 -0
- package/dist/media/png-encode.js +74 -0
- package/dist/media-understanding/apply.js +403 -3
- package/dist/media-understanding/attachments.js +38 -27
- package/dist/media-understanding/defaults.js +16 -0
- package/dist/media-understanding/providers/deepgram/audio.js +22 -14
- package/dist/media-understanding/providers/google/audio.js +24 -17
- package/dist/media-understanding/providers/google/video.js +24 -17
- package/dist/media-understanding/providers/image.js +4 -4
- package/dist/media-understanding/providers/index.js +4 -1
- package/dist/media-understanding/providers/openai/audio.js +22 -14
- package/dist/media-understanding/providers/shared.js +16 -11
- package/dist/media-understanding/providers/zai/index.js +6 -0
- package/dist/media-understanding/runner.js +158 -90
- package/dist/memory/backend-config.js +207 -0
- package/dist/memory/batch-voyage.js +277 -0
- package/dist/memory/embeddings-voyage.js +75 -0
- package/dist/memory/embeddings.js +29 -17
- package/dist/memory/internal.js +101 -18
- package/dist/memory/manager.js +155 -48
- package/dist/memory/search-manager.js +173 -0
- package/dist/memory/session-files.js +9 -3
- package/dist/memory/types.js +1 -0
- package/dist/node-host/runner.js +36 -26
- package/dist/node-host/with-timeout.js +27 -0
- package/dist/pairing/pairing-messages.js +1 -1
- package/dist/plugins/commands.js +5 -1
- package/dist/plugins/config-state.js +86 -7
- package/dist/plugins/discovery.js +1 -1
- package/dist/plugins/install.js +2 -2
- package/dist/plugins/source-display.js +51 -0
- package/dist/plugins/update.js +1 -1
- package/dist/process/exec.js +20 -2
- package/dist/routing/resolve-route.js +12 -0
- package/dist/routing/session-key.js +15 -0
- package/dist/runtime.js +2 -0
- package/dist/security/audit-extra.async.js +601 -0
- package/dist/security/audit-extra.js +2 -830
- package/dist/security/audit-extra.sync.js +505 -0
- package/dist/security/audit.js +2 -2
- package/dist/security/channel-metadata.js +34 -0
- package/dist/security/external-content.js +88 -6
- package/dist/security/skill-scanner.js +330 -0
- package/dist/sessions/session-key-utils.js +7 -0
- package/dist/shared/text/reasoning-tags.js +52 -7
- package/dist/signal/monitor/event-handler.js +80 -1
- package/dist/slack/monitor/media.js +85 -15
- package/dist/tailscale/detect.js +145 -0
- package/dist/telegram/bot/helpers.js +109 -28
- package/dist/telegram/bot-handlers.js +144 -3
- package/dist/telegram/bot-message-context.js +38 -11
- package/dist/telegram/bot-message-dispatch.js +48 -15
- package/dist/telegram/bot-native-commands.js +86 -29
- package/dist/telegram/bot.js +30 -29
- package/dist/telegram/model-buttons.js +163 -0
- package/dist/telegram/monitor.js +110 -85
- package/dist/telegram/send.js +129 -47
- package/dist/terminal/restore.js +45 -0
- package/dist/test-helpers/state-dir-env.js +16 -0
- package/dist/test-helpers/workspace.js +11 -0
- package/dist/test-utils/channel-plugins.js +82 -0
- package/dist/test-utils/ports.js +73 -0
- package/dist/tts/tts.js +12 -6
- package/dist/tui/tui-session-actions.js +166 -54
- package/dist/utils/fetch-timeout.js +20 -0
- package/dist/utils/normalize-secret-input.js +19 -0
- package/dist/utils/shell-argv.js +61 -0
- package/dist/utils/transcript-tools.js +58 -0
- package/dist/utils.js +55 -14
- package/dist/version.js +42 -5
- package/dist/web/qr-image.js +1 -61
- package/dist/wizard/onboarding.finalize.js +7 -7
- package/dist/wizard/onboarding.js +3 -3
- package/docs/RELEASE_WORKFOTS_COMPARISON.md +3 -3
- package/docs/_config.yml +2 -2
- package/docs/_layouts/default.html +9 -9
- package/docs/concepts/typebox.md +1 -1
- package/docs/docs.json +1 -1
- package/docs/northflank.mdx +7 -7
- package/docs/railway.mdx +3 -3
- package/docs/render.mdx +5 -5
- package/docs/start/lore.md +2 -2
- package/extensions/bluebubbles/index.ts +2 -2
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/bluebubbles/src/accounts.ts +8 -8
- package/extensions/bluebubbles/src/actions.test.ts +22 -22
- package/extensions/bluebubbles/src/actions.ts +5 -5
- package/extensions/bluebubbles/src/attachments.ts +2 -2
- package/extensions/bluebubbles/src/channel.ts +16 -16
- package/extensions/bluebubbles/src/chat.ts +2 -2
- package/extensions/bluebubbles/src/media-send.ts +2 -2
- package/extensions/bluebubbles/src/monitor.test.ts +46 -46
- package/extensions/bluebubbles/src/monitor.ts +5 -5
- package/extensions/bluebubbles/src/onboarding.ts +7 -7
- package/extensions/bluebubbles/src/reactions.ts +2 -2
- package/extensions/bluebubbles/src/send.ts +2 -2
- package/extensions/copilot-proxy/README.md +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/index.ts +2 -2
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/diagnostics-otel/src/service.ts +3 -3
- package/extensions/discord/index.ts +2 -2
- package/extensions/discord/package.json +1 -1
- package/extensions/google-antigravity-auth/README.md +1 -1
- package/extensions/google-antigravity-auth/index.ts +1 -1
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/README.md +1 -1
- package/extensions/google-gemini-cli-auth/oauth.ts +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/index.ts +3 -3
- package/extensions/googlechat/package.json +1 -1
- package/extensions/googlechat/src/accounts.ts +8 -8
- package/extensions/googlechat/src/actions.ts +6 -6
- package/extensions/googlechat/src/channel.ts +21 -21
- package/extensions/googlechat/src/monitor.ts +8 -8
- package/extensions/googlechat/src/onboarding.ts +10 -10
- package/extensions/imessage/index.ts +2 -2
- package/extensions/imessage/package.json +1 -1
- package/extensions/line/index.ts +2 -2
- package/extensions/line/package.json +1 -1
- package/extensions/line/src/card-command.ts +2 -2
- package/extensions/line/src/channel.logout.test.ts +4 -4
- package/extensions/line/src/channel.sendPayload.test.ts +8 -8
- package/extensions/line/src/channel.ts +3 -3
- package/extensions/llm-task/README.md +3 -3
- package/extensions/llm-task/index.ts +2 -2
- package/extensions/llm-task/package.json +1 -1
- package/extensions/llm-task/src/llm-task-tool.ts +4 -4
- package/extensions/lobster/README.md +6 -6
- package/extensions/lobster/index.ts +2 -2
- package/extensions/lobster/src/lobster-tool.test.ts +4 -4
- package/extensions/lobster/src/lobster-tool.ts +2 -2
- package/extensions/matrix/index.ts +2 -2
- package/extensions/matrix/package.json +1 -1
- package/extensions/matrix/src/matrix/client/config.ts +1 -1
- package/extensions/matrix/src/matrix/monitor/handler.ts +1 -1
- package/extensions/matrix/src/onboarding.ts +1 -1
- package/extensions/mattermost/index.ts +2 -2
- package/extensions/mattermost/package.json +1 -1
- package/extensions/mattermost/src/mattermost/accounts.ts +8 -8
- package/extensions/mattermost/src/mattermost/monitor-helpers.ts +5 -5
- package/extensions/mattermost/src/mattermost/monitor.ts +2 -2
- package/extensions/mattermost/src/onboarding-helpers.ts +3 -3
- package/extensions/mattermost/src/onboarding.ts +2 -2
- package/extensions/memory-core/index.ts +2 -2
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/index.ts +3 -3
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/msteams/index.ts +2 -2
- package/extensions/msteams/package.json +1 -1
- package/extensions/msteams/src/channel.directory.test.ts +2 -2
- package/extensions/msteams/src/channel.ts +2 -2
- package/extensions/msteams/src/graph-upload.ts +4 -4
- package/extensions/msteams/src/monitor-handler.ts +2 -2
- package/extensions/msteams/src/monitor.ts +2 -2
- package/extensions/msteams/src/onboarding.ts +9 -9
- package/extensions/msteams/src/reply-dispatcher.ts +2 -2
- package/extensions/msteams/src/send-context.ts +2 -2
- package/extensions/msteams/src/send.ts +4 -4
- package/extensions/nextcloud-talk/index.ts +2 -2
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nextcloud-talk/src/channel.ts +7 -7
- package/extensions/nextcloud-talk/src/inbound.ts +7 -7
- package/extensions/nextcloud-talk/src/onboarding.ts +1 -1
- package/extensions/nostr/README.md +2 -2
- package/extensions/nostr/index.ts +5 -5
- package/extensions/nostr/package.json +1 -1
- package/extensions/nostr/src/types.ts +4 -4
- package/extensions/open-prose/index.ts +2 -2
- package/extensions/qwen-portal-auth/README.md +1 -1
- package/extensions/signal/index.ts +2 -2
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/index.ts +2 -2
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/index.ts +2 -2
- package/extensions/telegram/package.json +1 -1
- package/extensions/telegram/src/channel.ts +2 -2
- package/extensions/tlon/README.md +2 -2
- package/extensions/tlon/index.ts +2 -2
- package/extensions/tlon/package.json +1 -1
- package/extensions/tlon/src/channel.ts +13 -13
- package/extensions/tlon/src/monitor/index.ts +3 -3
- package/extensions/tlon/src/onboarding.ts +3 -3
- package/extensions/tlon/src/types.ts +3 -3
- package/extensions/twitch/README.md +1 -1
- package/extensions/twitch/index.ts +2 -2
- package/extensions/twitch/package.json +1 -1
- package/extensions/twitch/src/config.ts +3 -3
- package/extensions/twitch/src/monitor.ts +3 -3
- package/extensions/twitch/src/onboarding.ts +9 -9
- package/extensions/twitch/src/outbound.test.ts +2 -2
- package/extensions/twitch/src/plugin.test.ts +2 -2
- package/extensions/twitch/src/plugin.ts +8 -8
- package/extensions/twitch/src/send.test.ts +2 -2
- package/extensions/twitch/src/send.ts +4 -4
- package/extensions/twitch/src/token.test.ts +8 -8
- package/extensions/twitch/src/token.ts +3 -3
- package/extensions/twitch/src/twitch-client.ts +3 -3
- package/extensions/twitch/src/types.ts +3 -3
- package/extensions/twitch/src/utils/markdown.ts +1 -1
- package/extensions/voice-call/README.md +3 -3
- package/extensions/voice-call/package.json +1 -1
- package/extensions/voice-call/src/core-bridge.ts +2 -2
- package/extensions/voice-call/src/response-generator.ts +1 -1
- package/extensions/whatsapp/index.ts +2 -2
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/README.md +1 -1
- package/extensions/zalo/index.ts +2 -2
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalo/src/accounts.ts +8 -8
- package/extensions/zalo/src/actions.ts +4 -4
- package/extensions/zalo/src/channel.directory.test.ts +2 -2
- package/extensions/zalo/src/channel.ts +18 -18
- package/extensions/zalo/src/monitor.ts +9 -9
- package/extensions/zalo/src/monitor.webhook.test.ts +2 -2
- package/extensions/zalo/src/onboarding.ts +24 -24
- package/extensions/zalo/src/send.ts +2 -2
- package/extensions/zalouser/README.md +2 -2
- package/extensions/zalouser/index.ts +2 -2
- package/extensions/zalouser/package.json +1 -1
- package/extensions/zalouser/src/accounts.ts +9 -9
- package/extensions/zalouser/src/channel.ts +24 -24
- package/extensions/zalouser/src/monitor.ts +4 -4
- package/extensions/zalouser/src/onboarding.ts +28 -28
- package/package.json +13 -251
- package/skills/nano-banana-pro/scripts/generate_image.py +1 -1
- package/skills/tmux/scripts/find-sessions.sh +1 -1
- package/CHANGELOG.md +0 -102
- package/README-header.png +0 -0
- package/git-hooks/pre-commit +0 -4
- package/scripts/format-staged.js +0 -148
- package/scripts/postinstall.js +0 -300
- package/scripts/setup-git-hooks.js +0 -96
|
@@ -25,6 +25,7 @@ import { truncateUtf16Safe } from "../../utils.js";
|
|
|
25
25
|
import { resolveControlCommandGate } from "../../channels/command-gating.js";
|
|
26
26
|
import { resolveIMessageAccount } from "../accounts.js";
|
|
27
27
|
import { createIMessageRpcClient } from "../client.js";
|
|
28
|
+
import { DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS } from "../constants.js";
|
|
28
29
|
import { probeIMessage } from "../probe.js";
|
|
29
30
|
import { sendMessageIMessage } from "../send.js";
|
|
30
31
|
import { formatIMessageChatTarget, isAllowedIMessageSender, normalizeIMessageHandle, } from "../targets.js";
|
|
@@ -72,6 +73,38 @@ function describeReplyContext(message) {
|
|
|
72
73
|
const sender = normalizeReplyField(message.reply_to_sender);
|
|
73
74
|
return { body, id, sender };
|
|
74
75
|
}
|
|
76
|
+
class SentMessageCache {
|
|
77
|
+
cache = new Map();
|
|
78
|
+
ttlMs = 5000;
|
|
79
|
+
remember(scope, text) {
|
|
80
|
+
if (!text?.trim())
|
|
81
|
+
return;
|
|
82
|
+
const key = `${scope}:${text.trim()}`;
|
|
83
|
+
this.cache.set(key, Date.now());
|
|
84
|
+
this.cleanup();
|
|
85
|
+
}
|
|
86
|
+
has(scope, text) {
|
|
87
|
+
if (!text?.trim())
|
|
88
|
+
return false;
|
|
89
|
+
const key = `${scope}:${text.trim()}`;
|
|
90
|
+
const timestamp = this.cache.get(key);
|
|
91
|
+
if (!timestamp)
|
|
92
|
+
return false;
|
|
93
|
+
const age = Date.now() - timestamp;
|
|
94
|
+
if (age > this.ttlMs) {
|
|
95
|
+
this.cache.delete(key);
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
cleanup() {
|
|
101
|
+
const now = Date.now();
|
|
102
|
+
for (const [text, timestamp] of this.cache.entries()) {
|
|
103
|
+
if (now - timestamp > this.ttlMs)
|
|
104
|
+
this.cache.delete(text);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
75
108
|
export async function monitorIMessageProvider(opts = {}) {
|
|
76
109
|
const runtime = resolveRuntime(opts);
|
|
77
110
|
const cfg = opts.config ?? loadConfig();
|
|
@@ -84,6 +117,7 @@ export async function monitorIMessageProvider(opts = {}) {
|
|
|
84
117
|
cfg.messages?.groupChat?.historyLimit ??
|
|
85
118
|
DEFAULT_GROUP_HISTORY_LIMIT);
|
|
86
119
|
const groupHistories = new Map();
|
|
120
|
+
const sentMessageCache = new SentMessageCache();
|
|
87
121
|
const textLimit = resolveTextChunkLimit(cfg, "imessage", accountInfo.accountId);
|
|
88
122
|
const allowFrom = normalizeAllowList(opts.allowFrom ?? imessageCfg.allowFrom);
|
|
89
123
|
const groupAllowFrom = normalizeAllowList(opts.groupAllowFrom ??
|
|
@@ -96,6 +130,7 @@ export async function monitorIMessageProvider(opts = {}) {
|
|
|
96
130
|
const mediaMaxBytes = (opts.mediaMaxMb ?? imessageCfg.mediaMaxMb ?? 16) * 1024 * 1024;
|
|
97
131
|
const cliPath = opts.cliPath ?? imessageCfg.cliPath ?? "imsg";
|
|
98
132
|
const dbPath = opts.dbPath ?? imessageCfg.dbPath;
|
|
133
|
+
const probeTimeoutMs = imessageCfg.probeTimeoutMs ?? DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS;
|
|
99
134
|
// Resolve remoteHost: explicit config, or auto-detect from SSH wrapper script
|
|
100
135
|
let remoteHost = imessageCfg.remoteHost;
|
|
101
136
|
if (!remoteHost && cliPath && cliPath !== "imsg") {
|
|
@@ -290,6 +325,11 @@ export async function monitorIMessageProvider(opts = {}) {
|
|
|
290
325
|
});
|
|
291
326
|
const mentionRegexes = buildMentionRegexes(cfg, route.agentId);
|
|
292
327
|
const messageText = (message.text ?? "").trim();
|
|
328
|
+
const echoScope = `${accountInfo.accountId}:${isGroup ? formatIMessageChatTarget(chatId) : `imessage:${sender}`}`;
|
|
329
|
+
if (messageText && sentMessageCache.has(echoScope, messageText)) {
|
|
330
|
+
logVerbose(`imessage: skipping echo message (matches recently sent text within 5s): "${truncateUtf16Safe(messageText, 50)}"`);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
293
333
|
const attachments = includeAttachments ? (message.attachments ?? []) : [];
|
|
294
334
|
// Filter to valid attachments with paths
|
|
295
335
|
const validAttachments = attachments.filter((entry) => entry?.original_path && !entry?.missing);
|
|
@@ -426,8 +466,17 @@ export async function monitorIMessageProvider(opts = {}) {
|
|
|
426
466
|
});
|
|
427
467
|
}
|
|
428
468
|
const imessageTo = (isGroup ? chatTarget : undefined) || `imessage:${sender}`;
|
|
469
|
+
const inboundHistory = isGroup && historyKey && historyLimit > 0
|
|
470
|
+
? (groupHistories.get(historyKey) ?? []).map((entry) => ({
|
|
471
|
+
sender: entry.sender,
|
|
472
|
+
body: entry.body,
|
|
473
|
+
timestamp: entry.timestamp,
|
|
474
|
+
}))
|
|
475
|
+
: undefined;
|
|
429
476
|
const ctxPayload = finalizeInboundContext({
|
|
430
477
|
Body: combinedBody,
|
|
478
|
+
BodyForAgent: bodyText,
|
|
479
|
+
InboundHistory: inboundHistory,
|
|
431
480
|
RawBody: bodyText,
|
|
432
481
|
CommandBody: bodyText,
|
|
433
482
|
From: isGroup ? `imessage:group:${chatId ?? "unknown"}` : `imessage:${sender}`,
|
|
@@ -495,6 +544,7 @@ export async function monitorIMessageProvider(opts = {}) {
|
|
|
495
544
|
runtime,
|
|
496
545
|
maxBytes: mediaMaxBytes,
|
|
497
546
|
textLimit,
|
|
547
|
+
sentMessageCache,
|
|
498
548
|
});
|
|
499
549
|
},
|
|
500
550
|
onError: (err, info) => {
|
|
@@ -542,7 +592,7 @@ export async function monitorIMessageProvider(opts = {}) {
|
|
|
542
592
|
abortSignal: opts.abortSignal,
|
|
543
593
|
runtime,
|
|
544
594
|
check: async () => {
|
|
545
|
-
const probe = await probeIMessage(
|
|
595
|
+
const probe = await probeIMessage(probeTimeoutMs, { cliPath, dbPath, runtime });
|
|
546
596
|
if (probe.ok)
|
|
547
597
|
return { ok: true };
|
|
548
598
|
if (probe.fatal) {
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import { ensureBinary } from "./infra/binaries.js";
|
|
|
13
13
|
import { loadDotEnv } from "./infra/dotenv.js";
|
|
14
14
|
import { normalizeEnv } from "./infra/env.js";
|
|
15
15
|
import { isMainModule } from "./infra/is-main.js";
|
|
16
|
-
import {
|
|
16
|
+
import { ensurePoolbotCliOnPath } from "./infra/path-env.js";
|
|
17
17
|
import { describePortOwner, ensurePortAvailable, handlePortError, PortInUseError, } from "./infra/ports.js";
|
|
18
18
|
import { assertSupportedRuntime } from "./infra/runtime-guard.js";
|
|
19
19
|
import { formatUncaughtError } from "./infra/errors.js";
|
|
@@ -23,7 +23,7 @@ import { runCommandWithTimeout, runExec } from "./process/exec.js";
|
|
|
23
23
|
import { assertWebChannel, normalizeE164, toWhatsappJid } from "./utils.js";
|
|
24
24
|
loadDotEnv({ quiet: true });
|
|
25
25
|
normalizeEnv();
|
|
26
|
-
|
|
26
|
+
ensurePoolbotCliOnPath();
|
|
27
27
|
// Capture all console output into structured logs while keeping stdout/stderr behavior.
|
|
28
28
|
enableConsoleCapture();
|
|
29
29
|
// Enforce the minimum supported runtime before doing any work.
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { runCommandWithTimeout } from "../process/exec.js";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveWideAreaDiscoveryDomain } from "./widearea-dns.js";
|
|
3
3
|
const DEFAULT_TIMEOUT_MS = 2000;
|
|
4
|
-
const
|
|
4
|
+
const GATEWAY_SERVICE_TYPE = "_poolbot-gw._tcp";
|
|
5
5
|
function decodeDnsSdEscapes(value) {
|
|
6
6
|
let decoded = false;
|
|
7
7
|
const bytes = [];
|
|
8
8
|
let pending = "";
|
|
9
9
|
const flush = () => {
|
|
10
|
-
if (!pending)
|
|
10
|
+
if (!pending) {
|
|
11
11
|
return;
|
|
12
|
+
}
|
|
12
13
|
bytes.push(...Buffer.from(pending, "utf8"));
|
|
13
14
|
pending = "";
|
|
14
15
|
};
|
|
@@ -31,18 +32,21 @@ function decodeDnsSdEscapes(value) {
|
|
|
31
32
|
}
|
|
32
33
|
pending += ch;
|
|
33
34
|
}
|
|
34
|
-
if (!decoded)
|
|
35
|
+
if (!decoded) {
|
|
35
36
|
return value;
|
|
37
|
+
}
|
|
36
38
|
flush();
|
|
37
39
|
return Buffer.from(bytes).toString("utf8");
|
|
38
40
|
}
|
|
39
41
|
function isTailnetIPv4(address) {
|
|
40
42
|
const parts = address.split(".");
|
|
41
|
-
if (parts.length !== 4)
|
|
43
|
+
if (parts.length !== 4) {
|
|
42
44
|
return false;
|
|
45
|
+
}
|
|
43
46
|
const octets = parts.map((p) => Number.parseInt(p, 10));
|
|
44
|
-
if (octets.some((n) => !Number.isFinite(n) || n < 0 || n > 255))
|
|
47
|
+
if (octets.some((n) => !Number.isFinite(n) || n < 0 || n > 255)) {
|
|
45
48
|
return false;
|
|
49
|
+
}
|
|
46
50
|
// Tailscale IPv4 range: 100.64.0.0/10
|
|
47
51
|
const [a, b] = octets;
|
|
48
52
|
return a === 100 && b >= 64 && b <= 127;
|
|
@@ -59,8 +63,9 @@ function parseDigTxt(stdout) {
|
|
|
59
63
|
const tokens = [];
|
|
60
64
|
for (const raw of stdout.split("\n")) {
|
|
61
65
|
const line = raw.trim();
|
|
62
|
-
if (!line)
|
|
66
|
+
if (!line) {
|
|
63
67
|
continue;
|
|
68
|
+
}
|
|
64
69
|
const matches = Array.from(line.matchAll(/"([^"]*)"/g), (m) => m[1] ?? "");
|
|
65
70
|
for (const m of matches) {
|
|
66
71
|
const unescaped = m.replaceAll("\\\\", "\\").replaceAll('\\"', '"').replaceAll("\\n", "\n");
|
|
@@ -75,35 +80,43 @@ function parseDigSrv(stdout) {
|
|
|
75
80
|
.split("\n")
|
|
76
81
|
.map((l) => l.trim())
|
|
77
82
|
.find(Boolean);
|
|
78
|
-
if (!line)
|
|
83
|
+
if (!line) {
|
|
79
84
|
return null;
|
|
85
|
+
}
|
|
80
86
|
const parts = line.split(/\s+/).filter(Boolean);
|
|
81
|
-
if (parts.length < 4)
|
|
87
|
+
if (parts.length < 4) {
|
|
82
88
|
return null;
|
|
89
|
+
}
|
|
83
90
|
const port = Number.parseInt(parts[2] ?? "", 10);
|
|
84
91
|
const hostRaw = parts[3] ?? "";
|
|
85
|
-
if (!Number.isFinite(port) || port <= 0)
|
|
92
|
+
if (!Number.isFinite(port) || port <= 0) {
|
|
86
93
|
return null;
|
|
94
|
+
}
|
|
87
95
|
const host = hostRaw.replace(/\.$/, "");
|
|
88
|
-
if (!host)
|
|
96
|
+
if (!host) {
|
|
89
97
|
return null;
|
|
98
|
+
}
|
|
90
99
|
return { host, port };
|
|
91
100
|
}
|
|
92
101
|
function parseTailscaleStatusIPv4s(stdout) {
|
|
93
102
|
const parsed = stdout ? JSON.parse(stdout) : {};
|
|
94
103
|
const out = [];
|
|
95
104
|
const addIps = (value) => {
|
|
96
|
-
if (!value || typeof value !== "object")
|
|
105
|
+
if (!value || typeof value !== "object") {
|
|
97
106
|
return;
|
|
107
|
+
}
|
|
98
108
|
const ips = value.TailscaleIPs;
|
|
99
|
-
if (!Array.isArray(ips))
|
|
109
|
+
if (!Array.isArray(ips)) {
|
|
100
110
|
return;
|
|
111
|
+
}
|
|
101
112
|
for (const ip of ips) {
|
|
102
|
-
if (typeof ip !== "string")
|
|
113
|
+
if (typeof ip !== "string") {
|
|
103
114
|
continue;
|
|
115
|
+
}
|
|
104
116
|
const trimmed = ip.trim();
|
|
105
|
-
if (trimmed && isTailnetIPv4(trimmed))
|
|
117
|
+
if (trimmed && isTailnetIPv4(trimmed)) {
|
|
106
118
|
out.push(trimmed);
|
|
119
|
+
}
|
|
107
120
|
}
|
|
108
121
|
};
|
|
109
122
|
addIps(parsed.Self);
|
|
@@ -116,8 +129,9 @@ function parseTailscaleStatusIPv4s(stdout) {
|
|
|
116
129
|
return [...new Set(out)];
|
|
117
130
|
}
|
|
118
131
|
function parseIntOrNull(value) {
|
|
119
|
-
if (!value)
|
|
132
|
+
if (!value) {
|
|
120
133
|
return undefined;
|
|
134
|
+
}
|
|
121
135
|
const parsed = Number.parseInt(value, 10);
|
|
122
136
|
return Number.isFinite(parsed) ? parsed : undefined;
|
|
123
137
|
}
|
|
@@ -125,12 +139,14 @@ function parseTxtTokens(tokens) {
|
|
|
125
139
|
const txt = {};
|
|
126
140
|
for (const token of tokens) {
|
|
127
141
|
const idx = token.indexOf("=");
|
|
128
|
-
if (idx <= 0)
|
|
142
|
+
if (idx <= 0) {
|
|
129
143
|
continue;
|
|
144
|
+
}
|
|
130
145
|
const key = token.slice(0, idx).trim();
|
|
131
146
|
const value = decodeDnsSdEscapes(token.slice(idx + 1).trim());
|
|
132
|
-
if (!key)
|
|
147
|
+
if (!key) {
|
|
133
148
|
continue;
|
|
149
|
+
}
|
|
134
150
|
txt[key] = value;
|
|
135
151
|
}
|
|
136
152
|
return txt;
|
|
@@ -139,10 +155,12 @@ function parseDnsSdBrowse(stdout) {
|
|
|
139
155
|
const instances = new Set();
|
|
140
156
|
for (const raw of stdout.split("\n")) {
|
|
141
157
|
const line = raw.trim();
|
|
142
|
-
if (!line || !line.includes(
|
|
158
|
+
if (!line || !line.includes(GATEWAY_SERVICE_TYPE)) {
|
|
143
159
|
continue;
|
|
144
|
-
|
|
160
|
+
}
|
|
161
|
+
if (!line.includes("Add")) {
|
|
145
162
|
continue;
|
|
163
|
+
}
|
|
146
164
|
const match = line.match(/_poolbot-gw\._tcp\.?\s+(.+)$/);
|
|
147
165
|
if (match?.[1]) {
|
|
148
166
|
instances.add(decodeDnsSdEscapes(match[1].trim()));
|
|
@@ -156,8 +174,9 @@ function parseDnsSdResolve(stdout, instanceName) {
|
|
|
156
174
|
let txt = {};
|
|
157
175
|
for (const raw of stdout.split("\n")) {
|
|
158
176
|
const line = raw.trim();
|
|
159
|
-
if (!line)
|
|
177
|
+
if (!line) {
|
|
160
178
|
continue;
|
|
179
|
+
}
|
|
161
180
|
if (line.includes("can be reached at")) {
|
|
162
181
|
const match = line.match(/can be reached at\s+([^\s:]+):(\d+)/i);
|
|
163
182
|
if (match?.[1]) {
|
|
@@ -174,49 +193,59 @@ function parseDnsSdResolve(stdout, instanceName) {
|
|
|
174
193
|
}
|
|
175
194
|
}
|
|
176
195
|
beacon.txt = Object.keys(txt).length ? txt : undefined;
|
|
177
|
-
if (txt.displayName)
|
|
196
|
+
if (txt.displayName) {
|
|
178
197
|
beacon.displayName = decodeDnsSdEscapes(txt.displayName);
|
|
179
|
-
|
|
198
|
+
}
|
|
199
|
+
if (txt.lanHost) {
|
|
180
200
|
beacon.lanHost = txt.lanHost;
|
|
181
|
-
|
|
201
|
+
}
|
|
202
|
+
if (txt.tailnetDns) {
|
|
182
203
|
beacon.tailnetDns = txt.tailnetDns;
|
|
183
|
-
|
|
204
|
+
}
|
|
205
|
+
if (txt.cliPath) {
|
|
184
206
|
beacon.cliPath = txt.cliPath;
|
|
207
|
+
}
|
|
185
208
|
beacon.gatewayPort = parseIntOrNull(txt.gatewayPort);
|
|
186
209
|
beacon.sshPort = parseIntOrNull(txt.sshPort);
|
|
187
210
|
if (txt.gatewayTls) {
|
|
188
211
|
const raw = txt.gatewayTls.trim().toLowerCase();
|
|
189
212
|
beacon.gatewayTls = raw === "1" || raw === "true" || raw === "yes";
|
|
190
213
|
}
|
|
191
|
-
if (txt.gatewayTlsSha256)
|
|
214
|
+
if (txt.gatewayTlsSha256) {
|
|
192
215
|
beacon.gatewayTlsFingerprintSha256 = txt.gatewayTlsSha256;
|
|
193
|
-
|
|
216
|
+
}
|
|
217
|
+
if (txt.role) {
|
|
194
218
|
beacon.role = txt.role;
|
|
195
|
-
|
|
219
|
+
}
|
|
220
|
+
if (txt.transport) {
|
|
196
221
|
beacon.transport = txt.transport;
|
|
197
|
-
|
|
222
|
+
}
|
|
223
|
+
if (!beacon.displayName) {
|
|
198
224
|
beacon.displayName = decodedInstanceName;
|
|
225
|
+
}
|
|
199
226
|
return beacon;
|
|
200
227
|
}
|
|
201
228
|
async function discoverViaDnsSd(domain, timeoutMs, run) {
|
|
202
|
-
const browse = await run(["dns-sd", "-B",
|
|
229
|
+
const browse = await run(["dns-sd", "-B", GATEWAY_SERVICE_TYPE, domain], {
|
|
203
230
|
timeoutMs,
|
|
204
231
|
});
|
|
205
232
|
const instances = parseDnsSdBrowse(browse.stdout);
|
|
206
233
|
const results = [];
|
|
207
234
|
for (const instance of instances) {
|
|
208
|
-
const resolved = await run(["dns-sd", "-L", instance,
|
|
235
|
+
const resolved = await run(["dns-sd", "-L", instance, GATEWAY_SERVICE_TYPE, domain], {
|
|
209
236
|
timeoutMs,
|
|
210
237
|
});
|
|
211
238
|
const parsed = parseDnsSdResolve(resolved.stdout, instance);
|
|
212
|
-
if (parsed)
|
|
239
|
+
if (parsed) {
|
|
213
240
|
results.push({ ...parsed, domain });
|
|
241
|
+
}
|
|
214
242
|
}
|
|
215
243
|
return results;
|
|
216
244
|
}
|
|
217
245
|
async function discoverWideAreaViaTailnetDns(domain, timeoutMs, run) {
|
|
218
|
-
if (domain
|
|
246
|
+
if (!domain || domain === "local.") {
|
|
219
247
|
return [];
|
|
248
|
+
}
|
|
220
249
|
const startedAt = Date.now();
|
|
221
250
|
const remainingMs = () => timeoutMs - (Date.now() - startedAt);
|
|
222
251
|
const tailscaleCandidates = ["tailscale", "/Applications/Tailscale.app/Contents/MacOS/Tailscale"];
|
|
@@ -227,20 +256,23 @@ async function discoverWideAreaViaTailnetDns(domain, timeoutMs, run) {
|
|
|
227
256
|
timeoutMs: Math.max(1, Math.min(700, remainingMs())),
|
|
228
257
|
});
|
|
229
258
|
ips = parseTailscaleStatusIPv4s(res.stdout);
|
|
230
|
-
if (ips.length > 0)
|
|
259
|
+
if (ips.length > 0) {
|
|
231
260
|
break;
|
|
261
|
+
}
|
|
232
262
|
}
|
|
233
263
|
catch {
|
|
234
264
|
// ignore
|
|
235
265
|
}
|
|
236
266
|
}
|
|
237
|
-
if (ips.length === 0)
|
|
267
|
+
if (ips.length === 0) {
|
|
238
268
|
return [];
|
|
239
|
-
|
|
269
|
+
}
|
|
270
|
+
if (remainingMs() <= 0) {
|
|
240
271
|
return [];
|
|
272
|
+
}
|
|
241
273
|
// Keep scans bounded: this is a fallback and should not block long.
|
|
242
274
|
ips = ips.slice(0, 40);
|
|
243
|
-
const probeName =
|
|
275
|
+
const probeName = `${GATEWAY_SERVICE_TYPE}.${domain.replace(/\.$/, "")}`;
|
|
244
276
|
const concurrency = 6;
|
|
245
277
|
let nextIndex = 0;
|
|
246
278
|
let nameserver = null;
|
|
@@ -248,20 +280,24 @@ async function discoverWideAreaViaTailnetDns(domain, timeoutMs, run) {
|
|
|
248
280
|
const worker = async () => {
|
|
249
281
|
while (nameserver === null) {
|
|
250
282
|
const budget = remainingMs();
|
|
251
|
-
if (budget <= 0)
|
|
283
|
+
if (budget <= 0) {
|
|
252
284
|
return;
|
|
285
|
+
}
|
|
253
286
|
const i = nextIndex;
|
|
254
287
|
nextIndex += 1;
|
|
255
|
-
if (i >= ips.length)
|
|
288
|
+
if (i >= ips.length) {
|
|
256
289
|
return;
|
|
290
|
+
}
|
|
257
291
|
const ip = ips[i] ?? "";
|
|
258
|
-
if (!ip)
|
|
292
|
+
if (!ip) {
|
|
259
293
|
continue;
|
|
294
|
+
}
|
|
260
295
|
try {
|
|
261
296
|
const probe = await run(["dig", "+short", "+time=1", "+tries=1", `@${ip}`, probeName, "PTR"], { timeoutMs: Math.max(1, Math.min(250, budget)) });
|
|
262
297
|
const lines = parseDigShortLines(probe.stdout);
|
|
263
|
-
if (lines.length === 0)
|
|
298
|
+
if (lines.length === 0) {
|
|
264
299
|
continue;
|
|
300
|
+
}
|
|
265
301
|
nameserver = ip;
|
|
266
302
|
ptrs = lines;
|
|
267
303
|
return;
|
|
@@ -272,26 +308,31 @@ async function discoverWideAreaViaTailnetDns(domain, timeoutMs, run) {
|
|
|
272
308
|
}
|
|
273
309
|
};
|
|
274
310
|
await Promise.all(Array.from({ length: Math.min(concurrency, ips.length) }, () => worker()));
|
|
275
|
-
if (!nameserver || ptrs.length === 0)
|
|
311
|
+
if (!nameserver || ptrs.length === 0) {
|
|
276
312
|
return [];
|
|
277
|
-
|
|
313
|
+
}
|
|
314
|
+
if (remainingMs() <= 0) {
|
|
278
315
|
return [];
|
|
316
|
+
}
|
|
279
317
|
const nameserverArg = `@${String(nameserver)}`;
|
|
280
318
|
const results = [];
|
|
281
319
|
for (const ptr of ptrs) {
|
|
282
320
|
const budget = remainingMs();
|
|
283
|
-
if (budget <= 0)
|
|
321
|
+
if (budget <= 0) {
|
|
284
322
|
break;
|
|
323
|
+
}
|
|
285
324
|
const ptrName = ptr.trim().replace(/\.$/, "");
|
|
286
|
-
if (!ptrName)
|
|
325
|
+
if (!ptrName) {
|
|
287
326
|
continue;
|
|
327
|
+
}
|
|
288
328
|
const instanceName = ptrName.replace(/\.?_poolbot-gw\._tcp\..*$/, "");
|
|
289
329
|
const srv = await run(["dig", "+short", "+time=1", "+tries=1", nameserverArg, ptrName, "SRV"], {
|
|
290
330
|
timeoutMs: Math.max(1, Math.min(350, budget)),
|
|
291
331
|
}).catch(() => null);
|
|
292
332
|
const srvParsed = srv ? parseDigSrv(srv.stdout) : null;
|
|
293
|
-
if (!srvParsed)
|
|
333
|
+
if (!srvParsed) {
|
|
294
334
|
continue;
|
|
335
|
+
}
|
|
295
336
|
const txtBudget = remainingMs();
|
|
296
337
|
if (txtBudget <= 0) {
|
|
297
338
|
results.push({
|
|
@@ -324,12 +365,15 @@ async function discoverWideAreaViaTailnetDns(domain, timeoutMs, run) {
|
|
|
324
365
|
const raw = txtMap.gatewayTls.trim().toLowerCase();
|
|
325
366
|
beacon.gatewayTls = raw === "1" || raw === "true" || raw === "yes";
|
|
326
367
|
}
|
|
327
|
-
if (txtMap.gatewayTlsSha256)
|
|
368
|
+
if (txtMap.gatewayTlsSha256) {
|
|
328
369
|
beacon.gatewayTlsFingerprintSha256 = txtMap.gatewayTlsSha256;
|
|
329
|
-
|
|
370
|
+
}
|
|
371
|
+
if (txtMap.role) {
|
|
330
372
|
beacon.role = txtMap.role;
|
|
331
|
-
|
|
373
|
+
}
|
|
374
|
+
if (txtMap.transport) {
|
|
332
375
|
beacon.transport = txtMap.transport;
|
|
376
|
+
}
|
|
333
377
|
results.push(beacon);
|
|
334
378
|
}
|
|
335
379
|
return results;
|
|
@@ -339,12 +383,14 @@ function parseAvahiBrowse(stdout) {
|
|
|
339
383
|
let current = null;
|
|
340
384
|
for (const raw of stdout.split("\n")) {
|
|
341
385
|
const line = raw.trimEnd();
|
|
342
|
-
if (!line)
|
|
386
|
+
if (!line) {
|
|
343
387
|
continue;
|
|
344
|
-
|
|
345
|
-
|
|
388
|
+
}
|
|
389
|
+
if (line.startsWith("=") && line.includes(GATEWAY_SERVICE_TYPE)) {
|
|
390
|
+
if (current) {
|
|
346
391
|
results.push(current);
|
|
347
|
-
|
|
392
|
+
}
|
|
393
|
+
const marker = ` ${GATEWAY_SERVICE_TYPE}`;
|
|
348
394
|
const idx = line.indexOf(marker);
|
|
349
395
|
const left = idx >= 0 ? line.slice(0, idx).trim() : line;
|
|
350
396
|
const parts = left.split(/\s+/);
|
|
@@ -355,53 +401,64 @@ function parseAvahiBrowse(stdout) {
|
|
|
355
401
|
};
|
|
356
402
|
continue;
|
|
357
403
|
}
|
|
358
|
-
if (!current)
|
|
404
|
+
if (!current) {
|
|
359
405
|
continue;
|
|
406
|
+
}
|
|
360
407
|
const trimmed = line.trim();
|
|
361
408
|
if (trimmed.startsWith("hostname =")) {
|
|
362
409
|
const match = trimmed.match(/hostname\s*=\s*\[([^\]]+)\]/);
|
|
363
|
-
if (match?.[1])
|
|
410
|
+
if (match?.[1]) {
|
|
364
411
|
current.host = match[1];
|
|
412
|
+
}
|
|
365
413
|
continue;
|
|
366
414
|
}
|
|
367
415
|
if (trimmed.startsWith("port =")) {
|
|
368
416
|
const match = trimmed.match(/port\s*=\s*\[(\d+)\]/);
|
|
369
|
-
if (match?.[1])
|
|
417
|
+
if (match?.[1]) {
|
|
370
418
|
current.port = parseIntOrNull(match[1]);
|
|
419
|
+
}
|
|
371
420
|
continue;
|
|
372
421
|
}
|
|
373
422
|
if (trimmed.startsWith("txt =")) {
|
|
374
423
|
const tokens = Array.from(trimmed.matchAll(/"([^"]*)"/g), (m) => m[1]);
|
|
375
424
|
const txt = parseTxtTokens(tokens);
|
|
376
425
|
current.txt = Object.keys(txt).length ? txt : undefined;
|
|
377
|
-
if (txt.displayName)
|
|
426
|
+
if (txt.displayName) {
|
|
378
427
|
current.displayName = txt.displayName;
|
|
379
|
-
|
|
428
|
+
}
|
|
429
|
+
if (txt.lanHost) {
|
|
380
430
|
current.lanHost = txt.lanHost;
|
|
381
|
-
|
|
431
|
+
}
|
|
432
|
+
if (txt.tailnetDns) {
|
|
382
433
|
current.tailnetDns = txt.tailnetDns;
|
|
383
|
-
|
|
434
|
+
}
|
|
435
|
+
if (txt.cliPath) {
|
|
384
436
|
current.cliPath = txt.cliPath;
|
|
437
|
+
}
|
|
385
438
|
current.gatewayPort = parseIntOrNull(txt.gatewayPort);
|
|
386
439
|
current.sshPort = parseIntOrNull(txt.sshPort);
|
|
387
440
|
if (txt.gatewayTls) {
|
|
388
441
|
const raw = txt.gatewayTls.trim().toLowerCase();
|
|
389
442
|
current.gatewayTls = raw === "1" || raw === "true" || raw === "yes";
|
|
390
443
|
}
|
|
391
|
-
if (txt.gatewayTlsSha256)
|
|
444
|
+
if (txt.gatewayTlsSha256) {
|
|
392
445
|
current.gatewayTlsFingerprintSha256 = txt.gatewayTlsSha256;
|
|
393
|
-
|
|
446
|
+
}
|
|
447
|
+
if (txt.role) {
|
|
394
448
|
current.role = txt.role;
|
|
395
|
-
|
|
449
|
+
}
|
|
450
|
+
if (txt.transport) {
|
|
396
451
|
current.transport = txt.transport;
|
|
452
|
+
}
|
|
397
453
|
}
|
|
398
454
|
}
|
|
399
|
-
if (current)
|
|
455
|
+
if (current) {
|
|
400
456
|
results.push(current);
|
|
457
|
+
}
|
|
401
458
|
return results;
|
|
402
459
|
}
|
|
403
460
|
async function discoverViaAvahi(domain, timeoutMs, run) {
|
|
404
|
-
const args = ["avahi-browse", "-rt",
|
|
461
|
+
const args = ["avahi-browse", "-rt", GATEWAY_SERVICE_TYPE];
|
|
405
462
|
if (domain && domain !== "local.") {
|
|
406
463
|
// avahi-browse wants a plain domain (no trailing dot)
|
|
407
464
|
args.push("-d", domain.replace(/\.$/, ""));
|
|
@@ -416,8 +473,10 @@ export async function discoverGatewayBeacons(opts = {}) {
|
|
|
416
473
|
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
417
474
|
const platform = opts.platform ?? process.platform;
|
|
418
475
|
const run = opts.run ?? runCommandWithTimeout;
|
|
476
|
+
const wideAreaDomain = resolveWideAreaDiscoveryDomain({ configDomain: opts.wideAreaDomain });
|
|
419
477
|
const domainsRaw = Array.isArray(opts.domains) ? opts.domains : [];
|
|
420
|
-
const
|
|
478
|
+
const defaultDomains = ["local.", ...(wideAreaDomain ? [wideAreaDomain] : [])];
|
|
479
|
+
const domains = (domainsRaw.length > 0 ? domainsRaw : defaultDomains)
|
|
421
480
|
.map((d) => String(d).trim())
|
|
422
481
|
.filter(Boolean)
|
|
423
482
|
.map((d) => (d.endsWith(".") ? d : `${d}.`));
|
|
@@ -425,10 +484,12 @@ export async function discoverGatewayBeacons(opts = {}) {
|
|
|
425
484
|
if (platform === "darwin") {
|
|
426
485
|
const perDomain = await Promise.allSettled(domains.map(async (domain) => await discoverViaDnsSd(domain, timeoutMs, run)));
|
|
427
486
|
const discovered = perDomain.flatMap((r) => (r.status === "fulfilled" ? r.value : []));
|
|
428
|
-
const wantsWideArea = domains.includes(
|
|
429
|
-
const hasWideArea =
|
|
430
|
-
|
|
431
|
-
|
|
487
|
+
const wantsWideArea = wideAreaDomain ? domains.includes(wideAreaDomain) : false;
|
|
488
|
+
const hasWideArea = wideAreaDomain
|
|
489
|
+
? discovered.some((b) => b.domain === wideAreaDomain)
|
|
490
|
+
: false;
|
|
491
|
+
if (wantsWideArea && !hasWideArea && wideAreaDomain) {
|
|
492
|
+
const fallback = await discoverWideAreaViaTailnetDns(wideAreaDomain, timeoutMs, run).catch(() => []);
|
|
432
493
|
return [...discovered, ...fallback];
|
|
433
494
|
}
|
|
434
495
|
return discovered;
|
package/dist/infra/bonjour.js
CHANGED
|
@@ -16,11 +16,11 @@ function isDisabledByEnv() {
|
|
|
16
16
|
}
|
|
17
17
|
function safeServiceName(name) {
|
|
18
18
|
const trimmed = name.trim();
|
|
19
|
-
return trimmed.length > 0 ? trimmed : "
|
|
19
|
+
return trimmed.length > 0 ? trimmed : "Poolbot";
|
|
20
20
|
}
|
|
21
21
|
function prettifyInstanceName(name) {
|
|
22
22
|
const normalized = name.trim().replace(/\s+/g, " ");
|
|
23
|
-
return normalized.replace(/\s+\(
|
|
23
|
+
return normalized.replace(/\s+\(Poolbot\)\s*$/i, "").trim() || normalized;
|
|
24
24
|
}
|
|
25
25
|
function serviceSummary(label, svc) {
|
|
26
26
|
let fqdn = "unknown";
|
|
@@ -63,7 +63,7 @@ export async function startGatewayBonjourAdvertiser(opts) {
|
|
|
63
63
|
.trim() || "poolbot";
|
|
64
64
|
const instanceName = typeof opts.instanceName === "string" && opts.instanceName.trim()
|
|
65
65
|
? opts.instanceName.trim()
|
|
66
|
-
: `${hostname} (
|
|
66
|
+
: `${hostname} (Poolbot)`;
|
|
67
67
|
const displayName = prettifyInstanceName(instanceName);
|
|
68
68
|
const txtBase = {
|
|
69
69
|
role: "gateway",
|