@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
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { upsertAuthProfile } from "../agents/auth-profiles.js";
|
|
2
2
|
import { formatApiKeyPreview, normalizeApiKeyInput, validateApiKeyInput, } from "./auth-choice.api-key.js";
|
|
3
3
|
import { buildTokenProfileId, validateAnthropicSetupToken } from "./auth-token.js";
|
|
4
|
+
import { applyAgentDefaultModelPrimary } from "./onboard-auth.config-shared.js";
|
|
4
5
|
import { applyAuthProfileConfig, setAnthropicApiKey } from "./onboard-auth.js";
|
|
6
|
+
const DEFAULT_ANTHROPIC_MODEL = "anthropic/claude-sonnet-4-6";
|
|
5
7
|
export async function applyAuthChoiceAnthropic(params) {
|
|
6
8
|
if (params.authChoice === "setup-token" ||
|
|
7
9
|
params.authChoice === "oauth" ||
|
|
@@ -12,7 +14,7 @@ export async function applyAuthChoiceAnthropic(params) {
|
|
|
12
14
|
message: "Paste Anthropic setup-token",
|
|
13
15
|
validate: (value) => validateAnthropicSetupToken(String(value ?? "")),
|
|
14
16
|
});
|
|
15
|
-
const token = String(tokenRaw).trim();
|
|
17
|
+
const token = String(tokenRaw ?? "").trim();
|
|
16
18
|
const profileNameRaw = await params.prompter.text({
|
|
17
19
|
message: "Token name (blank = default)",
|
|
18
20
|
placeholder: "default",
|
|
@@ -36,6 +38,9 @@ export async function applyAuthChoiceAnthropic(params) {
|
|
|
36
38
|
provider,
|
|
37
39
|
mode: "token",
|
|
38
40
|
});
|
|
41
|
+
if (params.setDefaultModel) {
|
|
42
|
+
nextConfig = applyAgentDefaultModelPrimary(nextConfig, DEFAULT_ANTHROPIC_MODEL);
|
|
43
|
+
}
|
|
39
44
|
return { config: nextConfig };
|
|
40
45
|
}
|
|
41
46
|
if (params.authChoice === "apiKey") {
|
|
@@ -64,13 +69,16 @@ export async function applyAuthChoiceAnthropic(params) {
|
|
|
64
69
|
message: "Enter Anthropic API key",
|
|
65
70
|
validate: validateApiKeyInput,
|
|
66
71
|
});
|
|
67
|
-
await setAnthropicApiKey(normalizeApiKeyInput(String(key)), params.agentDir);
|
|
72
|
+
await setAnthropicApiKey(normalizeApiKeyInput(String(key ?? "")), params.agentDir);
|
|
68
73
|
}
|
|
69
74
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
70
75
|
profileId: "anthropic:default",
|
|
71
76
|
provider: "anthropic",
|
|
72
77
|
mode: "api_key",
|
|
73
78
|
});
|
|
79
|
+
if (params.setDefaultModel) {
|
|
80
|
+
nextConfig = applyAgentDefaultModelPrimary(nextConfig, DEFAULT_ANTHROPIC_MODEL);
|
|
81
|
+
}
|
|
74
82
|
return { config: nextConfig };
|
|
75
83
|
}
|
|
76
84
|
return null;
|
|
@@ -10,40 +10,8 @@ export function applyChannelAccountConfig(params) {
|
|
|
10
10
|
const accountId = normalizeAccountId(params.accountId);
|
|
11
11
|
const plugin = getChannelPlugin(params.channel);
|
|
12
12
|
const apply = plugin?.setup?.applyAccountConfig;
|
|
13
|
-
if (!apply)
|
|
13
|
+
if (!apply) {
|
|
14
14
|
return params.cfg;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
token: params.token,
|
|
18
|
-
tokenFile: params.tokenFile,
|
|
19
|
-
botToken: params.botToken,
|
|
20
|
-
appToken: params.appToken,
|
|
21
|
-
signalNumber: params.signalNumber,
|
|
22
|
-
cliPath: params.cliPath,
|
|
23
|
-
dbPath: params.dbPath,
|
|
24
|
-
service: params.service,
|
|
25
|
-
region: params.region,
|
|
26
|
-
authDir: params.authDir,
|
|
27
|
-
httpUrl: params.httpUrl,
|
|
28
|
-
httpHost: params.httpHost,
|
|
29
|
-
httpPort: params.httpPort,
|
|
30
|
-
webhookPath: params.webhookPath,
|
|
31
|
-
webhookUrl: params.webhookUrl,
|
|
32
|
-
audienceType: params.audienceType,
|
|
33
|
-
audience: params.audience,
|
|
34
|
-
useEnv: params.useEnv,
|
|
35
|
-
homeserver: params.homeserver,
|
|
36
|
-
userId: params.userId,
|
|
37
|
-
accessToken: params.accessToken,
|
|
38
|
-
password: params.password,
|
|
39
|
-
deviceName: params.deviceName,
|
|
40
|
-
initialSyncLimit: params.initialSyncLimit,
|
|
41
|
-
ship: params.ship,
|
|
42
|
-
url: params.url,
|
|
43
|
-
code: params.code,
|
|
44
|
-
groupChannels: params.groupChannels,
|
|
45
|
-
dmAllowlist: params.dmAllowlist,
|
|
46
|
-
autoDiscoverChannels: params.autoDiscoverChannels,
|
|
47
|
-
};
|
|
48
|
-
return apply({ cfg: params.cfg, accountId, input });
|
|
15
|
+
}
|
|
16
|
+
return apply({ cfg: params.cfg, accountId, input: params.input });
|
|
49
17
|
}
|
|
@@ -4,14 +4,17 @@ import { getChannelPlugin, normalizeChannelId } from "../../channels/plugins/ind
|
|
|
4
4
|
import { writeConfigFile } from "../../config/config.js";
|
|
5
5
|
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../routing/session-key.js";
|
|
6
6
|
import { defaultRuntime } from "../../runtime.js";
|
|
7
|
+
import { resolveTelegramAccount } from "../../telegram/accounts.js";
|
|
8
|
+
import { deleteTelegramUpdateOffset } from "../../telegram/update-offset-store.js";
|
|
7
9
|
import { createClackPrompter } from "../../wizard/clack-prompter.js";
|
|
8
10
|
import { setupChannels } from "../onboard-channels.js";
|
|
9
11
|
import { ensureOnboardingPluginInstalled, reloadOnboardingPluginRegistry, } from "../onboarding/plugin-install.js";
|
|
10
12
|
import { applyAccountName, applyChannelAccountConfig } from "./add-mutators.js";
|
|
11
13
|
import { channelLabel, requireValidConfig, shouldUseWizard } from "./shared.js";
|
|
12
14
|
function parseList(value) {
|
|
13
|
-
if (!value?.trim())
|
|
15
|
+
if (!value?.trim()) {
|
|
14
16
|
return undefined;
|
|
17
|
+
}
|
|
15
18
|
const parsed = value
|
|
16
19
|
.split(/[\n,;]+/g)
|
|
17
20
|
.map((entry) => entry.trim())
|
|
@@ -20,19 +23,22 @@ function parseList(value) {
|
|
|
20
23
|
}
|
|
21
24
|
function resolveCatalogChannelEntry(raw, cfg) {
|
|
22
25
|
const trimmed = raw.trim().toLowerCase();
|
|
23
|
-
if (!trimmed)
|
|
26
|
+
if (!trimmed) {
|
|
24
27
|
return undefined;
|
|
28
|
+
}
|
|
25
29
|
const workspaceDir = cfg ? resolveAgentWorkspaceDir(cfg, resolveDefaultAgentId(cfg)) : undefined;
|
|
26
30
|
return listChannelPluginCatalogEntries({ workspaceDir }).find((entry) => {
|
|
27
|
-
if (entry.id.toLowerCase() === trimmed)
|
|
31
|
+
if (entry.id.toLowerCase() === trimmed) {
|
|
28
32
|
return true;
|
|
33
|
+
}
|
|
29
34
|
return (entry.meta.aliases ?? []).some((alias) => alias.trim().toLowerCase() === trimmed);
|
|
30
35
|
});
|
|
31
36
|
}
|
|
32
37
|
export async function channelsAddCommand(opts, runtime = defaultRuntime, params) {
|
|
33
38
|
const cfg = await requireValidConfig(runtime);
|
|
34
|
-
if (!cfg)
|
|
39
|
+
if (!cfg) {
|
|
35
40
|
return;
|
|
41
|
+
}
|
|
36
42
|
let nextConfig = cfg;
|
|
37
43
|
const useWizard = shouldUseWizard(params);
|
|
38
44
|
if (useWizard) {
|
|
@@ -98,8 +104,9 @@ export async function channelsAddCommand(opts, runtime = defaultRuntime, params)
|
|
|
98
104
|
workspaceDir,
|
|
99
105
|
});
|
|
100
106
|
nextConfig = result.cfg;
|
|
101
|
-
if (!result.installed)
|
|
107
|
+
if (!result.installed) {
|
|
102
108
|
return;
|
|
109
|
+
}
|
|
103
110
|
reloadOnboardingPluginRegistry({ cfg: nextConfig, runtime, workspaceDir });
|
|
104
111
|
channel = normalizeChannelId(catalogEntry.id) ?? catalogEntry.id;
|
|
105
112
|
}
|
|
@@ -127,52 +134,7 @@ export async function channelsAddCommand(opts, runtime = defaultRuntime, params)
|
|
|
127
134
|
: undefined;
|
|
128
135
|
const groupChannels = parseList(opts.groupChannels);
|
|
129
136
|
const dmAllowlist = parseList(opts.dmAllowlist);
|
|
130
|
-
const
|
|
131
|
-
cfg: nextConfig,
|
|
132
|
-
accountId,
|
|
133
|
-
input: {
|
|
134
|
-
name: opts.name,
|
|
135
|
-
token: opts.token,
|
|
136
|
-
tokenFile: opts.tokenFile,
|
|
137
|
-
botToken: opts.botToken,
|
|
138
|
-
appToken: opts.appToken,
|
|
139
|
-
signalNumber: opts.signalNumber,
|
|
140
|
-
cliPath: opts.cliPath,
|
|
141
|
-
dbPath: opts.dbPath,
|
|
142
|
-
service: opts.service,
|
|
143
|
-
region: opts.region,
|
|
144
|
-
authDir: opts.authDir,
|
|
145
|
-
httpUrl: opts.httpUrl,
|
|
146
|
-
httpHost: opts.httpHost,
|
|
147
|
-
httpPort: opts.httpPort,
|
|
148
|
-
webhookPath: opts.webhookPath,
|
|
149
|
-
webhookUrl: opts.webhookUrl,
|
|
150
|
-
audienceType: opts.audienceType,
|
|
151
|
-
audience: opts.audience,
|
|
152
|
-
homeserver: opts.homeserver,
|
|
153
|
-
userId: opts.userId,
|
|
154
|
-
accessToken: opts.accessToken,
|
|
155
|
-
password: opts.password,
|
|
156
|
-
deviceName: opts.deviceName,
|
|
157
|
-
initialSyncLimit,
|
|
158
|
-
useEnv,
|
|
159
|
-
ship: opts.ship,
|
|
160
|
-
url: opts.url,
|
|
161
|
-
code: opts.code,
|
|
162
|
-
groupChannels,
|
|
163
|
-
dmAllowlist,
|
|
164
|
-
autoDiscoverChannels: opts.autoDiscoverChannels,
|
|
165
|
-
},
|
|
166
|
-
});
|
|
167
|
-
if (validationError) {
|
|
168
|
-
runtime.error(validationError);
|
|
169
|
-
runtime.exit(1);
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
nextConfig = applyChannelAccountConfig({
|
|
173
|
-
cfg: nextConfig,
|
|
174
|
-
channel,
|
|
175
|
-
accountId,
|
|
137
|
+
const input = {
|
|
176
138
|
name: opts.name,
|
|
177
139
|
token: opts.token,
|
|
178
140
|
tokenFile: opts.tokenFile,
|
|
@@ -204,7 +166,33 @@ export async function channelsAddCommand(opts, runtime = defaultRuntime, params)
|
|
|
204
166
|
groupChannels,
|
|
205
167
|
dmAllowlist,
|
|
206
168
|
autoDiscoverChannels: opts.autoDiscoverChannels,
|
|
169
|
+
};
|
|
170
|
+
const validationError = plugin.setup.validateInput?.({
|
|
171
|
+
cfg: nextConfig,
|
|
172
|
+
accountId,
|
|
173
|
+
input,
|
|
174
|
+
});
|
|
175
|
+
if (validationError) {
|
|
176
|
+
runtime.error(validationError);
|
|
177
|
+
runtime.exit(1);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const previousTelegramToken = channel === "telegram"
|
|
181
|
+
? resolveTelegramAccount({ cfg: nextConfig, accountId }).token.trim()
|
|
182
|
+
: "";
|
|
183
|
+
nextConfig = applyChannelAccountConfig({
|
|
184
|
+
cfg: nextConfig,
|
|
185
|
+
channel,
|
|
186
|
+
accountId,
|
|
187
|
+
input,
|
|
207
188
|
});
|
|
189
|
+
if (channel === "telegram") {
|
|
190
|
+
const nextTelegramToken = resolveTelegramAccount({ cfg: nextConfig, accountId }).token.trim();
|
|
191
|
+
if (previousTelegramToken !== nextTelegramToken) {
|
|
192
|
+
// Clear stale polling offsets after Telegram token rotation.
|
|
193
|
+
await deleteTelegramUpdateOffset({ accountId });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
208
196
|
await writeConfigFile(nextConfig);
|
|
209
197
|
runtime.log(`Added ${channelLabel(channel)} account "${accountId}".`);
|
|
210
198
|
}
|
|
@@ -7,7 +7,7 @@ export async function requireValidConfigSnapshot(runtime) {
|
|
|
7
7
|
? snapshot.issues.map((issue) => `- ${issue.path}: ${issue.message}`).join("\n")
|
|
8
8
|
: "Unknown validation issue.";
|
|
9
9
|
runtime.error(`Config invalid:\n${issues}`);
|
|
10
|
-
runtime.error(`Fix the config or run ${formatCliCommand("
|
|
10
|
+
runtime.error(`Fix the config or run ${formatCliCommand("poolbot doctor")}.`);
|
|
11
11
|
runtime.exit(1);
|
|
12
12
|
return null;
|
|
13
13
|
}
|
|
@@ -1,8 +1,23 @@
|
|
|
1
1
|
import { ensureAuthProfileStore } from "../agents/auth-profiles.js";
|
|
2
|
-
import { applyAuthChoice, resolvePreferredProviderForAuthChoice } from "./auth-choice.js";
|
|
3
2
|
import { promptAuthChoiceGrouped } from "./auth-choice-prompt.js";
|
|
3
|
+
import { applyAuthChoice, resolvePreferredProviderForAuthChoice } from "./auth-choice.js";
|
|
4
4
|
import { applyModelAllowlist, applyModelFallbacksFromSelection, applyPrimaryModel, promptDefaultModel, promptModelAllowlist, } from "./model-picker.js";
|
|
5
|
+
import { promptCustomApiConfig } from "./onboard-custom.js";
|
|
6
|
+
import { randomToken } from "./onboard-helpers.js";
|
|
7
|
+
/** Reject undefined, empty, and common JS string-coercion artifacts for token auth. */
|
|
8
|
+
function sanitizeTokenValue(value) {
|
|
9
|
+
if (typeof value !== "string") {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
const trimmed = value.trim();
|
|
13
|
+
if (!trimmed || trimmed === "undefined" || trimmed === "null") {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
return trimmed;
|
|
17
|
+
}
|
|
5
18
|
const ANTHROPIC_OAUTH_MODEL_KEYS = [
|
|
19
|
+
"anthropic/claude-sonnet-4-6",
|
|
20
|
+
"anthropic/claude-opus-4-6",
|
|
6
21
|
"anthropic/claude-opus-4-5",
|
|
7
22
|
"anthropic/claude-sonnet-4-5",
|
|
8
23
|
"anthropic/claude-haiku-4-5",
|
|
@@ -10,12 +25,25 @@ const ANTHROPIC_OAUTH_MODEL_KEYS = [
|
|
|
10
25
|
export function buildGatewayAuthConfig(params) {
|
|
11
26
|
const allowTailscale = params.existing?.allowTailscale;
|
|
12
27
|
const base = {};
|
|
13
|
-
if (typeof allowTailscale === "boolean")
|
|
28
|
+
if (typeof allowTailscale === "boolean") {
|
|
14
29
|
base.allowTailscale = allowTailscale;
|
|
30
|
+
}
|
|
15
31
|
if (params.mode === "token") {
|
|
16
|
-
|
|
32
|
+
// Keep token mode always valid: treat empty/undefined/"undefined"/"null" as missing and generate a token.
|
|
33
|
+
const token = sanitizeTokenValue(params.token) ?? randomToken();
|
|
34
|
+
return { ...base, mode: "token", token };
|
|
35
|
+
}
|
|
36
|
+
if (params.mode === "password") {
|
|
37
|
+
const password = params.password?.trim();
|
|
38
|
+
return { ...base, mode: "password", ...(password && { password }) };
|
|
39
|
+
}
|
|
40
|
+
if (params.mode === "trusted-proxy") {
|
|
41
|
+
if (!params.trustedProxy) {
|
|
42
|
+
throw new Error("trustedProxy config is required when mode is trusted-proxy");
|
|
43
|
+
}
|
|
44
|
+
return { ...base, mode: "trusted-proxy", trustedProxy: params.trustedProxy };
|
|
17
45
|
}
|
|
18
|
-
return
|
|
46
|
+
return base;
|
|
19
47
|
}
|
|
20
48
|
export async function promptAuthConfig(cfg, runtime, prompter) {
|
|
21
49
|
const authChoice = await promptAuthChoiceGrouped({
|
|
@@ -26,7 +54,11 @@ export async function promptAuthConfig(cfg, runtime, prompter) {
|
|
|
26
54
|
includeSkip: true,
|
|
27
55
|
});
|
|
28
56
|
let next = cfg;
|
|
29
|
-
if (authChoice
|
|
57
|
+
if (authChoice === "custom-api-key") {
|
|
58
|
+
const customResult = await promptCustomApiConfig({ prompter, runtime, config: next });
|
|
59
|
+
next = customResult.config;
|
|
60
|
+
}
|
|
61
|
+
else if (authChoice !== "skip") {
|
|
30
62
|
const applied = await applyAuthChoice({
|
|
31
63
|
authChoice,
|
|
32
64
|
config: next,
|
|
@@ -44,21 +76,26 @@ export async function promptAuthConfig(cfg, runtime, prompter) {
|
|
|
44
76
|
ignoreAllowlist: true,
|
|
45
77
|
preferredProvider: resolvePreferredProviderForAuthChoice(authChoice),
|
|
46
78
|
});
|
|
79
|
+
if (modelSelection.config) {
|
|
80
|
+
next = modelSelection.config;
|
|
81
|
+
}
|
|
47
82
|
if (modelSelection.model) {
|
|
48
83
|
next = applyPrimaryModel(next, modelSelection.model);
|
|
49
84
|
}
|
|
50
85
|
}
|
|
51
86
|
const anthropicOAuth = authChoice === "setup-token" || authChoice === "token" || authChoice === "oauth";
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
87
|
+
if (authChoice !== "custom-api-key") {
|
|
88
|
+
const allowlistSelection = await promptModelAllowlist({
|
|
89
|
+
config: next,
|
|
90
|
+
prompter,
|
|
91
|
+
allowedKeys: anthropicOAuth ? ANTHROPIC_OAUTH_MODEL_KEYS : undefined,
|
|
92
|
+
initialSelections: anthropicOAuth ? ["anthropic/claude-sonnet-4-6"] : undefined,
|
|
93
|
+
message: anthropicOAuth ? "Anthropic OAuth models" : undefined,
|
|
94
|
+
});
|
|
95
|
+
if (allowlistSelection.models) {
|
|
96
|
+
next = applyModelAllowlist(next, allowlistSelection.models);
|
|
97
|
+
next = applyModelFallbacksFromSelection(next, allowlistSelection.models);
|
|
98
|
+
}
|
|
62
99
|
}
|
|
63
100
|
return next;
|
|
64
101
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { resolveGatewayPort } from "../config/config.js";
|
|
2
|
+
import { TAILSCALE_DOCS_LINES, TAILSCALE_EXPOSURE_OPTIONS, TAILSCALE_MISSING_BIN_NOTE_LINES, } from "../gateway/gateway-config-prompts.shared.js";
|
|
2
3
|
import { findTailscaleBinary } from "../infra/tailscale.js";
|
|
4
|
+
import { validateIPv4AddressInput } from "../shared/net/ipv4.js";
|
|
3
5
|
import { note } from "../terminal/note.js";
|
|
4
6
|
import { buildGatewayAuthConfig } from "./configure.gateway-auth.js";
|
|
5
7
|
import { confirm, select, text } from "./configure.shared.js";
|
|
6
|
-
import { guardCancel, randomToken } from "./onboard-helpers.js";
|
|
8
|
+
import { guardCancel, normalizeGatewayTokenInput, randomToken, validateGatewayPasswordInput, } from "./onboard-helpers.js";
|
|
7
9
|
export async function promptGatewayConfig(cfg, runtime) {
|
|
8
10
|
const portRaw = guardCancel(await text({
|
|
9
11
|
message: "Gateway port",
|
|
@@ -46,20 +48,7 @@ export async function promptGatewayConfig(cfg, runtime) {
|
|
|
46
48
|
const input = guardCancel(await text({
|
|
47
49
|
message: "Custom IP address",
|
|
48
50
|
placeholder: "192.168.1.100",
|
|
49
|
-
validate:
|
|
50
|
-
if (!value)
|
|
51
|
-
return "IP address is required for custom bind mode";
|
|
52
|
-
const trimmed = value.trim();
|
|
53
|
-
const parts = trimmed.split(".");
|
|
54
|
-
if (parts.length !== 4)
|
|
55
|
-
return "Invalid IPv4 address (e.g., 192.168.1.100)";
|
|
56
|
-
if (parts.every((part) => {
|
|
57
|
-
const n = parseInt(part, 10);
|
|
58
|
-
return !Number.isNaN(n) && n >= 0 && n <= 255 && part === String(n);
|
|
59
|
-
}))
|
|
60
|
-
return undefined;
|
|
61
|
-
return "Invalid IPv4 address (each octet must be 0-255)";
|
|
62
|
-
},
|
|
51
|
+
validate: validateIPv4AddressInput,
|
|
63
52
|
}), runtime);
|
|
64
53
|
customBindHost = typeof input === "string" ? input : undefined;
|
|
65
54
|
}
|
|
@@ -68,41 +57,28 @@ export async function promptGatewayConfig(cfg, runtime) {
|
|
|
68
57
|
options: [
|
|
69
58
|
{ value: "token", label: "Token", hint: "Recommended default" },
|
|
70
59
|
{ value: "password", label: "Password" },
|
|
60
|
+
{
|
|
61
|
+
value: "trusted-proxy",
|
|
62
|
+
label: "Trusted Proxy",
|
|
63
|
+
hint: "Behind reverse proxy (Pomerium, Caddy, Traefik, etc.)",
|
|
64
|
+
},
|
|
71
65
|
],
|
|
72
66
|
initialValue: "token",
|
|
73
67
|
}), runtime);
|
|
74
|
-
|
|
68
|
+
let tailscaleMode = guardCancel(await select({
|
|
75
69
|
message: "Tailscale exposure",
|
|
76
|
-
options: [
|
|
77
|
-
{ value: "off", label: "Off", hint: "No Tailscale exposure" },
|
|
78
|
-
{
|
|
79
|
-
value: "serve",
|
|
80
|
-
label: "Serve",
|
|
81
|
-
hint: "Private HTTPS for your tailnet (devices on Tailscale)",
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
value: "funnel",
|
|
85
|
-
label: "Funnel",
|
|
86
|
-
hint: "Public HTTPS via Tailscale Funnel (internet)",
|
|
87
|
-
},
|
|
88
|
-
],
|
|
70
|
+
options: [...TAILSCALE_EXPOSURE_OPTIONS],
|
|
89
71
|
}), runtime);
|
|
90
72
|
// Detect Tailscale binary before proceeding with serve/funnel setup.
|
|
91
73
|
if (tailscaleMode !== "off") {
|
|
92
74
|
const tailscaleBin = await findTailscaleBinary();
|
|
93
75
|
if (!tailscaleBin) {
|
|
94
|
-
note(
|
|
95
|
-
"Tailscale binary not found in PATH or /Applications.",
|
|
96
|
-
"Ensure Tailscale is installed from:",
|
|
97
|
-
" https://tailscale.com/download/mac",
|
|
98
|
-
"",
|
|
99
|
-
"You can continue setup, but serve/funnel will fail at runtime.",
|
|
100
|
-
].join("\n"), "Tailscale Warning");
|
|
76
|
+
note(TAILSCALE_MISSING_BIN_NOTE_LINES.join("\n"), "Tailscale Warning");
|
|
101
77
|
}
|
|
102
78
|
}
|
|
103
79
|
let tailscaleResetOnExit = false;
|
|
104
80
|
if (tailscaleMode !== "off") {
|
|
105
|
-
note(
|
|
81
|
+
note(TAILSCALE_DOCS_LINES.join("\n"), "Tailscale");
|
|
106
82
|
tailscaleResetOnExit = Boolean(guardCancel(await confirm({
|
|
107
83
|
message: "Reset Tailscale serve/funnel on exit?",
|
|
108
84
|
initialValue: false,
|
|
@@ -116,28 +92,95 @@ export async function promptGatewayConfig(cfg, runtime) {
|
|
|
116
92
|
note("Tailscale funnel requires password auth.", "Note");
|
|
117
93
|
authMode = "password";
|
|
118
94
|
}
|
|
95
|
+
if (authMode === "trusted-proxy" && bind === "loopback") {
|
|
96
|
+
note("Trusted proxy auth requires network bind. Adjusting bind to lan.", "Note");
|
|
97
|
+
bind = "lan";
|
|
98
|
+
}
|
|
99
|
+
if (authMode === "trusted-proxy" && tailscaleMode !== "off") {
|
|
100
|
+
note("Trusted proxy auth is incompatible with Tailscale serve/funnel. Disabling Tailscale.", "Note");
|
|
101
|
+
tailscaleMode = "off";
|
|
102
|
+
tailscaleResetOnExit = false;
|
|
103
|
+
}
|
|
119
104
|
let gatewayToken;
|
|
120
105
|
let gatewayPassword;
|
|
106
|
+
let trustedProxyConfig;
|
|
107
|
+
let trustedProxies;
|
|
121
108
|
let next = cfg;
|
|
122
109
|
if (authMode === "token") {
|
|
123
110
|
const tokenInput = guardCancel(await text({
|
|
124
111
|
message: "Gateway token (blank to generate)",
|
|
125
112
|
initialValue: randomToken(),
|
|
126
113
|
}), runtime);
|
|
127
|
-
gatewayToken =
|
|
114
|
+
gatewayToken = normalizeGatewayTokenInput(tokenInput) || randomToken();
|
|
128
115
|
}
|
|
129
116
|
if (authMode === "password") {
|
|
130
117
|
const password = guardCancel(await text({
|
|
131
118
|
message: "Gateway password",
|
|
132
|
-
validate:
|
|
119
|
+
validate: validateGatewayPasswordInput,
|
|
120
|
+
}), runtime);
|
|
121
|
+
gatewayPassword = String(password ?? "").trim();
|
|
122
|
+
}
|
|
123
|
+
if (authMode === "trusted-proxy") {
|
|
124
|
+
note([
|
|
125
|
+
"Trusted proxy mode: Pool Bot trusts user identity from a reverse proxy.",
|
|
126
|
+
"The proxy must authenticate users and pass identity via headers.",
|
|
127
|
+
"Only requests from specified proxy IPs will be trusted.",
|
|
128
|
+
"",
|
|
129
|
+
"Common use cases: Pomerium, Caddy + OAuth, Traefik + forward auth",
|
|
130
|
+
"Docs: https://docs.poolbot.dev/gateway/trusted-proxy-auth",
|
|
131
|
+
].join("\n"), "Trusted Proxy Auth");
|
|
132
|
+
const userHeader = guardCancel(await text({
|
|
133
|
+
message: "Header containing user identity",
|
|
134
|
+
placeholder: "x-forwarded-user",
|
|
135
|
+
initialValue: "x-forwarded-user",
|
|
136
|
+
validate: (value) => (value?.trim() ? undefined : "User header is required"),
|
|
137
|
+
}), runtime);
|
|
138
|
+
const requiredHeadersRaw = guardCancel(await text({
|
|
139
|
+
message: "Required headers (comma-separated, optional)",
|
|
140
|
+
placeholder: "x-forwarded-proto,x-forwarded-host",
|
|
141
|
+
}), runtime);
|
|
142
|
+
const requiredHeaders = requiredHeadersRaw
|
|
143
|
+
? String(requiredHeadersRaw)
|
|
144
|
+
.split(",")
|
|
145
|
+
.map((h) => h.trim())
|
|
146
|
+
.filter(Boolean)
|
|
147
|
+
: [];
|
|
148
|
+
const allowUsersRaw = guardCancel(await text({
|
|
149
|
+
message: "Allowed users (comma-separated, blank = all authenticated users)",
|
|
150
|
+
placeholder: "nick@example.com,admin@company.com",
|
|
151
|
+
}), runtime);
|
|
152
|
+
const allowUsers = allowUsersRaw
|
|
153
|
+
? String(allowUsersRaw)
|
|
154
|
+
.split(",")
|
|
155
|
+
.map((u) => u.trim())
|
|
156
|
+
.filter(Boolean)
|
|
157
|
+
: [];
|
|
158
|
+
const trustedProxiesRaw = guardCancel(await text({
|
|
159
|
+
message: "Trusted proxy IPs (comma-separated)",
|
|
160
|
+
placeholder: "10.0.1.10,192.168.1.5",
|
|
161
|
+
validate: (value) => {
|
|
162
|
+
if (!value || String(value).trim() === "") {
|
|
163
|
+
return "At least one trusted proxy IP is required";
|
|
164
|
+
}
|
|
165
|
+
return undefined;
|
|
166
|
+
},
|
|
133
167
|
}), runtime);
|
|
134
|
-
|
|
168
|
+
trustedProxies = String(trustedProxiesRaw)
|
|
169
|
+
.split(",")
|
|
170
|
+
.map((ip) => ip.trim())
|
|
171
|
+
.filter(Boolean);
|
|
172
|
+
trustedProxyConfig = {
|
|
173
|
+
userHeader: String(userHeader).trim(),
|
|
174
|
+
requiredHeaders: requiredHeaders.length > 0 ? requiredHeaders : undefined,
|
|
175
|
+
allowUsers: allowUsers.length > 0 ? allowUsers : undefined,
|
|
176
|
+
};
|
|
135
177
|
}
|
|
136
178
|
const authConfig = buildGatewayAuthConfig({
|
|
137
179
|
existing: next.gateway?.auth,
|
|
138
180
|
mode: authMode,
|
|
139
181
|
token: gatewayToken,
|
|
140
182
|
password: gatewayPassword,
|
|
183
|
+
trustedProxy: trustedProxyConfig,
|
|
141
184
|
});
|
|
142
185
|
next = {
|
|
143
186
|
...next,
|
|
@@ -148,6 +191,7 @@ export async function promptGatewayConfig(cfg, runtime) {
|
|
|
148
191
|
bind,
|
|
149
192
|
auth: authConfig,
|
|
150
193
|
...(customBindHost && { customBindHost }),
|
|
194
|
+
...(trustedProxies && { trustedProxies }),
|
|
151
195
|
tailscale: {
|
|
152
196
|
...next.gateway?.tailscale,
|
|
153
197
|
mode: tailscaleMode,
|
|
@@ -2,11 +2,11 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { resolveCliName } from "../cli/cli-name.js";
|
|
4
4
|
import { completionCacheExists, installCompletion, isCompletionInstalled, resolveCompletionCachePath, resolveShellFromEnv, usesSlowDynamicCompletion, } from "../cli/completion-cli.js";
|
|
5
|
-
import {
|
|
5
|
+
import { resolvePoolBotPackageRoot } from "../infra/poolbot-root.js";
|
|
6
6
|
import { note } from "../terminal/note.js";
|
|
7
7
|
/** Generate the completion cache by spawning the CLI. */
|
|
8
8
|
async function generateCompletionCache() {
|
|
9
|
-
const root = await
|
|
9
|
+
const root = await resolvePoolBotPackageRoot({
|
|
10
10
|
moduleUrl: import.meta.url,
|
|
11
11
|
argv1: process.argv[1],
|
|
12
12
|
cwd: process.cwd(),
|
|
@@ -14,7 +14,7 @@ async function generateCompletionCache() {
|
|
|
14
14
|
if (!root) {
|
|
15
15
|
return false;
|
|
16
16
|
}
|
|
17
|
-
const binPath = path.join(root, "
|
|
17
|
+
const binPath = path.join(root, "poolbot.mjs");
|
|
18
18
|
const result = spawnSync(process.execPath, [binPath, "completion", "--write-state"], {
|
|
19
19
|
cwd: root,
|
|
20
20
|
env: process.env,
|