@phuetz/code-buddy 1.1.0 → 1.3.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/README.md +211 -163
- package/dist/agent/autonomous/agentic-coding-contract.d.ts +12 -12
- package/dist/agent/base-agent.d.ts +4 -0
- package/dist/agent/base-agent.js +6 -0
- package/dist/agent/codebuddy-agent.d.ts +1 -1
- package/dist/agent/codebuddy-agent.js +69 -14
- package/dist/agent/execution/agent-executor.js +122 -12
- package/dist/agent/execution/tool-dependency-graph.js +7 -0
- package/dist/agent/execution/tool-hooks.d.ts +6 -0
- package/dist/agent/execution/tool-hooks.js +13 -5
- package/dist/agent/execution/tool-selection-strategy.d.ts +11 -2
- package/dist/agent/execution/tool-selection-strategy.js +67 -10
- package/dist/agent/extended-thinking.d.ts +8 -0
- package/dist/agent/extended-thinking.js +27 -0
- package/dist/agent/facades/infrastructure-facade.d.ts +9 -2
- package/dist/agent/facades/infrastructure-facade.js +15 -6
- package/dist/agent/hermes-browser-backends.js +151 -11
- package/dist/agent/hermes-claw-migrate.d.ts +59 -0
- package/dist/agent/hermes-claw-migrate.js +427 -26
- package/dist/agent/hermes-parity-manifest.js +78 -71
- package/dist/agent/hermes-runtime-lifecycle.d.ts +67 -0
- package/dist/agent/hermes-runtime-lifecycle.js +468 -0
- package/dist/agent/middleware/index.d.ts +1 -0
- package/dist/agent/middleware/index.js +1 -0
- package/dist/agent/middleware/visual-validation-middleware.d.ts +17 -0
- package/dist/agent/middleware/visual-validation-middleware.js +67 -0
- package/dist/agent/model-benchmark.d.ts +77 -0
- package/dist/agent/model-benchmark.js +309 -0
- package/dist/agent/model-tier.d.ts +14 -0
- package/dist/agent/model-tier.js +71 -0
- package/dist/agent/multi-agent/agents/orchestrator-agent.js +17 -6
- package/dist/agent/multi-agent/multi-agent-system.js +3 -1
- package/dist/agent/multi-agent/session-fleet-bridge.d.ts +2 -0
- package/dist/agent/multi-agent/session-fleet-bridge.js +9 -1
- package/dist/agent/multi-agent/session-tools.js +22 -5
- package/dist/agent/reasoning/mcts.js +20 -6
- package/dist/agent/self-improvement/authored-artifact-gate.d.ts +18 -0
- package/dist/agent/self-improvement/authored-artifact-gate.js +42 -0
- package/dist/agent/self-improvement/authored-tool-runtime.d.ts +27 -0
- package/dist/agent/self-improvement/authored-tool-runtime.js +57 -0
- package/dist/agent/self-improvement/authored-tool-store.d.ts +24 -0
- package/dist/agent/self-improvement/authored-tool-store.js +57 -0
- package/dist/agent/self-improvement/llm-tool-proposer.d.ts +41 -0
- package/dist/agent/self-improvement/llm-tool-proposer.js +136 -0
- package/dist/agent/self-improvement/sandbox-scorer.d.ts +17 -0
- package/dist/agent/self-improvement/sandbox-scorer.js +43 -0
- package/dist/agent/self-improvement/self-knowledge.d.ts +8 -0
- package/dist/agent/self-improvement/self-knowledge.js +24 -0
- package/dist/agent/self-improvement/skill-benchmark.d.ts +9 -0
- package/dist/agent/self-improvement/skill-benchmark.js +22 -0
- package/dist/agent/self-improvement/skill-consolidator.d.ts +71 -0
- package/dist/agent/self-improvement/skill-consolidator.js +137 -0
- package/dist/agent/self-improvement/skill-engine.d.ts +42 -0
- package/dist/agent/self-improvement/skill-engine.js +87 -0
- package/dist/agent/self-improvement/skill-gate.d.ts +19 -0
- package/dist/agent/self-improvement/skill-gate.js +62 -0
- package/dist/agent/self-improvement/skill-mutator.d.ts +74 -0
- package/dist/agent/self-improvement/skill-mutator.js +223 -0
- package/dist/agent/self-improvement/skill-proposer.d.ts +40 -0
- package/dist/agent/self-improvement/skill-proposer.js +82 -0
- package/dist/agent/self-improvement/skill-types.d.ts +41 -0
- package/dist/agent/self-improvement/skill-types.js +13 -0
- package/dist/agent/self-improvement/tool-benchmark.d.ts +10 -0
- package/dist/agent/self-improvement/tool-benchmark.js +37 -0
- package/dist/agent/self-improvement/tool-engine.d.ts +54 -0
- package/dist/agent/self-improvement/tool-engine.js +101 -0
- package/dist/agent/self-improvement/tool-gate.d.ts +20 -0
- package/dist/agent/self-improvement/tool-gate.js +78 -0
- package/dist/agent/self-improvement/tool-proposer.d.ts +31 -0
- package/dist/agent/self-improvement/tool-proposer.js +34 -0
- package/dist/agent/self-improvement/tool-skill-mutator.d.ts +40 -0
- package/dist/agent/self-improvement/tool-skill-mutator.js +79 -0
- package/dist/agent/self-improvement/tool-types.d.ts +48 -0
- package/dist/agent/self-improvement/tool-types.js +9 -0
- package/dist/agent/self-improvement/types.d.ts +3 -1
- package/dist/agent/session-end-flush.d.ts +6 -1
- package/dist/agent/session-end-flush.js +20 -4
- package/dist/agent/streaming/streaming-handler.d.ts +7 -0
- package/dist/agent/streaming/streaming-handler.js +8 -1
- package/dist/agent/tool-executor.js +1 -0
- package/dist/agent/tool-handler.d.ts +5 -0
- package/dist/agent/tool-handler.js +133 -4
- package/dist/browser-automation/browser-operator-executor.js +15 -0
- package/dist/browser-automation/browser-use-runner.d.ts +96 -0
- package/dist/browser-automation/browser-use-runner.js +492 -0
- package/dist/browser-automation/camofox-runner.d.ts +107 -0
- package/dist/browser-automation/camofox-runner.js +287 -0
- package/dist/channels/dingtalk/index.js +3 -0
- package/dist/channels/discord/client.d.ts +9 -0
- package/dist/channels/discord/client.js +12 -0
- package/dist/channels/feishu/index.d.ts +167 -1
- package/dist/channels/feishu/index.js +432 -7
- package/dist/channels/gateway-lifecycle.d.ts +132 -0
- package/dist/channels/gateway-lifecycle.js +219 -0
- package/dist/channels/google-chat/index.d.ts +5 -1
- package/dist/channels/google-chat/index.js +5 -1
- package/dist/channels/imessage/index.d.ts +14 -0
- package/dist/channels/imessage/index.js +64 -17
- package/dist/channels/index.d.ts +4 -0
- package/dist/channels/index.js +4 -0
- package/dist/channels/irc/index.d.ts +73 -3
- package/dist/channels/irc/index.js +446 -11
- package/dist/channels/line/index.js +3 -0
- package/dist/channels/mattermost/index.d.ts +51 -4
- package/dist/channels/mattermost/index.js +303 -20
- package/dist/channels/nextcloud-talk/index.d.ts +89 -8
- package/dist/channels/nextcloud-talk/index.js +367 -16
- package/dist/channels/nostr/index.d.ts +121 -1
- package/dist/channels/nostr/index.js +396 -8
- package/dist/channels/ntfy/index.js +3 -0
- package/dist/channels/qq/index.js +3 -0
- package/dist/channels/slash-parity.d.ts +117 -0
- package/dist/channels/slash-parity.js +185 -0
- package/dist/channels/synology-chat/index.js +3 -0
- package/dist/channels/teams/index.d.ts +3 -0
- package/dist/channels/teams/index.js +3 -0
- package/dist/channels/telegram/client.d.ts +9 -0
- package/dist/channels/telegram/client.js +12 -0
- package/dist/channels/twilio-voice/index.js +3 -0
- package/dist/channels/webchat/index.d.ts +7 -1
- package/dist/channels/webchat/index.js +7 -1
- package/dist/channels/wecom/index.js +3 -0
- package/dist/channels/weixin/index.js +3 -0
- package/dist/channels/zalo/index.js +3 -0
- package/dist/cli/config-loader.js +1 -1
- package/dist/codebuddy/client.d.ts +30 -1
- package/dist/codebuddy/client.js +167 -20
- package/dist/codebuddy/providers/provider-chatgpt-responses.d.ts +5 -0
- package/dist/codebuddy/providers/provider-chatgpt-responses.js +7 -1
- package/dist/codebuddy/providers/provider-gemini-native.js +1 -1
- package/dist/codebuddy/providers/provider-openai-compat.d.ts +5 -0
- package/dist/codebuddy/providers/provider-openai-compat.js +82 -2
- package/dist/codebuddy/tool-definitions/computer-control-tools.js +32 -2
- package/dist/codebuddy/tool-definitions/core-tools.js +3 -3
- package/dist/codebuddy/tool-definitions/index.d.ts +2 -1
- package/dist/codebuddy/tool-definitions/index.js +2 -1
- package/dist/codebuddy/tool-definitions/multimodal-tools.d.ts +1 -0
- package/dist/codebuddy/tool-definitions/multimodal-tools.js +44 -1
- package/dist/codebuddy/tool-definitions/windows-tools.d.ts +2 -0
- package/dist/codebuddy/tool-definitions/windows-tools.js +34 -0
- package/dist/codebuddy/tools.d.ts +8 -1
- package/dist/codebuddy/tools.js +67 -24
- package/dist/commands/cli/hermes-commands.js +108 -0
- package/dist/commands/cli/improve-command.js +123 -0
- package/dist/commands/cli/native-engine-commands.js +102 -3
- package/dist/commands/cli/utility-commands.js +45 -0
- package/dist/commands/enhanced-command-handler.js +2 -2
- package/dist/commands/goal-cli.d.ts +30 -0
- package/dist/commands/goal-cli.js +210 -27
- package/dist/commands/handlers/goal-handler.d.ts +9 -2
- package/dist/commands/handlers/goal-handler.js +36 -9
- package/dist/commands/handlers/infra-handlers.js +36 -0
- package/dist/commands/handlers/memory-handlers.js +96 -1
- package/dist/commands/handlers/missing-handlers.d.ts +1 -1
- package/dist/commands/handlers/missing-handlers.js +26 -3
- package/dist/commands/headless-slash.d.ts +2 -0
- package/dist/commands/headless-slash.js +12 -0
- package/dist/commands/llm-provider-resolution.d.ts +5 -3
- package/dist/commands/llm-provider-resolution.js +87 -33
- package/dist/commands/ollama.d.ts +25 -0
- package/dist/commands/ollama.js +100 -0
- package/dist/commands/provider.d.ts +5 -0
- package/dist/commands/provider.js +106 -55
- package/dist/commands/skills-cli/index.js +123 -0
- package/dist/commands/slash/builtin-commands.js +1 -1
- package/dist/commands/spec-next.js +2 -1
- package/dist/commands/spec-plan.js +5 -16
- package/dist/commands/tunnel.d.ts +2 -0
- package/dist/commands/tunnel.js +48 -0
- package/dist/companion/percepts.js +11 -1
- package/dist/config/config-resolver.d.ts +2 -1
- package/dist/config/config-resolver.js +54 -41
- package/dist/config/constants.d.ts +28 -0
- package/dist/config/constants.js +7 -0
- package/dist/config/env-schema.js +756 -0
- package/dist/config/model-tools.js +4 -4
- package/dist/config/toml-config.d.ts +16 -0
- package/dist/config/toml-config.js +3 -0
- package/dist/context/bootstrap-loader.js +6 -23
- package/dist/context/context-manager-v2.js +1 -0
- package/dist/context/import-directive-parser.d.ts +4 -0
- package/dist/context/import-directive-parser.js +51 -6
- package/dist/context/instruction-excludes.d.ts +30 -1
- package/dist/context/instruction-excludes.js +71 -1
- package/dist/context/jit-context.d.ts +8 -10
- package/dist/context/jit-context.js +28 -106
- package/dist/context/project-context.d.ts +90 -0
- package/dist/context/project-context.js +295 -0
- package/dist/daemon/autonomous-daemon.d.ts +1 -1
- package/dist/daemon/autonomous-daemon.js +3 -3
- package/dist/daemon/autonomous-loop.d.ts +31 -1
- package/dist/daemon/autonomous-loop.js +91 -4
- package/dist/daemon/colab-goal.js +9 -1
- package/dist/daemon/cron-agent-bridge.d.ts +12 -3
- package/dist/daemon/cron-agent-bridge.js +25 -9
- package/dist/desktop/codebuddy-engine-adapter.d.ts +32 -0
- package/dist/desktop/codebuddy-engine-adapter.js +257 -80
- package/dist/desktop/engine-adapter.d.ts +14 -0
- package/dist/desktop-automation/automation-manager.js +16 -0
- package/dist/desktop-automation/omniparser-runner.d.ts +63 -0
- package/dist/desktop-automation/omniparser-runner.js +115 -0
- package/dist/desktop-automation/smart-snapshot.d.ts +11 -0
- package/dist/desktop-automation/smart-snapshot.js +72 -5
- package/dist/doctor/index.js +40 -23
- package/dist/events/types.d.ts +11 -0
- package/dist/fleet/colab-store.js +14 -2
- package/dist/fleet/peer-session-bridge.js +50 -12
- package/dist/fleet/peer-tool-bridge.js +14 -0
- package/dist/goals/goal-decomposer.d.ts +27 -0
- package/dist/goals/goal-decomposer.js +293 -0
- package/dist/goals/goal-judge-client.d.ts +15 -0
- package/dist/goals/goal-judge-client.js +45 -0
- package/dist/goals/goal-judge.d.ts +2 -0
- package/dist/goals/goal-judge.js +35 -6
- package/dist/goals/goal-loop.d.ts +14 -0
- package/dist/goals/goal-loop.js +47 -2
- package/dist/goals/goal-manager.d.ts +6 -0
- package/dist/goals/goal-manager.js +67 -14
- package/dist/goals/goal-state.d.ts +13 -0
- package/dist/goals/goal-state.js +83 -13
- package/dist/goals/goal-store.d.ts +3 -0
- package/dist/goals/goal-store.js +31 -15
- package/dist/harness/contract.d.ts +28 -28
- package/dist/hooks/user-hooks.js +17 -3
- package/dist/identity/identity-manager.js +3 -2
- package/dist/index.js +481 -26
- package/dist/input/text-to-speech.d.ts +2 -6
- package/dist/input/text-to-speech.js +2 -27
- package/dist/integrations/screenpipe/screenpipe-client.d.ts +10 -0
- package/dist/integrations/screenpipe/screenpipe-client.js +12 -2
- package/dist/integrations/tailscale.d.ts +13 -0
- package/dist/integrations/tailscale.js +87 -34
- package/dist/knowledge/workspace-indexer.js +53 -9
- package/dist/mcp/client.js +1 -0
- package/dist/mcp/mcp-desktop-tools.d.ts +23 -0
- package/dist/mcp/mcp-desktop-tools.js +158 -0
- package/dist/mcp/mcp-resources.js +2 -3
- package/dist/mcp/mcp-server.js +2 -0
- package/dist/memory/enhanced-memory.d.ts +10 -0
- package/dist/memory/enhanced-memory.js +33 -2
- package/dist/memory/index.d.ts +3 -1
- package/dist/memory/index.js +4 -1
- package/dist/memory/memory-auto-proposer.d.ts +23 -0
- package/dist/memory/memory-auto-proposer.js +308 -0
- package/dist/memory/memory-candidate-queue.d.ts +92 -0
- package/dist/memory/memory-candidate-queue.js +261 -0
- package/dist/memory/persistent-memory.d.ts +45 -2
- package/dist/memory/persistent-memory.js +236 -40
- package/dist/ml/bayesian-qualifier.d.ts +1 -1
- package/dist/ml/bayesian-qualifier.js +35 -2
- package/dist/openclaw/gateway-bridge.js +5 -0
- package/dist/plugins/marketplace.d.ts +1 -0
- package/dist/plugins/marketplace.js +7 -0
- package/dist/prompts/execution-discipline.d.ts +14 -0
- package/dist/prompts/execution-discipline.js +29 -0
- package/dist/prompts/variation-injector.js +9 -2
- package/dist/protocols/acp/acp-agentic-runner.d.ts +7 -6
- package/dist/protocols/acp/acp-agentic-runner.js +115 -18
- package/dist/protocols/acp/acp-session-store.d.ts +23 -0
- package/dist/protocols/acp/acp-session-store.js +77 -0
- package/dist/protocols/acp/acp-stdio-server.d.ts +7 -0
- package/dist/protocols/acp/acp-stdio-server.js +71 -16
- package/dist/providers/active-llm-registry.d.ts +37 -0
- package/dist/providers/active-llm-registry.js +186 -0
- package/dist/providers/auxiliary-provider.d.ts +25 -0
- package/dist/providers/auxiliary-provider.js +192 -0
- package/dist/providers/codex-oauth.d.ts +1 -1
- package/dist/providers/codex-oauth.js +27 -4
- package/dist/providers/index.d.ts +3 -0
- package/dist/providers/index.js +4 -0
- package/dist/providers/provider-catalog.d.ts +70 -0
- package/dist/providers/provider-catalog.js +738 -0
- package/dist/providers/provider-fallback.d.ts +35 -0
- package/dist/providers/provider-fallback.js +171 -0
- package/dist/providers/xai-oauth.d.ts +128 -0
- package/dist/providers/xai-oauth.js +735 -0
- package/dist/scheduler/cron-scheduler.d.ts +15 -3
- package/dist/scheduler/cron-scheduler.js +53 -7
- package/dist/scheduler/script-runner.d.ts +2 -0
- package/dist/scheduler/script-runner.js +19 -4
- package/dist/scheduler/watchdog-handlers.js +7 -20
- package/dist/search/usearch-index.js +7 -2
- package/dist/security/tool-policy/tool-groups.js +2 -0
- package/dist/sensory/dreaming.d.ts +45 -0
- package/dist/sensory/dreaming.js +114 -0
- package/dist/sensory/heartbeat-scheduler.d.ts +38 -0
- package/dist/sensory/heartbeat-scheduler.js +72 -0
- package/dist/sensory/reactions.d.ts +24 -0
- package/dist/sensory/reactions.js +31 -0
- package/dist/sensory/screen-reaction.d.ts +23 -0
- package/dist/sensory/screen-reaction.js +59 -0
- package/dist/sensory/sensory-bridge.d.ts +23 -0
- package/dist/sensory/sensory-bridge.js +85 -0
- package/dist/sensory/sensory-memory.d.ts +20 -0
- package/dist/sensory/sensory-memory.js +39 -0
- package/dist/sensory/speech-reaction.d.ts +21 -0
- package/dist/sensory/speech-reaction.js +83 -0
- package/dist/sensory/vision-reaction.d.ts +31 -0
- package/dist/sensory/vision-reaction.js +74 -0
- package/dist/server/index.js +106 -2
- package/dist/server/routes/mobile.d.ts +12 -4
- package/dist/server/routes/mobile.js +116 -1
- package/dist/server/tls-config.d.ts +35 -0
- package/dist/server/tls-config.js +142 -0
- package/dist/server/tunnel-manager.d.ts +20 -0
- package/dist/server/tunnel-manager.js +58 -0
- package/dist/server/websocket/fleet-bridge.js +5 -0
- package/dist/services/prompt-builder.d.ts +11 -0
- package/dist/services/prompt-builder.js +124 -17
- package/dist/shared/engine-types.d.ts +15 -1
- package/dist/sidecar/sidecar-bridge.d.ts +1 -0
- package/dist/sidecar/sidecar-bridge.js +21 -10
- package/dist/skills/parser.js +3 -0
- package/dist/skills/skill-importer.d.ts +58 -0
- package/dist/skills/skill-importer.js +261 -0
- package/dist/skills/skill-sources.d.ts +20 -0
- package/dist/skills/skill-sources.js +102 -0
- package/dist/skills/types.d.ts +6 -0
- package/dist/spec/spec-store.js +8 -1
- package/dist/talk-mode/providers/audioreader-tts.d.ts +1 -1
- package/dist/talk-mode/providers/audioreader-tts.js +8 -8
- package/dist/templates/project-scaffolding.js +3 -2
- package/dist/themes/theme-schema.d.ts +10 -10
- package/dist/tools/application-profiles.js +38 -0
- package/dist/tools/bash/bash-tool.d.ts +1 -0
- package/dist/tools/bash/bash-tool.js +16 -2
- package/dist/tools/bash/command-validator.js +3 -0
- package/dist/tools/bash/rtk-rewrite.d.ts +16 -0
- package/dist/tools/bash/rtk-rewrite.js +100 -0
- package/dist/tools/bash/streaming-executor.js +14 -1
- package/dist/tools/computer-control-tool.d.ts +16 -1
- package/dist/tools/computer-control-tool.js +317 -5
- package/dist/tools/document-generator.d.ts +14 -0
- package/dist/tools/document-generator.js +79 -0
- package/dist/tools/execute-code-rpc-invoker.d.ts +26 -2
- package/dist/tools/execute-code-rpc-invoker.js +46 -5
- package/dist/tools/metadata.js +28 -0
- package/dist/tools/office-macro-tool.d.ts +10 -0
- package/dist/tools/office-macro-tool.js +93 -0
- package/dist/tools/register-tool-handler.d.ts +25 -0
- package/dist/tools/register-tool-handler.js +100 -0
- package/dist/tools/registry/index.d.ts +2 -1
- package/dist/tools/registry/index.js +2 -1
- package/dist/tools/registry/memory-tools.d.ts +20 -0
- package/dist/tools/registry/memory-tools.js +225 -3
- package/dist/tools/registry/multimodal-tools.js +2 -2
- package/dist/tools/registry/vision-tools.d.ts +33 -0
- package/dist/tools/registry/vision-tools.js +308 -6
- package/dist/tools/registry/windows-tools.d.ts +2 -0
- package/dist/tools/registry/windows-tools.js +47 -0
- package/dist/tools/registry.d.ts +6 -0
- package/dist/tools/registry.js +8 -0
- package/dist/tools/route-peer-tool.js +14 -0
- package/dist/tools/screenshot-tool.js +14 -2
- package/dist/tools/text-to-speech-tool.d.ts +1 -1
- package/dist/tools/text-to-speech-tool.js +2 -12
- package/dist/tools/tool-selector.js +3 -59
- package/dist/utils/config-validation/schema.d.ts +40 -7
- package/dist/utils/config-validation/schema.js +130 -1
- package/dist/utils/cost-tracker.js +21 -1
- package/dist/utils/disk-guard.d.ts +180 -0
- package/dist/utils/disk-guard.js +404 -0
- package/dist/utils/init-project.d.ts +7 -0
- package/dist/utils/init-project.js +37 -0
- package/dist/utils/interactive-setup.js +35 -2
- package/dist/utils/model-utils.js +11 -2
- package/dist/utils/output-sanitizer.js +11 -0
- package/dist/utils/provider-detector.d.ts +8 -7
- package/dist/utils/provider-detector.js +19 -77
- package/dist/utils/settings-manager.d.ts +19 -0
- package/dist/utils/token-display.d.ts +3 -3
- package/dist/utils/token-display.js +22 -4
- package/dist/wizard/onboarding.d.ts +39 -0
- package/dist/wizard/onboarding.js +433 -21
- package/dist/wizard/provider-onboarding.d.ts +8 -23
- package/dist/wizard/provider-onboarding.js +39 -158
- package/package.json +4 -2
- package/dist/plugins/provider-onboarding.d.ts +0 -23
- package/dist/plugins/provider-onboarding.js +0 -116
- package/dist/utils/kokoro-tts.d.ts +0 -8
- package/dist/utils/kokoro-tts.js +0 -67
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway Lifecycle Manager
|
|
3
|
+
*
|
|
4
|
+
* Unified lifecycle management (start/stop/restart/status) for the
|
|
5
|
+
* messaging gateway subsystem. Tracks which channel adapters are
|
|
6
|
+
* currently active and provides per-channel readiness information.
|
|
7
|
+
*/
|
|
8
|
+
import { EventEmitter } from 'events';
|
|
9
|
+
import { getChannelManager } from './core.js';
|
|
10
|
+
import { logger } from '../utils/logger.js';
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Gateway Lifecycle Manager
|
|
13
|
+
// ============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Manages the lifecycle of the messaging gateway and its channel adapters.
|
|
16
|
+
*
|
|
17
|
+
* Wraps the existing ChannelManager with explicit start/stop/restart/status
|
|
18
|
+
* semantics for individual channels and the entire gateway.
|
|
19
|
+
*/
|
|
20
|
+
export class GatewayLifecycleManager extends EventEmitter {
|
|
21
|
+
manager;
|
|
22
|
+
activeChannels = new Set();
|
|
23
|
+
channelErrors = new Map();
|
|
24
|
+
constructor(manager) {
|
|
25
|
+
super();
|
|
26
|
+
this.manager = manager ?? getChannelManager();
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get the underlying ChannelManager.
|
|
30
|
+
*/
|
|
31
|
+
getManager() {
|
|
32
|
+
return this.manager;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Start a single channel adapter by its channel type.
|
|
36
|
+
*
|
|
37
|
+
* The channel must already be registered with the ChannelManager.
|
|
38
|
+
* This calls connect() on the adapter and marks it as active.
|
|
39
|
+
*
|
|
40
|
+
* @param channelId - The channel type to start
|
|
41
|
+
* @throws Error if the channel is not registered
|
|
42
|
+
*/
|
|
43
|
+
async start(channelId) {
|
|
44
|
+
const channel = this.manager.getChannel(channelId);
|
|
45
|
+
if (!channel) {
|
|
46
|
+
throw new Error(`Channel '${channelId}' is not registered`);
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
await channel.connect();
|
|
50
|
+
this.activeChannels.add(channelId);
|
|
51
|
+
this.channelErrors.delete(channelId);
|
|
52
|
+
this.emit('channel:started', channelId);
|
|
53
|
+
logger.debug('Gateway: channel started', { channelId });
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
57
|
+
this.channelErrors.set(channelId, message);
|
|
58
|
+
this.emit('channel:error', channelId, err instanceof Error ? err : new Error(message));
|
|
59
|
+
throw err;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Stop a single channel adapter by its channel type.
|
|
64
|
+
*
|
|
65
|
+
* Calls disconnect() on the adapter and removes it from the active set.
|
|
66
|
+
*
|
|
67
|
+
* @param channelId - The channel type to stop
|
|
68
|
+
* @throws Error if the channel is not registered
|
|
69
|
+
*/
|
|
70
|
+
async stop(channelId) {
|
|
71
|
+
const channel = this.manager.getChannel(channelId);
|
|
72
|
+
if (!channel) {
|
|
73
|
+
throw new Error(`Channel '${channelId}' is not registered`);
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
await channel.disconnect();
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
logger.debug('Gateway: error during channel disconnect', {
|
|
80
|
+
channelId,
|
|
81
|
+
error: err instanceof Error ? err.message : String(err),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
this.activeChannels.delete(channelId);
|
|
85
|
+
this.channelErrors.delete(channelId);
|
|
86
|
+
this.emit('channel:stopped', channelId);
|
|
87
|
+
logger.debug('Gateway: channel stopped', { channelId });
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Restart a single channel adapter (stop + start).
|
|
91
|
+
*
|
|
92
|
+
* @param channelId - The channel type to restart
|
|
93
|
+
*/
|
|
94
|
+
async restart(channelId) {
|
|
95
|
+
if (this.activeChannels.has(channelId)) {
|
|
96
|
+
await this.stop(channelId);
|
|
97
|
+
}
|
|
98
|
+
await this.start(channelId);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Start all registered channel adapters.
|
|
102
|
+
*/
|
|
103
|
+
async startAll() {
|
|
104
|
+
const channels = this.manager.getAllChannels();
|
|
105
|
+
const errors = [];
|
|
106
|
+
for (const channel of channels) {
|
|
107
|
+
try {
|
|
108
|
+
await this.start(channel.type);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
errors.push({
|
|
112
|
+
channelId: channel.type,
|
|
113
|
+
error: err instanceof Error ? err.message : String(err),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
this.emit('gateway:started');
|
|
118
|
+
if (errors.length > 0) {
|
|
119
|
+
logger.debug('Gateway: some channels failed to start', { errors });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Stop all active channel adapters.
|
|
124
|
+
*/
|
|
125
|
+
async stopAll() {
|
|
126
|
+
const activeIds = [...this.activeChannels];
|
|
127
|
+
for (const channelId of activeIds) {
|
|
128
|
+
try {
|
|
129
|
+
await this.stop(channelId);
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
logger.debug('Gateway: error stopping channel', {
|
|
133
|
+
channelId,
|
|
134
|
+
error: err instanceof Error ? err.message : String(err),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
this.emit('gateway:stopped');
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get the full gateway status report.
|
|
142
|
+
*
|
|
143
|
+
* Aggregates per-channel readiness from the ChannelManager's status,
|
|
144
|
+
* the active set, and any recorded errors.
|
|
145
|
+
*/
|
|
146
|
+
status() {
|
|
147
|
+
const channels = this.manager.getAllChannels();
|
|
148
|
+
const channelStatuses = [];
|
|
149
|
+
let connectedCount = 0;
|
|
150
|
+
let errorCount = 0;
|
|
151
|
+
let disconnectedCount = 0;
|
|
152
|
+
for (const channel of channels) {
|
|
153
|
+
const s = channel.getStatus();
|
|
154
|
+
const errorMsg = this.channelErrors.get(channel.type) ?? s.error;
|
|
155
|
+
let readiness;
|
|
156
|
+
if (errorMsg) {
|
|
157
|
+
readiness = 'error';
|
|
158
|
+
errorCount++;
|
|
159
|
+
}
|
|
160
|
+
else if (s.connected) {
|
|
161
|
+
readiness = 'connected';
|
|
162
|
+
connectedCount++;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
readiness = 'disconnected';
|
|
166
|
+
disconnectedCount++;
|
|
167
|
+
}
|
|
168
|
+
channelStatuses.push({
|
|
169
|
+
channelId: channel.type,
|
|
170
|
+
readiness,
|
|
171
|
+
authenticated: s.authenticated,
|
|
172
|
+
lastActivity: s.lastActivity?.toISOString(),
|
|
173
|
+
error: errorMsg,
|
|
174
|
+
info: s.info,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
ok: errorCount === 0 && channels.length > 0,
|
|
179
|
+
generatedAt: new Date().toISOString(),
|
|
180
|
+
totalChannels: channels.length,
|
|
181
|
+
connectedCount,
|
|
182
|
+
errorCount,
|
|
183
|
+
disconnectedCount,
|
|
184
|
+
channels: channelStatuses,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Check whether a specific channel is currently active.
|
|
189
|
+
*/
|
|
190
|
+
isActive(channelId) {
|
|
191
|
+
return this.activeChannels.has(channelId);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Get the set of currently active channel IDs.
|
|
195
|
+
*/
|
|
196
|
+
getActiveChannels() {
|
|
197
|
+
return [...this.activeChannels];
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// ============================================================================
|
|
201
|
+
// Singleton
|
|
202
|
+
// ============================================================================
|
|
203
|
+
let lifecycleInstance = null;
|
|
204
|
+
/**
|
|
205
|
+
* Get the singleton GatewayLifecycleManager instance.
|
|
206
|
+
*/
|
|
207
|
+
export function getGatewayLifecycle() {
|
|
208
|
+
if (!lifecycleInstance) {
|
|
209
|
+
lifecycleInstance = new GatewayLifecycleManager();
|
|
210
|
+
}
|
|
211
|
+
return lifecycleInstance;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Reset the singleton (for testing).
|
|
215
|
+
*/
|
|
216
|
+
export function resetGatewayLifecycle() {
|
|
217
|
+
lifecycleInstance = null;
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=gateway-lifecycle.js.map
|
|
@@ -158,7 +158,11 @@ export declare class GoogleChatChannel extends BaseChannel {
|
|
|
158
158
|
private apiRequest;
|
|
159
159
|
/**
|
|
160
160
|
* Connect to Google Chat by validating the service account and
|
|
161
|
-
* verifying API access
|
|
161
|
+
* verifying API access.
|
|
162
|
+
*
|
|
163
|
+
* REST/webhook adapter — outbound via the Google Chat REST API, inbound via
|
|
164
|
+
* webhook (or Pub/Sub) callbacks; no persistent connection is held open
|
|
165
|
+
* here, so reconnection (ReconnectionManager) is N/A.
|
|
162
166
|
*/
|
|
163
167
|
connect(): Promise<void>;
|
|
164
168
|
/**
|
|
@@ -139,7 +139,11 @@ export class GoogleChatChannel extends BaseChannel {
|
|
|
139
139
|
// ==========================================================================
|
|
140
140
|
/**
|
|
141
141
|
* Connect to Google Chat by validating the service account and
|
|
142
|
-
* verifying API access
|
|
142
|
+
* verifying API access.
|
|
143
|
+
*
|
|
144
|
+
* REST/webhook adapter — outbound via the Google Chat REST API, inbound via
|
|
145
|
+
* webhook (or Pub/Sub) callbacks; no persistent connection is held open
|
|
146
|
+
* here, so reconnection (ReconnectionManager) is N/A.
|
|
143
147
|
*/
|
|
144
148
|
async connect() {
|
|
145
149
|
try {
|
|
@@ -51,6 +51,8 @@ export declare class IMessageAdapter extends EventEmitter {
|
|
|
51
51
|
private pollingTimer;
|
|
52
52
|
private lastMessageTimestamp;
|
|
53
53
|
private retryCount;
|
|
54
|
+
private reconnecting;
|
|
55
|
+
private reconnectionManager;
|
|
54
56
|
constructor(config: IMessageConfig);
|
|
55
57
|
start(): Promise<void>;
|
|
56
58
|
stop(): Promise<void>;
|
|
@@ -70,6 +72,18 @@ export declare class IMessageAdapter extends EventEmitter {
|
|
|
70
72
|
private startPolling;
|
|
71
73
|
private stopPolling;
|
|
72
74
|
private pollMessages;
|
|
75
|
+
/**
|
|
76
|
+
* Recover a dropped BlueBubbles connection via the shared
|
|
77
|
+
* ReconnectionManager (exponential backoff + jitter + max-retry
|
|
78
|
+
* exhaustion). Replaces the previous hand-rolled backoff loop so we
|
|
79
|
+
* never run two competing backoffs at once.
|
|
80
|
+
*
|
|
81
|
+
* `scheduleReconnect` is single-shot — one call schedules exactly one
|
|
82
|
+
* attempt — so on a failed health check we must re-drive it (the way
|
|
83
|
+
* discord's repeated WS `close` events and telegram's repeating poll loop
|
|
84
|
+
* naturally do) until the connection recovers or the manager exhausts its
|
|
85
|
+
* retries and emits `exhausted`.
|
|
86
|
+
*/
|
|
73
87
|
private reconnect;
|
|
74
88
|
private getBaseUrl;
|
|
75
89
|
private apiRequest;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { EventEmitter } from 'events';
|
|
9
9
|
import { logger } from '../../utils/logger.js';
|
|
10
10
|
import { BaseChannel } from '../core.js';
|
|
11
|
+
import { ReconnectionManager } from '../reconnection-manager.js';
|
|
11
12
|
// ============================================================================
|
|
12
13
|
// IMessageAdapter
|
|
13
14
|
// ============================================================================
|
|
@@ -17,6 +18,8 @@ export class IMessageAdapter extends EventEmitter {
|
|
|
17
18
|
pollingTimer = null;
|
|
18
19
|
lastMessageTimestamp = 0;
|
|
19
20
|
retryCount = 0;
|
|
21
|
+
reconnecting = false;
|
|
22
|
+
reconnectionManager;
|
|
20
23
|
constructor(config) {
|
|
21
24
|
super();
|
|
22
25
|
this.config = {
|
|
@@ -28,6 +31,13 @@ export class IMessageAdapter extends EventEmitter {
|
|
|
28
31
|
if (this.config.port === undefined) {
|
|
29
32
|
this.config.port = 1234;
|
|
30
33
|
}
|
|
34
|
+
// Persistent long-poll connection to BlueBubbles — drops are recovered
|
|
35
|
+
// with shared exponential backoff (same idiom as discord/slack/telegram).
|
|
36
|
+
this.reconnectionManager = new ReconnectionManager('imessage', {
|
|
37
|
+
maxRetries: this.config.maxRetries ?? 5,
|
|
38
|
+
initialDelayMs: this.config.retryDelay ?? 5000,
|
|
39
|
+
maxDelayMs: 60000,
|
|
40
|
+
});
|
|
31
41
|
}
|
|
32
42
|
// ============================================================================
|
|
33
43
|
// Lifecycle
|
|
@@ -42,6 +52,11 @@ export class IMessageAdapter extends EventEmitter {
|
|
|
42
52
|
});
|
|
43
53
|
// Verify connectivity
|
|
44
54
|
await this.healthCheck();
|
|
55
|
+
// Connectivity is confirmed for this session — reset the shared backoff
|
|
56
|
+
// state so a fresh start() never inherits a pre-exhausted retryCount from
|
|
57
|
+
// a previous outage episode (onConnected() resets retryCount + active +
|
|
58
|
+
// any pending timer; cancel() alone does not).
|
|
59
|
+
this.reconnectionManager.onConnected();
|
|
45
60
|
this.running = true;
|
|
46
61
|
this.lastMessageTimestamp = Date.now();
|
|
47
62
|
this.retryCount = 0;
|
|
@@ -54,6 +69,9 @@ export class IMessageAdapter extends EventEmitter {
|
|
|
54
69
|
if (!this.running) {
|
|
55
70
|
throw new Error('IMessageAdapter is not running');
|
|
56
71
|
}
|
|
72
|
+
// Cancel any pending reconnect so it can't fire after an explicit stop.
|
|
73
|
+
this.reconnectionManager.cancel();
|
|
74
|
+
this.reconnecting = false;
|
|
57
75
|
this.stopPolling();
|
|
58
76
|
this.running = false;
|
|
59
77
|
this.emit('disconnected');
|
|
@@ -147,6 +165,9 @@ export class IMessageAdapter extends EventEmitter {
|
|
|
147
165
|
try {
|
|
148
166
|
await this.pollMessages();
|
|
149
167
|
this.retryCount = 0;
|
|
168
|
+
// A successful poll means the connection is healthy again — reset
|
|
169
|
+
// the shared backoff state so a future drop starts from delay 0.
|
|
170
|
+
this.reconnectionManager.onConnected();
|
|
150
171
|
}
|
|
151
172
|
catch (error) {
|
|
152
173
|
this.retryCount++;
|
|
@@ -155,7 +176,7 @@ export class IMessageAdapter extends EventEmitter {
|
|
|
155
176
|
if (this.retryCount >= (this.config.maxRetries || 5)) {
|
|
156
177
|
logger.error('IMessageAdapter: max retries exceeded, attempting reconnect');
|
|
157
178
|
this.emit('error', new Error('Polling failed after max retries'));
|
|
158
|
-
|
|
179
|
+
this.reconnect();
|
|
159
180
|
}
|
|
160
181
|
}
|
|
161
182
|
}, this.config.pollingInterval);
|
|
@@ -193,32 +214,58 @@ export class IMessageAdapter extends EventEmitter {
|
|
|
193
214
|
// ============================================================================
|
|
194
215
|
// Reconnection
|
|
195
216
|
// ============================================================================
|
|
196
|
-
|
|
217
|
+
/**
|
|
218
|
+
* Recover a dropped BlueBubbles connection via the shared
|
|
219
|
+
* ReconnectionManager (exponential backoff + jitter + max-retry
|
|
220
|
+
* exhaustion). Replaces the previous hand-rolled backoff loop so we
|
|
221
|
+
* never run two competing backoffs at once.
|
|
222
|
+
*
|
|
223
|
+
* `scheduleReconnect` is single-shot — one call schedules exactly one
|
|
224
|
+
* attempt — so on a failed health check we must re-drive it (the way
|
|
225
|
+
* discord's repeated WS `close` events and telegram's repeating poll loop
|
|
226
|
+
* naturally do) until the connection recovers or the manager exhausts its
|
|
227
|
+
* retries and emits `exhausted`.
|
|
228
|
+
*/
|
|
229
|
+
reconnect() {
|
|
230
|
+
// Pause polling while we attempt to re-establish the connection; the
|
|
231
|
+
// backoff timer in the manager now owns the retry cadence.
|
|
197
232
|
this.stopPolling();
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
233
|
+
// Surface permanent failure once the manager exhausts its retries.
|
|
234
|
+
if (this.reconnectionManager.listenerCount('exhausted') === 0) {
|
|
235
|
+
this.reconnectionManager.on('exhausted', () => {
|
|
236
|
+
this.reconnecting = false;
|
|
237
|
+
this.running = false;
|
|
238
|
+
this.emit('disconnected', new Error('Reconnection failed after all retries'));
|
|
239
|
+
logger.error('IMessageAdapter: reconnection failed permanently');
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
this.reconnecting = true;
|
|
243
|
+
this.reconnectionManager.scheduleReconnect(async () => {
|
|
201
244
|
try {
|
|
202
|
-
logger.info(`IMessageAdapter: reconnection attempt ${attempt}/${maxRetries}`);
|
|
203
245
|
await this.healthCheck();
|
|
204
|
-
//
|
|
246
|
+
// Health check passed — resume the poll loop and reset counters.
|
|
247
|
+
this.reconnecting = false;
|
|
205
248
|
this.retryCount = 0;
|
|
206
249
|
this.startPolling();
|
|
250
|
+
this.reconnectionManager.onConnected();
|
|
207
251
|
this.emit('reconnected');
|
|
208
252
|
logger.info('IMessageAdapter: reconnected successfully');
|
|
209
|
-
return;
|
|
210
253
|
}
|
|
211
|
-
catch {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
254
|
+
catch (error) {
|
|
255
|
+
// This attempt failed. Defer re-driving the manager until after it
|
|
256
|
+
// clears its internal `active` flag (which it does in its own
|
|
257
|
+
// `finally`, once this closure settles), so the next attempt is
|
|
258
|
+
// actually scheduled instead of being dropped by the active-guard.
|
|
259
|
+
if (this.running) {
|
|
260
|
+
setTimeout(() => {
|
|
261
|
+
if (this.running && this.reconnecting) {
|
|
262
|
+
this.reconnect();
|
|
263
|
+
}
|
|
264
|
+
}, 0).unref?.();
|
|
216
265
|
}
|
|
266
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
217
267
|
}
|
|
218
|
-
}
|
|
219
|
-
this.running = false;
|
|
220
|
-
this.emit('disconnected', new Error('Reconnection failed after all retries'));
|
|
221
|
-
logger.error('IMessageAdapter: reconnection failed permanently');
|
|
268
|
+
});
|
|
222
269
|
}
|
|
223
270
|
// ============================================================================
|
|
224
271
|
// Internal Helpers
|
package/dist/channels/index.d.ts
CHANGED
|
@@ -48,3 +48,7 @@ export type { SynologyChatConfig, SynologyChatChannelConfig, SynologyChatMessage
|
|
|
48
48
|
export { NtfyAdapter, NtfyChannel } from './ntfy/index.js';
|
|
49
49
|
export type { NtfyConfig, NtfyChannelConfig, NtfyPublishOptions, NtfyPublishResult } from './ntfy/index.js';
|
|
50
50
|
export { TwitchAdapter, TlonAdapter, GmailWebhookAdapter, DocsSearchTool } from './niche-channels.js';
|
|
51
|
+
export { GatewayLifecycleManager, getGatewayLifecycle, resetGatewayLifecycle, } from './gateway-lifecycle.js';
|
|
52
|
+
export type { ChannelReadiness, GatewayChannelStatus, GatewayStatus, } from './gateway-lifecycle.js';
|
|
53
|
+
export { buildSlashParityManifest, buildPlatformParityReport, extractActualCommands, renderSlashParityManifest, EXPECTED_SLASH_COMMANDS, } from './slash-parity.js';
|
|
54
|
+
export type { SlashCommandSpec, SlashCommandParityEntry, PlatformSlashParityReport, SlashParityManifest, SlashCommandProvider, } from './slash-parity.js';
|
package/dist/channels/index.js
CHANGED
|
@@ -49,4 +49,8 @@ export { SynologyChatAdapter, SynologyChatChannel } from './synology-chat/index.
|
|
|
49
49
|
export { NtfyAdapter, NtfyChannel } from './ntfy/index.js';
|
|
50
50
|
// Niche Channels (Twitch, Tlon, Gmail)
|
|
51
51
|
export { TwitchAdapter, TlonAdapter, GmailWebhookAdapter, DocsSearchTool } from './niche-channels.js';
|
|
52
|
+
// Gateway Lifecycle
|
|
53
|
+
export { GatewayLifecycleManager, getGatewayLifecycle, resetGatewayLifecycle, } from './gateway-lifecycle.js';
|
|
54
|
+
// Slash-Command Parity
|
|
55
|
+
export { buildSlashParityManifest, buildPlatformParityReport, extractActualCommands, renderSlashParityManifest, EXPECTED_SLASH_COMMANDS, } from './slash-parity.js';
|
|
52
56
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* IRC Channel Adapter
|
|
3
3
|
*
|
|
4
|
-
* Connects to IRC servers for sending/receiving messages
|
|
5
|
-
*
|
|
4
|
+
* Connects to IRC servers for sending/receiving messages over a real,
|
|
5
|
+
* long-lived TCP (or TLS) socket implementing an RFC 1459/2812 subset.
|
|
6
|
+
* Supports multiple channels, password auth, TLS, and auto-reconnect with
|
|
7
|
+
* exponential backoff (shared ReconnectionManager idiom — same as
|
|
8
|
+
* imessage/discord/slack).
|
|
6
9
|
*/
|
|
10
|
+
import { EventEmitter } from 'events';
|
|
7
11
|
import { BaseChannel, ChannelConfig, DeliveryResult, OutboundMessage } from '../core.js';
|
|
8
12
|
export interface IRCConfig {
|
|
9
13
|
server: string;
|
|
@@ -15,6 +19,10 @@ export interface IRCConfig {
|
|
|
15
19
|
channels: string[];
|
|
16
20
|
useTLS?: boolean;
|
|
17
21
|
sasl?: boolean;
|
|
22
|
+
/** Milliseconds to wait for the 001 welcome reply before failing connect (default 15000) */
|
|
23
|
+
connectTimeoutMs?: number;
|
|
24
|
+
maxRetries?: number;
|
|
25
|
+
retryDelayMs?: number;
|
|
18
26
|
}
|
|
19
27
|
export interface IRCChannelConfig extends ChannelConfig {
|
|
20
28
|
server: string;
|
|
@@ -26,15 +34,76 @@ export interface IRCChannelConfig extends ChannelConfig {
|
|
|
26
34
|
channels: string[];
|
|
27
35
|
useTLS?: boolean;
|
|
28
36
|
sasl?: boolean;
|
|
37
|
+
connectTimeoutMs?: number;
|
|
38
|
+
maxRetries?: number;
|
|
39
|
+
retryDelayMs?: number;
|
|
29
40
|
}
|
|
30
|
-
|
|
41
|
+
/**
|
|
42
|
+
* A single parsed IRC protocol line.
|
|
43
|
+
*
|
|
44
|
+
* IRC lines are either prefixed (`:<prefix> <command> <params...>`) or
|
|
45
|
+
* unprefixed (`<command> <params...>`). The final parameter may be a
|
|
46
|
+
* "trailing" param introduced by ` :` which can contain spaces.
|
|
47
|
+
*/
|
|
48
|
+
interface IRCMessage {
|
|
49
|
+
prefix?: string;
|
|
50
|
+
command: string;
|
|
51
|
+
params: string[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Parse a raw IRC line (without the trailing CRLF) into prefix/command/params.
|
|
55
|
+
*
|
|
56
|
+
* Handles both prefixed and unprefixed lines — this distinction is
|
|
57
|
+
* load-bearing: the welcome reply `001 <nick> :Welcome` has NO prefix while
|
|
58
|
+
* `:nick!u@h PRIVMSG #cb :text` does. Treating tokens[0] as always-prefix (or
|
|
59
|
+
* never-prefix) misparses one of them.
|
|
60
|
+
*/
|
|
61
|
+
export declare function parseIRCLine(line: string): IRCMessage | null;
|
|
62
|
+
export declare class IRCAdapter extends EventEmitter {
|
|
31
63
|
private config;
|
|
32
64
|
private running;
|
|
33
65
|
private joinedChannels;
|
|
66
|
+
private socket;
|
|
67
|
+
private recvBuffer;
|
|
68
|
+
/** True while an intentional disconnect is in progress — suppresses reconnect. */
|
|
69
|
+
private closing;
|
|
70
|
+
/** True once a close/error for the current socket has been handled (de-dup). */
|
|
71
|
+
private closeHandled;
|
|
72
|
+
private reconnecting;
|
|
73
|
+
private reconnectionManager;
|
|
34
74
|
constructor(config: IRCConfig);
|
|
35
75
|
start(): Promise<void>;
|
|
36
76
|
stop(): Promise<void>;
|
|
37
77
|
isRunning(): boolean;
|
|
78
|
+
getConfig(): IRCConfig;
|
|
79
|
+
/**
|
|
80
|
+
* Open the socket, perform the registration handshake, and resolve once the
|
|
81
|
+
* server sends the 001 welcome numeric. Used by both start() and the
|
|
82
|
+
* reconnect callback (so it deliberately omits the running-guard).
|
|
83
|
+
*/
|
|
84
|
+
private connectInternal;
|
|
85
|
+
/**
|
|
86
|
+
* Buffer incoming bytes and dispatch complete CRLF-terminated lines.
|
|
87
|
+
* `onWelcome` is invoked when the 001 numeric is seen (resolves connect()).
|
|
88
|
+
*/
|
|
89
|
+
private handleData;
|
|
90
|
+
private handleLine;
|
|
91
|
+
private handlePrivmsg;
|
|
92
|
+
/**
|
|
93
|
+
* Handle a socket 'close' or 'error' that was NOT triggered by an
|
|
94
|
+
* intentional disconnect. De-dupes the error→close pair (ECONNRESET fires
|
|
95
|
+
* 'error' then 'close') and drives a single reconnect via the shared
|
|
96
|
+
* ReconnectionManager.
|
|
97
|
+
*/
|
|
98
|
+
private handleSocketClosed;
|
|
99
|
+
/**
|
|
100
|
+
* Recover a dropped connection via the shared ReconnectionManager
|
|
101
|
+
* (exponential backoff + jitter + exhaustion). `scheduleReconnect` is
|
|
102
|
+
* single-shot, so a failed attempt re-drives it (deferred past the manager's
|
|
103
|
+
* internal active-guard) until recovery or exhaustion.
|
|
104
|
+
*/
|
|
105
|
+
private reconnect;
|
|
106
|
+
private write;
|
|
38
107
|
sendMessage(target: string, text: string): Promise<{
|
|
39
108
|
success: boolean;
|
|
40
109
|
}>;
|
|
@@ -57,3 +126,4 @@ export declare class IRCChannel extends BaseChannel {
|
|
|
57
126
|
disconnect(): Promise<void>;
|
|
58
127
|
send(message: OutboundMessage): Promise<DeliveryResult>;
|
|
59
128
|
}
|
|
129
|
+
export default IRCAdapter;
|