@poolzin/pool-bot 2026.2.24 → 2026.2.26
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 +21 -0
- package/dist/acp/client.js +207 -18
- package/dist/acp/event-mapper.js +87 -22
- package/dist/acp/meta.js +12 -6
- package/dist/acp/secret-file.js +22 -0
- package/dist/agents/agent-paths.js +8 -9
- package/dist/agents/agent-scope.js +17 -5
- package/dist/agents/auth-profiles/oauth.js +148 -64
- package/dist/agents/auth-profiles/session-override.js +13 -7
- package/dist/agents/bash-process-registry.test-helpers.js +29 -0
- package/dist/agents/bash-tools.exec-approval-request.js +20 -0
- package/dist/agents/bash-tools.exec-host-gateway.js +240 -0
- package/dist/agents/bash-tools.exec-host-node.js +235 -0
- package/dist/agents/bash-tools.exec-runtime.js +2 -25
- package/dist/agents/bash-tools.exec-types.js +1 -0
- package/dist/agents/bash-tools.process.js +224 -218
- package/dist/agents/bedrock-discovery.js +3 -1
- package/dist/agents/byteplus-models.js +97 -0
- package/dist/agents/chutes-oauth.js +1 -0
- package/dist/agents/cli-runner/helpers.js +4 -0
- package/dist/agents/compaction.js +41 -14
- package/dist/agents/content-blocks.js +16 -0
- package/dist/agents/doubao-models.js +121 -0
- package/dist/agents/failover-error.js +2 -0
- package/dist/agents/huggingface-models.js +5 -3
- package/dist/agents/live-model-filter.js +5 -0
- package/dist/agents/minimax-vlm.js +10 -8
- package/dist/agents/model-auth.js +6 -0
- package/dist/agents/model-catalog.js +3 -1
- package/dist/agents/model-fallback.js +96 -101
- package/dist/agents/model-selection.js +7 -1
- package/dist/agents/models-config.providers.js +364 -165
- package/dist/agents/ollama-stream.js +117 -4
- package/dist/agents/opencode-zen-models.js +22 -11
- package/dist/agents/pi-embedded-helpers/errors.js +55 -33
- package/dist/agents/pi-embedded-helpers/messaging-dedupe.js +10 -5
- package/dist/agents/pi-embedded-helpers/thinking.js +10 -5
- package/dist/agents/pi-embedded-helpers.js +1 -1
- package/dist/agents/pi-embedded-payloads.js +1 -0
- package/dist/agents/pi-embedded-runner/compact.js +29 -7
- package/dist/agents/pi-embedded-runner/extensions.js +28 -26
- package/dist/agents/pi-embedded-runner/google.js +20 -8
- package/dist/agents/pi-embedded-runner/run/attempt.js +95 -36
- package/dist/agents/pi-embedded-runner/run.js +71 -12
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +34 -0
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +11 -2
- package/dist/agents/pi-embedded-runner/session-manager-cache.js +11 -7
- package/dist/agents/pi-embedded-runner/system-prompt.js +2 -0
- package/dist/agents/pi-embedded-runner/thinking.js +42 -0
- package/dist/agents/pi-embedded-runner/tool-name-allowlist.js +19 -0
- package/dist/agents/pi-embedded-runner/utils.js +7 -10
- package/dist/agents/pi-embedded-subscribe.handlers.lifecycle.js +45 -56
- package/dist/agents/pi-embedded-subscribe.handlers.tools.js +2 -2
- package/dist/agents/pi-embedded-subscribe.js +9 -4
- package/dist/agents/pi-embedded-subscribe.tools.js +68 -14
- package/dist/agents/pi-embedded-utils.js +3 -0
- package/dist/agents/pi-extensions/compaction-safeguard-runtime.js +4 -20
- package/dist/agents/pi-extensions/compaction-safeguard.js +75 -33
- package/dist/agents/pi-settings.js +40 -0
- package/dist/agents/pi-tools.policy.js +2 -1
- package/dist/agents/provider/config-loader.js +1 -1
- package/dist/agents/sandbox/browser.js +170 -33
- package/dist/agents/sandbox/config-hash.js +14 -27
- package/dist/agents/sandbox/config.js +21 -2
- package/dist/agents/sandbox/constants.js +2 -0
- package/dist/agents/sandbox/docker.js +16 -2
- package/dist/agents/sandbox/novnc-auth.js +62 -0
- package/dist/agents/sandbox/sanitize-env-vars.js +1 -1
- package/dist/agents/sandbox/shared.js +10 -6
- package/dist/agents/sandbox-paths.js +24 -11
- package/dist/agents/schema/clean-for-gemini.js +132 -85
- package/dist/agents/session-slug.js +10 -5
- package/dist/agents/session-tool-result-guard-wrapper.js +1 -0
- package/dist/agents/session-tool-result-guard.js +3 -1
- package/dist/agents/session-transcript-repair.js +40 -6
- package/dist/agents/skills/bundled-dir.js +19 -5
- package/dist/agents/skills/env-overrides.js +124 -43
- package/dist/agents/skills/frontmatter.js +6 -6
- package/dist/agents/skills/plugin-skills.js +14 -7
- package/dist/agents/skills/workspace.js +1 -0
- package/dist/agents/skills.test-helpers.js +13 -0
- package/dist/agents/stable-stringify.js +12 -0
- package/dist/agents/subagent-announce.js +251 -49
- package/dist/agents/subagent-lifecycle-events.js +19 -0
- package/dist/agents/subagent-registry-cleanup.js +31 -0
- package/dist/agents/subagent-registry-completion.js +68 -0
- package/dist/agents/subagent-registry-queries.js +117 -0
- package/dist/agents/subagent-registry-state.js +46 -0
- package/dist/agents/subagent-registry.js +252 -221
- package/dist/agents/subagent-registry.mocks.shared.js +12 -0
- package/dist/agents/subagent-registry.store.js +1 -0
- package/dist/agents/subagent-registry.types.js +1 -0
- package/dist/agents/subagent-spawn.js +195 -7
- package/dist/agents/system-prompt.js +22 -6
- package/dist/agents/test-helpers/assistant-message-fixtures.js +29 -0
- package/dist/agents/test-helpers/fast-coding-tools.js +1 -18
- package/dist/agents/test-helpers/fast-core-tools.js +1 -17
- package/dist/agents/test-helpers/pi-tools-sandbox-context.js +27 -0
- package/dist/agents/timeout.js +18 -6
- package/dist/agents/tool-call-id.js +1 -1
- package/dist/agents/tool-display-common.js +162 -29
- package/dist/agents/tool-images.js +82 -9
- package/dist/agents/tool-policy-shared.js +108 -0
- package/dist/agents/tool-policy.js +51 -26
- package/dist/agents/tools/browser-tool.js +160 -54
- package/dist/agents/tools/canvas-tool.js +27 -1
- package/dist/agents/tools/common.js +45 -0
- package/dist/agents/tools/cron-tool.test-helpers.js +12 -0
- package/dist/agents/tools/discord-actions-guild.js +4 -1
- package/dist/agents/tools/discord-actions-moderation-shared.js +27 -0
- package/dist/agents/tools/gateway-tool.js +3 -1
- package/dist/agents/tools/image-tool.js +214 -99
- package/dist/agents/tools/nodes-utils.js +1 -10
- package/dist/agents/tools/sessions-history-tool.js +140 -108
- package/dist/agents/tools/sessions-send-helpers.js +12 -6
- package/dist/agents/tools/sessions-spawn-tool.js +8 -2
- package/dist/agents/tools/subagents-tool.js +2 -1
- package/dist/agents/tools/whatsapp-actions.js +10 -2
- package/dist/agents/tools/whatsapp-target-auth.js +18 -0
- package/dist/agents/transcript-policy.js +22 -8
- package/dist/agents/venice-models.js +11 -3
- package/dist/agents/workspace.js +222 -46
- package/dist/auto-reply/commands-registry.data.js +51 -0
- package/dist/auto-reply/commands-registry.js +19 -21
- package/dist/auto-reply/fallback-state.js +114 -0
- package/dist/auto-reply/group-activation.js +10 -5
- package/dist/auto-reply/inbound-debounce.js +10 -5
- package/dist/auto-reply/model-runtime.js +68 -0
- package/dist/auto-reply/reply/abort.js +1 -1
- package/dist/auto-reply/reply/agent-runner-execution.js +40 -5
- package/dist/auto-reply/reply/agent-runner.js +165 -39
- package/dist/auto-reply/reply/bash-command.js +41 -39
- package/dist/auto-reply/reply/command-gates.js +25 -0
- package/dist/auto-reply/reply/commands-allowlist.js +111 -72
- package/dist/auto-reply/reply/commands-bash.js +6 -5
- package/dist/auto-reply/reply/commands-config.js +30 -28
- package/dist/auto-reply/reply/commands-core.js +2 -1
- package/dist/auto-reply/reply/commands-info.js +1 -0
- package/dist/auto-reply/reply/commands-models.js +65 -14
- package/dist/auto-reply/reply/commands-session.js +237 -82
- package/dist/auto-reply/reply/commands-setunset-standard.js +13 -0
- package/dist/auto-reply/reply/commands-setunset.js +45 -0
- package/dist/auto-reply/reply/commands-subagents/action-agents.js +44 -0
- package/dist/auto-reply/reply/commands-subagents/action-focus.js +64 -0
- package/dist/auto-reply/reply/commands-subagents/action-help.js +4 -0
- package/dist/auto-reply/reply/commands-subagents/action-info.js +45 -0
- package/dist/auto-reply/reply/commands-subagents/action-kill.js +60 -0
- package/dist/auto-reply/reply/commands-subagents/action-list.js +44 -0
- package/dist/auto-reply/reply/commands-subagents/action-log.js +29 -0
- package/dist/auto-reply/reply/commands-subagents/action-send.js +119 -0
- package/dist/auto-reply/reply/commands-subagents/action-spawn.js +52 -0
- package/dist/auto-reply/reply/commands-subagents/action-unfocus.js +30 -0
- package/dist/auto-reply/reply/commands-subagents/shared.js +303 -0
- package/dist/auto-reply/reply/commands-subagents.js +51 -587
- package/dist/auto-reply/reply/commands-tts.js +10 -5
- package/dist/auto-reply/reply/config-value.js +10 -5
- package/dist/auto-reply/reply/directive-handling.model-picker.js +12 -6
- package/dist/auto-reply/reply/directive-handling.persist.js +9 -21
- package/dist/auto-reply/reply/directive-handling.shared.js +24 -4
- package/dist/auto-reply/reply/followup-runner.js +1 -0
- package/dist/auto-reply/reply/get-reply-directives-utils.js +23 -14
- package/dist/auto-reply/reply/get-reply-directives.js +17 -28
- package/dist/auto-reply/reply/get-reply-inline-actions.js +1 -0
- package/dist/auto-reply/reply/get-reply.js +71 -12
- package/dist/auto-reply/reply/model-selection.js +80 -39
- package/dist/auto-reply/reply/queue/enqueue.js +10 -5
- package/dist/auto-reply/reply/queue/state.js +13 -12
- package/dist/auto-reply/reply/reply-payloads.js +67 -36
- package/dist/auto-reply/reply/reply-reference.js +9 -8
- package/dist/auto-reply/reply/route-reply.js +15 -8
- package/dist/auto-reply/reply/session-reset-prompt.js +1 -1
- package/dist/auto-reply/reply/session.js +22 -6
- package/dist/auto-reply/reply/strip-inbound-meta.js +147 -0
- package/dist/auto-reply/reply/subagents-utils.js +56 -30
- package/dist/auto-reply/reply/typing.js +46 -21
- package/dist/auto-reply/send-policy.js +14 -7
- package/dist/auto-reply/status.js +140 -16
- package/dist/auto-reply/templating.js +10 -5
- package/dist/auto-reply/thinking.js +7 -16
- package/dist/auto-reply/tokens.js +21 -5
- package/dist/browser/bridge-server.js +36 -20
- package/dist/browser/cdp.helpers.js +7 -14
- package/dist/browser/cdp.js +35 -15
- package/dist/browser/chrome.profile-decoration.js +7 -4
- package/dist/browser/config.js +30 -0
- package/dist/browser/extension-relay-auth.js +55 -0
- package/dist/browser/extension-relay.js +74 -29
- package/dist/browser/navigation-guard.js +39 -0
- package/dist/browser/paths.js +77 -0
- package/dist/browser/profiles.js +13 -8
- package/dist/browser/pw-ai-module.js +10 -5
- package/dist/browser/pw-session.js +76 -39
- package/dist/browser/pw-tools-core.interactions.js +14 -7
- package/dist/browser/pw-tools-core.state.js +12 -6
- package/dist/browser/routes/agent.act.js +431 -424
- package/dist/browser/routes/agent.shared.js +47 -3
- package/dist/browser/routes/agent.snapshot.js +122 -116
- package/dist/browser/routes/agent.storage.js +303 -297
- package/dist/browser/routes/tabs.js +154 -100
- package/dist/browser/server-context.js +7 -0
- package/dist/browser/server-lifecycle.js +37 -0
- package/dist/build-info.json +3 -3
- package/dist/channels/allow-from.js +26 -0
- package/dist/channels/allowlists/resolve-utils.js +43 -19
- package/dist/channels/channel-config.js +14 -7
- package/dist/channels/draft-stream-loop.js +7 -0
- package/dist/channels/model-overrides.js +82 -0
- package/dist/channels/plugins/account-action-gate.js +13 -0
- package/dist/channels/plugins/message-actions.js +10 -0
- package/dist/channels/plugins/normalize/imessage.js +14 -7
- package/dist/channels/plugins/normalize/slack.js +10 -5
- package/dist/channels/plugins/normalize/telegram.js +14 -7
- package/dist/channels/plugins/outbound/discord.js +80 -8
- package/dist/channels/plugins/outbound/signal.js +11 -11
- package/dist/channels/plugins/setup-helpers.js +10 -5
- package/dist/channels/sender-label.js +14 -7
- package/dist/channels/session.js +4 -2
- package/dist/channels/status-reactions.js +297 -0
- package/dist/channels/telegram/api.js +18 -0
- package/dist/cli/argv.js +84 -21
- package/dist/cli/banner.js +3 -2
- package/dist/cli/browser-cli-actions-input/register.files-downloads.js +65 -56
- package/dist/cli/cli-name.js +11 -11
- package/dist/cli/cli-utils.js +13 -3
- package/dist/cli/command-format.js +1 -1
- package/dist/cli/config-cli.js +1 -1
- package/dist/cli/daemon-cli/lifecycle-core.js +31 -19
- package/dist/cli/daemon-cli/lifecycle.js +64 -2
- package/dist/cli/daemon-cli/restart-health.js +126 -0
- package/dist/cli/daemon-cli/status.gather.js +9 -13
- package/dist/cli/daemon-cli/status.print.js +2 -10
- package/dist/cli/deps.js +27 -22
- package/dist/cli/exec-approvals-cli.js +92 -124
- package/dist/cli/gateway-cli/run-loop.js +23 -5
- package/dist/cli/memory-cli.js +158 -61
- package/dist/cli/node-cli/register.js +14 -5
- package/dist/cli/nodes-cli/register.push.js +63 -0
- package/dist/cli/nodes-media-utils.js +26 -0
- package/dist/cli/outbound-send-deps.js +2 -9
- package/dist/cli/outbound-send-mapping.js +11 -0
- package/dist/cli/pairing-cli.js +40 -14
- package/dist/cli/plugins-cli.js +250 -73
- package/dist/cli/ports.js +11 -10
- package/dist/cli/program/build-program.js +3 -1
- package/dist/cli/program/command-registry.js +214 -136
- package/dist/cli/program/command-tree.js +16 -0
- package/dist/cli/program/help.js +43 -12
- package/dist/cli/program/preaction.js +13 -9
- package/dist/cli/program/register.configure.js +3 -18
- package/dist/cli/program/register.maintenance.js +2 -2
- package/dist/cli/program/register.onboard.js +2 -0
- package/dist/cli/program/register.status-health-sessions.js +16 -17
- package/dist/cli/program/register.subclis.js +93 -52
- package/dist/cli/route.js +12 -8
- package/dist/cli/system-cli.js +36 -46
- package/dist/cli/test-runtime-capture.js +24 -0
- package/dist/cli/update-cli/shared.js +22 -9
- package/dist/cli/update-cli/update-command.js +89 -14
- package/dist/cli/update-cli/wizard.js +6 -12
- package/dist/commands/agent/run-context.js +18 -5
- package/dist/commands/agent/session-store.js +17 -4
- package/dist/commands/agent.js +185 -89
- package/dist/commands/agents.bindings.js +14 -7
- package/dist/commands/agents.commands.add.js +13 -9
- package/dist/commands/agents.commands.identity.js +12 -6
- package/dist/commands/agents.commands.list.js +11 -6
- package/dist/commands/agents.config.js +8 -10
- package/dist/commands/agents.providers.js +12 -6
- package/dist/commands/auth-choice-options.js +103 -75
- package/dist/commands/auth-choice.apply.byteplus.js +55 -0
- package/dist/commands/auth-choice.apply.js +4 -0
- package/dist/commands/auth-choice.apply.minimax.js +61 -13
- package/dist/commands/auth-choice.apply.openai.js +3 -1
- package/dist/commands/auth-choice.apply.volcengine.js +55 -0
- package/dist/commands/auth-choice.preferred-provider.js +2 -0
- package/dist/commands/channels/remove.js +13 -6
- package/dist/commands/channels/shared.js +4 -14
- package/dist/commands/channels.mock-harness.js +23 -0
- package/dist/commands/configure.commands.js +14 -0
- package/dist/commands/configure.gateway.js +2 -4
- package/dist/commands/configure.js +1 -1
- package/dist/commands/configure.shared.js +11 -0
- package/dist/commands/daemon-install-helpers.js +2 -2
- package/dist/commands/daemon-install-runtime-warning.js +11 -0
- package/dist/commands/dashboard.js +12 -10
- package/dist/commands/docs.js +14 -8
- package/dist/commands/doctor-config-flow.js +11 -9
- package/dist/commands/doctor-legacy-config.js +281 -0
- package/dist/commands/doctor-state-integrity.js +99 -23
- package/dist/commands/doctor-update.js +12 -9
- package/dist/commands/models/list.list-command.js +7 -5
- package/dist/commands/models/set-image.js +2 -21
- package/dist/commands/node-daemon-install-helpers.js +10 -8
- package/dist/commands/onboard-auth.config-minimax.js +54 -80
- package/dist/commands/onboard-auth.config-opencode.js +2 -18
- package/dist/commands/onboard-auth.credentials.js +90 -13
- package/dist/commands/onboard-auth.js +1 -1
- package/dist/commands/onboard-auth.models.js +6 -5
- package/dist/commands/onboard-hooks.js +1 -1
- package/dist/commands/onboard-non-interactive/api-keys.js +14 -7
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +64 -49
- package/dist/commands/onboard-provider-auth-flags.js +14 -0
- package/dist/commands/onboard-remote.js +14 -7
- package/dist/commands/onboard.js +11 -13
- package/dist/commands/sandbox-display.js +6 -5
- package/dist/commands/sessions.test-helpers.js +61 -0
- package/dist/commands/status-all/diagnosis.js +14 -10
- package/dist/commands/status-all/format.js +1 -0
- package/dist/commands/status.gateway-probe.js +1 -16
- package/dist/commands/systemd-linger.js +12 -6
- package/dist/config/agent-limits.js +2 -0
- package/dist/config/commands.js +32 -15
- package/dist/config/config-paths.js +9 -11
- package/dist/config/config.js +1 -1
- package/dist/config/defaults.js +22 -2
- package/dist/config/discord-preview-streaming.js +104 -0
- package/dist/config/env-substitution.js +62 -34
- package/dist/config/env-vars.js +45 -7
- package/dist/config/includes.js +4 -0
- package/dist/config/io.js +656 -171
- package/dist/config/legacy.migrations.part-1.js +189 -78
- package/dist/config/legacy.shared.js +3 -1
- package/dist/config/merge-patch.js +54 -4
- package/dist/config/prototype-keys.js +4 -0
- package/dist/config/redact-snapshot.js +404 -76
- package/dist/config/schema.help.js +44 -7
- package/dist/config/schema.js +58 -570
- package/dist/config/schema.labels.js +38 -6
- package/dist/config/sessions/delivery-info.js +10 -3
- package/dist/config/sessions/main-session.js +10 -5
- package/dist/config/sessions/session-file.js +33 -0
- package/dist/config/sessions/session-key.js +10 -5
- package/dist/config/sessions/store.js +1 -1
- package/dist/config/sessions.js +1 -0
- package/dist/config/validation.js +140 -85
- package/dist/config/zod-schema.agent-runtime.js +11 -0
- package/dist/config/zod-schema.hooks.js +40 -11
- package/dist/config/zod-schema.installs.js +20 -0
- package/dist/config/zod-schema.js +156 -20
- package/dist/config/zod-schema.providers-core.js +78 -4
- package/dist/config/zod-schema.providers.js +6 -1
- package/dist/config/zod-schema.session.js +41 -2
- package/dist/cron/run-log.js +3 -0
- package/dist/cron/schedule.js +21 -10
- package/dist/cron/service/ops.js +35 -21
- package/dist/cron/service/timer.js +116 -16
- package/dist/cron/stagger.js +3 -1
- package/dist/daemon/cmd-argv.js +21 -0
- package/dist/daemon/cmd-set.js +58 -0
- package/dist/daemon/service-types.js +1 -0
- package/dist/discord/api.js +12 -6
- package/dist/discord/draft-chunking.js +22 -0
- package/dist/discord/draft-stream.js +124 -0
- package/dist/discord/monitor/agent-components.js +1 -1
- package/dist/discord/monitor/commands.js +5 -0
- package/dist/discord/monitor/exec-approvals.js +357 -162
- package/dist/discord/monitor/gateway-plugin.js +2 -1
- package/dist/discord/monitor/listeners.js +37 -27
- package/dist/discord/monitor/message-handler.js +4 -1
- package/dist/discord/monitor/message-handler.preflight.js +65 -8
- package/dist/discord/monitor/message-handler.process.js +246 -217
- package/dist/discord/monitor/message-utils.js +143 -6
- package/dist/discord/monitor/model-picker-preferences.js +143 -0
- package/dist/discord/monitor/model-picker.js +651 -0
- package/dist/discord/monitor/native-command.js +573 -16
- package/dist/discord/monitor/provider.allowlist.js +223 -0
- package/dist/discord/monitor/provider.js +275 -347
- package/dist/discord/monitor/provider.lifecycle.js +100 -0
- package/dist/discord/monitor/reply-delivery.js +123 -16
- package/dist/discord/monitor/thread-bindings.discord-api.js +215 -0
- package/dist/discord/monitor/thread-bindings.js +4 -0
- package/dist/discord/monitor/thread-bindings.lifecycle.js +177 -0
- package/dist/discord/monitor/thread-bindings.manager.js +423 -0
- package/dist/discord/monitor/thread-bindings.messages.js +55 -0
- package/dist/discord/monitor/thread-bindings.state.js +358 -0
- package/dist/discord/monitor/thread-bindings.types.js +6 -0
- package/dist/discord/resolve-users.js +33 -21
- package/dist/discord/send.channels.js +15 -0
- package/dist/discord/send.js +3 -2
- package/dist/discord/send.outbound.js +82 -26
- package/dist/discord/send.permissions.js +83 -30
- package/dist/discord/send.reactions.js +8 -4
- package/dist/discord/token.js +10 -5
- package/dist/discord/voice/command.js +263 -0
- package/dist/discord/voice/manager.js +531 -0
- package/dist/gateway/auth.js +72 -13
- package/dist/gateway/call.js +152 -83
- package/dist/gateway/canvas-capability.js +75 -0
- package/dist/gateway/client.js +28 -4
- package/dist/gateway/config-reload.js +3 -4
- package/dist/gateway/control-plane-audit.js +28 -0
- package/dist/gateway/control-plane-rate-limit.js +53 -0
- package/dist/gateway/control-ui.js +219 -96
- package/dist/gateway/events.js +1 -0
- package/dist/gateway/hooks-mapping.js +88 -38
- package/dist/gateway/hooks.js +109 -54
- package/dist/gateway/http-auth-helpers.js +3 -2
- package/dist/gateway/http-common.js +22 -0
- package/dist/gateway/http-endpoint-helpers.js +1 -0
- package/dist/gateway/method-scopes.js +169 -0
- package/dist/gateway/net.js +74 -9
- package/dist/gateway/node-invoke-system-run-approval.js +14 -35
- package/dist/gateway/node-registry.js +10 -5
- package/dist/gateway/openai-http.js +1 -0
- package/dist/gateway/openresponses-http.js +121 -110
- package/dist/gateway/origin-check.js +1 -18
- package/dist/gateway/probe-auth.js +2 -0
- package/dist/gateway/protocol/index.js +4 -2
- package/dist/gateway/protocol/schema/cron.js +1 -0
- package/dist/gateway/protocol/schema/devices.js +1 -0
- package/dist/gateway/protocol/schema/protocol-schemas.js +4 -1
- package/dist/gateway/protocol/schema/push.js +18 -0
- package/dist/gateway/protocol/schema/sessions.js +6 -0
- package/dist/gateway/protocol/schema.js +1 -0
- package/dist/gateway/role-policy.js +17 -0
- package/dist/gateway/server/ws-connection/connect-policy.js +37 -0
- package/dist/gateway/server/ws-connection/message-handler.js +175 -148
- package/dist/gateway/server-chat.js +83 -25
- package/dist/gateway/server-constants.js +10 -9
- package/dist/gateway/server-cron.js +1 -0
- package/dist/gateway/server-http.js +247 -54
- package/dist/gateway/server-maintenance.js +20 -5
- package/dist/gateway/server-methods/agent.js +162 -24
- package/dist/gateway/server-methods/chat.js +465 -130
- package/dist/gateway/server-methods/config.js +193 -152
- package/dist/gateway/server-methods/devices.js +17 -3
- package/dist/gateway/server-methods/models.js +11 -1
- package/dist/gateway/server-methods/nodes.helpers.js +12 -0
- package/dist/gateway/server-methods/nodes.js +251 -69
- package/dist/gateway/server-methods/push.js +53 -0
- package/dist/gateway/server-methods/sessions.js +64 -8
- package/dist/gateway/server-methods/usage.js +162 -75
- package/dist/gateway/server-node-events.js +29 -0
- package/dist/gateway/server-reload-handlers.js +2 -3
- package/dist/gateway/server-runtime-config.js +39 -13
- package/dist/gateway/server-runtime-state.js +2 -0
- package/dist/gateway/server-startup-memory.js +17 -11
- package/dist/gateway/server-ws-runtime.js +1 -0
- package/dist/gateway/server.impl.js +296 -139
- package/dist/gateway/session-preview.test-helpers.js +11 -0
- package/dist/gateway/session-utils.fs.js +32 -34
- package/dist/gateway/sessions-resolve.js +17 -5
- package/dist/gateway/startup-auth.js +126 -0
- package/dist/gateway/test-helpers.agent-results.js +15 -0
- package/dist/gateway/test-helpers.mocks.js +37 -14
- package/dist/gateway/test-helpers.openai-mock.js +14 -7
- package/dist/gateway/test-helpers.server.js +161 -77
- package/dist/gateway/tools-invoke-http.js +21 -10
- package/dist/hooks/bundled/bootstrap-extra-files/handler.js +3 -1
- package/dist/hooks/bundled/command-logger/handler.js +7 -2
- package/dist/hooks/bundled/session-memory/handler.js +170 -38
- package/dist/hooks/frontmatter.js +6 -6
- package/dist/hooks/gmail-watcher-lifecycle.js +23 -0
- package/dist/hooks/gmail-watcher.js +11 -6
- package/dist/hooks/internal-hooks.js +11 -1
- package/dist/hooks/llm-slug-generator.js +4 -1
- package/dist/hooks/workspace.js +47 -17
- package/dist/imessage/accounts.js +9 -20
- package/dist/imessage/monitor/inbound-processing.js +2 -1
- package/dist/infra/archive-path.js +49 -0
- package/dist/infra/archive.js +174 -73
- package/dist/infra/control-ui-assets.js +14 -6
- package/dist/infra/device-pairing.js +204 -144
- package/dist/infra/env.js +10 -5
- package/dist/infra/exec-approvals-allowlist.js +141 -70
- package/dist/infra/exec-approvals-analysis.js +78 -20
- package/dist/infra/exec-approvals.js +5 -17
- package/dist/infra/exec-safe-bin-policy.js +277 -0
- package/dist/infra/fixed-window-rate-limit.js +33 -0
- package/dist/infra/fs-safe.js +71 -39
- package/dist/infra/gateway-lock.js +6 -2
- package/dist/infra/git-root.js +61 -0
- package/dist/infra/heartbeat-active-hours.js +2 -2
- package/dist/infra/heartbeat-reason.js +40 -0
- package/dist/infra/heartbeat-runner.js +72 -32
- package/dist/infra/heartbeat-wake.js +6 -12
- package/dist/infra/host-env-security-policy.json +19 -0
- package/dist/infra/host-env-security.js +66 -0
- package/dist/infra/install-source-utils.js +91 -7
- package/dist/infra/net/ssrf.js +131 -38
- package/dist/infra/node-pairing.js +50 -105
- package/dist/infra/npm-integrity.js +45 -0
- package/dist/infra/npm-pack-install.js +40 -0
- package/dist/infra/outbound/bound-delivery-router.js +88 -0
- package/dist/infra/outbound/channel-adapters.js +20 -7
- package/dist/infra/outbound/channel-selection.js +12 -6
- package/dist/infra/outbound/envelope.js +1 -1
- package/dist/infra/outbound/format.js +12 -6
- package/dist/infra/outbound/message-action-runner.js +107 -327
- package/dist/infra/outbound/message.js +59 -36
- package/dist/infra/outbound/outbound-policy.js +52 -25
- package/dist/infra/outbound/outbound-send-service.js +58 -71
- package/dist/infra/outbound/payloads.js +14 -7
- package/dist/infra/outbound/session-binding-service.js +123 -0
- package/dist/infra/pairing-files.js +10 -0
- package/dist/infra/path-guards.js +25 -0
- package/dist/infra/plain-object.js +9 -0
- package/dist/infra/provider-usage.fetch.codex.js +7 -15
- package/dist/infra/provider-usage.fetch.gemini.js +14 -11
- package/dist/infra/provider-usage.fetch.shared.js +30 -1
- package/dist/infra/provider-usage.fetch.zai.js +10 -9
- package/dist/infra/push-apns.js +365 -0
- package/dist/infra/restart-sentinel.js +16 -1
- package/dist/infra/restart.js +229 -26
- package/dist/infra/retry-policy.js +4 -2
- package/dist/infra/retry.js +9 -5
- package/dist/infra/scp-host.js +54 -0
- package/dist/infra/session-cost-usage.js +107 -59
- package/dist/infra/session-maintenance-warning.js +3 -1
- package/dist/infra/shell-env.js +98 -34
- package/dist/infra/ssh-config.js +12 -6
- package/dist/infra/system-run-command.js +49 -4
- package/dist/infra/update-channels.js +10 -5
- package/dist/infra/update-startup.js +86 -9
- package/dist/line/accounts.js +5 -7
- package/dist/line/bot-access.js +8 -20
- package/dist/line/bot-handlers.js +3 -1
- package/dist/link-understanding/detect.js +15 -7
- package/dist/media/constants.js +15 -6
- package/dist/media/image-ops.js +7 -0
- package/dist/media/inbound-path-policy.js +114 -0
- package/dist/media/input-files.js +16 -0
- package/dist/media/local-roots.js +3 -2
- package/dist/media-understanding/apply.js +4 -1
- package/dist/media-understanding/concurrency.js +8 -20
- package/dist/memory/backend-config.js +45 -6
- package/dist/memory/embeddings.js +10 -4
- package/dist/memory/fs-utils.js +23 -0
- package/dist/memory/manager-search.js +12 -6
- package/dist/memory/manager-sync-ops.js +12 -2
- package/dist/memory/qmd-manager.js +466 -53
- package/dist/memory/query-expansion.js +167 -3
- package/dist/memory/status-format.js +10 -5
- package/dist/memory/sync-memory-files.js +1 -1
- package/dist/memory/test-manager.js +8 -0
- package/dist/node-host/invoke-system-run.js +281 -0
- package/dist/node-host/invoke.js +55 -337
- package/dist/pairing/pairing-store.js +22 -0
- package/dist/plugin-sdk/allow-from.js +1 -1
- package/dist/plugin-sdk/command-auth.js +3 -1
- package/dist/plugin-sdk/index.js +6 -3
- package/dist/plugin-sdk/temp-path.js +47 -0
- package/dist/plugin-sdk/webhook-targets.js +32 -0
- package/dist/plugins/bundled-dir.js +9 -6
- package/dist/plugins/discovery.js +217 -23
- package/dist/plugins/hook-runner-global.js +16 -0
- package/dist/plugins/hooks.js +50 -0
- package/dist/plugins/install.js +28 -16
- package/dist/plugins/loader.js +192 -26
- package/dist/plugins/logger.js +8 -0
- package/dist/plugins/manifest-registry.js +3 -0
- package/dist/plugins/path-safety.js +34 -0
- package/dist/plugins/registry.js +5 -2
- package/dist/plugins/runtime/index.js +271 -206
- package/dist/plugins/runtime.js +3 -17
- package/dist/plugins/update.js +78 -12
- package/dist/process/spawn-utils.js +14 -7
- package/dist/providers/github-copilot-models.js +4 -1
- package/dist/providers/github-copilot-token.js +11 -6
- package/dist/providers/qwen-portal-oauth.js +14 -6
- package/dist/routing/account-id.js +30 -0
- package/dist/routing/resolve-route.js +3 -7
- package/dist/routing/session-key.js +2 -16
- package/dist/security/audit-channel.js +100 -20
- package/dist/security/audit-extra.async.js +505 -179
- package/dist/security/audit-extra.js +12 -2
- package/dist/security/audit-extra.sync.js +421 -35
- package/dist/security/audit-fs.js +31 -13
- package/dist/security/audit.js +180 -370
- package/dist/security/dm-policy-shared.js +68 -0
- package/dist/security/external-content.js +46 -14
- package/dist/security/fix.js +49 -85
- package/dist/security/scan-paths.js +20 -0
- package/dist/security/secret-equal.js +3 -7
- package/dist/security/windows-acl.js +30 -15
- package/dist/shared/entry-status.js +6 -0
- package/dist/shared/frontmatter.js +5 -5
- package/dist/shared/node-list-parse.js +13 -0
- package/dist/shared/node-match.js +11 -4
- package/dist/shared/operator-scope-compat.js +42 -0
- package/dist/shared/text-chunking.js +29 -0
- package/dist/signal/accounts.js +7 -20
- package/dist/signal/monitor/event-handler.js +3 -1
- package/dist/slack/accounts.js +6 -19
- package/dist/slack/actions.js +11 -3
- package/dist/slack/blocks.test-helpers.js +31 -0
- package/dist/slack/monitor/auth.js +1 -1
- package/dist/slack/monitor/message-handler/dispatch.js +50 -29
- package/dist/slack/monitor/mrkdwn.js +8 -0
- package/dist/slack/monitor/replies.js +15 -7
- package/dist/slack/monitor/slash.js +22 -13
- package/dist/slack/resolve-channels.js +10 -5
- package/dist/slack/send.js +102 -12
- package/dist/slack/stream-mode.js +10 -0
- package/dist/slack/streaming.js +4 -2
- package/dist/telegram/accounts.js +19 -14
- package/dist/telegram/bot/helpers.js +3 -5
- package/dist/telegram/bot-access.js +35 -36
- package/dist/telegram/bot-handlers.js +120 -148
- package/dist/telegram/bot-message-context.js +68 -9
- package/dist/telegram/bot-message-dispatch.js +477 -210
- package/dist/telegram/bot-native-commands.js +16 -0
- package/dist/telegram/draft-stream.js +44 -8
- package/dist/telegram/inline-buttons.js +5 -15
- package/dist/telegram/monitor.js +11 -7
- package/dist/telegram/network-config.js +19 -7
- package/dist/telegram/reasoning-lane-coordinator.js +128 -0
- package/dist/telegram/send.js +3 -2
- package/dist/telegram/sent-message-cache.js +5 -6
- package/dist/telegram/status-reaction-variants.js +208 -0
- package/dist/telegram/sticker-cache.js +11 -9
- package/dist/terminal/prompt-select-styled.js +9 -0
- package/dist/terminal/theme.js +12 -12
- package/dist/test-utils/command-runner.js +6 -0
- package/dist/test-utils/internal-hook-event-payload.js +10 -0
- package/dist/test-utils/model-auth-mock.js +12 -0
- package/dist/test-utils/provider-usage-fetch.js +14 -0
- package/dist/test-utils/temp-home.js +33 -0
- package/dist/tts/tts.js +80 -567
- package/dist/tui/components/chat-log.js +50 -8
- package/dist/tui/theme/theme.js +10 -12
- package/dist/tui/tui-command-handlers.js +36 -27
- package/dist/tui/tui-event-handlers.js +122 -32
- package/dist/tui/tui-local-shell.js +16 -6
- package/dist/tui/tui.js +236 -48
- package/dist/utils/account-id.js +2 -4
- package/dist/utils/boolean.js +10 -5
- package/dist/utils/directive-tags.js +11 -0
- package/dist/utils/mask-api-key.js +10 -0
- package/dist/utils/queue-helpers.js +67 -12
- package/dist/utils/run-with-concurrency.js +39 -0
- package/dist/web/auto-reply/deliver-reply.js +8 -4
- package/dist/web/auto-reply/mentions.js +10 -5
- package/dist/web/auto-reply/monitor/group-members.js +14 -7
- package/dist/web/auto-reply/monitor/process-message.js +45 -24
- package/dist/web/inbound/access-control.js +5 -2
- package/dist/web/login-qr.js +12 -6
- package/dist/web/media.js +126 -15
- package/docs/tools/slash-commands.md +5 -1
- package/extensions/bluebubbles/src/monitor-processing.ts +580 -139
- package/extensions/bluebubbles/src/monitor.ts +208 -1950
- package/extensions/feishu/src/external-keys.ts +19 -0
- package/extensions/lobster/src/windows-spawn.ts +193 -0
- package/extensions/matrix/src/matrix/actions/limits.ts +6 -0
- package/extensions/mattermost/src/mattermost/reactions.test-helpers.ts +83 -0
- package/package.json +1 -1
|
@@ -1,97 +1,223 @@
|
|
|
1
|
+
import { createSubsystemLogger } from "../logging/subsystem.js";
|
|
2
|
+
import { isSensitiveConfigPath } from "./schema.hints.js";
|
|
3
|
+
const log = createSubsystemLogger("config/redaction");
|
|
4
|
+
const ENV_VAR_PLACEHOLDER_PATTERN = /^\$\{[^}]*\}$/;
|
|
5
|
+
function isSensitivePath(path) {
|
|
6
|
+
if (path.endsWith("[]")) {
|
|
7
|
+
return isSensitiveConfigPath(path.slice(0, -2));
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
return isSensitiveConfigPath(path);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function isEnvVarPlaceholder(value) {
|
|
14
|
+
return ENV_VAR_PLACEHOLDER_PATTERN.test(value.trim());
|
|
15
|
+
}
|
|
16
|
+
function isExtensionPath(path) {
|
|
17
|
+
return (path === "plugins" ||
|
|
18
|
+
path.startsWith("plugins.") ||
|
|
19
|
+
path === "channels" ||
|
|
20
|
+
path.startsWith("channels."));
|
|
21
|
+
}
|
|
22
|
+
function isExplicitlyNonSensitivePath(hints, paths) {
|
|
23
|
+
if (!hints) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
return paths.some((path) => hints[path]?.sensitive === false);
|
|
27
|
+
}
|
|
1
28
|
/**
|
|
2
29
|
* Sentinel value used to replace sensitive config fields in gateway responses.
|
|
3
30
|
* Write-side handlers (config.set, config.apply, config.patch) detect this
|
|
4
31
|
* sentinel and restore the original value from the on-disk config, so a
|
|
5
32
|
* round-trip through the Web UI does not corrupt credentials.
|
|
6
33
|
*/
|
|
7
|
-
export const REDACTED_SENTINEL = "
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
34
|
+
export const REDACTED_SENTINEL = "__CLAWDBOT_REDACTED__";
|
|
35
|
+
// ConfigUiHints' keys look like this:
|
|
36
|
+
// - path.subpath.key (nested objects)
|
|
37
|
+
// - path.subpath[].key (object in array in object)
|
|
38
|
+
// - path.*.key (object in record in object)
|
|
39
|
+
// records are handled by the lookup, but arrays need two entries in
|
|
40
|
+
// the Set, as their first lookup is done before the code knows it's
|
|
41
|
+
// an array.
|
|
42
|
+
function buildRedactionLookup(hints) {
|
|
43
|
+
let result = new Set();
|
|
44
|
+
for (const [path, hint] of Object.entries(hints)) {
|
|
45
|
+
if (!hint.sensitive) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const parts = path.split(".");
|
|
49
|
+
let joinedPath = parts.shift() ?? "";
|
|
50
|
+
result.add(joinedPath);
|
|
51
|
+
if (joinedPath.endsWith("[]")) {
|
|
52
|
+
result.add(joinedPath.slice(0, -2));
|
|
53
|
+
}
|
|
54
|
+
for (const part of parts) {
|
|
55
|
+
if (part.endsWith("[]")) {
|
|
56
|
+
result.add(`${joinedPath}.${part.slice(0, -2)}`);
|
|
57
|
+
}
|
|
58
|
+
// hey, greptile, notice how this is *NOT* in an else block?
|
|
59
|
+
joinedPath = `${joinedPath}.${part}`;
|
|
60
|
+
result.add(joinedPath);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (result.size !== 0) {
|
|
64
|
+
result.add("");
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
15
67
|
}
|
|
16
68
|
/**
|
|
17
|
-
* Deep-walk an object and replace values
|
|
69
|
+
* Deep-walk an object and replace string values at sensitive paths
|
|
18
70
|
* with the redaction sentinel.
|
|
19
71
|
*/
|
|
20
|
-
function redactObject(obj) {
|
|
21
|
-
if (
|
|
22
|
-
|
|
72
|
+
function redactObject(obj, hints) {
|
|
73
|
+
if (hints) {
|
|
74
|
+
const lookup = buildRedactionLookup(hints);
|
|
75
|
+
return lookup.has("")
|
|
76
|
+
? redactObjectWithLookup(obj, lookup, "", [], hints)
|
|
77
|
+
: redactObjectGuessing(obj, "", [], hints);
|
|
23
78
|
}
|
|
24
|
-
|
|
25
|
-
return obj;
|
|
26
|
-
}
|
|
27
|
-
if (Array.isArray(obj)) {
|
|
28
|
-
return obj.map(redactObject);
|
|
79
|
+
else {
|
|
80
|
+
return redactObjectGuessing(obj, "", []);
|
|
29
81
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Collect all sensitive string values from a config object.
|
|
85
|
+
* Used for text-based redaction of the raw JSON5 source.
|
|
86
|
+
*/
|
|
87
|
+
function collectSensitiveValues(obj, hints) {
|
|
88
|
+
const result = [];
|
|
89
|
+
if (hints) {
|
|
90
|
+
const lookup = buildRedactionLookup(hints);
|
|
91
|
+
if (lookup.has("")) {
|
|
92
|
+
redactObjectWithLookup(obj, lookup, "", result, hints);
|
|
37
93
|
}
|
|
38
94
|
else {
|
|
39
|
-
result
|
|
95
|
+
redactObjectGuessing(obj, "", result, hints);
|
|
40
96
|
}
|
|
41
97
|
}
|
|
98
|
+
else {
|
|
99
|
+
redactObjectGuessing(obj, "", result);
|
|
100
|
+
}
|
|
42
101
|
return result;
|
|
43
102
|
}
|
|
44
|
-
export function redactConfigObject(value) {
|
|
45
|
-
return redactObject(value);
|
|
46
|
-
}
|
|
47
103
|
/**
|
|
48
|
-
*
|
|
49
|
-
* Used
|
|
104
|
+
* Worker for redactObject() and collectSensitiveValues().
|
|
105
|
+
* Used when there are ConfigUiHints available.
|
|
50
106
|
*/
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return values;
|
|
107
|
+
function redactObjectWithLookup(obj, lookup, prefix, values, hints) {
|
|
108
|
+
if (obj === null || obj === undefined) {
|
|
109
|
+
return obj;
|
|
55
110
|
}
|
|
56
111
|
if (Array.isArray(obj)) {
|
|
57
|
-
|
|
58
|
-
|
|
112
|
+
const path = `${prefix}[]`;
|
|
113
|
+
if (!lookup.has(path)) {
|
|
114
|
+
if (!isExtensionPath(prefix)) {
|
|
115
|
+
return obj;
|
|
116
|
+
}
|
|
117
|
+
return redactObjectGuessing(obj, prefix, values, hints);
|
|
59
118
|
}
|
|
60
|
-
return
|
|
119
|
+
return obj.map((item) => {
|
|
120
|
+
if (typeof item === "string" && !isEnvVarPlaceholder(item)) {
|
|
121
|
+
values.push(item);
|
|
122
|
+
return REDACTED_SENTINEL;
|
|
123
|
+
}
|
|
124
|
+
return redactObjectWithLookup(item, lookup, path, values, hints);
|
|
125
|
+
});
|
|
61
126
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
127
|
+
if (typeof obj === "object") {
|
|
128
|
+
const result = {};
|
|
129
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
130
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
131
|
+
const wildcardPath = prefix ? `${prefix}.*` : "*";
|
|
132
|
+
let matched = false;
|
|
133
|
+
for (const candidate of [path, wildcardPath]) {
|
|
134
|
+
result[key] = value;
|
|
135
|
+
if (lookup.has(candidate)) {
|
|
136
|
+
matched = true;
|
|
137
|
+
// Hey, greptile, look here, this **IS** only applied to strings
|
|
138
|
+
if (typeof value === "string" && !isEnvVarPlaceholder(value)) {
|
|
139
|
+
result[key] = REDACTED_SENTINEL;
|
|
140
|
+
values.push(value);
|
|
141
|
+
}
|
|
142
|
+
else if (typeof value === "object" && value !== null) {
|
|
143
|
+
result[key] = redactObjectWithLookup(value, lookup, candidate, values, hints);
|
|
144
|
+
}
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (!matched && isExtensionPath(path)) {
|
|
149
|
+
const markedNonSensitive = isExplicitlyNonSensitivePath(hints, [path, wildcardPath]);
|
|
150
|
+
if (typeof value === "string" &&
|
|
151
|
+
!markedNonSensitive &&
|
|
152
|
+
isSensitivePath(path) &&
|
|
153
|
+
!isEnvVarPlaceholder(value)) {
|
|
154
|
+
result[key] = REDACTED_SENTINEL;
|
|
155
|
+
values.push(value);
|
|
156
|
+
}
|
|
157
|
+
else if (typeof value === "object" && value !== null) {
|
|
158
|
+
result[key] = redactObjectGuessing(value, path, values, hints);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
65
161
|
}
|
|
66
|
-
|
|
67
|
-
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
return obj;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Worker for redactObject() and collectSensitiveValues().
|
|
168
|
+
* Used when ConfigUiHints are NOT available.
|
|
169
|
+
*/
|
|
170
|
+
function redactObjectGuessing(obj, prefix, values, hints) {
|
|
171
|
+
if (obj === null || obj === undefined) {
|
|
172
|
+
return obj;
|
|
173
|
+
}
|
|
174
|
+
if (Array.isArray(obj)) {
|
|
175
|
+
return obj.map((item) => {
|
|
176
|
+
const path = `${prefix}[]`;
|
|
177
|
+
if (!isExplicitlyNonSensitivePath(hints, [path]) &&
|
|
178
|
+
isSensitivePath(path) &&
|
|
179
|
+
typeof item === "string" &&
|
|
180
|
+
!isEnvVarPlaceholder(item)) {
|
|
181
|
+
values.push(item);
|
|
182
|
+
return REDACTED_SENTINEL;
|
|
183
|
+
}
|
|
184
|
+
return redactObjectGuessing(item, path, values, hints);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
if (typeof obj === "object") {
|
|
188
|
+
const result = {};
|
|
189
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
190
|
+
const dotPath = prefix ? `${prefix}.${key}` : key;
|
|
191
|
+
const wildcardPath = prefix ? `${prefix}.*` : "*";
|
|
192
|
+
if (!isExplicitlyNonSensitivePath(hints, [dotPath, wildcardPath]) &&
|
|
193
|
+
isSensitivePath(dotPath) &&
|
|
194
|
+
typeof value === "string" &&
|
|
195
|
+
!isEnvVarPlaceholder(value)) {
|
|
196
|
+
result[key] = REDACTED_SENTINEL;
|
|
197
|
+
values.push(value);
|
|
198
|
+
}
|
|
199
|
+
else if (typeof value === "object" && value !== null) {
|
|
200
|
+
result[key] = redactObjectGuessing(value, dotPath, values, hints);
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
result[key] = value;
|
|
204
|
+
}
|
|
68
205
|
}
|
|
206
|
+
return result;
|
|
69
207
|
}
|
|
70
|
-
return
|
|
208
|
+
return obj;
|
|
71
209
|
}
|
|
72
210
|
/**
|
|
73
211
|
* Replace known sensitive values in a raw JSON5 string with the sentinel.
|
|
74
212
|
* Values are replaced longest-first to avoid partial matches.
|
|
75
213
|
*/
|
|
76
|
-
function redactRawText(raw, config) {
|
|
77
|
-
const sensitiveValues = collectSensitiveValues(config);
|
|
214
|
+
function redactRawText(raw, config, hints) {
|
|
215
|
+
const sensitiveValues = collectSensitiveValues(config, hints);
|
|
78
216
|
sensitiveValues.sort((a, b) => b.length - a.length);
|
|
79
217
|
let result = raw;
|
|
80
218
|
for (const value of sensitiveValues) {
|
|
81
|
-
|
|
82
|
-
result = result.replace(new RegExp(escaped, "g"), REDACTED_SENTINEL);
|
|
219
|
+
result = result.replaceAll(value, REDACTED_SENTINEL);
|
|
83
220
|
}
|
|
84
|
-
const keyValuePattern = /(^|[{\s,])((["'])([^"']+)\3|([A-Za-z0-9_$.-]+))(\s*:\s*)(["'])([^"']*)\7/g;
|
|
85
|
-
result = result.replace(keyValuePattern, (match, prefix, keyExpr, _keyQuote, keyQuoted, keyBare, sep, valQuote, val) => {
|
|
86
|
-
const key = (keyQuoted ?? keyBare);
|
|
87
|
-
if (!key || !isSensitiveKey(key)) {
|
|
88
|
-
return match;
|
|
89
|
-
}
|
|
90
|
-
if (val === REDACTED_SENTINEL) {
|
|
91
|
-
return match;
|
|
92
|
-
}
|
|
93
|
-
return `${prefix}${keyExpr}${sep}${valQuote}${REDACTED_SENTINEL}${valQuote}`;
|
|
94
|
-
});
|
|
95
221
|
return result;
|
|
96
222
|
}
|
|
97
223
|
/**
|
|
@@ -101,49 +227,251 @@ function redactRawText(raw, config) {
|
|
|
101
227
|
*
|
|
102
228
|
* Both `config` (the parsed object) and `raw` (the JSON5 source) are scrubbed
|
|
103
229
|
* so no credential can leak through either path.
|
|
230
|
+
*
|
|
231
|
+
* When `uiHints` are provided, sensitivity is determined from the schema hints.
|
|
232
|
+
* Without hints, falls back to regex-based detection via `isSensitivePath()`.
|
|
104
233
|
*/
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
234
|
+
/**
|
|
235
|
+
* Redact sensitive fields from a plain config object (not a full snapshot).
|
|
236
|
+
* Used by write endpoints (config.set, config.patch, config.apply) to avoid
|
|
237
|
+
* leaking credentials in their responses.
|
|
238
|
+
*/
|
|
239
|
+
export function redactConfigObject(value, uiHints) {
|
|
240
|
+
return redactObject(value, uiHints);
|
|
241
|
+
}
|
|
242
|
+
export function redactConfigSnapshot(snapshot, uiHints) {
|
|
243
|
+
if (!snapshot.valid) {
|
|
244
|
+
// This is bad. We could try to redact the raw string using known key names,
|
|
245
|
+
// but then we would not be able to restore them, and would trash the user's
|
|
246
|
+
// credentials. Less than ideal---we should never delete important data.
|
|
247
|
+
// On the other hand, we cannot hand out "raw" if we're not sure we have
|
|
248
|
+
// properly redacted all sensitive data. Handing out a partially or, worse,
|
|
249
|
+
// unredacted config string would be bad.
|
|
250
|
+
// Therefore, the only safe route is to reject handling out broken configs.
|
|
251
|
+
return {
|
|
252
|
+
...snapshot,
|
|
253
|
+
config: {},
|
|
254
|
+
raw: null,
|
|
255
|
+
parsed: null,
|
|
256
|
+
resolved: {},
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
// else: snapshot.config must be valid and populated, as that is what
|
|
260
|
+
// readConfigFileSnapshot() does when it creates the snapshot.
|
|
261
|
+
const redactedConfig = redactObject(snapshot.config, uiHints);
|
|
262
|
+
const redactedRaw = snapshot.raw ? redactRawText(snapshot.raw, snapshot.config, uiHints) : null;
|
|
263
|
+
const redactedParsed = snapshot.parsed ? redactObject(snapshot.parsed, uiHints) : snapshot.parsed;
|
|
264
|
+
// Also redact the resolved config (contains values after ${ENV} substitution)
|
|
265
|
+
const redactedResolved = redactConfigObject(snapshot.resolved, uiHints);
|
|
109
266
|
return {
|
|
110
267
|
...snapshot,
|
|
111
268
|
config: redactedConfig,
|
|
112
269
|
raw: redactedRaw,
|
|
113
270
|
parsed: redactedParsed,
|
|
271
|
+
resolved: redactedResolved,
|
|
114
272
|
};
|
|
115
273
|
}
|
|
116
274
|
/**
|
|
117
275
|
* Deep-walk `incoming` and replace any {@link REDACTED_SENTINEL} values
|
|
118
|
-
* (on sensitive
|
|
276
|
+
* (on sensitive paths) with the corresponding value from `original`.
|
|
119
277
|
*
|
|
120
278
|
* This is called by config.set / config.apply / config.patch before writing,
|
|
121
279
|
* so that credentials survive a Web UI round-trip unmodified.
|
|
122
280
|
*/
|
|
123
|
-
export function restoreRedactedValues(incoming, original) {
|
|
281
|
+
export function restoreRedactedValues(incoming, original, hints) {
|
|
124
282
|
if (incoming === null || incoming === undefined) {
|
|
125
|
-
return
|
|
283
|
+
return { ok: false, error: "no input" };
|
|
126
284
|
}
|
|
127
285
|
if (typeof incoming !== "object") {
|
|
286
|
+
return { ok: false, error: "input not an object" };
|
|
287
|
+
}
|
|
288
|
+
try {
|
|
289
|
+
if (hints) {
|
|
290
|
+
const lookup = buildRedactionLookup(hints);
|
|
291
|
+
if (lookup.has("")) {
|
|
292
|
+
return {
|
|
293
|
+
ok: true,
|
|
294
|
+
result: restoreRedactedValuesWithLookup(incoming, original, lookup, "", hints),
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
return { ok: true, result: restoreRedactedValuesGuessing(incoming, original, "", hints) };
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
return { ok: true, result: restoreRedactedValuesGuessing(incoming, original, "") };
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
catch (err) {
|
|
306
|
+
if (err instanceof RedactionError) {
|
|
307
|
+
return {
|
|
308
|
+
ok: false,
|
|
309
|
+
humanReadableMessage: `Sentinel value "${REDACTED_SENTINEL}" in key ${err.key} is not valid as real data`,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
throw err; // some coding error, pass through
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
class RedactionError extends Error {
|
|
316
|
+
key;
|
|
317
|
+
constructor(key) {
|
|
318
|
+
super("internal error class---should never escape");
|
|
319
|
+
this.key = key;
|
|
320
|
+
this.name = "RedactionError";
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function restoreOriginalValueOrThrow(params) {
|
|
324
|
+
if (params.key in params.original) {
|
|
325
|
+
return params.original[params.key];
|
|
326
|
+
}
|
|
327
|
+
log.warn(`Cannot un-redact config key ${params.path} as it doesn't have any value`);
|
|
328
|
+
throw new RedactionError(params.path);
|
|
329
|
+
}
|
|
330
|
+
function mapRedactedArray(params) {
|
|
331
|
+
const originalArray = Array.isArray(params.original) ? params.original : [];
|
|
332
|
+
if (params.incoming.length < originalArray.length) {
|
|
333
|
+
log.warn(`Redacted config array key ${params.path} has been truncated`);
|
|
334
|
+
}
|
|
335
|
+
return params.incoming.map((item, index) => params.mapItem(item, index, originalArray));
|
|
336
|
+
}
|
|
337
|
+
function toObjectRecord(value) {
|
|
338
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
339
|
+
return value;
|
|
340
|
+
}
|
|
341
|
+
return {};
|
|
342
|
+
}
|
|
343
|
+
function shouldPassThroughRestoreValue(incoming) {
|
|
344
|
+
return incoming === null || incoming === undefined || typeof incoming !== "object";
|
|
345
|
+
}
|
|
346
|
+
function toRestoreArrayContext(incoming, prefix) {
|
|
347
|
+
if (!Array.isArray(incoming)) {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
return { incoming, path: `${prefix}[]` };
|
|
351
|
+
}
|
|
352
|
+
function restoreArrayItemWithLookup(params) {
|
|
353
|
+
if (params.item === REDACTED_SENTINEL) {
|
|
354
|
+
return params.originalArray[params.index];
|
|
355
|
+
}
|
|
356
|
+
return restoreRedactedValuesWithLookup(params.item, params.originalArray[params.index], params.lookup, params.path, params.hints);
|
|
357
|
+
}
|
|
358
|
+
function restoreArrayItemWithGuessing(params) {
|
|
359
|
+
if (!isExplicitlyNonSensitivePath(params.hints, [params.path]) &&
|
|
360
|
+
isSensitivePath(params.path) &&
|
|
361
|
+
params.item === REDACTED_SENTINEL) {
|
|
362
|
+
return params.originalArray[params.index];
|
|
363
|
+
}
|
|
364
|
+
return restoreRedactedValuesGuessing(params.item, params.originalArray[params.index], params.path, params.hints);
|
|
365
|
+
}
|
|
366
|
+
function restoreGuessingArray(incoming, original, path, hints) {
|
|
367
|
+
return mapRedactedArray({
|
|
368
|
+
incoming,
|
|
369
|
+
original,
|
|
370
|
+
path,
|
|
371
|
+
mapItem: (item, index, originalArray) => restoreArrayItemWithGuessing({
|
|
372
|
+
item,
|
|
373
|
+
index,
|
|
374
|
+
originalArray,
|
|
375
|
+
path,
|
|
376
|
+
hints,
|
|
377
|
+
}),
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Worker for restoreRedactedValues().
|
|
382
|
+
* Used when there are ConfigUiHints available.
|
|
383
|
+
*/
|
|
384
|
+
function restoreRedactedValuesWithLookup(incoming, original, lookup, prefix, hints) {
|
|
385
|
+
if (shouldPassThroughRestoreValue(incoming)) {
|
|
128
386
|
return incoming;
|
|
129
387
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
388
|
+
const arrayContext = toRestoreArrayContext(incoming, prefix);
|
|
389
|
+
if (arrayContext) {
|
|
390
|
+
// Note: If the user removed an item in the middle of the array,
|
|
391
|
+
// we have no way of knowing which one. In this case, the last
|
|
392
|
+
// element(s) get(s) chopped off. Not good, so please don't put
|
|
393
|
+
// sensitive string array in the config...
|
|
394
|
+
const { incoming: incomingArray, path } = arrayContext;
|
|
395
|
+
if (!lookup.has(path)) {
|
|
396
|
+
if (!isExtensionPath(prefix)) {
|
|
397
|
+
return incomingArray;
|
|
398
|
+
}
|
|
399
|
+
return restoreRedactedValuesGuessing(incomingArray, original, prefix, hints);
|
|
400
|
+
}
|
|
401
|
+
return mapRedactedArray({
|
|
402
|
+
incoming: incomingArray,
|
|
403
|
+
original,
|
|
404
|
+
path,
|
|
405
|
+
mapItem: (item, index, originalArray) => restoreArrayItemWithLookup({
|
|
406
|
+
item,
|
|
407
|
+
index,
|
|
408
|
+
originalArray,
|
|
409
|
+
lookup,
|
|
410
|
+
path,
|
|
411
|
+
hints,
|
|
412
|
+
}),
|
|
413
|
+
});
|
|
133
414
|
}
|
|
134
|
-
const orig =
|
|
135
|
-
? original
|
|
136
|
-
: {};
|
|
415
|
+
const orig = toObjectRecord(original);
|
|
137
416
|
const result = {};
|
|
138
417
|
for (const [key, value] of Object.entries(incoming)) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
418
|
+
result[key] = value;
|
|
419
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
420
|
+
const wildcardPath = prefix ? `${prefix}.*` : "*";
|
|
421
|
+
let matched = false;
|
|
422
|
+
for (const candidate of [path, wildcardPath]) {
|
|
423
|
+
if (lookup.has(candidate)) {
|
|
424
|
+
matched = true;
|
|
425
|
+
if (value === REDACTED_SENTINEL) {
|
|
426
|
+
result[key] = restoreOriginalValueOrThrow({ key, path: candidate, original: orig });
|
|
427
|
+
}
|
|
428
|
+
else if (typeof value === "object" && value !== null) {
|
|
429
|
+
result[key] = restoreRedactedValuesWithLookup(value, orig[key], lookup, candidate, hints);
|
|
430
|
+
}
|
|
431
|
+
break;
|
|
142
432
|
}
|
|
143
|
-
|
|
433
|
+
}
|
|
434
|
+
if (!matched && isExtensionPath(path)) {
|
|
435
|
+
const markedNonSensitive = isExplicitlyNonSensitivePath(hints, [path, wildcardPath]);
|
|
436
|
+
if (!markedNonSensitive && isSensitivePath(path) && value === REDACTED_SENTINEL) {
|
|
437
|
+
result[key] = restoreOriginalValueOrThrow({ key, path, original: orig });
|
|
438
|
+
}
|
|
439
|
+
else if (typeof value === "object" && value !== null) {
|
|
440
|
+
result[key] = restoreRedactedValuesGuessing(value, orig[key], path, hints);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return result;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Worker for restoreRedactedValues().
|
|
448
|
+
* Used when ConfigUiHints are NOT available.
|
|
449
|
+
*/
|
|
450
|
+
function restoreRedactedValuesGuessing(incoming, original, prefix, hints) {
|
|
451
|
+
if (shouldPassThroughRestoreValue(incoming)) {
|
|
452
|
+
return incoming;
|
|
453
|
+
}
|
|
454
|
+
const arrayContext = toRestoreArrayContext(incoming, prefix);
|
|
455
|
+
if (arrayContext) {
|
|
456
|
+
// Note: If the user removed an item in the middle of the array,
|
|
457
|
+
// we have no way of knowing which one. In this case, the last
|
|
458
|
+
// element(s) get(s) chopped off. Not good, so please don't put
|
|
459
|
+
// sensitive string array in the config...
|
|
460
|
+
const { incoming: incomingArray, path } = arrayContext;
|
|
461
|
+
return restoreGuessingArray(incomingArray, original, path, hints);
|
|
462
|
+
}
|
|
463
|
+
const orig = toObjectRecord(original);
|
|
464
|
+
const result = {};
|
|
465
|
+
for (const [key, value] of Object.entries(incoming)) {
|
|
466
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
467
|
+
const wildcardPath = prefix ? `${prefix}.*` : "*";
|
|
468
|
+
if (!isExplicitlyNonSensitivePath(hints, [path, wildcardPath]) &&
|
|
469
|
+
isSensitivePath(path) &&
|
|
470
|
+
value === REDACTED_SENTINEL) {
|
|
471
|
+
result[key] = restoreOriginalValueOrThrow({ key, path, original: orig });
|
|
144
472
|
}
|
|
145
473
|
else if (typeof value === "object" && value !== null) {
|
|
146
|
-
result[key] =
|
|
474
|
+
result[key] = restoreRedactedValuesGuessing(value, orig[key], path, hints);
|
|
147
475
|
}
|
|
148
476
|
else {
|
|
149
477
|
result[key] = value;
|