@gajae-code/coding-agent 0.13.2 → 0.14.0
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 +215 -8
- package/README.md +2 -0
- package/bin/gajaessi.js +4 -0
- package/dist/types/async/job-manager.d.ts +55 -2
- package/dist/types/async/support.d.ts +14 -0
- package/dist/types/capability/mcp.d.ts +6 -0
- package/dist/types/capability/types.d.ts +6 -0
- package/dist/types/cli/accounts-cli.d.ts +19 -0
- package/dist/types/cli/args.d.ts +3 -0
- package/dist/types/cli/config-cli.d.ts +6 -0
- package/dist/types/cli/crash-cli.d.ts +10 -0
- package/dist/types/cli/customize-doctor.d.ts +145 -0
- package/dist/types/cli/daemon-cli.d.ts +3 -1
- package/dist/types/cli/mcp-cli.d.ts +11 -0
- package/dist/types/cli/notify-cli.d.ts +1 -1
- package/dist/types/cli/root-flags.d.ts +12 -0
- package/dist/types/cli/setup-cli.d.ts +3 -1
- package/dist/types/cli/skills-cli.d.ts +2 -1
- package/dist/types/cli/update-cli.d.ts +19 -1
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/commands/accounts.d.ts +40 -0
- package/dist/types/commands/crash.d.ts +24 -0
- package/dist/types/commands/customize.d.ts +22 -0
- package/dist/types/commands/daemon.d.ts +1 -1
- package/dist/types/commands/launch.d.ts +6 -0
- package/dist/types/commands/setup.d.ts +6 -0
- package/dist/types/commands/skills.d.ts +6 -1
- package/dist/types/commands/update.d.ts +7 -0
- package/dist/types/config/atomic-yaml-patch-worker.d.ts +25 -0
- package/dist/types/config/atomic-yaml-patch.d.ts +62 -2
- package/dist/types/config/config-schema-version.d.ts +10 -0
- package/dist/types/config/file-lock.d.ts +18 -0
- package/dist/types/config/model-profile-activation.d.ts +3 -1
- package/dist/types/config/model-registry.d.ts +10 -1
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +73 -9
- package/dist/types/config/settings.d.ts +63 -0
- package/dist/types/config/skill-settings-defaults.d.ts +26 -0
- package/dist/types/config/task-delegation.d.ts +39 -0
- package/dist/types/config/update-channel.d.ts +10 -0
- package/dist/types/coordinator-mcp/server.d.ts +5 -1
- package/dist/types/crash/index-store.d.ts +87 -0
- package/dist/types/crash/nudge.d.ts +50 -0
- package/dist/types/crash/record-loader.d.ts +17 -0
- package/dist/types/crash/report.d.ts +134 -0
- package/dist/types/crash/sanitize.d.ts +25 -0
- package/dist/types/cursor.d.ts +13 -2
- package/dist/types/customization/import.d.ts +37 -0
- package/dist/types/customization/index.d.ts +4 -0
- package/dist/types/customization/inventory.d.ts +25 -0
- package/dist/types/customization/mutations.d.ts +32 -0
- package/dist/types/customization/types.d.ts +115 -0
- package/dist/types/daemon/control-types.d.ts +8 -1
- package/dist/types/daemon/operator-contract.d.ts +4 -4
- package/dist/types/discovery/claude.d.ts +39 -1
- package/dist/types/discovery/codex.d.ts +39 -1
- package/dist/types/discovery/index.d.ts +2 -0
- package/dist/types/discovery/mcp-compat.d.ts +30 -0
- package/dist/types/edit/renderer.d.ts +23 -0
- package/dist/types/extensibility/extensions/runner.d.ts +3 -0
- package/dist/types/extensibility/extensions/types.d.ts +21 -4
- package/dist/types/extensibility/gjc-plugins/observability.d.ts +6 -1
- package/dist/types/extensibility/gjc-plugins/registry.d.ts +8 -1
- package/dist/types/extensibility/hooks/loader.d.ts +19 -5
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +22 -1
- package/dist/types/extensibility/skill-management.d.ts +107 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +3 -1
- package/dist/types/gjc-runtime/launch-worktree.d.ts +8 -0
- package/dist/types/gjc-runtime/linux-proc.d.ts +3 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +10 -6
- package/dist/types/gjc-runtime/session-state-lock.d.ts +104 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +120 -2
- package/dist/types/gjc-runtime/state-writer.d.ts +10 -1
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +4 -2
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -6
- package/dist/types/gjc-runtime/workflow-settings.d.ts +109 -0
- package/dist/types/hooks/events.d.ts +60 -0
- package/dist/types/hooks/normalize.d.ts +83 -0
- package/dist/types/hooks/skill-state.d.ts +9 -2
- package/dist/types/main.d.ts +2 -1
- package/dist/types/modes/acp/abort-scope.d.ts +13 -0
- package/dist/types/modes/acp/acp-agent.d.ts +7 -4
- package/dist/types/modes/components/customization/customization-dashboard.d.ts +44 -0
- package/dist/types/modes/components/customization/import-wizard.d.ts +21 -0
- package/dist/types/modes/components/customization/index.d.ts +1 -0
- package/dist/types/modes/components/dynamic-theme-text.d.ts +9 -0
- package/dist/types/modes/components/gajae-pet-widget.d.ts +6 -28
- package/dist/types/modes/components/irc-sidebar.d.ts +1 -0
- package/dist/types/modes/components/iterm-pet-transport.d.ts +122 -0
- package/dist/types/modes/components/oauth-selector.d.ts +10 -4
- package/dist/types/modes/components/pet-capability.d.ts +7 -21
- package/dist/types/modes/components/settings-selector.d.ts +5 -0
- package/dist/types/modes/components/status-line/gh.d.ts +6 -2
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +7 -8
- package/dist/types/modes/controllers/stt-controller.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/theme/defaults/index.d.ts +118 -0
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/modes/utils/injected-user-submission.d.ts +10 -0
- package/dist/types/runtime-mcp/config.d.ts +9 -0
- package/dist/types/runtime-mcp/manager.d.ts +26 -1
- package/dist/types/runtime-mcp/oauth-discovery.d.ts +4 -0
- package/dist/types/runtime-mcp/oauth-flow.d.ts +24 -1
- package/dist/types/runtime-mcp/pool-key.d.ts +2 -0
- package/dist/types/runtime-mcp/protocol.d.ts +278 -0
- package/dist/types/runtime-mcp/scope-config.d.ts +29 -0
- package/dist/types/runtime-mcp/tool-bridge.d.ts +15 -13
- package/dist/types/runtime-mcp/transports/http.d.ts +9 -0
- package/dist/types/runtime-mcp/types.d.ts +102 -10
- package/dist/types/sdk/acp/adapter.d.ts +26 -5
- package/dist/types/sdk/broker/broker.d.ts +3 -55
- package/dist/types/sdk/broker/lifecycle.d.ts +18 -12
- package/dist/types/sdk/broker/session-index.d.ts +14 -5
- package/dist/types/sdk/broker/startup-failure.d.ts +16 -1
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +51 -1
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +4 -41
- package/dist/types/sdk/bus/config.d.ts +11 -0
- package/dist/types/sdk/bus/conversation-store.d.ts +0 -1
- package/dist/types/sdk/bus/daemon-paths.d.ts +6 -0
- package/dist/types/sdk/bus/discord-conversation.d.ts +2 -0
- package/dist/types/sdk/bus/discord-daemon.d.ts +17 -12
- package/dist/types/sdk/bus/existing-thread-readiness.d.ts +4 -34
- package/dist/types/sdk/bus/inbound-reaction-ordering.d.ts +61 -0
- package/dist/types/sdk/bus/index.d.ts +85 -99
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +29 -7
- package/dist/types/sdk/bus/managed-daemon.d.ts +2 -32
- package/dist/types/sdk/bus/notification-service.d.ts +52 -0
- package/dist/types/sdk/bus/operator-runtime.d.ts +1 -1
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +16 -5
- package/dist/types/sdk/bus/reconciliation-store.d.ts +113 -5
- package/dist/types/sdk/bus/session-control.d.ts +25 -1
- package/dist/types/sdk/bus/slack-conversation.d.ts +4 -0
- package/dist/types/sdk/bus/slack-daemon.d.ts +9 -17
- package/dist/types/sdk/bus/slack-live-provider.d.ts +3 -1
- package/dist/types/sdk/bus/slack-provider.d.ts +4 -0
- package/dist/types/sdk/bus/slack-thread-binding.d.ts +6 -40
- package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +30 -104
- package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +10 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +262 -19
- package/dist/types/sdk/bus/telegram-daemon-orphan-reap.d.ts +125 -0
- package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +22 -0
- package/dist/types/sdk/bus/telegram-daemon.d.ts +119 -310
- package/dist/types/sdk/bus/telegram-reference.d.ts +1 -47
- package/dist/types/sdk/bus/threaded-render.d.ts +1 -0
- package/dist/types/sdk/bus/topic-registry.d.ts +33 -17
- package/dist/types/sdk/cli/rows.d.ts +2 -11
- package/dist/types/sdk/cli/session-cli.d.ts +15 -25
- package/dist/types/sdk/client/client.d.ts +97 -1
- package/dist/types/sdk/host/control/dispatch.d.ts +0 -7
- package/dist/types/sdk/host/control/index.d.ts +1 -1
- package/dist/types/sdk/host/control/operations.d.ts +18 -5
- package/dist/types/sdk/host/control/runtime-gate.d.ts +19 -0
- package/dist/types/sdk/host/host.d.ts +15 -1
- package/dist/types/sdk/host/query/handlers.d.ts +5 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
- package/dist/types/sdk/host/session-runtime.d.ts +127 -7
- package/dist/types/sdk/host/types.d.ts +1 -1
- package/dist/types/sdk/host/websocket-transport.d.ts +1 -1
- package/dist/types/sdk/index.d.ts +2 -1
- package/dist/types/sdk/lifecycle/broker-client.d.ts +8 -0
- package/dist/types/sdk/lifecycle/client.d.ts +59 -0
- package/dist/types/sdk/lifecycle/index.d.ts +3 -0
- package/dist/types/sdk/lifecycle/service.d.ts +232 -0
- package/dist/types/sdk/mcp/server.d.ts +9 -6
- package/dist/types/sdk/prompt-deadline-lease.d.ts +43 -0
- package/dist/types/sdk/prompt-deadline-manager.d.ts +28 -0
- package/dist/types/sdk/prompt-status.d.ts +10 -3
- package/dist/types/sdk/protocol/operation-registry.d.ts +5 -0
- package/dist/types/sdk/receipt-state.d.ts +17 -0
- package/dist/types/sdk/reconciliation-extensions.d.ts +2 -0
- package/dist/types/sdk/router/index.d.ts +1 -0
- package/dist/types/sdk/router/session-router.d.ts +152 -0
- package/dist/types/sdk/session-list.d.ts +22 -0
- package/dist/types/sdk/session-reconnect.d.ts +43 -1
- package/dist/types/sdk/session.d.ts +34 -1
- package/dist/types/sdk/transport/serve-cli.d.ts +1 -4
- package/dist/types/session/account-inventory.d.ts +86 -0
- package/dist/types/session/agent-session.d.ts +145 -6
- package/dist/types/session/agent-storage.d.ts +10 -0
- package/dist/types/session/coordinator-tool-label.d.ts +28 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +23 -4
- package/dist/types/session/messages.d.ts +1 -1
- package/dist/types/session/secure-token-file.d.ts +3 -0
- package/dist/types/session/session-manager.d.ts +47 -1
- package/dist/types/session/startup-auth-config.d.ts +44 -0
- package/dist/types/session/terminal-abort.d.ts +378 -0
- package/dist/types/session/yield-queue.d.ts +7 -0
- package/dist/types/session-import/claude.d.ts +26 -0
- package/dist/types/session-import/codex.d.ts +88 -0
- package/dist/types/session-import/command.d.ts +35 -0
- package/dist/types/session-import/detect.d.ts +22 -0
- package/dist/types/session-import/index.d.ts +7 -0
- package/dist/types/session-import/provider-codex.d.ts +22 -0
- package/dist/types/session-import/provider-service.d.ts +38 -0
- package/dist/types/session-import/redact.d.ts +23 -0
- package/dist/types/session-import/service.d.ts +47 -0
- package/dist/types/session-import/types.d.ts +120 -0
- package/dist/types/setup/paseo/check.d.ts +16 -0
- package/dist/types/setup/paseo/install-saga.d.ts +115 -0
- package/dist/types/setup/paseo/json-publisher.d.ts +76 -0
- package/dist/types/setup/paseo/orchestration-preferences.d.ts +24 -0
- package/dist/types/setup/paseo/paseo-ownership.d.ts +87 -0
- package/dist/types/setup/paseo/paseo-setup.d.ts +29 -0
- package/dist/types/setup/paseo/provider-config.d.ts +35 -0
- package/dist/types/setup/paseo/remove.d.ts +14 -0
- package/dist/types/setup/paseo/result-types.d.ts +59 -0
- package/dist/types/setup/paseo/setup-deps.d.ts +73 -0
- package/dist/types/setup/paseo/skills-bridge.d.ts +44 -0
- package/dist/types/skill-state/active-state.d.ts +5 -1
- package/dist/types/slash-commands/acp-builtins.d.ts +5 -1
- package/dist/types/slash-commands/builtin-registry.d.ts +2 -0
- package/dist/types/slash-commands/helpers/credential-switch.d.ts +12 -0
- package/dist/types/slash-commands/helpers/usage-report.d.ts +5 -6
- package/dist/types/slash-commands/types.d.ts +7 -1
- package/dist/types/task/executor.d.ts +10 -0
- package/dist/types/task/index.d.ts +3 -1
- package/dist/types/tools/ask-answer-registry.d.ts +6 -3
- package/dist/types/tools/bash-sleep-advisory.d.ts +14 -0
- package/dist/types/tools/bash.d.ts +2 -6
- package/dist/types/tools/browser/attach.d.ts +11 -0
- package/dist/types/tools/browser/launch.d.ts +20 -0
- package/dist/types/tools/browser/profile-discovery.d.ts +6 -0
- package/dist/types/tools/browser/render.d.ts +1 -0
- package/dist/types/tools/browser.d.ts +3 -1
- package/dist/types/tools/image-gen.d.ts +10 -2
- package/dist/types/tools/index.d.ts +8 -0
- package/dist/types/tools/monitor.d.ts +1 -1
- package/dist/types/tools/skill-discovery.d.ts +8 -1
- package/dist/types/tools/subagent.d.ts +2 -0
- package/dist/types/tools/ultragoal-ask-guard.d.ts +2 -2
- package/dist/types/utils/herdr-pane.d.ts +76 -0
- package/package.json +19 -9
- package/scripts/build-binary.ts +2 -1
- package/scripts/build-sdk-package-smoke.ts +2 -13
- package/scripts/capture-sticky-viewport-showcase.ts +0 -1
- package/scripts/compile-args.ts +2 -0
- package/scripts/generate-sdk-adapter-parity-manifest.ts +31 -16
- package/scripts/generate-sdk-operation-inventory.ts +28 -0
- package/scripts/generate-telegram-baseline-manifest.ts +1 -0
- package/scripts/generate-tool-catalog.ts +6 -4
- package/scripts/verify-gjc-sdk-canonicalization.ts +5 -39
- package/src/async/job-manager.ts +352 -17
- package/src/async/support.ts +25 -0
- package/src/autoresearch/dashboard.ts +28 -13
- package/src/capability/index.ts +3 -1
- package/src/capability/mcp.ts +6 -0
- package/src/capability/types.ts +6 -0
- package/src/cli/accounts-cli.ts +395 -0
- package/src/cli/args.ts +23 -0
- package/src/cli/auth-broker-cli.ts +136 -66
- package/src/cli/auth-gateway-cli.ts +94 -70
- package/src/cli/config-cli.ts +27 -2
- package/src/cli/crash-cli.ts +78 -0
- package/src/cli/customize-doctor.ts +1605 -0
- package/src/cli/daemon-cli.ts +12 -3
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/mcp-cli.ts +128 -60
- package/src/cli/notify-cli.ts +8 -14
- package/src/cli/root-flags.ts +8 -0
- package/src/cli/setup-cli.ts +145 -0
- package/src/cli/skills-cli.ts +38 -2
- package/src/cli/update-cli.ts +167 -12
- package/src/cli.ts +4 -0
- package/src/commands/accounts.ts +71 -0
- package/src/commands/crash.ts +35 -0
- package/src/commands/customize.ts +84 -0
- package/src/commands/daemon.ts +2 -2
- package/src/commands/deep-interview.ts +2 -0
- package/src/commands/launch.ts +1 -0
- package/src/commands/mcp.ts +12 -7
- package/src/commands/ralplan.ts +2 -0
- package/src/commands/sdk.ts +65 -32
- package/src/commands/setup.ts +5 -0
- package/src/commands/skills.ts +14 -4
- package/src/commands/ultragoal.ts +10 -1
- package/src/commands/update.ts +26 -15
- package/src/config/atomic-yaml-patch-worker.ts +57 -0
- package/src/config/atomic-yaml-patch.ts +769 -29
- package/src/config/config-schema-version.ts +10 -0
- package/src/config/file-lock.ts +70 -1
- package/src/config/mcp-schema.json +52 -14
- package/src/config/model-profile-activation.ts +23 -2
- package/src/config/model-profiles.ts +88 -21
- package/src/config/model-registry.ts +147 -21
- package/src/config/models-config-schema.ts +1 -1
- package/src/config/settings-schema.ts +77 -7
- package/src/config/settings.ts +4038 -199
- package/src/config/skill-settings-defaults.ts +41 -3
- package/src/config/task-delegation.ts +87 -0
- package/src/config/update-channel.ts +23 -0
- package/src/coordinator-mcp/server.ts +377 -308
- package/src/crash/index-store.ts +723 -0
- package/src/crash/nudge.ts +89 -0
- package/src/crash/record-loader.ts +149 -0
- package/src/crash/report.ts +551 -0
- package/src/crash/sanitize.ts +129 -0
- package/src/cursor.ts +36 -10
- package/src/customization/import.ts +946 -0
- package/src/customization/index.ts +4 -0
- package/src/customization/inventory.ts +335 -0
- package/src/customization/mutations.ts +141 -0
- package/src/customization/types.ts +223 -0
- package/src/daemon/control-types.ts +8 -1
- package/src/daemon/operator-contract.ts +6 -6
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +31 -6
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +11 -22
- package/src/defaults/gjc/skills/ralplan/SKILL.md +36 -23
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +16 -0
- package/src/discovery/claude-hooks.ts +38 -0
- package/src/discovery/claude.ts +142 -209
- package/src/discovery/codex-hooks.ts +38 -0
- package/src/discovery/codex.ts +132 -198
- package/src/discovery/helpers.ts +8 -1
- package/src/discovery/index.ts +2 -0
- package/src/discovery/mcp-compat.ts +234 -0
- package/src/discovery/mcp-json.ts +6 -0
- package/src/edit/renderer.ts +40 -0
- package/src/edit/streaming.ts +4 -2
- package/src/exec/bash-executor.ts +24 -20
- package/src/export/html/index.ts +51 -2
- package/src/extensibility/extensions/loader.ts +9 -1
- package/src/extensibility/extensions/runner.ts +17 -4
- package/src/extensibility/extensions/types.ts +31 -6
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +33 -0
- package/src/extensibility/gjc-plugins/installer.ts +9 -5
- package/src/extensibility/gjc-plugins/observability.ts +8 -2
- package/src/extensibility/gjc-plugins/registry.ts +13 -2
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +3 -1
- package/src/extensibility/gjc-plugins/schema.ts +222 -39
- package/src/extensibility/hooks/loader.ts +154 -10
- package/src/extensibility/runtime-skill-discovery.ts +257 -60
- package/src/extensibility/skill-management.ts +368 -0
- package/src/extensibility/skills.ts +52 -16
- package/src/gjc-runtime/deep-interview-runtime.ts +45 -61
- package/src/gjc-runtime/launch-worktree.ts +56 -2
- package/src/gjc-runtime/linux-proc.ts +7 -1
- package/src/gjc-runtime/ralplan-runtime.ts +100 -164
- package/src/gjc-runtime/session-state-lock.ts +992 -0
- package/src/gjc-runtime/session-state-sidecar.ts +644 -142
- package/src/gjc-runtime/state-writer.ts +39 -14
- package/src/gjc-runtime/tmux-owner-isolation.ts +5 -4
- package/src/gjc-runtime/ultragoal-guard.ts +11 -4
- package/src/gjc-runtime/ultragoal-runtime.ts +44 -41
- package/src/gjc-runtime/workflow-settings.ts +596 -0
- package/src/goals/tools/goal-tool.ts +6 -1
- package/src/hooks/events.ts +291 -0
- package/src/hooks/native-skill-hook.ts +4 -0
- package/src/hooks/normalize.ts +369 -0
- package/src/hooks/skill-state.ts +165 -46
- package/src/internal-urls/docs-index.generated.ts +41 -32
- package/src/main.ts +36 -5
- package/src/migrate/mcp-mapper.ts +25 -2
- package/src/modes/acp/abort-scope.ts +29 -0
- package/src/modes/acp/acp-agent.ts +423 -98
- package/src/modes/components/assistant-message.ts +6 -1
- package/src/modes/components/chrome.ts +4 -3
- package/src/modes/components/customization/customization-dashboard.ts +443 -0
- package/src/modes/components/customization/import-wizard.ts +372 -0
- package/src/modes/components/customization/index.ts +1 -0
- package/src/modes/components/dynamic-theme-text.ts +22 -0
- package/src/modes/components/gajae-pet-widget.ts +607 -193
- package/src/modes/components/irc-sidebar.ts +11 -0
- package/src/modes/components/iterm-pet-transport.ts +585 -0
- package/src/modes/components/model-selector.ts +1 -6
- package/src/modes/components/oauth-selector.ts +277 -86
- package/src/modes/components/pet-capability.ts +35 -31
- package/src/modes/components/settings-selector.ts +29 -5
- package/src/modes/components/status-line/gh.ts +45 -1
- package/src/modes/components/status-line/segments.ts +19 -4
- package/src/modes/components/tool-status-header.ts +13 -3
- package/src/modes/controllers/command-controller.ts +20 -8
- package/src/modes/controllers/extension-ui-controller.ts +56 -257
- package/src/modes/controllers/input-controller.ts +10 -0
- package/src/modes/controllers/runtime-mcp-command-controller.ts +16 -3
- package/src/modes/controllers/selector-controller.ts +238 -77
- package/src/modes/controllers/stt-controller.ts +3 -3
- package/src/modes/interactive-mode.ts +88 -16
- package/src/modes/print-mode.ts +35 -6
- package/src/modes/runtime-init.ts +21 -68
- package/src/modes/theme/defaults/index.ts +2 -0
- package/src/modes/theme/defaults/ouroboros.json +118 -0
- package/src/modes/types.ts +1 -0
- package/src/modes/utils/injected-user-submission.ts +25 -0
- package/src/modes/utils/terminal-bell.ts +15 -1
- package/src/prompts/agent-fragments/ralplan-persistence.md +1 -1
- package/src/prompts/agent-fragments/restricted-bash.md +1 -1
- package/src/prompts/agents/critic.md +1 -1
- package/src/prompts/system/rlm-research.md +1 -1
- package/src/prompts/system/system-prompt.md +0 -2
- package/src/prompts/tools/bash.md +7 -1
- package/src/prompts/tools/browser.md +1 -1
- package/src/prompts/tools/cron.md +6 -6
- package/src/prompts/tools/read.md +0 -2
- package/src/prompts/tools/skill-discovery.md +4 -2
- package/src/runtime-mcp/client.ts +427 -23
- package/src/runtime-mcp/config.ts +37 -5
- package/src/runtime-mcp/manager-pool.test.ts +56 -0
- package/src/runtime-mcp/manager.ts +52 -2
- package/src/runtime-mcp/oauth-discovery.ts +13 -0
- package/src/runtime-mcp/oauth-flow.ts +46 -1
- package/src/runtime-mcp/pool-key.ts +5 -1
- package/src/runtime-mcp/pool.test.ts +9 -0
- package/src/runtime-mcp/protocol.test.ts +353 -0
- package/src/runtime-mcp/protocol.ts +624 -0
- package/src/runtime-mcp/scope-config.ts +78 -0
- package/src/runtime-mcp/tool-bridge.ts +44 -10
- package/src/runtime-mcp/transports/http.ts +84 -13
- package/src/runtime-mcp/types.ts +123 -12
- package/src/sdk/acp/adapter.ts +328 -97
- package/src/sdk/broker/broker.ts +160 -741
- package/src/sdk/broker/ensure.ts +9 -1
- package/src/sdk/broker/lifecycle.ts +510 -116
- package/src/sdk/broker/operation-receipt-ledger.ts +11 -2
- package/src/sdk/broker/process-incarnation.ts +19 -0
- package/src/sdk/broker/session-index.ts +516 -117
- package/src/sdk/broker/startup-failure.ts +28 -5
- package/src/sdk/broker/transport.ts +1 -13
- package/src/sdk/bus/chat-daemon-cli.ts +4 -2
- package/src/sdk/bus/chat-daemon-control.ts +67 -6
- package/src/sdk/bus/chat-daemon-runtime.ts +183 -859
- package/src/sdk/bus/config.ts +13 -0
- package/src/sdk/bus/conversation-store.ts +59 -171
- package/src/sdk/bus/daemon-paths.ts +20 -0
- package/src/sdk/bus/discord-conversation.ts +2 -0
- package/src/sdk/bus/discord-daemon.ts +524 -126
- package/src/sdk/bus/discord-live-provider.ts +206 -79
- package/src/sdk/bus/existing-thread-readiness.ts +4 -97
- package/src/sdk/bus/inbound-reaction-ordering.ts +122 -0
- package/src/sdk/bus/index.ts +2480 -456
- package/src/sdk/bus/kind-aware-reconciliation.ts +204 -34
- package/src/sdk/bus/lifecycle-commands.ts +2 -2
- package/src/sdk/bus/managed-daemon.ts +2 -145
- package/src/sdk/bus/notification-service.ts +196 -0
- package/src/sdk/bus/operator-runtime.ts +1 -1
- package/src/sdk/bus/prompt-reconciliation.ts +24 -15
- package/src/sdk/bus/reconciliation-store.ts +553 -24
- package/src/sdk/bus/session-control.ts +49 -3
- package/src/sdk/bus/slack-conversation.ts +4 -0
- package/src/sdk/bus/slack-daemon.ts +733 -134
- package/src/sdk/bus/slack-live-provider.ts +65 -15
- package/src/sdk/bus/slack-provider.ts +4 -0
- package/src/sdk/bus/slack-thread-binding.ts +9 -104
- package/src/sdk/bus/telegram-adoption-intent.ts +299 -209
- package/src/sdk/bus/telegram-daemon-cli.ts +194 -7
- package/src/sdk/bus/telegram-daemon-contract.ts +265 -19
- package/src/sdk/bus/telegram-daemon-control.ts +3 -13
- package/src/sdk/bus/telegram-daemon-orphan-reap.ts +498 -0
- package/src/sdk/bus/telegram-daemon-owner-registry.ts +176 -0
- package/src/sdk/bus/telegram-daemon.ts +2552 -2280
- package/src/sdk/bus/telegram-reference.ts +1 -226
- package/src/sdk/bus/telegram-setup.ts +2 -2
- package/src/sdk/bus/threaded-render.ts +1 -0
- package/src/sdk/bus/topic-registry.ts +279 -146
- package/src/sdk/cli/rows.ts +2 -35
- package/src/sdk/cli/session-cli.ts +776 -700
- package/src/sdk/client/client.ts +892 -1
- package/src/sdk/host/control/dispatch.ts +93 -58
- package/src/sdk/host/control/index.ts +1 -1
- package/src/sdk/host/control/operations.ts +18 -10
- package/src/sdk/host/control/runtime-gate.ts +40 -0
- package/src/sdk/host/host.ts +63 -12
- package/src/sdk/host/query/handlers.ts +66 -7
- package/src/sdk/host/reverse-leases.ts +2 -2
- package/src/sdk/host/sdk-surface-parity.test.ts +1 -1
- package/src/sdk/host/session-runtime.test.ts +2787 -34
- package/src/sdk/host/session-runtime.ts +1489 -101
- package/src/sdk/host/surface-policy.ts +12 -8
- package/src/sdk/host/types.ts +1 -1
- package/src/sdk/host/websocket-transport.lifecycle.test.ts +31 -59
- package/src/sdk/host/websocket-transport.ts +85 -50
- package/src/sdk/index.ts +2 -1
- package/src/sdk/lifecycle/broker-client.ts +53 -0
- package/src/sdk/lifecycle/client.ts +234 -0
- package/src/sdk/lifecycle/index.ts +3 -0
- package/src/sdk/{bus/recent-activity.ts → lifecycle/recent-sessions.ts} +5 -2
- package/src/sdk/lifecycle/service.ts +720 -0
- package/src/sdk/mcp/server.ts +226 -188
- package/src/sdk/prompt-deadline-lease.ts +55 -0
- package/src/sdk/prompt-deadline-manager.ts +148 -0
- package/src/sdk/prompt-status.ts +11 -3
- package/src/sdk/protocol/operation-inventory.generated.json +272 -129
- package/src/sdk/protocol/operation-registry.ts +71 -8
- package/src/sdk/receipt-state.ts +43 -0
- package/src/sdk/reconciliation-extensions.ts +14 -0
- package/src/sdk/router/index.ts +1 -0
- package/src/sdk/router/session-router.ts +1658 -0
- package/src/sdk/session-list.ts +93 -0
- package/src/sdk/session-reconnect.ts +45 -1
- package/src/sdk/session.ts +716 -120
- package/src/sdk/transport/serve-cli.ts +18 -34
- package/src/session/account-inventory.ts +603 -0
- package/src/session/agent-session.ts +2873 -559
- package/src/session/agent-storage.ts +35 -0
- package/src/session/blob-store.ts +32 -1
- package/src/session/coordinator-tool-label.ts +40 -0
- package/src/session/internal/managed-session-scope.ts +4 -0
- package/src/session/internal/managed-session-storage.ts +199 -31
- package/src/session/messages.ts +1 -1
- package/src/session/secure-token-file.ts +80 -0
- package/src/session/session-manager.ts +757 -57
- package/src/session/session-storage.ts +25 -16
- package/src/session/startup-auth-config.ts +297 -0
- package/src/session/terminal-abort.ts +1253 -0
- package/src/session/yield-queue.ts +57 -15
- package/src/session-import/claude.ts +334 -0
- package/src/session-import/codex.ts +1033 -0
- package/src/session-import/command.ts +77 -0
- package/src/session-import/detect.ts +133 -0
- package/src/session-import/index.ts +7 -0
- package/src/session-import/provider-codex.ts +327 -0
- package/src/session-import/provider-service.ts +457 -0
- package/src/session-import/redact.ts +128 -0
- package/src/session-import/service.ts +1264 -0
- package/src/session-import/types.ts +148 -0
- package/src/setup/paseo/check.ts +213 -0
- package/src/setup/paseo/install-saga.ts +293 -0
- package/src/setup/paseo/json-publisher.ts +263 -0
- package/src/setup/paseo/orchestration-preferences.ts +86 -0
- package/src/setup/paseo/paseo-ownership.ts +224 -0
- package/src/setup/paseo/paseo-setup.ts +253 -0
- package/src/setup/paseo/provider-config.ts +139 -0
- package/src/setup/paseo/remove.ts +183 -0
- package/src/setup/paseo/result-types.ts +79 -0
- package/src/setup/paseo/setup-deps.ts +175 -0
- package/src/setup/paseo/skills-bridge.ts +260 -0
- package/src/skill-state/active-state.ts +21 -11
- package/src/slash-commands/acp-builtins.ts +9 -1
- package/src/slash-commands/builtin-registry.ts +117 -19
- package/src/slash-commands/helpers/credential-switch.ts +143 -0
- package/src/slash-commands/helpers/mcp.ts +9 -3
- package/src/slash-commands/helpers/usage-report.ts +61 -56
- package/src/slash-commands/types.ts +7 -2
- package/src/task/executor.ts +30 -11
- package/src/task/index.ts +66 -7
- package/src/task/render.ts +23 -9
- package/src/tools/ask-answer-registry.ts +23 -7
- package/src/tools/ask.ts +8 -4
- package/src/tools/bash-sleep-advisory.ts +115 -0
- package/src/tools/bash.ts +98 -18
- package/src/tools/browser/attach.ts +71 -3
- package/src/tools/browser/launch.ts +86 -13
- package/src/tools/browser/profile-discovery.ts +57 -7
- package/src/tools/browser/render.ts +8 -1
- package/src/tools/browser.ts +130 -21
- package/src/tools/computer.enforcement.test.ts +1 -1
- package/src/tools/computer.ts +3 -2
- package/src/tools/cron.ts +12 -1
- package/src/tools/image-gen.ts +349 -142
- package/src/tools/index.ts +8 -0
- package/src/tools/job.ts +33 -6
- package/src/tools/monitor.ts +41 -2
- package/src/tools/skill-discovery.ts +21 -29
- package/src/tools/subagent.ts +142 -24
- package/src/tools/todo-contract.ts +55 -3
- package/src/tools/todo-write.ts +4 -3
- package/src/tools/tool-catalog.generated.ts +6 -6
- package/src/tools/ultragoal-ask-guard.ts +10 -3
- package/src/utils/herdr-pane.ts +345 -0
- package/src/utils/title-generator.ts +2 -0
- package/src/web/scrapers/index.ts +6 -4
- package/dist/types/cli/malloc-env-guard.test.d.ts +0 -1
- package/dist/types/defaults/gjc-defaults.test.d.ts +0 -1
- package/dist/types/memory-backend/lazy-loading.test.d.ts +0 -1
- package/dist/types/runtime/boot-ordering.test.d.ts +0 -1
- package/dist/types/runtime/lazy-service.test.d.ts +0 -1
- package/dist/types/runtime/network-prewarm-service.test.d.ts +0 -1
- package/dist/types/runtime/workspace-tree-service.test.d.ts +0 -1
- package/dist/types/runtime-mcp/config.test.d.ts +0 -1
- package/dist/types/runtime-mcp/http.test.d.ts +0 -1
- package/dist/types/runtime-mcp/manager-pool.test.d.ts +0 -1
- package/dist/types/runtime-mcp/pool-key.test.d.ts +0 -1
- package/dist/types/runtime-mcp/pool.test.d.ts +0 -1
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +0 -117
- package/dist/types/sdk/bus/lifecycle-orchestrator.d.ts +0 -141
- package/dist/types/sdk/bus/telegram-cli.d.ts +0 -31
- package/dist/types/sdk/elevation/allowlist.d.ts +0 -20
- package/dist/types/sdk/elevation/audit.d.ts +0 -93
- package/dist/types/sdk/elevation/capability.d.ts +0 -3
- package/dist/types/sdk/elevation/digest.d.ts +0 -72
- package/dist/types/sdk/elevation/dispatch-receipt.d.ts +0 -85
- package/dist/types/sdk/elevation/grant-ledger.d.ts +0 -163
- package/dist/types/sdk/elevation/owner.d.ts +0 -48
- package/dist/types/sdk/host/import-graph.test.d.ts +0 -1
- package/dist/types/sdk/host/sdk-surface-parity.test.d.ts +0 -1
- package/dist/types/sdk/host/session-runtime.test.d.ts +0 -1
- package/dist/types/sdk/host/websocket-transport.lifecycle.test.d.ts +0 -1
- package/dist/types/session/auth-broker-config.d.ts +0 -13
- package/dist/types/session/heap-eviction-artifacts.test.d.ts +0 -1
- package/dist/types/skills/skills.test.d.ts +0 -1
- package/dist/types/slash-commands/notify-command.test.d.ts +0 -1
- package/dist/types/task/token-log.test.d.ts +0 -1
- package/dist/types/tools/computer.enforcement.test.d.ts +0 -1
- package/dist/types/tools/descriptors.test.d.ts +0 -1
- package/scripts/g005-daemon-smoke.ts +0 -180
- package/scripts/g011-daemon-path-smoke.ts +0 -153
- package/src/sdk/bus/lifecycle-control-runtime.ts +0 -1733
- package/src/sdk/bus/lifecycle-orchestrator.ts +0 -489
- package/src/sdk/bus/telegram-cli.ts +0 -212
- package/src/sdk/elevation/allowlist.ts +0 -54
- package/src/sdk/elevation/audit.ts +0 -208
- package/src/sdk/elevation/capability.ts +0 -41
- package/src/sdk/elevation/digest.ts +0 -129
- package/src/sdk/elevation/dispatch-receipt.ts +0 -184
- package/src/sdk/elevation/grant-ledger.ts +0 -1142
- package/src/sdk/elevation/owner.ts +0 -109
- package/src/session/auth-broker-config.ts +0 -109
- /package/dist/types/{ai-core-import-gate.test.d.ts → discovery/claude-hooks.d.ts} +0 -0
- /package/dist/types/{cli/fixture-report.test.d.ts → discovery/codex-hooks.d.ts} +0 -0
- /package/dist/types/sdk/{bus/recent-activity.d.ts → lifecycle/recent-sessions.d.ts} +0 -0
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
const API_BASE = "https://discord.com/api/v10";
|
|
12
12
|
const GATEWAY_INTENTS = 1 + 512 + 32_768;
|
|
13
13
|
const MAX_RATE_LIMIT_RETRIES = 2;
|
|
14
|
+
const REST_REQUEST_TIMEOUT_MS = 5_000;
|
|
14
15
|
const NONCE_PREFIX = "<!-- gjc-thread-nonce:";
|
|
15
16
|
const INVALID_SESSION_RECONNECT_DELAY_MS = 1_000;
|
|
16
17
|
const TERMINAL_GATEWAY_CLOSE_CODES: ReadonlySet<number> = new Set([4_004, 4_010, 4_011, 4_012, 4_013, 4_014]);
|
|
@@ -42,6 +43,22 @@ export interface DiscordLiveProviderOptions {
|
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
type JsonRecord = Record<string, unknown>;
|
|
46
|
+
type DiscordRequestContext = {
|
|
47
|
+
deadline: number;
|
|
48
|
+
controller: AbortController;
|
|
49
|
+
signal: AbortSignal;
|
|
50
|
+
timeoutError: Error;
|
|
51
|
+
timeout: NodeJS.Timeout;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
function discordRequestTimeoutError(): Error {
|
|
55
|
+
return new Error("Discord API request timed out");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function discordAbortError(signal: AbortSignal): Error {
|
|
59
|
+
const reason = signal.reason;
|
|
60
|
+
return reason instanceof Error ? reason : new Error("Discord API request aborted");
|
|
61
|
+
}
|
|
45
62
|
|
|
46
63
|
/** Discord REST/Gateway implementation. The only credential is held privately and is never emitted. */
|
|
47
64
|
export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticProvider {
|
|
@@ -112,33 +129,47 @@ export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticPr
|
|
|
112
129
|
name: string;
|
|
113
130
|
nonce: string;
|
|
114
131
|
}): Promise<DiscordThread> {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
132
|
+
return await this.#withRequestContext(undefined, async context => {
|
|
133
|
+
const marker = `${NONCE_PREFIX}${input.nonce}${NONCE_SUFFIX}`;
|
|
134
|
+
const starter = await this.#findStarterMessage(input.parentId, marker, context);
|
|
135
|
+
if (starter?.thread) {
|
|
136
|
+
const existing = this.#starterThread(starter.thread, input.guildId, input.parentId);
|
|
137
|
+
if (!existing) throw new Error("Discord returned an invalid starter-message thread");
|
|
138
|
+
return existing;
|
|
139
|
+
}
|
|
140
|
+
const messageId = starter?.id ?? (await this.#createStarterMessage(input.parentId, marker, context));
|
|
141
|
+
const body = await this.#request(
|
|
142
|
+
`/channels/${input.parentId}/messages/${messageId}/threads`,
|
|
143
|
+
{
|
|
144
|
+
method: "POST",
|
|
145
|
+
body: JSON.stringify({ name: input.name, auto_archive_duration: 1_440 }),
|
|
146
|
+
},
|
|
147
|
+
context,
|
|
148
|
+
);
|
|
149
|
+
return this.#thread(body, input.guildId, input.parentId);
|
|
126
150
|
});
|
|
127
|
-
return this.#thread(body, input.guildId, input.parentId);
|
|
128
151
|
}
|
|
129
152
|
|
|
130
|
-
async #createStarterMessage(parentId: string, marker: string): Promise<string> {
|
|
131
|
-
const message = await this.#request(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
153
|
+
async #createStarterMessage(parentId: string, marker: string, context: DiscordRequestContext): Promise<string> {
|
|
154
|
+
const message = await this.#request(
|
|
155
|
+
`/channels/${parentId}/messages`,
|
|
156
|
+
{
|
|
157
|
+
method: "POST",
|
|
158
|
+
body: JSON.stringify({ content: marker }),
|
|
159
|
+
},
|
|
160
|
+
context,
|
|
161
|
+
);
|
|
135
162
|
const id = this.#string(message, "id");
|
|
136
163
|
if (!id) throw new Error("Discord returned an invalid starter-message response");
|
|
137
164
|
return id;
|
|
138
165
|
}
|
|
139
166
|
|
|
140
|
-
async #findStarterMessage(
|
|
141
|
-
|
|
167
|
+
async #findStarterMessage(
|
|
168
|
+
parentId: string,
|
|
169
|
+
marker: string,
|
|
170
|
+
context: DiscordRequestContext,
|
|
171
|
+
): Promise<{ id: string; thread?: unknown } | undefined> {
|
|
172
|
+
const messages = await this.#request(`/channels/${parentId}/messages?limit=100`, {}, context);
|
|
142
173
|
if (!Array.isArray(messages)) return undefined;
|
|
143
174
|
for (const message of messages) {
|
|
144
175
|
if (!this.#messageContent(message).includes(marker)) continue;
|
|
@@ -153,21 +184,23 @@ export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticPr
|
|
|
153
184
|
}
|
|
154
185
|
|
|
155
186
|
async findThreadByNonce(input: { guildId: string; parentId: string; nonce: string }): Promise<DiscordThread | null> {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
187
|
+
return await this.#withRequestContext(undefined, async context => {
|
|
188
|
+
const marker = `${NONCE_PREFIX}${input.nonce}${NONCE_SUFFIX}`;
|
|
189
|
+
const parentMessages = await this.#request(`/channels/${input.parentId}/messages?limit=100`, {}, context);
|
|
190
|
+
if (Array.isArray(parentMessages))
|
|
191
|
+
for (const message of parentMessages) {
|
|
192
|
+
if (!this.#messageContent(message).includes(marker)) continue;
|
|
193
|
+
const thread = this.#starterThread(this.#record(message).thread, input.guildId, input.parentId);
|
|
194
|
+
if (thread) return thread;
|
|
195
|
+
}
|
|
196
|
+
const candidates = await this.#listThreads(input.guildId, input.parentId, context);
|
|
197
|
+
for (const candidate of candidates) {
|
|
198
|
+
const messages = await this.#request(`/channels/${candidate.id}/messages?limit=25`, {}, context);
|
|
199
|
+
if (Array.isArray(messages) && messages.some(message => this.#messageContent(message).includes(marker)))
|
|
200
|
+
return candidate;
|
|
163
201
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const messages = await this.#request(`/channels/${candidate.id}/messages?limit=25`);
|
|
167
|
-
if (Array.isArray(messages) && messages.some(message => this.#messageContent(message).includes(marker)))
|
|
168
|
-
return candidate;
|
|
169
|
-
}
|
|
170
|
-
return null;
|
|
202
|
+
return null;
|
|
203
|
+
});
|
|
171
204
|
}
|
|
172
205
|
|
|
173
206
|
async postMessage(input: {
|
|
@@ -242,15 +275,17 @@ export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticPr
|
|
|
242
275
|
async probeConfiguration(signal?: AbortSignal): Promise<DiscordConfigurationProbeResult> {
|
|
243
276
|
if (signal?.aborted) return { ok: false, detail: "Discord configuration probe cancelled." };
|
|
244
277
|
try {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
278
|
+
return await this.#withRequestContext(signal, async context => {
|
|
279
|
+
const currentUser = await this.#request("/users/@me", {}, context);
|
|
280
|
+
const botUserId = this.#string(currentUser, "id");
|
|
281
|
+
if (!botUserId) throw new Error("Discord returned an invalid bot identity.");
|
|
282
|
+
const application = await this.#request("/applications/@me", {}, context);
|
|
283
|
+
const applicationId = this.#string(application, "id");
|
|
284
|
+
if (!applicationId || applicationId !== this.applicationId) {
|
|
285
|
+
throw new Error("Discord application identity does not match the configured application ID.");
|
|
286
|
+
}
|
|
287
|
+
return { ok: true, detail: "Discord bot and application credentials are valid.", botUserId };
|
|
288
|
+
});
|
|
254
289
|
} catch (error) {
|
|
255
290
|
if (signal?.aborted) return { ok: false, detail: "Discord configuration probe cancelled." };
|
|
256
291
|
const detail = error instanceof Error ? error.message : "Discord configuration probe failed.";
|
|
@@ -265,20 +300,25 @@ export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticPr
|
|
|
265
300
|
}): Promise<DiscordOneShotTestResult> {
|
|
266
301
|
if (input.signal?.aborted) return { ok: false, detail: "Discord notification test cancelled." };
|
|
267
302
|
try {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
303
|
+
return await this.#withRequestContext(input.signal, async context => {
|
|
304
|
+
const response = await this.#request(
|
|
305
|
+
`/channels/${input.channelId}/messages`,
|
|
306
|
+
{
|
|
307
|
+
method: "POST",
|
|
308
|
+
body: JSON.stringify({ content: input.message }),
|
|
309
|
+
},
|
|
310
|
+
context,
|
|
311
|
+
);
|
|
312
|
+
const messageId = this.#string(response, "id");
|
|
313
|
+
if (!messageId) {
|
|
314
|
+
return {
|
|
315
|
+
ok: false,
|
|
316
|
+
detail: "Discord may have accepted the message but returned no message receipt.",
|
|
317
|
+
uncertain: true,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
return { ok: true, detail: "Discord notification test delivered.", messageId };
|
|
272
321
|
});
|
|
273
|
-
const messageId = this.#string(response, "id");
|
|
274
|
-
if (!messageId) {
|
|
275
|
-
return {
|
|
276
|
-
ok: false,
|
|
277
|
-
detail: "Discord may have accepted the message but returned no message receipt.",
|
|
278
|
-
uncertain: true,
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
return { ok: true, detail: "Discord notification test delivered.", messageId };
|
|
282
322
|
} catch (error) {
|
|
283
323
|
if (input.signal?.aborted) return { ok: false, detail: "Discord notification test cancelled." };
|
|
284
324
|
const detail = error instanceof Error ? error.message : "Discord notification test failed.";
|
|
@@ -291,15 +331,17 @@ export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticPr
|
|
|
291
331
|
this.#onEvent = onEvent;
|
|
292
332
|
this.#stopped = false;
|
|
293
333
|
try {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
334
|
+
await this.#withRequestContext(undefined, async context => {
|
|
335
|
+
const me = await this.#request("/users/@me", {}, context);
|
|
336
|
+
const id = this.#string(me, "id");
|
|
337
|
+
if (!id) throw new Error("Discord returned an invalid current-user response");
|
|
338
|
+
this.#botUserId = id;
|
|
339
|
+
const gateway = await this.#request("/gateway/bot", {}, context);
|
|
340
|
+
const url = this.#string(gateway, "url");
|
|
341
|
+
if (!url) throw new Error("Discord returned an invalid gateway response");
|
|
342
|
+
this.#gatewayUrl = url;
|
|
343
|
+
this.#connect(url);
|
|
344
|
+
});
|
|
303
345
|
} catch (error) {
|
|
304
346
|
await this.stop();
|
|
305
347
|
throw error;
|
|
@@ -462,16 +504,18 @@ export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticPr
|
|
|
462
504
|
);
|
|
463
505
|
}
|
|
464
506
|
|
|
465
|
-
async #listThreads(guildId: string, parentId: string): Promise<DiscordThread[]> {
|
|
507
|
+
async #listThreads(guildId: string, parentId: string, context: DiscordRequestContext): Promise<DiscordThread[]> {
|
|
466
508
|
const result: DiscordThread[] = [];
|
|
467
|
-
const active = this.#record(await this.#request(`/guilds/${guildId}/threads/active
|
|
509
|
+
const active = this.#record(await this.#request(`/guilds/${guildId}/threads/active`, {}, context));
|
|
468
510
|
const activeThreads = active.threads;
|
|
469
511
|
if (Array.isArray(activeThreads))
|
|
470
512
|
for (const thread of activeThreads) {
|
|
471
513
|
const parsed = this.#threadOrUndefined(thread, guildId, parentId);
|
|
472
514
|
if (parsed) result.push(parsed);
|
|
473
515
|
}
|
|
474
|
-
const archived = this.#record(
|
|
516
|
+
const archived = this.#record(
|
|
517
|
+
await this.#request(`/channels/${parentId}/threads/archived/public?limit=100`, {}, context),
|
|
518
|
+
);
|
|
475
519
|
const archivedThreads = archived.threads;
|
|
476
520
|
if (Array.isArray(archivedThreads))
|
|
477
521
|
for (const thread of archivedThreads) {
|
|
@@ -481,29 +525,112 @@ export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticPr
|
|
|
481
525
|
return result;
|
|
482
526
|
}
|
|
483
527
|
|
|
484
|
-
async #
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
528
|
+
async #withRequestContext<T>(
|
|
529
|
+
callerSignal: AbortSignal | undefined,
|
|
530
|
+
run: (context: DiscordRequestContext) => Promise<T>,
|
|
531
|
+
): Promise<T> {
|
|
532
|
+
const controller = new AbortController();
|
|
533
|
+
const timeoutError = discordRequestTimeoutError();
|
|
534
|
+
const deadline = this.#now() + REST_REQUEST_TIMEOUT_MS;
|
|
535
|
+
const signal = callerSignal ? AbortSignal.any([callerSignal, controller.signal]) : controller.signal;
|
|
536
|
+
const timeout = setTimeout(() => controller.abort(timeoutError), REST_REQUEST_TIMEOUT_MS);
|
|
537
|
+
const context: DiscordRequestContext = {
|
|
538
|
+
deadline,
|
|
539
|
+
controller,
|
|
540
|
+
signal,
|
|
541
|
+
timeoutError,
|
|
542
|
+
timeout,
|
|
543
|
+
};
|
|
544
|
+
try {
|
|
545
|
+
return await run(context);
|
|
546
|
+
} finally {
|
|
547
|
+
clearTimeout(timeout);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
async #request(path: string, init: RequestInit = {}, context?: DiscordRequestContext): Promise<unknown> {
|
|
552
|
+
if (context) {
|
|
553
|
+
return await this.#requestWithHeaders(
|
|
554
|
+
path,
|
|
555
|
+
{ Authorization: `Bot ${this.#token}`, "Content-Type": "application/json" },
|
|
556
|
+
init,
|
|
557
|
+
context,
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
return await this.#withRequestContext(init.signal ?? undefined, requestContext =>
|
|
561
|
+
this.#requestWithHeaders(
|
|
562
|
+
path,
|
|
563
|
+
{ Authorization: `Bot ${this.#token}`, "Content-Type": "application/json" },
|
|
564
|
+
init,
|
|
565
|
+
requestContext,
|
|
566
|
+
),
|
|
489
567
|
);
|
|
490
568
|
}
|
|
491
|
-
async #interactionRequest(path: string, init: RequestInit = {}): Promise<unknown> {
|
|
492
|
-
return await this.#requestWithHeaders(path, { "Content-Type": "application/json" }, init);
|
|
569
|
+
async #interactionRequest(path: string, init: RequestInit = {}, context?: DiscordRequestContext): Promise<unknown> {
|
|
570
|
+
if (context) return await this.#requestWithHeaders(path, { "Content-Type": "application/json" }, init, context);
|
|
571
|
+
return await this.#withRequestContext(init.signal ?? undefined, requestContext =>
|
|
572
|
+
this.#requestWithHeaders(path, { "Content-Type": "application/json" }, init, requestContext),
|
|
573
|
+
);
|
|
493
574
|
}
|
|
494
|
-
async #requestWithHeaders(
|
|
575
|
+
async #requestWithHeaders(
|
|
576
|
+
path: string,
|
|
577
|
+
headers: Record<string, string>,
|
|
578
|
+
init: RequestInit,
|
|
579
|
+
context: DiscordRequestContext,
|
|
580
|
+
): Promise<unknown> {
|
|
495
581
|
for (let attempt = 0; ; attempt++) {
|
|
582
|
+
this.#assertRequestDeadline(context);
|
|
496
583
|
const mergedHeaders = new Headers(headers);
|
|
497
584
|
for (const [key, value] of new Headers(init.headers)) mergedHeaders.set(key, value);
|
|
498
|
-
const response = await this.#
|
|
585
|
+
const response = await this.#requestPhase(
|
|
586
|
+
() =>
|
|
587
|
+
this.#fetch(`${this.#apiBaseUrl}${path}`, { ...init, headers: mergedHeaders, signal: context.signal }),
|
|
588
|
+
context,
|
|
589
|
+
);
|
|
499
590
|
if (response.status !== 429) {
|
|
500
591
|
if (!response.ok) throw new Error(`Discord API request failed (${response.status})`);
|
|
501
|
-
return response.status === 204 ? undefined : await response
|
|
592
|
+
return response.status === 204 ? undefined : await this.#responseJson(response, context);
|
|
502
593
|
}
|
|
503
594
|
if (attempt >= MAX_RATE_LIMIT_RETRIES) throw new Error("Discord API rate limit retry exhausted");
|
|
504
|
-
const limited = this.#record(await response
|
|
595
|
+
const limited = this.#record(await this.#responseJson(response, context));
|
|
505
596
|
const seconds = this.#number(limited, "retry_after") ?? 1;
|
|
506
|
-
|
|
597
|
+
this.#assertRequestDeadline(context);
|
|
598
|
+
const retryRemaining = context.deadline - this.#now();
|
|
599
|
+
await this.#requestPhase(() => this.#sleep(Math.min(Math.max(0, seconds * 1_000), retryRemaining)), context);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
async #responseJson(response: Response, context: DiscordRequestContext): Promise<unknown> {
|
|
604
|
+
return await this.#requestPhase(() => response.json(), context);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
async #requestPhase<T>(phase: () => Promise<T> | T, context: DiscordRequestContext): Promise<T> {
|
|
608
|
+
this.#assertRequestDeadline(context);
|
|
609
|
+
const aborted = Promise.withResolvers<never>();
|
|
610
|
+
const onAbort = () => aborted.reject(discordAbortError(context.signal));
|
|
611
|
+
context.signal.addEventListener("abort", onAbort, { once: true });
|
|
612
|
+
if (context.signal.aborted) onAbort();
|
|
613
|
+
try {
|
|
614
|
+
const value = await Promise.race([Promise.resolve().then(phase), aborted.promise]);
|
|
615
|
+
this.#assertRequestDeadline(context);
|
|
616
|
+
return value as T;
|
|
617
|
+
} catch (error) {
|
|
618
|
+
if (context.controller.signal.aborted || this.#now() >= context.deadline) {
|
|
619
|
+
if (!context.controller.signal.aborted) context.controller.abort(context.timeoutError);
|
|
620
|
+
throw context.timeoutError;
|
|
621
|
+
}
|
|
622
|
+
throw error;
|
|
623
|
+
} finally {
|
|
624
|
+
context.signal.removeEventListener("abort", onAbort);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
#assertRequestDeadline(context: DiscordRequestContext): void {
|
|
629
|
+
if (context.controller.signal.aborted) throw context.timeoutError;
|
|
630
|
+
if (context.signal.aborted) throw discordAbortError(context.signal);
|
|
631
|
+
if (this.#now() >= context.deadline) {
|
|
632
|
+
context.controller.abort(context.timeoutError);
|
|
633
|
+
throw context.timeoutError;
|
|
507
634
|
}
|
|
508
635
|
}
|
|
509
636
|
|
|
@@ -4,29 +4,17 @@
|
|
|
4
4
|
* Stock startup publishes a session's readiness immediately, so the running
|
|
5
5
|
* chat daemon surfaces the session and creates its own root before an operator
|
|
6
6
|
* could ever name an existing one. A session that opts in is *prepared*
|
|
7
|
-
* instead:
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* and the daemon adopts the bound root instead of replacing it.
|
|
7
|
+
* instead: readiness stays withheld while the provider applies its one root
|
|
8
|
+
* claim. The SessionRouter owns endpoint authority and activation; this module
|
|
9
|
+
* only proves that the provider mapping authorizes readiness publication.
|
|
11
10
|
*
|
|
12
11
|
* Nothing here mutates a mapping. The gate only reads the daemon-owned store to
|
|
13
|
-
* prove a binding exists
|
|
14
|
-
* host to publish the readiness it withheld.
|
|
12
|
+
* prove a binding exists for the exact session and endpoint generation.
|
|
15
13
|
*/
|
|
16
14
|
|
|
17
|
-
import type { SessionIndex } from "../broker/session-index";
|
|
18
|
-
import { SdkClient } from "../client/client";
|
|
19
|
-
import type { SdkSessionEndpoint, SdkSessionEndpointScope } from "../client/discovery";
|
|
20
15
|
import type { SessionActivationGate } from "../host";
|
|
21
|
-
import {
|
|
22
|
-
type ActivatedPreparedSession,
|
|
23
|
-
type PreparedSessionActivationClient,
|
|
24
|
-
requestPreparedSessionActivation,
|
|
25
|
-
SessionActivationError,
|
|
26
|
-
} from "../session-activation";
|
|
27
16
|
import type { ConversationStore } from "./conversation-store";
|
|
28
17
|
import type { SlackConversation } from "./slack-conversation";
|
|
29
|
-
import { resolveSessionBindingAuthority } from "./slack-thread-binding";
|
|
30
18
|
|
|
31
19
|
/** Explicit, session-scoped opt-in for withholding readiness until a root is bound. */
|
|
32
20
|
export const EXISTING_THREAD_BIND_ENV = "GJC_NOTIFY_BIND_EXISTING_THREAD";
|
|
@@ -72,84 +60,3 @@ export function createSlackBindingActivationGate(input: SlackBindingActivationIn
|
|
|
72
60
|
);
|
|
73
61
|
};
|
|
74
62
|
}
|
|
75
|
-
|
|
76
|
-
export type {
|
|
77
|
-
ActivatedPreparedSession,
|
|
78
|
-
PreparedSessionActivationClient,
|
|
79
|
-
SessionActivationErrorCode,
|
|
80
|
-
} from "../session-activation";
|
|
81
|
-
export { requestPreparedSessionActivation, SessionActivationError } from "../session-activation";
|
|
82
|
-
|
|
83
|
-
export interface PreparedSessionActivationInput {
|
|
84
|
-
sessionIndex: SessionIndex;
|
|
85
|
-
sessionId: string;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export interface PreparedSessionActivationDeps {
|
|
89
|
-
readEndpoint?: (
|
|
90
|
-
repo: string,
|
|
91
|
-
sessionId: string,
|
|
92
|
-
scope?: SdkSessionEndpointScope,
|
|
93
|
-
) => Promise<SdkSessionEndpoint | null>;
|
|
94
|
-
connect?: (endpoint: { url: string; token: string }) => Promise<PreparedSessionActivationClient>;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Ask a prepared session to publish the readiness it withheld.
|
|
99
|
-
*
|
|
100
|
-
* The same discovery authority the binding requires is resolved first, so an
|
|
101
|
-
* unindexed, terminated, or endpoint-rolled session is refused before any
|
|
102
|
-
* connection is opened. The request names the exact session and endpoint
|
|
103
|
-
* generation, and the answer is accepted only when it proves both, so a
|
|
104
|
-
* replacement session can never be activated in place of the requested one.
|
|
105
|
-
* Activation is idempotent: an exact retry answers `already` without a second
|
|
106
|
-
* readiness signal.
|
|
107
|
-
*/
|
|
108
|
-
export async function activatePreparedSession(
|
|
109
|
-
input: PreparedSessionActivationInput,
|
|
110
|
-
deps: PreparedSessionActivationDeps = {},
|
|
111
|
-
): Promise<ActivatedPreparedSession> {
|
|
112
|
-
const authority = await resolveSessionBindingAuthority({
|
|
113
|
-
sessionIndex: input.sessionIndex,
|
|
114
|
-
sessionId: input.sessionId,
|
|
115
|
-
...(deps.readEndpoint ? { readEndpoint: deps.readEndpoint } : {}),
|
|
116
|
-
});
|
|
117
|
-
if (!authority)
|
|
118
|
-
throw new SessionActivationError(
|
|
119
|
-
"session_not_live",
|
|
120
|
-
"Session activation requires an exact live session endpoint.",
|
|
121
|
-
);
|
|
122
|
-
// Deliberately not a second discovery read. The authority proof is bound to
|
|
123
|
-
// one endpoint file, verified by pid and mtime at one scope; re-resolving here
|
|
124
|
-
// could connect to a replacement process whose endpoint generation repeats,
|
|
125
|
-
// and the generation carried below could not tell the two apart.
|
|
126
|
-
const endpoint = authority.endpoint;
|
|
127
|
-
if (!endpoint.url || !endpoint.token)
|
|
128
|
-
throw new SessionActivationError(
|
|
129
|
-
"session_not_live",
|
|
130
|
-
"Session activation requires a readable session discovery endpoint.",
|
|
131
|
-
);
|
|
132
|
-
let client: PreparedSessionActivationClient;
|
|
133
|
-
try {
|
|
134
|
-
client = await (deps.connect ?? defaultActivationClient)({ url: endpoint.url, token: endpoint.token });
|
|
135
|
-
} catch {
|
|
136
|
-
// Nothing was ever sent, so no activation can have been applied.
|
|
137
|
-
throw new SessionActivationError("activation_unavailable", "The session endpoint could not be reached.");
|
|
138
|
-
}
|
|
139
|
-
try {
|
|
140
|
-
return await requestPreparedSessionActivation(client, input.sessionId, authority.endpointGeneration);
|
|
141
|
-
} finally {
|
|
142
|
-
await client.close().catch(() => undefined);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async function defaultActivationClient(endpoint: {
|
|
147
|
-
url: string;
|
|
148
|
-
token: string;
|
|
149
|
-
}): Promise<PreparedSessionActivationClient> {
|
|
150
|
-
const client = await SdkClient.connect(endpoint.url, endpoint.token, { reconnectAttempts: 0 });
|
|
151
|
-
return {
|
|
152
|
-
request: async frame => (await client.request(frame)) as Record<string, unknown>,
|
|
153
|
-
close: async () => await client.close(),
|
|
154
|
-
};
|
|
155
|
-
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure per-update inbound reaction transition ordering.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from the Telegram daemon so the serialization and terminal-state
|
|
5
|
+
* contract is testable without daemon/attachment/topic-lease infrastructure.
|
|
6
|
+
* The production router dispatches notification frames without awaiting prior
|
|
7
|
+
* callbacks, so an `accepted` handler can still be in flight when the
|
|
8
|
+
* `consumed` handler runs. Chaining every transition for one update through a
|
|
9
|
+
* single promise keeps effects ordered, and skipping nonterminal transitions
|
|
10
|
+
* after a terminal one makes the terminal state monotonic: a late queued
|
|
11
|
+
* marker can never overwrite an already-sent consumed marker or retraction.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** A single ordered Bot API reaction transition for one update id. */
|
|
15
|
+
export interface InboundReactionTransition {
|
|
16
|
+
/** Serialized in submission order per update id. */
|
|
17
|
+
readonly effect: () => Promise<void>;
|
|
18
|
+
/** Terminal transitions (consumed / retraction) close the update. */
|
|
19
|
+
readonly terminal: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Terminal tombstones are retained only for a bounded window of recent update
|
|
24
|
+
* ids. Telegram update ids are monotonically increasing per bot, so a stale
|
|
25
|
+
* `accepted` ack that could overwrite a terminal state always carries an id at
|
|
26
|
+
* or below the terminal one; ids far below the window are long-expired updates
|
|
27
|
+
* whose correction target no longer exists, so the daemon's own target lookup
|
|
28
|
+
* already ignores them.
|
|
29
|
+
*/
|
|
30
|
+
export const INBOUND_REACTION_TOMBSTONE_WINDOW = 512;
|
|
31
|
+
|
|
32
|
+
export class InboundReactionSequencer {
|
|
33
|
+
/** Update ids whose reaction reached a terminal (consumed/retracted) state. */
|
|
34
|
+
readonly #terminal = new Map<number, true>();
|
|
35
|
+
/** Per-update serialization chain, deleted once settled. */
|
|
36
|
+
readonly #chains = new Map<number, Promise<void>>();
|
|
37
|
+
|
|
38
|
+
/** True once a terminal transition completed for this update. */
|
|
39
|
+
isTerminal(updateId: number): boolean {
|
|
40
|
+
return this.#terminal.has(updateId);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Enqueue one transition. The returned promise settles when the transition
|
|
45
|
+
* has run (or was skipped because a terminal state already closed it).
|
|
46
|
+
*/
|
|
47
|
+
apply(updateId: number, transition: InboundReactionTransition): Promise<void> {
|
|
48
|
+
const run = async (): Promise<void> => {
|
|
49
|
+
if (this.#terminal.has(updateId)) return;
|
|
50
|
+
await transition.effect();
|
|
51
|
+
if (transition.terminal) {
|
|
52
|
+
this.#terminal.set(updateId, true);
|
|
53
|
+
this.#evictStaleTombstones(updateId);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const prior = this.#chains.get(updateId) ?? Promise.resolve();
|
|
57
|
+
const next = prior.then(run, run);
|
|
58
|
+
// The chain is retained only while unsettled work exists for the update;
|
|
59
|
+
// once settled it is deleted so the map cannot grow without bound. The
|
|
60
|
+
// stored tail never rejects (both arms handle) so an unawaited chain can
|
|
61
|
+
// never surface an unhandled rejection.
|
|
62
|
+
const settled = next.then(
|
|
63
|
+
() => this.#chains.delete(updateId),
|
|
64
|
+
() => this.#chains.delete(updateId),
|
|
65
|
+
);
|
|
66
|
+
this.#chains.set(
|
|
67
|
+
updateId,
|
|
68
|
+
settled.then(() => undefined),
|
|
69
|
+
);
|
|
70
|
+
return next;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** @internal Test-only: number of retained per-update chains. */
|
|
74
|
+
debugChainCount(): number {
|
|
75
|
+
return this.#chains.size;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** @internal Test-only: number of retained terminal tombstones. */
|
|
79
|
+
debugTombstoneCount(): number {
|
|
80
|
+
return this.#terminal.size;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Keep only recent terminal tombstones relative to the newest terminal id. */
|
|
84
|
+
#evictStaleTombstones(newestTerminalId: number): void {
|
|
85
|
+
// Distance-based, not count-based: any terminal id further than the
|
|
86
|
+
// retention window below the newest terminal id is evicted regardless of
|
|
87
|
+
// how many tombstones are currently retained, so the map stays bounded by
|
|
88
|
+
// the window while near-term tombstones always survive.
|
|
89
|
+
for (const updateId of this.#terminal.keys()) {
|
|
90
|
+
if (newestTerminalId - updateId >= INBOUND_REACTION_TOMBSTONE_WINDOW) this.#terminal.delete(updateId);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Body for setting an emoji reaction on an inbound Telegram message. */
|
|
96
|
+
export function inboundReactionSetPayload(
|
|
97
|
+
chatId: string,
|
|
98
|
+
messageId: number,
|
|
99
|
+
emoji: string,
|
|
100
|
+
): {
|
|
101
|
+
chat_id: string;
|
|
102
|
+
message_id: number;
|
|
103
|
+
reaction: Array<{ type: "emoji"; emoji: string }>;
|
|
104
|
+
} {
|
|
105
|
+
return { chat_id: chatId, message_id: messageId, reaction: [{ type: "emoji", emoji }] };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Body for retracting a reaction. The Bot API clears a bot reaction with the
|
|
110
|
+
* empty reaction list; an empty `emoji` string is not a valid reaction and is
|
|
111
|
+
* silently rejected, leaving the stale queued marker visible.
|
|
112
|
+
*/
|
|
113
|
+
export function inboundReactionRetractPayload(
|
|
114
|
+
chatId: string,
|
|
115
|
+
messageId: number,
|
|
116
|
+
): {
|
|
117
|
+
chat_id: string;
|
|
118
|
+
message_id: number;
|
|
119
|
+
reaction: [];
|
|
120
|
+
} {
|
|
121
|
+
return { chat_id: chatId, message_id: messageId, reaction: [] };
|
|
122
|
+
}
|