@poolzin/pool-bot 2026.2.17 → 2026.2.18
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 +17 -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/discord/src/channel.js +366 -0
- package/extensions/discord/src/runtime.js +10 -0
- package/extensions/feishu/index.ts +63 -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/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/index.ts +161 -0
- package/extensions/minimax-portal-auth/oauth.ts +247 -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/index.ts +177 -0
- package/extensions/phone-control/index.ts +421 -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/telegram/src/channel.js +424 -0
- package/extensions/telegram/src/runtime.js +10 -0
- package/extensions/thread-ownership/index.ts +133 -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
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { assertMediaNotDataUrl, resolveSandboxedMediaSource } from "../../agents/sandbox-paths.js";
|
|
5
|
+
import { readStringParam } from "../../agents/tools/common.js";
|
|
6
|
+
import { extensionForMime } from "../../media/mime.js";
|
|
7
|
+
import { parseSlackTarget } from "../../slack/targets.js";
|
|
8
|
+
import { parseTelegramTarget } from "../../telegram/targets.js";
|
|
9
|
+
import { loadWebMedia } from "../../web/media.js";
|
|
10
|
+
export function readBooleanParam(params, key) {
|
|
11
|
+
const raw = params[key];
|
|
12
|
+
if (typeof raw === "boolean") {
|
|
13
|
+
return raw;
|
|
14
|
+
}
|
|
15
|
+
if (typeof raw === "string") {
|
|
16
|
+
const trimmed = raw.trim().toLowerCase();
|
|
17
|
+
if (trimmed === "true") {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
if (trimmed === "false") {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
export function resolveSlackAutoThreadId(params) {
|
|
27
|
+
const context = params.toolContext;
|
|
28
|
+
if (!context?.currentThreadTs || !context.currentChannelId) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
// Only mirror auto-threading when Slack would reply in the active thread for this channel.
|
|
32
|
+
if (context.replyToMode !== "all" && context.replyToMode !== "first") {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
const parsedTarget = parseSlackTarget(params.to, { defaultKind: "channel" });
|
|
36
|
+
if (!parsedTarget || parsedTarget.kind !== "channel") {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
if (parsedTarget.id.toLowerCase() !== context.currentChannelId.toLowerCase()) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
if (context.replyToMode === "first" && context.hasRepliedRef?.value) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
return context.currentThreadTs;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Auto-inject Telegram forum topic thread ID when the message tool targets
|
|
49
|
+
* the same chat the session originated from. Mirrors the Slack auto-threading
|
|
50
|
+
* pattern so media, buttons, and other tool-sent messages land in the correct
|
|
51
|
+
* topic instead of the General Topic.
|
|
52
|
+
*
|
|
53
|
+
* Unlike Slack, we do not gate on `replyToMode` here: Telegram forum topics
|
|
54
|
+
* are persistent sub-channels (not ephemeral reply threads), so auto-injection
|
|
55
|
+
* should always apply when the target chat matches.
|
|
56
|
+
*/
|
|
57
|
+
export function resolveTelegramAutoThreadId(params) {
|
|
58
|
+
const context = params.toolContext;
|
|
59
|
+
if (!context?.currentThreadTs || !context.currentChannelId) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
// Use parseTelegramTarget to extract canonical chatId from both sides,
|
|
63
|
+
// mirroring how Slack uses parseSlackTarget. This handles format variations
|
|
64
|
+
// like `telegram:group:123:topic:456` vs `telegram:123`.
|
|
65
|
+
const parsedTo = parseTelegramTarget(params.to);
|
|
66
|
+
const parsedChannel = parseTelegramTarget(context.currentChannelId);
|
|
67
|
+
if (parsedTo.chatId.toLowerCase() !== parsedChannel.chatId.toLowerCase()) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
return context.currentThreadTs;
|
|
71
|
+
}
|
|
72
|
+
function resolveAttachmentMaxBytes(params) {
|
|
73
|
+
const accountId = typeof params.accountId === "string" ? params.accountId.trim() : "";
|
|
74
|
+
const channelCfg = params.cfg.channels?.[params.channel];
|
|
75
|
+
const channelObj = channelCfg && typeof channelCfg === "object"
|
|
76
|
+
? channelCfg
|
|
77
|
+
: undefined;
|
|
78
|
+
const channelMediaMax = typeof channelObj?.mediaMaxMb === "number" ? channelObj.mediaMaxMb : undefined;
|
|
79
|
+
const accountsObj = channelObj?.accounts && typeof channelObj.accounts === "object"
|
|
80
|
+
? channelObj.accounts
|
|
81
|
+
: undefined;
|
|
82
|
+
const accountCfg = accountId && accountsObj ? accountsObj[accountId] : undefined;
|
|
83
|
+
const accountMediaMax = accountCfg && typeof accountCfg === "object"
|
|
84
|
+
? accountCfg.mediaMaxMb
|
|
85
|
+
: undefined;
|
|
86
|
+
// Priority: account-specific > channel-level > global default
|
|
87
|
+
const limitMb = (typeof accountMediaMax === "number" ? accountMediaMax : undefined) ??
|
|
88
|
+
channelMediaMax ??
|
|
89
|
+
params.cfg.agents?.defaults?.mediaMaxMb;
|
|
90
|
+
return typeof limitMb === "number" ? limitMb * 1024 * 1024 : undefined;
|
|
91
|
+
}
|
|
92
|
+
function inferAttachmentFilename(params) {
|
|
93
|
+
const mediaHint = params.mediaHint?.trim();
|
|
94
|
+
if (mediaHint) {
|
|
95
|
+
try {
|
|
96
|
+
if (mediaHint.startsWith("file://")) {
|
|
97
|
+
const filePath = fileURLToPath(mediaHint);
|
|
98
|
+
const base = path.basename(filePath);
|
|
99
|
+
if (base) {
|
|
100
|
+
return base;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else if (/^https?:\/\//i.test(mediaHint)) {
|
|
104
|
+
const url = new URL(mediaHint);
|
|
105
|
+
const base = path.basename(url.pathname);
|
|
106
|
+
if (base) {
|
|
107
|
+
return base;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
const base = path.basename(mediaHint);
|
|
112
|
+
if (base) {
|
|
113
|
+
return base;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// fall through to content-type based default
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const ext = params.contentType ? extensionForMime(params.contentType) : undefined;
|
|
122
|
+
return ext ? `attachment${ext}` : "attachment";
|
|
123
|
+
}
|
|
124
|
+
function normalizeBase64Payload(params) {
|
|
125
|
+
if (!params.base64) {
|
|
126
|
+
return { base64: params.base64, contentType: params.contentType };
|
|
127
|
+
}
|
|
128
|
+
const match = /^data:([^;]+);base64,(.*)$/i.exec(params.base64.trim());
|
|
129
|
+
if (!match) {
|
|
130
|
+
return { base64: params.base64, contentType: params.contentType };
|
|
131
|
+
}
|
|
132
|
+
const [, mime, payload] = match;
|
|
133
|
+
return {
|
|
134
|
+
base64: payload,
|
|
135
|
+
contentType: params.contentType ?? mime,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async function hydrateAttachmentPayload(params) {
|
|
139
|
+
const contentTypeParam = params.contentTypeParam ?? undefined;
|
|
140
|
+
const rawBuffer = readStringParam(params.args, "buffer", { trim: false });
|
|
141
|
+
const normalized = normalizeBase64Payload({
|
|
142
|
+
base64: rawBuffer,
|
|
143
|
+
contentType: contentTypeParam ?? undefined,
|
|
144
|
+
});
|
|
145
|
+
if (normalized.base64 !== rawBuffer && normalized.base64) {
|
|
146
|
+
params.args.buffer = normalized.base64;
|
|
147
|
+
if (normalized.contentType && !contentTypeParam) {
|
|
148
|
+
params.args.contentType = normalized.contentType;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const filename = readStringParam(params.args, "filename");
|
|
152
|
+
const mediaSource = (params.mediaHint ?? undefined) || (params.fileHint ?? undefined);
|
|
153
|
+
if (!params.dryRun && !readStringParam(params.args, "buffer", { trim: false }) && mediaSource) {
|
|
154
|
+
const maxBytes = resolveAttachmentMaxBytes({
|
|
155
|
+
cfg: params.cfg,
|
|
156
|
+
channel: params.channel,
|
|
157
|
+
accountId: params.accountId,
|
|
158
|
+
});
|
|
159
|
+
// mediaSource already validated by normalizeSandboxMediaList; allow bypass but force explicit readFile.
|
|
160
|
+
const media = await loadWebMedia(mediaSource, {
|
|
161
|
+
maxBytes,
|
|
162
|
+
sandboxValidated: true,
|
|
163
|
+
readFile: (filePath) => fs.readFile(filePath),
|
|
164
|
+
});
|
|
165
|
+
params.args.buffer = media.buffer.toString("base64");
|
|
166
|
+
if (!contentTypeParam && media.contentType) {
|
|
167
|
+
params.args.contentType = media.contentType;
|
|
168
|
+
}
|
|
169
|
+
if (!filename) {
|
|
170
|
+
params.args.filename = inferAttachmentFilename({
|
|
171
|
+
mediaHint: media.fileName ?? mediaSource,
|
|
172
|
+
contentType: media.contentType ?? contentTypeParam ?? undefined,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else if (!filename) {
|
|
177
|
+
params.args.filename = inferAttachmentFilename({
|
|
178
|
+
mediaHint: mediaSource,
|
|
179
|
+
contentType: contentTypeParam ?? undefined,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
export async function normalizeSandboxMediaParams(params) {
|
|
184
|
+
const sandboxRoot = params.sandboxRoot?.trim();
|
|
185
|
+
const mediaKeys = ["media", "path", "filePath"];
|
|
186
|
+
for (const key of mediaKeys) {
|
|
187
|
+
const raw = readStringParam(params.args, key, { trim: false });
|
|
188
|
+
if (!raw) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
assertMediaNotDataUrl(raw);
|
|
192
|
+
if (!sandboxRoot) {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
const normalized = await resolveSandboxedMediaSource({ media: raw, sandboxRoot });
|
|
196
|
+
if (normalized !== raw) {
|
|
197
|
+
params.args[key] = normalized;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
export async function normalizeSandboxMediaList(params) {
|
|
202
|
+
const sandboxRoot = params.sandboxRoot?.trim();
|
|
203
|
+
const normalized = [];
|
|
204
|
+
const seen = new Set();
|
|
205
|
+
for (const value of params.values) {
|
|
206
|
+
const raw = value?.trim();
|
|
207
|
+
if (!raw) {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
assertMediaNotDataUrl(raw);
|
|
211
|
+
const resolved = sandboxRoot
|
|
212
|
+
? await resolveSandboxedMediaSource({ media: raw, sandboxRoot })
|
|
213
|
+
: raw;
|
|
214
|
+
if (seen.has(resolved)) {
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
seen.add(resolved);
|
|
218
|
+
normalized.push(resolved);
|
|
219
|
+
}
|
|
220
|
+
return normalized;
|
|
221
|
+
}
|
|
222
|
+
async function hydrateAttachmentActionPayload(params) {
|
|
223
|
+
const mediaHint = readStringParam(params.args, "media", { trim: false });
|
|
224
|
+
const fileHint = readStringParam(params.args, "path", { trim: false }) ??
|
|
225
|
+
readStringParam(params.args, "filePath", { trim: false });
|
|
226
|
+
const contentTypeParam = readStringParam(params.args, "contentType") ?? readStringParam(params.args, "mimeType");
|
|
227
|
+
if (params.allowMessageCaptionFallback) {
|
|
228
|
+
const caption = readStringParam(params.args, "caption", { allowEmpty: true })?.trim();
|
|
229
|
+
const message = readStringParam(params.args, "message", { allowEmpty: true })?.trim();
|
|
230
|
+
if (!caption && message) {
|
|
231
|
+
params.args.caption = message;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
await hydrateAttachmentPayload({
|
|
235
|
+
cfg: params.cfg,
|
|
236
|
+
channel: params.channel,
|
|
237
|
+
accountId: params.accountId,
|
|
238
|
+
args: params.args,
|
|
239
|
+
dryRun: params.dryRun,
|
|
240
|
+
contentTypeParam,
|
|
241
|
+
mediaHint,
|
|
242
|
+
fileHint,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
export async function hydrateSetGroupIconParams(params) {
|
|
246
|
+
if (params.action !== "setGroupIcon") {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
await hydrateAttachmentActionPayload(params);
|
|
250
|
+
}
|
|
251
|
+
export async function hydrateSendAttachmentParams(params) {
|
|
252
|
+
if (params.action !== "sendAttachment") {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
await hydrateAttachmentActionPayload({ ...params, allowMessageCaptionFallback: true });
|
|
256
|
+
}
|
|
257
|
+
export function parseButtonsParam(params) {
|
|
258
|
+
const raw = params.buttons;
|
|
259
|
+
if (typeof raw !== "string") {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const trimmed = raw.trim();
|
|
263
|
+
if (!trimmed) {
|
|
264
|
+
delete params.buttons;
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
try {
|
|
268
|
+
params.buttons = JSON.parse(trimmed);
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
throw new Error("--buttons must be valid JSON");
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
export function parseCardParam(params) {
|
|
275
|
+
const raw = params.card;
|
|
276
|
+
if (typeof raw !== "string") {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const trimmed = raw.trim();
|
|
280
|
+
if (!trimmed) {
|
|
281
|
+
delete params.card;
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
params.card = JSON.parse(trimmed);
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
throw new Error("--card must be valid JSON");
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
export function parseComponentsParam(params) {
|
|
292
|
+
const raw = params.components;
|
|
293
|
+
if (typeof raw !== "string") {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const trimmed = raw.trim();
|
|
297
|
+
if (!trimmed) {
|
|
298
|
+
delete params.components;
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
params.components = JSON.parse(trimmed);
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
throw new Error("--components must be valid JSON");
|
|
306
|
+
}
|
|
307
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function extractToolPayload(result) {
|
|
2
|
+
if (result.details !== undefined) {
|
|
3
|
+
return result.details;
|
|
4
|
+
}
|
|
5
|
+
const textBlock = Array.isArray(result.content)
|
|
6
|
+
? result.content.find((block) => block &&
|
|
7
|
+
typeof block === "object" &&
|
|
8
|
+
block.type === "text" &&
|
|
9
|
+
typeof block.text === "string")
|
|
10
|
+
: undefined;
|
|
11
|
+
const text = textBlock?.text;
|
|
12
|
+
if (text) {
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(text);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return text;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return result.content ?? result;
|
|
21
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
export async function readPackageVersion(root) {
|
|
4
|
+
try {
|
|
5
|
+
const raw = await fs.readFile(path.join(root, "package.json"), "utf-8");
|
|
6
|
+
const parsed = JSON.parse(raw);
|
|
7
|
+
return typeof parsed?.version === "string" ? parsed.version : null;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export async function readPackageName(root) {
|
|
14
|
+
try {
|
|
15
|
+
const raw = await fs.readFile(path.join(root, "package.json"), "utf-8");
|
|
16
|
+
const parsed = JSON.parse(raw);
|
|
17
|
+
const name = parsed?.name?.trim();
|
|
18
|
+
return name ? name : null;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { resolveStateDir } from "../config/paths.js";
|
|
3
|
+
export { createAsyncLock, readJsonFile, writeJsonAtomic } from "./json-files.js";
|
|
4
|
+
export function resolvePairingPaths(baseDir, subdir) {
|
|
5
|
+
const root = baseDir ?? resolveStateDir();
|
|
6
|
+
const dir = path.join(root, subdir);
|
|
7
|
+
return {
|
|
8
|
+
dir,
|
|
9
|
+
pendingPath: path.join(dir, "pending.json"),
|
|
10
|
+
pairedPath: path.join(dir, "paired.json"),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function pruneExpiredPending(pendingById, nowMs, ttlMs) {
|
|
14
|
+
for (const [id, req] of Object.entries(pendingById)) {
|
|
15
|
+
if (nowMs - req.ts > ttlMs) {
|
|
16
|
+
delete pendingById[id];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { safeEqualSecret } from "../security/secret-equal.js";
|
|
3
|
+
export const PAIRING_TOKEN_BYTES = 32;
|
|
4
|
+
export function generatePairingToken() {
|
|
5
|
+
return randomBytes(PAIRING_TOKEN_BYTES).toString("base64url");
|
|
6
|
+
}
|
|
7
|
+
export function verifyPairingToken(provided, expected) {
|
|
8
|
+
return safeEqualSecret(provided, expected);
|
|
9
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
export function normalizePathPrepend(entries) {
|
|
3
|
+
if (!Array.isArray(entries)) {
|
|
4
|
+
return [];
|
|
5
|
+
}
|
|
6
|
+
const seen = new Set();
|
|
7
|
+
const normalized = [];
|
|
8
|
+
for (const entry of entries) {
|
|
9
|
+
if (typeof entry !== "string") {
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
const trimmed = entry.trim();
|
|
13
|
+
if (!trimmed || seen.has(trimmed)) {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
seen.add(trimmed);
|
|
17
|
+
normalized.push(trimmed);
|
|
18
|
+
}
|
|
19
|
+
return normalized;
|
|
20
|
+
}
|
|
21
|
+
export function mergePathPrepend(existing, prepend) {
|
|
22
|
+
if (prepend.length === 0) {
|
|
23
|
+
return existing;
|
|
24
|
+
}
|
|
25
|
+
const partsExisting = (existing ?? "")
|
|
26
|
+
.split(path.delimiter)
|
|
27
|
+
.map((part) => part.trim())
|
|
28
|
+
.filter(Boolean);
|
|
29
|
+
const merged = [];
|
|
30
|
+
const seen = new Set();
|
|
31
|
+
for (const part of [...prepend, ...partsExisting]) {
|
|
32
|
+
if (seen.has(part)) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
seen.add(part);
|
|
36
|
+
merged.push(part);
|
|
37
|
+
}
|
|
38
|
+
return merged.join(path.delimiter);
|
|
39
|
+
}
|
|
40
|
+
export function applyPathPrepend(env, prepend, options) {
|
|
41
|
+
if (!Array.isArray(prepend) || prepend.length === 0) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (options?.requireExisting && !env.PATH) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const merged = mergePathPrepend(env.PATH, prepend);
|
|
48
|
+
if (merged) {
|
|
49
|
+
env.PATH = merged;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
const SUPERVISOR_HINT_ENV_VARS = [
|
|
3
|
+
"LAUNCH_JOB_LABEL",
|
|
4
|
+
"LAUNCH_JOB_NAME",
|
|
5
|
+
"INVOCATION_ID",
|
|
6
|
+
"SYSTEMD_EXEC_PID",
|
|
7
|
+
"JOURNAL_STREAM",
|
|
8
|
+
];
|
|
9
|
+
function isTruthy(value) {
|
|
10
|
+
if (!value) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
const normalized = value.trim().toLowerCase();
|
|
14
|
+
return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
|
|
15
|
+
}
|
|
16
|
+
function isLikelySupervisedProcess(env = process.env) {
|
|
17
|
+
return SUPERVISOR_HINT_ENV_VARS.some((key) => {
|
|
18
|
+
const value = env[key];
|
|
19
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Attempt to restart this process with a fresh PID.
|
|
24
|
+
* - supervised environments (launchd/systemd): caller should exit and let supervisor restart
|
|
25
|
+
* - POOLBOT_NO_RESPAWN=1: caller should keep in-process restart behavior (tests/dev)
|
|
26
|
+
* - otherwise: spawn detached child with current argv/execArgv, then caller exits
|
|
27
|
+
*/
|
|
28
|
+
export function restartGatewayProcessWithFreshPid() {
|
|
29
|
+
if (isTruthy(process.env.POOLBOT_NO_RESPAWN)) {
|
|
30
|
+
return { mode: "disabled" };
|
|
31
|
+
}
|
|
32
|
+
if (isLikelySupervisedProcess(process.env)) {
|
|
33
|
+
return { mode: "supervised" };
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const args = [...process.execArgv, ...process.argv.slice(1)];
|
|
37
|
+
const child = spawn(process.execPath, args, {
|
|
38
|
+
env: process.env,
|
|
39
|
+
detached: true,
|
|
40
|
+
stdio: "inherit",
|
|
41
|
+
});
|
|
42
|
+
child.unref();
|
|
43
|
+
return { mode: "spawned", pid: child.pid ?? undefined };
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
47
|
+
return { mode: "failed", detail };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function formatRuntimeStatusWithDetails({ status, pid, state, details = [], }) {
|
|
2
|
+
const runtimeStatus = status ?? "unknown";
|
|
3
|
+
const fullDetails = [];
|
|
4
|
+
if (pid) {
|
|
5
|
+
fullDetails.push(`pid ${pid}`);
|
|
6
|
+
}
|
|
7
|
+
if (state && state.toLowerCase() !== runtimeStatus) {
|
|
8
|
+
fullDetails.push(`state ${state}`);
|
|
9
|
+
}
|
|
10
|
+
for (const detail of details) {
|
|
11
|
+
if (detail) {
|
|
12
|
+
fullDetails.push(detail);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return fullDetails.length > 0 ? `${runtimeStatus} (${fullDetails.join(", ")})` : runtimeStatus;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { resolveSessionAgentId } from "../agents/agent-scope.js";
|
|
2
|
+
import { isDeliverableMessageChannel, normalizeMessageChannel } from "../utils/message-channel.js";
|
|
3
|
+
import { resolveSessionDeliveryTarget } from "./outbound/targets.js";
|
|
4
|
+
import { enqueueSystemEvent } from "./system-events.js";
|
|
5
|
+
const warnedContexts = new Map();
|
|
6
|
+
function shouldSendWarning() {
|
|
7
|
+
return !process.env.VITEST && process.env.NODE_ENV !== "test";
|
|
8
|
+
}
|
|
9
|
+
function buildWarningContext(params) {
|
|
10
|
+
const { warning } = params;
|
|
11
|
+
return [
|
|
12
|
+
warning.activeSessionKey,
|
|
13
|
+
warning.pruneAfterMs,
|
|
14
|
+
warning.maxEntries,
|
|
15
|
+
warning.wouldPrune ? "prune" : "",
|
|
16
|
+
warning.wouldCap ? "cap" : "",
|
|
17
|
+
]
|
|
18
|
+
.filter(Boolean)
|
|
19
|
+
.join("|");
|
|
20
|
+
}
|
|
21
|
+
function formatDuration(ms) {
|
|
22
|
+
if (ms >= 86_400_000) {
|
|
23
|
+
const days = Math.round(ms / 86_400_000);
|
|
24
|
+
return `${days} day${days === 1 ? "" : "s"}`;
|
|
25
|
+
}
|
|
26
|
+
if (ms >= 3_600_000) {
|
|
27
|
+
const hours = Math.round(ms / 3_600_000);
|
|
28
|
+
return `${hours} hour${hours === 1 ? "" : "s"}`;
|
|
29
|
+
}
|
|
30
|
+
if (ms >= 60_000) {
|
|
31
|
+
const mins = Math.round(ms / 60_000);
|
|
32
|
+
return `${mins} minute${mins === 1 ? "" : "s"}`;
|
|
33
|
+
}
|
|
34
|
+
const secs = Math.round(ms / 1000);
|
|
35
|
+
return `${secs} second${secs === 1 ? "" : "s"}`;
|
|
36
|
+
}
|
|
37
|
+
function buildWarningText(warning) {
|
|
38
|
+
const reasons = [];
|
|
39
|
+
if (warning.wouldPrune) {
|
|
40
|
+
reasons.push(`older than ${formatDuration(warning.pruneAfterMs)}`);
|
|
41
|
+
}
|
|
42
|
+
if (warning.wouldCap) {
|
|
43
|
+
reasons.push(`not in the most recent ${warning.maxEntries} sessions`);
|
|
44
|
+
}
|
|
45
|
+
const reasonText = reasons.length > 0 ? reasons.join(" and ") : "over maintenance limits";
|
|
46
|
+
return (`⚠️ Session maintenance warning: this active session would be evicted (${reasonText}). ` +
|
|
47
|
+
`Maintenance is set to warn-only, so nothing was reset. ` +
|
|
48
|
+
`To enforce cleanup, set \`session.maintenance.mode: "enforce"\` or increase the limits.`);
|
|
49
|
+
}
|
|
50
|
+
export async function deliverSessionMaintenanceWarning(params) {
|
|
51
|
+
if (!shouldSendWarning()) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const contextKey = buildWarningContext(params);
|
|
55
|
+
if (warnedContexts.get(params.sessionKey) === contextKey) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
warnedContexts.set(params.sessionKey, contextKey);
|
|
59
|
+
const text = buildWarningText(params.warning);
|
|
60
|
+
const target = resolveSessionDeliveryTarget({
|
|
61
|
+
entry: params.entry,
|
|
62
|
+
requestedChannel: "last",
|
|
63
|
+
});
|
|
64
|
+
if (!target.channel || !target.to) {
|
|
65
|
+
enqueueSystemEvent(text, { sessionKey: params.sessionKey });
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const channel = normalizeMessageChannel(target.channel) ?? target.channel;
|
|
69
|
+
if (!isDeliverableMessageChannel(channel)) {
|
|
70
|
+
enqueueSystemEvent(text, { sessionKey: params.sessionKey });
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const { deliverOutboundPayloads } = await import("./outbound/deliver.js");
|
|
75
|
+
await deliverOutboundPayloads({
|
|
76
|
+
cfg: params.cfg,
|
|
77
|
+
channel,
|
|
78
|
+
to: target.to,
|
|
79
|
+
accountId: target.accountId,
|
|
80
|
+
threadId: target.threadId,
|
|
81
|
+
payloads: [{ text }],
|
|
82
|
+
agentId: resolveSessionAgentId({ sessionKey: params.sessionKey, config: params.cfg }),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
console.warn(`Failed to deliver session maintenance warning: ${String(err)}`);
|
|
87
|
+
enqueueSystemEvent(text, { sessionKey: params.sessionKey });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
function basenameLower(token) {
|
|
3
|
+
const win = path.win32.basename(token);
|
|
4
|
+
const posix = path.posix.basename(token);
|
|
5
|
+
const base = win.length < posix.length ? win : posix;
|
|
6
|
+
return base.trim().toLowerCase();
|
|
7
|
+
}
|
|
8
|
+
export function formatExecCommand(argv) {
|
|
9
|
+
return argv
|
|
10
|
+
.map((arg) => {
|
|
11
|
+
const trimmed = arg.trim();
|
|
12
|
+
if (!trimmed) {
|
|
13
|
+
return '""';
|
|
14
|
+
}
|
|
15
|
+
const needsQuotes = /\s|"/.test(trimmed);
|
|
16
|
+
if (!needsQuotes) {
|
|
17
|
+
return trimmed;
|
|
18
|
+
}
|
|
19
|
+
return `"${trimmed.replace(/"/g, '\\"')}"`;
|
|
20
|
+
})
|
|
21
|
+
.join(" ");
|
|
22
|
+
}
|
|
23
|
+
export function extractShellCommandFromArgv(argv) {
|
|
24
|
+
const token0 = argv[0]?.trim();
|
|
25
|
+
if (!token0) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const base0 = basenameLower(token0);
|
|
29
|
+
// POSIX-style shells: sh -lc "<cmd>"
|
|
30
|
+
if (base0 === "sh" ||
|
|
31
|
+
base0 === "bash" ||
|
|
32
|
+
base0 === "zsh" ||
|
|
33
|
+
base0 === "dash" ||
|
|
34
|
+
base0 === "ksh") {
|
|
35
|
+
const flag = argv[1]?.trim();
|
|
36
|
+
if (flag !== "-lc" && flag !== "-c") {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const cmd = argv[2];
|
|
40
|
+
return typeof cmd === "string" ? cmd : null;
|
|
41
|
+
}
|
|
42
|
+
// Windows cmd.exe: cmd.exe /d /s /c "<cmd>"
|
|
43
|
+
if (base0 === "cmd.exe" || base0 === "cmd") {
|
|
44
|
+
const idx = argv.findIndex((item) => String(item).trim().toLowerCase() === "/c");
|
|
45
|
+
if (idx === -1) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const cmd = argv[idx + 1];
|
|
49
|
+
return typeof cmd === "string" ? cmd : null;
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
export function validateSystemRunCommandConsistency(params) {
|
|
54
|
+
const raw = typeof params.rawCommand === "string" && params.rawCommand.trim().length > 0
|
|
55
|
+
? params.rawCommand.trim()
|
|
56
|
+
: null;
|
|
57
|
+
const shellCommand = extractShellCommandFromArgv(params.argv);
|
|
58
|
+
const inferred = shellCommand ? shellCommand.trim() : formatExecCommand(params.argv);
|
|
59
|
+
if (raw && raw !== inferred) {
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
message: "INVALID_REQUEST: rawCommand does not match command",
|
|
63
|
+
details: {
|
|
64
|
+
code: "RAW_COMMAND_MISMATCH",
|
|
65
|
+
rawCommand: raw,
|
|
66
|
+
inferred,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
ok: true,
|
|
72
|
+
// Only treat this as a shell command when argv is a recognized shell wrapper.
|
|
73
|
+
// For direct argv execution, rawCommand is purely display/approval text and
|
|
74
|
+
// must match the formatted argv.
|
|
75
|
+
shellCommand: shellCommand ? (raw ?? shellCommand) : null,
|
|
76
|
+
cmdText: raw ?? shellCommand ?? inferred,
|
|
77
|
+
};
|
|
78
|
+
}
|