@poolzin/pool-bot 2026.2.17 → 2026.2.19
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 +25 -0
- package/dist/agents/agent-scope.js +4 -0
- package/dist/agents/announce-idempotency.js +14 -0
- package/dist/agents/auth-profiles.resolve-auth-profile-order.fixtures.js +23 -0
- package/dist/agents/bash-tools.exec-runtime.js +438 -0
- package/dist/agents/bash-tools.shared.js +6 -0
- package/dist/agents/cli-runner/reliability.js +61 -0
- package/dist/agents/cli-watchdog-defaults.js +11 -0
- package/dist/agents/command-poll-backoff.js +63 -0
- package/dist/agents/current-time.js +16 -0
- package/dist/agents/model-alias-lines.js +18 -0
- package/dist/agents/model-auth-label.js +61 -0
- package/dist/agents/models-config.e2e-harness.js +115 -0
- package/dist/agents/ollama-stream.js +11 -3
- package/dist/agents/openclaw-tools.js +135 -0
- package/dist/agents/pi-auth-json.js +118 -0
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +147 -0
- package/dist/agents/pi-embedded-subscribe.e2e-harness.js +90 -0
- package/dist/agents/pi-embedded-subscribe.handlers.compaction.js +63 -0
- package/dist/agents/pi-embedded-subscribe.handlers.tools.media.test-helpers.js +30 -0
- package/dist/agents/pi-extensions/session-manager-runtime-registry.js +23 -0
- package/dist/agents/pi-tools.js +2 -0
- package/dist/agents/queued-file-writer.js +22 -0
- package/dist/agents/sandbox/docker.js +133 -40
- package/dist/agents/sandbox/fs-bridge.js +146 -0
- package/dist/agents/sandbox/fs-paths.js +205 -0
- package/dist/agents/sandbox/hash.js +4 -0
- package/dist/agents/sandbox-paths.js +3 -0
- package/dist/agents/session-dirs.js +20 -0
- package/dist/agents/skills/filter.js +24 -0
- package/dist/agents/skills/tools-dir.js +9 -0
- package/dist/agents/skills-install-download.js +290 -0
- package/dist/agents/skills-install-output.js +30 -0
- package/dist/agents/skills-install.download-test-utils.js +36 -0
- package/dist/agents/skills.e2e-test-helpers.js +13 -0
- package/dist/agents/subagent-announce-queue.js +59 -15
- package/dist/agents/subagent-depth.js +137 -0
- package/dist/agents/subagent-registry.js +448 -96
- package/dist/agents/subagent-spawn.js +262 -0
- package/dist/agents/test-helpers/fast-tool-stubs.js +18 -0
- package/dist/agents/test-helpers/host-sandbox-fs-bridge.js +74 -0
- package/dist/agents/tool-display-common.js +782 -0
- package/dist/agents/tools/image-tool.js +1 -1
- package/dist/agents/tools/sessions-access.js +178 -0
- package/dist/agents/tools/sessions-resolution.js +206 -0
- package/dist/agents/tools/subagents-tool.js +616 -0
- package/dist/agents/workspace-dir.js +18 -0
- package/dist/agents/workspace-dirs.js +14 -0
- package/dist/agents/workspace.js +70 -0
- package/dist/auto-reply/heartbeat-reply-payload.js +18 -0
- package/dist/auto-reply/reply/commands-export-session.js +163 -0
- package/dist/auto-reply/reply/commands-mesh.js +245 -0
- package/dist/auto-reply/reply/commands-setunset.js +28 -0
- package/dist/auto-reply/reply/commands-slash-parse.js +31 -0
- package/dist/auto-reply/reply/commands-system-prompt.js +117 -0
- package/dist/auto-reply/reply/directive-handling.levels.js +17 -0
- package/dist/auto-reply/reply/directive-handling.params.js +1 -0
- package/dist/auto-reply/reply/directive-parsing.js +36 -0
- package/dist/auto-reply/reply/dispatcher-registry.js +43 -0
- package/dist/auto-reply/reply/elevated-unavailable.js +20 -0
- package/dist/auto-reply/reply/reply-delivery.js +92 -0
- package/dist/auto-reply/reply/session-reset-prompt.js +1 -0
- package/dist/auto-reply/reply/session-run-accounting.js +33 -0
- package/dist/auto-reply/reply.directive.directive-behavior.e2e-harness.js +115 -0
- package/dist/auto-reply/reply.directive.directive-behavior.e2e-mocks.js +12 -0
- package/dist/browser/bridge-auth-registry.js +26 -0
- package/dist/browser/client-actions-url.js +10 -0
- package/dist/browser/control-auth.js +73 -0
- package/dist/browser/csrf.js +64 -0
- package/dist/browser/http-auth.js +52 -0
- package/dist/browser/paths.js +37 -0
- package/dist/browser/proxy-files.js +32 -0
- package/dist/browser/pw-ai-state.js +7 -0
- package/dist/browser/resolved-config-refresh.js +42 -0
- package/dist/browser/routes/path-output.js +1 -0
- package/dist/browser/server-context.chrome-test-harness.js +20 -0
- package/dist/browser/server-middleware.js +31 -0
- package/dist/browser/test-port.js +16 -0
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/file-resolver.js +43 -0
- package/dist/channels/account-summary.js +19 -0
- package/dist/channels/draft-stream-loop.js +77 -0
- package/dist/channels/plugins/account-helpers.js +26 -0
- package/dist/channels/telegram/allow-from.js +10 -0
- package/dist/cli/browser-cli-resize.js +22 -0
- package/dist/cli/browser-cli-shared.js +8 -0
- package/dist/cli/clawbot-cli.js +5 -0
- package/dist/cli/completion-cli.js +566 -0
- package/dist/cli/config-cli.js +63 -5
- package/dist/cli/daemon-cli/lifecycle-core.js +256 -0
- package/dist/cli/daemon-cli/register-service-commands.js +60 -0
- package/dist/cli/daemon-cli-compat.js +80 -0
- package/dist/cli/nodes-cli/pairing-render.js +26 -0
- package/dist/cli/program/action-reparse.js +17 -0
- package/dist/cli/program/command-registry.js +17 -0
- package/dist/cli/program/program-context.js +8 -0
- package/dist/cli/program/register.subclis.js +7 -0
- package/dist/cli/program/routes.js +233 -0
- package/dist/cli/qr-cli.js +132 -0
- package/dist/cli/requirements-test-fixtures.js +17 -0
- package/dist/cli/respawn-policy.js +4 -0
- package/dist/cli/shared/parse-port.js +18 -0
- package/dist/cli/skills-cli.format.js +241 -0
- package/dist/cli/update-cli/progress.js +121 -0
- package/dist/cli/update-cli/restart-helper.js +108 -0
- package/dist/cli/update-cli/shared.js +196 -0
- package/dist/cli/update-cli/status.js +97 -0
- package/dist/cli/update-cli/suppress-deprecations.js +17 -0
- package/dist/cli/update-cli/update-command.js +506 -0
- package/dist/cli/update-cli/wizard.js +130 -0
- package/dist/cli/update-cli.js +3 -9
- package/dist/cli/windows-argv.js +69 -0
- package/dist/commands/auth-choice-legacy.js +20 -0
- package/dist/commands/auth-choice.apply-helpers.js +8 -0
- package/dist/commands/channel-test-helpers.js +19 -0
- package/dist/commands/cleanup-plan.js +10 -0
- package/dist/commands/cleanup-utils.js +7 -0
- package/dist/commands/config-validation.js +15 -0
- package/dist/commands/doctor-completion.js +112 -0
- package/dist/commands/doctor-memory-search.js +119 -0
- package/dist/commands/doctor-session-locks.js +73 -0
- package/dist/commands/doctor.e2e-harness.js +364 -0
- package/dist/commands/gateway-presence.js +19 -0
- package/dist/commands/model-default.js +35 -0
- package/dist/commands/models/fallbacks-shared.js +102 -0
- package/dist/commands/models/shared.js +24 -0
- package/dist/commands/onboard-auth.config-gateways.js +64 -0
- package/dist/commands/onboard-auth.config-litellm.js +45 -0
- package/dist/commands/onboard-auth.config-shared.js +116 -0
- package/dist/commands/onboard-config.js +16 -0
- package/dist/commands/onboard-non-interactive.test-helpers.js +31 -0
- package/dist/commands/onboard-provider-auth-flags.js +136 -0
- package/dist/commands/openai-codex-oauth.js +40 -0
- package/dist/commands/test-runtime-config-helpers.js +21 -0
- package/dist/commands/test-wizard-helpers.js +68 -0
- package/dist/commands/vllm-setup.js +66 -0
- package/dist/compat/legacy-names.js +2 -0
- package/dist/config/backup-rotation.js +19 -0
- package/dist/config/env-preserve.js +122 -0
- package/dist/config/includes-scan.js +78 -0
- package/dist/config/plugins-allowlist.js +13 -0
- package/dist/config/schema.help.js +256 -0
- package/dist/config/schema.hints.js +189 -0
- package/dist/config/schema.irc.js +20 -0
- package/dist/config/schema.labels.js +317 -0
- package/dist/config/sessions/delivery-info.js +40 -0
- package/dist/config/types.irc.js +1 -0
- package/dist/config/zod-schema.agent-model.js +10 -0
- package/dist/config/zod-schema.allowdeny.js +35 -0
- package/dist/config/zod-schema.sensitive.js +4 -0
- package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
- package/dist/cron/isolated-agent/skills-snapshot.js +26 -0
- package/dist/cron/isolated-agent/subagent-followup.js +127 -0
- package/dist/cron/isolated-agent.mocks.js +12 -0
- package/dist/cron/isolated-agent.test-setup.js +22 -0
- package/dist/cron/legacy-delivery.js +43 -0
- package/dist/cron/webhook-url.js +22 -0
- package/dist/daemon/arg-split.js +40 -0
- package/dist/daemon/exec-file.js +23 -0
- package/dist/daemon/output.js +6 -0
- package/dist/daemon/runtime-format.js +31 -0
- package/dist/daemon/schtasks-exec.js +4 -0
- package/dist/daemon/service-audit.js +22 -0
- package/dist/discord/client.js +41 -0
- package/dist/discord/components-registry.js +57 -0
- package/dist/discord/components.js +816 -0
- package/dist/discord/guilds.js +12 -0
- package/dist/discord/monitor/gateway-plugin.js +48 -0
- package/dist/discord/monitor/presence.js +30 -0
- package/dist/discord/send.components.js +115 -0
- package/dist/discord/send.shared.js +4 -0
- package/dist/discord/ui.js +26 -0
- package/dist/discord/voice-message.js +254 -0
- package/dist/gateway/agent-event-assistant-text.js +5 -0
- package/dist/gateway/agent-prompt.js +33 -0
- package/dist/gateway/auth-rate-limit.js +136 -0
- package/dist/gateway/channel-health-monitor.js +114 -0
- package/dist/gateway/control-ui-contract.js +1 -0
- package/dist/gateway/control-ui-csp.js +15 -0
- package/dist/gateway/gateway-config-prompts.shared.js +25 -0
- package/dist/gateway/http-auth-helpers.js +18 -0
- package/dist/gateway/http-common.js +18 -0
- package/dist/gateway/http-endpoint-helpers.js +27 -0
- package/dist/gateway/node-invoke-sanitize.js +11 -0
- package/dist/gateway/node-invoke-system-run-approval.js +205 -0
- package/dist/gateway/probe-auth.js +21 -0
- package/dist/gateway/protocol/index.js +7 -2
- package/dist/gateway/protocol/schema/mesh.js +54 -0
- package/dist/gateway/protocol/schema/protocol-schemas.js +7 -0
- package/dist/gateway/protocol/schema.js +1 -0
- package/dist/gateway/server/ws-connection/auth-messages.js +54 -0
- package/dist/gateway/server-channels.js +11 -0
- package/dist/gateway/server-methods/attachment-normalize.js +16 -0
- package/dist/gateway/server-methods/base-hash.js +8 -0
- package/dist/gateway/server-methods/mesh.js +700 -0
- package/dist/gateway/server-methods/nodes.handlers.invoke-result.js +55 -0
- package/dist/gateway/server-methods/restart-request.js +13 -0
- package/dist/gateway/server-methods/validation.js +8 -0
- package/dist/gateway/server.agent.gateway-server-agent.mocks.js +35 -0
- package/dist/gateway/server.e2e-registry-helpers.js +1 -0
- package/dist/gateway/server.e2e-ws-harness.js +20 -0
- package/dist/gateway/test-helpers.js +2 -0
- package/dist/gateway/test-helpers.server.js +3 -1
- package/dist/gateway/test-http-response.js +12 -0
- package/dist/gateway/test-openai-responses-model.js +20 -0
- package/dist/gateway/test-temp-config.js +30 -0
- package/dist/gateway/test-with-server.js +32 -0
- package/dist/hooks/bundled/bootstrap-extra-files/handler.js +46 -0
- package/dist/imessage/monitor/abort-handler.js +23 -0
- package/dist/imessage/monitor/inbound-processing.js +346 -0
- package/dist/imessage/monitor/parse-notification.js +64 -0
- package/dist/imessage/target-parsing-helpers.js +92 -0
- package/dist/infra/archive.js +244 -20
- package/dist/infra/detect-package-manager.js +26 -0
- package/dist/infra/exec-approvals-allowlist.js +257 -0
- package/dist/infra/exec-approvals-analysis.js +770 -0
- package/dist/infra/exec-approvals.js +13 -0
- package/dist/infra/file-lock.js +1 -0
- package/dist/infra/gemini-auth.js +39 -0
- package/dist/infra/heartbeat-active-hours.js +85 -0
- package/dist/infra/heartbeat-events-filter.js +50 -0
- package/dist/infra/heartbeat-runner.test-utils.js +39 -0
- package/dist/infra/http-body.js +265 -0
- package/dist/infra/install-package-dir.js +50 -0
- package/dist/infra/install-safe-path.js +49 -0
- package/dist/infra/json-files.js +49 -0
- package/dist/infra/jsonl-socket.js +52 -0
- package/dist/infra/map-size.js +14 -0
- package/dist/infra/net/hostname.js +7 -0
- package/dist/infra/npm-registry-spec.js +39 -0
- package/dist/infra/openclaw-root.js +109 -0
- package/dist/infra/outbound/delivery-queue.js +214 -0
- package/dist/infra/outbound/identity.js +23 -0
- package/dist/infra/outbound/message-action-params.js +307 -0
- package/dist/infra/outbound/tool-payload.js +21 -0
- package/dist/infra/package-json.js +23 -0
- package/dist/infra/pairing-files.js +19 -0
- package/dist/infra/pairing-token.js +9 -0
- package/dist/infra/path-prepend.js +51 -0
- package/dist/infra/process-respawn.js +49 -0
- package/dist/infra/runtime-status.js +16 -0
- package/dist/infra/session-cost-usage.types.js +1 -0
- package/dist/infra/session-maintenance-warning.js +89 -0
- package/dist/infra/system-run-command.js +78 -0
- package/dist/infra/tmp-openclaw-dir.js +81 -0
- package/dist/infra/tmp-poolbot-dir.js +2 -0
- package/dist/infra/update-channels.js +19 -0
- package/dist/line/actions.js +45 -0
- package/dist/line/channel-access-token.js +9 -0
- package/dist/line/flex-templates/basic-cards.js +332 -0
- package/dist/line/flex-templates/common.js +18 -0
- package/dist/line/flex-templates/media-control-cards.js +453 -0
- package/dist/line/flex-templates/message.js +10 -0
- package/dist/line/flex-templates/schedule-cards.js +399 -0
- package/dist/line/flex-templates/types.js +1 -0
- package/dist/line/webhook-node.js +100 -0
- package/dist/line/webhook-utils.js +11 -0
- package/dist/logging/timestamps.js +14 -0
- package/dist/markdown/whatsapp.js +62 -0
- package/dist/media/base64.js +34 -0
- package/dist/media/local-roots.js +32 -0
- package/dist/media/outbound-attachment.js +10 -0
- package/dist/media/read-response-with-limit.js +41 -0
- package/dist/media/sniff-mime-from-base64.js +19 -0
- package/dist/media-understanding/audio-preflight.js +67 -0
- package/dist/media-understanding/fs.js +13 -0
- package/dist/media-understanding/output-extract.js +26 -0
- package/dist/media-understanding/providers/audio.test-helpers.js +34 -0
- package/dist/media-understanding/providers/google/inline-data.js +64 -0
- package/dist/media-understanding/providers/shared.js +7 -0
- package/dist/media-understanding/runner.entries.js +459 -0
- package/dist/memory/batch-error-utils.js +11 -0
- package/dist/memory/batch-http.js +27 -0
- package/dist/memory/batch-output.js +29 -0
- package/dist/memory/batch-runner.js +22 -0
- package/dist/memory/batch-upload.js +23 -0
- package/dist/memory/batch-utils.js +26 -0
- package/dist/memory/embeddings-debug.js +11 -0
- package/dist/memory/embeddings-remote-client.js +22 -0
- package/dist/memory/embeddings-remote-fetch.js +14 -0
- package/dist/memory/manager-embedding-ops.js +616 -0
- package/dist/memory/manager-sync-ops.js +953 -0
- package/dist/memory/qmd-manager.js +1061 -0
- package/dist/memory/qmd-query-parser.js +107 -0
- package/dist/memory/qmd-scope.js +93 -0
- package/dist/memory/search-manager.js +0 -1
- package/dist/memory/sync-index.js +21 -0
- package/dist/memory/sync-progress.js +22 -0
- package/dist/memory/sync-stale.js +30 -0
- package/dist/memory/test-embeddings-mock.js +16 -0
- package/dist/memory/test-manager-helpers.js +14 -0
- package/dist/memory/test-runtime-mocks.js +11 -0
- package/dist/node-host/invoke-browser.js +177 -0
- package/dist/node-host/invoke.js +685 -0
- package/dist/pairing/setup-code.js +285 -0
- package/dist/plugin-sdk/account-id.js +1 -0
- package/dist/plugin-sdk/agent-media-payload.js +13 -0
- package/dist/plugin-sdk/allow-from.js +47 -0
- package/dist/plugin-sdk/command-auth.js +23 -0
- package/dist/plugin-sdk/config-paths.js +9 -0
- package/dist/plugin-sdk/file-lock.js +116 -0
- package/dist/plugin-sdk/json-store.js +31 -0
- package/dist/plugin-sdk/onboarding.js +28 -0
- package/dist/plugin-sdk/provider-auth-result.js +29 -0
- package/dist/plugin-sdk/slack-message-actions.js +133 -0
- package/dist/plugin-sdk/status-helpers.js +35 -0
- package/dist/plugin-sdk/text-chunking.js +31 -0
- package/dist/plugin-sdk/tool-send.js +12 -0
- package/dist/plugin-sdk/webhook-path.js +27 -0
- package/dist/plugin-sdk/webhook-targets.js +34 -0
- package/dist/plugins/hooks.test-helpers.js +21 -0
- package/dist/plugins/uninstall.js +171 -0
- package/dist/process/supervisor/adapters/child.js +143 -0
- package/dist/process/supervisor/adapters/env.js +13 -0
- package/dist/process/supervisor/adapters/pty.js +148 -0
- package/dist/process/supervisor/index.js +10 -0
- package/dist/process/supervisor/registry.js +117 -0
- package/dist/process/supervisor/supervisor.js +244 -0
- package/dist/process/supervisor/types.js +1 -0
- package/dist/providers/google-shared.test-helpers.js +75 -0
- package/dist/security/audit-channel.js +419 -0
- package/dist/security/audit-tool-policy.js +1 -0
- package/dist/security/scan-paths.js +12 -0
- package/dist/sessions/input-provenance.js +55 -0
- package/dist/sessions/session-key-utils.js +7 -0
- package/dist/shared/chat-content.js +31 -0
- package/dist/shared/chat-envelope.js +45 -0
- package/dist/shared/config-eval.js +117 -0
- package/dist/shared/device-auth.js +16 -0
- package/dist/shared/entry-metadata.js +9 -0
- package/dist/shared/entry-status.js +25 -0
- package/dist/shared/frontmatter.js +98 -0
- package/dist/shared/model-param-b.js +19 -0
- package/dist/shared/net/ipv4.js +17 -0
- package/dist/shared/node-match.js +53 -0
- package/dist/shared/requirements.js +128 -0
- package/dist/shared/subagents-format.js +84 -0
- package/dist/shared/usage-aggregates.js +28 -0
- package/dist/signal/monitor/mentions.js +45 -0
- package/dist/signal/rpc-context.js +19 -0
- package/dist/slack/blocks-fallback.js +76 -0
- package/dist/slack/blocks-input.js +40 -0
- package/dist/slack/draft-stream.js +106 -0
- package/dist/slack/message-actions.js +51 -0
- package/dist/slack/modal-metadata.js +32 -0
- package/dist/slack/monitor/events/interactions.js +462 -0
- package/dist/slack/monitor/room-context.js +17 -0
- package/dist/slack/stream-mode.js +41 -0
- package/dist/telegram/bot-native-command-menu.js +64 -0
- package/dist/telegram/bot.media.e2e-harness.js +81 -0
- package/dist/telegram/button-types.js +1 -0
- package/dist/telegram/group-access.js +65 -0
- package/dist/telegram/outbound-params.js +21 -0
- package/dist/telegram/poll-vote-cache.js +21 -0
- package/dist/terminal/health-style.js +36 -0
- package/dist/test-utils/chunk-test-helpers.js +21 -0
- package/dist/test-utils/env.js +72 -0
- package/dist/test-utils/exec-assertions.js +12 -0
- package/dist/test-utils/imessage-test-plugin.js +54 -0
- package/dist/test-utils/mock-http-response.js +17 -0
- package/dist/test-utils/vitest-mock-fn.js +1 -0
- package/dist/tts/tts-core.js +550 -0
- package/dist/utils/chunk-items.js +10 -0
- package/dist/utils/reaction-level.js +52 -0
- package/dist/utils/safe-json.js +22 -0
- package/dist/utils/with-timeout.js +14 -0
- package/dist/web/media.js +17 -5
- package/dist/whatsapp/resolve-outbound-target.js +42 -0
- package/dist/wizard/onboarding.completion.js +74 -0
- package/extensions/bluebubbles/src/account-resolve.ts +29 -0
- package/extensions/bluebubbles/src/monitor-normalize.ts +796 -0
- package/extensions/bluebubbles/src/monitor-processing.ts +1007 -0
- package/extensions/bluebubbles/src/monitor-reply-cache.ts +185 -0
- package/extensions/bluebubbles/src/monitor-shared.ts +51 -0
- package/extensions/bluebubbles/src/multipart.ts +32 -0
- package/extensions/bluebubbles/src/send-helpers.ts +53 -0
- package/extensions/bluebubbles/src/test-harness.ts +50 -0
- package/extensions/bluebubbles/src/test-mocks.ts +11 -0
- package/extensions/device-pair/index.ts +554 -0
- package/extensions/device-pair/poolbot.plugin.json +20 -0
- package/extensions/discord/src/channel.js +366 -0
- package/extensions/discord/src/runtime.js +10 -0
- package/extensions/feishu/index.ts +63 -0
- package/extensions/feishu/package.json +37 -0
- package/extensions/feishu/poolbot.plugin.json +10 -0
- package/extensions/feishu/skills/feishu-doc/SKILL.md +105 -0
- package/extensions/feishu/skills/feishu-doc/references/block-types.md +103 -0
- package/extensions/feishu/skills/feishu-drive/SKILL.md +97 -0
- package/extensions/feishu/skills/feishu-perm/SKILL.md +119 -0
- package/extensions/feishu/skills/feishu-wiki/SKILL.md +111 -0
- package/extensions/feishu/src/accounts.ts +114 -0
- package/extensions/feishu/src/bitable.ts +739 -0
- package/extensions/feishu/src/bot.ts +965 -0
- package/extensions/feishu/src/channel.ts +351 -0
- package/extensions/feishu/src/client.ts +118 -0
- package/extensions/feishu/src/config-schema.ts +206 -0
- package/extensions/feishu/src/dedup.ts +33 -0
- package/extensions/feishu/src/directory.ts +177 -0
- package/extensions/feishu/src/doc-schema.ts +47 -0
- package/extensions/feishu/src/docx.ts +536 -0
- package/extensions/feishu/src/drive-schema.ts +46 -0
- package/extensions/feishu/src/drive.ts +227 -0
- package/extensions/feishu/src/dynamic-agent.ts +131 -0
- package/extensions/feishu/src/media.ts +449 -0
- package/extensions/feishu/src/mention.ts +126 -0
- package/extensions/feishu/src/monitor.ts +330 -0
- package/extensions/feishu/src/onboarding.ts +359 -0
- package/extensions/feishu/src/outbound.ts +55 -0
- package/extensions/feishu/src/perm-schema.ts +52 -0
- package/extensions/feishu/src/perm.ts +173 -0
- package/extensions/feishu/src/policy.ts +84 -0
- package/extensions/feishu/src/probe.ts +44 -0
- package/extensions/feishu/src/reactions.ts +160 -0
- package/extensions/feishu/src/reply-dispatcher.ts +239 -0
- package/extensions/feishu/src/runtime.ts +14 -0
- package/extensions/feishu/src/send-result.ts +29 -0
- package/extensions/feishu/src/send.ts +335 -0
- package/extensions/feishu/src/streaming-card.ts +223 -0
- package/extensions/feishu/src/targets.ts +78 -0
- package/extensions/feishu/src/tools-config.ts +21 -0
- package/extensions/feishu/src/types.ts +81 -0
- package/extensions/feishu/src/typing.ts +80 -0
- package/extensions/feishu/src/wiki-schema.ts +55 -0
- package/extensions/feishu/src/wiki.ts +232 -0
- package/extensions/imessage/src/channel.js +253 -0
- package/extensions/imessage/src/runtime.js +10 -0
- package/extensions/irc/index.ts +17 -0
- package/extensions/irc/package.json +14 -0
- package/extensions/irc/poolbot.plugin.json +9 -0
- package/extensions/irc/src/accounts.ts +268 -0
- package/extensions/irc/src/channel.ts +367 -0
- package/extensions/irc/src/client.ts +439 -0
- package/extensions/irc/src/config-schema.ts +97 -0
- package/extensions/irc/src/connect-options.ts +30 -0
- package/extensions/irc/src/control-chars.ts +22 -0
- package/extensions/irc/src/inbound.ts +334 -0
- package/extensions/irc/src/monitor.ts +147 -0
- package/extensions/irc/src/normalize.ts +117 -0
- package/extensions/irc/src/onboarding.ts +479 -0
- package/extensions/irc/src/policy.ts +157 -0
- package/extensions/irc/src/probe.ts +53 -0
- package/extensions/irc/src/protocol.ts +169 -0
- package/extensions/irc/src/runtime.ts +14 -0
- package/extensions/irc/src/send.ts +88 -0
- package/extensions/irc/src/types.ts +93 -0
- package/extensions/matrix/src/matrix/client-bootstrap.ts +39 -0
- package/extensions/mattermost/src/mattermost/monitor-onchar.ts +25 -0
- package/extensions/mattermost/src/mattermost/monitor-websocket.ts +221 -0
- package/extensions/mattermost/src/mattermost/reactions.ts +130 -0
- package/extensions/mattermost/src/mattermost/reconnect.ts +103 -0
- package/extensions/minimax-portal-auth/README.md +33 -0
- package/extensions/minimax-portal-auth/index.ts +161 -0
- package/extensions/minimax-portal-auth/oauth.ts +247 -0
- package/extensions/minimax-portal-auth/package.json +15 -0
- package/extensions/minimax-portal-auth/poolbot.plugin.json +9 -0
- package/extensions/msteams/src/file-lock.ts +1 -0
- package/extensions/msteams/src/graph.ts +92 -0
- package/extensions/msteams/src/mentions.ts +114 -0
- package/extensions/msteams/src/test-runtime.ts +16 -0
- package/extensions/openai-codex-auth/README.md +82 -0
- package/extensions/openai-codex-auth/index.ts +177 -0
- package/extensions/openai-codex-auth/package.json +15 -0
- package/extensions/openai-codex-auth/poolbot.plugin.json +9 -0
- package/extensions/phone-control/index.ts +421 -0
- package/extensions/phone-control/poolbot.plugin.json +10 -0
- package/extensions/shared/resolve-target-test-helpers.ts +66 -0
- package/extensions/signal/src/channel.js +273 -0
- package/extensions/signal/src/runtime.js +10 -0
- package/extensions/slack/src/channel.js +489 -0
- package/extensions/slack/src/runtime.js +10 -0
- package/extensions/talk-voice/index.ts +150 -0
- package/extensions/talk-voice/poolbot.plugin.json +10 -0
- package/extensions/telegram/src/channel.js +424 -0
- package/extensions/telegram/src/runtime.js +10 -0
- package/extensions/thread-ownership/index.ts +133 -0
- package/extensions/thread-ownership/poolbot.plugin.json +28 -0
- package/extensions/tlon/src/account-fields.ts +25 -0
- package/extensions/tlon/src/urbit/base-url.ts +57 -0
- package/extensions/tlon/src/urbit/channel-client.ts +157 -0
- package/extensions/tlon/src/urbit/channel-ops.ts +164 -0
- package/extensions/tlon/src/urbit/context.ts +47 -0
- package/extensions/tlon/src/urbit/errors.ts +51 -0
- package/extensions/tlon/src/urbit/fetch.ts +39 -0
- package/extensions/twitch/src/test-fixtures.ts +30 -0
- package/extensions/voice-call/src/allowlist.ts +19 -0
- package/extensions/whatsapp/src/channel.js +429 -0
- package/extensions/whatsapp/src/runtime.js +10 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
## v2026.2.19 (2026-02-17)
|
|
2
|
+
|
|
3
|
+
### Fixes
|
|
4
|
+
- **Build:** `pnpm build` now succeeds cleanly — added tsconfig excludes for `*.e2e-harness.ts`, `*-test-helpers.ts`, and `*.e2e-test-helpers.ts` patterns that caused TS6059 rootDir errors
|
|
5
|
+
- **Audit:** verified all 37 extensions have `poolbot.plugin.json` manifests and supporting files (package.json, skills, READMEs) — no gaps found
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## v2026.2.18 (2026-02-17)
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
- Upstream bulk port — 394 new production files + 52 modified files aligned with upstream:
|
|
13
|
+
- **Archive security hardening:** path traversal guards, symlink/hardlink blocking, entry count + byte budget limits, `preservePaths: false` + `strict: true` for tar extraction
|
|
14
|
+
- **Agent workspace:** `loadExtraBootstrapFiles()` with full security (path traversal guards, symlink resolution, basename allowlist)
|
|
15
|
+
- **Gateway channels:** `ChannelManager` restart tracking with `restartAttempts` map, `manuallyStopped` set, exponential backoff
|
|
16
|
+
- **Config CLI:** `runConfigGet`/`runConfigUnset` now accept injectable `RuntimeEnv`; `runConfigUnset` uses `snapshot.resolved` with `structuredClone` to prevent runtime defaults leaking into config file
|
|
17
|
+
- **Gateway auth:** rate limiting support (`rateLimited`, `retryAfterMs`), `"none" | "trusted-proxy"` auth modes
|
|
18
|
+
- **Mesh networking:** protocol schemas, validators, and server methods for mesh gateway federation
|
|
19
|
+
- **Subagent registry:** complete rewrite with announcement queue
|
|
20
|
+
- **Memory:** QMD search mode fallback, hybrid search backend config
|
|
21
|
+
- **Exec approvals:** normalized path signature for approval checks
|
|
22
|
+
- Plus 375+ new source files covering agents, CLI, config, cron, daemon, gateway, hooks, infra, media, routing, and more
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
1
26
|
## v2026.2.17 (2026-02-17)
|
|
2
27
|
|
|
3
28
|
### Features
|
|
@@ -2,6 +2,7 @@ import os from "node:os";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { resolveStateDir } from "../config/paths.js";
|
|
4
4
|
import { DEFAULT_AGENT_ID, normalizeAgentId, parseAgentSessionKey, } from "../routing/session-key.js";
|
|
5
|
+
import { normalizeSkillFilter } from "./skills/filter.js";
|
|
5
6
|
import { resolveUserPath } from "../utils.js";
|
|
6
7
|
import { DEFAULT_AGENT_WORKSPACE_DIR } from "./workspace.js";
|
|
7
8
|
export { resolveAgentIdFromSessionKey } from "../routing/session-key.js";
|
|
@@ -76,6 +77,9 @@ export function resolveAgentConfig(cfg, agentId) {
|
|
|
76
77
|
tools: entry.tools,
|
|
77
78
|
};
|
|
78
79
|
}
|
|
80
|
+
export function resolveAgentSkillsFilter(cfg, agentId) {
|
|
81
|
+
return normalizeSkillFilter(resolveAgentConfig(cfg, agentId)?.skills);
|
|
82
|
+
}
|
|
79
83
|
export function resolveAgentModelPrimary(cfg, agentId) {
|
|
80
84
|
const raw = resolveAgentConfig(cfg, agentId)?.model;
|
|
81
85
|
if (!raw)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function buildAnnounceIdFromChildRun(params) {
|
|
2
|
+
return `v1:${params.childSessionKey}:${params.childRunId}`;
|
|
3
|
+
}
|
|
4
|
+
export function buildAnnounceIdempotencyKey(announceId) {
|
|
5
|
+
return `announce:${announceId}`;
|
|
6
|
+
}
|
|
7
|
+
export function resolveQueueAnnounceId(params) {
|
|
8
|
+
const announceId = params.announceId?.trim();
|
|
9
|
+
if (announceId) {
|
|
10
|
+
return announceId;
|
|
11
|
+
}
|
|
12
|
+
// Backward-compatible fallback for queue items that predate announceId.
|
|
13
|
+
return `legacy:${params.sessionKey}:${params.enqueuedAt}`;
|
|
14
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const ANTHROPIC_STORE = {
|
|
2
|
+
version: 1,
|
|
3
|
+
profiles: {
|
|
4
|
+
"anthropic:default": {
|
|
5
|
+
type: "api_key",
|
|
6
|
+
provider: "anthropic",
|
|
7
|
+
key: "sk-default",
|
|
8
|
+
},
|
|
9
|
+
"anthropic:work": {
|
|
10
|
+
type: "api_key",
|
|
11
|
+
provider: "anthropic",
|
|
12
|
+
key: "sk-work",
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
export const ANTHROPIC_CFG = {
|
|
17
|
+
auth: {
|
|
18
|
+
profiles: {
|
|
19
|
+
"anthropic:default": { provider: "anthropic", mode: "api_key" },
|
|
20
|
+
"anthropic:work": { provider: "anthropic", mode: "api_key" },
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
import { requestHeartbeatNow } from "../infra/heartbeat-wake.js";
|
|
4
|
+
import { mergePathPrepend } from "../infra/path-prepend.js";
|
|
5
|
+
import { enqueueSystemEvent } from "../infra/system-events.js";
|
|
6
|
+
export { applyPathPrepend, normalizePathPrepend } from "../infra/path-prepend.js";
|
|
7
|
+
import { logWarn } from "../logger.js";
|
|
8
|
+
import { getProcessSupervisor } from "../process/supervisor/index.js";
|
|
9
|
+
import { addSession, appendOutput, createSessionSlug, markExited, tail, } from "./bash-process-registry.js";
|
|
10
|
+
import { buildDockerExecArgs, chunkString, clampWithDefault, readEnvInt, } from "./bash-tools.shared.js";
|
|
11
|
+
import { buildCursorPositionResponse, stripDsrRequests } from "./pty-dsr.js";
|
|
12
|
+
import { getShellConfig, sanitizeBinaryOutput } from "./shell-utils.js";
|
|
13
|
+
// Security: Blocklist of environment variables that could alter execution flow
|
|
14
|
+
// or inject code when running on non-sandboxed hosts (Gateway/Node).
|
|
15
|
+
const DANGEROUS_HOST_ENV_VARS = new Set([
|
|
16
|
+
"LD_PRELOAD",
|
|
17
|
+
"LD_LIBRARY_PATH",
|
|
18
|
+
"LD_AUDIT",
|
|
19
|
+
"DYLD_INSERT_LIBRARIES",
|
|
20
|
+
"DYLD_LIBRARY_PATH",
|
|
21
|
+
"NODE_OPTIONS",
|
|
22
|
+
"NODE_PATH",
|
|
23
|
+
"PYTHONPATH",
|
|
24
|
+
"PYTHONHOME",
|
|
25
|
+
"RUBYLIB",
|
|
26
|
+
"PERL5LIB",
|
|
27
|
+
"BASH_ENV",
|
|
28
|
+
"ENV",
|
|
29
|
+
"GCONV_PATH",
|
|
30
|
+
"IFS",
|
|
31
|
+
"SSLKEYLOGFILE",
|
|
32
|
+
]);
|
|
33
|
+
const DANGEROUS_HOST_ENV_PREFIXES = ["DYLD_", "LD_"];
|
|
34
|
+
// Centralized sanitization helper.
|
|
35
|
+
// Throws an error if dangerous variables or PATH modifications are detected on the host.
|
|
36
|
+
export function validateHostEnv(env) {
|
|
37
|
+
for (const key of Object.keys(env)) {
|
|
38
|
+
const upperKey = key.toUpperCase();
|
|
39
|
+
// 1. Block known dangerous variables (Fail Closed)
|
|
40
|
+
if (DANGEROUS_HOST_ENV_PREFIXES.some((prefix) => upperKey.startsWith(prefix))) {
|
|
41
|
+
throw new Error(`Security Violation: Environment variable '${key}' is forbidden during host execution.`);
|
|
42
|
+
}
|
|
43
|
+
if (DANGEROUS_HOST_ENV_VARS.has(upperKey)) {
|
|
44
|
+
throw new Error(`Security Violation: Environment variable '${key}' is forbidden during host execution.`);
|
|
45
|
+
}
|
|
46
|
+
// 2. Strictly block PATH modification on host
|
|
47
|
+
// Allowing custom PATH on the gateway/node can lead to binary hijacking.
|
|
48
|
+
if (upperKey === "PATH") {
|
|
49
|
+
throw new Error("Security Violation: Custom 'PATH' variable is forbidden during host execution.");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export const DEFAULT_MAX_OUTPUT = clampWithDefault(readEnvInt("PI_BASH_MAX_OUTPUT_CHARS"), 200_000, 1_000, 200_000);
|
|
54
|
+
export const DEFAULT_PENDING_MAX_OUTPUT = clampWithDefault(readEnvInt("POOLBOT_BASH_PENDING_MAX_OUTPUT_CHARS"), 30_000, 1_000, 200_000);
|
|
55
|
+
export const DEFAULT_PATH = process.env.PATH ?? "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
|
|
56
|
+
export const DEFAULT_NOTIFY_TAIL_CHARS = 400;
|
|
57
|
+
const DEFAULT_NOTIFY_SNIPPET_CHARS = 180;
|
|
58
|
+
export const DEFAULT_APPROVAL_TIMEOUT_MS = 120_000;
|
|
59
|
+
export const DEFAULT_APPROVAL_REQUEST_TIMEOUT_MS = 130_000;
|
|
60
|
+
const DEFAULT_APPROVAL_RUNNING_NOTICE_MS = 10_000;
|
|
61
|
+
const APPROVAL_SLUG_LENGTH = 8;
|
|
62
|
+
export const execSchema = Type.Object({
|
|
63
|
+
command: Type.String({ description: "Shell command to execute" }),
|
|
64
|
+
workdir: Type.Optional(Type.String({ description: "Working directory (defaults to cwd)" })),
|
|
65
|
+
env: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
66
|
+
yieldMs: Type.Optional(Type.Number({
|
|
67
|
+
description: "Milliseconds to wait before backgrounding (default 10000)",
|
|
68
|
+
})),
|
|
69
|
+
background: Type.Optional(Type.Boolean({ description: "Run in background immediately" })),
|
|
70
|
+
timeout: Type.Optional(Type.Number({
|
|
71
|
+
description: "Timeout in seconds (optional, kills process on expiry)",
|
|
72
|
+
})),
|
|
73
|
+
pty: Type.Optional(Type.Boolean({
|
|
74
|
+
description: "Run in a pseudo-terminal (PTY) when available (TTY-required CLIs, coding agents)",
|
|
75
|
+
})),
|
|
76
|
+
elevated: Type.Optional(Type.Boolean({
|
|
77
|
+
description: "Run on the host with elevated permissions (if allowed)",
|
|
78
|
+
})),
|
|
79
|
+
host: Type.Optional(Type.String({
|
|
80
|
+
description: "Exec host (sandbox|gateway|node).",
|
|
81
|
+
})),
|
|
82
|
+
security: Type.Optional(Type.String({
|
|
83
|
+
description: "Exec security mode (deny|allowlist|full).",
|
|
84
|
+
})),
|
|
85
|
+
ask: Type.Optional(Type.String({
|
|
86
|
+
description: "Exec ask mode (off|on-miss|always).",
|
|
87
|
+
})),
|
|
88
|
+
node: Type.Optional(Type.String({
|
|
89
|
+
description: "Node id/name for host=node.",
|
|
90
|
+
})),
|
|
91
|
+
});
|
|
92
|
+
export function normalizeExecHost(value) {
|
|
93
|
+
const normalized = value?.trim().toLowerCase();
|
|
94
|
+
if (normalized === "sandbox" || normalized === "gateway" || normalized === "node") {
|
|
95
|
+
return normalized;
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
export function normalizeExecSecurity(value) {
|
|
100
|
+
const normalized = value?.trim().toLowerCase();
|
|
101
|
+
if (normalized === "deny" || normalized === "allowlist" || normalized === "full") {
|
|
102
|
+
return normalized;
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
export function normalizeExecAsk(value) {
|
|
107
|
+
const normalized = value?.trim().toLowerCase();
|
|
108
|
+
if (normalized === "off" || normalized === "on-miss" || normalized === "always") {
|
|
109
|
+
return normalized;
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
export function renderExecHostLabel(host) {
|
|
114
|
+
return host === "sandbox" ? "sandbox" : host === "gateway" ? "gateway" : "node";
|
|
115
|
+
}
|
|
116
|
+
export function normalizeNotifyOutput(value) {
|
|
117
|
+
return value.replace(/\s+/g, " ").trim();
|
|
118
|
+
}
|
|
119
|
+
function compactNotifyOutput(value, maxChars = DEFAULT_NOTIFY_SNIPPET_CHARS) {
|
|
120
|
+
const normalized = normalizeNotifyOutput(value);
|
|
121
|
+
if (!normalized) {
|
|
122
|
+
return "";
|
|
123
|
+
}
|
|
124
|
+
if (normalized.length <= maxChars) {
|
|
125
|
+
return normalized;
|
|
126
|
+
}
|
|
127
|
+
const safe = Math.max(1, maxChars - 1);
|
|
128
|
+
return `${normalized.slice(0, safe)}…`;
|
|
129
|
+
}
|
|
130
|
+
export function applyShellPath(env, shellPath) {
|
|
131
|
+
if (!shellPath) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const entries = shellPath
|
|
135
|
+
.split(path.delimiter)
|
|
136
|
+
.map((part) => part.trim())
|
|
137
|
+
.filter(Boolean);
|
|
138
|
+
if (entries.length === 0) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const merged = mergePathPrepend(env.PATH, entries);
|
|
142
|
+
if (merged) {
|
|
143
|
+
env.PATH = merged;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function maybeNotifyOnExit(session, status) {
|
|
147
|
+
if (!session.backgrounded || !session.notifyOnExit || session.exitNotified) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const sessionKey = session.sessionKey?.trim();
|
|
151
|
+
if (!sessionKey) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
session.exitNotified = true;
|
|
155
|
+
const exitLabel = session.exitSignal
|
|
156
|
+
? `signal ${session.exitSignal}`
|
|
157
|
+
: `code ${session.exitCode ?? 0}`;
|
|
158
|
+
const output = compactNotifyOutput(tail(session.tail || session.aggregated || "", DEFAULT_NOTIFY_TAIL_CHARS));
|
|
159
|
+
if (status === "completed" && !output && session.notifyOnExitEmptySuccess !== true) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const summary = output
|
|
163
|
+
? `Exec ${status} (${session.id.slice(0, 8)}, ${exitLabel}) :: ${output}`
|
|
164
|
+
: `Exec ${status} (${session.id.slice(0, 8)}, ${exitLabel})`;
|
|
165
|
+
enqueueSystemEvent(summary, { sessionKey });
|
|
166
|
+
requestHeartbeatNow({ reason: `exec:${session.id}:exit` });
|
|
167
|
+
}
|
|
168
|
+
export function createApprovalSlug(id) {
|
|
169
|
+
return id.slice(0, APPROVAL_SLUG_LENGTH);
|
|
170
|
+
}
|
|
171
|
+
export function resolveApprovalRunningNoticeMs(value) {
|
|
172
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
173
|
+
return DEFAULT_APPROVAL_RUNNING_NOTICE_MS;
|
|
174
|
+
}
|
|
175
|
+
if (value <= 0) {
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
return Math.floor(value);
|
|
179
|
+
}
|
|
180
|
+
export function emitExecSystemEvent(text, opts) {
|
|
181
|
+
const sessionKey = opts.sessionKey?.trim();
|
|
182
|
+
if (!sessionKey) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
enqueueSystemEvent(text, { sessionKey, contextKey: opts.contextKey });
|
|
186
|
+
requestHeartbeatNow({ reason: "exec-event" });
|
|
187
|
+
}
|
|
188
|
+
export async function runExecProcess(opts) {
|
|
189
|
+
const startedAt = Date.now();
|
|
190
|
+
const sessionId = createSessionSlug();
|
|
191
|
+
const execCommand = opts.execCommand ?? opts.command;
|
|
192
|
+
const supervisor = getProcessSupervisor();
|
|
193
|
+
const session = {
|
|
194
|
+
id: sessionId,
|
|
195
|
+
command: opts.command,
|
|
196
|
+
scopeKey: opts.scopeKey,
|
|
197
|
+
sessionKey: opts.sessionKey,
|
|
198
|
+
notifyOnExit: opts.notifyOnExit,
|
|
199
|
+
notifyOnExitEmptySuccess: opts.notifyOnExitEmptySuccess === true,
|
|
200
|
+
exitNotified: false,
|
|
201
|
+
child: undefined,
|
|
202
|
+
stdin: undefined,
|
|
203
|
+
pid: undefined,
|
|
204
|
+
startedAt,
|
|
205
|
+
cwd: opts.workdir,
|
|
206
|
+
maxOutputChars: opts.maxOutput,
|
|
207
|
+
pendingMaxOutputChars: opts.pendingMaxOutput,
|
|
208
|
+
totalOutputChars: 0,
|
|
209
|
+
pendingStdout: [],
|
|
210
|
+
pendingStderr: [],
|
|
211
|
+
pendingStdoutChars: 0,
|
|
212
|
+
pendingStderrChars: 0,
|
|
213
|
+
aggregated: "",
|
|
214
|
+
tail: "",
|
|
215
|
+
exited: false,
|
|
216
|
+
exitCode: undefined,
|
|
217
|
+
exitSignal: undefined,
|
|
218
|
+
truncated: false,
|
|
219
|
+
backgrounded: false,
|
|
220
|
+
};
|
|
221
|
+
addSession(session);
|
|
222
|
+
const emitUpdate = () => {
|
|
223
|
+
if (!opts.onUpdate) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const tailText = session.tail || session.aggregated;
|
|
227
|
+
const warningText = opts.warnings.length ? `${opts.warnings.join("\n")}\n\n` : "";
|
|
228
|
+
opts.onUpdate({
|
|
229
|
+
content: [{ type: "text", text: warningText + (tailText || "") }],
|
|
230
|
+
details: {
|
|
231
|
+
status: "running",
|
|
232
|
+
sessionId,
|
|
233
|
+
pid: session.pid ?? undefined,
|
|
234
|
+
startedAt,
|
|
235
|
+
cwd: session.cwd,
|
|
236
|
+
tail: session.tail,
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
};
|
|
240
|
+
const handleStdout = (data) => {
|
|
241
|
+
const str = sanitizeBinaryOutput(data.toString());
|
|
242
|
+
for (const chunk of chunkString(str)) {
|
|
243
|
+
appendOutput(session, "stdout", chunk);
|
|
244
|
+
emitUpdate();
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
const handleStderr = (data) => {
|
|
248
|
+
const str = sanitizeBinaryOutput(data.toString());
|
|
249
|
+
for (const chunk of chunkString(str)) {
|
|
250
|
+
appendOutput(session, "stderr", chunk);
|
|
251
|
+
emitUpdate();
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
const timeoutMs = typeof opts.timeoutSec === "number" && opts.timeoutSec > 0
|
|
255
|
+
? Math.floor(opts.timeoutSec * 1000)
|
|
256
|
+
: undefined;
|
|
257
|
+
const spawnSpec = (() => {
|
|
258
|
+
if (opts.sandbox) {
|
|
259
|
+
return {
|
|
260
|
+
mode: "child",
|
|
261
|
+
argv: [
|
|
262
|
+
"docker",
|
|
263
|
+
...buildDockerExecArgs({
|
|
264
|
+
containerName: opts.sandbox.containerName,
|
|
265
|
+
command: execCommand,
|
|
266
|
+
workdir: opts.containerWorkdir ?? opts.sandbox.containerWorkdir,
|
|
267
|
+
env: opts.env,
|
|
268
|
+
tty: opts.usePty,
|
|
269
|
+
}),
|
|
270
|
+
],
|
|
271
|
+
env: process.env,
|
|
272
|
+
stdinMode: opts.usePty ? "pipe-open" : "pipe-closed",
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
const { shell, args: shellArgs } = getShellConfig();
|
|
276
|
+
const childArgv = [shell, ...shellArgs, execCommand];
|
|
277
|
+
if (opts.usePty) {
|
|
278
|
+
return {
|
|
279
|
+
mode: "pty",
|
|
280
|
+
ptyCommand: execCommand,
|
|
281
|
+
childFallbackArgv: childArgv,
|
|
282
|
+
env: opts.env,
|
|
283
|
+
stdinMode: "pipe-open",
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
mode: "child",
|
|
288
|
+
argv: childArgv,
|
|
289
|
+
env: opts.env,
|
|
290
|
+
stdinMode: "pipe-closed",
|
|
291
|
+
};
|
|
292
|
+
})();
|
|
293
|
+
let managedRun = null;
|
|
294
|
+
let usingPty = spawnSpec.mode === "pty";
|
|
295
|
+
const cursorResponse = buildCursorPositionResponse();
|
|
296
|
+
const onSupervisorStdout = (chunk) => {
|
|
297
|
+
if (usingPty) {
|
|
298
|
+
const { cleaned, requests } = stripDsrRequests(chunk);
|
|
299
|
+
if (requests > 0 && managedRun?.stdin) {
|
|
300
|
+
for (let i = 0; i < requests; i += 1) {
|
|
301
|
+
managedRun.stdin.write(cursorResponse);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
handleStdout(cleaned);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
handleStdout(chunk);
|
|
308
|
+
};
|
|
309
|
+
try {
|
|
310
|
+
const spawnBase = {
|
|
311
|
+
runId: sessionId,
|
|
312
|
+
sessionId: opts.sessionKey?.trim() || sessionId,
|
|
313
|
+
backendId: opts.sandbox ? "exec-sandbox" : "exec-host",
|
|
314
|
+
scopeKey: opts.scopeKey,
|
|
315
|
+
cwd: opts.workdir,
|
|
316
|
+
env: spawnSpec.env,
|
|
317
|
+
timeoutMs,
|
|
318
|
+
captureOutput: false,
|
|
319
|
+
onStdout: onSupervisorStdout,
|
|
320
|
+
onStderr: handleStderr,
|
|
321
|
+
};
|
|
322
|
+
managedRun =
|
|
323
|
+
spawnSpec.mode === "pty"
|
|
324
|
+
? await supervisor.spawn({
|
|
325
|
+
...spawnBase,
|
|
326
|
+
mode: "pty",
|
|
327
|
+
ptyCommand: spawnSpec.ptyCommand,
|
|
328
|
+
})
|
|
329
|
+
: await supervisor.spawn({
|
|
330
|
+
...spawnBase,
|
|
331
|
+
mode: "child",
|
|
332
|
+
argv: spawnSpec.argv,
|
|
333
|
+
stdinMode: spawnSpec.stdinMode,
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
catch (err) {
|
|
337
|
+
if (spawnSpec.mode === "pty") {
|
|
338
|
+
const warning = `Warning: PTY spawn failed (${String(err)}); retrying without PTY for \`${opts.command}\`.`;
|
|
339
|
+
logWarn(`exec: PTY spawn failed (${String(err)}); retrying without PTY for "${opts.command}".`);
|
|
340
|
+
opts.warnings.push(warning);
|
|
341
|
+
usingPty = false;
|
|
342
|
+
try {
|
|
343
|
+
managedRun = await supervisor.spawn({
|
|
344
|
+
runId: sessionId,
|
|
345
|
+
sessionId: opts.sessionKey?.trim() || sessionId,
|
|
346
|
+
backendId: "exec-host",
|
|
347
|
+
scopeKey: opts.scopeKey,
|
|
348
|
+
mode: "child",
|
|
349
|
+
argv: spawnSpec.childFallbackArgv,
|
|
350
|
+
cwd: opts.workdir,
|
|
351
|
+
env: spawnSpec.env,
|
|
352
|
+
stdinMode: "pipe-open",
|
|
353
|
+
timeoutMs,
|
|
354
|
+
captureOutput: false,
|
|
355
|
+
onStdout: handleStdout,
|
|
356
|
+
onStderr: handleStderr,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
catch (retryErr) {
|
|
360
|
+
markExited(session, null, null, "failed");
|
|
361
|
+
maybeNotifyOnExit(session, "failed");
|
|
362
|
+
throw retryErr;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
markExited(session, null, null, "failed");
|
|
367
|
+
maybeNotifyOnExit(session, "failed");
|
|
368
|
+
throw err;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
session.stdin = managedRun.stdin;
|
|
372
|
+
session.pid = managedRun.pid;
|
|
373
|
+
const promise = managedRun
|
|
374
|
+
.wait()
|
|
375
|
+
.then((exit) => {
|
|
376
|
+
const durationMs = Date.now() - startedAt;
|
|
377
|
+
const isNormalExit = exit.reason === "exit";
|
|
378
|
+
const status = isNormalExit ? "completed" : "failed";
|
|
379
|
+
markExited(session, exit.exitCode, exit.exitSignal, status);
|
|
380
|
+
maybeNotifyOnExit(session, status);
|
|
381
|
+
if (!session.child && session.stdin) {
|
|
382
|
+
session.stdin.destroyed = true;
|
|
383
|
+
}
|
|
384
|
+
const aggregated = session.aggregated.trim();
|
|
385
|
+
if (status === "completed") {
|
|
386
|
+
const exitCode = exit.exitCode ?? 0;
|
|
387
|
+
const exitMsg = exitCode !== 0 ? `\n\n(Command exited with code ${exitCode})` : "";
|
|
388
|
+
return {
|
|
389
|
+
status: "completed",
|
|
390
|
+
exitCode,
|
|
391
|
+
exitSignal: exit.exitSignal,
|
|
392
|
+
durationMs,
|
|
393
|
+
aggregated: aggregated + exitMsg,
|
|
394
|
+
timedOut: false,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
const reason = exit.reason === "overall-timeout"
|
|
398
|
+
? `Command timed out after ${opts.timeoutSec} seconds`
|
|
399
|
+
: exit.reason === "no-output-timeout"
|
|
400
|
+
? "Command timed out waiting for output"
|
|
401
|
+
: exit.exitSignal != null
|
|
402
|
+
? `Command aborted by signal ${exit.exitSignal}`
|
|
403
|
+
: "Command aborted before exit code was captured";
|
|
404
|
+
return {
|
|
405
|
+
status: "failed",
|
|
406
|
+
exitCode: exit.exitCode,
|
|
407
|
+
exitSignal: exit.exitSignal,
|
|
408
|
+
durationMs,
|
|
409
|
+
aggregated,
|
|
410
|
+
timedOut: exit.timedOut,
|
|
411
|
+
reason: aggregated ? `${aggregated}\n\n${reason}` : reason,
|
|
412
|
+
};
|
|
413
|
+
})
|
|
414
|
+
.catch((err) => {
|
|
415
|
+
markExited(session, null, null, "failed");
|
|
416
|
+
maybeNotifyOnExit(session, "failed");
|
|
417
|
+
const aggregated = session.aggregated.trim();
|
|
418
|
+
const message = aggregated ? `${aggregated}\n\n${String(err)}` : String(err);
|
|
419
|
+
return {
|
|
420
|
+
status: "failed",
|
|
421
|
+
exitCode: null,
|
|
422
|
+
exitSignal: null,
|
|
423
|
+
durationMs: Date.now() - startedAt,
|
|
424
|
+
aggregated,
|
|
425
|
+
timedOut: false,
|
|
426
|
+
reason: message,
|
|
427
|
+
};
|
|
428
|
+
});
|
|
429
|
+
return {
|
|
430
|
+
session,
|
|
431
|
+
startedAt,
|
|
432
|
+
pid: session.pid ?? undefined,
|
|
433
|
+
promise,
|
|
434
|
+
kill: () => {
|
|
435
|
+
managedRun?.cancel("manual-cancel");
|
|
436
|
+
},
|
|
437
|
+
};
|
|
438
|
+
}
|
|
@@ -197,3 +197,9 @@ export function pad(str, width) {
|
|
|
197
197
|
return str;
|
|
198
198
|
return str + " ".repeat(width - str.length);
|
|
199
199
|
}
|
|
200
|
+
export function clampWithDefault(value, defaultValue, min, max) {
|
|
201
|
+
if (value === undefined || Number.isNaN(value)) {
|
|
202
|
+
return defaultValue;
|
|
203
|
+
}
|
|
204
|
+
return Math.min(Math.max(value, min), max);
|
|
205
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { CLI_FRESH_WATCHDOG_DEFAULTS, CLI_RESUME_WATCHDOG_DEFAULTS, CLI_WATCHDOG_MIN_TIMEOUT_MS, } from "../cli-watchdog-defaults.js";
|
|
3
|
+
function pickWatchdogProfile(backend, useResume) {
|
|
4
|
+
const defaults = useResume ? CLI_RESUME_WATCHDOG_DEFAULTS : CLI_FRESH_WATCHDOG_DEFAULTS;
|
|
5
|
+
const configured = useResume
|
|
6
|
+
? backend.reliability?.watchdog?.resume
|
|
7
|
+
: backend.reliability?.watchdog?.fresh;
|
|
8
|
+
const ratio = (() => {
|
|
9
|
+
const value = configured?.noOutputTimeoutRatio;
|
|
10
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
11
|
+
return defaults.noOutputTimeoutRatio;
|
|
12
|
+
}
|
|
13
|
+
return Math.max(0.05, Math.min(0.95, value));
|
|
14
|
+
})();
|
|
15
|
+
const minMs = (() => {
|
|
16
|
+
const value = configured?.minMs;
|
|
17
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
18
|
+
return defaults.minMs;
|
|
19
|
+
}
|
|
20
|
+
return Math.max(CLI_WATCHDOG_MIN_TIMEOUT_MS, Math.floor(value));
|
|
21
|
+
})();
|
|
22
|
+
const maxMs = (() => {
|
|
23
|
+
const value = configured?.maxMs;
|
|
24
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
25
|
+
return defaults.maxMs;
|
|
26
|
+
}
|
|
27
|
+
return Math.max(CLI_WATCHDOG_MIN_TIMEOUT_MS, Math.floor(value));
|
|
28
|
+
})();
|
|
29
|
+
return {
|
|
30
|
+
noOutputTimeoutMs: typeof configured?.noOutputTimeoutMs === "number" &&
|
|
31
|
+
Number.isFinite(configured.noOutputTimeoutMs)
|
|
32
|
+
? Math.max(CLI_WATCHDOG_MIN_TIMEOUT_MS, Math.floor(configured.noOutputTimeoutMs))
|
|
33
|
+
: undefined,
|
|
34
|
+
noOutputTimeoutRatio: ratio,
|
|
35
|
+
minMs: Math.min(minMs, maxMs),
|
|
36
|
+
maxMs: Math.max(minMs, maxMs),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function resolveCliNoOutputTimeoutMs(params) {
|
|
40
|
+
const profile = pickWatchdogProfile(params.backend, params.useResume);
|
|
41
|
+
// Keep watchdog below global timeout in normal cases.
|
|
42
|
+
const cap = Math.max(CLI_WATCHDOG_MIN_TIMEOUT_MS, params.timeoutMs - 1_000);
|
|
43
|
+
if (profile.noOutputTimeoutMs !== undefined) {
|
|
44
|
+
return Math.min(profile.noOutputTimeoutMs, cap);
|
|
45
|
+
}
|
|
46
|
+
const computed = Math.floor(params.timeoutMs * profile.noOutputTimeoutRatio);
|
|
47
|
+
const bounded = Math.min(profile.maxMs, Math.max(profile.minMs, computed));
|
|
48
|
+
return Math.min(bounded, cap);
|
|
49
|
+
}
|
|
50
|
+
export function buildCliSupervisorScopeKey(params) {
|
|
51
|
+
const commandToken = path
|
|
52
|
+
.basename(params.backend.command ?? "")
|
|
53
|
+
.trim()
|
|
54
|
+
.toLowerCase();
|
|
55
|
+
const backendToken = params.backendId.trim().toLowerCase();
|
|
56
|
+
const sessionToken = params.cliSessionId?.trim();
|
|
57
|
+
if (!sessionToken) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
return `cli:${backendToken}:${commandToken}:${sessionToken}`;
|
|
61
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const CLI_WATCHDOG_MIN_TIMEOUT_MS = 1_000;
|
|
2
|
+
export const CLI_FRESH_WATCHDOG_DEFAULTS = {
|
|
3
|
+
noOutputTimeoutRatio: 0.8,
|
|
4
|
+
minMs: 180_000,
|
|
5
|
+
maxMs: 600_000,
|
|
6
|
+
};
|
|
7
|
+
export const CLI_RESUME_WATCHDOG_DEFAULTS = {
|
|
8
|
+
noOutputTimeoutRatio: 0.3,
|
|
9
|
+
minMs: 60_000,
|
|
10
|
+
maxMs: 180_000,
|
|
11
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Exponential backoff schedule for command polling
|
|
2
|
+
const BACKOFF_SCHEDULE_MS = [5000, 10000, 30000, 60000];
|
|
3
|
+
/**
|
|
4
|
+
* Calculate suggested retry delay based on consecutive no-output poll count.
|
|
5
|
+
* Implements exponential backoff schedule: 5s → 10s → 30s → 60s (capped).
|
|
6
|
+
*/
|
|
7
|
+
export function calculateBackoffMs(consecutiveNoOutputPolls) {
|
|
8
|
+
const index = Math.min(consecutiveNoOutputPolls, BACKOFF_SCHEDULE_MS.length - 1);
|
|
9
|
+
return BACKOFF_SCHEDULE_MS[index] ?? 60000;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Record a command poll and return suggested retry delay.
|
|
13
|
+
* @param state Session state to track polling in
|
|
14
|
+
* @param commandId Unique identifier for the command being polled
|
|
15
|
+
* @param hasNewOutput Whether this poll returned new output
|
|
16
|
+
* @returns Suggested delay in milliseconds before next poll
|
|
17
|
+
*/
|
|
18
|
+
export function recordCommandPoll(state, commandId, hasNewOutput) {
|
|
19
|
+
if (!state.commandPollCounts) {
|
|
20
|
+
state.commandPollCounts = new Map();
|
|
21
|
+
}
|
|
22
|
+
const existing = state.commandPollCounts.get(commandId);
|
|
23
|
+
const now = Date.now();
|
|
24
|
+
if (hasNewOutput) {
|
|
25
|
+
state.commandPollCounts.set(commandId, { count: 0, lastPollAt: now });
|
|
26
|
+
return BACKOFF_SCHEDULE_MS[0] ?? 5000;
|
|
27
|
+
}
|
|
28
|
+
const newCount = (existing?.count ?? -1) + 1;
|
|
29
|
+
state.commandPollCounts.set(commandId, { count: newCount, lastPollAt: now });
|
|
30
|
+
return calculateBackoffMs(newCount);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get current suggested backoff for a command without modifying state.
|
|
34
|
+
* Useful for checking current backoff level.
|
|
35
|
+
*/
|
|
36
|
+
export function getCommandPollSuggestion(state, commandId) {
|
|
37
|
+
const pollData = state.commandPollCounts?.get(commandId);
|
|
38
|
+
if (!pollData) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
return calculateBackoffMs(pollData.count);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Reset poll count for a command (e.g., when command completes).
|
|
45
|
+
*/
|
|
46
|
+
export function resetCommandPollCount(state, commandId) {
|
|
47
|
+
state.commandPollCounts?.delete(commandId);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Prune stale command poll records (older than 1 hour).
|
|
51
|
+
* Call periodically to prevent memory bloat.
|
|
52
|
+
*/
|
|
53
|
+
export function pruneStaleCommandPolls(state, maxAgeMs = 3600000) {
|
|
54
|
+
if (!state.commandPollCounts) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const now = Date.now();
|
|
58
|
+
for (const [commandId, data] of state.commandPollCounts.entries()) {
|
|
59
|
+
if (now - data.lastPollAt > maxAgeMs) {
|
|
60
|
+
state.commandPollCounts.delete(commandId);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { formatUserTime, resolveUserTimeFormat, resolveUserTimezone, } from "./date-time.js";
|
|
2
|
+
export function resolveCronStyleNow(cfg, nowMs) {
|
|
3
|
+
const userTimezone = resolveUserTimezone(cfg.agents?.defaults?.userTimezone);
|
|
4
|
+
const userTimeFormat = resolveUserTimeFormat(cfg.agents?.defaults?.timeFormat);
|
|
5
|
+
const formattedTime = formatUserTime(new Date(nowMs), userTimezone, userTimeFormat) ?? new Date(nowMs).toISOString();
|
|
6
|
+
const timeLine = `Current time: ${formattedTime} (${userTimezone})`;
|
|
7
|
+
return { userTimezone, formattedTime, timeLine };
|
|
8
|
+
}
|
|
9
|
+
export function appendCronStyleCurrentTimeLine(text, cfg, nowMs) {
|
|
10
|
+
const base = text.trimEnd();
|
|
11
|
+
if (!base || base.includes("Current time:")) {
|
|
12
|
+
return base;
|
|
13
|
+
}
|
|
14
|
+
const { timeLine } = resolveCronStyleNow(cfg, nowMs);
|
|
15
|
+
return `${base}\n${timeLine}`;
|
|
16
|
+
}
|