@poolzin/pool-bot 2026.2.21 → 2026.2.23
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/api-key-rotation.js +47 -0
- package/dist/agents/apply-patch-update.js +19 -9
- package/dist/agents/apply-patch.js +72 -47
- package/dist/agents/bash-tools.exec.js +141 -559
- package/dist/agents/cli-backends.js +49 -6
- package/dist/agents/cli-runner/helpers.js +69 -152
- package/dist/agents/cli-runner.js +70 -19
- package/dist/agents/identity.js +20 -1
- package/dist/agents/image-sanitization.js +9 -0
- package/dist/agents/live-auth-keys.js +123 -26
- package/dist/agents/live-model-filter.js +13 -4
- package/dist/agents/model-catalog.js +40 -9
- package/dist/agents/model-forward-compat.js +60 -23
- package/dist/agents/model-selection.js +134 -41
- package/dist/agents/pi-auth-json.js +2 -2
- package/dist/agents/pi-embedded-helpers/bootstrap.js +65 -15
- package/dist/agents/pi-embedded-helpers/errors.js +140 -15
- package/dist/agents/pi-embedded-helpers/images.js +22 -12
- package/dist/agents/pi-embedded-helpers.js +2 -2
- package/dist/agents/pi-embedded-runner/abort.js +10 -3
- package/dist/agents/pi-embedded-runner/compact.js +230 -32
- package/dist/agents/pi-embedded-runner/extra-params.js +203 -12
- package/dist/agents/pi-embedded-runner/google.js +109 -19
- package/dist/agents/pi-embedded-runner/history.js +35 -17
- package/dist/agents/pi-embedded-runner/run/attempt.js +386 -95
- package/dist/agents/pi-embedded-runner/run/images.js +81 -55
- package/dist/agents/pi-embedded-runner/run/payloads.js +89 -39
- package/dist/agents/pi-embedded-runner/run.js +193 -25
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +2 -2
- package/dist/agents/pi-embedded-runner/runs.js +17 -8
- package/dist/agents/pi-embedded-runner/tool-result-context-guard.js +262 -0
- package/dist/agents/pi-embedded-runner.js +1 -1
- package/dist/agents/pi-embedded-subscribe.handlers.tools.js +180 -10
- package/dist/agents/pi-embedded-subscribe.js +37 -0
- package/dist/agents/pi-embedded-subscribe.tools.js +127 -30
- package/dist/agents/pi-model-discovery.js +9 -2
- package/dist/agents/pi-tool-definition-adapter.js +60 -8
- package/dist/agents/pi-tools.before-tool-call.js +1 -1
- package/dist/agents/pi-tools.js +113 -94
- package/dist/agents/pi-tools.read.js +337 -38
- package/dist/agents/poolbot-tools.js +14 -5
- package/dist/agents/sandbox/docker.js +10 -5
- package/dist/agents/sandbox/registry.js +96 -46
- package/dist/agents/sandbox/sanitize-env-vars.js +82 -0
- package/dist/agents/sandbox-paths.js +43 -10
- package/dist/agents/session-tool-result-guard-wrapper.js +23 -11
- package/dist/agents/session-tool-result-guard.js +39 -39
- package/dist/agents/session-transcript-repair.js +36 -33
- package/dist/agents/session-write-lock.js +62 -44
- package/dist/agents/skills/frontmatter.js +49 -88
- package/dist/agents/skills/workspace.js +335 -28
- package/dist/agents/subagent-announce.js +508 -174
- package/dist/agents/subagent-registry.js +45 -4
- package/dist/agents/subagent-spawn.js +16 -33
- package/dist/agents/system-prompt-report.js +27 -10
- package/dist/agents/system-prompt.js +26 -32
- package/dist/agents/tool-call-id.js +69 -17
- package/dist/agents/tool-display-common.js +1 -1
- package/dist/agents/tool-images.js +64 -31
- package/dist/agents/tools/canvas-tool.js +17 -11
- package/dist/agents/tools/common.js +37 -19
- package/dist/agents/tools/cron-tool.js +40 -38
- package/dist/agents/tools/gateway.js +70 -2
- package/dist/agents/tools/message-tool.js +181 -40
- package/dist/agents/tools/nodes-tool.js +128 -36
- package/dist/agents/tools/nodes-utils.js +12 -38
- package/dist/agents/tools/session-status-tool.js +24 -71
- package/dist/agents/tools/sessions-helpers.js +38 -210
- package/dist/agents/tools/sessions-spawn-tool.js +28 -198
- package/dist/agents/tools/telegram-actions.js +58 -7
- package/dist/agents/tools/web-fetch-utils.js +112 -7
- package/dist/agents/tools/web-fetch.js +279 -175
- package/dist/agents/tools/web-shared.js +71 -8
- package/dist/agents/usage.js +25 -16
- package/dist/auto-reply/commands-registry.data.js +85 -11
- package/dist/auto-reply/dispatch.js +40 -21
- package/dist/auto-reply/reply/abort.js +102 -33
- package/dist/auto-reply/reply/commands-core.js +82 -33
- package/dist/auto-reply/reply/commands-export-session.js +1 -1
- package/dist/auto-reply/reply/commands-info.js +41 -12
- package/dist/auto-reply/reply/commands-subagents.js +352 -100
- package/dist/auto-reply/reply/commands-system-prompt.js +2 -2
- package/dist/auto-reply/reply/dispatch-from-config.js +100 -29
- package/dist/auto-reply/reply/elevated-unavailable.js +1 -1
- package/dist/auto-reply/reply/inbound-meta.js +12 -1
- package/dist/auto-reply/reply/mentions.js +18 -11
- package/dist/auto-reply/reply/normalize-reply.js +17 -8
- package/dist/auto-reply/reply/reply-dispatcher.js +62 -10
- package/dist/auto-reply/reply/session.js +102 -21
- package/dist/auto-reply/reply/streaming-directives.js +16 -5
- package/dist/auto-reply/status.js +73 -50
- package/dist/browser/extension-relay.js +3 -3
- package/dist/browser/http-auth.js +1 -1
- package/dist/browser/paths.js +2 -2
- package/dist/build-info.json +3 -3
- package/dist/channels/allowlist-match.js +20 -0
- package/dist/channels/allowlists/resolve-utils.js +65 -2
- package/dist/channels/chat-type.js +8 -4
- package/dist/channels/dock.js +127 -35
- package/dist/channels/draft-stream-loop.js +6 -2
- package/dist/channels/plugins/actions/telegram.js +42 -18
- package/dist/channels/plugins/allowlist-match.js +1 -1
- package/dist/channels/plugins/group-mentions.js +51 -41
- package/dist/channels/plugins/message-action-names.js +2 -0
- package/dist/channels/plugins/message-actions.js +24 -5
- package/dist/channels/plugins/normalize/discord.js +26 -4
- package/dist/channels/plugins/normalize/signal.js +35 -22
- package/dist/channels/plugins/onboarding/helpers.js +8 -26
- package/dist/channels/plugins/outbound/imessage.js +15 -14
- package/dist/channels/registry.js +20 -7
- package/dist/cli/acp-cli.js +7 -5
- package/dist/cli/browser-cli-extension.js +25 -12
- package/dist/cli/browser-cli-state.cookies-storage.js +25 -6
- package/dist/cli/browser-cli-state.js +101 -145
- package/dist/cli/command-options.js +28 -0
- package/dist/cli/completion-cli.js +6 -6
- package/dist/cli/cron-cli/register.cron-add.js +25 -1
- package/dist/cli/cron-cli/register.cron-edit.js +44 -0
- package/dist/cli/cron-cli/shared.js +7 -1
- package/dist/cli/daemon-cli/lifecycle-core.js +23 -21
- package/dist/cli/daemon-cli/lifecycle.js +23 -247
- package/dist/cli/daemon-cli/register-service-commands.js +25 -4
- package/dist/cli/daemon-cli.js +1 -0
- package/dist/cli/devices-cli.js +33 -20
- package/dist/cli/gateway-cli/register.js +37 -105
- package/dist/cli/gateway-cli/run.js +49 -11
- package/dist/cli/nodes-camera.js +59 -4
- package/dist/cli/nodes-cli/register.camera.js +27 -24
- package/dist/cli/nodes-cli/rpc.js +21 -38
- package/dist/cli/qr-cli.js +2 -2
- package/dist/cli/skills-cli.format.js +2 -2
- package/dist/cli/update-cli/progress.js +2 -2
- package/dist/cli/update-cli/restart-helper.js +28 -7
- package/dist/cli/update-cli/shared.js +7 -7
- package/dist/cli/update-cli/status.js +1 -1
- package/dist/cli/update-cli/update-command.js +14 -8
- package/dist/cli/update-cli/wizard.js +2 -2
- package/dist/cli/update-cli.js +21 -1027
- package/dist/commands/auth-choice.apply.anthropic.js +10 -2
- package/dist/commands/channels/add-mutators.js +3 -35
- package/dist/commands/channels/add.js +39 -51
- package/dist/commands/config-validation.js +1 -1
- package/dist/commands/configure.gateway-auth.js +52 -15
- package/dist/commands/configure.gateway.js +84 -40
- package/dist/commands/doctor-completion.js +3 -3
- package/dist/commands/doctor-config-flow.js +536 -16
- package/dist/commands/doctor-gateway-services.js +103 -79
- package/dist/commands/doctor-memory-search.js +9 -9
- package/dist/commands/doctor-platform-notes.js +57 -30
- package/dist/commands/doctor-prompter.js +26 -15
- package/dist/commands/doctor-session-locks.js +1 -1
- package/dist/commands/doctor.js +21 -9
- package/dist/commands/model-picker.js +120 -95
- package/dist/commands/models/set.js +2 -21
- package/dist/commands/models/shared.js +65 -37
- package/dist/commands/onboard-helpers.js +81 -39
- package/dist/commands/openai-codex-oauth.js +1 -1
- package/dist/commands/sessions.js +52 -53
- package/dist/commands/status.summary.js +52 -34
- package/dist/commands/test-wizard-helpers.js +2 -2
- package/dist/config/defaults.js +79 -42
- package/dist/config/group-policy.js +50 -18
- package/dist/config/includes.js +37 -10
- package/dist/config/schema.help.js +5 -4
- package/dist/config/schema.hints.js +2 -2
- package/dist/config/schema.labels.js +1 -0
- package/dist/config/sessions/group.js +12 -11
- package/dist/config/sessions/paths.js +137 -11
- package/dist/config/sessions/store.js +185 -65
- package/dist/config/sessions/types.js +15 -1
- package/dist/config/sessions.js +1 -0
- package/dist/config/telegram-custom-commands.js +3 -2
- package/dist/config/types.js +2 -0
- package/dist/config/zod-schema.agent-defaults.js +6 -27
- package/dist/config/zod-schema.agent-runtime.js +171 -79
- package/dist/config/zod-schema.providers-core.js +138 -65
- package/dist/config/zod-schema.session.js +49 -22
- package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
- package/dist/cron/isolated-agent/run.js +224 -57
- package/dist/cron/normalize.js +48 -45
- package/dist/cron/run-log.js +14 -0
- package/dist/cron/service/jobs.js +190 -28
- package/dist/cron/service/normalize.js +29 -11
- package/dist/cron/service/store.js +30 -44
- package/dist/cron/service/timer.js +182 -96
- package/dist/cron/service.js +3 -0
- package/dist/cron/stagger.js +37 -0
- package/dist/daemon/inspect.js +132 -92
- package/dist/daemon/runtime-paths.js +25 -4
- package/dist/daemon/service-audit.js +47 -16
- package/dist/discord/accounts.js +23 -20
- package/dist/discord/monitor/agent-components.js +1115 -219
- package/dist/discord/monitor/allow-list.js +114 -34
- package/dist/discord/monitor/listeners.js +204 -97
- package/dist/discord/monitor/message-handler.js +21 -10
- package/dist/discord/monitor/message-handler.preflight.js +195 -101
- package/dist/discord/monitor/message-handler.process.js +384 -123
- package/dist/discord/monitor/message-utils.js +86 -23
- package/dist/discord/monitor/native-command.js +77 -57
- package/dist/discord/monitor/provider.js +122 -117
- package/dist/discord/monitor/reply-context.js +20 -16
- package/dist/discord/monitor/reply-delivery.js +40 -8
- package/dist/discord/monitor/rest-fetch.js +22 -0
- package/dist/discord/monitor/threading.js +117 -24
- package/dist/discord/send.js +2 -1
- package/dist/discord/send.outbound.js +124 -11
- package/dist/discord/send.shared.js +112 -72
- package/dist/discord/voice-message.js +3 -3
- package/dist/gateway/auth.js +119 -44
- package/dist/gateway/call.js +76 -34
- package/dist/gateway/channel-health-monitor.js +57 -50
- package/dist/gateway/client.js +63 -29
- package/dist/gateway/control-ui-contract.js +1 -1
- package/dist/gateway/gateway-config-prompts.shared.js +2 -2
- package/dist/gateway/net.js +109 -1
- package/dist/gateway/protocol/index.js +5 -8
- package/dist/gateway/protocol/schema/agent.js +19 -1
- package/dist/gateway/protocol/schema/channels.js +21 -0
- package/dist/gateway/protocol/schema/cron.js +43 -30
- package/dist/gateway/protocol/schema/protocol-schemas.js +6 -11
- package/dist/gateway/protocol/schema/sessions.js +5 -1
- package/dist/gateway/protocol/schema.js +0 -1
- package/dist/gateway/server/presence-events.js +12 -0
- package/dist/gateway/server/ws-connection/message-handler.js +203 -212
- package/dist/gateway/server/ws-connection.js +58 -21
- package/dist/gateway/server-broadcast.js +18 -13
- package/dist/gateway/server-cron.js +177 -10
- package/dist/gateway/server-methods/agent-job.js +131 -38
- package/dist/gateway/server-methods/send.js +60 -14
- package/dist/gateway/server-methods/sessions.js +160 -96
- package/dist/gateway/server-methods/system.js +5 -7
- package/dist/gateway/server-methods-list.js +8 -0
- package/dist/gateway/server-methods.js +24 -8
- package/dist/gateway/server-node-events.js +278 -68
- package/dist/gateway/session-utils.fs.js +316 -75
- package/dist/gateway/session-utils.js +224 -70
- package/dist/gateway/sessions-patch.js +63 -20
- package/dist/gateway/test-temp-config.js +1 -1
- package/dist/gateway/tools-invoke-http.js +118 -70
- package/dist/gateway/ws-log.js +135 -107
- package/dist/hooks/frontmatter.js +36 -82
- package/dist/hooks/install.js +149 -139
- package/dist/hooks/internal-hooks.js +29 -4
- package/dist/hooks/plugin-hooks.js +2 -1
- package/dist/imessage/monitor/deliver.js +10 -4
- package/dist/imessage/monitor/monitor-provider.js +138 -375
- package/dist/imessage/monitor/runtime.js +4 -8
- package/dist/imessage/send.js +65 -19
- package/dist/infra/exec-approvals-allowlist.js +7 -0
- package/dist/infra/exec-approvals.js +35 -920
- package/dist/infra/exec-safe-bin-trust.js +64 -0
- package/dist/infra/heartbeat-runner.js +207 -134
- package/dist/infra/heartbeat-wake.js +183 -22
- package/dist/infra/install-source-utils.js +47 -0
- package/dist/infra/net/ssrf.js +170 -36
- package/dist/infra/outbound/deliver.js +224 -58
- package/dist/infra/outbound/message-action-spec.js +12 -5
- package/dist/infra/outbound/outbound-session.js +27 -25
- package/dist/infra/poolbot-root.js +32 -22
- package/dist/infra/ports.js +14 -11
- package/dist/infra/skills-remote.js +48 -37
- package/dist/infra/system-events.js +25 -11
- package/dist/infra/system-presence.js +26 -33
- package/dist/infra/tmp-poolbot-dir.js +81 -2
- package/dist/infra/wsl.js +37 -1
- package/dist/line/bot-message-context.js +163 -191
- package/dist/logging/subsystem.js +59 -22
- package/dist/markdown/ir.js +124 -50
- package/dist/media/store.js +1 -1
- package/dist/media-understanding/runner.entries.js +42 -25
- package/dist/media-understanding/runner.js +53 -488
- package/dist/memory/embeddings-gemini.js +53 -38
- package/dist/memory/manager-embedding-ops.js +48 -69
- package/dist/pairing/pairing-store.js +178 -119
- package/dist/plugin-sdk/index.js +34 -6
- package/dist/plugins/hooks.js +135 -14
- package/dist/plugins/install.js +190 -152
- package/dist/polls.js +11 -0
- package/dist/routing/resolve-route.js +190 -56
- package/dist/routing/session-key.js +38 -22
- package/dist/runtime.js +35 -9
- package/dist/security/audit-channel.js +1 -1
- package/dist/sessions/session-key-utils.js +29 -11
- package/dist/shared/frontmatter.js +5 -5
- package/dist/shared/node-list-types.js +1 -0
- package/dist/shared/string-normalization.js +15 -0
- package/dist/signal/monitor/event-handler.js +68 -36
- package/dist/signal/send.js +29 -37
- package/dist/slack/monitor/allow-list.js +10 -11
- package/dist/slack/monitor/commands.js +14 -3
- package/dist/slack/monitor/events/interactions.js +4 -4
- package/dist/slack/monitor/media.js +224 -16
- package/dist/slack/monitor/message-handler/dispatch.js +247 -13
- package/dist/slack/monitor/message-handler/prepare.js +128 -45
- package/dist/slack/monitor/slash.js +357 -144
- package/dist/slack/streaming.js +77 -0
- package/dist/telegram/accounts.js +40 -13
- package/dist/telegram/allowed-updates.js +3 -0
- package/dist/telegram/bot/delivery.js +129 -66
- package/dist/telegram/bot/helpers.js +136 -122
- package/dist/telegram/bot-handlers.js +600 -339
- package/dist/telegram/bot-message-context.js +115 -73
- package/dist/telegram/bot-message-dispatch.js +235 -104
- package/dist/telegram/bot-native-command-menu.js +3 -1
- package/dist/telegram/bot-native-commands.js +213 -193
- package/dist/telegram/bot.js +24 -132
- package/dist/telegram/draft-stream.js +84 -75
- package/dist/telegram/format.js +150 -6
- package/dist/telegram/send.js +415 -255
- package/dist/telegram/targets.js +21 -2
- package/dist/telegram/update-offset-store.js +19 -3
- package/dist/terminal/restore.js +5 -2
- package/dist/test-utils/fetch-mock.js +5 -0
- package/dist/version.js +18 -5
- package/dist/web/auto-reply/monitor/broadcast.js +7 -3
- package/dist/web/auto-reply/monitor/on-message.js +6 -3
- package/dist/web/inbound/media.js +34 -8
- package/dist/web/inbound/monitor.js +34 -17
- package/dist/web/inbound/send-api.js +18 -17
- package/dist/web/outbound.js +12 -5
- package/dist/wizard/clack-prompter.js +40 -7
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/device-pair/index.ts +2 -2
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/discord/package.json +1 -1
- package/extensions/feishu/package.json +1 -1
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/irc/src/accounts.ts +1 -1
- package/extensions/irc/src/onboarding.ts +4 -4
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +10 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +10 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +10 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/openai-codex-auth/package.json +1 -1
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +10 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +10 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +10 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +10 -0
- package/extensions/zalouser/package.json +1 -1
- package/package.json +1 -1
- package/skills/apple-reminders/SKILL.md +100 -49
- package/skills/coding-agent/SKILL.md +34 -28
- package/skills/github/SKILL.md +131 -16
- package/skills/imsg/SKILL.md +112 -15
- package/skills/openhue/SKILL.md +101 -19
- package/skills/tmux/SKILL.md +111 -79
- package/skills/weather/SKILL.md +88 -25
- package/dist/agents/openclaw-tools.js +0 -151
- package/dist/agents/tool-security.js +0 -96
- package/dist/gateway/url-validation.js +0 -94
- package/dist/infra/openclaw-root.js +0 -109
- package/dist/infra/tmp-openclaw-dir.js +0 -81
- package/dist/media/path-sanitization.js +0 -78
|
@@ -29,7 +29,11 @@ const READ_SCOPE = "operator.read";
|
|
|
29
29
|
const WRITE_SCOPE = "operator.write";
|
|
30
30
|
const APPROVALS_SCOPE = "operator.approvals";
|
|
31
31
|
const PAIRING_SCOPE = "operator.pairing";
|
|
32
|
-
const APPROVAL_METHODS = new Set([
|
|
32
|
+
const APPROVAL_METHODS = new Set([
|
|
33
|
+
"exec.approval.request",
|
|
34
|
+
"exec.approval.waitDecision",
|
|
35
|
+
"exec.approval.resolve",
|
|
36
|
+
]);
|
|
33
37
|
const NODE_ROLE_METHODS = new Set(["node.invoke.result", "node.event", "skills.bins"]);
|
|
34
38
|
const PAIRING_METHODS = new Set([
|
|
35
39
|
"node.pair.request",
|
|
@@ -69,6 +73,8 @@ const READ_METHODS = new Set([
|
|
|
69
73
|
"node.list",
|
|
70
74
|
"node.describe",
|
|
71
75
|
"chat.history",
|
|
76
|
+
"config.get",
|
|
77
|
+
"talk.config",
|
|
72
78
|
]);
|
|
73
79
|
const WRITE_METHODS = new Set([
|
|
74
80
|
"send",
|
|
@@ -87,13 +93,15 @@ const WRITE_METHODS = new Set([
|
|
|
87
93
|
"browser.request",
|
|
88
94
|
]);
|
|
89
95
|
function authorizeGatewayMethod(method, client) {
|
|
90
|
-
if (!client?.connect)
|
|
96
|
+
if (!client?.connect) {
|
|
91
97
|
return null;
|
|
98
|
+
}
|
|
92
99
|
const role = client.connect.role ?? "operator";
|
|
93
100
|
const scopes = client.connect.scopes ?? [];
|
|
94
101
|
if (NODE_ROLE_METHODS.has(method)) {
|
|
95
|
-
if (role === "node")
|
|
102
|
+
if (role === "node") {
|
|
96
103
|
return null;
|
|
104
|
+
}
|
|
97
105
|
return errorShape(ErrorCodes.INVALID_REQUEST, `unauthorized role: ${role}`);
|
|
98
106
|
}
|
|
99
107
|
if (role === "node") {
|
|
@@ -102,8 +110,9 @@ function authorizeGatewayMethod(method, client) {
|
|
|
102
110
|
if (role !== "operator") {
|
|
103
111
|
return errorShape(ErrorCodes.INVALID_REQUEST, `unauthorized role: ${role}`);
|
|
104
112
|
}
|
|
105
|
-
if (scopes.includes(ADMIN_SCOPE))
|
|
113
|
+
if (scopes.includes(ADMIN_SCOPE)) {
|
|
106
114
|
return null;
|
|
115
|
+
}
|
|
107
116
|
if (APPROVAL_METHODS.has(method) && !scopes.includes(APPROVALS_SCOPE)) {
|
|
108
117
|
return errorShape(ErrorCodes.INVALID_REQUEST, "missing scope: operator.approvals");
|
|
109
118
|
}
|
|
@@ -116,14 +125,18 @@ function authorizeGatewayMethod(method, client) {
|
|
|
116
125
|
if (WRITE_METHODS.has(method) && !scopes.includes(WRITE_SCOPE)) {
|
|
117
126
|
return errorShape(ErrorCodes.INVALID_REQUEST, "missing scope: operator.write");
|
|
118
127
|
}
|
|
119
|
-
if (APPROVAL_METHODS.has(method))
|
|
128
|
+
if (APPROVAL_METHODS.has(method)) {
|
|
120
129
|
return null;
|
|
121
|
-
|
|
130
|
+
}
|
|
131
|
+
if (PAIRING_METHODS.has(method)) {
|
|
122
132
|
return null;
|
|
123
|
-
|
|
133
|
+
}
|
|
134
|
+
if (READ_METHODS.has(method)) {
|
|
124
135
|
return null;
|
|
125
|
-
|
|
136
|
+
}
|
|
137
|
+
if (WRITE_METHODS.has(method)) {
|
|
126
138
|
return null;
|
|
139
|
+
}
|
|
127
140
|
if (ADMIN_METHOD_PREFIXES.some((prefix) => method.startsWith(prefix))) {
|
|
128
141
|
return errorShape(ErrorCodes.INVALID_REQUEST, "missing scope: operator.admin");
|
|
129
142
|
}
|
|
@@ -131,6 +144,9 @@ function authorizeGatewayMethod(method, client) {
|
|
|
131
144
|
method.startsWith("wizard.") ||
|
|
132
145
|
method.startsWith("update.") ||
|
|
133
146
|
method === "channels.logout" ||
|
|
147
|
+
method === "agents.create" ||
|
|
148
|
+
method === "agents.update" ||
|
|
149
|
+
method === "agents.delete" ||
|
|
134
150
|
method === "skills.install" ||
|
|
135
151
|
method === "skills.update" ||
|
|
136
152
|
method === "cron.add" ||
|
|
@@ -1,19 +1,183 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { resolveSessionAgentId } from "../agents/agent-scope.js";
|
|
2
3
|
import { normalizeChannelId } from "../channels/plugins/index.js";
|
|
4
|
+
import { createOutboundSendDeps } from "../cli/outbound-send-deps.js";
|
|
3
5
|
import { agentCommand } from "../commands/agent.js";
|
|
4
6
|
import { loadConfig } from "../config/config.js";
|
|
5
7
|
import { updateSessionStore } from "../config/sessions.js";
|
|
6
8
|
import { requestHeartbeatNow } from "../infra/heartbeat-wake.js";
|
|
9
|
+
import { deliverOutboundPayloads } from "../infra/outbound/deliver.js";
|
|
10
|
+
import { resolveOutboundTarget } from "../infra/outbound/targets.js";
|
|
7
11
|
import { enqueueSystemEvent } from "../infra/system-events.js";
|
|
8
12
|
import { normalizeMainKey } from "../routing/session-key.js";
|
|
9
13
|
import { defaultRuntime } from "../runtime.js";
|
|
10
|
-
import {
|
|
14
|
+
import { parseMessageWithAttachments } from "./chat-attachments.js";
|
|
15
|
+
import { normalizeRpcAttachmentsToChatAttachments } from "./server-methods/attachment-normalize.js";
|
|
16
|
+
import { loadSessionEntry, pruneLegacyStoreKeys, resolveGatewaySessionStoreTarget, } from "./session-utils.js";
|
|
11
17
|
import { formatForLog } from "./ws-log.js";
|
|
18
|
+
const MAX_EXEC_EVENT_OUTPUT_CHARS = 180;
|
|
19
|
+
const VOICE_TRANSCRIPT_DEDUPE_WINDOW_MS = 1500;
|
|
20
|
+
const MAX_RECENT_VOICE_TRANSCRIPTS = 200;
|
|
21
|
+
const recentVoiceTranscripts = new Map();
|
|
22
|
+
function normalizeNonEmptyString(value) {
|
|
23
|
+
if (typeof value !== "string") {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const trimmed = value.trim();
|
|
27
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
28
|
+
}
|
|
29
|
+
function normalizeFiniteInteger(value) {
|
|
30
|
+
return typeof value === "number" && Number.isFinite(value) ? Math.trunc(value) : null;
|
|
31
|
+
}
|
|
32
|
+
function resolveVoiceTranscriptFingerprint(obj, text) {
|
|
33
|
+
const eventId = normalizeNonEmptyString(obj.eventId) ??
|
|
34
|
+
normalizeNonEmptyString(obj.providerEventId) ??
|
|
35
|
+
normalizeNonEmptyString(obj.transcriptId);
|
|
36
|
+
if (eventId) {
|
|
37
|
+
return `event:${eventId}`;
|
|
38
|
+
}
|
|
39
|
+
const callId = normalizeNonEmptyString(obj.providerCallId) ?? normalizeNonEmptyString(obj.callId);
|
|
40
|
+
const sequence = normalizeFiniteInteger(obj.sequence) ?? normalizeFiniteInteger(obj.seq);
|
|
41
|
+
if (callId && sequence !== null) {
|
|
42
|
+
return `call-seq:${callId}:${sequence}`;
|
|
43
|
+
}
|
|
44
|
+
const eventTimestamp = normalizeFiniteInteger(obj.timestamp) ??
|
|
45
|
+
normalizeFiniteInteger(obj.ts) ??
|
|
46
|
+
normalizeFiniteInteger(obj.eventTimestamp);
|
|
47
|
+
if (callId && eventTimestamp !== null) {
|
|
48
|
+
return `call-ts:${callId}:${eventTimestamp}`;
|
|
49
|
+
}
|
|
50
|
+
if (eventTimestamp !== null) {
|
|
51
|
+
return `timestamp:${eventTimestamp}|text:${text}`;
|
|
52
|
+
}
|
|
53
|
+
return `text:${text}`;
|
|
54
|
+
}
|
|
55
|
+
function shouldDropDuplicateVoiceTranscript(params) {
|
|
56
|
+
const previous = recentVoiceTranscripts.get(params.sessionKey);
|
|
57
|
+
if (previous &&
|
|
58
|
+
previous.fingerprint === params.fingerprint &&
|
|
59
|
+
params.now - previous.ts <= VOICE_TRANSCRIPT_DEDUPE_WINDOW_MS) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
recentVoiceTranscripts.set(params.sessionKey, {
|
|
63
|
+
fingerprint: params.fingerprint,
|
|
64
|
+
ts: params.now,
|
|
65
|
+
});
|
|
66
|
+
if (recentVoiceTranscripts.size > MAX_RECENT_VOICE_TRANSCRIPTS) {
|
|
67
|
+
const cutoff = params.now - VOICE_TRANSCRIPT_DEDUPE_WINDOW_MS * 2;
|
|
68
|
+
for (const [key, value] of recentVoiceTranscripts) {
|
|
69
|
+
if (value.ts < cutoff) {
|
|
70
|
+
recentVoiceTranscripts.delete(key);
|
|
71
|
+
}
|
|
72
|
+
if (recentVoiceTranscripts.size <= MAX_RECENT_VOICE_TRANSCRIPTS) {
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
while (recentVoiceTranscripts.size > MAX_RECENT_VOICE_TRANSCRIPTS) {
|
|
77
|
+
const oldestKey = recentVoiceTranscripts.keys().next().value;
|
|
78
|
+
if (oldestKey === undefined) {
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
recentVoiceTranscripts.delete(oldestKey);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
function compactExecEventOutput(raw) {
|
|
87
|
+
const normalized = raw.replace(/\s+/g, " ").trim();
|
|
88
|
+
if (!normalized) {
|
|
89
|
+
return "";
|
|
90
|
+
}
|
|
91
|
+
if (normalized.length <= MAX_EXEC_EVENT_OUTPUT_CHARS) {
|
|
92
|
+
return normalized;
|
|
93
|
+
}
|
|
94
|
+
const safe = Math.max(1, MAX_EXEC_EVENT_OUTPUT_CHARS - 1);
|
|
95
|
+
return `${normalized.slice(0, safe)}…`;
|
|
96
|
+
}
|
|
97
|
+
async function touchSessionStore(params) {
|
|
98
|
+
const { storePath } = params;
|
|
99
|
+
if (!storePath) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
await updateSessionStore(storePath, (store) => {
|
|
103
|
+
const target = resolveGatewaySessionStoreTarget({
|
|
104
|
+
cfg: params.cfg,
|
|
105
|
+
key: params.sessionKey,
|
|
106
|
+
store,
|
|
107
|
+
});
|
|
108
|
+
pruneLegacyStoreKeys({
|
|
109
|
+
store,
|
|
110
|
+
canonicalKey: target.canonicalKey,
|
|
111
|
+
candidates: target.storeKeys,
|
|
112
|
+
});
|
|
113
|
+
store[params.canonicalKey] = {
|
|
114
|
+
sessionId: params.sessionId,
|
|
115
|
+
updatedAt: params.now,
|
|
116
|
+
thinkingLevel: params.entry?.thinkingLevel,
|
|
117
|
+
verboseLevel: params.entry?.verboseLevel,
|
|
118
|
+
reasoningLevel: params.entry?.reasoningLevel,
|
|
119
|
+
systemSent: params.entry?.systemSent,
|
|
120
|
+
sendPolicy: params.entry?.sendPolicy,
|
|
121
|
+
lastChannel: params.entry?.lastChannel,
|
|
122
|
+
lastTo: params.entry?.lastTo,
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function queueSessionStoreTouch(params) {
|
|
127
|
+
void touchSessionStore({
|
|
128
|
+
cfg: params.cfg,
|
|
129
|
+
sessionKey: params.sessionKey,
|
|
130
|
+
storePath: params.storePath,
|
|
131
|
+
canonicalKey: params.canonicalKey,
|
|
132
|
+
entry: params.entry,
|
|
133
|
+
sessionId: params.sessionId,
|
|
134
|
+
now: params.now,
|
|
135
|
+
}).catch((err) => {
|
|
136
|
+
params.ctx.logGateway.warn("voice session-store update failed: " + formatForLog(err));
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function parseSessionKeyFromPayloadJSON(payloadJSON) {
|
|
140
|
+
let payload;
|
|
141
|
+
try {
|
|
142
|
+
payload = JSON.parse(payloadJSON);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
if (typeof payload !== "object" || payload === null) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
const obj = payload;
|
|
151
|
+
const sessionKey = typeof obj.sessionKey === "string" ? obj.sessionKey.trim() : "";
|
|
152
|
+
return sessionKey.length > 0 ? sessionKey : null;
|
|
153
|
+
}
|
|
154
|
+
async function sendReceiptAck(params) {
|
|
155
|
+
const resolved = resolveOutboundTarget({
|
|
156
|
+
channel: params.channel,
|
|
157
|
+
to: params.to,
|
|
158
|
+
cfg: params.cfg,
|
|
159
|
+
mode: "explicit",
|
|
160
|
+
});
|
|
161
|
+
if (!resolved.ok) {
|
|
162
|
+
throw new Error(String(resolved.error));
|
|
163
|
+
}
|
|
164
|
+
const agentId = resolveSessionAgentId({ sessionKey: params.sessionKey, config: params.cfg });
|
|
165
|
+
await deliverOutboundPayloads({
|
|
166
|
+
cfg: params.cfg,
|
|
167
|
+
channel: params.channel,
|
|
168
|
+
to: resolved.to,
|
|
169
|
+
payloads: [{ text: params.text }],
|
|
170
|
+
agentId,
|
|
171
|
+
bestEffort: true,
|
|
172
|
+
deps: createOutboundSendDeps(params.deps),
|
|
173
|
+
});
|
|
174
|
+
}
|
|
12
175
|
export const handleNodeEvent = async (ctx, nodeId, evt) => {
|
|
13
176
|
switch (evt.event) {
|
|
14
177
|
case "voice.transcript": {
|
|
15
|
-
if (!evt.payloadJSON)
|
|
178
|
+
if (!evt.payloadJSON) {
|
|
16
179
|
return;
|
|
180
|
+
}
|
|
17
181
|
let payload;
|
|
18
182
|
try {
|
|
19
183
|
payload = JSON.parse(evt.payloadJSON);
|
|
@@ -23,53 +187,60 @@ export const handleNodeEvent = async (ctx, nodeId, evt) => {
|
|
|
23
187
|
}
|
|
24
188
|
const obj = typeof payload === "object" && payload !== null ? payload : {};
|
|
25
189
|
const text = typeof obj.text === "string" ? obj.text.trim() : "";
|
|
26
|
-
if (!text)
|
|
190
|
+
if (!text) {
|
|
27
191
|
return;
|
|
28
|
-
|
|
192
|
+
}
|
|
193
|
+
if (text.length > 20_000) {
|
|
29
194
|
return;
|
|
195
|
+
}
|
|
30
196
|
const sessionKeyRaw = typeof obj.sessionKey === "string" ? obj.sessionKey.trim() : "";
|
|
31
197
|
const cfg = loadConfig();
|
|
32
198
|
const rawMainKey = normalizeMainKey(cfg.session?.mainKey);
|
|
33
199
|
const sessionKey = sessionKeyRaw.length > 0 ? sessionKeyRaw : rawMainKey;
|
|
34
200
|
const { storePath, entry, canonicalKey } = loadSessionEntry(sessionKey);
|
|
35
201
|
const now = Date.now();
|
|
36
|
-
const
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
store[canonicalKey] = {
|
|
40
|
-
sessionId,
|
|
41
|
-
updatedAt: now,
|
|
42
|
-
thinkingLevel: entry?.thinkingLevel,
|
|
43
|
-
verboseLevel: entry?.verboseLevel,
|
|
44
|
-
reasoningLevel: entry?.reasoningLevel,
|
|
45
|
-
systemSent: entry?.systemSent,
|
|
46
|
-
sendPolicy: entry?.sendPolicy,
|
|
47
|
-
lastChannel: entry?.lastChannel,
|
|
48
|
-
lastTo: entry?.lastTo,
|
|
49
|
-
};
|
|
50
|
-
});
|
|
202
|
+
const fingerprint = resolveVoiceTranscriptFingerprint(obj, text);
|
|
203
|
+
if (shouldDropDuplicateVoiceTranscript({ sessionKey: canonicalKey, fingerprint, now })) {
|
|
204
|
+
return;
|
|
51
205
|
}
|
|
206
|
+
const sessionId = entry?.sessionId ?? randomUUID();
|
|
207
|
+
queueSessionStoreTouch({
|
|
208
|
+
ctx,
|
|
209
|
+
cfg,
|
|
210
|
+
sessionKey,
|
|
211
|
+
storePath,
|
|
212
|
+
canonicalKey,
|
|
213
|
+
entry,
|
|
214
|
+
sessionId,
|
|
215
|
+
now,
|
|
216
|
+
});
|
|
52
217
|
// Ensure chat UI clients refresh when this run completes (even though it wasn't started via chat.send).
|
|
53
218
|
// This maps agent bus events (keyed by sessionId) to chat events (keyed by clientRunId).
|
|
54
219
|
ctx.addChatRun(sessionId, {
|
|
55
|
-
sessionKey,
|
|
220
|
+
sessionKey: canonicalKey,
|
|
56
221
|
clientRunId: `voice-${randomUUID()}`,
|
|
57
222
|
});
|
|
58
223
|
void agentCommand({
|
|
59
224
|
message: text,
|
|
60
225
|
sessionId,
|
|
61
|
-
sessionKey,
|
|
226
|
+
sessionKey: canonicalKey,
|
|
62
227
|
thinking: "low",
|
|
63
228
|
deliver: false,
|
|
64
229
|
messageChannel: "node",
|
|
230
|
+
inputProvenance: {
|
|
231
|
+
kind: "external_user",
|
|
232
|
+
sourceChannel: "voice",
|
|
233
|
+
sourceTool: "gateway.voice.transcript",
|
|
234
|
+
},
|
|
65
235
|
}, defaultRuntime, ctx.deps).catch((err) => {
|
|
66
236
|
ctx.logGateway.warn(`agent failed node=${nodeId}: ${formatForLog(err)}`);
|
|
67
237
|
});
|
|
68
238
|
return;
|
|
69
239
|
}
|
|
70
240
|
case "agent.request": {
|
|
71
|
-
if (!evt.payloadJSON)
|
|
241
|
+
if (!evt.payloadJSON) {
|
|
72
242
|
return;
|
|
243
|
+
}
|
|
73
244
|
let link = null;
|
|
74
245
|
try {
|
|
75
246
|
link = JSON.parse(evt.payloadJSON);
|
|
@@ -77,43 +248,84 @@ export const handleNodeEvent = async (ctx, nodeId, evt) => {
|
|
|
77
248
|
catch {
|
|
78
249
|
return;
|
|
79
250
|
}
|
|
80
|
-
|
|
81
|
-
|
|
251
|
+
let message = (link?.message ?? "").trim();
|
|
252
|
+
const normalizedAttachments = normalizeRpcAttachmentsToChatAttachments(link?.attachments ?? undefined);
|
|
253
|
+
let images = [];
|
|
254
|
+
if (normalizedAttachments.length > 0) {
|
|
255
|
+
try {
|
|
256
|
+
const parsed = await parseMessageWithAttachments(message, normalizedAttachments, {
|
|
257
|
+
maxBytes: 5_000_000,
|
|
258
|
+
log: ctx.logGateway,
|
|
259
|
+
});
|
|
260
|
+
message = parsed.message.trim();
|
|
261
|
+
images = parsed.images;
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (!message) {
|
|
82
268
|
return;
|
|
83
|
-
|
|
269
|
+
}
|
|
270
|
+
if (message.length > 20_000) {
|
|
84
271
|
return;
|
|
272
|
+
}
|
|
85
273
|
const channelRaw = typeof link?.channel === "string" ? link.channel.trim() : "";
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
274
|
+
let channel = normalizeChannelId(channelRaw) ?? undefined;
|
|
275
|
+
let to = typeof link?.to === "string" && link.to.trim() ? link.to.trim() : undefined;
|
|
276
|
+
const deliverRequested = Boolean(link?.deliver);
|
|
277
|
+
const wantsReceipt = Boolean(link?.receipt);
|
|
278
|
+
const receiptTextRaw = typeof link?.receiptText === "string" ? link.receiptText.trim() : "";
|
|
279
|
+
const receiptText = receiptTextRaw || "Just received your iOS share + request, working on it.";
|
|
89
280
|
const sessionKeyRaw = (link?.sessionKey ?? "").trim();
|
|
90
281
|
const sessionKey = sessionKeyRaw.length > 0 ? sessionKeyRaw : `node-${nodeId}`;
|
|
282
|
+
const cfg = loadConfig();
|
|
91
283
|
const { storePath, entry, canonicalKey } = loadSessionEntry(sessionKey);
|
|
92
284
|
const now = Date.now();
|
|
93
285
|
const sessionId = entry?.sessionId ?? randomUUID();
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
286
|
+
await touchSessionStore({ cfg, sessionKey, storePath, canonicalKey, entry, sessionId, now });
|
|
287
|
+
if (deliverRequested && (!channel || !to)) {
|
|
288
|
+
const entryChannel = typeof entry?.lastChannel === "string"
|
|
289
|
+
? normalizeChannelId(entry.lastChannel)
|
|
290
|
+
: undefined;
|
|
291
|
+
const entryTo = typeof entry?.lastTo === "string" ? entry.lastTo.trim() : "";
|
|
292
|
+
if (!channel && entryChannel) {
|
|
293
|
+
channel = entryChannel;
|
|
294
|
+
}
|
|
295
|
+
if (!to && entryTo) {
|
|
296
|
+
to = entryTo;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const deliver = deliverRequested && Boolean(channel && to);
|
|
300
|
+
const deliveryChannel = deliver ? channel : undefined;
|
|
301
|
+
const deliveryTo = deliver ? to : undefined;
|
|
302
|
+
if (deliverRequested && !deliver) {
|
|
303
|
+
ctx.logGateway.warn(`agent delivery disabled node=${nodeId}: missing session delivery route (channel=${channel ?? "-"} to=${to ?? "-"})`);
|
|
304
|
+
}
|
|
305
|
+
if (wantsReceipt && deliveryChannel && deliveryTo) {
|
|
306
|
+
void sendReceiptAck({
|
|
307
|
+
cfg,
|
|
308
|
+
deps: ctx.deps,
|
|
309
|
+
sessionKey: canonicalKey,
|
|
310
|
+
channel: deliveryChannel,
|
|
311
|
+
to: deliveryTo,
|
|
312
|
+
text: receiptText,
|
|
313
|
+
}).catch((err) => {
|
|
314
|
+
ctx.logGateway.warn(`agent receipt failed node=${nodeId}: ${formatForLog(err)}`);
|
|
107
315
|
});
|
|
108
316
|
}
|
|
317
|
+
else if (wantsReceipt) {
|
|
318
|
+
ctx.logGateway.warn(`agent receipt skipped node=${nodeId}: missing delivery route (channel=${deliveryChannel ?? "-"} to=${deliveryTo ?? "-"})`);
|
|
319
|
+
}
|
|
109
320
|
void agentCommand({
|
|
110
321
|
message,
|
|
322
|
+
images,
|
|
111
323
|
sessionId,
|
|
112
|
-
sessionKey,
|
|
324
|
+
sessionKey: canonicalKey,
|
|
113
325
|
thinking: link?.thinking ?? undefined,
|
|
114
326
|
deliver,
|
|
115
|
-
to,
|
|
116
|
-
channel,
|
|
327
|
+
to: deliveryTo,
|
|
328
|
+
channel: deliveryChannel,
|
|
117
329
|
timeout: typeof link?.timeoutSeconds === "number" ? link.timeoutSeconds.toString() : undefined,
|
|
118
330
|
messageChannel: "node",
|
|
119
331
|
}, defaultRuntime, ctx.deps).catch((err) => {
|
|
@@ -122,44 +334,33 @@ export const handleNodeEvent = async (ctx, nodeId, evt) => {
|
|
|
122
334
|
return;
|
|
123
335
|
}
|
|
124
336
|
case "chat.subscribe": {
|
|
125
|
-
if (!evt.payloadJSON)
|
|
337
|
+
if (!evt.payloadJSON) {
|
|
126
338
|
return;
|
|
127
|
-
let payload;
|
|
128
|
-
try {
|
|
129
|
-
payload = JSON.parse(evt.payloadJSON);
|
|
130
339
|
}
|
|
131
|
-
|
|
340
|
+
const sessionKey = parseSessionKeyFromPayloadJSON(evt.payloadJSON);
|
|
341
|
+
if (!sessionKey) {
|
|
132
342
|
return;
|
|
133
343
|
}
|
|
134
|
-
const obj = typeof payload === "object" && payload !== null ? payload : {};
|
|
135
|
-
const sessionKey = typeof obj.sessionKey === "string" ? obj.sessionKey.trim() : "";
|
|
136
|
-
if (!sessionKey)
|
|
137
|
-
return;
|
|
138
344
|
ctx.nodeSubscribe(nodeId, sessionKey);
|
|
139
345
|
return;
|
|
140
346
|
}
|
|
141
347
|
case "chat.unsubscribe": {
|
|
142
|
-
if (!evt.payloadJSON)
|
|
348
|
+
if (!evt.payloadJSON) {
|
|
143
349
|
return;
|
|
144
|
-
let payload;
|
|
145
|
-
try {
|
|
146
|
-
payload = JSON.parse(evt.payloadJSON);
|
|
147
350
|
}
|
|
148
|
-
|
|
351
|
+
const sessionKey = parseSessionKeyFromPayloadJSON(evt.payloadJSON);
|
|
352
|
+
if (!sessionKey) {
|
|
149
353
|
return;
|
|
150
354
|
}
|
|
151
|
-
const obj = typeof payload === "object" && payload !== null ? payload : {};
|
|
152
|
-
const sessionKey = typeof obj.sessionKey === "string" ? obj.sessionKey.trim() : "";
|
|
153
|
-
if (!sessionKey)
|
|
154
|
-
return;
|
|
155
355
|
ctx.nodeUnsubscribe(nodeId, sessionKey);
|
|
156
356
|
return;
|
|
157
357
|
}
|
|
158
358
|
case "exec.started":
|
|
159
359
|
case "exec.finished":
|
|
160
360
|
case "exec.denied": {
|
|
161
|
-
if (!evt.payloadJSON)
|
|
361
|
+
if (!evt.payloadJSON) {
|
|
162
362
|
return;
|
|
363
|
+
}
|
|
163
364
|
let payload;
|
|
164
365
|
try {
|
|
165
366
|
payload = JSON.parse(evt.payloadJSON);
|
|
@@ -169,8 +370,9 @@ export const handleNodeEvent = async (ctx, nodeId, evt) => {
|
|
|
169
370
|
}
|
|
170
371
|
const obj = typeof payload === "object" && payload !== null ? payload : {};
|
|
171
372
|
const sessionKey = typeof obj.sessionKey === "string" ? obj.sessionKey.trim() : `node-${nodeId}`;
|
|
172
|
-
if (!sessionKey)
|
|
373
|
+
if (!sessionKey) {
|
|
173
374
|
return;
|
|
375
|
+
}
|
|
174
376
|
const runId = typeof obj.runId === "string" ? obj.runId.trim() : "";
|
|
175
377
|
const command = typeof obj.command === "string" ? obj.command.trim() : "";
|
|
176
378
|
const exitCode = typeof obj.exitCode === "number" && Number.isFinite(obj.exitCode)
|
|
@@ -182,19 +384,27 @@ export const handleNodeEvent = async (ctx, nodeId, evt) => {
|
|
|
182
384
|
let text = "";
|
|
183
385
|
if (evt.event === "exec.started") {
|
|
184
386
|
text = `Exec started (node=${nodeId}${runId ? ` id=${runId}` : ""})`;
|
|
185
|
-
if (command)
|
|
387
|
+
if (command) {
|
|
186
388
|
text += `: ${command}`;
|
|
389
|
+
}
|
|
187
390
|
}
|
|
188
391
|
else if (evt.event === "exec.finished") {
|
|
189
392
|
const exitLabel = timedOut ? "timeout" : `code ${exitCode ?? "?"}`;
|
|
393
|
+
const compactOutput = compactExecEventOutput(output);
|
|
394
|
+
const shouldNotify = timedOut || exitCode !== 0 || compactOutput.length > 0;
|
|
395
|
+
if (!shouldNotify) {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
190
398
|
text = `Exec finished (node=${nodeId}${runId ? ` id=${runId}` : ""}, ${exitLabel})`;
|
|
191
|
-
if (
|
|
192
|
-
text += `\n${
|
|
399
|
+
if (compactOutput) {
|
|
400
|
+
text += `\n${compactOutput}`;
|
|
401
|
+
}
|
|
193
402
|
}
|
|
194
403
|
else {
|
|
195
404
|
text = `Exec denied (node=${nodeId}${runId ? ` id=${runId}` : ""}${reason ? `, ${reason}` : ""})`;
|
|
196
|
-
if (command)
|
|
405
|
+
if (command) {
|
|
197
406
|
text += `: ${command}`;
|
|
407
|
+
}
|
|
198
408
|
}
|
|
199
409
|
enqueueSystemEvent(text, { sessionKey, contextKey: runId ? `exec:${runId}` : "exec" });
|
|
200
410
|
requestHeartbeatNow({ reason: "exec-event" });
|