@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
|
@@ -63,7 +63,8 @@ export function resolveIMessageInboundDecision(params) {
|
|
|
63
63
|
return { kind: "drop", reason: "group without chat_id" };
|
|
64
64
|
}
|
|
65
65
|
const groupId = isGroup ? groupIdCandidate : undefined;
|
|
66
|
-
const
|
|
66
|
+
const storeAllowFrom = params.dmPolicy === "allowlist" ? [] : params.storeAllowFrom;
|
|
67
|
+
const effectiveDmAllowFrom = Array.from(new Set([...params.allowFrom, ...storeAllowFrom]))
|
|
67
68
|
.map((v) => String(v).trim())
|
|
68
69
|
.filter(Boolean);
|
|
69
70
|
// Keep DM pairing-store authorization scoped to DMs; group access must come from explicit group allowlist config.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { resolveSafeBaseDir } from "./path-safety.js";
|
|
3
|
+
export function isWindowsDrivePath(value) {
|
|
4
|
+
return /^[a-zA-Z]:[\\/]/.test(value);
|
|
5
|
+
}
|
|
6
|
+
export function normalizeArchiveEntryPath(raw) {
|
|
7
|
+
return raw.replaceAll("\\", "/");
|
|
8
|
+
}
|
|
9
|
+
export function validateArchiveEntryPath(entryPath, params) {
|
|
10
|
+
if (!entryPath || entryPath === "." || entryPath === "./") {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
if (isWindowsDrivePath(entryPath)) {
|
|
14
|
+
throw new Error(`archive entry uses a drive path: ${entryPath}`);
|
|
15
|
+
}
|
|
16
|
+
const normalized = path.posix.normalize(normalizeArchiveEntryPath(entryPath));
|
|
17
|
+
const escapeLabel = params?.escapeLabel ?? "destination";
|
|
18
|
+
if (normalized === ".." || normalized.startsWith("../")) {
|
|
19
|
+
throw new Error(`archive entry escapes ${escapeLabel}: ${entryPath}`);
|
|
20
|
+
}
|
|
21
|
+
if (path.posix.isAbsolute(normalized) || normalized.startsWith("//")) {
|
|
22
|
+
throw new Error(`archive entry is absolute: ${entryPath}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function stripArchivePath(entryPath, stripComponents) {
|
|
26
|
+
const raw = normalizeArchiveEntryPath(entryPath);
|
|
27
|
+
if (!raw || raw === "." || raw === "./") {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
// Mimic tar --strip-components semantics (raw segments before normalization)
|
|
31
|
+
// so strip-induced escapes like "a/../b" are visible to validators.
|
|
32
|
+
const parts = raw.split("/").filter((part) => part.length > 0 && part !== ".");
|
|
33
|
+
const strip = Math.max(0, Math.floor(stripComponents));
|
|
34
|
+
const stripped = strip === 0 ? parts.join("/") : parts.slice(strip).join("/");
|
|
35
|
+
const result = path.posix.normalize(stripped);
|
|
36
|
+
if (!result || result === "." || result === "./") {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
export function resolveArchiveOutputPath(params) {
|
|
42
|
+
const safeBase = resolveSafeBaseDir(params.rootDir);
|
|
43
|
+
const outPath = path.resolve(params.rootDir, params.relPath);
|
|
44
|
+
const escapeLabel = params.escapeLabel ?? "destination";
|
|
45
|
+
if (!outPath.startsWith(safeBase)) {
|
|
46
|
+
throw new Error(`archive entry escapes ${escapeLabel}: ${params.originalPath}`);
|
|
47
|
+
}
|
|
48
|
+
return outPath;
|
|
49
|
+
}
|
package/dist/infra/archive.js
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { constants as fsConstants } from "node:fs";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { Readable, Transform } from "node:stream";
|
|
5
5
|
import { pipeline } from "node:stream/promises";
|
|
6
6
|
import JSZip from "jszip";
|
|
7
7
|
import * as tar from "tar";
|
|
8
|
-
import {
|
|
8
|
+
import { resolveArchiveOutputPath, stripArchivePath, validateArchiveEntryPath, } from "./archive-path.js";
|
|
9
|
+
import { isNotFoundPathError, isPathInside, isSymlinkOpenError } from "./path-guards.js";
|
|
10
|
+
export class ArchiveSecurityError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
constructor(code, message, options) {
|
|
13
|
+
super(message, options);
|
|
14
|
+
this.code = code;
|
|
15
|
+
this.name = "ArchiveSecurityError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
9
18
|
/** @internal */
|
|
10
19
|
export const DEFAULT_MAX_ARCHIVE_BYTES_ZIP = 256 * 1024 * 1024;
|
|
11
20
|
/** @internal */
|
|
@@ -18,7 +27,12 @@ const ERROR_ARCHIVE_SIZE_EXCEEDS_LIMIT = "archive size exceeds limit";
|
|
|
18
27
|
const ERROR_ARCHIVE_ENTRY_COUNT_EXCEEDS_LIMIT = "archive entry count exceeds limit";
|
|
19
28
|
const ERROR_ARCHIVE_ENTRY_EXTRACTED_SIZE_EXCEEDS_LIMIT = "archive entry extracted size exceeds limit";
|
|
20
29
|
const ERROR_ARCHIVE_EXTRACTED_SIZE_EXCEEDS_LIMIT = "archive extracted size exceeds limit";
|
|
30
|
+
const ERROR_ARCHIVE_ENTRY_TRAVERSES_SYMLINK = "archive entry traverses symlink in destination";
|
|
21
31
|
const TAR_SUFFIXES = [".tgz", ".tar.gz", ".tar"];
|
|
32
|
+
const OPEN_WRITE_FLAGS = fsConstants.O_WRONLY |
|
|
33
|
+
fsConstants.O_CREAT |
|
|
34
|
+
fsConstants.O_TRUNC |
|
|
35
|
+
(process.platform !== "win32" && "O_NOFOLLOW" in fsConstants ? fsConstants.O_NOFOLLOW : 0);
|
|
22
36
|
export function resolveArchiveKind(filePath) {
|
|
23
37
|
const lower = filePath.toLowerCase();
|
|
24
38
|
if (lower.endsWith(".zip")) {
|
|
@@ -67,53 +81,6 @@ export async function withTimeout(promise, timeoutMs, label) {
|
|
|
67
81
|
}
|
|
68
82
|
}
|
|
69
83
|
}
|
|
70
|
-
// Path hygiene.
|
|
71
|
-
function normalizeArchivePath(raw) {
|
|
72
|
-
// Archives may contain Windows separators; treat them as separators.
|
|
73
|
-
return raw.replaceAll("\\", "/");
|
|
74
|
-
}
|
|
75
|
-
function isWindowsDrivePath(p) {
|
|
76
|
-
return /^[a-zA-Z]:[\\/]/.test(p);
|
|
77
|
-
}
|
|
78
|
-
function validateArchiveEntryPath(entryPath) {
|
|
79
|
-
if (!entryPath || entryPath === "." || entryPath === "./") {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
if (isWindowsDrivePath(entryPath)) {
|
|
83
|
-
throw new Error(`archive entry uses a drive path: ${entryPath}`);
|
|
84
|
-
}
|
|
85
|
-
const normalized = path.posix.normalize(normalizeArchivePath(entryPath));
|
|
86
|
-
if (normalized === ".." || normalized.startsWith("../")) {
|
|
87
|
-
throw new Error(`archive entry escapes destination: ${entryPath}`);
|
|
88
|
-
}
|
|
89
|
-
if (path.posix.isAbsolute(normalized) || normalized.startsWith("//")) {
|
|
90
|
-
throw new Error(`archive entry is absolute: ${entryPath}`);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
function stripArchivePath(entryPath, stripComponents) {
|
|
94
|
-
const raw = normalizeArchivePath(entryPath);
|
|
95
|
-
if (!raw || raw === "." || raw === "./") {
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
// Important: mimic tar --strip-components semantics (raw segments before
|
|
99
|
-
// normalization) so strip-induced escapes like "a/../b" are not hidden.
|
|
100
|
-
const parts = raw.split("/").filter((part) => part.length > 0 && part !== ".");
|
|
101
|
-
const strip = Math.max(0, Math.floor(stripComponents));
|
|
102
|
-
const stripped = strip === 0 ? parts.join("/") : parts.slice(strip).join("/");
|
|
103
|
-
const result = path.posix.normalize(stripped);
|
|
104
|
-
if (!result || result === "." || result === "./") {
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
return result;
|
|
108
|
-
}
|
|
109
|
-
function resolveCheckedOutPath(destDir, relPath, original) {
|
|
110
|
-
const safeBase = resolveSafeBaseDir(destDir);
|
|
111
|
-
const outPath = path.resolve(destDir, relPath);
|
|
112
|
-
if (!outPath.startsWith(safeBase)) {
|
|
113
|
-
throw new Error(`archive entry escapes destination: ${original}`);
|
|
114
|
-
}
|
|
115
|
-
return outPath;
|
|
116
|
-
}
|
|
117
84
|
function clampLimit(value) {
|
|
118
85
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
119
86
|
return undefined;
|
|
@@ -181,6 +148,80 @@ function createExtractBudgetTransform(params) {
|
|
|
181
148
|
},
|
|
182
149
|
});
|
|
183
150
|
}
|
|
151
|
+
function symlinkTraversalError(originalPath) {
|
|
152
|
+
return new ArchiveSecurityError("destination-symlink-traversal", `${ERROR_ARCHIVE_ENTRY_TRAVERSES_SYMLINK}: ${originalPath}`);
|
|
153
|
+
}
|
|
154
|
+
async function assertDestinationDirReady(destDir) {
|
|
155
|
+
const stat = await fs.lstat(destDir);
|
|
156
|
+
if (stat.isSymbolicLink()) {
|
|
157
|
+
throw new ArchiveSecurityError("destination-symlink", "archive destination is a symlink");
|
|
158
|
+
}
|
|
159
|
+
if (!stat.isDirectory()) {
|
|
160
|
+
throw new ArchiveSecurityError("destination-not-directory", "archive destination is not a directory");
|
|
161
|
+
}
|
|
162
|
+
return await fs.realpath(destDir);
|
|
163
|
+
}
|
|
164
|
+
async function assertNoSymlinkTraversal(params) {
|
|
165
|
+
const parts = params.relPath.split("/").filter(Boolean);
|
|
166
|
+
let current = path.resolve(params.rootDir);
|
|
167
|
+
for (const part of parts) {
|
|
168
|
+
current = path.join(current, part);
|
|
169
|
+
let stat;
|
|
170
|
+
try {
|
|
171
|
+
stat = await fs.lstat(current);
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
if (isNotFoundPathError(err)) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
throw err;
|
|
178
|
+
}
|
|
179
|
+
if (stat.isSymbolicLink()) {
|
|
180
|
+
throw symlinkTraversalError(params.originalPath);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async function assertResolvedInsideDestination(params) {
|
|
185
|
+
let resolved;
|
|
186
|
+
try {
|
|
187
|
+
resolved = await fs.realpath(params.targetPath);
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
if (isNotFoundPathError(err)) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
throw err;
|
|
194
|
+
}
|
|
195
|
+
if (!isPathInside(params.destinationRealDir, resolved)) {
|
|
196
|
+
throw symlinkTraversalError(params.originalPath);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
async function openZipOutputFile(outPath, originalPath) {
|
|
200
|
+
try {
|
|
201
|
+
return await fs.open(outPath, OPEN_WRITE_FLAGS, 0o666);
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
if (isSymlinkOpenError(err)) {
|
|
205
|
+
throw symlinkTraversalError(originalPath);
|
|
206
|
+
}
|
|
207
|
+
throw err;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
async function cleanupPartialRegularFile(filePath) {
|
|
211
|
+
let stat;
|
|
212
|
+
try {
|
|
213
|
+
stat = await fs.lstat(filePath);
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
if (isNotFoundPathError(err)) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
throw err;
|
|
220
|
+
}
|
|
221
|
+
if (stat.isFile()) {
|
|
222
|
+
await fs.unlink(filePath).catch(() => undefined);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
184
225
|
async function readZipEntryStream(entry) {
|
|
185
226
|
if (typeof entry.nodeStream === "function") {
|
|
186
227
|
return entry.nodeStream();
|
|
@@ -189,8 +230,68 @@ async function readZipEntryStream(entry) {
|
|
|
189
230
|
const buf = await entry.async("nodebuffer");
|
|
190
231
|
return Readable.from(buf);
|
|
191
232
|
}
|
|
233
|
+
function resolveZipOutputPath(params) {
|
|
234
|
+
validateArchiveEntryPath(params.entryPath);
|
|
235
|
+
const relPath = stripArchivePath(params.entryPath, params.strip);
|
|
236
|
+
if (!relPath) {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
validateArchiveEntryPath(relPath);
|
|
240
|
+
return {
|
|
241
|
+
relPath,
|
|
242
|
+
outPath: resolveArchiveOutputPath({
|
|
243
|
+
rootDir: params.destinationDir,
|
|
244
|
+
relPath,
|
|
245
|
+
originalPath: params.entryPath,
|
|
246
|
+
}),
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
async function prepareZipOutputPath(params) {
|
|
250
|
+
await assertNoSymlinkTraversal({
|
|
251
|
+
rootDir: params.destinationDir,
|
|
252
|
+
relPath: params.relPath,
|
|
253
|
+
originalPath: params.originalPath,
|
|
254
|
+
});
|
|
255
|
+
if (params.isDirectory) {
|
|
256
|
+
await fs.mkdir(params.outPath, { recursive: true });
|
|
257
|
+
await assertResolvedInsideDestination({
|
|
258
|
+
destinationRealDir: params.destinationRealDir,
|
|
259
|
+
targetPath: params.outPath,
|
|
260
|
+
originalPath: params.originalPath,
|
|
261
|
+
});
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const parentDir = path.dirname(params.outPath);
|
|
265
|
+
await fs.mkdir(parentDir, { recursive: true });
|
|
266
|
+
await assertResolvedInsideDestination({
|
|
267
|
+
destinationRealDir: params.destinationRealDir,
|
|
268
|
+
targetPath: parentDir,
|
|
269
|
+
originalPath: params.originalPath,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
async function writeZipFileEntry(params) {
|
|
273
|
+
const handle = await openZipOutputFile(params.outPath, params.entry.name);
|
|
274
|
+
params.budget.startEntry();
|
|
275
|
+
const readable = await readZipEntryStream(params.entry);
|
|
276
|
+
const writable = handle.createWriteStream();
|
|
277
|
+
try {
|
|
278
|
+
await pipeline(readable, createExtractBudgetTransform({ onChunkBytes: params.budget.addBytes }), writable);
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
281
|
+
await cleanupPartialRegularFile(params.outPath).catch(() => undefined);
|
|
282
|
+
throw err;
|
|
283
|
+
}
|
|
284
|
+
// Best-effort permission restore for zip entries created on unix.
|
|
285
|
+
if (typeof params.entry.unixPermissions === "number") {
|
|
286
|
+
const mode = params.entry.unixPermissions & 0o777;
|
|
287
|
+
if (mode !== 0) {
|
|
288
|
+
await fs.chmod(params.outPath, mode).catch(() => undefined);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
192
292
|
async function extractZip(params) {
|
|
193
293
|
const limits = resolveExtractLimits(params.limits);
|
|
294
|
+
const destinationRealDir = await assertDestinationDirReady(params.destDir);
|
|
194
295
|
const stat = await fs.stat(params.archivePath);
|
|
195
296
|
if (stat.size > limits.maxArchiveBytes) {
|
|
196
297
|
throw new Error(ERROR_ARCHIVE_SIZE_EXCEEDS_LIMIT);
|
|
@@ -202,34 +303,30 @@ async function extractZip(params) {
|
|
|
202
303
|
assertArchiveEntryCountWithinLimit(entries.length, limits);
|
|
203
304
|
const budget = createByteBudgetTracker(limits);
|
|
204
305
|
for (const entry of entries) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
306
|
+
const output = resolveZipOutputPath({
|
|
307
|
+
entryPath: entry.name,
|
|
308
|
+
strip,
|
|
309
|
+
destinationDir: params.destDir,
|
|
310
|
+
});
|
|
311
|
+
if (!output) {
|
|
208
312
|
continue;
|
|
209
313
|
}
|
|
210
|
-
|
|
211
|
-
|
|
314
|
+
await prepareZipOutputPath({
|
|
315
|
+
destinationDir: params.destDir,
|
|
316
|
+
destinationRealDir,
|
|
317
|
+
relPath: output.relPath,
|
|
318
|
+
outPath: output.outPath,
|
|
319
|
+
originalPath: entry.name,
|
|
320
|
+
isDirectory: entry.dir,
|
|
321
|
+
});
|
|
212
322
|
if (entry.dir) {
|
|
213
|
-
await fs.mkdir(outPath, { recursive: true });
|
|
214
323
|
continue;
|
|
215
324
|
}
|
|
216
|
-
await
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
catch (err) {
|
|
223
|
-
await fs.unlink(outPath).catch(() => undefined);
|
|
224
|
-
throw err;
|
|
225
|
-
}
|
|
226
|
-
// Best-effort permission restore for zip entries created on unix.
|
|
227
|
-
if (typeof entry.unixPermissions === "number") {
|
|
228
|
-
const mode = entry.unixPermissions & 0o777;
|
|
229
|
-
if (mode !== 0) {
|
|
230
|
-
await fs.chmod(outPath, mode).catch(() => undefined);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
325
|
+
await writeZipFileEntry({
|
|
326
|
+
entry,
|
|
327
|
+
outPath: output.outPath,
|
|
328
|
+
budget,
|
|
329
|
+
});
|
|
233
330
|
}
|
|
234
331
|
}
|
|
235
332
|
function readTarEntryInfo(entry) {
|
|
@@ -275,7 +372,11 @@ export async function extractArchive(params) {
|
|
|
275
372
|
return;
|
|
276
373
|
}
|
|
277
374
|
validateArchiveEntryPath(relPath);
|
|
278
|
-
|
|
375
|
+
resolveArchiveOutputPath({
|
|
376
|
+
rootDir: params.destDir,
|
|
377
|
+
relPath,
|
|
378
|
+
originalPath: info.path,
|
|
379
|
+
});
|
|
279
380
|
if (info.type === "SymbolicLink" ||
|
|
280
381
|
info.type === "Link" ||
|
|
281
382
|
info.type === "BlockDevice" ||
|
|
@@ -11,7 +11,10 @@ export function resolveControlUiDistIndexPathForRoot(root) {
|
|
|
11
11
|
export async function resolveControlUiDistIndexHealth(opts = {}) {
|
|
12
12
|
const indexPath = opts.root
|
|
13
13
|
? resolveControlUiDistIndexPathForRoot(opts.root)
|
|
14
|
-
: await resolveControlUiDistIndexPath(
|
|
14
|
+
: await resolveControlUiDistIndexPath({
|
|
15
|
+
argv1: opts.argv1 ?? process.argv[1],
|
|
16
|
+
moduleUrl: opts.moduleUrl,
|
|
17
|
+
});
|
|
15
18
|
return {
|
|
16
19
|
indexPath,
|
|
17
20
|
exists: Boolean(indexPath && fs.existsSync(indexPath)),
|
|
@@ -44,7 +47,9 @@ export function resolveControlUiRepoRoot(argv1 = process.argv[1]) {
|
|
|
44
47
|
}
|
|
45
48
|
return null;
|
|
46
49
|
}
|
|
47
|
-
export async function resolveControlUiDistIndexPath(
|
|
50
|
+
export async function resolveControlUiDistIndexPath(argv1OrOpts) {
|
|
51
|
+
const argv1 = typeof argv1OrOpts === "string" ? argv1OrOpts : (argv1OrOpts?.argv1 ?? process.argv[1]);
|
|
52
|
+
const moduleUrl = typeof argv1OrOpts === "object" ? argv1OrOpts?.moduleUrl : undefined;
|
|
48
53
|
if (!argv1) {
|
|
49
54
|
return null;
|
|
50
55
|
}
|
|
@@ -54,7 +59,7 @@ export async function resolveControlUiDistIndexPath(argv1 = process.argv[1]) {
|
|
|
54
59
|
if (path.basename(distDir) === "dist") {
|
|
55
60
|
return path.join(distDir, "control-ui", "index.html");
|
|
56
61
|
}
|
|
57
|
-
const packageRoot = await resolvePoolBotPackageRoot({ argv1: normalized });
|
|
62
|
+
const packageRoot = await resolvePoolBotPackageRoot({ argv1: normalized, moduleUrl });
|
|
58
63
|
if (packageRoot) {
|
|
59
64
|
return path.join(packageRoot, "dist", "control-ui", "index.html");
|
|
60
65
|
}
|
|
@@ -64,16 +69,19 @@ export async function resolveControlUiDistIndexPath(argv1 = process.argv[1]) {
|
|
|
64
69
|
for (let i = 0; i < 8; i++) {
|
|
65
70
|
const pkgJsonPath = path.join(dir, "package.json");
|
|
66
71
|
const indexPath = path.join(dir, "dist", "control-ui", "index.html");
|
|
67
|
-
if (fs.existsSync(pkgJsonPath)
|
|
72
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
68
73
|
try {
|
|
69
74
|
const raw = fs.readFileSync(pkgJsonPath, "utf-8");
|
|
70
75
|
const parsed = JSON.parse(raw);
|
|
71
76
|
if (parsed.name === "poolbot") {
|
|
72
|
-
return indexPath;
|
|
77
|
+
return fs.existsSync(indexPath) ? indexPath : null;
|
|
73
78
|
}
|
|
79
|
+
// Stop at the first package boundary to avoid resolving through unrelated ancestors.
|
|
80
|
+
return null;
|
|
74
81
|
}
|
|
75
82
|
catch {
|
|
76
|
-
// Invalid package.json
|
|
83
|
+
// Invalid package.json at package boundary; abort fallback resolution.
|
|
84
|
+
return null;
|
|
77
85
|
}
|
|
78
86
|
}
|
|
79
87
|
const parent = path.dirname(dir);
|