@xopcai/xopc 0.0.82 → 0.0.83
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +2 -3
- package/dist/extensions/feishu/src/outbound/media-load.js.map +1 -1
- package/dist/extensions/feishu/src/schema/config-schema.d.ts +6 -6
- package/dist/extensions/telegram/src/config-schema.d.ts +6 -6
- package/dist/extensions/telegram/src/plugin.d.ts +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/api/api.js +3 -3
- package/dist/extensions/weixin/src/auth/accounts.js +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/config-schema.d.ts +3 -3
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
- package/dist/gateway/static/root/assets/agents-CrpYTHJS.js +222 -0
- package/dist/gateway/static/root/assets/{apps-page-pJ27dsqn.js → apps-page-1mcKh5Rh.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-zd6QNKPx.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-D1KYmOmi.js → channels-status-swr-uRAuhiUo.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-api-Y2wfSJVI.js → cron-api-O2Q_ruV6.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-B97KU_RG.js → cron-page-By09AQD-.js} +1 -1
- package/dist/gateway/static/root/assets/{dist-CboA_Css.js → dist-BpQxde0t.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DN_zNmpo.js → extension-debug-page-CY27wj_p.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BUXtOzv5.js → extension-page-C-Ed5ZmP.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-C2dX4KCW.js → extension-settings-page-raLux7E7.js} +1 -1
- package/dist/gateway/static/root/assets/fetch-2iRFmd3n.js +3 -0
- package/dist/gateway/static/root/assets/{field-primitives-B9rOLqdm.js → field-primitives-fa_hiQcX.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-DvfiRVrc.js → heartbeat-config-api-BVl5VHvL.js} +1 -1
- package/dist/gateway/static/root/assets/index-BuFldCsB.css +1 -0
- package/dist/gateway/static/root/assets/{index-DQuaMye9.js → index-Y-iqo-gL.js} +94 -85
- package/dist/gateway/static/root/assets/{logs-page-BQuBpHcc.js → logs-page-BdH2n7ZW.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-Vpchzdp-.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-2Yu-FASs.js → settings-form-section-Kk1yAGBl.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-KBm0u6Dz.js +3 -0
- package/dist/gateway/static/root/assets/skills-page-BjeXXaOn.js +2 -0
- package/dist/gateway/static/root/assets/{theme-store-DnwYutiX.js → theme-store-D01dJt95.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-D2Gn2qod.js → utils-DpTxN4AF.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-CwO8Cf01.js +1 -0
- package/dist/gateway/static/root/index.html +4 -4
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-instance-gateway.d.ts +50 -0
- package/dist/src/agent/agent-instance-gateway.js +1 -0
- package/dist/src/agent/agent-manager.d.ts +20 -14
- package/dist/src/agent/agent-manager.js +74 -186
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/background-review/coordinator.d.ts +61 -0
- package/dist/src/agent/background-review/coordinator.js +120 -0
- package/dist/src/agent/background-review/coordinator.js.map +1 -0
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
- package/dist/src/agent/child-agent-factory.d.ts +14 -0
- package/dist/src/agent/child-agent-factory.js +2 -8
- package/dist/src/agent/child-agent-factory.js.map +1 -1
- package/dist/src/agent/context/workspace-seed.js +3 -3
- package/dist/src/agent/embedded/index.d.ts +1 -2
- package/dist/src/agent/embedded/index.js +2 -3
- package/dist/src/agent/embedded/run-for-session.d.ts +2 -2
- package/dist/src/agent/embedded/run-for-session.js.map +1 -1
- package/dist/src/agent/embedded/runs.d.ts +32 -0
- package/dist/src/agent/embedded/runs.js +79 -19
- package/dist/src/agent/embedded/runs.js.map +1 -1
- package/dist/src/agent/embedded/session-manager-cache.d.ts +14 -0
- package/dist/src/agent/embedded/session-manager-cache.js +32 -11
- package/dist/src/agent/embedded/session-manager-cache.js.map +1 -1
- package/dist/src/agent/embedded/session-runner.d.ts +37 -7
- package/dist/src/agent/embedded/session-runner.js +184 -153
- package/dist/src/agent/embedded/session-runner.js.map +1 -1
- package/dist/src/agent/embedded/session-tool-result-guard.d.ts +57 -9
- package/dist/src/agent/embedded/session-tool-result-guard.js +159 -67
- package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
- package/dist/src/agent/goals/goal-run-store.js +4 -4
- package/dist/src/agent/goals/persistent-goal-service.d.ts +84 -0
- package/dist/src/agent/goals/persistent-goal-service.js +139 -0
- package/dist/src/agent/goals/persistent-goal-service.js.map +1 -0
- package/dist/src/agent/goals/post-turn.js +2 -2
- package/dist/src/agent/goals/state.d.ts +1 -1
- package/dist/src/agent/goals/state.js.map +1 -1
- package/dist/src/agent/image/load-image-media.js +1 -1
- package/dist/src/agent/inbound/inbound-loop.d.ts +77 -0
- package/dist/src/agent/inbound/inbound-loop.js +226 -0
- package/dist/src/agent/inbound/inbound-loop.js.map +1 -0
- package/dist/src/agent/inbound/turn-dispatcher.d.ts +80 -0
- package/dist/src/agent/inbound/turn-dispatcher.js +138 -0
- package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -0
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/ipc/inbox.js +2 -2
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/lifecycle/handlers/compaction.d.ts +1 -1
- package/dist/src/agent/lifecycle/handlers/compaction.js.map +1 -1
- package/dist/src/agent/lifecycle/manager.d.ts +1 -1
- package/dist/src/agent/lifecycle/manager.js.map +1 -1
- package/dist/src/agent/lifecycle/types.d.ts +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
- package/dist/src/agent/memory/dreaming/events.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
- package/dist/src/agent/memory/dreaming/preview.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.d.ts +12 -2
- package/dist/src/agent/memory/dreaming/utils.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.js.map +1 -1
- package/dist/src/agent/memory/index.js +3 -3
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/memory/prefetch-coordinator.d.ts +37 -0
- package/dist/src/agent/memory/prefetch-coordinator.js +45 -0
- package/dist/src/agent/memory/prefetch-coordinator.js.map +1 -0
- package/dist/src/agent/messaging/command-handler.d.ts +5 -1
- package/dist/src/agent/messaging/command-handler.js +24 -96
- package/dist/src/agent/messaging/command-handler.js.map +1 -1
- package/dist/src/agent/messaging/index.d.ts +1 -0
- package/dist/src/agent/messaging/index.js +2 -1
- package/dist/src/agent/messaging/message-router.d.ts +1 -1
- package/dist/src/agent/messaging/message-router.js.map +1 -1
- package/dist/src/agent/messaging/outbound-coordinator.d.ts +82 -0
- package/dist/src/agent/messaging/outbound-coordinator.js +123 -0
- package/dist/src/agent/messaging/outbound-coordinator.js.map +1 -0
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/orchestration/agent-event-handler.d.ts +36 -33
- package/dist/src/agent/orchestration/agent-event-handler.js +212 -174
- package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.d.ts +4 -4
- package/dist/src/agent/orchestration/agent-orchestrator.js +4 -8
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/orchestration/index.d.ts +1 -1
- package/dist/src/agent/orchestration/index.js +2 -2
- package/dist/src/agent/prompt/service-prompt-builder.js +4 -4
- package/dist/src/agent/reply/post-compaction-context.js +1 -1
- package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
- package/dist/src/agent/sandbox/path-policy.js +1 -1
- package/dist/src/agent/service/async-queue.d.ts +20 -0
- package/dist/src/agent/service/async-queue.js +53 -0
- package/dist/src/agent/service/async-queue.js.map +1 -0
- package/dist/src/agent/service/build-direct-message-content.d.ts +2 -2
- package/dist/src/agent/service/build-direct-message-content.js.map +1 -1
- package/dist/src/agent/service/direct-turn-helpers.d.ts +70 -0
- package/dist/src/agent/service/direct-turn-helpers.js +90 -0
- package/dist/src/agent/service/direct-turn-helpers.js.map +1 -0
- package/dist/src/agent/service/process-direct-one-shot.d.ts +3 -3
- package/dist/src/agent/service/process-direct-one-shot.js +17 -34
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.d.ts +2 -2
- package/dist/src/agent/service/process-direct-streaming.js +122 -168
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service/webchat-tts.d.ts +2 -2
- package/dist/src/agent/service/webchat-tts.js +1 -1
- package/dist/src/agent/service/webchat-tts.js.map +1 -1
- package/dist/src/agent/service.d.ts +62 -167
- package/dist/src/agent/service.js +177 -786
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/session/index.d.ts +4 -0
- package/dist/src/agent/session/index.js +5 -1
- package/dist/src/agent/session/session-config-service.d.ts +68 -0
- package/dist/src/agent/session/session-config-service.js +172 -0
- package/dist/src/agent/session/session-config-service.js.map +1 -0
- package/dist/src/agent/session/session-context.d.ts +27 -19
- package/dist/src/agent/session/session-context.js +39 -24
- package/dist/src/agent/session/session-context.js.map +1 -1
- package/dist/src/agent/session/session-hydrator.d.ts +42 -0
- package/dist/src/agent/session/session-hydrator.js +66 -0
- package/dist/src/agent/session/session-hydrator.js.map +1 -0
- package/dist/src/agent/session/session-inspector.d.ts +80 -0
- package/dist/src/agent/session/session-inspector.js +119 -0
- package/dist/src/agent/session/session-inspector.js.map +1 -0
- package/dist/src/agent/session/session-state-bag.d.ts +83 -0
- package/dist/src/agent/session/session-state-bag.js +192 -0
- package/dist/src/agent/session/session-state-bag.js.map +1 -0
- package/dist/src/agent/skills/config.js +1 -1
- package/dist/src/agent/skills/hub-hash.js +2 -2
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +2 -2
- package/dist/src/agent/skills/index.d.ts +0 -2
- package/dist/src/agent/skills/index.js +3 -5
- package/dist/src/agent/skills/index.js.map +1 -1
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/marketplace/adapters/clawhub/adapter.js +11 -6
- package/dist/src/agent/skills/marketplace/adapters/clawhub/adapter.js.map +1 -1
- package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js +35 -7
- package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js.map +1 -1
- package/dist/src/agent/skills/scanner.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +2 -2
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +7 -0
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js +37 -0
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js.map +1 -1
- package/dist/src/agent/tools/delegate-tool.d.ts +7 -0
- package/dist/src/agent/tools/delegate-tool.js +2 -1
- package/dist/src/agent/tools/delegate-tool.js.map +1 -1
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/executor.d.ts +34 -15
- package/dist/src/agent/tools/executor.js +44 -79
- package/dist/src/agent/tools/executor.js.map +1 -1
- package/dist/src/agent/tools/factory.d.ts +6 -0
- package/dist/src/agent/tools/factory.js +63 -4
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +1 -1
- package/dist/src/agent/tools/send-media.js +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/skills-tools.js +1 -1
- package/dist/src/agent/tools/tts-tool.js +1 -1
- package/dist/src/agent/tools/write.js +1 -1
- package/dist/src/agent/workspace-runtime/registry.d.ts +48 -0
- package/dist/src/agent/workspace-runtime/registry.js +59 -0
- package/dist/src/agent/workspace-runtime/registry.js.map +1 -0
- package/dist/src/auth/credentials.js +3 -3
- package/dist/src/auth/profiles/store.js +1 -1
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/cdp-local-launcher.js +4 -3
- package/dist/src/browser/cdp-local-launcher.js.map +1 -1
- package/dist/src/browser/index.d.ts +1 -0
- package/dist/src/browser/index.js +2 -1
- package/dist/src/browser/manager.js +3 -2
- package/dist/src/browser/manager.js.map +1 -1
- package/dist/src/browser/providers/browser-ext-install.js +4 -4
- package/dist/src/browser/providers/browser-use.js +2 -1
- package/dist/src/browser/providers/browser-use.js.map +1 -1
- package/dist/src/browser/providers/browserbase.js +2 -1
- package/dist/src/browser/providers/browserbase.js.map +1 -1
- package/dist/src/browser/providers/cloakbrowser.js +7 -6
- package/dist/src/browser/providers/cloakbrowser.js.map +1 -1
- package/dist/src/browser/providers/playwright-doctor.d.ts +2 -0
- package/dist/src/browser/providers/playwright-doctor.js +7 -3
- package/dist/src/browser/providers/playwright-doctor.js.map +1 -1
- package/dist/src/browser/readiness.d.ts +33 -0
- package/dist/src/browser/readiness.js +138 -0
- package/dist/src/browser/readiness.js.map +1 -0
- package/dist/src/browser/stealth.js +2 -2
- package/dist/src/channels/attachments/inbound-persist.js +1 -1
- package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
- package/dist/src/channels/channel-domain.d.ts +1 -1
- package/dist/src/channels/config-helpers.d.ts +1 -1
- package/dist/src/channels/config-helpers.js.map +1 -1
- package/dist/src/channels/heartbeat-scheduler.d.ts +40 -0
- package/dist/src/channels/heartbeat-scheduler.js +94 -0
- package/dist/src/channels/heartbeat-scheduler.js.map +1 -0
- package/dist/src/channels/lifecycle-supervisor.d.ts +81 -0
- package/dist/src/channels/lifecycle-supervisor.js +263 -0
- package/dist/src/channels/lifecycle-supervisor.js.map +1 -0
- package/dist/src/channels/manager.d.ts +34 -68
- package/dist/src/channels/manager.js +107 -477
- package/dist/src/channels/manager.js.map +1 -1
- package/dist/src/channels/outbound/deliver.d.ts +1 -1
- package/dist/src/channels/outbound/deliver.js.map +1 -1
- package/dist/src/channels/outbound/persist-store.js +1 -1
- package/dist/src/channels/outbound-sender.d.ts +51 -0
- package/dist/src/channels/outbound-sender.js +125 -0
- package/dist/src/channels/outbound-sender.js.map +1 -0
- package/dist/src/channels/pairing/allow-from-file.js +1 -1
- package/dist/src/channels/pairing/pairing-service.d.ts +3 -10
- package/dist/src/channels/pairing/pairing-service.js.map +1 -1
- package/dist/src/channels/pairing/pairing-store.js +2 -2
- package/dist/src/channels/pairing/pairing-types.d.ts +15 -0
- package/dist/src/channels/pairing/pairing-types.js +1 -0
- package/dist/src/channels/plugin-registry.d.ts +22 -0
- package/dist/src/channels/plugin-registry.js +44 -0
- package/dist/src/channels/plugin-registry.js.map +1 -0
- package/dist/src/channels/plugin-types.d.ts +1 -1
- package/dist/src/channels/plugins/types.adapters.d.ts +2 -2
- package/dist/src/channels/security-helpers.d.ts +1 -1
- package/dist/src/channels/security-helpers.js.map +1 -1
- package/dist/src/channels/setup-wizard.d.ts +1 -1
- package/dist/src/chat-commands/builtins/config.js +2 -2
- package/dist/src/chat-commands/context.js +1 -1
- package/dist/src/cli/commands/agent/stream-renderer.js +1 -1
- package/dist/src/cli/commands/agent/stream-renderer.js.map +1 -1
- package/dist/src/cli/commands/agent.js +4 -4
- package/dist/src/cli/commands/agent.js.map +1 -1
- package/dist/src/cli/commands/browser-cli-helpers.js +2 -1
- package/dist/src/cli/commands/browser-cli-helpers.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +2 -2
- package/dist/src/cli/commands/extension-dev.js.map +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +2 -2
- package/dist/src/cli/commands/extension-marketplace.js.map +1 -1
- package/dist/src/cli/commands/extension-pack.js +1 -1
- package/dist/src/cli/commands/gateway/call.js +1 -1
- package/dist/src/cli/commands/gateway/call.js.map +1 -1
- package/dist/src/cli/commands/gateway/health.js +1 -1
- package/dist/src/cli/commands/gateway/health.js.map +1 -1
- package/dist/src/cli/commands/gateway/lifecycle-core.d.ts +31 -12
- package/dist/src/cli/commands/gateway/lifecycle-core.js +167 -116
- package/dist/src/cli/commands/gateway/lifecycle-core.js.map +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.d.ts +11 -0
- package/dist/src/cli/commands/gateway/lifecycle.js +102 -0
- package/dist/src/cli/commands/gateway/lifecycle.js.map +1 -0
- package/dist/src/cli/commands/gateway/logs.js +1 -1
- package/dist/src/cli/commands/gateway/logs.js.map +1 -1
- package/dist/src/cli/commands/gateway/probe.js +1 -1
- package/dist/src/cli/commands/gateway/probe.js.map +1 -1
- package/dist/src/cli/commands/gateway/restart-health.d.ts +12 -0
- package/dist/src/cli/commands/gateway/restart-health.js +45 -1
- package/dist/src/cli/commands/gateway/restart-health.js.map +1 -1
- package/dist/src/cli/commands/gateway/restart.js +3 -3
- package/dist/src/cli/commands/gateway/restart.js.map +1 -1
- package/dist/src/cli/commands/gateway/run-foreground.d.ts +0 -1
- package/dist/src/cli/commands/gateway/run-foreground.js +0 -35
- package/dist/src/cli/commands/gateway/run-foreground.js.map +1 -1
- package/dist/src/cli/commands/gateway/service.js +1 -1
- package/dist/src/cli/commands/gateway/service.js.map +1 -1
- package/dist/src/cli/commands/gateway/shared.d.ts +3 -0
- package/dist/src/cli/commands/gateway/shared.js +54 -0
- package/dist/src/cli/commands/gateway/shared.js.map +1 -0
- package/dist/src/cli/commands/gateway/status.js +1 -1
- package/dist/src/cli/commands/gateway/status.js.map +1 -1
- package/dist/src/cli/commands/gateway/stop.js +2 -2
- package/dist/src/cli/commands/gateway/stop.js.map +1 -1
- package/dist/src/cli/commands/gateway/token.js +1 -1
- package/dist/src/cli/commands/gateway/token.js.map +1 -1
- package/dist/src/cli/commands/gateway.js +5 -5
- package/dist/src/cli/commands/gateway.js.map +1 -1
- package/dist/src/cli/commands/image.js +2 -2
- package/dist/src/cli/commands/image.js.map +1 -1
- package/dist/src/cli/commands/init.js +4 -4
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/models.js.map +1 -1
- package/dist/src/cli/commands/onboard/gateway.d.ts +0 -8
- package/dist/src/cli/commands/onboard/gateway.js +48 -49
- package/dist/src/cli/commands/onboard/gateway.js.map +1 -1
- package/dist/src/cli/commands/onboard.js +9 -64
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/cli/commands/session/utils.js +1 -1
- package/dist/src/cli/commands/session/utils.js.map +1 -1
- package/dist/src/cli/commands/skills.js +1 -1
- package/dist/src/cli/commands/tailscale.js +1 -1
- package/dist/src/cli/commands/tailscale.js.map +1 -1
- package/dist/src/cli/context.d.ts +20 -0
- package/dist/src/cli/context.js +23 -0
- package/dist/src/cli/context.js.map +1 -0
- package/dist/src/cli/extension-cli-register.js +3 -3
- package/dist/src/cli/gateway-run-argv.js +1 -4
- package/dist/src/cli/gateway-run-argv.js.map +1 -1
- package/dist/src/cli/gateway-run-fast-path.js +1 -1
- package/dist/src/cli/gateway-run-fast-path.js.map +1 -1
- package/dist/src/cli/index.d.ts +1 -7
- package/dist/src/cli/index.js +4 -6
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +2 -2
- package/dist/src/config/commands.flags.d.ts +3 -0
- package/dist/src/config/commands.flags.js +11 -0
- package/dist/src/config/commands.flags.js.map +1 -0
- package/dist/src/config/index.d.ts +1 -0
- package/dist/src/config/index.js +6 -5
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/config/loader.js +2 -2
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/profile.js +2 -2
- package/dist/src/config/schema.d.ts +11 -4
- package/dist/src/config/schema.js +13 -12
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/workspace-path-helpers.d.ts +15 -0
- package/dist/src/config/workspace-path-helpers.js +14 -0
- package/dist/src/config/workspace-path-helpers.js.map +1 -0
- package/dist/src/cron/executor.js +4 -4
- package/dist/src/cron/executor.js.map +1 -1
- package/dist/src/cron/persistence.js +1 -1
- package/dist/src/cron/run-log-store.js +1 -1
- package/dist/src/daemon/index.d.ts +0 -1
- package/dist/src/daemon/index.js +1 -2
- package/dist/src/daemon/install-plan.js +3 -2
- package/dist/src/daemon/install-plan.js.map +1 -1
- package/dist/src/daemon/launchd.js +2 -2
- package/dist/src/daemon/systemd.js +2 -2
- package/dist/src/daemon/types.d.ts +0 -6
- package/dist/src/extensions/api.d.ts +1 -1
- package/dist/src/extensions/api.js +2 -2
- package/dist/src/extensions/api.js.map +1 -1
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +1 -1
- package/dist/src/extensions/extension-registry-impl.d.ts +51 -0
- package/dist/src/extensions/extension-registry-impl.js +117 -0
- package/dist/src/extensions/extension-registry-impl.js.map +1 -0
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/index.js +3 -2
- package/dist/src/extensions/loader.d.ts +3 -43
- package/dist/src/extensions/loader.js +3 -110
- package/dist/src/extensions/loader.js.map +1 -1
- package/dist/src/extensions/lockfile.js +2 -2
- package/dist/src/extensions/sdk/index.js +2 -1
- package/dist/src/extensions/sdk/index.js.map +1 -1
- package/dist/src/extensions/types/events.d.ts +7 -1
- package/dist/src/gateway/agents-admin.js +2 -2
- package/dist/src/gateway/file-path-classifier.js +2 -2
- package/dist/src/gateway/heartbeat/service.js +2 -2
- package/dist/src/gateway/heartbeat/service.js.map +1 -1
- package/dist/src/gateway/hono/app.js +5 -53
- package/dist/src/gateway/hono/app.js.map +1 -1
- package/dist/src/gateway/hono/lib/extension-store.js +1 -1
- package/dist/src/gateway/hono/lib/static-ui.js +2 -2
- package/dist/src/gateway/hono/middleware/auth.d.ts +5 -14
- package/dist/src/gateway/hono/middleware/auth.js +89 -126
- package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
- package/dist/src/gateway/hono/middleware/logger.js +1 -1
- package/dist/src/gateway/hono/middleware/logger.js.map +1 -1
- package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +14 -0
- package/dist/src/gateway/hono/middleware/strict-rate-limit.js +62 -0
- package/dist/src/gateway/hono/middleware/strict-rate-limit.js.map +1 -0
- package/dist/src/gateway/hono/oauth.js +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +4 -4
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js.map +1 -1
- package/dist/src/gateway/hono/routes/browser.d.ts +20 -0
- package/dist/src/gateway/hono/routes/browser.js +626 -0
- package/dist/src/gateway/hono/routes/browser.js.map +1 -0
- package/dist/src/gateway/hono/routes/commands-skills.js +13 -13
- package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/agents.d.ts +18 -0
- package/dist/src/gateway/hono/routes/config-patch/agents.js +418 -0
- package/dist/src/gateway/hono/routes/config-patch/agents.js.map +1 -0
- package/dist/src/gateway/hono/routes/config-patch/channels.d.ts +12 -0
- package/dist/src/gateway/hono/routes/config-patch/channels.js +186 -0
- package/dist/src/gateway/hono/routes/config-patch/channels.js.map +1 -0
- package/dist/src/gateway/hono/routes/config-patch/gateway.d.ts +18 -0
- package/dist/src/gateway/hono/routes/config-patch/gateway.js +264 -0
- package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -0
- package/dist/src/gateway/hono/routes/config-patch/index.d.ts +9 -0
- package/dist/src/gateway/hono/routes/config-patch/index.js +6 -0
- package/dist/src/gateway/hono/routes/config-patch/misc.d.ts +23 -0
- package/dist/src/gateway/hono/routes/config-patch/misc.js +139 -0
- package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -0
- package/dist/src/gateway/hono/routes/config-patch/result.d.ts +18 -0
- package/dist/src/gateway/hono/routes/config-patch/result.js +13 -0
- package/dist/src/gateway/hono/routes/config-patch/result.js.map +1 -0
- package/dist/src/gateway/hono/routes/config.js +20 -1764
- package/dist/src/gateway/hono/routes/config.js.map +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +2 -3
- package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
- package/dist/src/gateway/hono/routes/host-fs.js +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +10 -5
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/mcp.js +1 -2
- package/dist/src/gateway/hono/routes/mcp.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +32 -32
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/shares.js +4 -4
- package/dist/src/gateway/hono/routes/shares.js.map +1 -1
- package/dist/src/gateway/hono/routes/tunnel.js +1 -1
- package/dist/src/gateway/hono/routes/tunnel.js.map +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +6 -7
- package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
- package/dist/src/gateway/hono/sse.js +2 -2
- package/dist/src/gateway/index.d.ts +1 -1
- package/dist/src/gateway/index.js +4 -2
- package/dist/src/gateway/lock.js +3 -3
- package/dist/src/gateway/rate-limit/auth-policy.d.ts +34 -0
- package/dist/src/gateway/rate-limit/auth-policy.js +49 -0
- package/dist/src/gateway/rate-limit/auth-policy.js.map +1 -0
- package/dist/src/gateway/rate-limit/buckets.d.ts +63 -0
- package/dist/src/gateway/rate-limit/buckets.js +143 -0
- package/dist/src/gateway/rate-limit/buckets.js.map +1 -0
- package/dist/src/gateway/rate-limit/env-flags.d.ts +13 -0
- package/dist/src/gateway/rate-limit/env-flags.js +16 -0
- package/dist/src/gateway/rate-limit/env-flags.js.map +1 -0
- package/dist/src/gateway/rate-limit/index.d.ts +3 -0
- package/dist/src/gateway/rate-limit/index.js +4 -0
- package/dist/src/gateway/run-loop.d.ts +1 -1
- package/dist/src/gateway/run-loop.js +24 -4
- package/dist/src/gateway/run-loop.js.map +1 -1
- package/dist/src/gateway/runtime-config.js +2 -1
- package/dist/src/gateway/runtime-config.js.map +1 -1
- package/dist/src/gateway/security/audit.js +2 -1
- package/dist/src/gateway/security/audit.js.map +1 -1
- package/dist/src/gateway/security/index.d.ts +0 -1
- package/dist/src/gateway/security/index.js +1 -2
- package/dist/src/gateway/security/loopback.d.ts +13 -0
- package/dist/src/gateway/security/loopback.js +45 -0
- package/dist/src/gateway/security/loopback.js.map +1 -0
- package/dist/src/gateway/service/agent-runner.d.ts +108 -0
- package/dist/src/gateway/service/agent-runner.js +184 -0
- package/dist/src/gateway/service/agent-runner.js.map +1 -0
- package/dist/src/gateway/service/config-coordinator.d.ts +119 -0
- package/dist/src/gateway/service/config-coordinator.js +351 -0
- package/dist/src/gateway/service/config-coordinator.js.map +1 -0
- package/dist/src/gateway/service/marketplace-service.d.ts +85 -0
- package/dist/src/gateway/service/marketplace-service.js +239 -0
- package/dist/src/gateway/service/marketplace-service.js.map +1 -0
- package/dist/src/gateway/service/run-gateway-agent.js +5 -5
- package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
- package/dist/src/gateway/service/sessions-api.d.ts +125 -0
- package/dist/src/gateway/service/sessions-api.js +135 -0
- package/dist/src/gateway/service/sessions-api.js.map +1 -0
- package/dist/src/gateway/service.d.ts +30 -360
- package/dist/src/gateway/service.js +121 -903
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/gateway/workspace-heartbeat-path.js +1 -2
- package/dist/src/gateway/workspace-heartbeat-path.js.map +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/gateway-process-argv.d.ts +4 -0
- package/dist/src/infra/gateway-process-argv.js +26 -0
- package/dist/src/infra/gateway-process-argv.js.map +1 -0
- package/dist/src/infra/gateway-processes.d.ts +5 -0
- package/dist/src/infra/gateway-processes.js +65 -0
- package/dist/src/infra/gateway-processes.js.map +1 -0
- package/dist/src/infra/rate-limit/failure-limiter.d.ts +50 -0
- package/dist/src/infra/rate-limit/failure-limiter.js +100 -0
- package/dist/src/infra/rate-limit/failure-limiter.js.map +1 -0
- package/dist/src/infra/rate-limit/index.d.ts +5 -0
- package/dist/src/infra/rate-limit/index.js +3 -0
- package/dist/src/infra/rate-limit/keyed-store.d.ts +34 -0
- package/dist/src/infra/rate-limit/keyed-store.js +44 -0
- package/dist/src/infra/rate-limit/keyed-store.js.map +1 -0
- package/dist/src/infra/rate-limit/rate-limiter.d.ts +39 -0
- package/dist/src/infra/rate-limit/rate-limiter.js +65 -0
- package/dist/src/infra/rate-limit/rate-limiter.js.map +1 -0
- package/dist/src/infra/restart.d.ts +21 -0
- package/dist/src/infra/restart.js +122 -0
- package/dist/src/infra/restart.js.map +1 -0
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-lock.js +3 -3
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +2 -2
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/mcp/channel-bridge.d.ts +0 -6
- package/dist/src/mcp/channel-bridge.js +1 -5
- package/dist/src/mcp/channel-bridge.js.map +1 -1
- package/dist/src/media-shared/http/ssrf-guard.js +1 -1
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/session/config-store.js +2 -2
- package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
- package/dist/src/session/parity/sessions-json-file-read.d.ts +2 -1
- package/dist/src/session/parity/sessions-json-file-read.js.map +1 -1
- package/dist/src/session/parity/sessions-json-file.js +1 -1
- package/dist/src/session/parity/transcript-file-lock.js +2 -2
- package/dist/src/session/parity/transcript-paths.js +1 -1
- package/dist/src/session/search-index-cache.js +1 -1
- package/dist/src/session/search-index.js +1 -1
- package/dist/src/session/session-title.js +1 -1
- package/dist/src/session/store.js +5 -5
- package/dist/src/share/share-rate-limit.d.ts +10 -2
- package/dist/src/share/share-rate-limit.js +33 -42
- package/dist/src/share/share-rate-limit.js.map +1 -1
- package/dist/src/share/share-store.js +3 -3
- package/dist/src/tui/backends/embedded-backend.js +16 -12
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/clipboard-image.js +2 -2
- package/dist/src/tui/extension-host/load-extensions.js +1 -1
- package/dist/src/tui/format-tui-hotkeys.js +1 -1
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/tui-keybindings-file.js +1 -1
- package/dist/src/tui/tui-scoped-models.js +1 -1
- package/dist/src/tui/tui-settings.js +1 -1
- package/dist/src/tui/tui-skills-autocomplete.js +1 -1
- package/dist/src/tui/tui.js +1 -2
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/tui/xopc-tui-keybindings.d.ts +0 -1
- package/dist/src/tui/xopc-tui-keybindings.js +1 -2
- package/dist/src/tui/xopc-tui-keybindings.js.map +1 -1
- package/dist/src/tunnel/frpc-binary.js +2 -2
- package/dist/src/tunnel/frpc-config.js +1 -1
- package/dist/src/tunnel/frpc-extract.js +1 -1
- package/dist/src/tunnel/pairing-rate-limit.d.ts +10 -2
- package/dist/src/tunnel/pairing-rate-limit.js +19 -15
- package/dist/src/tunnel/pairing-rate-limit.js.map +1 -1
- package/dist/src/tunnel/tunnel-rate-limit.d.ts +6 -3
- package/dist/src/tunnel/tunnel-rate-limit.js +11 -22
- package/dist/src/tunnel/tunnel-rate-limit.js.map +1 -1
- package/dist/src/tunnel/tunnel-state.js +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/log-store.js +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/utils/logger/stats.d.ts +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/dist/src/voice/tts/factory.js +1 -1
- package/dist/src/voice/tts/index.js +2 -2
- package/dist/src/voice/tts/merge-config.js +1 -1
- package/dist/src/voice/tts/providers/edge-speech.js +1 -1
- package/dist/src/voice/tts/service.js +1 -1
- package/dist/src/voice/tts/service.js.map +1 -1
- package/dist/src/voice/tts/speak-core.js +1 -1
- package/package.json +10 -5
- package/dist/gateway/static/root/assets/agents-Cqh1ts38.js +0 -222
- package/dist/gateway/static/root/assets/channels-settings-wTiWStg9.js +0 -1
- package/dist/gateway/static/root/assets/fetch-BAAh_kXG.js +0 -3
- package/dist/gateway/static/root/assets/index-C8yHX-AA.css +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BeiFm0Ms.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-RPAz_Wg_.js +0 -3
- package/dist/gateway/static/root/assets/skills-page-Wu4aNWDx.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-BxIGhhEL.js +0 -1
- package/dist/src/agent/embedded/session-raw-append-message.d.ts +0 -11
- package/dist/src/agent/embedded/session-raw-append-message.js +0 -15
- package/dist/src/agent/embedded/session-raw-append-message.js.map +0 -1
- package/dist/src/agent/embedded/session-tool-result-guard-wrapper.d.ts +0 -15
- package/dist/src/agent/embedded/session-tool-result-guard-wrapper.js +0 -24
- package/dist/src/agent/embedded/session-tool-result-guard-wrapper.js.map +0 -1
- package/dist/src/agent/embedded/session-tool-result-state.d.ts +0 -17
- package/dist/src/agent/embedded/session-tool-result-state.js +0 -26
- package/dist/src/agent/embedded/session-tool-result-state.js.map +0 -1
- package/dist/src/daemon/launchd-restart-handoff.d.ts +0 -25
- package/dist/src/daemon/launchd-restart-handoff.js +0 -132
- package/dist/src/daemon/launchd-restart-handoff.js.map +0 -1
- package/dist/src/gateway/auth-rate-limit.d.ts +0 -71
- package/dist/src/gateway/auth-rate-limit.js +0 -192
- package/dist/src/gateway/auth-rate-limit.js.map +0 -1
- package/dist/src/gateway/restart-handler.d.ts +0 -14
- package/dist/src/gateway/restart-handler.js +0 -64
- package/dist/src/gateway/restart-handler.js.map +0 -1
- package/dist/src/gateway/security/flood-guard.d.ts +0 -28
- package/dist/src/gateway/security/flood-guard.js +0 -42
- package/dist/src/gateway/security/flood-guard.js.map +0 -1
- package/dist/src/infra/rate-limit.d.ts +0 -38
- package/dist/src/infra/rate-limit.js +0 -60
- package/dist/src/infra/rate-limit.js.map +0 -1
- package/dist/src/infra/restart-intent.d.ts +0 -13
- package/dist/src/infra/restart-intent.js +0 -40
- package/dist/src/infra/restart-intent.js.map +0 -1
- package/dist/src/infra/restart-sentinel.d.ts +0 -23
- package/dist/src/infra/restart-sentinel.js +0 -75
- package/dist/src/infra/restart-sentinel.js.map +0 -1
- package/skills/creative/canvas-design/LICENSE.txt +0 -202
- package/skills/creative/canvas-design/SKILL-zh.md +0 -130
- package/skills/creative/canvas-design/SKILL.md +0 -130
- package/skills/creative/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
- package/skills/creative/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","names":[],"sources":["../../../src/channels/manager.ts"],"sourcesContent":["/**\n * Channel Manager - Channel plugin management based on ChannelPlugin interface\n */\n\nimport type { Config } from '../config/index.js';\nimport type { MessageBus } from '../infra/bus/index.js';\nimport type { InboundMessage, OutboundMessage } from './transport-types.js';\nimport type {\n ChannelPlugin,\n ChannelPluginInitOptions,\n ChannelPluginSessionModelHooks,\n ChannelPluginStartOptions,\n ChannelStreamHandle,\n} from './plugin-types.js';\n\nimport { createLogger } from '../utils/logger.js';\nimport { INTERNAL_OUTBOUND_DROP_CHANNEL } from './internal-outbound.js';\nimport { mergeTtsConfigFromAppConfig } from '../voice/tts/merge-config.js';\nimport { maybeApplyTtsToPayload } from '../voice/tts/payload.js';\nimport { deliverOutboundMessage } from './outbound/deliver.js';\nimport { OutboundPersistStore } from './outbound/persist-store.js';\nimport { syncChannelPluginsFromManager } from './plugins/registry.js';\nimport { CHANNEL_RESTART_POLICY, computeBackoff } from './restart-policy.js';\nimport { ChannelHealthMonitor, type ChannelHealthState } from './health-monitor.js';\n\nconst log = createLogger('ChannelManager');\n\nfunction asChannelConfig(raw: unknown): Record<string, unknown> | undefined {\n if (raw && typeof raw === 'object' && !Array.isArray(raw)) {\n return raw as Record<string, unknown>;\n }\n return undefined;\n}\n\n/** Hooks wired from AgentService for `message_sending` / `message_sent` on outbound delivery. */\nexport interface OutboundChannelHooks {\n runMessageSending: (\n to: string,\n content: string,\n channel: string,\n ) => Promise<{ send: boolean; content?: string; reason?: string }>;\n runMessageSent: (\n to: string,\n content: string,\n success: boolean,\n error: string | undefined,\n channel: string,\n ) => Promise<void>;\n}\n\n// ============================================\n// Manager Implementation\n// ============================================\n\nexport class ChannelManager {\n private plugins = new Map<string, ChannelPlugin>();\n /** Plugins that completed `init()` successfully (skipped channels are not listed). */\n private initializedPluginIds = new Set<string>();\n private bus: MessageBus;\n private config: Config;\n private initialized = false;\n private running = false;\n private restartAttempts = new Map<string, number>();\n /** When set, failed-start auto-restart is suppressed for that channel id. */\n private manuallyStopped = new Set<string>();\n private heartbeatTimers = new Map<string, ReturnType<typeof setInterval>>();\n private outboundHooks?: OutboundChannelHooks;\n private persistStore?: OutboundPersistStore;\n private _lastHeartbeatRestartAt = new Map<string, number>();\n private readonly healthMonitor = new ChannelHealthMonitor();\n private sessionModelHooks?: ChannelPluginSessionModelHooks;\n /** Plugins that skipped `start()` until `startDeferredConnects()` (see `ChannelMeta.deferConnectUntilAfterListen`). */\n private deferredConnectPending = new Set<string>();\n\n constructor(config: Config, bus: MessageBus) {\n this.bus = bus;\n this.config = config;\n }\n \n setOutboundHooks(hooks: OutboundChannelHooks): void {\n this.outboundHooks = hooks;\n }\n\n /** Call before `initialize()` so plugins can persist per-session model overrides (e.g. Telegram /models UI). */\n setSessionModelHooks(hooks: ChannelPluginSessionModelHooks | undefined): void {\n this.sessionModelHooks = hooks;\n }\n\n enableOutboundPersistence(agentDir: string): void {\n this.persistStore = new OutboundPersistStore(agentDir);\n }\n\n /**\n * Redeliver persisted outbound items (after channels are started). Best-effort; may duplicate if prior send succeeded but ack did not.\n */\n async replayPendingOutboundMessages(): Promise<void> {\n if (!this.persistStore) return;\n const pending = [...this.persistStore.peek()];\n for (const p of pending) {\n try {\n await this.send(p.message, { skipPersist: true });\n this.persistStore.ack(p.id);\n } catch (err) {\n log.error({ id: p.id, err }, 'Failed to replay outbound message');\n }\n }\n }\n\n registerPlugin(plugin: ChannelPlugin): void {\n if (this.plugins.has(plugin.id)) {\n log.warn({ channel: plugin.id }, 'Channel plugin already registered, overwriting');\n }\n this.plugins.set(plugin.id, plugin);\n syncChannelPluginsFromManager(this.getAllPlugins());\n log.debug({ channel: plugin.id }, 'Registered channel plugin');\n }\n \n getPlugin(id: string): ChannelPlugin | undefined {\n return this.plugins.get(id);\n }\n\n /**\n * Optional channel hook before AgentService consumes an inbound message (e.g. Feishu card actions).\n */\n async dispatchInboundMessageAction(msg: InboundMessage): Promise<void> {\n const plugin = this.plugins.get(msg.channel);\n const handle = plugin?.actions?.handleAction;\n if (!handle) {\n return;\n }\n\n const meta = msg.metadata as Record<string, unknown> | undefined;\n if (msg.channel !== 'feishu' || meta?.feishuEventType !== 'card.action.trigger') {\n return;\n }\n\n const cardAction = meta.cardAction as Record<string, unknown> | undefined;\n const actionTag =\n cardAction && typeof cardAction.tag === 'string' && cardAction.tag.trim()\n ? cardAction.tag.trim()\n : 'feishu.card_action';\n const cardCtx = meta.cardContext as Record<string, unknown> | undefined;\n const openMsg =\n cardCtx && typeof cardCtx.open_message_id === 'string' ? cardCtx.open_message_id.trim() : '';\n const fallbackMsgId = typeof meta.messageId === 'string' ? meta.messageId.trim() : '';\n const messageId = openMsg || fallbackMsgId;\n const accountId = typeof meta.accountId === 'string' && meta.accountId.trim() ? meta.accountId.trim() : 'default';\n\n try {\n await handle({\n action: actionTag,\n data: JSON.stringify({\n cardAction: meta.cardAction,\n cardContext: meta.cardContext,\n cardActionText: meta.cardActionText,\n }),\n messageId,\n senderId: msg.sender_id,\n chatId: msg.chat_id,\n accountId,\n metadata: {\n feishuEventType: meta.feishuEventType,\n raw: meta.raw,\n sessionKey: meta.sessionKey,\n userContent: msg.content,\n },\n });\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err, channel: msg.channel, accountId, em }, 'dispatchInboundMessageAction failed');\n }\n }\n \n getAllPlugins(): ChannelPlugin[] {\n return Array.from(this.plugins.values());\n }\n \n async initialize(): Promise<void> {\n if (this.initialized) {\n log.warn({ pluginCount: this.plugins.size }, 'initialize() called again; channels already initialized — skipping');\n return;\n }\n \n const initPromises: Promise<void>[] = [];\n \n for (const [id, plugin] of this.plugins) {\n const channelConfig = asChannelConfig(this.config.channels?.[id]);\n // Always init so `onConfigUpdated` runs on hot reload (e.g. Weixin turned off after QR-login\n // started monitors while the plugin was previously skipped here and had no bus/`initialized` id).\n const initPromise = this.initializePlugin(plugin, channelConfig ?? {});\n initPromises.push(initPromise);\n }\n \n await Promise.allSettled(initPromises);\n this.initialized = true;\n log.info('All channel plugins initialized');\n }\n \n /**\n * Builtin channels require `channels.<id>.enabled`. Extension-managed channels run unless explicitly disabled.\n */\n private shouldRunChannelPlugin(\n plugin: ChannelPlugin,\n channelConfig: Record<string, unknown> | undefined,\n ): boolean {\n if (plugin.extensionManagedConfig) {\n return channelConfig?.enabled !== false;\n }\n return !!channelConfig?.enabled;\n }\n\n private async initializePlugin(\n plugin: ChannelPlugin, \n channelConfig: Record<string, unknown>\n ): Promise<void> {\n try {\n const options: ChannelPluginInitOptions = {\n bus: this.bus,\n config: this.config,\n channelConfig,\n sessionModel: this.sessionModelHooks,\n };\n await plugin.init(options);\n this.initializedPluginIds.add(plugin.id);\n log.debug({ channel: plugin.id }, 'Channel plugin initialized');\n } catch (err) {\n log.error({ channel: plugin.id, err }, 'Failed to initialize channel plugin');\n }\n }\n \n /**\n * Channel ids that would run and declare `meta.deferConnectUntilAfterListen` (for logging / metrics).\n */\n listDeferConnectChannelIds(cfg: Config): string[] {\n const out: string[] = [];\n for (const [id, plugin] of this.plugins) {\n const channelConfig = asChannelConfig(cfg.channels?.[id]);\n if (!this.shouldRunChannelPlugin(plugin, channelConfig)) continue;\n if (plugin.meta.deferConnectUntilAfterListen === true) {\n out.push(id);\n }\n }\n return out;\n }\n\n /**\n * Phase 1: start every enabled channel except those in `deferConnectPluginIds` (they stay pending).\n */\n async start(options?: { deferConnectPluginIds?: ReadonlySet<string> }): Promise<void> {\n if (!this.initialized) {\n throw new Error('Channels not initialized');\n }\n\n if (this.running) {\n log.warn({ pluginCount: this.plugins.size }, 'start() called while channels already running — skipping');\n return;\n }\n\n const deferIds = options?.deferConnectPluginIds ?? new Set<string>();\n this.deferredConnectPending.clear();\n\n const startPromises: Promise<void>[] = [];\n\n for (const [id, plugin] of this.plugins) {\n const channelConfig = asChannelConfig(this.config.channels?.[id]);\n if (!this.shouldRunChannelPlugin(plugin, channelConfig)) continue;\n\n if (deferIds.has(id)) {\n this.deferredConnectPending.add(id);\n log.info({ channel: id }, 'Channel connect deferred until HTTP listen');\n continue;\n }\n\n const startPromise = this.startPlugin(plugin, {}).catch((err) => {\n log.error({ channel: id, err }, 'Failed to start channel plugin');\n });\n startPromises.push(startPromise);\n }\n\n await Promise.allSettled(startPromises);\n this.running = true;\n log.info(\n { deferred: [...this.deferredConnectPending] },\n this.deferredConnectPending.size > 0\n ? 'Channel plugins started (deferred connects pending)'\n : 'All channel plugins started',\n );\n }\n\n /** Phase 2: run `start()` for channels deferred at `start()`. No-op if none pending. */\n async startDeferredConnects(): Promise<void> {\n if (this.deferredConnectPending.size === 0) {\n return;\n }\n if (!this.running) {\n log.warn('startDeferredConnects called before channel phase-1 start; skipping');\n return;\n }\n const ids = [...this.deferredConnectPending];\n this.deferredConnectPending.clear();\n const startPromises: Promise<void>[] = [];\n for (const id of ids) {\n const plugin = this.plugins.get(id);\n if (!plugin) continue;\n const channelConfig = asChannelConfig(this.config.channels?.[id]);\n if (!this.shouldRunChannelPlugin(plugin, channelConfig)) continue;\n startPromises.push(\n this.startPlugin(plugin, {}).catch((err) => {\n log.error({ channel: id, err }, 'Failed to start deferred channel plugin');\n }),\n );\n }\n await Promise.allSettled(startPromises);\n log.info({ channels: ids }, 'Deferred channel connects completed');\n }\n \n private async startPlugin(\n plugin: ChannelPlugin,\n opts: { preserveRestartAttempts?: boolean },\n ): Promise<void> {\n const options: ChannelPluginStartOptions = {};\n try {\n await plugin.start(options);\n if (!opts.preserveRestartAttempts) {\n this.restartAttempts.delete(plugin.id);\n }\n this._scheduleHeartbeat(plugin);\n log.debug({ channel: plugin.id }, 'Channel plugin started');\n } catch (err) {\n const attempt = (this.restartAttempts.get(plugin.id) ?? 0) + 1;\n this.restartAttempts.set(plugin.id, attempt);\n if (attempt <= CHANNEL_RESTART_POLICY.maxAttempts) {\n const delayMs = computeBackoff(CHANNEL_RESTART_POLICY, attempt);\n log.warn(\n { channel: plugin.id, attempt, delayMs, err },\n 'Channel failed to start, scheduling restart',\n );\n setTimeout(() => {\n if (this.manuallyStopped.has(plugin.id)) {\n log.debug({ channel: plugin.id }, 'Skipping scheduled restart (manual stop)');\n return;\n }\n void this.startPlugin(plugin, { preserveRestartAttempts: true }).catch((e) => {\n log.error({ channel: plugin.id, err: e }, 'Channel restart attempt failed');\n });\n }, delayMs);\n } else {\n log.error({ channel: plugin.id, err }, 'Channel exceeded max restart attempts');\n }\n }\n }\n \n async stop(): Promise<void> {\n if (!this.running) return;\n\n this.deferredConnectPending.clear();\n\n const stopPromises: Promise<void>[] = [];\n \n for (const id of this.initializedPluginIds) {\n const plugin = this.plugins.get(id);\n if (!plugin) continue;\n const stopPromise = this.stopPlugin(plugin).catch(err => {\n log.error({ channel: id, err }, 'Failed to stop channel plugin');\n });\n stopPromises.push(stopPromise);\n }\n \n await Promise.allSettled(stopPromises);\n this.running = false;\n log.info('All channel plugins stopped');\n }\n \n private async stopPlugin(plugin: ChannelPlugin): Promise<void> {\n this._clearHeartbeatTimers(plugin.id);\n await plugin.stop();\n log.info({ channel: plugin.id }, 'Channel plugin stopped');\n }\n\n private _clearHeartbeatTimers(pluginId: string): void {\n const prefix = `${pluginId}:`;\n for (const key of [...this.heartbeatTimers.keys()]) {\n if (key.startsWith(prefix)) {\n clearInterval(this.heartbeatTimers.get(key)!);\n this.heartbeatTimers.delete(key);\n }\n }\n }\n\n private _scheduleHeartbeat(plugin: ChannelPlugin): void {\n const hb = plugin.heartbeat;\n if (!hb) return;\n this._clearHeartbeatTimers(plugin.id);\n let accountIds: string[] = [];\n try {\n accountIds = plugin.config.listAccountIds(this.config);\n } catch (e) {\n log.warn({ channel: plugin.id, err: e }, 'Heartbeat: failed to list accounts');\n return;\n }\n for (const accountId of accountIds) {\n const key = `${plugin.id}:${accountId}`;\n const timer = setInterval(() => {\n void (async () => {\n try {\n const r = await hb.check({ cfg: this.config, accountId });\n this.healthMonitor.set(plugin.id, accountId, {\n healthy: r.healthy,\n lastCheckAt: Date.now(),\n detail:\n typeof r.details === 'string'\n ? r.details\n : r.details != null\n ? JSON.stringify(r.details)\n : undefined,\n });\n if (!r.healthy) {\n log.warn(\n { channel: plugin.id, accountId, detail: r.details },\n 'Channel heartbeat unhealthy',\n );\n const now = Date.now();\n const last = this._lastHeartbeatRestartAt.get(plugin.id) ?? 0;\n if (now - last < 60_000) {\n return;\n }\n this._lastHeartbeatRestartAt.set(plugin.id, now);\n void this._softRestartChannel(plugin.id);\n }\n } catch (err) {\n this.healthMonitor.set(plugin.id, accountId, {\n healthy: false,\n lastCheckAt: Date.now(),\n detail: err instanceof Error ? err.message : String(err),\n });\n log.error({ channel: plugin.id, accountId, err }, 'Channel heartbeat check failed');\n }\n })();\n }, hb.intervalMs);\n this.heartbeatTimers.set(key, timer);\n }\n }\n\n private async _softRestartChannel(channelId: string): Promise<void> {\n if (this.manuallyStopped.has(channelId)) return;\n const plugin = this.plugins.get(channelId);\n if (!plugin || !this.initializedPluginIds.has(channelId)) return;\n this._clearHeartbeatTimers(channelId);\n try {\n await plugin.stop();\n await this.startPlugin(plugin, {});\n } catch (err) {\n log.error({ channel: channelId, err }, 'Channel soft restart after heartbeat failed');\n }\n }\n\n private cloneOutbound(m: OutboundMessage): OutboundMessage {\n return structuredClone(m);\n }\n \n async send(msg: OutboundMessage, options?: { skipPersist?: boolean }): Promise<void> {\n log.debug({ type: msg.type, channel: msg.channel, chatId: msg.chat_id }, 'Received outbound message');\n\n let processedMsg = await this.applyTtsIfNeeded(msg);\n const queueId =\n !options?.skipPersist && this.persistStore ? this.persistStore.enqueue(this.cloneOutbound(processedMsg)) : null;\n\n try {\n if (this.outboundHooks) {\n const hookResult = await this.outboundHooks.runMessageSending(\n processedMsg.chat_id,\n processedMsg.content ?? '',\n processedMsg.channel,\n );\n if (!hookResult.send) {\n if (queueId) this.persistStore!.ack(queueId);\n return;\n }\n processedMsg = { ...processedMsg, content: hookResult.content ?? processedMsg.content };\n }\n\n if (processedMsg.channel === INTERNAL_OUTBOUND_DROP_CHANNEL) {\n log.debug(\n { chatId: processedMsg.chat_id },\n 'Outbound dropped (internal session — not a real channel)',\n );\n if (queueId) this.persistStore!.ack(queueId);\n return;\n }\n\n const plugin = this.plugins.get(processedMsg.channel);\n if (!plugin?.outbound) {\n log.error({ channel: processedMsg.channel }, 'Unknown channel or no outbound adapter');\n if (queueId) this.persistStore!.ack(queueId);\n return;\n }\n\n const result = await deliverOutboundMessage({\n cfg: this.config,\n plugin,\n processedMsg,\n });\n\n if (this.outboundHooks) {\n const err = result && !result.success ? result.error : undefined;\n await this.outboundHooks.runMessageSent(\n processedMsg.chat_id,\n processedMsg.content ?? '',\n result?.success ?? false,\n err,\n processedMsg.channel,\n );\n }\n\n if (!result) {\n if (queueId) this.persistStore!.ack(queueId);\n return;\n }\n\n if (result.success) {\n log.info(\n { channel: processedMsg.channel, chatId: processedMsg.chat_id, messageId: result.messageId },\n 'Message sent',\n );\n } else {\n log.error(\n { channel: processedMsg.channel, chatId: processedMsg.chat_id, error: result.error },\n 'Failed to send message',\n );\n }\n\n if (queueId) this.persistStore!.ack(queueId);\n } catch (err) {\n log.error(\n { channel: processedMsg.channel, chatId: processedMsg.chat_id, err },\n 'Outbound send threw',\n );\n if (!queueId) throw err;\n }\n }\n \n startStream(\n channel: string,\n chatId: string,\n accountId?: string,\n opts?: { threadId?: string; replyToMessageId?: string },\n ): ChannelStreamHandle | null {\n const plugin = this.plugins.get(channel);\n if (!plugin) {\n log.error({ channel }, 'Unknown channel');\n return null;\n }\n\n return (\n plugin.streaming?.startStream?.({\n chatId,\n accountId,\n threadId: opts?.threadId,\n replyToMessageId: opts?.replyToMessageId,\n }) ?? null\n );\n }\n \n async getChannelStatus(channel: string): Promise<Record<string, unknown>> {\n const plugin = this.plugins.get(channel);\n if (!plugin) return { error: 'Unknown channel' };\n \n if (!plugin.status?.buildChannelSummary) return { status: 'unknown' };\n\n try {\n const accountId = plugin.config.listAccountIds(this.config)[0] ?? 'default';\n const account = plugin.config.resolveAccount(this.config, accountId);\n \n const summary = await plugin.status.buildChannelSummary({\n account,\n cfg: this.config,\n defaultAccountId: accountId,\n snapshot: plugin.status.defaultRuntime ?? { accountId, channelId: channel, enabled: true, configured: true },\n });\n return summary;\n } catch (err) {\n return { error: String(err) };\n }\n }\n \n async updateConfig(config: Config): Promise<void> {\n this.config = config;\n for (const id of this.initializedPluginIds) {\n const plugin = this.plugins.get(id);\n if (plugin?.onConfigUpdated) {\n await Promise.resolve(plugin.onConfigUpdated(config));\n }\n }\n log.info('Channel config updated');\n }\n\n /** Replace in-memory config without running plugin `onConfigUpdated` hooks. */\n setRuntimeConfig(config: Config): void {\n this.config = config;\n }\n \n private async applyTtsIfNeeded(msg: OutboundMessage): Promise<OutboundMessage> {\n if (msg.type && msg.type !== 'message') return msg;\n if (!msg.content?.trim()) return msg;\n if (msg.mediaUrl) return msg;\n \n const ttsConfig = mergeTtsConfigFromAppConfig(this.config.messages?.tts);\n if (!ttsConfig.enabled) return msg;\n\n const inboundAudio = msg.metadata?.transcribedVoice === true;\n return maybeApplyTtsToPayload(msg, {\n config: ttsConfig,\n channel: msg.channel,\n inboundAudio,\n appConfig: this.config,\n });\n }\n \n /**\n * Stop a single channel and suppress automatic restart until `startChannel` is called.\n */\n async stopChannel(channelId: string): Promise<void> {\n this.manuallyStopped.add(channelId);\n const plugin = this.plugins.get(channelId);\n if (!plugin || !this.initializedPluginIds.has(channelId)) {\n return;\n }\n await this.stopPlugin(plugin).catch((err) => {\n log.error({ channel: channelId, err }, 'Failed to stop channel plugin');\n });\n }\n\n /**\n * Clear manual-stop and start one channel (requires prior `initialize()`).\n */\n async startChannel(channelId: string): Promise<void> {\n this.manuallyStopped.delete(channelId);\n const plugin = this.plugins.get(channelId);\n if (!plugin) {\n log.warn({ channel: channelId }, 'Unknown channel');\n return;\n }\n if (!this.initialized) {\n log.warn({ channel: channelId }, 'Channels not initialized');\n return;\n }\n const channelConfig = asChannelConfig(this.config.channels?.[channelId]);\n if (!this.shouldRunChannelPlugin(plugin, channelConfig)) {\n log.debug({ channel: channelId }, 'Channel disabled in config, skipping start');\n return;\n }\n if (!this.initializedPluginIds.has(channelId)) {\n log.warn({ channel: channelId }, 'Channel was never initialized; call initialize() first');\n return;\n }\n await this.startPlugin(plugin, {});\n }\n\n getRuntimeSnapshot(): {\n initialized: boolean;\n running: boolean;\n pluginIds: string[];\n initializedPluginIds: string[];\n manuallyStopped: string[];\n restartAttempts: Record<string, number>;\n channelHealth: Record<string, ChannelHealthState>;\n } {\n return {\n initialized: this.initialized,\n running: this.running,\n pluginIds: [...this.plugins.keys()],\n initializedPluginIds: [...this.initializedPluginIds],\n manuallyStopped: [...this.manuallyStopped],\n restartAttempts: Object.fromEntries(this.restartAttempts),\n channelHealth: this.healthMonitor.toJSON(),\n };\n }\n\n getHealthMonitor(): ChannelHealthMonitor {\n return this.healthMonitor;\n }\n \n /**\n * Channel IDs whose runtime reports connected (e.g. Telegram polling active).\n */\n getRunningChannels(): string[] {\n const result: string[] = [];\n for (const id of this.initializedPluginIds) {\n const plugin = this.plugins.get(id);\n if (!plugin?.channelIsRunning) {\n continue;\n }\n if (plugin.channelIsRunning(this.config)) {\n result.push(id);\n }\n }\n return result;\n }\n \n getAllChannels(): ChannelPlugin[] {\n return this.getAllPlugins();\n }\n}\n\nexport function createChannelManager(config: Config, bus: MessageBus): ChannelManager {\n return new ChannelManager(config, bus);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"manager.js","names":[],"sources":["../../../src/channels/manager.ts"],"sourcesContent":["/**\n * Channel Manager — thin composition root for the channel subsystem.\n *\n * Wires together the four coordinators that own what used to be the eight\n * concerns of this 707-line class:\n *\n * - {@link ChannelPluginRegistry} — plugins Map, register/get\n * - {@link ChannelLifecycleSupervisor} — init/start/stop/restart-backoff\n * - {@link ChannelHeartbeatScheduler} — per-account heartbeat probes\n * - {@link ChannelOutboundSender} — TTS rewrite + persist + delivery\n *\n * The public surface (`registerPlugin`, `initialize`, `start`, `send`, etc.) is\n * preserved so callers (`GatewayService`, CLI commands, channel plugins) are\n * unchanged.\n */\n\nimport type { Config } from '../config/schema.js';\nimport type { MessageBus } from '../infra/bus/index.js';\n\nimport type { InboundMessage, OutboundMessage } from './transport-types.js';\nimport type {\n ChannelPlugin,\n ChannelPluginSessionModelHooks,\n ChannelStreamHandle,\n} from './plugin-types.js';\nimport { ChannelHealthMonitor, type ChannelHealthState } from './health-monitor.js';\nimport { ChannelPluginRegistry } from './plugin-registry.js';\nimport { ChannelHeartbeatScheduler } from './heartbeat-scheduler.js';\nimport {\n ChannelOutboundSender,\n type OutboundChannelHooks,\n} from './outbound-sender.js';\nimport { ChannelLifecycleSupervisor } from './lifecycle-supervisor.js';\nimport { createLogger } from '../utils/logger.js';\n\nconst log = createLogger('ChannelManager');\n\nexport type { OutboundChannelHooks } from './outbound-sender.js';\n\nexport class ChannelManager {\n private config: Config;\n private readonly registry = new ChannelPluginRegistry();\n private readonly healthMonitor = new ChannelHealthMonitor();\n private readonly lifecycle: ChannelLifecycleSupervisor;\n private readonly heartbeat: ChannelHeartbeatScheduler;\n private readonly outbound: ChannelOutboundSender;\n private sessionModelHooks?: ChannelPluginSessionModelHooks;\n\n constructor(config: Config, bus: MessageBus) {\n this.config = config;\n\n this.heartbeat = new ChannelHeartbeatScheduler({\n getConfig: () => this.config,\n healthMonitor: this.healthMonitor,\n requestSoftRestart: (channelId) => {\n void this.lifecycle.softRestart(channelId);\n },\n });\n\n this.lifecycle = new ChannelLifecycleSupervisor({\n bus,\n registry: this.registry,\n getConfig: () => this.config,\n getSessionModelHooks: () => this.sessionModelHooks,\n onPluginStarted: (plugin) => this.heartbeat.schedule(plugin),\n onPluginStopped: (pluginId) => this.heartbeat.clear(pluginId),\n });\n\n this.outbound = new ChannelOutboundSender({\n registry: this.registry,\n getConfig: () => this.config,\n });\n }\n\n // ── Wiring hooks (called by GatewayService / cli) ─────────────────────\n\n setOutboundHooks(hooks: OutboundChannelHooks): void {\n this.outbound.setHooks(hooks);\n }\n\n /** Call before `initialize()` so plugins can persist per-session model overrides. */\n setSessionModelHooks(hooks: ChannelPluginSessionModelHooks | undefined): void {\n this.sessionModelHooks = hooks;\n }\n\n enableOutboundPersistence(agentDir: string): void {\n this.outbound.enablePersistence(agentDir);\n }\n\n // ── Plugin registry pass-throughs ──────────────────────────────────────\n\n registerPlugin(plugin: ChannelPlugin): void {\n this.registry.register(plugin);\n }\n\n getPlugin(id: string): ChannelPlugin | undefined {\n return this.registry.get(id);\n }\n\n getAllPlugins(): ChannelPlugin[] {\n return this.registry.all();\n }\n\n /** Backward-compat alias for `getAllPlugins`. */\n getAllChannels(): ChannelPlugin[] {\n return this.registry.all();\n }\n\n /** Channel IDs whose runtime reports connected (e.g. Telegram polling active). */\n getRunningChannels(): string[] {\n return this.registry.runningChannelIds(this.config, (id) => this.lifecycle.isInitialized(id));\n }\n\n // ── Lifecycle pass-throughs ────────────────────────────────────────────\n\n initialize(): Promise<void> {\n return this.lifecycle.initialize();\n }\n\n start(options?: { deferConnectPluginIds?: ReadonlySet<string> }): Promise<void> {\n return this.lifecycle.start(options);\n }\n\n startDeferredConnects(): Promise<void> {\n return this.lifecycle.startDeferredConnects();\n }\n\n async stop(): Promise<void> {\n await this.lifecycle.stop();\n this.heartbeat.clearAll();\n }\n\n stopChannel(channelId: string): Promise<void> {\n return this.lifecycle.stopChannel(channelId);\n }\n\n startChannel(channelId: string): Promise<void> {\n return this.lifecycle.startChannel(channelId);\n }\n\n listDeferConnectChannelIds(cfg: Config): string[] {\n return this.lifecycle.listDeferConnectChannelIds(cfg);\n }\n\n // ── Outbound pass-throughs ─────────────────────────────────────────────\n\n send(msg: OutboundMessage, options?: { skipPersist?: boolean }): Promise<void> {\n return this.outbound.send(msg, options);\n }\n\n replayPendingOutboundMessages(): Promise<void> {\n return this.outbound.replayPending();\n }\n\n // ── Streaming + status query (delegated to plugin directly) ────────────\n\n startStream(\n channel: string,\n chatId: string,\n accountId?: string,\n opts?: { threadId?: string; replyToMessageId?: string },\n ): ChannelStreamHandle | null {\n const plugin = this.registry.get(channel);\n if (!plugin) {\n log.error({ channel }, 'Unknown channel');\n return null;\n }\n return (\n plugin.streaming?.startStream?.({\n chatId,\n accountId,\n threadId: opts?.threadId,\n replyToMessageId: opts?.replyToMessageId,\n }) ?? null\n );\n }\n\n async getChannelStatus(channel: string): Promise<Record<string, unknown>> {\n const plugin = this.registry.get(channel);\n if (!plugin) return { error: 'Unknown channel' };\n if (!plugin.status?.buildChannelSummary) return { status: 'unknown' };\n\n try {\n const accountId = plugin.config.listAccountIds(this.config)[0] ?? 'default';\n const account = plugin.config.resolveAccount(this.config, accountId);\n return await plugin.status.buildChannelSummary({\n account,\n cfg: this.config,\n defaultAccountId: accountId,\n snapshot: plugin.status.defaultRuntime ?? { accountId, channelId: channel, enabled: true, configured: true },\n });\n } catch (err) {\n return { error: String(err) };\n }\n }\n\n // ── Inbound action dispatch (Feishu card actions) ──────────────────────\n\n /**\n * Optional channel hook before `AgentService` consumes an inbound message\n * (e.g. Feishu card-action triggers).\n */\n async dispatchInboundMessageAction(msg: InboundMessage): Promise<void> {\n const plugin = this.registry.get(msg.channel);\n const handle = plugin?.actions?.handleAction;\n if (!handle) return;\n\n const meta = msg.metadata as Record<string, unknown> | undefined;\n if (msg.channel !== 'feishu' || meta?.feishuEventType !== 'card.action.trigger') {\n return;\n }\n\n const cardAction = meta.cardAction as Record<string, unknown> | undefined;\n const actionTag =\n cardAction && typeof cardAction.tag === 'string' && cardAction.tag.trim()\n ? cardAction.tag.trim()\n : 'feishu.card_action';\n const cardCtx = meta.cardContext as Record<string, unknown> | undefined;\n const openMsg =\n cardCtx && typeof cardCtx.open_message_id === 'string' ? cardCtx.open_message_id.trim() : '';\n const fallbackMsgId = typeof meta.messageId === 'string' ? meta.messageId.trim() : '';\n const messageId = openMsg || fallbackMsgId;\n const accountId =\n typeof meta.accountId === 'string' && meta.accountId.trim() ? meta.accountId.trim() : 'default';\n\n try {\n await handle({\n action: actionTag,\n data: JSON.stringify({\n cardAction: meta.cardAction,\n cardContext: meta.cardContext,\n cardActionText: meta.cardActionText,\n }),\n messageId,\n senderId: msg.sender_id,\n chatId: msg.chat_id,\n accountId,\n metadata: {\n feishuEventType: meta.feishuEventType,\n raw: meta.raw,\n sessionKey: meta.sessionKey,\n userContent: msg.content,\n },\n });\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err, channel: msg.channel, accountId, em }, 'dispatchInboundMessageAction failed');\n }\n }\n\n // ── Config + introspection ─────────────────────────────────────────────\n\n async updateConfig(config: Config): Promise<void> {\n this.config = config;\n await this.lifecycle.forwardConfigUpdate(config);\n log.info('Channel config updated');\n }\n\n /** Replace in-memory config without running plugin `onConfigUpdated` hooks. */\n setRuntimeConfig(config: Config): void {\n this.config = config;\n }\n\n getRuntimeSnapshot(): {\n initialized: boolean;\n running: boolean;\n pluginIds: string[];\n initializedPluginIds: string[];\n manuallyStopped: string[];\n restartAttempts: Record<string, number>;\n channelHealth: Record<string, ChannelHealthState>;\n } {\n const lifecycleSnap = this.lifecycle.snapshot();\n return {\n ...lifecycleSnap,\n pluginIds: this.registry.ids(),\n channelHealth: this.healthMonitor.toJSON(),\n };\n }\n\n getHealthMonitor(): ChannelHealthMonitor {\n return this.healthMonitor;\n }\n}\n\nexport function createChannelManager(config: Config, bus: MessageBus): ChannelManager {\n return new ChannelManager(config, bus);\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Outbound delivery helper: normalize then invoke the plugin outbound adapter.
|
|
3
3
|
*/
|
|
4
|
-
import type { Config } from '../../config/
|
|
4
|
+
import type { Config } from '../../config/schema.js';
|
|
5
5
|
import type { ChannelPlugin, OutboundDeliveryResult } from '../plugin-types.js';
|
|
6
6
|
import type { OutboundMessage } from '../transport-types.js';
|
|
7
7
|
export interface DeliverOutboundMessageParams {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deliver.js","names":[],"sources":["../../../../src/channels/outbound/deliver.ts"],"sourcesContent":["/**\n * Outbound delivery helper: normalize then invoke the plugin outbound adapter.\n */\n\nimport type { Config } from '../../config/
|
|
1
|
+
{"version":3,"file":"deliver.js","names":[],"sources":["../../../../src/channels/outbound/deliver.ts"],"sourcesContent":["/**\n * Outbound delivery helper: normalize then invoke the plugin outbound adapter.\n */\n\nimport type { Config } from '../../config/schema.js';\nimport type {\n ChannelOutboundContext,\n ChannelPlugin,\n OutboundDeliveryResult,\n} from '../plugin-types.js';\nimport type { OutboundMessage } from '../transport-types.js';\nimport { normalizeTelegramDeliveryChatId } from '../telegram/index.js';\nimport { normalizePayloadForPlugin } from './normalize.js';\n\nexport interface DeliverOutboundMessageParams {\n cfg: Config;\n plugin: ChannelPlugin;\n processedMsg: OutboundMessage;\n}\n\nexport async function deliverOutboundMessage(\n params: DeliverOutboundMessageParams,\n): Promise<OutboundDeliveryResult | undefined> {\n const { cfg, plugin, processedMsg } = params;\n const outbound = plugin.outbound;\n if (!outbound) return undefined;\n\n const chatId =\n plugin.id === 'telegram' && typeof processedMsg.chat_id === 'string'\n ? normalizeTelegramDeliveryChatId(processedMsg.chat_id)\n : processedMsg.chat_id;\n\n const msg: OutboundMessage = { ...processedMsg, chat_id: chatId };\n\n const normalizedPayload = normalizePayloadForPlugin(msg, plugin);\n\n const outboundMeta =\n msg.metadata && typeof msg.metadata === 'object' ? (msg.metadata as Record<string, unknown>) : undefined;\n\n if (msg.type === 'typing_on' || msg.type === 'typing_off') {\n if (outbound.sendPayload) {\n return outbound.sendPayload({\n cfg,\n to: chatId,\n text: msg.content ?? '',\n mediaUrl: msg.mediaUrl,\n threadId: msg.metadata?.threadId as string | number | null,\n replyToId: msg.replyToMessageId,\n accountId: msg.metadata?.accountId as string ?? undefined,\n silent: msg.silent,\n outboundMetadata: outboundMeta,\n payload: normalizedPayload,\n });\n }\n return undefined;\n }\n\n const outboundCtx: ChannelOutboundContext = {\n cfg,\n to: chatId,\n text: msg.content ?? '',\n mediaUrl: msg.mediaUrl,\n mediaType: msg.mediaType,\n threadId: msg.metadata?.threadId as string | number | null,\n replyToId: msg.replyToMessageId,\n accountId: msg.metadata?.accountId as string ?? undefined,\n silent: msg.silent,\n audioAsVoice: msg.audioAsVoice,\n outboundMetadata: outboundMeta,\n };\n\n if (outbound.sendPayload) {\n return outbound.sendPayload({ ...outboundCtx, payload: normalizedPayload });\n }\n\n const hasMediaUrl = Boolean(msg.mediaUrl?.trim());\n\n // Plugins often expose both sendText and sendMedia; text-only replies must use sendText.\n if (!hasMediaUrl && outbound.sendText) {\n return outbound.sendText(outboundCtx);\n }\n if (hasMediaUrl && outbound.sendMedia) {\n return outbound.sendMedia(outboundCtx);\n }\n if (outbound.sendMedia) {\n return outbound.sendMedia(outboundCtx);\n }\n if (outbound.sendText) {\n return outbound.sendText(outboundCtx);\n }\n return { messageId: '', chatId, success: false, error: 'No send method' };\n}\n"],"mappings":";;;;AAoBA,eAAsB,uBACpB,QAC6C;CAC7C,MAAM,EAAE,KAAK,QAAQ,iBAAiB;CACtC,MAAM,WAAW,OAAO;AACxB,KAAI,CAAC,SAAU,QAAO,KAAA;CAEtB,MAAM,SACJ,OAAO,OAAO,cAAc,OAAO,aAAa,YAAY,WACxD,gCAAgC,aAAa,QAAQ,GACrD,aAAa;CAEnB,MAAM,MAAuB;EAAE,GAAG;EAAc,SAAS;EAAQ;CAEjE,MAAM,oBAAoB,0BAA0B,KAAK,OAAO;CAEhE,MAAM,eACJ,IAAI,YAAY,OAAO,IAAI,aAAa,WAAY,IAAI,WAAuC,KAAA;AAEjG,KAAI,IAAI,SAAS,eAAe,IAAI,SAAS,cAAc;AACzD,MAAI,SAAS,YACX,QAAO,SAAS,YAAY;GAC1B;GACA,IAAI;GACJ,MAAM,IAAI,WAAW;GACrB,UAAU,IAAI;GACd,UAAU,IAAI,UAAU;GACxB,WAAW,IAAI;GACf,WAAW,IAAI,UAAU,aAAuB,KAAA;GAChD,QAAQ,IAAI;GACZ,kBAAkB;GAClB,SAAS;GACV,CAAC;AAEJ;;CAGF,MAAM,cAAsC;EAC1C;EACA,IAAI;EACJ,MAAM,IAAI,WAAW;EACrB,UAAU,IAAI;EACd,WAAW,IAAI;EACf,UAAU,IAAI,UAAU;EACxB,WAAW,IAAI;EACf,WAAW,IAAI,UAAU,aAAuB,KAAA;EAChD,QAAQ,IAAI;EACZ,cAAc,IAAI;EAClB,kBAAkB;EACnB;AAED,KAAI,SAAS,YACX,QAAO,SAAS,YAAY;EAAE,GAAG;EAAa,SAAS;EAAmB,CAAC;CAG7E,MAAM,cAAc,QAAQ,IAAI,UAAU,MAAM,CAAC;AAGjD,KAAI,CAAC,eAAe,SAAS,SAC3B,QAAO,SAAS,SAAS,YAAY;AAEvC,KAAI,eAAe,SAAS,UAC1B,QAAO,SAAS,UAAU,YAAY;AAExC,KAAI,SAAS,UACX,QAAO,SAAS,UAAU,YAAY;AAExC,KAAI,SAAS,SACX,QAAO,SAAS,SAAS,YAAY;AAEvC,QAAO;EAAE,WAAW;EAAI;EAAQ,SAAS;EAAO,OAAO;EAAkB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { init_write_file_atomic, writeTextAtomicSync } from "../../infra/write-file-atomic.js";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
2
3
|
import { join } from "path";
|
|
3
4
|
import { existsSync, mkdirSync, readFileSync } from "fs";
|
|
4
|
-
import { randomUUID } from "node:crypto";
|
|
5
5
|
//#region src/channels/outbound/persist-store.ts
|
|
6
6
|
/**
|
|
7
7
|
* Durable outbound queue (crash recovery): JSON file under agent internal dir.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChannelOutboundSender — single owner of the outbound pipeline:
|
|
3
|
+
*
|
|
4
|
+
* 1. Optional TTS rewrite (`maybeApplyTtsToPayload`)
|
|
5
|
+
* 2. Persist-store enqueue (best-effort durability if a send hangs)
|
|
6
|
+
* 3. Extension `message_sending` hook (block / mutate)
|
|
7
|
+
* 4. Internal-channel drop guard
|
|
8
|
+
* 5. Plugin delivery via `deliverOutboundMessage`
|
|
9
|
+
* 6. Extension `message_sent` hook
|
|
10
|
+
* 7. Persist-store ack
|
|
11
|
+
*
|
|
12
|
+
* Extracted from `ChannelManager.send` so the lifecycle supervisor and plugin
|
|
13
|
+
* registry stay focused on plugin start/stop and lookup. The send pipeline is
|
|
14
|
+
* the highest-traffic path in the channel layer; centralising it makes its
|
|
15
|
+
* error semantics easier to reason about.
|
|
16
|
+
*/
|
|
17
|
+
import type { Config } from '../config/schema.js';
|
|
18
|
+
import type { OutboundMessage } from './transport-types.js';
|
|
19
|
+
import type { ChannelPluginRegistry } from './plugin-registry.js';
|
|
20
|
+
/** Hooks wired from `AgentService` for `message_sending` / `message_sent` on outbound delivery. */
|
|
21
|
+
export interface OutboundChannelHooks {
|
|
22
|
+
runMessageSending: (to: string, content: string, channel: string) => Promise<{
|
|
23
|
+
send: boolean;
|
|
24
|
+
content?: string;
|
|
25
|
+
reason?: string;
|
|
26
|
+
}>;
|
|
27
|
+
runMessageSent: (to: string, content: string, success: boolean, error: string | undefined, channel: string) => Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
export interface ChannelOutboundSenderOptions {
|
|
30
|
+
registry: ChannelPluginRegistry;
|
|
31
|
+
/** Effective config snapshot (TTS rules + plugin delivery context). */
|
|
32
|
+
getConfig: () => Config;
|
|
33
|
+
}
|
|
34
|
+
export declare class ChannelOutboundSender {
|
|
35
|
+
private readonly opts;
|
|
36
|
+
private hooks?;
|
|
37
|
+
private persistStore?;
|
|
38
|
+
constructor(opts: ChannelOutboundSenderOptions);
|
|
39
|
+
setHooks(hooks: OutboundChannelHooks): void;
|
|
40
|
+
enablePersistence(agentDir: string): void;
|
|
41
|
+
/**
|
|
42
|
+
* Redeliver every queued outbound item (called after channels are started).
|
|
43
|
+
* Best-effort — may duplicate if the prior send succeeded but ack did not
|
|
44
|
+
* land on disk.
|
|
45
|
+
*/
|
|
46
|
+
replayPending(): Promise<void>;
|
|
47
|
+
send(msg: OutboundMessage, options?: {
|
|
48
|
+
skipPersist?: boolean;
|
|
49
|
+
}): Promise<void>;
|
|
50
|
+
private applyTtsIfNeeded;
|
|
51
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../utils/logger.js";
|
|
3
|
+
import { mergeTtsConfigFromAppConfig } from "../voice/tts/merge-config.js";
|
|
4
|
+
import { maybeApplyTtsToPayload } from "../voice/tts/payload.js";
|
|
5
|
+
import "./internal-outbound.js";
|
|
6
|
+
import { deliverOutboundMessage } from "./outbound/deliver.js";
|
|
7
|
+
import { OutboundPersistStore } from "./outbound/persist-store.js";
|
|
8
|
+
//#region src/channels/outbound-sender.ts
|
|
9
|
+
init_logger();
|
|
10
|
+
const log = createLogger("ChannelOutboundSender");
|
|
11
|
+
var ChannelOutboundSender = class {
|
|
12
|
+
opts;
|
|
13
|
+
hooks;
|
|
14
|
+
persistStore;
|
|
15
|
+
constructor(opts) {
|
|
16
|
+
this.opts = opts;
|
|
17
|
+
}
|
|
18
|
+
setHooks(hooks) {
|
|
19
|
+
this.hooks = hooks;
|
|
20
|
+
}
|
|
21
|
+
enablePersistence(agentDir) {
|
|
22
|
+
this.persistStore = new OutboundPersistStore(agentDir);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Redeliver every queued outbound item (called after channels are started).
|
|
26
|
+
* Best-effort — may duplicate if the prior send succeeded but ack did not
|
|
27
|
+
* land on disk.
|
|
28
|
+
*/
|
|
29
|
+
async replayPending() {
|
|
30
|
+
if (!this.persistStore) return;
|
|
31
|
+
const pending = [...this.persistStore.peek()];
|
|
32
|
+
for (const p of pending) try {
|
|
33
|
+
await this.send(p.message, { skipPersist: true });
|
|
34
|
+
this.persistStore.ack(p.id);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
log.error({
|
|
37
|
+
id: p.id,
|
|
38
|
+
err
|
|
39
|
+
}, "Failed to replay outbound message");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async send(msg, options) {
|
|
43
|
+
log.debug({
|
|
44
|
+
type: msg.type,
|
|
45
|
+
channel: msg.channel,
|
|
46
|
+
chatId: msg.chat_id
|
|
47
|
+
}, "Received outbound message");
|
|
48
|
+
let processedMsg = await this.applyTtsIfNeeded(msg);
|
|
49
|
+
const queueId = !options?.skipPersist && this.persistStore ? this.persistStore.enqueue(structuredClone(processedMsg)) : null;
|
|
50
|
+
try {
|
|
51
|
+
if (this.hooks) {
|
|
52
|
+
const hookResult = await this.hooks.runMessageSending(processedMsg.chat_id, processedMsg.content ?? "", processedMsg.channel);
|
|
53
|
+
if (!hookResult.send) {
|
|
54
|
+
if (queueId) this.persistStore.ack(queueId);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
processedMsg = {
|
|
58
|
+
...processedMsg,
|
|
59
|
+
content: hookResult.content ?? processedMsg.content
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (processedMsg.channel === "__xopc_internal") {
|
|
63
|
+
log.debug({ chatId: processedMsg.chat_id }, "Outbound dropped (internal session — not a real channel)");
|
|
64
|
+
if (queueId) this.persistStore.ack(queueId);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const plugin = this.opts.registry.get(processedMsg.channel);
|
|
68
|
+
if (!plugin?.outbound) {
|
|
69
|
+
log.error({ channel: processedMsg.channel }, "Unknown channel or no outbound adapter");
|
|
70
|
+
if (queueId) this.persistStore.ack(queueId);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const result = await deliverOutboundMessage({
|
|
74
|
+
cfg: this.opts.getConfig(),
|
|
75
|
+
plugin,
|
|
76
|
+
processedMsg
|
|
77
|
+
});
|
|
78
|
+
if (this.hooks) {
|
|
79
|
+
const err = result && !result.success ? result.error : void 0;
|
|
80
|
+
await this.hooks.runMessageSent(processedMsg.chat_id, processedMsg.content ?? "", result?.success ?? false, err, processedMsg.channel);
|
|
81
|
+
}
|
|
82
|
+
if (!result) {
|
|
83
|
+
if (queueId) this.persistStore.ack(queueId);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (result.success) log.info({
|
|
87
|
+
channel: processedMsg.channel,
|
|
88
|
+
chatId: processedMsg.chat_id,
|
|
89
|
+
messageId: result.messageId
|
|
90
|
+
}, "Message sent");
|
|
91
|
+
else log.error({
|
|
92
|
+
channel: processedMsg.channel,
|
|
93
|
+
chatId: processedMsg.chat_id,
|
|
94
|
+
error: result.error
|
|
95
|
+
}, "Failed to send message");
|
|
96
|
+
if (queueId) this.persistStore.ack(queueId);
|
|
97
|
+
} catch (err) {
|
|
98
|
+
log.error({
|
|
99
|
+
channel: processedMsg.channel,
|
|
100
|
+
chatId: processedMsg.chat_id,
|
|
101
|
+
err
|
|
102
|
+
}, "Outbound send threw");
|
|
103
|
+
if (!queueId) throw err;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async applyTtsIfNeeded(msg) {
|
|
107
|
+
if (msg.type && msg.type !== "message") return msg;
|
|
108
|
+
if (!msg.content?.trim()) return msg;
|
|
109
|
+
if (msg.mediaUrl) return msg;
|
|
110
|
+
const cfg = this.opts.getConfig();
|
|
111
|
+
const ttsConfig = mergeTtsConfigFromAppConfig(cfg.messages?.tts);
|
|
112
|
+
if (!ttsConfig.enabled) return msg;
|
|
113
|
+
const inboundAudio = msg.metadata?.transcribedVoice === true;
|
|
114
|
+
return maybeApplyTtsToPayload(msg, {
|
|
115
|
+
config: ttsConfig,
|
|
116
|
+
channel: msg.channel,
|
|
117
|
+
inboundAudio,
|
|
118
|
+
appConfig: cfg
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
//#endregion
|
|
123
|
+
export { ChannelOutboundSender };
|
|
124
|
+
|
|
125
|
+
//# sourceMappingURL=outbound-sender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-sender.js","names":[],"sources":["../../../src/channels/outbound-sender.ts"],"sourcesContent":["/**\n * ChannelOutboundSender — single owner of the outbound pipeline:\n *\n * 1. Optional TTS rewrite (`maybeApplyTtsToPayload`)\n * 2. Persist-store enqueue (best-effort durability if a send hangs)\n * 3. Extension `message_sending` hook (block / mutate)\n * 4. Internal-channel drop guard\n * 5. Plugin delivery via `deliverOutboundMessage`\n * 6. Extension `message_sent` hook\n * 7. Persist-store ack\n *\n * Extracted from `ChannelManager.send` so the lifecycle supervisor and plugin\n * registry stay focused on plugin start/stop and lookup. The send pipeline is\n * the highest-traffic path in the channel layer; centralising it makes its\n * error semantics easier to reason about.\n */\n\nimport type { Config } from '../config/schema.js';\n\nimport type { OutboundMessage } from './transport-types.js';\nimport { INTERNAL_OUTBOUND_DROP_CHANNEL } from './internal-outbound.js';\nimport { mergeTtsConfigFromAppConfig } from '../voice/tts/merge-config.js';\nimport { maybeApplyTtsToPayload } from '../voice/tts/payload.js';\nimport { deliverOutboundMessage } from './outbound/deliver.js';\nimport { OutboundPersistStore } from './outbound/persist-store.js';\nimport type { ChannelPluginRegistry } from './plugin-registry.js';\nimport { createLogger } from '../utils/logger.js';\n\nconst log = createLogger('ChannelOutboundSender');\n\n/** Hooks wired from `AgentService` for `message_sending` / `message_sent` on outbound delivery. */\nexport interface OutboundChannelHooks {\n runMessageSending: (\n to: string,\n content: string,\n channel: string,\n ) => Promise<{ send: boolean; content?: string; reason?: string }>;\n runMessageSent: (\n to: string,\n content: string,\n success: boolean,\n error: string | undefined,\n channel: string,\n ) => Promise<void>;\n}\n\nexport interface ChannelOutboundSenderOptions {\n registry: ChannelPluginRegistry;\n /** Effective config snapshot (TTS rules + plugin delivery context). */\n getConfig: () => Config;\n}\n\nexport class ChannelOutboundSender {\n private readonly opts: ChannelOutboundSenderOptions;\n private hooks?: OutboundChannelHooks;\n private persistStore?: OutboundPersistStore;\n\n constructor(opts: ChannelOutboundSenderOptions) {\n this.opts = opts;\n }\n\n setHooks(hooks: OutboundChannelHooks): void {\n this.hooks = hooks;\n }\n\n enablePersistence(agentDir: string): void {\n this.persistStore = new OutboundPersistStore(agentDir);\n }\n\n /**\n * Redeliver every queued outbound item (called after channels are started).\n * Best-effort — may duplicate if the prior send succeeded but ack did not\n * land on disk.\n */\n async replayPending(): Promise<void> {\n if (!this.persistStore) return;\n const pending = [...this.persistStore.peek()];\n for (const p of pending) {\n try {\n await this.send(p.message, { skipPersist: true });\n this.persistStore.ack(p.id);\n } catch (err) {\n log.error({ id: p.id, err }, 'Failed to replay outbound message');\n }\n }\n }\n\n async send(msg: OutboundMessage, options?: { skipPersist?: boolean }): Promise<void> {\n log.debug({ type: msg.type, channel: msg.channel, chatId: msg.chat_id }, 'Received outbound message');\n\n let processedMsg = await this.applyTtsIfNeeded(msg);\n const queueId =\n !options?.skipPersist && this.persistStore\n ? this.persistStore.enqueue(structuredClone(processedMsg))\n : null;\n\n try {\n if (this.hooks) {\n const hookResult = await this.hooks.runMessageSending(\n processedMsg.chat_id,\n processedMsg.content ?? '',\n processedMsg.channel,\n );\n if (!hookResult.send) {\n if (queueId) this.persistStore!.ack(queueId);\n return;\n }\n processedMsg = { ...processedMsg, content: hookResult.content ?? processedMsg.content };\n }\n\n if (processedMsg.channel === INTERNAL_OUTBOUND_DROP_CHANNEL) {\n log.debug(\n { chatId: processedMsg.chat_id },\n 'Outbound dropped (internal session — not a real channel)',\n );\n if (queueId) this.persistStore!.ack(queueId);\n return;\n }\n\n const plugin = this.opts.registry.get(processedMsg.channel);\n if (!plugin?.outbound) {\n log.error({ channel: processedMsg.channel }, 'Unknown channel or no outbound adapter');\n if (queueId) this.persistStore!.ack(queueId);\n return;\n }\n\n const result = await deliverOutboundMessage({\n cfg: this.opts.getConfig(),\n plugin,\n processedMsg,\n });\n\n if (this.hooks) {\n const err = result && !result.success ? result.error : undefined;\n await this.hooks.runMessageSent(\n processedMsg.chat_id,\n processedMsg.content ?? '',\n result?.success ?? false,\n err,\n processedMsg.channel,\n );\n }\n\n if (!result) {\n if (queueId) this.persistStore!.ack(queueId);\n return;\n }\n\n if (result.success) {\n log.info(\n { channel: processedMsg.channel, chatId: processedMsg.chat_id, messageId: result.messageId },\n 'Message sent',\n );\n } else {\n log.error(\n { channel: processedMsg.channel, chatId: processedMsg.chat_id, error: result.error },\n 'Failed to send message',\n );\n }\n\n if (queueId) this.persistStore!.ack(queueId);\n } catch (err) {\n log.error(\n { channel: processedMsg.channel, chatId: processedMsg.chat_id, err },\n 'Outbound send threw',\n );\n // No queueId means the persist-store was never engaged — caller is responsible for retrying.\n if (!queueId) throw err;\n }\n }\n\n private async applyTtsIfNeeded(msg: OutboundMessage): Promise<OutboundMessage> {\n if (msg.type && msg.type !== 'message') return msg;\n if (!msg.content?.trim()) return msg;\n if (msg.mediaUrl) return msg;\n\n const cfg = this.opts.getConfig();\n const ttsConfig = mergeTtsConfigFromAppConfig(cfg.messages?.tts);\n if (!ttsConfig.enabled) return msg;\n\n const inboundAudio = msg.metadata?.transcribedVoice === true;\n return maybeApplyTtsToPayload(msg, {\n config: ttsConfig,\n channel: msg.channel,\n inboundAudio,\n appConfig: cfg,\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
import type { Config } from '../../config/
|
|
1
|
+
import type { Config } from '../../config/schema.js';
|
|
2
2
|
import type { DmPolicy } from '../channel-domain.js';
|
|
3
3
|
import type { PairingCliChannel } from './pairing-channel.js';
|
|
4
|
-
export type PairingPendingView
|
|
5
|
-
|
|
6
|
-
codeLast4: string;
|
|
7
|
-
createdAt: string;
|
|
8
|
-
lastSeenAt: string;
|
|
9
|
-
expiresAt: string;
|
|
10
|
-
isStale: boolean;
|
|
11
|
-
meta?: Record<string, string>;
|
|
12
|
-
};
|
|
4
|
+
export { type PairingPendingView } from './pairing-types.js';
|
|
5
|
+
import type { PairingPendingView } from './pairing-types.js';
|
|
13
6
|
export type ChannelPairingState = {
|
|
14
7
|
channel: PairingCliChannel;
|
|
15
8
|
accountId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pairing-service.js","names":["block"],"sources":["../../../../src/channels/pairing/pairing-service.ts"],"sourcesContent":["import type { Config } from '../../config/index.js';\nimport { resolveDmPolicy } from '../security.js';\nimport type { DmPolicy } from '../channel-domain.js';\n\nimport { readAllowFromIdsSync, removeAllowFromIdSync } from './allow-from-file.js';\nimport type { PairingCliChannel } from './pairing-channel.js';\nimport { broadcastPairingEvent } from './pairing-events.js';\nimport { PAIRING_PENDING_MAX, PAIRING_STALE_PENDING_MS } from './pairing-constants.js';\nimport {\n approvePairingBySenderIdSync,\n approvePairingCodeSync,\n dismissPairingBySenderIdSync,\n listPendingPairingRequestsSync,\n PAIRING_PENDING_TTL_MS,\n type PairingRequest,\n} from './pairing-store.js';\nimport {\n resolveStandardAllowFromPath,\n resolveStandardPairingPath,\n resolveWeixinAllowFromPath,\n resolveWeixinPairingPath,\n} from './paths.js';\n\nexport type PairingPendingView = {\n senderId: string;\n codeLast4: string;\n createdAt: string;\n lastSeenAt: string;\n expiresAt: string;\n isStale: boolean;\n meta?: Record<string, string>;\n};\n\nexport type ChannelPairingState = {\n channel: PairingCliChannel;\n accountId: string;\n dmPolicy: DmPolicy;\n pending: PairingPendingView[];\n paired: {\n fromConfig: string[];\n fromCredentials: string[];\n };\n};\n\nfunction normalizeAccountId(accountId: string | undefined): string {\n return (accountId ?? 'default').trim().toLowerCase() || 'default';\n}\n\nfunction resolvePairingPaths(channel: PairingCliChannel, accountId: string): {\n pairingPath: string;\n allowPath: string;\n} {\n const normalized = normalizeAccountId(accountId);\n if (channel === 'weixin') {\n return {\n pairingPath: resolveWeixinPairingPath(normalized),\n allowPath: resolveWeixinAllowFromPath(normalized),\n };\n }\n return {\n pairingPath: resolveStandardPairingPath(channel, normalized),\n allowPath: resolveStandardAllowFromPath(channel, normalized),\n };\n}\n\nfunction requestAccountId(entry: PairingRequest): string {\n const fromMeta = entry.meta?.accountId?.trim().toLowerCase();\n return fromMeta || 'default';\n}\n\nfunction toPendingView(entry: PairingRequest): PairingPendingView {\n const createdMs = Date.parse(entry.createdAt);\n const expiresAt = Number.isFinite(createdMs)\n ? new Date(createdMs + PAIRING_PENDING_TTL_MS).toISOString()\n : new Date(Date.now() + PAIRING_PENDING_TTL_MS).toISOString();\n const code = entry.code ?? '';\n const codeLast4 = code.length >= 4 ? code.slice(-4) : code;\n const meta =\n entry.meta && typeof entry.meta === 'object'\n ? Object.fromEntries(\n Object.entries(entry.meta).filter(\n ([k, v]) => k !== 'accountId' && typeof v === 'string' && v.trim() !== '',\n ),\n )\n : undefined;\n return {\n senderId: entry.id,\n codeLast4,\n createdAt: entry.createdAt,\n lastSeenAt: entry.lastSeenAt,\n expiresAt,\n isStale:\n Number.isFinite(createdMs) && Date.now() - (createdMs as number) >= PAIRING_STALE_PENDING_MS,\n meta: meta && Object.keys(meta).length > 0 ? meta : undefined,\n };\n}\n\nfunction pendingEntryStats(pending: PairingRequest[]): {\n pending: number;\n stale: number;\n atCapacity: boolean;\n} {\n const now = Date.now();\n let stale = 0;\n for (const p of pending) {\n const created = Date.parse(p.createdAt);\n if (Number.isFinite(created) && now - created >= PAIRING_STALE_PENDING_MS) {\n stale += 1;\n }\n }\n return {\n pending: pending.length,\n stale,\n atCapacity: pending.length >= PAIRING_PENDING_MAX,\n };\n}\n\nfunction resolveChannelAllowFromConfig(\n config: Config | undefined,\n channel: PairingCliChannel,\n accountId: string,\n): string[] {\n const ch = config?.channels?.[channel as keyof NonNullable<Config['channels']>];\n if (!ch || typeof ch !== 'object' || Array.isArray(ch)) return [];\n const block = ch as Record<string, unknown>;\n const top = Array.isArray(block.allowFrom)\n ? block.allowFrom.map(String).filter(Boolean)\n : [];\n const accounts = block.accounts;\n if (accounts && typeof accounts === 'object' && !Array.isArray(accounts)) {\n const acc = (accounts as Record<string, unknown>)[accountId];\n if (acc && typeof acc === 'object' && !Array.isArray(acc)) {\n const fromAcc = (acc as { allowFrom?: unknown }).allowFrom;\n if (Array.isArray(fromAcc)) {\n return [...new Set([...top, ...fromAcc.map(String).filter(Boolean)])];\n }\n }\n }\n return [...new Set(top)];\n}\n\nfunction resolveChannelEnabled(config: Config | undefined, channel: PairingCliChannel): boolean {\n const ch = config?.channels?.[channel as keyof NonNullable<Config['channels']>];\n if (!ch || typeof ch !== 'object' || Array.isArray(ch)) return false;\n return (ch as { enabled?: boolean }).enabled === true;\n}\n\nfunction resolveAccountEnabled(\n config: Config | undefined,\n channel: PairingCliChannel,\n accountId: string,\n): boolean {\n if (!resolveChannelEnabled(config, channel)) return false;\n const ch = config?.channels?.[channel as keyof NonNullable<Config['channels']>];\n if (!ch || typeof ch !== 'object' || Array.isArray(ch)) return true;\n const block = ch as Record<string, unknown>;\n const accounts = block.accounts;\n if (accounts && typeof accounts === 'object' && !Array.isArray(accounts)) {\n const acc = (accounts as Record<string, unknown>)[accountId];\n if (acc && typeof acc === 'object' && !Array.isArray(acc)) {\n return (acc as { enabled?: boolean }).enabled !== false;\n }\n }\n return true;\n}\n\nfunction resolveChannelDmPolicy(\n config: Config | undefined,\n channel: PairingCliChannel,\n accountId: string,\n): DmPolicy {\n const ch = config?.channels?.[channel as keyof NonNullable<Config['channels']>];\n if (!ch || typeof ch !== 'object' || Array.isArray(ch)) {\n return resolveDmPolicy(undefined, channel === 'weixin' ? 'open' : 'pairing');\n }\n const block = ch as Record<string, unknown>;\n const accounts = block.accounts;\n if (accounts && typeof accounts === 'object' && !Array.isArray(accounts)) {\n const acc = (accounts as Record<string, unknown>)[accountId];\n if (acc && typeof acc === 'object' && !Array.isArray(acc)) {\n const accPolicy = (acc as { dmPolicy?: DmPolicy }).dmPolicy;\n if (accPolicy) return resolveDmPolicy(accPolicy, 'pairing');\n }\n }\n const topPolicy = block.dmPolicy as DmPolicy | undefined;\n return resolveDmPolicy(topPolicy, channel === 'weixin' ? 'open' : 'pairing');\n}\n\nexport type ChannelPairingSummaryEntry = {\n pending: number;\n stale: number;\n atCapacity: boolean;\n};\n\nexport type ChannelPairingSummary = Record<PairingCliChannel, ChannelPairingSummaryEntry>;\n\nexport type PairingPendingIssue = {\n channel: PairingCliChannel;\n accountId: string;\n pending: number;\n stale: number;\n atCapacity: boolean;\n};\n\nfunction resolvePairingAccountIds(config: Config | undefined, channel: PairingCliChannel): string[] {\n const ch = config?.channels?.[channel as keyof NonNullable<Config['channels']>];\n if (!ch || typeof ch !== 'object' || Array.isArray(ch)) {\n return channel === 'telegram' ? ['default'] : [];\n }\n const block = ch as Record<string, unknown>;\n const accounts = block.accounts;\n if (accounts && typeof accounts === 'object' && !Array.isArray(accounts)) {\n const keys = Object.keys(accounts as Record<string, unknown>).sort();\n if (keys.length > 0) return keys;\n }\n if (channel === 'feishu') {\n const appId = typeof block.appId === 'string' ? block.appId.trim() : '';\n const appSecret = typeof block.appSecret === 'string' ? block.appSecret.trim() : '';\n return appId && appSecret ? ['default'] : [];\n }\n if (channel === 'telegram') return ['default'];\n return ['default'];\n}\n\nexport function listChannelPairingSummary(config?: Config): ChannelPairingSummary {\n const channels: PairingCliChannel[] = ['telegram', 'feishu', 'weixin'];\n const summary: ChannelPairingSummary = {\n telegram: { pending: 0, stale: 0, atCapacity: false },\n feishu: { pending: 0, stale: 0, atCapacity: false },\n weixin: { pending: 0, stale: 0, atCapacity: false },\n };\n for (const channel of channels) {\n if (!resolveChannelEnabled(config, channel)) continue;\n const accountIds = resolvePairingAccountIds(config, channel);\n for (const accountId of accountIds) {\n if (!resolveAccountEnabled(config, channel, accountId)) continue;\n if (resolveChannelDmPolicy(config, channel, accountId) !== 'pairing') continue;\n const { pairingPath } = resolvePairingPaths(channel, accountId);\n const pendingRaw = listPendingPairingRequestsSync(pairingPath).filter(\n (r) => requestAccountId(r) === accountId,\n );\n const stats = pendingEntryStats(pendingRaw);\n summary[channel].pending += stats.pending;\n summary[channel].stale += stats.stale;\n summary[channel].atCapacity ||= stats.atCapacity;\n }\n }\n return summary;\n}\n\nexport function collectPairingPendingIssues(config?: Config): PairingPendingIssue[] {\n const issues: PairingPendingIssue[] = [];\n for (const channel of ['telegram', 'feishu', 'weixin'] as const) {\n if (!resolveChannelEnabled(config, channel)) continue;\n const accountIds = resolvePairingAccountIds(config, channel);\n for (const accountId of accountIds) {\n if (!resolveAccountEnabled(config, channel, accountId)) continue;\n if (resolveChannelDmPolicy(config, channel, accountId) !== 'pairing') continue;\n const { pairingPath } = resolvePairingPaths(channel, accountId);\n const pendingRaw = listPendingPairingRequestsSync(pairingPath).filter(\n (r) => requestAccountId(r) === accountId,\n );\n const stats = pendingEntryStats(pendingRaw);\n if (stats.pending > 0) {\n issues.push({ channel, accountId, ...stats });\n }\n }\n }\n return issues;\n}\n\nexport function listChannelPairingState(params: {\n channel: PairingCliChannel;\n accountId?: string;\n config?: Config;\n}): ChannelPairingState {\n const accountId = normalizeAccountId(params.accountId);\n const { pairingPath, allowPath } = resolvePairingPaths(params.channel, accountId);\n const pendingRaw = listPendingPairingRequestsSync(pairingPath).filter(\n (r) => requestAccountId(r) === accountId,\n );\n return {\n channel: params.channel,\n accountId,\n dmPolicy: resolveChannelDmPolicy(params.config, params.channel, accountId),\n pending: pendingRaw.map(toPendingView),\n paired: {\n fromConfig: resolveChannelAllowFromConfig(params.config, params.channel, accountId),\n fromCredentials: readAllowFromIdsSync(allowPath),\n },\n };\n}\n\nexport function approveChannelPairing(params: {\n channel: PairingCliChannel;\n accountId?: string;\n code: string;\n}): { ok: true; senderId: string; alreadyPaired: boolean } | { ok: false; error: string } {\n const accountId = normalizeAccountId(params.accountId);\n const code = params.code.trim();\n if (!code) return { ok: false, error: 'Missing pairing code.' };\n\n const { pairingPath, allowPath } = resolvePairingPaths(params.channel, accountId);\n const alreadyPaired = readAllowFromIdsSync(allowPath);\n\n const result = approvePairingCodeSync({\n pairingFilePath: pairingPath,\n allowFromFilePath: allowPath,\n code,\n accountId,\n });\n if (!result) {\n return { ok: false, error: 'Invalid or expired pairing code (or wrong account).' };\n }\n broadcastPairingEvent('channels.pairing.approved', {\n channel: params.channel,\n accountId,\n senderId: result.senderId,\n });\n return {\n ok: true,\n senderId: result.senderId,\n alreadyPaired: alreadyPaired.includes(result.senderId),\n };\n}\n\nexport function approveChannelPairingBySender(params: {\n channel: PairingCliChannel;\n accountId?: string;\n senderId: string;\n}): { ok: true; senderId: string; alreadyPaired: boolean } | { ok: false; error: string } {\n const accountId = normalizeAccountId(params.accountId);\n const senderId = params.senderId.trim();\n if (!senderId) return { ok: false, error: 'Missing sender id.' };\n\n const { pairingPath, allowPath } = resolvePairingPaths(params.channel, accountId);\n const alreadyPaired = readAllowFromIdsSync(allowPath);\n\n const result = approvePairingBySenderIdSync({\n pairingFilePath: pairingPath,\n allowFromFilePath: allowPath,\n senderId,\n accountId,\n });\n if (!result) {\n return { ok: false, error: 'No pending pairing request for this sender (or wrong account).' };\n }\n broadcastPairingEvent('channels.pairing.approved', {\n channel: params.channel,\n accountId,\n senderId: result.senderId,\n });\n return {\n ok: true,\n senderId: result.senderId,\n alreadyPaired: alreadyPaired.includes(result.senderId),\n };\n}\n\nexport function revokeChannelPairingPaired(params: {\n channel: PairingCliChannel;\n accountId?: string;\n senderId: string;\n}): { ok: true; changed: boolean } | { ok: false; error: string } {\n const accountId = normalizeAccountId(params.accountId);\n const senderId = params.senderId.trim();\n if (!senderId) return { ok: false, error: 'Missing sender id.' };\n\n const { allowPath } = resolvePairingPaths(params.channel, accountId);\n const { changed } = removeAllowFromIdSync(allowPath, senderId);\n if (changed) {\n broadcastPairingEvent('channels.pairing.revoked', {\n channel: params.channel,\n accountId,\n senderId,\n });\n }\n return { ok: true, changed };\n}\n\nexport function dismissChannelPairingPending(params: {\n channel: PairingCliChannel;\n accountId?: string;\n senderId: string;\n}): { ok: true; senderId: string } | { ok: false; error: string } {\n const accountId = normalizeAccountId(params.accountId);\n const senderId = params.senderId.trim();\n if (!senderId) return { ok: false, error: 'Missing sender id.' };\n\n const { pairingPath } = resolvePairingPaths(params.channel, accountId);\n const result = dismissPairingBySenderIdSync({\n pairingFilePath: pairingPath,\n senderId,\n accountId,\n });\n if (!result) {\n return { ok: false, error: 'No pending pairing request for this sender (or wrong account).' };\n }\n broadcastPairingEvent('channels.pairing.dismissed', {\n channel: params.channel,\n accountId,\n senderId: result.senderId,\n });\n return { ok: true, senderId: result.senderId };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pairing-service.js","names":["block"],"sources":["../../../../src/channels/pairing/pairing-service.ts"],"sourcesContent":["import type { Config } from '../../config/schema.js';\nimport { resolveDmPolicy } from '../security.js';\nimport type { DmPolicy } from '../channel-domain.js';\n\nimport { readAllowFromIdsSync, removeAllowFromIdSync } from './allow-from-file.js';\nimport type { PairingCliChannel } from './pairing-channel.js';\nimport { broadcastPairingEvent } from './pairing-events.js';\nimport { PAIRING_PENDING_MAX, PAIRING_STALE_PENDING_MS } from './pairing-constants.js';\nimport {\n approvePairingBySenderIdSync,\n approvePairingCodeSync,\n dismissPairingBySenderIdSync,\n listPendingPairingRequestsSync,\n PAIRING_PENDING_TTL_MS,\n type PairingRequest,\n} from './pairing-store.js';\nimport {\n resolveStandardAllowFromPath,\n resolveStandardPairingPath,\n resolveWeixinAllowFromPath,\n resolveWeixinPairingPath,\n} from './paths.js';\n\n// `PairingPendingView` moved to `./pairing-types.js` (leaf) so\n// `plugins/types.adapters.ts` and other lower-level callers can reference it\n// without forming a `types.adapters → pairing-service → security → plugin-types\n// → types.adapters` cycle. Re-exported here for backward-compat.\nexport { type PairingPendingView } from './pairing-types.js';\nimport type { PairingPendingView } from './pairing-types.js';\n\nexport type ChannelPairingState = {\n channel: PairingCliChannel;\n accountId: string;\n dmPolicy: DmPolicy;\n pending: PairingPendingView[];\n paired: {\n fromConfig: string[];\n fromCredentials: string[];\n };\n};\n\nfunction normalizeAccountId(accountId: string | undefined): string {\n return (accountId ?? 'default').trim().toLowerCase() || 'default';\n}\n\nfunction resolvePairingPaths(channel: PairingCliChannel, accountId: string): {\n pairingPath: string;\n allowPath: string;\n} {\n const normalized = normalizeAccountId(accountId);\n if (channel === 'weixin') {\n return {\n pairingPath: resolveWeixinPairingPath(normalized),\n allowPath: resolveWeixinAllowFromPath(normalized),\n };\n }\n return {\n pairingPath: resolveStandardPairingPath(channel, normalized),\n allowPath: resolveStandardAllowFromPath(channel, normalized),\n };\n}\n\nfunction requestAccountId(entry: PairingRequest): string {\n const fromMeta = entry.meta?.accountId?.trim().toLowerCase();\n return fromMeta || 'default';\n}\n\nfunction toPendingView(entry: PairingRequest): PairingPendingView {\n const createdMs = Date.parse(entry.createdAt);\n const expiresAt = Number.isFinite(createdMs)\n ? new Date(createdMs + PAIRING_PENDING_TTL_MS).toISOString()\n : new Date(Date.now() + PAIRING_PENDING_TTL_MS).toISOString();\n const code = entry.code ?? '';\n const codeLast4 = code.length >= 4 ? code.slice(-4) : code;\n const meta =\n entry.meta && typeof entry.meta === 'object'\n ? Object.fromEntries(\n Object.entries(entry.meta).filter(\n ([k, v]) => k !== 'accountId' && typeof v === 'string' && v.trim() !== '',\n ),\n )\n : undefined;\n return {\n senderId: entry.id,\n codeLast4,\n createdAt: entry.createdAt,\n lastSeenAt: entry.lastSeenAt,\n expiresAt,\n isStale:\n Number.isFinite(createdMs) && Date.now() - (createdMs as number) >= PAIRING_STALE_PENDING_MS,\n meta: meta && Object.keys(meta).length > 0 ? meta : undefined,\n };\n}\n\nfunction pendingEntryStats(pending: PairingRequest[]): {\n pending: number;\n stale: number;\n atCapacity: boolean;\n} {\n const now = Date.now();\n let stale = 0;\n for (const p of pending) {\n const created = Date.parse(p.createdAt);\n if (Number.isFinite(created) && now - created >= PAIRING_STALE_PENDING_MS) {\n stale += 1;\n }\n }\n return {\n pending: pending.length,\n stale,\n atCapacity: pending.length >= PAIRING_PENDING_MAX,\n };\n}\n\nfunction resolveChannelAllowFromConfig(\n config: Config | undefined,\n channel: PairingCliChannel,\n accountId: string,\n): string[] {\n const ch = config?.channels?.[channel as keyof NonNullable<Config['channels']>];\n if (!ch || typeof ch !== 'object' || Array.isArray(ch)) return [];\n const block = ch as Record<string, unknown>;\n const top = Array.isArray(block.allowFrom)\n ? block.allowFrom.map(String).filter(Boolean)\n : [];\n const accounts = block.accounts;\n if (accounts && typeof accounts === 'object' && !Array.isArray(accounts)) {\n const acc = (accounts as Record<string, unknown>)[accountId];\n if (acc && typeof acc === 'object' && !Array.isArray(acc)) {\n const fromAcc = (acc as { allowFrom?: unknown }).allowFrom;\n if (Array.isArray(fromAcc)) {\n return [...new Set([...top, ...fromAcc.map(String).filter(Boolean)])];\n }\n }\n }\n return [...new Set(top)];\n}\n\nfunction resolveChannelEnabled(config: Config | undefined, channel: PairingCliChannel): boolean {\n const ch = config?.channels?.[channel as keyof NonNullable<Config['channels']>];\n if (!ch || typeof ch !== 'object' || Array.isArray(ch)) return false;\n return (ch as { enabled?: boolean }).enabled === true;\n}\n\nfunction resolveAccountEnabled(\n config: Config | undefined,\n channel: PairingCliChannel,\n accountId: string,\n): boolean {\n if (!resolveChannelEnabled(config, channel)) return false;\n const ch = config?.channels?.[channel as keyof NonNullable<Config['channels']>];\n if (!ch || typeof ch !== 'object' || Array.isArray(ch)) return true;\n const block = ch as Record<string, unknown>;\n const accounts = block.accounts;\n if (accounts && typeof accounts === 'object' && !Array.isArray(accounts)) {\n const acc = (accounts as Record<string, unknown>)[accountId];\n if (acc && typeof acc === 'object' && !Array.isArray(acc)) {\n return (acc as { enabled?: boolean }).enabled !== false;\n }\n }\n return true;\n}\n\nfunction resolveChannelDmPolicy(\n config: Config | undefined,\n channel: PairingCliChannel,\n accountId: string,\n): DmPolicy {\n const ch = config?.channels?.[channel as keyof NonNullable<Config['channels']>];\n if (!ch || typeof ch !== 'object' || Array.isArray(ch)) {\n return resolveDmPolicy(undefined, channel === 'weixin' ? 'open' : 'pairing');\n }\n const block = ch as Record<string, unknown>;\n const accounts = block.accounts;\n if (accounts && typeof accounts === 'object' && !Array.isArray(accounts)) {\n const acc = (accounts as Record<string, unknown>)[accountId];\n if (acc && typeof acc === 'object' && !Array.isArray(acc)) {\n const accPolicy = (acc as { dmPolicy?: DmPolicy }).dmPolicy;\n if (accPolicy) return resolveDmPolicy(accPolicy, 'pairing');\n }\n }\n const topPolicy = block.dmPolicy as DmPolicy | undefined;\n return resolveDmPolicy(topPolicy, channel === 'weixin' ? 'open' : 'pairing');\n}\n\nexport type ChannelPairingSummaryEntry = {\n pending: number;\n stale: number;\n atCapacity: boolean;\n};\n\nexport type ChannelPairingSummary = Record<PairingCliChannel, ChannelPairingSummaryEntry>;\n\nexport type PairingPendingIssue = {\n channel: PairingCliChannel;\n accountId: string;\n pending: number;\n stale: number;\n atCapacity: boolean;\n};\n\nfunction resolvePairingAccountIds(config: Config | undefined, channel: PairingCliChannel): string[] {\n const ch = config?.channels?.[channel as keyof NonNullable<Config['channels']>];\n if (!ch || typeof ch !== 'object' || Array.isArray(ch)) {\n return channel === 'telegram' ? ['default'] : [];\n }\n const block = ch as Record<string, unknown>;\n const accounts = block.accounts;\n if (accounts && typeof accounts === 'object' && !Array.isArray(accounts)) {\n const keys = Object.keys(accounts as Record<string, unknown>).sort();\n if (keys.length > 0) return keys;\n }\n if (channel === 'feishu') {\n const appId = typeof block.appId === 'string' ? block.appId.trim() : '';\n const appSecret = typeof block.appSecret === 'string' ? block.appSecret.trim() : '';\n return appId && appSecret ? ['default'] : [];\n }\n if (channel === 'telegram') return ['default'];\n return ['default'];\n}\n\nexport function listChannelPairingSummary(config?: Config): ChannelPairingSummary {\n const channels: PairingCliChannel[] = ['telegram', 'feishu', 'weixin'];\n const summary: ChannelPairingSummary = {\n telegram: { pending: 0, stale: 0, atCapacity: false },\n feishu: { pending: 0, stale: 0, atCapacity: false },\n weixin: { pending: 0, stale: 0, atCapacity: false },\n };\n for (const channel of channels) {\n if (!resolveChannelEnabled(config, channel)) continue;\n const accountIds = resolvePairingAccountIds(config, channel);\n for (const accountId of accountIds) {\n if (!resolveAccountEnabled(config, channel, accountId)) continue;\n if (resolveChannelDmPolicy(config, channel, accountId) !== 'pairing') continue;\n const { pairingPath } = resolvePairingPaths(channel, accountId);\n const pendingRaw = listPendingPairingRequestsSync(pairingPath).filter(\n (r) => requestAccountId(r) === accountId,\n );\n const stats = pendingEntryStats(pendingRaw);\n summary[channel].pending += stats.pending;\n summary[channel].stale += stats.stale;\n summary[channel].atCapacity ||= stats.atCapacity;\n }\n }\n return summary;\n}\n\nexport function collectPairingPendingIssues(config?: Config): PairingPendingIssue[] {\n const issues: PairingPendingIssue[] = [];\n for (const channel of ['telegram', 'feishu', 'weixin'] as const) {\n if (!resolveChannelEnabled(config, channel)) continue;\n const accountIds = resolvePairingAccountIds(config, channel);\n for (const accountId of accountIds) {\n if (!resolveAccountEnabled(config, channel, accountId)) continue;\n if (resolveChannelDmPolicy(config, channel, accountId) !== 'pairing') continue;\n const { pairingPath } = resolvePairingPaths(channel, accountId);\n const pendingRaw = listPendingPairingRequestsSync(pairingPath).filter(\n (r) => requestAccountId(r) === accountId,\n );\n const stats = pendingEntryStats(pendingRaw);\n if (stats.pending > 0) {\n issues.push({ channel, accountId, ...stats });\n }\n }\n }\n return issues;\n}\n\nexport function listChannelPairingState(params: {\n channel: PairingCliChannel;\n accountId?: string;\n config?: Config;\n}): ChannelPairingState {\n const accountId = normalizeAccountId(params.accountId);\n const { pairingPath, allowPath } = resolvePairingPaths(params.channel, accountId);\n const pendingRaw = listPendingPairingRequestsSync(pairingPath).filter(\n (r) => requestAccountId(r) === accountId,\n );\n return {\n channel: params.channel,\n accountId,\n dmPolicy: resolveChannelDmPolicy(params.config, params.channel, accountId),\n pending: pendingRaw.map(toPendingView),\n paired: {\n fromConfig: resolveChannelAllowFromConfig(params.config, params.channel, accountId),\n fromCredentials: readAllowFromIdsSync(allowPath),\n },\n };\n}\n\nexport function approveChannelPairing(params: {\n channel: PairingCliChannel;\n accountId?: string;\n code: string;\n}): { ok: true; senderId: string; alreadyPaired: boolean } | { ok: false; error: string } {\n const accountId = normalizeAccountId(params.accountId);\n const code = params.code.trim();\n if (!code) return { ok: false, error: 'Missing pairing code.' };\n\n const { pairingPath, allowPath } = resolvePairingPaths(params.channel, accountId);\n const alreadyPaired = readAllowFromIdsSync(allowPath);\n\n const result = approvePairingCodeSync({\n pairingFilePath: pairingPath,\n allowFromFilePath: allowPath,\n code,\n accountId,\n });\n if (!result) {\n return { ok: false, error: 'Invalid or expired pairing code (or wrong account).' };\n }\n broadcastPairingEvent('channels.pairing.approved', {\n channel: params.channel,\n accountId,\n senderId: result.senderId,\n });\n return {\n ok: true,\n senderId: result.senderId,\n alreadyPaired: alreadyPaired.includes(result.senderId),\n };\n}\n\nexport function approveChannelPairingBySender(params: {\n channel: PairingCliChannel;\n accountId?: string;\n senderId: string;\n}): { ok: true; senderId: string; alreadyPaired: boolean } | { ok: false; error: string } {\n const accountId = normalizeAccountId(params.accountId);\n const senderId = params.senderId.trim();\n if (!senderId) return { ok: false, error: 'Missing sender id.' };\n\n const { pairingPath, allowPath } = resolvePairingPaths(params.channel, accountId);\n const alreadyPaired = readAllowFromIdsSync(allowPath);\n\n const result = approvePairingBySenderIdSync({\n pairingFilePath: pairingPath,\n allowFromFilePath: allowPath,\n senderId,\n accountId,\n });\n if (!result) {\n return { ok: false, error: 'No pending pairing request for this sender (or wrong account).' };\n }\n broadcastPairingEvent('channels.pairing.approved', {\n channel: params.channel,\n accountId,\n senderId: result.senderId,\n });\n return {\n ok: true,\n senderId: result.senderId,\n alreadyPaired: alreadyPaired.includes(result.senderId),\n };\n}\n\nexport function revokeChannelPairingPaired(params: {\n channel: PairingCliChannel;\n accountId?: string;\n senderId: string;\n}): { ok: true; changed: boolean } | { ok: false; error: string } {\n const accountId = normalizeAccountId(params.accountId);\n const senderId = params.senderId.trim();\n if (!senderId) return { ok: false, error: 'Missing sender id.' };\n\n const { allowPath } = resolvePairingPaths(params.channel, accountId);\n const { changed } = removeAllowFromIdSync(allowPath, senderId);\n if (changed) {\n broadcastPairingEvent('channels.pairing.revoked', {\n channel: params.channel,\n accountId,\n senderId,\n });\n }\n return { ok: true, changed };\n}\n\nexport function dismissChannelPairingPending(params: {\n channel: PairingCliChannel;\n accountId?: string;\n senderId: string;\n}): { ok: true; senderId: string } | { ok: false; error: string } {\n const accountId = normalizeAccountId(params.accountId);\n const senderId = params.senderId.trim();\n if (!senderId) return { ok: false, error: 'Missing sender id.' };\n\n const { pairingPath } = resolvePairingPaths(params.channel, accountId);\n const result = dismissPairingBySenderIdSync({\n pairingFilePath: pairingPath,\n senderId,\n accountId,\n });\n if (!result) {\n return { ok: false, error: 'No pending pairing request for this sender (or wrong account).' };\n }\n broadcastPairingEvent('channels.pairing.dismissed', {\n channel: params.channel,\n accountId,\n senderId: result.senderId,\n });\n return { ok: true, senderId: result.senderId };\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { appendAllowFromIdSync } from "./allow-from-file.js";
|
|
2
2
|
import "./pairing-constants.js";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import fsSync from "node:fs";
|
|
5
3
|
import crypto from "node:crypto";
|
|
4
|
+
import fsSync from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
6
|
//#region src/channels/pairing/pairing-store.ts
|
|
7
7
|
const PAIRING_CODE_LENGTH = 8;
|
|
8
8
|
const PAIRING_CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pairing public types — extracted from `pairing-service.ts` so leaf modules
|
|
3
|
+
* (`plugins/types.adapters.ts`, etc.) can reference `PairingPendingView`
|
|
4
|
+
* without pulling the full pairing service implementation, which in turn
|
|
5
|
+
* imports `security.ts` and forms a circular cycle.
|
|
6
|
+
*/
|
|
7
|
+
export type PairingPendingView = {
|
|
8
|
+
senderId: string;
|
|
9
|
+
codeLast4: string;
|
|
10
|
+
createdAt: string;
|
|
11
|
+
lastSeenAt: string;
|
|
12
|
+
expiresAt: string;
|
|
13
|
+
isStale: boolean;
|
|
14
|
+
meta?: Record<string, string>;
|
|
15
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChannelPluginRegistry — owns the in-memory plugin map and provides typed
|
|
3
|
+
* lookup helpers.
|
|
4
|
+
*
|
|
5
|
+
* Previously this lived as one of the eight responsibilities on the 707-line
|
|
6
|
+
* `ChannelManager`. Splitting it out lets the lifecycle / heartbeat / outbound
|
|
7
|
+
* coordinators depend only on the lookup surface they need (registry +
|
|
8
|
+
* `getPlugin`), not on the full manager.
|
|
9
|
+
*/
|
|
10
|
+
import type { Config } from '../config/schema.js';
|
|
11
|
+
import type { ChannelPlugin } from './plugin-types.js';
|
|
12
|
+
export declare class ChannelPluginRegistry {
|
|
13
|
+
private readonly plugins;
|
|
14
|
+
register(plugin: ChannelPlugin): void;
|
|
15
|
+
get(id: string): ChannelPlugin | undefined;
|
|
16
|
+
has(id: string): boolean;
|
|
17
|
+
all(): ChannelPlugin[];
|
|
18
|
+
ids(): string[];
|
|
19
|
+
entries(): IterableIterator<[string, ChannelPlugin]>;
|
|
20
|
+
/** Plugin ids whose runtime currently reports connected (e.g. Telegram polling active). */
|
|
21
|
+
runningChannelIds(cfg: Config, isInitialized: (id: string) => boolean): string[];
|
|
22
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../utils/logger.js";
|
|
3
|
+
import { syncChannelPluginsFromManager } from "./plugins/registry.js";
|
|
4
|
+
//#region src/channels/plugin-registry.ts
|
|
5
|
+
init_logger();
|
|
6
|
+
const log = createLogger("ChannelPluginRegistry");
|
|
7
|
+
var ChannelPluginRegistry = class {
|
|
8
|
+
plugins = /* @__PURE__ */ new Map();
|
|
9
|
+
register(plugin) {
|
|
10
|
+
if (this.plugins.has(plugin.id)) log.warn({ channel: plugin.id }, "Channel plugin already registered, overwriting");
|
|
11
|
+
this.plugins.set(plugin.id, plugin);
|
|
12
|
+
syncChannelPluginsFromManager(this.all());
|
|
13
|
+
log.debug({ channel: plugin.id }, "Registered channel plugin");
|
|
14
|
+
}
|
|
15
|
+
get(id) {
|
|
16
|
+
return this.plugins.get(id);
|
|
17
|
+
}
|
|
18
|
+
has(id) {
|
|
19
|
+
return this.plugins.has(id);
|
|
20
|
+
}
|
|
21
|
+
all() {
|
|
22
|
+
return Array.from(this.plugins.values());
|
|
23
|
+
}
|
|
24
|
+
ids() {
|
|
25
|
+
return [...this.plugins.keys()];
|
|
26
|
+
}
|
|
27
|
+
entries() {
|
|
28
|
+
return this.plugins.entries();
|
|
29
|
+
}
|
|
30
|
+
/** Plugin ids whose runtime currently reports connected (e.g. Telegram polling active). */
|
|
31
|
+
runningChannelIds(cfg, isInitialized) {
|
|
32
|
+
const out = [];
|
|
33
|
+
for (const [id, plugin] of this.plugins) {
|
|
34
|
+
if (!isInitialized(id)) continue;
|
|
35
|
+
if (!plugin.channelIsRunning) continue;
|
|
36
|
+
if (plugin.channelIsRunning(cfg)) out.push(id);
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
//#endregion
|
|
42
|
+
export { ChannelPluginRegistry };
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=plugin-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-registry.js","names":[],"sources":["../../../src/channels/plugin-registry.ts"],"sourcesContent":["/**\n * ChannelPluginRegistry — owns the in-memory plugin map and provides typed\n * lookup helpers.\n *\n * Previously this lived as one of the eight responsibilities on the 707-line\n * `ChannelManager`. Splitting it out lets the lifecycle / heartbeat / outbound\n * coordinators depend only on the lookup surface they need (registry +\n * `getPlugin`), not on the full manager.\n */\n\nimport type { Config } from '../config/schema.js';\n\nimport type { ChannelPlugin } from './plugin-types.js';\nimport { syncChannelPluginsFromManager } from './plugins/registry.js';\nimport { createLogger } from '../utils/logger.js';\n\nconst log = createLogger('ChannelPluginRegistry');\n\nexport class ChannelPluginRegistry {\n private readonly plugins = new Map<string, ChannelPlugin>();\n\n register(plugin: ChannelPlugin): void {\n if (this.plugins.has(plugin.id)) {\n log.warn({ channel: plugin.id }, 'Channel plugin already registered, overwriting');\n }\n this.plugins.set(plugin.id, plugin);\n syncChannelPluginsFromManager(this.all());\n log.debug({ channel: plugin.id }, 'Registered channel plugin');\n }\n\n get(id: string): ChannelPlugin | undefined {\n return this.plugins.get(id);\n }\n\n has(id: string): boolean {\n return this.plugins.has(id);\n }\n\n all(): ChannelPlugin[] {\n return Array.from(this.plugins.values());\n }\n\n ids(): string[] {\n return [...this.plugins.keys()];\n }\n\n entries(): IterableIterator<[string, ChannelPlugin]> {\n return this.plugins.entries();\n }\n\n /** Plugin ids whose runtime currently reports connected (e.g. Telegram polling active). */\n runningChannelIds(cfg: Config, isInitialized: (id: string) => boolean): string[] {\n const out: string[] = [];\n for (const [id, plugin] of this.plugins) {\n if (!isInitialized(id)) continue;\n if (!plugin.channelIsRunning) continue;\n if (plugin.channelIsRunning(cfg)) out.push(id);\n }\n return out;\n }\n}\n"],"mappings":";;;;aAckD;AAElD,MAAM,MAAM,aAAa,wBAAwB;AAEjD,IAAa,wBAAb,MAAmC;CACjC,0BAA2B,IAAI,KAA4B;CAE3D,SAAS,QAA6B;AACpC,MAAI,KAAK,QAAQ,IAAI,OAAO,GAAG,CAC7B,KAAI,KAAK,EAAE,SAAS,OAAO,IAAI,EAAE,iDAAiD;AAEpF,OAAK,QAAQ,IAAI,OAAO,IAAI,OAAO;AACnC,gCAA8B,KAAK,KAAK,CAAC;AACzC,MAAI,MAAM,EAAE,SAAS,OAAO,IAAI,EAAE,4BAA4B;;CAGhE,IAAI,IAAuC;AACzC,SAAO,KAAK,QAAQ,IAAI,GAAG;;CAG7B,IAAI,IAAqB;AACvB,SAAO,KAAK,QAAQ,IAAI,GAAG;;CAG7B,MAAuB;AACrB,SAAO,MAAM,KAAK,KAAK,QAAQ,QAAQ,CAAC;;CAG1C,MAAgB;AACd,SAAO,CAAC,GAAG,KAAK,QAAQ,MAAM,CAAC;;CAGjC,UAAqD;AACnD,SAAO,KAAK,QAAQ,SAAS;;;CAI/B,kBAAkB,KAAa,eAAkD;EAC/E,MAAM,MAAgB,EAAE;AACxB,OAAK,MAAM,CAAC,IAAI,WAAW,KAAK,SAAS;AACvC,OAAI,CAAC,cAAc,GAAG,CAAE;AACxB,OAAI,CAAC,OAAO,iBAAkB;AAC9B,OAAI,OAAO,iBAAiB,IAAI,CAAE,KAAI,KAAK,GAAG;;AAEhD,SAAO"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Channel Plugin Types - Core type definitions for channel plugins
|
|
3
3
|
*/
|
|
4
|
-
import type { Config } from '../config/
|
|
4
|
+
import type { Config } from '../config/schema.js';
|
|
5
5
|
import type { MessageBus } from '../infra/bus/index.js';
|
|
6
6
|
import type { ChannelId, ChannelMeta, ChannelCapabilities } from './plugins/types.core.js';
|
|
7
7
|
import type { ChannelPairingAdapter, ChannelAllowlistAdapter, ChannelThreadingAdapter, ChannelLifecycleAdapter, ChannelHeartbeatAdapter, ChannelConfiguredBindingProvider, ChannelMessagingAdapter, ChannelDirectoryAdapter, ChannelResolverAdapter, ChannelAuthAdapter, ChannelElevatedAdapter, ChannelExecApprovalAdapter, ChannelAgentPromptAdapter, ChannelSetupWizard, ChannelCronDeliveryAdapter, ChannelCliLoginAdapter, ChannelConfigSurfaceAdapter, ChannelOnboardAdapter } from './plugins/types.adapters.js';
|