@poolzin/pool-bot 2026.2.21 → 2026.2.22
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 +17 -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/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/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 +5 -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 +5 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +5 -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 +5 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +5 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +5 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +5 -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/config/defaults.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { DEFAULT_CONTEXT_TOKENS } from "../agents/defaults.js";
|
|
2
2
|
import { parseModelRef } from "../agents/model-selection.js";
|
|
3
|
-
import { resolveTalkApiKey } from "./talk.js";
|
|
4
3
|
import { DEFAULT_AGENT_MAX_CONCURRENT, DEFAULT_SUBAGENT_MAX_CONCURRENT } from "./agent-limits.js";
|
|
4
|
+
import { resolveTalkApiKey } from "./talk.js";
|
|
5
5
|
let defaultWarnState = { warned: false };
|
|
6
6
|
const DEFAULT_MODEL_ALIASES = {
|
|
7
7
|
// Anthropic (pi-ai catalog uses "latest" ids without date suffix)
|
|
8
8
|
opus: "anthropic/claude-opus-4-6",
|
|
9
|
-
sonnet: "anthropic/claude-sonnet-4-
|
|
9
|
+
sonnet: "anthropic/claude-sonnet-4-6",
|
|
10
10
|
// OpenAI
|
|
11
11
|
gpt: "openai/gpt-5.2",
|
|
12
12
|
"gpt-mini": "openai/gpt-5-mini",
|
|
@@ -39,39 +39,49 @@ function resolveAnthropicDefaultAuthMode(cfg) {
|
|
|
39
39
|
const order = cfg.auth?.order?.anthropic ?? [];
|
|
40
40
|
for (const profileId of order) {
|
|
41
41
|
const entry = profiles[profileId];
|
|
42
|
-
if (!entry || entry.provider !== "anthropic")
|
|
42
|
+
if (!entry || entry.provider !== "anthropic") {
|
|
43
43
|
continue;
|
|
44
|
-
|
|
44
|
+
}
|
|
45
|
+
if (entry.mode === "api_key") {
|
|
45
46
|
return "api_key";
|
|
46
|
-
|
|
47
|
+
}
|
|
48
|
+
if (entry.mode === "oauth" || entry.mode === "token") {
|
|
47
49
|
return "oauth";
|
|
50
|
+
}
|
|
48
51
|
}
|
|
49
52
|
const hasApiKey = anthropicProfiles.some(([, profile]) => profile?.mode === "api_key");
|
|
50
53
|
const hasOauth = anthropicProfiles.some(([, profile]) => profile?.mode === "oauth" || profile?.mode === "token");
|
|
51
|
-
if (hasApiKey && !hasOauth)
|
|
54
|
+
if (hasApiKey && !hasOauth) {
|
|
52
55
|
return "api_key";
|
|
53
|
-
|
|
56
|
+
}
|
|
57
|
+
if (hasOauth && !hasApiKey) {
|
|
54
58
|
return "oauth";
|
|
55
|
-
|
|
59
|
+
}
|
|
60
|
+
if (process.env.ANTHROPIC_OAUTH_TOKEN?.trim()) {
|
|
56
61
|
return "oauth";
|
|
57
|
-
|
|
62
|
+
}
|
|
63
|
+
if (process.env.ANTHROPIC_API_KEY?.trim()) {
|
|
58
64
|
return "api_key";
|
|
65
|
+
}
|
|
59
66
|
return null;
|
|
60
67
|
}
|
|
61
68
|
function resolvePrimaryModelRef(raw) {
|
|
62
|
-
if (!raw || typeof raw !== "string")
|
|
69
|
+
if (!raw || typeof raw !== "string") {
|
|
63
70
|
return null;
|
|
71
|
+
}
|
|
64
72
|
const trimmed = raw.trim();
|
|
65
|
-
if (!trimmed)
|
|
73
|
+
if (!trimmed) {
|
|
66
74
|
return null;
|
|
75
|
+
}
|
|
67
76
|
const aliasKey = trimmed.toLowerCase();
|
|
68
77
|
return DEFAULT_MODEL_ALIASES[aliasKey] ?? trimmed;
|
|
69
78
|
}
|
|
70
79
|
export function applyMessageDefaults(cfg) {
|
|
71
80
|
const messages = cfg.messages;
|
|
72
81
|
const hasAckScope = messages?.ackReactionScope !== undefined;
|
|
73
|
-
if (hasAckScope)
|
|
82
|
+
if (hasAckScope) {
|
|
74
83
|
return cfg;
|
|
84
|
+
}
|
|
75
85
|
const nextMessages = messages ? { ...messages } : {};
|
|
76
86
|
nextMessages.ackReactionScope = "group-mentions";
|
|
77
87
|
return {
|
|
@@ -81,8 +91,9 @@ export function applyMessageDefaults(cfg) {
|
|
|
81
91
|
}
|
|
82
92
|
export function applySessionDefaults(cfg, options = {}) {
|
|
83
93
|
const session = cfg.session;
|
|
84
|
-
if (!session || session.mainKey === undefined)
|
|
94
|
+
if (!session || session.mainKey === undefined) {
|
|
85
95
|
return cfg;
|
|
96
|
+
}
|
|
86
97
|
const trimmed = session.mainKey.trim();
|
|
87
98
|
const warn = options.warn ?? console.warn;
|
|
88
99
|
const warnState = options.warnState ?? defaultWarnState;
|
|
@@ -98,11 +109,13 @@ export function applySessionDefaults(cfg, options = {}) {
|
|
|
98
109
|
}
|
|
99
110
|
export function applyTalkApiKey(config) {
|
|
100
111
|
const resolved = resolveTalkApiKey();
|
|
101
|
-
if (!resolved)
|
|
112
|
+
if (!resolved) {
|
|
102
113
|
return config;
|
|
114
|
+
}
|
|
103
115
|
const existing = config.talk?.apiKey?.trim();
|
|
104
|
-
if (existing)
|
|
116
|
+
if (existing) {
|
|
105
117
|
return config;
|
|
118
|
+
}
|
|
106
119
|
return {
|
|
107
120
|
...config,
|
|
108
121
|
talk: {
|
|
@@ -119,38 +132,45 @@ export function applyModelDefaults(cfg) {
|
|
|
119
132
|
const nextProviders = { ...providerConfig };
|
|
120
133
|
for (const [providerId, provider] of Object.entries(providerConfig)) {
|
|
121
134
|
const models = provider.models;
|
|
122
|
-
if (!Array.isArray(models) || models.length === 0)
|
|
135
|
+
if (!Array.isArray(models) || models.length === 0) {
|
|
123
136
|
continue;
|
|
137
|
+
}
|
|
124
138
|
let providerMutated = false;
|
|
125
139
|
const nextModels = models.map((model) => {
|
|
126
140
|
const raw = model;
|
|
127
141
|
let modelMutated = false;
|
|
128
142
|
const reasoning = typeof raw.reasoning === "boolean" ? raw.reasoning : false;
|
|
129
|
-
if (raw.reasoning !== reasoning)
|
|
143
|
+
if (raw.reasoning !== reasoning) {
|
|
130
144
|
modelMutated = true;
|
|
145
|
+
}
|
|
131
146
|
const input = raw.input ?? [...DEFAULT_MODEL_INPUT];
|
|
132
|
-
if (raw.input === undefined)
|
|
147
|
+
if (raw.input === undefined) {
|
|
133
148
|
modelMutated = true;
|
|
149
|
+
}
|
|
134
150
|
const cost = resolveModelCost(raw.cost);
|
|
135
151
|
const costMutated = !raw.cost ||
|
|
136
152
|
raw.cost.input !== cost.input ||
|
|
137
153
|
raw.cost.output !== cost.output ||
|
|
138
154
|
raw.cost.cacheRead !== cost.cacheRead ||
|
|
139
155
|
raw.cost.cacheWrite !== cost.cacheWrite;
|
|
140
|
-
if (costMutated)
|
|
156
|
+
if (costMutated) {
|
|
141
157
|
modelMutated = true;
|
|
158
|
+
}
|
|
142
159
|
const contextWindow = isPositiveNumber(raw.contextWindow)
|
|
143
160
|
? raw.contextWindow
|
|
144
161
|
: DEFAULT_CONTEXT_TOKENS;
|
|
145
|
-
if (raw.contextWindow !== contextWindow)
|
|
162
|
+
if (raw.contextWindow !== contextWindow) {
|
|
146
163
|
modelMutated = true;
|
|
164
|
+
}
|
|
147
165
|
const defaultMaxTokens = Math.min(DEFAULT_MODEL_MAX_TOKENS, contextWindow);
|
|
148
166
|
const rawMaxTokens = isPositiveNumber(raw.maxTokens) ? raw.maxTokens : defaultMaxTokens;
|
|
149
167
|
const maxTokens = Math.min(rawMaxTokens, contextWindow);
|
|
150
|
-
if (raw.maxTokens !== maxTokens)
|
|
168
|
+
if (raw.maxTokens !== maxTokens) {
|
|
151
169
|
modelMutated = true;
|
|
152
|
-
|
|
170
|
+
}
|
|
171
|
+
if (!modelMutated) {
|
|
153
172
|
return model;
|
|
173
|
+
}
|
|
154
174
|
providerMutated = true;
|
|
155
175
|
return {
|
|
156
176
|
...raw,
|
|
@@ -161,8 +181,9 @@ export function applyModelDefaults(cfg) {
|
|
|
161
181
|
maxTokens,
|
|
162
182
|
};
|
|
163
183
|
});
|
|
164
|
-
if (!providerMutated)
|
|
184
|
+
if (!providerMutated) {
|
|
165
185
|
continue;
|
|
186
|
+
}
|
|
166
187
|
nextProviders[providerId] = { ...provider, models: nextModels };
|
|
167
188
|
mutated = true;
|
|
168
189
|
}
|
|
@@ -177,25 +198,30 @@ export function applyModelDefaults(cfg) {
|
|
|
177
198
|
}
|
|
178
199
|
}
|
|
179
200
|
const existingAgent = nextCfg.agents?.defaults;
|
|
180
|
-
if (!existingAgent)
|
|
201
|
+
if (!existingAgent) {
|
|
181
202
|
return mutated ? nextCfg : cfg;
|
|
203
|
+
}
|
|
182
204
|
const existingModels = existingAgent.models ?? {};
|
|
183
|
-
if (Object.keys(existingModels).length === 0)
|
|
205
|
+
if (Object.keys(existingModels).length === 0) {
|
|
184
206
|
return mutated ? nextCfg : cfg;
|
|
207
|
+
}
|
|
185
208
|
const nextModels = {
|
|
186
209
|
...existingModels,
|
|
187
210
|
};
|
|
188
211
|
for (const [alias, target] of Object.entries(DEFAULT_MODEL_ALIASES)) {
|
|
189
212
|
const entry = nextModels[target];
|
|
190
|
-
if (!entry)
|
|
213
|
+
if (!entry) {
|
|
191
214
|
continue;
|
|
192
|
-
|
|
215
|
+
}
|
|
216
|
+
if (entry.alias !== undefined) {
|
|
193
217
|
continue;
|
|
218
|
+
}
|
|
194
219
|
nextModels[target] = { ...entry, alias };
|
|
195
220
|
mutated = true;
|
|
196
221
|
}
|
|
197
|
-
if (!mutated)
|
|
222
|
+
if (!mutated) {
|
|
198
223
|
return cfg;
|
|
224
|
+
}
|
|
199
225
|
return {
|
|
200
226
|
...nextCfg,
|
|
201
227
|
agents: {
|
|
@@ -210,8 +236,9 @@ export function applyAgentDefaults(cfg) {
|
|
|
210
236
|
const hasMax = typeof defaults?.maxConcurrent === "number" && Number.isFinite(defaults.maxConcurrent);
|
|
211
237
|
const hasSubMax = typeof defaults?.subagents?.maxConcurrent === "number" &&
|
|
212
238
|
Number.isFinite(defaults.subagents.maxConcurrent);
|
|
213
|
-
if (hasMax && hasSubMax)
|
|
239
|
+
if (hasMax && hasSubMax) {
|
|
214
240
|
return cfg;
|
|
241
|
+
}
|
|
215
242
|
let mutated = false;
|
|
216
243
|
const nextDefaults = defaults ? { ...defaults } : {};
|
|
217
244
|
if (!hasMax) {
|
|
@@ -223,8 +250,9 @@ export function applyAgentDefaults(cfg) {
|
|
|
223
250
|
nextSubagents.maxConcurrent = DEFAULT_SUBAGENT_MAX_CONCURRENT;
|
|
224
251
|
mutated = true;
|
|
225
252
|
}
|
|
226
|
-
if (!mutated)
|
|
253
|
+
if (!mutated) {
|
|
227
254
|
return cfg;
|
|
255
|
+
}
|
|
228
256
|
return {
|
|
229
257
|
...cfg,
|
|
230
258
|
agents: {
|
|
@@ -238,10 +266,12 @@ export function applyAgentDefaults(cfg) {
|
|
|
238
266
|
}
|
|
239
267
|
export function applyLoggingDefaults(cfg) {
|
|
240
268
|
const logging = cfg.logging;
|
|
241
|
-
if (!logging)
|
|
269
|
+
if (!logging) {
|
|
242
270
|
return cfg;
|
|
243
|
-
|
|
271
|
+
}
|
|
272
|
+
if (logging.redactSensitive) {
|
|
244
273
|
return cfg;
|
|
274
|
+
}
|
|
245
275
|
return {
|
|
246
276
|
...cfg,
|
|
247
277
|
logging: {
|
|
@@ -252,11 +282,13 @@ export function applyLoggingDefaults(cfg) {
|
|
|
252
282
|
}
|
|
253
283
|
export function applyContextPruningDefaults(cfg) {
|
|
254
284
|
const defaults = cfg.agents?.defaults;
|
|
255
|
-
if (!defaults)
|
|
285
|
+
if (!defaults) {
|
|
256
286
|
return cfg;
|
|
287
|
+
}
|
|
257
288
|
const authMode = resolveAnthropicDefaultAuthMode(cfg);
|
|
258
|
-
if (!authMode)
|
|
289
|
+
if (!authMode) {
|
|
259
290
|
return cfg;
|
|
291
|
+
}
|
|
260
292
|
let mutated = false;
|
|
261
293
|
const nextDefaults = { ...defaults };
|
|
262
294
|
const contextPruning = defaults.contextPruning ?? {};
|
|
@@ -281,15 +313,17 @@ export function applyContextPruningDefaults(cfg) {
|
|
|
281
313
|
let modelsMutated = false;
|
|
282
314
|
for (const [key, entry] of Object.entries(nextModels)) {
|
|
283
315
|
const parsed = parseModelRef(key, "anthropic");
|
|
284
|
-
if (!parsed || parsed.provider !== "anthropic")
|
|
316
|
+
if (!parsed || parsed.provider !== "anthropic") {
|
|
285
317
|
continue;
|
|
318
|
+
}
|
|
286
319
|
const current = entry ?? {};
|
|
287
320
|
const params = current.params ?? {};
|
|
288
|
-
if (typeof params.
|
|
321
|
+
if (typeof params.cacheRetention === "string") {
|
|
289
322
|
continue;
|
|
323
|
+
}
|
|
290
324
|
nextModels[key] = {
|
|
291
325
|
...current,
|
|
292
|
-
params: { ...params,
|
|
326
|
+
params: { ...params, cacheRetention: "short" },
|
|
293
327
|
};
|
|
294
328
|
modelsMutated = true;
|
|
295
329
|
}
|
|
@@ -301,10 +335,10 @@ export function applyContextPruningDefaults(cfg) {
|
|
|
301
335
|
const entry = nextModels[key];
|
|
302
336
|
const current = entry ?? {};
|
|
303
337
|
const params = current.params ?? {};
|
|
304
|
-
if (typeof params.
|
|
338
|
+
if (typeof params.cacheRetention !== "string") {
|
|
305
339
|
nextModels[key] = {
|
|
306
340
|
...current,
|
|
307
|
-
params: { ...params,
|
|
341
|
+
params: { ...params, cacheRetention: "short" },
|
|
308
342
|
};
|
|
309
343
|
modelsMutated = true;
|
|
310
344
|
}
|
|
@@ -315,8 +349,9 @@ export function applyContextPruningDefaults(cfg) {
|
|
|
315
349
|
mutated = true;
|
|
316
350
|
}
|
|
317
351
|
}
|
|
318
|
-
if (!mutated)
|
|
352
|
+
if (!mutated) {
|
|
319
353
|
return cfg;
|
|
354
|
+
}
|
|
320
355
|
return {
|
|
321
356
|
...cfg,
|
|
322
357
|
agents: {
|
|
@@ -327,11 +362,13 @@ export function applyContextPruningDefaults(cfg) {
|
|
|
327
362
|
}
|
|
328
363
|
export function applyCompactionDefaults(cfg) {
|
|
329
364
|
const defaults = cfg.agents?.defaults;
|
|
330
|
-
if (!defaults)
|
|
365
|
+
if (!defaults) {
|
|
331
366
|
return cfg;
|
|
367
|
+
}
|
|
332
368
|
const compaction = defaults?.compaction;
|
|
333
|
-
if (compaction?.mode)
|
|
369
|
+
if (compaction?.mode) {
|
|
334
370
|
return cfg;
|
|
371
|
+
}
|
|
335
372
|
return {
|
|
336
373
|
...cfg,
|
|
337
374
|
agents: {
|
|
@@ -1,26 +1,49 @@
|
|
|
1
1
|
import { normalizeAccountId } from "../routing/session-key.js";
|
|
2
|
+
function resolveChannelGroupConfig(groups, groupId, caseInsensitive = false) {
|
|
3
|
+
if (!groups) {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
const direct = groups[groupId];
|
|
7
|
+
if (direct) {
|
|
8
|
+
return direct;
|
|
9
|
+
}
|
|
10
|
+
if (!caseInsensitive) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
const target = groupId.toLowerCase();
|
|
14
|
+
const matchedKey = Object.keys(groups).find((key) => key !== "*" && key.toLowerCase() === target);
|
|
15
|
+
if (!matchedKey) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
return groups[matchedKey];
|
|
19
|
+
}
|
|
2
20
|
function normalizeSenderKey(value) {
|
|
3
21
|
const trimmed = value.trim();
|
|
4
|
-
if (!trimmed)
|
|
22
|
+
if (!trimmed) {
|
|
5
23
|
return "";
|
|
24
|
+
}
|
|
6
25
|
const withoutAt = trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
|
|
7
26
|
return withoutAt.toLowerCase();
|
|
8
27
|
}
|
|
9
28
|
export function resolveToolsBySender(params) {
|
|
10
29
|
const toolsBySender = params.toolsBySender;
|
|
11
|
-
if (!toolsBySender)
|
|
30
|
+
if (!toolsBySender) {
|
|
12
31
|
return undefined;
|
|
32
|
+
}
|
|
13
33
|
const entries = Object.entries(toolsBySender);
|
|
14
|
-
if (entries.length === 0)
|
|
34
|
+
if (entries.length === 0) {
|
|
15
35
|
return undefined;
|
|
36
|
+
}
|
|
16
37
|
const normalized = new Map();
|
|
17
38
|
let wildcard;
|
|
18
39
|
for (const [rawKey, policy] of entries) {
|
|
19
|
-
if (!policy)
|
|
40
|
+
if (!policy) {
|
|
20
41
|
continue;
|
|
42
|
+
}
|
|
21
43
|
const key = normalizeSenderKey(rawKey);
|
|
22
|
-
if (!key)
|
|
44
|
+
if (!key) {
|
|
23
45
|
continue;
|
|
46
|
+
}
|
|
24
47
|
if (key === "*") {
|
|
25
48
|
wildcard = policy;
|
|
26
49
|
continue;
|
|
@@ -32,8 +55,9 @@ export function resolveToolsBySender(params) {
|
|
|
32
55
|
const candidates = [];
|
|
33
56
|
const pushCandidate = (value) => {
|
|
34
57
|
const trimmed = value?.trim();
|
|
35
|
-
if (!trimmed)
|
|
58
|
+
if (!trimmed) {
|
|
36
59
|
return;
|
|
60
|
+
}
|
|
37
61
|
candidates.push(trimmed);
|
|
38
62
|
};
|
|
39
63
|
pushCandidate(params.senderId);
|
|
@@ -42,19 +66,22 @@ export function resolveToolsBySender(params) {
|
|
|
42
66
|
pushCandidate(params.senderName);
|
|
43
67
|
for (const candidate of candidates) {
|
|
44
68
|
const key = normalizeSenderKey(candidate);
|
|
45
|
-
if (!key)
|
|
69
|
+
if (!key) {
|
|
46
70
|
continue;
|
|
71
|
+
}
|
|
47
72
|
const match = normalized.get(key);
|
|
48
|
-
if (match)
|
|
73
|
+
if (match) {
|
|
49
74
|
return match;
|
|
75
|
+
}
|
|
50
76
|
}
|
|
51
77
|
return wildcard;
|
|
52
78
|
}
|
|
53
79
|
function resolveChannelGroups(cfg, channel, accountId) {
|
|
54
80
|
const normalizedAccountId = normalizeAccountId(accountId);
|
|
55
81
|
const channelConfig = cfg.channels?.[channel];
|
|
56
|
-
if (!channelConfig)
|
|
82
|
+
if (!channelConfig) {
|
|
57
83
|
return undefined;
|
|
84
|
+
}
|
|
58
85
|
const accountGroups = channelConfig.accounts?.[normalizedAccountId]?.groups ??
|
|
59
86
|
channelConfig.accounts?.[Object.keys(channelConfig.accounts ?? {}).find((key) => key.toLowerCase() === normalizedAccountId.toLowerCase()) ?? ""]?.groups;
|
|
60
87
|
return accountGroups ?? channelConfig.groups;
|
|
@@ -64,12 +91,12 @@ export function resolveChannelGroupPolicy(params) {
|
|
|
64
91
|
const groups = resolveChannelGroups(cfg, channel, params.accountId);
|
|
65
92
|
const allowlistEnabled = Boolean(groups && Object.keys(groups).length > 0);
|
|
66
93
|
const normalizedId = params.groupId?.trim();
|
|
67
|
-
const groupConfig = normalizedId
|
|
94
|
+
const groupConfig = normalizedId
|
|
95
|
+
? resolveChannelGroupConfig(groups, normalizedId, params.groupIdCaseInsensitive)
|
|
96
|
+
: undefined;
|
|
68
97
|
const defaultConfig = groups?.["*"];
|
|
69
98
|
const allowAll = allowlistEnabled && Boolean(groups && Object.hasOwn(groups, "*"));
|
|
70
|
-
const allowed = !allowlistEnabled ||
|
|
71
|
-
allowAll ||
|
|
72
|
-
(normalizedId ? Boolean(groups && Object.hasOwn(groups, normalizedId)) : false);
|
|
99
|
+
const allowed = !allowlistEnabled || allowAll || Boolean(groupConfig);
|
|
73
100
|
return {
|
|
74
101
|
allowlistEnabled,
|
|
75
102
|
allowed,
|
|
@@ -88,8 +115,9 @@ export function resolveChannelGroupRequireMention(params) {
|
|
|
88
115
|
if (overrideOrder === "before-config" && typeof requireMentionOverride === "boolean") {
|
|
89
116
|
return requireMentionOverride;
|
|
90
117
|
}
|
|
91
|
-
if (typeof configMention === "boolean")
|
|
118
|
+
if (typeof configMention === "boolean") {
|
|
92
119
|
return configMention;
|
|
120
|
+
}
|
|
93
121
|
if (overrideOrder !== "before-config" && typeof requireMentionOverride === "boolean") {
|
|
94
122
|
return requireMentionOverride;
|
|
95
123
|
}
|
|
@@ -104,10 +132,12 @@ export function resolveChannelGroupToolsPolicy(params) {
|
|
|
104
132
|
senderUsername: params.senderUsername,
|
|
105
133
|
senderE164: params.senderE164,
|
|
106
134
|
});
|
|
107
|
-
if (groupSenderPolicy)
|
|
135
|
+
if (groupSenderPolicy) {
|
|
108
136
|
return groupSenderPolicy;
|
|
109
|
-
|
|
137
|
+
}
|
|
138
|
+
if (groupConfig?.tools) {
|
|
110
139
|
return groupConfig.tools;
|
|
140
|
+
}
|
|
111
141
|
const defaultSenderPolicy = resolveToolsBySender({
|
|
112
142
|
toolsBySender: defaultConfig?.toolsBySender,
|
|
113
143
|
senderId: params.senderId,
|
|
@@ -115,9 +145,11 @@ export function resolveChannelGroupToolsPolicy(params) {
|
|
|
115
145
|
senderUsername: params.senderUsername,
|
|
116
146
|
senderE164: params.senderE164,
|
|
117
147
|
});
|
|
118
|
-
if (defaultSenderPolicy)
|
|
148
|
+
if (defaultSenderPolicy) {
|
|
119
149
|
return defaultSenderPolicy;
|
|
120
|
-
|
|
150
|
+
}
|
|
151
|
+
if (defaultConfig?.tools) {
|
|
121
152
|
return defaultConfig.tools;
|
|
153
|
+
}
|
|
122
154
|
return undefined;
|
|
123
155
|
}
|
package/dist/config/includes.js
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
import fs from "node:fs";
|
|
13
13
|
import path from "node:path";
|
|
14
14
|
import JSON5 from "json5";
|
|
15
|
+
import { isPathInside } from "../security/scan-paths.js";
|
|
16
|
+
import { isPlainObject } from "../utils.js";
|
|
15
17
|
export const INCLUDE_KEY = "$include";
|
|
16
18
|
export const MAX_INCLUDE_DEPTH = 10;
|
|
17
19
|
// ============================================================================
|
|
@@ -38,12 +40,6 @@ export class CircularIncludeError extends ConfigIncludeError {
|
|
|
38
40
|
// ============================================================================
|
|
39
41
|
// Utilities
|
|
40
42
|
// ============================================================================
|
|
41
|
-
function isPlainObject(value) {
|
|
42
|
-
return (typeof value === "object" &&
|
|
43
|
-
value !== null &&
|
|
44
|
-
!Array.isArray(value) &&
|
|
45
|
-
Object.prototype.toString.call(value) === "[object Object]");
|
|
46
|
-
}
|
|
47
43
|
/** Deep merge: arrays concatenate, objects merge recursively, primitives: source wins */
|
|
48
44
|
export function deepMerge(target, source) {
|
|
49
45
|
if (Array.isArray(target) && Array.isArray(source)) {
|
|
@@ -66,10 +62,14 @@ class IncludeProcessor {
|
|
|
66
62
|
resolver;
|
|
67
63
|
visited = new Set();
|
|
68
64
|
depth = 0;
|
|
69
|
-
|
|
65
|
+
rootDir;
|
|
66
|
+
rootRealDir;
|
|
67
|
+
constructor(basePath, resolver, rootDir) {
|
|
70
68
|
this.basePath = basePath;
|
|
71
69
|
this.resolver = resolver;
|
|
72
70
|
this.visited.add(path.normalize(basePath));
|
|
71
|
+
this.rootDir = path.normalize(rootDir ?? path.dirname(basePath));
|
|
72
|
+
this.rootRealDir = path.normalize(safeRealpath(this.rootDir));
|
|
73
73
|
}
|
|
74
74
|
process(obj) {
|
|
75
75
|
if (Array.isArray(obj)) {
|
|
@@ -130,10 +130,29 @@ class IncludeProcessor {
|
|
|
130
130
|
return this.processNested(resolvedPath, parsed);
|
|
131
131
|
}
|
|
132
132
|
resolvePath(includePath) {
|
|
133
|
+
const configDir = path.dirname(this.basePath);
|
|
133
134
|
const resolved = path.isAbsolute(includePath)
|
|
134
135
|
? includePath
|
|
135
|
-
: path.resolve(
|
|
136
|
-
|
|
136
|
+
: path.resolve(configDir, includePath);
|
|
137
|
+
const normalized = path.normalize(resolved);
|
|
138
|
+
// SECURITY: Reject paths outside top-level config directory (CWE-22: Path Traversal)
|
|
139
|
+
if (!isPathInside(this.rootDir, normalized)) {
|
|
140
|
+
throw new ConfigIncludeError(`Include path escapes config directory: ${includePath} (root: ${this.rootDir})`, includePath);
|
|
141
|
+
}
|
|
142
|
+
// SECURITY: Resolve symlinks and re-validate to prevent symlink bypass
|
|
143
|
+
try {
|
|
144
|
+
const real = fs.realpathSync(normalized);
|
|
145
|
+
if (!isPathInside(this.rootRealDir, real)) {
|
|
146
|
+
throw new ConfigIncludeError(`Include path resolves outside config directory (symlink): ${includePath} (root: ${this.rootDir})`, includePath);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
if (err instanceof ConfigIncludeError) {
|
|
151
|
+
throw err;
|
|
152
|
+
}
|
|
153
|
+
// File doesn't exist yet - normalized path check above is sufficient
|
|
154
|
+
}
|
|
155
|
+
return normalized;
|
|
137
156
|
}
|
|
138
157
|
checkCircular(resolvedPath) {
|
|
139
158
|
if (this.visited.has(resolvedPath)) {
|
|
@@ -162,12 +181,20 @@ class IncludeProcessor {
|
|
|
162
181
|
}
|
|
163
182
|
}
|
|
164
183
|
processNested(resolvedPath, parsed) {
|
|
165
|
-
const nested = new IncludeProcessor(resolvedPath, this.resolver);
|
|
184
|
+
const nested = new IncludeProcessor(resolvedPath, this.resolver, this.rootDir);
|
|
166
185
|
nested.visited = new Set([...this.visited, resolvedPath]);
|
|
167
186
|
nested.depth = this.depth + 1;
|
|
168
187
|
return nested.process(parsed);
|
|
169
188
|
}
|
|
170
189
|
}
|
|
190
|
+
function safeRealpath(target) {
|
|
191
|
+
try {
|
|
192
|
+
return fs.realpathSync(target);
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return target;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
171
198
|
// ============================================================================
|
|
172
199
|
// Public API
|
|
173
200
|
// ============================================================================
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IRC_FIELD_HELP } from "./schema.irc.js";
|
|
2
2
|
export const FIELD_HELP = {
|
|
3
|
-
"meta.lastTouchedVersion": "Auto-set when
|
|
3
|
+
"meta.lastTouchedVersion": "Auto-set when Pool Bot writes the config.",
|
|
4
4
|
"meta.lastTouchedAt": "ISO timestamp of the last config write (auto-set).",
|
|
5
5
|
"update.channel": 'Update channel for git + npm installs ("stable", "beta", or "dev").',
|
|
6
6
|
"update.checkOnStart": "Check for npm updates when the gateway starts (default: true).",
|
|
@@ -16,7 +16,7 @@ export const FIELD_HELP = {
|
|
|
16
16
|
"discovery.mdns.mode": 'mDNS broadcast mode ("minimal" default, "full" includes cliPath/sshPort, "off" disables mDNS).',
|
|
17
17
|
"gateway.auth.token": "Required by default for gateway access (unless using Tailscale Serve identity); required for non-loopback binds.",
|
|
18
18
|
"gateway.auth.password": "Required for Tailscale funnel.",
|
|
19
|
-
"gateway.controlUi.basePath": "Optional URL prefix where the Control UI is served (e.g. /
|
|
19
|
+
"gateway.controlUi.basePath": "Optional URL prefix where the Control UI is served (e.g. /poolbot).",
|
|
20
20
|
"gateway.controlUi.root": "Optional filesystem root for Control UI assets (defaults to dist/control-ui).",
|
|
21
21
|
"gateway.controlUi.allowedOrigins": "Allowed browser origins for Control UI/WebChat websocket connections (full origins only, e.g. https://control.example.com).",
|
|
22
22
|
"gateway.controlUi.allowInsecureAuth": "Allow Control UI auth over insecure HTTP (token-only; not recommended).",
|
|
@@ -129,7 +129,7 @@ export const FIELD_HELP = {
|
|
|
129
129
|
"agents.defaults.memorySearch.query.hybrid.candidateMultiplier": "Multiplier for candidate pool size (default: 4).",
|
|
130
130
|
"agents.defaults.memorySearch.cache.enabled": "Cache chunk embeddings in SQLite to speed up reindexing and frequent updates (default: true).",
|
|
131
131
|
memory: "Memory backend configuration (global).",
|
|
132
|
-
"memory.backend": 'Memory backend ("builtin" for
|
|
132
|
+
"memory.backend": 'Memory backend ("builtin" for Pool Bot embeddings, "qmd" for QMD sidecar).',
|
|
133
133
|
"memory.citations": 'Default citation behavior ("auto", "on", or "off").',
|
|
134
134
|
"memory.qmd.command": "Path to the qmd binary (default: resolves from PATH).",
|
|
135
135
|
"memory.qmd.includeDefaultMemory": "Whether to automatically index MEMORY.md + memory/**/*.md (default: true).",
|
|
@@ -167,7 +167,7 @@ export const FIELD_HELP = {
|
|
|
167
167
|
"plugins.entries": "Per-plugin settings keyed by plugin id (enable/disable + config payloads).",
|
|
168
168
|
"plugins.entries.*.enabled": "Overrides plugin enable/disable for this entry (restart required).",
|
|
169
169
|
"plugins.entries.*.config": "Plugin-defined config payload (schema is provided by the plugin).",
|
|
170
|
-
"plugins.installs": "CLI-managed install metadata (used by `
|
|
170
|
+
"plugins.installs": "CLI-managed install metadata (used by `poolbot plugins update` to locate install sources).",
|
|
171
171
|
"plugins.installs.*.source": 'Install source ("npm", "archive", or "path").',
|
|
172
172
|
"plugins.installs.*.spec": "Original npm spec used for install (if source is npm).",
|
|
173
173
|
"plugins.installs.*.sourcePath": "Original archive/path used for install (if any).",
|
|
@@ -179,6 +179,7 @@ export const FIELD_HELP = {
|
|
|
179
179
|
"agents.defaults.model.fallbacks": "Ordered fallback models (provider/model). Used when the primary model fails.",
|
|
180
180
|
"agents.defaults.imageModel.primary": "Optional image model (provider/model) used when the primary model lacks image input.",
|
|
181
181
|
"agents.defaults.imageModel.fallbacks": "Ordered fallback image models (provider/model).",
|
|
182
|
+
"agents.defaults.imageMaxDimensionPx": "Max image side length in pixels when sanitizing transcript/tool-result image payloads (default: 1200).",
|
|
182
183
|
"agents.defaults.cliBackends": "Optional CLI backends for text-only fallback (claude-cli, etc.).",
|
|
183
184
|
"agents.defaults.humanDelay.mode": 'Delay style for block replies ("off", "natural", "custom").',
|
|
184
185
|
"agents.defaults.humanDelay.minMs": "Minimum delay in ms for custom humanDelay (default: 800).",
|
|
@@ -62,11 +62,11 @@ const FIELD_PLACEHOLDERS = {
|
|
|
62
62
|
"gateway.remote.url": "ws://host:18789",
|
|
63
63
|
"gateway.remote.tlsFingerprint": "sha256:ab12cd34…",
|
|
64
64
|
"gateway.remote.sshTarget": "user@host",
|
|
65
|
-
"gateway.controlUi.basePath": "/
|
|
65
|
+
"gateway.controlUi.basePath": "/poolbot",
|
|
66
66
|
"gateway.controlUi.root": "dist/control-ui",
|
|
67
67
|
"gateway.controlUi.allowedOrigins": "https://control.example.com",
|
|
68
68
|
"channels.mattermost.baseUrl": "https://chat.example.com",
|
|
69
|
-
"agents.list[].identity.avatar": "avatars/
|
|
69
|
+
"agents.list[].identity.avatar": "avatars/poolbot.png",
|
|
70
70
|
};
|
|
71
71
|
/**
|
|
72
72
|
* Non-sensitive field names that happen to match sensitive patterns.
|
|
@@ -201,6 +201,7 @@ export const FIELD_LABELS = {
|
|
|
201
201
|
"agents.defaults.model.fallbacks": "Model Fallbacks",
|
|
202
202
|
"agents.defaults.imageModel.primary": "Image Model",
|
|
203
203
|
"agents.defaults.imageModel.fallbacks": "Image Model Fallbacks",
|
|
204
|
+
"agents.defaults.imageMaxDimensionPx": "Image Max Dimension (px)",
|
|
204
205
|
"agents.defaults.humanDelay.mode": "Human Delay Mode",
|
|
205
206
|
"agents.defaults.humanDelay.minMs": "Human Delay Min (ms)",
|
|
206
207
|
"agents.defaults.humanDelay.maxMs": "Human Delay Max (ms)",
|
|
@@ -1,19 +1,17 @@
|
|
|
1
|
+
import { normalizeHyphenSlug } from "../../shared/string-normalization.js";
|
|
1
2
|
import { listDeliverableMessageChannels } from "../../utils/message-channel.js";
|
|
2
3
|
const getGroupSurfaces = () => new Set([...listDeliverableMessageChannels(), "webchat"]);
|
|
3
4
|
function normalizeGroupLabel(raw) {
|
|
4
|
-
|
|
5
|
-
if (!trimmed)
|
|
6
|
-
return "";
|
|
7
|
-
const dashed = trimmed.replace(/\s+/g, "-");
|
|
8
|
-
const cleaned = dashed.replace(/[^a-z0-9#@._+-]+/g, "-");
|
|
9
|
-
return cleaned.replace(/-{2,}/g, "-").replace(/^[-.]+|[-.]+$/g, "");
|
|
5
|
+
return normalizeHyphenSlug(raw);
|
|
10
6
|
}
|
|
11
7
|
function shortenGroupId(value) {
|
|
12
8
|
const trimmed = value?.trim() ?? "";
|
|
13
|
-
if (!trimmed)
|
|
9
|
+
if (!trimmed) {
|
|
14
10
|
return "";
|
|
15
|
-
|
|
11
|
+
}
|
|
12
|
+
if (trimmed.length <= 14) {
|
|
16
13
|
return trimmed;
|
|
14
|
+
}
|
|
17
15
|
return `${trimmed.slice(0, 6)}...${trimmed.slice(-4)}`;
|
|
18
16
|
}
|
|
19
17
|
export function buildGroupDisplayName(params) {
|
|
@@ -48,8 +46,9 @@ export function resolveGroupSessionKey(ctx) {
|
|
|
48
46
|
from.includes(":group:") ||
|
|
49
47
|
from.includes(":channel:") ||
|
|
50
48
|
isWhatsAppGroupId;
|
|
51
|
-
if (!looksLikeGroup)
|
|
49
|
+
if (!looksLikeGroup) {
|
|
52
50
|
return null;
|
|
51
|
+
}
|
|
53
52
|
const providerHint = ctx.Provider?.trim().toLowerCase();
|
|
54
53
|
const parts = from.split(":").filter(Boolean);
|
|
55
54
|
const head = parts[0]?.trim().toLowerCase() ?? "";
|
|
@@ -57,8 +56,9 @@ export function resolveGroupSessionKey(ctx) {
|
|
|
57
56
|
const provider = headIsSurface
|
|
58
57
|
? head
|
|
59
58
|
: (providerHint ?? (isWhatsAppGroupId ? "whatsapp" : undefined));
|
|
60
|
-
if (!provider)
|
|
59
|
+
if (!provider) {
|
|
61
60
|
return null;
|
|
61
|
+
}
|
|
62
62
|
const second = parts[1]?.trim().toLowerCase();
|
|
63
63
|
const secondIsKind = second === "group" || second === "channel";
|
|
64
64
|
const kind = secondIsKind
|
|
@@ -72,8 +72,9 @@ export function resolveGroupSessionKey(ctx) {
|
|
|
72
72
|
: parts.slice(1).join(":")
|
|
73
73
|
: from;
|
|
74
74
|
const finalId = id.trim().toLowerCase();
|
|
75
|
-
if (!finalId)
|
|
75
|
+
if (!finalId) {
|
|
76
76
|
return null;
|
|
77
|
+
}
|
|
77
78
|
return {
|
|
78
79
|
key: `${provider}:${kind}:${finalId}`,
|
|
79
80
|
channel: provider,
|