@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
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { readChannelAllowFromStore } from "../pairing/pairing-store.js";
|
|
2
|
+
import { normalizeStringEntries } from "../shared/string-normalization.js";
|
|
3
|
+
export function resolveEffectiveAllowFromLists(params) {
|
|
4
|
+
const configAllowFrom = normalizeStringEntries(Array.isArray(params.allowFrom) ? params.allowFrom : undefined);
|
|
5
|
+
const configGroupAllowFrom = normalizeStringEntries(Array.isArray(params.groupAllowFrom) ? params.groupAllowFrom : undefined);
|
|
6
|
+
const storeAllowFrom = params.dmPolicy === "allowlist"
|
|
7
|
+
? []
|
|
8
|
+
: normalizeStringEntries(Array.isArray(params.storeAllowFrom) ? params.storeAllowFrom : undefined);
|
|
9
|
+
const effectiveAllowFrom = normalizeStringEntries([...configAllowFrom, ...storeAllowFrom]);
|
|
10
|
+
const groupBase = configGroupAllowFrom.length > 0 ? configGroupAllowFrom : configAllowFrom;
|
|
11
|
+
const effectiveGroupAllowFrom = normalizeStringEntries([...groupBase, ...storeAllowFrom]);
|
|
12
|
+
return { effectiveAllowFrom, effectiveGroupAllowFrom };
|
|
13
|
+
}
|
|
14
|
+
export function resolveDmGroupAccessDecision(params) {
|
|
15
|
+
const dmPolicy = params.dmPolicy ?? "pairing";
|
|
16
|
+
const groupPolicy = params.groupPolicy ?? "allowlist";
|
|
17
|
+
const effectiveAllowFrom = normalizeStringEntries(params.effectiveAllowFrom);
|
|
18
|
+
const effectiveGroupAllowFrom = normalizeStringEntries(params.effectiveGroupAllowFrom);
|
|
19
|
+
if (params.isGroup) {
|
|
20
|
+
if (groupPolicy === "disabled") {
|
|
21
|
+
return { decision: "block", reason: "groupPolicy=disabled" };
|
|
22
|
+
}
|
|
23
|
+
if (groupPolicy === "allowlist") {
|
|
24
|
+
if (effectiveGroupAllowFrom.length === 0) {
|
|
25
|
+
return { decision: "block", reason: "groupPolicy=allowlist (empty allowlist)" };
|
|
26
|
+
}
|
|
27
|
+
if (!params.isSenderAllowed(effectiveGroupAllowFrom)) {
|
|
28
|
+
return { decision: "block", reason: "groupPolicy=allowlist (not allowlisted)" };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return { decision: "allow", reason: `groupPolicy=${groupPolicy}` };
|
|
32
|
+
}
|
|
33
|
+
if (dmPolicy === "disabled") {
|
|
34
|
+
return { decision: "block", reason: "dmPolicy=disabled" };
|
|
35
|
+
}
|
|
36
|
+
if (dmPolicy === "open") {
|
|
37
|
+
return { decision: "allow", reason: "dmPolicy=open" };
|
|
38
|
+
}
|
|
39
|
+
if (params.isSenderAllowed(effectiveAllowFrom)) {
|
|
40
|
+
return { decision: "allow", reason: `dmPolicy=${dmPolicy} (allowlisted)` };
|
|
41
|
+
}
|
|
42
|
+
if (dmPolicy === "pairing") {
|
|
43
|
+
return { decision: "pairing", reason: "dmPolicy=pairing (not allowlisted)" };
|
|
44
|
+
}
|
|
45
|
+
return { decision: "block", reason: `dmPolicy=${dmPolicy} (not allowlisted)` };
|
|
46
|
+
}
|
|
47
|
+
export async function resolveDmAllowState(params) {
|
|
48
|
+
const configAllowFrom = normalizeStringEntries(Array.isArray(params.allowFrom) ? params.allowFrom : undefined);
|
|
49
|
+
const hasWildcard = configAllowFrom.includes("*");
|
|
50
|
+
const storeAllowFrom = await (params.readStore ?? readChannelAllowFromStore)(params.provider).catch(() => []);
|
|
51
|
+
const normalizeEntry = params.normalizeEntry ?? ((value) => value);
|
|
52
|
+
const normalizedCfg = configAllowFrom
|
|
53
|
+
.filter((value) => value !== "*")
|
|
54
|
+
.map((value) => normalizeEntry(value))
|
|
55
|
+
.map((value) => value.trim())
|
|
56
|
+
.filter(Boolean);
|
|
57
|
+
const normalizedStore = storeAllowFrom
|
|
58
|
+
.map((value) => normalizeEntry(value))
|
|
59
|
+
.map((value) => value.trim())
|
|
60
|
+
.filter(Boolean);
|
|
61
|
+
const allowCount = Array.from(new Set([...normalizedCfg, ...normalizedStore])).length;
|
|
62
|
+
return {
|
|
63
|
+
configAllowFrom,
|
|
64
|
+
hasWildcard,
|
|
65
|
+
allowCount,
|
|
66
|
+
isMultiUserDm: hasWildcard || allowCount > 1,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
1
2
|
/**
|
|
2
3
|
* Security utilities for handling untrusted external content.
|
|
3
4
|
*
|
|
@@ -40,9 +41,20 @@ export function detectSuspiciousPatterns(content) {
|
|
|
40
41
|
/**
|
|
41
42
|
* Unique boundary markers for external content.
|
|
42
43
|
* Using XML-style tags that are unlikely to appear in legitimate content.
|
|
44
|
+
* Each wrapper gets a unique random ID to prevent spoofing attacks where
|
|
45
|
+
* malicious content injects fake boundary markers.
|
|
43
46
|
*/
|
|
44
|
-
const
|
|
45
|
-
const
|
|
47
|
+
const EXTERNAL_CONTENT_START_NAME = "EXTERNAL_UNTRUSTED_CONTENT";
|
|
48
|
+
const EXTERNAL_CONTENT_END_NAME = "END_EXTERNAL_UNTRUSTED_CONTENT";
|
|
49
|
+
function createExternalContentMarkerId() {
|
|
50
|
+
return randomBytes(8).toString("hex");
|
|
51
|
+
}
|
|
52
|
+
function createExternalContentStartMarker(id) {
|
|
53
|
+
return `<<<${EXTERNAL_CONTENT_START_NAME} id="${id}">>>`;
|
|
54
|
+
}
|
|
55
|
+
function createExternalContentEndMarker(id) {
|
|
56
|
+
return `<<<${EXTERNAL_CONTENT_END_NAME} id="${id}">>>`;
|
|
57
|
+
}
|
|
46
58
|
/**
|
|
47
59
|
* Security warning prepended to external content.
|
|
48
60
|
*/
|
|
@@ -62,14 +74,28 @@ const EXTERNAL_SOURCE_LABELS = {
|
|
|
62
74
|
email: "Email",
|
|
63
75
|
webhook: "Webhook",
|
|
64
76
|
api: "API",
|
|
77
|
+
browser: "Browser",
|
|
65
78
|
channel_metadata: "Channel metadata",
|
|
66
79
|
web_search: "Web Search",
|
|
67
80
|
web_fetch: "Web Fetch",
|
|
68
81
|
unknown: "External",
|
|
69
82
|
};
|
|
70
83
|
const FULLWIDTH_ASCII_OFFSET = 0xfee0;
|
|
71
|
-
|
|
72
|
-
const
|
|
84
|
+
// Map of Unicode angle bracket homoglyphs to their ASCII equivalents.
|
|
85
|
+
const ANGLE_BRACKET_MAP = {
|
|
86
|
+
0xff1c: "<", // fullwidth <
|
|
87
|
+
0xff1e: ">", // fullwidth >
|
|
88
|
+
0x2329: "<", // left-pointing angle bracket
|
|
89
|
+
0x232a: ">", // right-pointing angle bracket
|
|
90
|
+
0x3008: "<", // CJK left angle bracket
|
|
91
|
+
0x3009: ">", // CJK right angle bracket
|
|
92
|
+
0x2039: "<", // single left-pointing angle quotation mark
|
|
93
|
+
0x203a: ">", // single right-pointing angle quotation mark
|
|
94
|
+
0x27e8: "<", // mathematical left angle bracket
|
|
95
|
+
0x27e9: ">", // mathematical right angle bracket
|
|
96
|
+
0xfe64: "<", // small less-than sign
|
|
97
|
+
0xfe65: ">", // small greater-than sign
|
|
98
|
+
};
|
|
73
99
|
function foldMarkerChar(char) {
|
|
74
100
|
const code = char.charCodeAt(0);
|
|
75
101
|
if (code >= 0xff21 && code <= 0xff3a) {
|
|
@@ -78,16 +104,14 @@ function foldMarkerChar(char) {
|
|
|
78
104
|
if (code >= 0xff41 && code <= 0xff5a) {
|
|
79
105
|
return String.fromCharCode(code - FULLWIDTH_ASCII_OFFSET);
|
|
80
106
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (code === FULLWIDTH_RIGHT_ANGLE) {
|
|
85
|
-
return ">";
|
|
107
|
+
const bracket = ANGLE_BRACKET_MAP[code];
|
|
108
|
+
if (bracket) {
|
|
109
|
+
return bracket;
|
|
86
110
|
}
|
|
87
111
|
return char;
|
|
88
112
|
}
|
|
89
113
|
function foldMarkerText(input) {
|
|
90
|
-
return input.replace(/[\uFF21-\uFF3A\uFF41-\uFF5A\uFF1C\uFF1E]/g, (char) => foldMarkerChar(char));
|
|
114
|
+
return input.replace(/[\uFF21-\uFF3A\uFF41-\uFF5A\uFF1C\uFF1E\u2329\u232A\u3008\u3009\u2039\u203A\u27E8\u27E9\uFE64\uFE65]/g, (char) => foldMarkerChar(char));
|
|
91
115
|
}
|
|
92
116
|
function replaceMarkers(content) {
|
|
93
117
|
const folded = foldMarkerText(content);
|
|
@@ -95,9 +119,16 @@ function replaceMarkers(content) {
|
|
|
95
119
|
return content;
|
|
96
120
|
}
|
|
97
121
|
const replacements = [];
|
|
122
|
+
// Match markers with or without id attribute (handles both legacy and spoofed markers)
|
|
98
123
|
const patterns = [
|
|
99
|
-
{
|
|
100
|
-
|
|
124
|
+
{
|
|
125
|
+
regex: /<<<EXTERNAL_UNTRUSTED_CONTENT(?:\s+id="[^"]{1,128}")?\s*>>>/gi,
|
|
126
|
+
value: "[[MARKER_SANITIZED]]",
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
regex: /<<<END_EXTERNAL_UNTRUSTED_CONTENT(?:\s+id="[^"]{1,128}")?\s*>>>/gi,
|
|
130
|
+
value: "[[END_MARKER_SANITIZED]]",
|
|
131
|
+
},
|
|
101
132
|
];
|
|
102
133
|
for (const pattern of patterns) {
|
|
103
134
|
pattern.regex.lastIndex = 0;
|
|
@@ -156,13 +187,14 @@ export function wrapExternalContent(content, options) {
|
|
|
156
187
|
}
|
|
157
188
|
const metadata = metadataLines.join("\n");
|
|
158
189
|
const warningBlock = includeWarning ? `${EXTERNAL_CONTENT_WARNING}\n\n` : "";
|
|
190
|
+
const markerId = createExternalContentMarkerId();
|
|
159
191
|
return [
|
|
160
192
|
warningBlock,
|
|
161
|
-
|
|
193
|
+
createExternalContentStartMarker(markerId),
|
|
162
194
|
metadata,
|
|
163
195
|
"---",
|
|
164
196
|
sanitized,
|
|
165
|
-
|
|
197
|
+
createExternalContentEndMarker(markerId),
|
|
166
198
|
].join("\n");
|
|
167
199
|
}
|
|
168
200
|
/**
|
package/dist/security/fix.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import
|
|
3
|
+
import { resolveDefaultAgentId } from "../agents/agent-scope.js";
|
|
4
4
|
import { createConfigIO } from "../config/config.js";
|
|
5
|
+
import { collectIncludePathsRecursive } from "../config/includes-scan.js";
|
|
5
6
|
import { resolveConfigPath, resolveOAuthDir, resolveStateDir } from "../config/paths.js";
|
|
6
|
-
import { resolveDefaultAgentId } from "../agents/agent-scope.js";
|
|
7
|
-
import { INCLUDE_KEY, MAX_INCLUDE_DEPTH } from "../config/includes.js";
|
|
8
|
-
import { normalizeAgentId } from "../routing/session-key.js";
|
|
9
7
|
import { readChannelAllowFromStore } from "../pairing/pairing-store.js";
|
|
10
8
|
import { runExec } from "../process/exec.js";
|
|
9
|
+
import { normalizeAgentId } from "../routing/session-key.js";
|
|
11
10
|
import { createIcaclsResetCommand, formatIcaclsResetCommand } from "./windows-acl.js";
|
|
12
11
|
async function safeChmod(params) {
|
|
13
12
|
try {
|
|
@@ -144,11 +143,13 @@ async function safeAclReset(params) {
|
|
|
144
143
|
}
|
|
145
144
|
}
|
|
146
145
|
function setGroupPolicyAllowlist(params) {
|
|
147
|
-
if (!params.cfg.channels)
|
|
146
|
+
if (!params.cfg.channels) {
|
|
148
147
|
return;
|
|
148
|
+
}
|
|
149
149
|
const section = params.cfg.channels[params.channel];
|
|
150
|
-
if (!section || typeof section !== "object")
|
|
150
|
+
if (!section || typeof section !== "object") {
|
|
151
151
|
return;
|
|
152
|
+
}
|
|
152
153
|
const topPolicy = section.groupPolicy;
|
|
153
154
|
if (topPolicy === "open") {
|
|
154
155
|
section.groupPolicy = "allowlist";
|
|
@@ -156,13 +157,16 @@ function setGroupPolicyAllowlist(params) {
|
|
|
156
157
|
params.policyFlips.add(`channels.${params.channel}.`);
|
|
157
158
|
}
|
|
158
159
|
const accounts = section.accounts;
|
|
159
|
-
if (!accounts || typeof accounts !== "object")
|
|
160
|
+
if (!accounts || typeof accounts !== "object") {
|
|
160
161
|
return;
|
|
162
|
+
}
|
|
161
163
|
for (const [accountId, accountValue] of Object.entries(accounts)) {
|
|
162
|
-
if (!accountId)
|
|
164
|
+
if (!accountId) {
|
|
163
165
|
continue;
|
|
164
|
-
|
|
166
|
+
}
|
|
167
|
+
if (!accountValue || typeof accountValue !== "object") {
|
|
165
168
|
continue;
|
|
169
|
+
}
|
|
166
170
|
const account = accountValue;
|
|
167
171
|
if (account.groupPolicy === "open") {
|
|
168
172
|
account.groupPolicy = "allowlist";
|
|
@@ -173,29 +177,36 @@ function setGroupPolicyAllowlist(params) {
|
|
|
173
177
|
}
|
|
174
178
|
function setWhatsAppGroupAllowFromFromStore(params) {
|
|
175
179
|
const section = params.cfg.channels?.whatsapp;
|
|
176
|
-
if (!section || typeof section !== "object")
|
|
180
|
+
if (!section || typeof section !== "object") {
|
|
177
181
|
return;
|
|
178
|
-
|
|
182
|
+
}
|
|
183
|
+
if (params.storeAllowFrom.length === 0) {
|
|
179
184
|
return;
|
|
185
|
+
}
|
|
180
186
|
const maybeApply = (prefix, obj) => {
|
|
181
|
-
if (!params.policyFlips.has(prefix))
|
|
187
|
+
if (!params.policyFlips.has(prefix)) {
|
|
182
188
|
return;
|
|
189
|
+
}
|
|
183
190
|
const allowFrom = Array.isArray(obj.allowFrom) ? obj.allowFrom : [];
|
|
184
191
|
const groupAllowFrom = Array.isArray(obj.groupAllowFrom) ? obj.groupAllowFrom : [];
|
|
185
|
-
if (allowFrom.length > 0)
|
|
192
|
+
if (allowFrom.length > 0) {
|
|
186
193
|
return;
|
|
187
|
-
|
|
194
|
+
}
|
|
195
|
+
if (groupAllowFrom.length > 0) {
|
|
188
196
|
return;
|
|
197
|
+
}
|
|
189
198
|
obj.groupAllowFrom = params.storeAllowFrom;
|
|
190
199
|
params.changes.push(`${prefix}groupAllowFrom=pairing-store`);
|
|
191
200
|
};
|
|
192
201
|
maybeApply("channels.whatsapp.", section);
|
|
193
202
|
const accounts = section.accounts;
|
|
194
|
-
if (!accounts || typeof accounts !== "object")
|
|
203
|
+
if (!accounts || typeof accounts !== "object") {
|
|
195
204
|
return;
|
|
205
|
+
}
|
|
196
206
|
for (const [accountId, accountValue] of Object.entries(accounts)) {
|
|
197
|
-
if (!accountValue || typeof accountValue !== "object")
|
|
207
|
+
if (!accountValue || typeof accountValue !== "object") {
|
|
198
208
|
continue;
|
|
209
|
+
}
|
|
199
210
|
const account = accountValue;
|
|
200
211
|
maybeApply(`channels.whatsapp.accounts.${accountId}.`, account);
|
|
201
212
|
}
|
|
@@ -221,80 +232,17 @@ function applyConfigFixes(params) {
|
|
|
221
232
|
}
|
|
222
233
|
return { cfg: next, changes, policyFlips };
|
|
223
234
|
}
|
|
224
|
-
function listDirectIncludes(parsed) {
|
|
225
|
-
const out = [];
|
|
226
|
-
const visit = (value) => {
|
|
227
|
-
if (!value)
|
|
228
|
-
return;
|
|
229
|
-
if (Array.isArray(value)) {
|
|
230
|
-
for (const item of value)
|
|
231
|
-
visit(item);
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
if (typeof value !== "object")
|
|
235
|
-
return;
|
|
236
|
-
const rec = value;
|
|
237
|
-
const includeVal = rec[INCLUDE_KEY];
|
|
238
|
-
if (typeof includeVal === "string")
|
|
239
|
-
out.push(includeVal);
|
|
240
|
-
else if (Array.isArray(includeVal)) {
|
|
241
|
-
for (const item of includeVal) {
|
|
242
|
-
if (typeof item === "string")
|
|
243
|
-
out.push(item);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
for (const v of Object.values(rec))
|
|
247
|
-
visit(v);
|
|
248
|
-
};
|
|
249
|
-
visit(parsed);
|
|
250
|
-
return out;
|
|
251
|
-
}
|
|
252
|
-
function resolveIncludePath(baseConfigPath, includePath) {
|
|
253
|
-
return path.normalize(path.isAbsolute(includePath)
|
|
254
|
-
? includePath
|
|
255
|
-
: path.resolve(path.dirname(baseConfigPath), includePath));
|
|
256
|
-
}
|
|
257
|
-
async function collectIncludePathsRecursive(params) {
|
|
258
|
-
const visited = new Set();
|
|
259
|
-
const result = [];
|
|
260
|
-
const walk = async (basePath, parsed, depth) => {
|
|
261
|
-
if (depth > MAX_INCLUDE_DEPTH)
|
|
262
|
-
return;
|
|
263
|
-
for (const raw of listDirectIncludes(parsed)) {
|
|
264
|
-
const resolved = resolveIncludePath(basePath, raw);
|
|
265
|
-
if (visited.has(resolved))
|
|
266
|
-
continue;
|
|
267
|
-
visited.add(resolved);
|
|
268
|
-
result.push(resolved);
|
|
269
|
-
const rawText = await fs.readFile(resolved, "utf-8").catch(() => null);
|
|
270
|
-
if (!rawText)
|
|
271
|
-
continue;
|
|
272
|
-
const nestedParsed = (() => {
|
|
273
|
-
try {
|
|
274
|
-
return JSON5.parse(rawText);
|
|
275
|
-
}
|
|
276
|
-
catch {
|
|
277
|
-
return null;
|
|
278
|
-
}
|
|
279
|
-
})();
|
|
280
|
-
if (nestedParsed) {
|
|
281
|
-
// eslint-disable-next-line no-await-in-loop
|
|
282
|
-
await walk(resolved, nestedParsed, depth + 1);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
await walk(params.configPath, params.parsed, 0);
|
|
287
|
-
return result;
|
|
288
|
-
}
|
|
289
235
|
async function chmodCredentialsAndAgentState(params) {
|
|
290
236
|
const credsDir = resolveOAuthDir(params.env, params.stateDir);
|
|
291
237
|
params.actions.push(await safeChmod({ path: credsDir, mode: 0o700, require: "dir" }));
|
|
292
238
|
const credsEntries = await fs.readdir(credsDir, { withFileTypes: true }).catch(() => []);
|
|
293
239
|
for (const entry of credsEntries) {
|
|
294
|
-
if (!entry.isFile())
|
|
240
|
+
if (!entry.isFile()) {
|
|
295
241
|
continue;
|
|
296
|
-
|
|
242
|
+
}
|
|
243
|
+
if (!entry.name.endsWith(".json")) {
|
|
297
244
|
continue;
|
|
245
|
+
}
|
|
298
246
|
const p = path.join(credsDir, entry.name);
|
|
299
247
|
// eslint-disable-next-line no-await-in-loop
|
|
300
248
|
params.actions.push(await safeChmod({ path: p, mode: 0o600, require: "file" }));
|
|
@@ -303,11 +251,13 @@ async function chmodCredentialsAndAgentState(params) {
|
|
|
303
251
|
ids.add(resolveDefaultAgentId(params.cfg));
|
|
304
252
|
const list = Array.isArray(params.cfg.agents?.list) ? params.cfg.agents?.list : [];
|
|
305
253
|
for (const agent of list ?? []) {
|
|
306
|
-
if (!agent || typeof agent !== "object")
|
|
254
|
+
if (!agent || typeof agent !== "object") {
|
|
307
255
|
continue;
|
|
256
|
+
}
|
|
308
257
|
const id = typeof agent.id === "string" ? agent.id.trim() : "";
|
|
309
|
-
if (id)
|
|
258
|
+
if (id) {
|
|
310
259
|
ids.add(id);
|
|
260
|
+
}
|
|
311
261
|
}
|
|
312
262
|
for (const agentId of ids) {
|
|
313
263
|
const normalizedAgentId = normalizeAgentId(agentId);
|
|
@@ -326,6 +276,20 @@ async function chmodCredentialsAndAgentState(params) {
|
|
|
326
276
|
const storePath = path.join(sessionsDir, "sessions.json");
|
|
327
277
|
// eslint-disable-next-line no-await-in-loop
|
|
328
278
|
params.actions.push(await params.applyPerms({ path: storePath, mode: 0o600, require: "file" }));
|
|
279
|
+
// Fix permissions on session transcript files (*.jsonl)
|
|
280
|
+
// eslint-disable-next-line no-await-in-loop
|
|
281
|
+
const sessionEntries = await fs.readdir(sessionsDir, { withFileTypes: true }).catch(() => []);
|
|
282
|
+
for (const entry of sessionEntries) {
|
|
283
|
+
if (!entry.isFile()) {
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
if (!entry.name.endsWith(".jsonl")) {
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
const p = path.join(sessionsDir, entry.name);
|
|
290
|
+
// eslint-disable-next-line no-await-in-loop
|
|
291
|
+
params.actions.push(await params.applyPerms({ path: p, mode: 0o600, require: "file" }));
|
|
292
|
+
}
|
|
329
293
|
}
|
|
330
294
|
}
|
|
331
295
|
export async function fixSecurityFootguns(opts) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
1
2
|
import path from "node:path";
|
|
2
3
|
export function isPathInside(basePath, candidatePath) {
|
|
3
4
|
const base = path.resolve(basePath);
|
|
@@ -5,6 +6,25 @@ export function isPathInside(basePath, candidatePath) {
|
|
|
5
6
|
const rel = path.relative(base, candidate);
|
|
6
7
|
return rel === "" || (!rel.startsWith(`..${path.sep}`) && rel !== ".." && !path.isAbsolute(rel));
|
|
7
8
|
}
|
|
9
|
+
function safeRealpathSync(filePath) {
|
|
10
|
+
try {
|
|
11
|
+
return fs.realpathSync(filePath);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function isPathInsideWithRealpath(basePath, candidatePath, opts) {
|
|
18
|
+
if (!isPathInside(basePath, candidatePath)) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
const baseReal = safeRealpathSync(basePath);
|
|
22
|
+
const candidateReal = safeRealpathSync(candidatePath);
|
|
23
|
+
if (!baseReal || !candidateReal) {
|
|
24
|
+
return opts?.requireRealpath !== true;
|
|
25
|
+
}
|
|
26
|
+
return isPathInside(baseReal, candidateReal);
|
|
27
|
+
}
|
|
8
28
|
export function extensionUsesSkippedScannerPath(entry) {
|
|
9
29
|
const segments = entry.split(/[\\/]+/).filter(Boolean);
|
|
10
30
|
return segments.some((segment) => segment === "node_modules" ||
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import { timingSafeEqual } from "node:crypto";
|
|
1
|
+
import { createHash, timingSafeEqual } from "node:crypto";
|
|
2
2
|
export function safeEqualSecret(provided, expected) {
|
|
3
3
|
if (typeof provided !== "string" || typeof expected !== "string") {
|
|
4
4
|
return false;
|
|
5
5
|
}
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
if (providedBuffer.length !== expectedBuffer.length) {
|
|
9
|
-
return false;
|
|
10
|
-
}
|
|
11
|
-
return timingSafeEqual(providedBuffer, expectedBuffer);
|
|
6
|
+
const hash = (s) => createHash("sha256").update(s).digest();
|
|
7
|
+
return timingSafeEqual(hash(provided), hash(expected));
|
|
12
8
|
}
|
|
@@ -19,8 +19,9 @@ const TRUSTED_SUFFIXES = ["\\administrators", "\\system"];
|
|
|
19
19
|
const normalize = (value) => value.trim().toLowerCase();
|
|
20
20
|
export function resolveWindowsUserPrincipal(env) {
|
|
21
21
|
const username = env?.USERNAME?.trim() || os.userInfo().username?.trim();
|
|
22
|
-
if (!username)
|
|
22
|
+
if (!username) {
|
|
23
23
|
return null;
|
|
24
|
+
}
|
|
24
25
|
const domain = env?.USERDOMAIN?.trim();
|
|
25
26
|
return domain ? `${domain}\\${username}` : username;
|
|
26
27
|
}
|
|
@@ -31,18 +32,21 @@ function buildTrustedPrincipals(env) {
|
|
|
31
32
|
trusted.add(normalize(principal));
|
|
32
33
|
const parts = principal.split("\\");
|
|
33
34
|
const userOnly = parts.at(-1);
|
|
34
|
-
if (userOnly)
|
|
35
|
+
if (userOnly) {
|
|
35
36
|
trusted.add(normalize(userOnly));
|
|
37
|
+
}
|
|
36
38
|
}
|
|
37
39
|
return trusted;
|
|
38
40
|
}
|
|
39
41
|
function classifyPrincipal(principal, env) {
|
|
40
42
|
const normalized = normalize(principal);
|
|
41
43
|
const trusted = buildTrustedPrincipals(env);
|
|
42
|
-
if (trusted.has(normalized) || TRUSTED_SUFFIXES.some((s) => normalized.endsWith(s)))
|
|
44
|
+
if (trusted.has(normalized) || TRUSTED_SUFFIXES.some((s) => normalized.endsWith(s))) {
|
|
43
45
|
return "trusted";
|
|
44
|
-
|
|
46
|
+
}
|
|
47
|
+
if (WORLD_PRINCIPALS.has(normalized) || WORLD_SUFFIXES.some((s) => normalized.endsWith(s))) {
|
|
45
48
|
return "world";
|
|
49
|
+
}
|
|
46
50
|
return "group";
|
|
47
51
|
}
|
|
48
52
|
function rightsFromTokens(tokens) {
|
|
@@ -59,8 +63,9 @@ export function parseIcaclsOutput(output, targetPath) {
|
|
|
59
63
|
const quotedLower = quotedTarget.toLowerCase();
|
|
60
64
|
for (const rawLine of output.split(/\r?\n/)) {
|
|
61
65
|
const line = rawLine.trimEnd();
|
|
62
|
-
if (!line.trim())
|
|
66
|
+
if (!line.trim()) {
|
|
63
67
|
continue;
|
|
68
|
+
}
|
|
64
69
|
const trimmed = line.trim();
|
|
65
70
|
const lower = trimmed.toLowerCase();
|
|
66
71
|
if (lower.startsWith("successfully processed") ||
|
|
@@ -76,22 +81,26 @@ export function parseIcaclsOutput(output, targetPath) {
|
|
|
76
81
|
else if (lower.startsWith(quotedLower)) {
|
|
77
82
|
entry = trimmed.slice(quotedTarget.length).trim();
|
|
78
83
|
}
|
|
79
|
-
if (!entry)
|
|
84
|
+
if (!entry) {
|
|
80
85
|
continue;
|
|
86
|
+
}
|
|
81
87
|
const idx = entry.indexOf(":");
|
|
82
|
-
if (idx === -1)
|
|
88
|
+
if (idx === -1) {
|
|
83
89
|
continue;
|
|
90
|
+
}
|
|
84
91
|
const principal = entry.slice(0, idx).trim();
|
|
85
92
|
const rawRights = entry.slice(idx + 1).trim();
|
|
86
93
|
const tokens = rawRights
|
|
87
94
|
.match(/\(([^)]+)\)/g)
|
|
88
95
|
?.map((token) => token.slice(1, -1).trim())
|
|
89
96
|
.filter(Boolean) ?? [];
|
|
90
|
-
if (tokens.some((token) => token.toUpperCase() === "DENY"))
|
|
97
|
+
if (tokens.some((token) => token.toUpperCase() === "DENY")) {
|
|
91
98
|
continue;
|
|
99
|
+
}
|
|
92
100
|
const rights = tokens.filter((token) => !INHERIT_FLAGS.has(token.toUpperCase()));
|
|
93
|
-
if (rights.length === 0)
|
|
101
|
+
if (rights.length === 0) {
|
|
94
102
|
continue;
|
|
103
|
+
}
|
|
95
104
|
const { canRead, canWrite } = rightsFromTokens(rights);
|
|
96
105
|
entries.push({ principal, rights, rawRights, canRead, canWrite });
|
|
97
106
|
}
|
|
@@ -103,12 +112,15 @@ export function summarizeWindowsAcl(entries, env) {
|
|
|
103
112
|
const untrustedGroup = [];
|
|
104
113
|
for (const entry of entries) {
|
|
105
114
|
const classification = classifyPrincipal(entry.principal, env);
|
|
106
|
-
if (classification === "trusted")
|
|
115
|
+
if (classification === "trusted") {
|
|
107
116
|
trusted.push(entry);
|
|
108
|
-
|
|
117
|
+
}
|
|
118
|
+
else if (classification === "world") {
|
|
109
119
|
untrustedWorld.push(entry);
|
|
110
|
-
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
111
122
|
untrustedGroup.push(entry);
|
|
123
|
+
}
|
|
112
124
|
}
|
|
113
125
|
return { trusted, untrustedWorld, untrustedGroup };
|
|
114
126
|
}
|
|
@@ -133,11 +145,13 @@ export async function inspectWindowsAcl(targetPath, opts) {
|
|
|
133
145
|
}
|
|
134
146
|
}
|
|
135
147
|
export function formatWindowsAclSummary(summary) {
|
|
136
|
-
if (!summary.ok)
|
|
148
|
+
if (!summary.ok) {
|
|
137
149
|
return "unknown";
|
|
150
|
+
}
|
|
138
151
|
const untrusted = [...summary.untrustedWorld, ...summary.untrustedGroup];
|
|
139
|
-
if (untrusted.length === 0)
|
|
152
|
+
if (untrusted.length === 0) {
|
|
140
153
|
return "trusted-only";
|
|
154
|
+
}
|
|
141
155
|
return untrusted.map((entry) => `${entry.principal}:${entry.rawRights}`).join(", ");
|
|
142
156
|
}
|
|
143
157
|
export function formatIcaclsResetCommand(targetPath, opts) {
|
|
@@ -147,8 +161,9 @@ export function formatIcaclsResetCommand(targetPath, opts) {
|
|
|
147
161
|
}
|
|
148
162
|
export function createIcaclsResetCommand(targetPath, opts) {
|
|
149
163
|
const user = resolveWindowsUserPrincipal(opts.env);
|
|
150
|
-
if (!user)
|
|
164
|
+
if (!user) {
|
|
151
165
|
return null;
|
|
166
|
+
}
|
|
152
167
|
const grant = opts.isDir ? "(OI)(CI)F" : "F";
|
|
153
168
|
const args = [
|
|
154
169
|
targetPath,
|
|
@@ -23,3 +23,9 @@ export function evaluateEntryMetadataRequirements(params) {
|
|
|
23
23
|
configChecks,
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
|
+
export function evaluateEntryMetadataRequirementsForCurrentPlatform(params) {
|
|
27
|
+
return evaluateEntryMetadataRequirements({
|
|
28
|
+
...params,
|
|
29
|
+
localPlatform: process.platform,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -24,7 +24,7 @@ export function parseFrontmatterBool(value, fallback) {
|
|
|
24
24
|
const parsed = parseBooleanValue(value);
|
|
25
25
|
return parsed === undefined ? fallback : parsed;
|
|
26
26
|
}
|
|
27
|
-
export function
|
|
27
|
+
export function resolvePoolBotManifestBlock(params) {
|
|
28
28
|
const raw = getFrontmatterString(params.frontmatter, params.key ?? "metadata");
|
|
29
29
|
if (!raw) {
|
|
30
30
|
return undefined;
|
|
@@ -47,7 +47,7 @@ export function resolvePoolbotManifestBlock(params) {
|
|
|
47
47
|
return undefined;
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
-
export function
|
|
50
|
+
export function resolvePoolBotManifestRequires(metadataObj) {
|
|
51
51
|
const requiresRaw = typeof metadataObj.requires === "object" && metadataObj.requires !== null
|
|
52
52
|
? metadataObj.requires
|
|
53
53
|
: undefined;
|
|
@@ -61,16 +61,16 @@ export function resolvePoolbotManifestRequires(metadataObj) {
|
|
|
61
61
|
config: normalizeStringList(requiresRaw.config),
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
|
-
export function
|
|
64
|
+
export function resolvePoolBotManifestInstall(metadataObj, parseInstallSpec) {
|
|
65
65
|
const installRaw = Array.isArray(metadataObj.install) ? metadataObj.install : [];
|
|
66
66
|
return installRaw
|
|
67
67
|
.map((entry) => parseInstallSpec(entry))
|
|
68
68
|
.filter((entry) => Boolean(entry));
|
|
69
69
|
}
|
|
70
|
-
export function
|
|
70
|
+
export function resolvePoolBotManifestOs(metadataObj) {
|
|
71
71
|
return normalizeStringList(metadataObj.os);
|
|
72
72
|
}
|
|
73
|
-
export function
|
|
73
|
+
export function parsePoolBotManifestInstallBase(input, allowedKinds) {
|
|
74
74
|
if (!input || typeof input !== "object") {
|
|
75
75
|
return undefined;
|
|
76
76
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function asRecord(value) {
|
|
2
|
+
return typeof value === "object" && value !== null ? value : {};
|
|
3
|
+
}
|
|
4
|
+
export function parsePairingList(value) {
|
|
5
|
+
const obj = asRecord(value);
|
|
6
|
+
const pending = Array.isArray(obj.pending) ? obj.pending : [];
|
|
7
|
+
const paired = Array.isArray(obj.paired) ? obj.paired : [];
|
|
8
|
+
return { pending, paired };
|
|
9
|
+
}
|
|
10
|
+
export function parseNodeList(value) {
|
|
11
|
+
const obj = asRecord(value);
|
|
12
|
+
return Array.isArray(obj.nodes) ? obj.nodes : [];
|
|
13
|
+
}
|
|
@@ -39,14 +39,21 @@ export function resolveNodeIdFromCandidates(nodes, query) {
|
|
|
39
39
|
if (!q) {
|
|
40
40
|
throw new Error("node required");
|
|
41
41
|
}
|
|
42
|
-
const
|
|
43
|
-
if (
|
|
44
|
-
return
|
|
42
|
+
const rawMatches = resolveNodeMatches(nodes, q);
|
|
43
|
+
if (rawMatches.length === 1) {
|
|
44
|
+
return rawMatches[0]?.nodeId ?? "";
|
|
45
45
|
}
|
|
46
|
-
if (
|
|
46
|
+
if (rawMatches.length === 0) {
|
|
47
47
|
const known = listKnownNodes(nodes);
|
|
48
48
|
throw new Error(`unknown node: ${q}${known ? ` (known: ${known})` : ""}`);
|
|
49
49
|
}
|
|
50
|
+
// Re-pair/reinstall flows can leave multiple nodes with the same display name.
|
|
51
|
+
// Prefer a unique connected match when available.
|
|
52
|
+
const connectedMatches = rawMatches.filter((match) => match.connected === true);
|
|
53
|
+
const matches = connectedMatches.length > 0 ? connectedMatches : rawMatches;
|
|
54
|
+
if (matches.length === 1) {
|
|
55
|
+
return matches[0]?.nodeId ?? "";
|
|
56
|
+
}
|
|
50
57
|
throw new Error(`ambiguous node: ${q} (matches: ${matches
|
|
51
58
|
.map((n) => n.displayName || n.remoteIp || n.nodeId)
|
|
52
59
|
.join(", ")})`);
|