@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,5 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { extractSections } from "../../auto-reply/reply/post-compaction-context.js";
|
|
4
|
+
import { createSubsystemLogger } from "../../logging/subsystem.js";
|
|
5
|
+
import { BASE_CHUNK_RATIO, MIN_CHUNK_RATIO, SAFETY_MARGIN, SUMMARIZATION_OVERHEAD_TOKENS, computeAdaptiveChunkRatio, estimateMessagesTokens, isOversizedForSummary, pruneHistoryForContextShare, resolveContextWindowTokens, summarizeInStages, } from "../compaction.js";
|
|
6
|
+
import { collectTextContentBlocks } from "../content-blocks.js";
|
|
2
7
|
import { getCompactionSafeguardRuntime } from "./compaction-safeguard-runtime.js";
|
|
8
|
+
const log = createSubsystemLogger("compaction-safeguard");
|
|
3
9
|
const FALLBACK_SUMMARY = "Summary unavailable due to context limits. Older messages were truncated.";
|
|
4
10
|
const TURN_PREFIX_INSTRUCTIONS = "This summary covers the prefix of a split turn. Focus on the original request," +
|
|
5
11
|
" early progress, and any details needed to understand the retained suffix.";
|
|
@@ -9,54 +15,51 @@ function normalizeFailureText(text) {
|
|
|
9
15
|
return text.replace(/\s+/g, " ").trim();
|
|
10
16
|
}
|
|
11
17
|
function truncateFailureText(text, maxChars) {
|
|
12
|
-
if (text.length <= maxChars)
|
|
18
|
+
if (text.length <= maxChars) {
|
|
13
19
|
return text;
|
|
20
|
+
}
|
|
14
21
|
return `${text.slice(0, Math.max(0, maxChars - 3))}...`;
|
|
15
22
|
}
|
|
16
23
|
function formatToolFailureMeta(details) {
|
|
17
|
-
if (!details || typeof details !== "object")
|
|
24
|
+
if (!details || typeof details !== "object") {
|
|
18
25
|
return undefined;
|
|
26
|
+
}
|
|
19
27
|
const record = details;
|
|
20
28
|
const status = typeof record.status === "string" ? record.status : undefined;
|
|
21
29
|
const exitCode = typeof record.exitCode === "number" && Number.isFinite(record.exitCode)
|
|
22
30
|
? record.exitCode
|
|
23
31
|
: undefined;
|
|
24
32
|
const parts = [];
|
|
25
|
-
if (status)
|
|
33
|
+
if (status) {
|
|
26
34
|
parts.push(`status=${status}`);
|
|
27
|
-
|
|
35
|
+
}
|
|
36
|
+
if (exitCode !== undefined) {
|
|
28
37
|
parts.push(`exitCode=${exitCode}`);
|
|
38
|
+
}
|
|
29
39
|
return parts.length > 0 ? parts.join(" ") : undefined;
|
|
30
40
|
}
|
|
31
41
|
function extractToolResultText(content) {
|
|
32
|
-
|
|
33
|
-
return "";
|
|
34
|
-
const parts = [];
|
|
35
|
-
for (const block of content) {
|
|
36
|
-
if (!block || typeof block !== "object")
|
|
37
|
-
continue;
|
|
38
|
-
const rec = block;
|
|
39
|
-
if (rec.type === "text" && typeof rec.text === "string") {
|
|
40
|
-
parts.push(rec.text);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return parts.join("\n");
|
|
42
|
+
return collectTextContentBlocks(content).join("\n");
|
|
44
43
|
}
|
|
45
44
|
function collectToolFailures(messages) {
|
|
46
45
|
const failures = [];
|
|
47
46
|
const seen = new Set();
|
|
48
47
|
for (const message of messages) {
|
|
49
|
-
if (!message || typeof message !== "object")
|
|
48
|
+
if (!message || typeof message !== "object") {
|
|
50
49
|
continue;
|
|
50
|
+
}
|
|
51
51
|
const role = message.role;
|
|
52
|
-
if (role !== "toolResult")
|
|
52
|
+
if (role !== "toolResult") {
|
|
53
53
|
continue;
|
|
54
|
+
}
|
|
54
55
|
const toolResult = message;
|
|
55
|
-
if (toolResult.isError !== true)
|
|
56
|
+
if (toolResult.isError !== true) {
|
|
56
57
|
continue;
|
|
58
|
+
}
|
|
57
59
|
const toolCallId = typeof toolResult.toolCallId === "string" ? toolResult.toolCallId : "";
|
|
58
|
-
if (!toolCallId || seen.has(toolCallId))
|
|
60
|
+
if (!toolCallId || seen.has(toolCallId)) {
|
|
59
61
|
continue;
|
|
62
|
+
}
|
|
60
63
|
seen.add(toolCallId);
|
|
61
64
|
const toolName = typeof toolResult.toolName === "string" && toolResult.toolName.trim()
|
|
62
65
|
? toolResult.toolName
|
|
@@ -70,8 +73,9 @@ function collectToolFailures(messages) {
|
|
|
70
73
|
return failures;
|
|
71
74
|
}
|
|
72
75
|
function formatToolFailuresSection(failures) {
|
|
73
|
-
if (failures.length === 0)
|
|
76
|
+
if (failures.length === 0) {
|
|
74
77
|
return "";
|
|
78
|
+
}
|
|
75
79
|
const lines = failures.slice(0, MAX_TOOL_FAILURES).map((failure) => {
|
|
76
80
|
const meta = failure.meta ? ` (${failure.meta})` : "";
|
|
77
81
|
return `- ${failure.toolName}${meta}: ${failure.summary}`;
|
|
@@ -83,8 +87,8 @@ function formatToolFailuresSection(failures) {
|
|
|
83
87
|
}
|
|
84
88
|
function computeFileLists(fileOps) {
|
|
85
89
|
const modified = new Set([...fileOps.edited, ...fileOps.written]);
|
|
86
|
-
const readFiles = [...fileOps.read].filter((f) => !modified.has(f)).
|
|
87
|
-
const modifiedFiles = [...modified].
|
|
90
|
+
const readFiles = [...fileOps.read].filter((f) => !modified.has(f)).toSorted();
|
|
91
|
+
const modifiedFiles = [...modified].toSorted();
|
|
88
92
|
return { readFiles, modifiedFiles };
|
|
89
93
|
}
|
|
90
94
|
function formatFileOperations(readFiles, modifiedFiles) {
|
|
@@ -95,10 +99,39 @@ function formatFileOperations(readFiles, modifiedFiles) {
|
|
|
95
99
|
if (modifiedFiles.length > 0) {
|
|
96
100
|
sections.push(`<modified-files>\n${modifiedFiles.join("\n")}\n</modified-files>`);
|
|
97
101
|
}
|
|
98
|
-
if (sections.length === 0)
|
|
102
|
+
if (sections.length === 0) {
|
|
99
103
|
return "";
|
|
104
|
+
}
|
|
100
105
|
return `\n\n${sections.join("\n\n")}`;
|
|
101
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Read and format critical workspace context for compaction summary.
|
|
109
|
+
* Extracts "Session Startup" and "Red Lines" from AGENTS.md.
|
|
110
|
+
* Limited to 2000 chars to avoid bloating the summary.
|
|
111
|
+
*/
|
|
112
|
+
async function readWorkspaceContextForSummary() {
|
|
113
|
+
const MAX_SUMMARY_CONTEXT_CHARS = 2000;
|
|
114
|
+
const workspaceDir = process.cwd();
|
|
115
|
+
const agentsPath = path.join(workspaceDir, "AGENTS.md");
|
|
116
|
+
try {
|
|
117
|
+
if (!fs.existsSync(agentsPath)) {
|
|
118
|
+
return "";
|
|
119
|
+
}
|
|
120
|
+
const content = await fs.promises.readFile(agentsPath, "utf-8");
|
|
121
|
+
const sections = extractSections(content, ["Session Startup", "Red Lines"]);
|
|
122
|
+
if (sections.length === 0) {
|
|
123
|
+
return "";
|
|
124
|
+
}
|
|
125
|
+
const combined = sections.join("\n\n");
|
|
126
|
+
const safeContent = combined.length > MAX_SUMMARY_CONTEXT_CHARS
|
|
127
|
+
? combined.slice(0, MAX_SUMMARY_CONTEXT_CHARS) + "\n...[truncated]..."
|
|
128
|
+
: combined;
|
|
129
|
+
return `\n\n<workspace-critical-rules>\n${safeContent}\n</workspace-critical-rules>`;
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return "";
|
|
133
|
+
}
|
|
134
|
+
}
|
|
102
135
|
export default function compactionSafeguardExtension(api) {
|
|
103
136
|
api.on("session_before_compact", async (event, ctx) => {
|
|
104
137
|
const { preparation, customInstructions, signal } = event;
|
|
@@ -133,10 +166,11 @@ export default function compactionSafeguardExtension(api) {
|
|
|
133
166
|
};
|
|
134
167
|
}
|
|
135
168
|
try {
|
|
136
|
-
const
|
|
169
|
+
const runtime = getCompactionSafeguardRuntime(ctx.sessionManager);
|
|
170
|
+
const modelContextWindow = resolveContextWindowTokens(model);
|
|
171
|
+
const contextWindowTokens = runtime?.contextWindowTokens ?? modelContextWindow;
|
|
137
172
|
const turnPrefixMessages = preparation.turnPrefixMessages ?? [];
|
|
138
173
|
let messagesToSummarize = preparation.messagesToSummarize;
|
|
139
|
-
const runtime = getCompactionSafeguardRuntime(ctx.sessionManager);
|
|
140
174
|
const maxHistoryShare = runtime?.maxHistoryShare ?? 0.5;
|
|
141
175
|
const tokensBefore = typeof preparation.tokensBefore === "number" && Number.isFinite(preparation.tokensBefore)
|
|
142
176
|
? preparation.tokensBefore
|
|
@@ -156,14 +190,15 @@ export default function compactionSafeguardExtension(api) {
|
|
|
156
190
|
});
|
|
157
191
|
if (pruned.droppedChunks > 0) {
|
|
158
192
|
const newContentRatio = (newContentTokens / contextWindowTokens) * 100;
|
|
159
|
-
|
|
193
|
+
log.warn(`Compaction safeguard: new content uses ${newContentRatio.toFixed(1)}% of context; dropped ${pruned.droppedChunks} older chunk(s) ` +
|
|
160
194
|
`(${pruned.droppedMessages} messages) to fit history budget.`);
|
|
161
195
|
messagesToSummarize = pruned.messages;
|
|
162
196
|
// Summarize dropped messages so context isn't lost
|
|
163
197
|
if (pruned.droppedMessagesList.length > 0) {
|
|
164
198
|
try {
|
|
165
199
|
const droppedChunkRatio = computeAdaptiveChunkRatio(pruned.droppedMessagesList, contextWindowTokens);
|
|
166
|
-
const droppedMaxChunkTokens = Math.max(1, Math.floor(contextWindowTokens * droppedChunkRatio)
|
|
200
|
+
const droppedMaxChunkTokens = Math.max(1, Math.floor(contextWindowTokens * droppedChunkRatio) -
|
|
201
|
+
SUMMARIZATION_OVERHEAD_TOKENS);
|
|
167
202
|
droppedSummary = await summarizeInStages({
|
|
168
203
|
messages: pruned.droppedMessagesList,
|
|
169
204
|
model,
|
|
@@ -177,16 +212,18 @@ export default function compactionSafeguardExtension(api) {
|
|
|
177
212
|
});
|
|
178
213
|
}
|
|
179
214
|
catch (droppedError) {
|
|
180
|
-
|
|
215
|
+
log.warn(`Compaction safeguard: failed to summarize dropped messages, continuing without: ${droppedError instanceof Error ? droppedError.message : String(droppedError)}`);
|
|
181
216
|
}
|
|
182
217
|
}
|
|
183
218
|
}
|
|
184
219
|
}
|
|
185
220
|
}
|
|
186
|
-
// Use adaptive chunk ratio based on message sizes
|
|
221
|
+
// Use adaptive chunk ratio based on message sizes, reserving headroom for
|
|
222
|
+
// the summarization prompt, system prompt, previous summary, and reasoning budget
|
|
223
|
+
// that generateSummary adds on top of the serialized conversation chunk.
|
|
187
224
|
const allMessages = [...messagesToSummarize, ...turnPrefixMessages];
|
|
188
225
|
const adaptiveRatio = computeAdaptiveChunkRatio(allMessages, contextWindowTokens);
|
|
189
|
-
const maxChunkTokens = Math.max(1, Math.floor(contextWindowTokens * adaptiveRatio));
|
|
226
|
+
const maxChunkTokens = Math.max(1, Math.floor(contextWindowTokens * adaptiveRatio) - SUMMARIZATION_OVERHEAD_TOKENS);
|
|
190
227
|
const reserveTokens = Math.max(1, Math.floor(preparation.settings.reserveTokens));
|
|
191
228
|
// Feed dropped-messages summary as previousSummary so the main summarization
|
|
192
229
|
// incorporates context from pruned messages instead of losing it entirely.
|
|
@@ -219,6 +256,11 @@ export default function compactionSafeguardExtension(api) {
|
|
|
219
256
|
}
|
|
220
257
|
summary += toolFailureSection;
|
|
221
258
|
summary += fileOpsSummary;
|
|
259
|
+
// Append workspace critical context (Session Startup + Red Lines from AGENTS.md)
|
|
260
|
+
const workspaceContext = await readWorkspaceContextForSummary();
|
|
261
|
+
if (workspaceContext) {
|
|
262
|
+
summary += workspaceContext;
|
|
263
|
+
}
|
|
222
264
|
return {
|
|
223
265
|
compaction: {
|
|
224
266
|
summary,
|
|
@@ -229,7 +271,7 @@ export default function compactionSafeguardExtension(api) {
|
|
|
229
271
|
};
|
|
230
272
|
}
|
|
231
273
|
catch (error) {
|
|
232
|
-
|
|
274
|
+
log.warn(`Compaction summarization failed; truncating history: ${error instanceof Error ? error.message : String(error)}`);
|
|
233
275
|
return {
|
|
234
276
|
compaction: {
|
|
235
277
|
summary: fallbackSummary,
|
|
@@ -17,3 +17,43 @@ export function resolveCompactionReserveTokensFloor(cfg) {
|
|
|
17
17
|
}
|
|
18
18
|
return DEFAULT_PI_COMPACTION_RESERVE_TOKENS_FLOOR;
|
|
19
19
|
}
|
|
20
|
+
function toNonNegativeInt(value) {
|
|
21
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
return Math.floor(value);
|
|
25
|
+
}
|
|
26
|
+
function toPositiveInt(value) {
|
|
27
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
return Math.floor(value);
|
|
31
|
+
}
|
|
32
|
+
export function applyPiCompactionSettingsFromConfig(params) {
|
|
33
|
+
const currentReserveTokens = params.settingsManager.getCompactionReserveTokens();
|
|
34
|
+
const currentKeepRecentTokens = params.settingsManager.getCompactionKeepRecentTokens();
|
|
35
|
+
const compactionCfg = params.cfg?.agents?.defaults?.compaction;
|
|
36
|
+
const configuredReserveTokens = toNonNegativeInt(compactionCfg?.reserveTokens);
|
|
37
|
+
const configuredKeepRecentTokens = toPositiveInt(compactionCfg?.keepRecentTokens);
|
|
38
|
+
const reserveTokensFloor = resolveCompactionReserveTokensFloor(params.cfg);
|
|
39
|
+
const targetReserveTokens = Math.max(configuredReserveTokens ?? currentReserveTokens, reserveTokensFloor);
|
|
40
|
+
const targetKeepRecentTokens = configuredKeepRecentTokens ?? currentKeepRecentTokens;
|
|
41
|
+
const overrides = {};
|
|
42
|
+
if (targetReserveTokens !== currentReserveTokens) {
|
|
43
|
+
overrides.reserveTokens = targetReserveTokens;
|
|
44
|
+
}
|
|
45
|
+
if (targetKeepRecentTokens !== currentKeepRecentTokens) {
|
|
46
|
+
overrides.keepRecentTokens = targetKeepRecentTokens;
|
|
47
|
+
}
|
|
48
|
+
const didOverride = Object.keys(overrides).length > 0;
|
|
49
|
+
if (didOverride) {
|
|
50
|
+
params.settingsManager.applyOverrides({ compaction: overrides });
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
didOverride,
|
|
54
|
+
compaction: {
|
|
55
|
+
reserveTokens: targetReserveTokens,
|
|
56
|
+
keepRecentTokens: targetKeepRecentTokens,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -5,6 +5,7 @@ import { normalizeMessageChannel } from "../utils/message-channel.js";
|
|
|
5
5
|
import { resolveAgentConfig, resolveAgentIdFromSessionKey } from "./agent-scope.js";
|
|
6
6
|
import { compileGlobPatterns, matchesAnyGlobPattern } from "./glob-pattern.js";
|
|
7
7
|
import { pickSandboxToolPolicy } from "./sandbox-tool-policy.js";
|
|
8
|
+
import { DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH } from "../config/agent-limits.js";
|
|
8
9
|
import { expandToolGroups, normalizeToolName } from "./tool-policy.js";
|
|
9
10
|
function makeToolPolicyMatcher(policy) {
|
|
10
11
|
const deny = compileGlobPatterns({
|
|
@@ -75,7 +76,7 @@ function resolveSubagentDenyList(depth, maxSpawnDepth) {
|
|
|
75
76
|
}
|
|
76
77
|
export function resolveSubagentToolPolicy(cfg, depth) {
|
|
77
78
|
const configured = cfg?.tools?.subagents?.tools;
|
|
78
|
-
const maxSpawnDepth = cfg?.agents?.defaults?.subagents?.maxSpawnDepth ??
|
|
79
|
+
const maxSpawnDepth = cfg?.agents?.defaults?.subagents?.maxSpawnDepth ?? DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH;
|
|
79
80
|
const effectiveDepth = typeof depth === "number" && depth >= 0 ? depth : 1;
|
|
80
81
|
const baseDeny = resolveSubagentDenyList(effectiveDepth, maxSpawnDepth);
|
|
81
82
|
const deny = [...baseDeny, ...(Array.isArray(configured?.deny) ? configured.deny : [])];
|
|
@@ -1,23 +1,31 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
1
2
|
import { startBrowserBridgeServer, stopBrowserBridgeServer } from "../../browser/bridge-server.js";
|
|
2
3
|
import { resolveProfile } from "../../browser/config.js";
|
|
3
|
-
import { DEFAULT_BROWSER_EVALUATE_ENABLED, DEFAULT_CLAWD_BROWSER_COLOR, } from "../../browser/constants.js";
|
|
4
|
+
import { DEFAULT_BROWSER_EVALUATE_ENABLED, DEFAULT_CLAWD_BROWSER_COLOR, DEFAULT_CLAWD_BROWSER_PROFILE_NAME, } from "../../browser/constants.js";
|
|
5
|
+
import { defaultRuntime } from "../../runtime.js";
|
|
4
6
|
import { BROWSER_BRIDGES } from "./browser-bridges.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { computeSandboxBrowserConfigHash } from "./config-hash.js";
|
|
8
|
+
import { resolveSandboxBrowserDockerCreateConfig } from "./config.js";
|
|
9
|
+
import { DEFAULT_SANDBOX_BROWSER_IMAGE, SANDBOX_AGENT_WORKSPACE_MOUNT, SANDBOX_BROWSER_SECURITY_HASH_EPOCH, } from "./constants.js";
|
|
10
|
+
import { buildSandboxCreateArgs, dockerContainerState, execDocker, readDockerContainerEnvVar, readDockerContainerLabel, readDockerPort, } from "./docker.js";
|
|
11
|
+
import { buildNoVncDirectUrl, buildNoVncObserverTokenUrl, consumeNoVncObserverToken, generateNoVncPassword, isNoVncEnabled, NOVNC_PASSWORD_ENV_KEY, issueNoVncObserverToken, } from "./novnc-auth.js";
|
|
12
|
+
import { readBrowserRegistry, updateBrowserRegistry } from "./registry.js";
|
|
13
|
+
import { resolveSandboxAgentId, slugifySessionKey } from "./shared.js";
|
|
9
14
|
import { isToolAllowed } from "./tool-policy.js";
|
|
15
|
+
const HOT_BROWSER_WINDOW_MS = 5 * 60 * 1000;
|
|
16
|
+
const CDP_SOURCE_RANGE_ENV_KEY = "POOLBOT_BROWSER_CDP_SOURCE_RANGE";
|
|
10
17
|
async function waitForSandboxCdp(params) {
|
|
11
18
|
const deadline = Date.now() + Math.max(0, params.timeoutMs);
|
|
12
19
|
const url = `http://127.0.0.1:${params.cdpPort}/json/version`;
|
|
13
20
|
while (Date.now() < deadline) {
|
|
14
21
|
try {
|
|
15
22
|
const ctrl = new AbortController();
|
|
16
|
-
const t = setTimeout(
|
|
23
|
+
const t = setTimeout(ctrl.abort.bind(ctrl), 1000);
|
|
17
24
|
try {
|
|
18
25
|
const res = await fetch(url, { signal: ctrl.signal });
|
|
19
|
-
if (res.ok)
|
|
26
|
+
if (res.ok) {
|
|
20
27
|
return true;
|
|
28
|
+
}
|
|
21
29
|
}
|
|
22
30
|
finally {
|
|
23
31
|
clearTimeout(t);
|
|
@@ -46,9 +54,13 @@ function buildSandboxBrowserResolvedConfig(params) {
|
|
|
46
54
|
headless: params.headless,
|
|
47
55
|
noSandbox: false,
|
|
48
56
|
attachOnly: true,
|
|
49
|
-
defaultProfile:
|
|
57
|
+
defaultProfile: DEFAULT_CLAWD_BROWSER_PROFILE_NAME,
|
|
58
|
+
extraArgs: [],
|
|
50
59
|
profiles: {
|
|
51
|
-
|
|
60
|
+
[DEFAULT_CLAWD_BROWSER_PROFILE_NAME]: {
|
|
61
|
+
cdpPort: params.cdpPort,
|
|
62
|
+
color: DEFAULT_CLAWD_BROWSER_COLOR,
|
|
63
|
+
},
|
|
52
64
|
},
|
|
53
65
|
};
|
|
54
66
|
}
|
|
@@ -56,26 +68,115 @@ async function ensureSandboxBrowserImage(image) {
|
|
|
56
68
|
const result = await execDocker(["image", "inspect", image], {
|
|
57
69
|
allowFailure: true,
|
|
58
70
|
});
|
|
59
|
-
if (result.code === 0)
|
|
71
|
+
if (result.code === 0) {
|
|
60
72
|
return;
|
|
73
|
+
}
|
|
61
74
|
throw new Error(`Sandbox browser image not found: ${image}. Build it with scripts/sandbox-browser-setup.sh.`);
|
|
62
75
|
}
|
|
76
|
+
async function ensureDockerNetwork(network) {
|
|
77
|
+
const normalized = network.trim().toLowerCase();
|
|
78
|
+
if (!normalized ||
|
|
79
|
+
normalized === "bridge" ||
|
|
80
|
+
normalized === "none" ||
|
|
81
|
+
normalized.startsWith("container:")) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const inspect = await execDocker(["network", "inspect", network], { allowFailure: true });
|
|
85
|
+
if (inspect.code === 0) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
await execDocker(["network", "create", "--driver", "bridge", network]);
|
|
89
|
+
}
|
|
63
90
|
export async function ensureSandboxBrowser(params) {
|
|
64
|
-
if (!params.cfg.browser.enabled)
|
|
91
|
+
if (!params.cfg.browser.enabled) {
|
|
65
92
|
return null;
|
|
66
|
-
|
|
93
|
+
}
|
|
94
|
+
if (!isToolAllowed(params.cfg.tools, "browser")) {
|
|
67
95
|
return null;
|
|
96
|
+
}
|
|
68
97
|
const slug = params.cfg.scope === "shared" ? "shared" : slugifySessionKey(params.scopeKey);
|
|
69
98
|
const name = `${params.cfg.browser.containerPrefix}${slug}`;
|
|
70
99
|
const containerName = name.slice(0, 63);
|
|
71
100
|
const state = await dockerContainerState(containerName);
|
|
72
|
-
|
|
73
|
-
|
|
101
|
+
const browserImage = params.cfg.browser.image ?? DEFAULT_SANDBOX_BROWSER_IMAGE;
|
|
102
|
+
const cdpSourceRange = params.cfg.browser.cdpSourceRange?.trim() || undefined;
|
|
103
|
+
const browserDockerCfg = resolveSandboxBrowserDockerCreateConfig({
|
|
104
|
+
docker: params.cfg.docker,
|
|
105
|
+
browser: { ...params.cfg.browser, image: browserImage },
|
|
106
|
+
});
|
|
107
|
+
const expectedHash = computeSandboxBrowserConfigHash({
|
|
108
|
+
docker: browserDockerCfg,
|
|
109
|
+
browser: {
|
|
110
|
+
cdpPort: params.cfg.browser.cdpPort,
|
|
111
|
+
vncPort: params.cfg.browser.vncPort,
|
|
112
|
+
noVncPort: params.cfg.browser.noVncPort,
|
|
113
|
+
headless: params.cfg.browser.headless,
|
|
114
|
+
enableNoVnc: params.cfg.browser.enableNoVnc,
|
|
115
|
+
cdpSourceRange,
|
|
116
|
+
},
|
|
117
|
+
securityEpoch: SANDBOX_BROWSER_SECURITY_HASH_EPOCH,
|
|
118
|
+
workspaceAccess: params.cfg.workspaceAccess,
|
|
119
|
+
workspaceDir: params.workspaceDir,
|
|
120
|
+
agentWorkspaceDir: params.agentWorkspaceDir,
|
|
121
|
+
});
|
|
122
|
+
const now = Date.now();
|
|
123
|
+
let hasContainer = state.exists;
|
|
124
|
+
let running = state.running;
|
|
125
|
+
let currentHash = null;
|
|
126
|
+
let hashMismatch = false;
|
|
127
|
+
const noVncEnabled = isNoVncEnabled(params.cfg.browser);
|
|
128
|
+
let noVncPassword;
|
|
129
|
+
if (hasContainer) {
|
|
130
|
+
if (noVncEnabled) {
|
|
131
|
+
noVncPassword =
|
|
132
|
+
(await readDockerContainerEnvVar(containerName, NOVNC_PASSWORD_ENV_KEY)) ?? undefined;
|
|
133
|
+
}
|
|
134
|
+
const registry = await readBrowserRegistry();
|
|
135
|
+
const registryEntry = registry.entries.find((entry) => entry.containerName === containerName);
|
|
136
|
+
currentHash = await readDockerContainerLabel(containerName, "poolbot.configHash");
|
|
137
|
+
hashMismatch = !currentHash || currentHash !== expectedHash;
|
|
138
|
+
if (!currentHash) {
|
|
139
|
+
currentHash = registryEntry?.configHash ?? null;
|
|
140
|
+
hashMismatch = !currentHash || currentHash !== expectedHash;
|
|
141
|
+
}
|
|
142
|
+
if (hashMismatch) {
|
|
143
|
+
const lastUsedAtMs = registryEntry?.lastUsedAtMs;
|
|
144
|
+
const isHot = running && (typeof lastUsedAtMs !== "number" || now - lastUsedAtMs < HOT_BROWSER_WINDOW_MS);
|
|
145
|
+
if (isHot) {
|
|
146
|
+
const hint = (() => {
|
|
147
|
+
if (params.cfg.scope === "session") {
|
|
148
|
+
return `poolbot sandbox recreate --browser --session ${params.scopeKey}`;
|
|
149
|
+
}
|
|
150
|
+
if (params.cfg.scope === "agent") {
|
|
151
|
+
const agentId = resolveSandboxAgentId(params.scopeKey) ?? "main";
|
|
152
|
+
return `poolbot sandbox recreate --browser --agent ${agentId}`;
|
|
153
|
+
}
|
|
154
|
+
return "poolbot sandbox recreate --browser --all";
|
|
155
|
+
})();
|
|
156
|
+
defaultRuntime.log(`Sandbox browser config changed for ${containerName} (recently used). Recreate to apply: ${hint}`);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
await execDocker(["rm", "-f", containerName], { allowFailure: true });
|
|
160
|
+
hasContainer = false;
|
|
161
|
+
running = false;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (!hasContainer) {
|
|
166
|
+
if (noVncEnabled) {
|
|
167
|
+
noVncPassword = generateNoVncPassword();
|
|
168
|
+
}
|
|
169
|
+
await ensureDockerNetwork(browserDockerCfg.network);
|
|
170
|
+
await ensureSandboxBrowserImage(browserImage);
|
|
74
171
|
const args = buildSandboxCreateArgs({
|
|
75
172
|
name: containerName,
|
|
76
|
-
cfg:
|
|
173
|
+
cfg: browserDockerCfg,
|
|
77
174
|
scopeKey: params.scopeKey,
|
|
78
|
-
labels: {
|
|
175
|
+
labels: {
|
|
176
|
+
"poolbot.sandboxBrowser": "1",
|
|
177
|
+
"poolbot.browserConfigEpoch": SANDBOX_BROWSER_SECURITY_HASH_EPOCH,
|
|
178
|
+
},
|
|
179
|
+
configHash: expectedHash,
|
|
79
180
|
});
|
|
80
181
|
const mainMountSuffix = params.cfg.workspaceAccess === "ro" && params.workspaceDir === params.agentWorkspaceDir
|
|
81
182
|
? ":ro"
|
|
@@ -86,48 +187,75 @@ export async function ensureSandboxBrowser(params) {
|
|
|
86
187
|
args.push("-v", `${params.agentWorkspaceDir}:${SANDBOX_AGENT_WORKSPACE_MOUNT}${agentMountSuffix}`);
|
|
87
188
|
}
|
|
88
189
|
args.push("-p", `127.0.0.1::${params.cfg.browser.cdpPort}`);
|
|
89
|
-
if (
|
|
190
|
+
if (noVncEnabled) {
|
|
90
191
|
args.push("-p", `127.0.0.1::${params.cfg.browser.noVncPort}`);
|
|
91
192
|
}
|
|
92
193
|
args.push("-e", `POOLBOT_BROWSER_HEADLESS=${params.cfg.browser.headless ? "1" : "0"}`);
|
|
93
|
-
args.push("-e", `CLAWDBOT_BROWSER_HEADLESS=${params.cfg.browser.headless ? "1" : "0"}`);
|
|
94
194
|
args.push("-e", `POOLBOT_BROWSER_ENABLE_NOVNC=${params.cfg.browser.enableNoVnc ? "1" : "0"}`);
|
|
95
|
-
args.push("-e", `CLAWDBOT_BROWSER_ENABLE_NOVNC=${params.cfg.browser.enableNoVnc ? "1" : "0"}`);
|
|
96
195
|
args.push("-e", `POOLBOT_BROWSER_CDP_PORT=${params.cfg.browser.cdpPort}`);
|
|
97
|
-
|
|
196
|
+
if (cdpSourceRange) {
|
|
197
|
+
args.push("-e", `${CDP_SOURCE_RANGE_ENV_KEY}=${cdpSourceRange}`);
|
|
198
|
+
}
|
|
98
199
|
args.push("-e", `POOLBOT_BROWSER_VNC_PORT=${params.cfg.browser.vncPort}`);
|
|
99
|
-
args.push("-e", `CLAWDBOT_BROWSER_VNC_PORT=${params.cfg.browser.vncPort}`);
|
|
100
200
|
args.push("-e", `POOLBOT_BROWSER_NOVNC_PORT=${params.cfg.browser.noVncPort}`);
|
|
101
|
-
|
|
102
|
-
|
|
201
|
+
if (noVncEnabled && noVncPassword) {
|
|
202
|
+
args.push("-e", `${NOVNC_PASSWORD_ENV_KEY}=${noVncPassword}`);
|
|
203
|
+
}
|
|
204
|
+
args.push(browserImage);
|
|
103
205
|
await execDocker(args);
|
|
104
206
|
await execDocker(["start", containerName]);
|
|
105
207
|
}
|
|
106
|
-
else if (!
|
|
208
|
+
else if (!running) {
|
|
107
209
|
await execDocker(["start", containerName]);
|
|
108
210
|
}
|
|
109
211
|
const mappedCdp = await readDockerPort(containerName, params.cfg.browser.cdpPort);
|
|
110
212
|
if (!mappedCdp) {
|
|
111
213
|
throw new Error(`Failed to resolve CDP port mapping for ${containerName}.`);
|
|
112
214
|
}
|
|
113
|
-
const mappedNoVnc =
|
|
215
|
+
const mappedNoVnc = noVncEnabled
|
|
114
216
|
? await readDockerPort(containerName, params.cfg.browser.noVncPort)
|
|
115
217
|
: null;
|
|
218
|
+
if (noVncEnabled && !noVncPassword) {
|
|
219
|
+
noVncPassword =
|
|
220
|
+
(await readDockerContainerEnvVar(containerName, NOVNC_PASSWORD_ENV_KEY)) ?? undefined;
|
|
221
|
+
}
|
|
116
222
|
const existing = BROWSER_BRIDGES.get(params.scopeKey);
|
|
117
|
-
const existingProfile = existing
|
|
223
|
+
const existingProfile = existing
|
|
224
|
+
? resolveProfile(existing.bridge.state.resolved, DEFAULT_CLAWD_BROWSER_PROFILE_NAME)
|
|
225
|
+
: null;
|
|
226
|
+
let desiredAuthToken = params.bridgeAuth?.token?.trim() || undefined;
|
|
227
|
+
let desiredAuthPassword = params.bridgeAuth?.password?.trim() || undefined;
|
|
228
|
+
if (!desiredAuthToken && !desiredAuthPassword) {
|
|
229
|
+
// Always require auth for the sandbox bridge server, even if gateway auth
|
|
230
|
+
// mode doesn't produce a shared secret (e.g. trusted-proxy).
|
|
231
|
+
// Keep it stable across calls by reusing the existing bridge auth.
|
|
232
|
+
desiredAuthToken = existing?.authToken;
|
|
233
|
+
desiredAuthPassword = existing?.authPassword;
|
|
234
|
+
if (!desiredAuthToken && !desiredAuthPassword) {
|
|
235
|
+
desiredAuthToken = crypto.randomBytes(24).toString("hex");
|
|
236
|
+
}
|
|
237
|
+
}
|
|
118
238
|
const shouldReuse = existing && existing.containerName === containerName && existingProfile?.cdpPort === mappedCdp;
|
|
239
|
+
const authMatches = !existing ||
|
|
240
|
+
(existing.authToken === desiredAuthToken && existing.authPassword === desiredAuthPassword);
|
|
119
241
|
if (existing && !shouldReuse) {
|
|
120
242
|
await stopBrowserBridgeServer(existing.bridge.server).catch(() => undefined);
|
|
121
243
|
BROWSER_BRIDGES.delete(params.scopeKey);
|
|
122
244
|
}
|
|
245
|
+
if (existing && shouldReuse && !authMatches) {
|
|
246
|
+
await stopBrowserBridgeServer(existing.bridge.server).catch(() => undefined);
|
|
247
|
+
BROWSER_BRIDGES.delete(params.scopeKey);
|
|
248
|
+
}
|
|
123
249
|
const bridge = (() => {
|
|
124
|
-
if (shouldReuse && existing)
|
|
250
|
+
if (shouldReuse && authMatches && existing) {
|
|
125
251
|
return existing.bridge;
|
|
252
|
+
}
|
|
126
253
|
return null;
|
|
127
254
|
})();
|
|
128
255
|
const ensureBridge = async () => {
|
|
129
|
-
if (bridge)
|
|
256
|
+
if (bridge) {
|
|
130
257
|
return bridge;
|
|
258
|
+
}
|
|
131
259
|
const onEnsureAttachTarget = params.cfg.browser.autoStart
|
|
132
260
|
? async () => {
|
|
133
261
|
const state = await dockerContainerState(containerName);
|
|
@@ -150,28 +278,37 @@ export async function ensureSandboxBrowser(params) {
|
|
|
150
278
|
headless: params.cfg.browser.headless,
|
|
151
279
|
evaluateEnabled: params.evaluateEnabled ?? DEFAULT_BROWSER_EVALUATE_ENABLED,
|
|
152
280
|
}),
|
|
281
|
+
authToken: desiredAuthToken,
|
|
282
|
+
authPassword: desiredAuthPassword,
|
|
153
283
|
onEnsureAttachTarget,
|
|
284
|
+
resolveSandboxNoVncToken: consumeNoVncObserverToken,
|
|
154
285
|
});
|
|
155
286
|
};
|
|
156
287
|
const resolvedBridge = await ensureBridge();
|
|
157
|
-
if (!shouldReuse) {
|
|
288
|
+
if (!shouldReuse || !authMatches) {
|
|
158
289
|
BROWSER_BRIDGES.set(params.scopeKey, {
|
|
159
290
|
bridge: resolvedBridge,
|
|
160
291
|
containerName,
|
|
292
|
+
authToken: desiredAuthToken,
|
|
293
|
+
authPassword: desiredAuthPassword,
|
|
161
294
|
});
|
|
162
295
|
}
|
|
163
|
-
const now = Date.now();
|
|
164
296
|
await updateBrowserRegistry({
|
|
165
297
|
containerName,
|
|
166
298
|
sessionKey: params.scopeKey,
|
|
167
299
|
createdAtMs: now,
|
|
168
300
|
lastUsedAtMs: now,
|
|
169
|
-
image:
|
|
301
|
+
image: browserImage,
|
|
302
|
+
configHash: hashMismatch && running ? (currentHash ?? undefined) : expectedHash,
|
|
170
303
|
cdpPort: mappedCdp,
|
|
171
304
|
noVncPort: mappedNoVnc ?? undefined,
|
|
172
305
|
});
|
|
173
|
-
const noVncUrl = mappedNoVnc &&
|
|
174
|
-
?
|
|
306
|
+
const noVncUrl = mappedNoVnc && noVncEnabled
|
|
307
|
+
? (() => {
|
|
308
|
+
const directUrl = buildNoVncDirectUrl(mappedNoVnc, noVncPassword);
|
|
309
|
+
const token = issueNoVncObserverToken({ url: directUrl });
|
|
310
|
+
return buildNoVncObserverTokenUrl(resolvedBridge.baseUrl, token);
|
|
311
|
+
})()
|
|
175
312
|
: undefined;
|
|
176
313
|
return {
|
|
177
314
|
bridgeUrl: resolvedBridge.baseUrl,
|
|
@@ -1,45 +1,32 @@
|
|
|
1
|
-
import
|
|
2
|
-
function isPrimitive(value) {
|
|
3
|
-
return value === null || (typeof value !== "object" && typeof value !== "function");
|
|
4
|
-
}
|
|
1
|
+
import { hashTextSha256 } from "./hash.js";
|
|
5
2
|
function normalizeForHash(value) {
|
|
6
|
-
if (value === undefined)
|
|
3
|
+
if (value === undefined) {
|
|
7
4
|
return undefined;
|
|
5
|
+
}
|
|
8
6
|
if (Array.isArray(value)) {
|
|
9
|
-
|
|
10
|
-
.map(normalizeForHash)
|
|
11
|
-
.filter((item) => item !== undefined);
|
|
12
|
-
const primitives = normalized.filter(isPrimitive);
|
|
13
|
-
if (primitives.length === normalized.length) {
|
|
14
|
-
return [...primitives].sort((a, b) => primitiveToString(a).localeCompare(primitiveToString(b)));
|
|
15
|
-
}
|
|
16
|
-
return normalized;
|
|
7
|
+
return value.map(normalizeForHash).filter((item) => item !== undefined);
|
|
17
8
|
}
|
|
18
9
|
if (value && typeof value === "object") {
|
|
19
|
-
const entries = Object.entries(value).
|
|
10
|
+
const entries = Object.entries(value).toSorted(([a], [b]) => a.localeCompare(b));
|
|
20
11
|
const normalized = {};
|
|
21
12
|
for (const [key, entryValue] of entries) {
|
|
22
13
|
const next = normalizeForHash(entryValue);
|
|
23
|
-
if (next !== undefined)
|
|
14
|
+
if (next !== undefined) {
|
|
24
15
|
normalized[key] = next;
|
|
16
|
+
}
|
|
25
17
|
}
|
|
26
18
|
return normalized;
|
|
27
19
|
}
|
|
28
20
|
return value;
|
|
29
21
|
}
|
|
30
|
-
function primitiveToString(value) {
|
|
31
|
-
if (value === null)
|
|
32
|
-
return "null";
|
|
33
|
-
if (typeof value === "string")
|
|
34
|
-
return value;
|
|
35
|
-
if (typeof value === "number")
|
|
36
|
-
return String(value);
|
|
37
|
-
if (typeof value === "boolean")
|
|
38
|
-
return value ? "true" : "false";
|
|
39
|
-
return JSON.stringify(value);
|
|
40
|
-
}
|
|
41
22
|
export function computeSandboxConfigHash(input) {
|
|
23
|
+
return computeHash(input);
|
|
24
|
+
}
|
|
25
|
+
export function computeSandboxBrowserConfigHash(input) {
|
|
26
|
+
return computeHash(input);
|
|
27
|
+
}
|
|
28
|
+
function computeHash(input) {
|
|
42
29
|
const payload = normalizeForHash(input);
|
|
43
30
|
const raw = JSON.stringify(payload);
|
|
44
|
-
return
|
|
31
|
+
return hashTextSha256(raw);
|
|
45
32
|
}
|