agim-cli 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1234 -0
- package/LICENSE +21 -0
- package/README.md +422 -0
- package/README.zh-CN.md +414 -0
- package/dist/cli-ui/cmd-handlers.d.ts +11 -0
- package/dist/cli-ui/cmd-handlers.d.ts.map +1 -0
- package/dist/cli-ui/cmd-handlers.js +240 -0
- package/dist/cli-ui/cmd-handlers.js.map +1 -0
- package/dist/cli-ui/config-wizard.d.ts +3 -0
- package/dist/cli-ui/config-wizard.d.ts.map +1 -0
- package/dist/cli-ui/config-wizard.js +851 -0
- package/dist/cli-ui/config-wizard.js.map +1 -0
- package/dist/cli-ui/entry-menu.d.ts +28 -0
- package/dist/cli-ui/entry-menu.d.ts.map +1 -0
- package/dist/cli-ui/entry-menu.js +50 -0
- package/dist/cli-ui/entry-menu.js.map +1 -0
- package/dist/cli-ui/env-file.d.ts +35 -0
- package/dist/cli-ui/env-file.d.ts.map +1 -0
- package/dist/cli-ui/env-file.js +163 -0
- package/dist/cli-ui/env-file.js.map +1 -0
- package/dist/cli-ui/i18n.d.ts +204 -0
- package/dist/cli-ui/i18n.d.ts.map +1 -0
- package/dist/cli-ui/i18n.js +455 -0
- package/dist/cli-ui/i18n.js.map +1 -0
- package/dist/cli-ui/lang-picker.d.ts +10 -0
- package/dist/cli-ui/lang-picker.d.ts.map +1 -0
- package/dist/cli-ui/lang-picker.js +33 -0
- package/dist/cli-ui/lang-picker.js.map +1 -0
- package/dist/cli-ui/paths.d.ts +4 -0
- package/dist/cli-ui/paths.d.ts.map +1 -0
- package/dist/cli-ui/paths.js +11 -0
- package/dist/cli-ui/paths.js.map +1 -0
- package/dist/cli-ui/prompts.d.ts +65 -0
- package/dist/cli-ui/prompts.d.ts.map +1 -0
- package/dist/cli-ui/prompts.js +125 -0
- package/dist/cli-ui/prompts.js.map +1 -0
- package/dist/cli-ui/service.d.ts +41 -0
- package/dist/cli-ui/service.d.ts.map +1 -0
- package/dist/cli-ui/service.js +241 -0
- package/dist/cli-ui/service.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1143 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/acp-server.d.ts +8 -0
- package/dist/core/acp-server.d.ts.map +1 -0
- package/dist/core/acp-server.js +266 -0
- package/dist/core/acp-server.js.map +1 -0
- package/dist/core/agent-base.d.ts +94 -0
- package/dist/core/agent-base.d.ts.map +1 -0
- package/dist/core/agent-base.js +373 -0
- package/dist/core/agent-base.js.map +1 -0
- package/dist/core/agent-cwd.d.ts +48 -0
- package/dist/core/agent-cwd.d.ts.map +1 -0
- package/dist/core/agent-cwd.js +181 -0
- package/dist/core/agent-cwd.js.map +1 -0
- package/dist/core/agent-helper.d.ts +65 -0
- package/dist/core/agent-helper.d.ts.map +1 -0
- package/dist/core/agent-helper.js +150 -0
- package/dist/core/agent-helper.js.map +1 -0
- package/dist/core/agim-paths.d.ts +10 -0
- package/dist/core/agim-paths.d.ts.map +1 -0
- package/dist/core/agim-paths.js +64 -0
- package/dist/core/agim-paths.js.map +1 -0
- package/dist/core/approval-bus.d.ts +300 -0
- package/dist/core/approval-bus.d.ts.map +1 -0
- package/dist/core/approval-bus.js +990 -0
- package/dist/core/approval-bus.js.map +1 -0
- package/dist/core/approval-router.d.ts +101 -0
- package/dist/core/approval-router.d.ts.map +1 -0
- package/dist/core/approval-router.js +540 -0
- package/dist/core/approval-router.js.map +1 -0
- package/dist/core/audit-log.d.ts +55 -0
- package/dist/core/audit-log.d.ts.map +1 -0
- package/dist/core/audit-log.js +203 -0
- package/dist/core/audit-log.js.map +1 -0
- package/dist/core/bgjob-reader.d.ts +65 -0
- package/dist/core/bgjob-reader.d.ts.map +1 -0
- package/dist/core/bgjob-reader.js +212 -0
- package/dist/core/bgjob-reader.js.map +1 -0
- package/dist/core/circuit-breaker.d.ts +37 -0
- package/dist/core/circuit-breaker.d.ts.map +1 -0
- package/dist/core/circuit-breaker.js +115 -0
- package/dist/core/circuit-breaker.js.map +1 -0
- package/dist/core/commands/agent.d.ts +4 -0
- package/dist/core/commands/agent.d.ts.map +1 -0
- package/dist/core/commands/agent.js +40 -0
- package/dist/core/commands/agent.js.map +1 -0
- package/dist/core/commands/approval.d.ts +3 -0
- package/dist/core/commands/approval.d.ts.map +1 -0
- package/dist/core/commands/approval.js +85 -0
- package/dist/core/commands/approval.js.map +1 -0
- package/dist/core/commands/audit.d.ts +3 -0
- package/dist/core/commands/audit.d.ts.map +1 -0
- package/dist/core/commands/audit.js +84 -0
- package/dist/core/commands/audit.js.map +1 -0
- package/dist/core/commands/builtin.d.ts +3 -0
- package/dist/core/commands/builtin.d.ts.map +1 -0
- package/dist/core/commands/builtin.js +304 -0
- package/dist/core/commands/builtin.js.map +1 -0
- package/dist/core/commands/cron.d.ts +3 -0
- package/dist/core/commands/cron.d.ts.map +1 -0
- package/dist/core/commands/cron.js +128 -0
- package/dist/core/commands/cron.js.map +1 -0
- package/dist/core/commands/job.d.ts +3 -0
- package/dist/core/commands/job.d.ts.map +1 -0
- package/dist/core/commands/job.js +195 -0
- package/dist/core/commands/job.js.map +1 -0
- package/dist/core/commands/memo.d.ts +3 -0
- package/dist/core/commands/memo.d.ts.map +1 -0
- package/dist/core/commands/memo.js +151 -0
- package/dist/core/commands/memo.js.map +1 -0
- package/dist/core/commands/model.d.ts +9 -0
- package/dist/core/commands/model.d.ts.map +1 -0
- package/dist/core/commands/model.js +183 -0
- package/dist/core/commands/model.js.map +1 -0
- package/dist/core/commands/plan.d.ts +3 -0
- package/dist/core/commands/plan.d.ts.map +1 -0
- package/dist/core/commands/plan.js +75 -0
- package/dist/core/commands/plan.js.map +1 -0
- package/dist/core/commands/remind.d.ts +3 -0
- package/dist/core/commands/remind.d.ts.map +1 -0
- package/dist/core/commands/remind.js +271 -0
- package/dist/core/commands/remind.js.map +1 -0
- package/dist/core/commands/router.d.ts +3 -0
- package/dist/core/commands/router.d.ts.map +1 -0
- package/dist/core/commands/router.js +71 -0
- package/dist/core/commands/router.js.map +1 -0
- package/dist/core/commands/sessions.d.ts +3 -0
- package/dist/core/commands/sessions.d.ts.map +1 -0
- package/dist/core/commands/sessions.js +88 -0
- package/dist/core/commands/sessions.js.map +1 -0
- package/dist/core/commands/stats.d.ts +3 -0
- package/dist/core/commands/stats.d.ts.map +1 -0
- package/dist/core/commands/stats.js +73 -0
- package/dist/core/commands/stats.js.map +1 -0
- package/dist/core/commands/think.d.ts +3 -0
- package/dist/core/commands/think.d.ts.map +1 -0
- package/dist/core/commands/think.js +28 -0
- package/dist/core/commands/think.js.map +1 -0
- package/dist/core/commands/workspaces.d.ts +3 -0
- package/dist/core/commands/workspaces.d.ts.map +1 -0
- package/dist/core/commands/workspaces.js +47 -0
- package/dist/core/commands/workspaces.js.map +1 -0
- package/dist/core/config-schema.d.ts +60 -0
- package/dist/core/config-schema.d.ts.map +1 -0
- package/dist/core/config-schema.js +75 -0
- package/dist/core/config-schema.js.map +1 -0
- package/dist/core/coord-systems.d.ts +65 -0
- package/dist/core/coord-systems.d.ts.map +1 -0
- package/dist/core/coord-systems.js +229 -0
- package/dist/core/coord-systems.js.map +1 -0
- package/dist/core/cron.d.ts +29 -0
- package/dist/core/cron.d.ts.map +1 -0
- package/dist/core/cron.js +184 -0
- package/dist/core/cron.js.map +1 -0
- package/dist/core/event-bus.d.ts +80 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +62 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/intent-llm.d.ts +27 -0
- package/dist/core/intent-llm.d.ts.map +1 -0
- package/dist/core/intent-llm.js +170 -0
- package/dist/core/intent-llm.js.map +1 -0
- package/dist/core/intent.d.ts +12 -0
- package/dist/core/intent.d.ts.map +1 -0
- package/dist/core/intent.js +187 -0
- package/dist/core/intent.js.map +1 -0
- package/dist/core/job-board.d.ts +82 -0
- package/dist/core/job-board.d.ts.map +1 -0
- package/dist/core/job-board.js +379 -0
- package/dist/core/job-board.js.map +1 -0
- package/dist/core/location-context.d.ts +32 -0
- package/dist/core/location-context.d.ts.map +1 -0
- package/dist/core/location-context.js +69 -0
- package/dist/core/location-context.js.map +1 -0
- package/dist/core/location-token.d.ts +57 -0
- package/dist/core/location-token.d.ts.map +1 -0
- package/dist/core/location-token.js +128 -0
- package/dist/core/location-token.js.map +1 -0
- package/dist/core/logger.d.ts +6 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +54 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/memo-rpc.d.ts +13 -0
- package/dist/core/memo-rpc.d.ts.map +1 -0
- package/dist/core/memo-rpc.js +288 -0
- package/dist/core/memo-rpc.js.map +1 -0
- package/dist/core/memos.d.ts +163 -0
- package/dist/core/memos.d.ts.map +1 -0
- package/dist/core/memos.js +502 -0
- package/dist/core/memos.js.map +1 -0
- package/dist/core/metrics.d.ts +55 -0
- package/dist/core/metrics.d.ts.map +1 -0
- package/dist/core/metrics.js +291 -0
- package/dist/core/metrics.js.map +1 -0
- package/dist/core/onboarding.d.ts +99 -0
- package/dist/core/onboarding.d.ts.map +1 -0
- package/dist/core/onboarding.js +426 -0
- package/dist/core/onboarding.js.map +1 -0
- package/dist/core/pending-reminder.d.ts +25 -0
- package/dist/core/pending-reminder.d.ts.map +1 -0
- package/dist/core/pending-reminder.js +53 -0
- package/dist/core/pending-reminder.js.map +1 -0
- package/dist/core/rate-limiter.d.ts +44 -0
- package/dist/core/rate-limiter.d.ts.map +1 -0
- package/dist/core/rate-limiter.js +115 -0
- package/dist/core/rate-limiter.js.map +1 -0
- package/dist/core/registry.d.ts +32 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +126 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/remind-intent.d.ts +25 -0
- package/dist/core/remind-intent.d.ts.map +1 -0
- package/dist/core/remind-intent.js +196 -0
- package/dist/core/remind-intent.js.map +1 -0
- package/dist/core/reminder-rpc.d.ts +17 -0
- package/dist/core/reminder-rpc.d.ts.map +1 -0
- package/dist/core/reminder-rpc.js +169 -0
- package/dist/core/reminder-rpc.js.map +1 -0
- package/dist/core/reminders.d.ts +159 -0
- package/dist/core/reminders.d.ts.map +1 -0
- package/dist/core/reminders.js +977 -0
- package/dist/core/reminders.js.map +1 -0
- package/dist/core/router.d.ts +55 -0
- package/dist/core/router.d.ts.map +1 -0
- package/dist/core/router.js +497 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/schedule.d.ts +65 -0
- package/dist/core/schedule.d.ts.map +1 -0
- package/dist/core/schedule.js +323 -0
- package/dist/core/schedule.js.map +1 -0
- package/dist/core/session.d.ts +182 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +807 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/sqlite-helper.d.ts +37 -0
- package/dist/core/sqlite-helper.d.ts.map +1 -0
- package/dist/core/sqlite-helper.js +79 -0
- package/dist/core/sqlite-helper.js.map +1 -0
- package/dist/core/transcribe.d.ts +25 -0
- package/dist/core/transcribe.d.ts.map +1 -0
- package/dist/core/transcribe.js +217 -0
- package/dist/core/transcribe.js.map +1 -0
- package/dist/core/types.d.ts +360 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +3 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/workspace.d.ts +67 -0
- package/dist/core/workspace.d.ts.map +1 -0
- package/dist/core/workspace.js +113 -0
- package/dist/core/workspace.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/agents/acp/acp-adapter.d.ts +16 -0
- package/dist/plugins/agents/acp/acp-adapter.d.ts.map +1 -0
- package/dist/plugins/agents/acp/acp-adapter.js +49 -0
- package/dist/plugins/agents/acp/acp-adapter.js.map +1 -0
- package/dist/plugins/agents/acp/acp-client.d.ts +32 -0
- package/dist/plugins/agents/acp/acp-client.d.ts.map +1 -0
- package/dist/plugins/agents/acp/acp-client.js +177 -0
- package/dist/plugins/agents/acp/acp-client.js.map +1 -0
- package/dist/plugins/agents/acp/discovery.d.ts +19 -0
- package/dist/plugins/agents/acp/discovery.d.ts.map +1 -0
- package/dist/plugins/agents/acp/discovery.js +111 -0
- package/dist/plugins/agents/acp/discovery.js.map +1 -0
- package/dist/plugins/agents/acp/index.d.ts +4 -0
- package/dist/plugins/agents/acp/index.d.ts.map +1 -0
- package/dist/plugins/agents/acp/index.js +4 -0
- package/dist/plugins/agents/acp/index.js.map +1 -0
- package/dist/plugins/agents/acp/types.d.ts +62 -0
- package/dist/plugins/agents/acp/types.d.ts.map +1 -0
- package/dist/plugins/agents/acp/types.js +5 -0
- package/dist/plugins/agents/acp/types.js.map +1 -0
- package/dist/plugins/agents/claude-code/index.d.ts +25 -0
- package/dist/plugins/agents/claude-code/index.d.ts.map +1 -0
- package/dist/plugins/agents/claude-code/index.js +184 -0
- package/dist/plugins/agents/claude-code/index.js.map +1 -0
- package/dist/plugins/agents/claude-code/mcp-approval-server.d.ts +59 -0
- package/dist/plugins/agents/claude-code/mcp-approval-server.d.ts.map +1 -0
- package/dist/plugins/agents/claude-code/mcp-approval-server.js +645 -0
- package/dist/plugins/agents/claude-code/mcp-approval-server.js.map +1 -0
- package/dist/plugins/agents/codex/build-mcp-cli-args.d.ts +28 -0
- package/dist/plugins/agents/codex/build-mcp-cli-args.d.ts.map +1 -0
- package/dist/plugins/agents/codex/build-mcp-cli-args.js +74 -0
- package/dist/plugins/agents/codex/build-mcp-cli-args.js.map +1 -0
- package/dist/plugins/agents/codex/index.d.ts +53 -0
- package/dist/plugins/agents/codex/index.d.ts.map +1 -0
- package/dist/plugins/agents/codex/index.js +341 -0
- package/dist/plugins/agents/codex/index.js.map +1 -0
- package/dist/plugins/agents/copilot/index.d.ts +35 -0
- package/dist/plugins/agents/copilot/index.d.ts.map +1 -0
- package/dist/plugins/agents/copilot/index.js +182 -0
- package/dist/plugins/agents/copilot/index.js.map +1 -0
- package/dist/plugins/agents/opencode/ensure-mcp-config.d.ts +11 -0
- package/dist/plugins/agents/opencode/ensure-mcp-config.d.ts.map +1 -0
- package/dist/plugins/agents/opencode/ensure-mcp-config.js +100 -0
- package/dist/plugins/agents/opencode/ensure-mcp-config.js.map +1 -0
- package/dist/plugins/agents/opencode/index.d.ts +5 -0
- package/dist/plugins/agents/opencode/index.d.ts.map +1 -0
- package/dist/plugins/agents/opencode/index.js +30 -0
- package/dist/plugins/agents/opencode/index.js.map +1 -0
- package/dist/plugins/agents/opencode/opencode-http-adapter.d.ts +166 -0
- package/dist/plugins/agents/opencode/opencode-http-adapter.d.ts.map +1 -0
- package/dist/plugins/agents/opencode/opencode-http-adapter.js +682 -0
- package/dist/plugins/agents/opencode/opencode-http-adapter.js.map +1 -0
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.d.ts +32 -0
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.d.ts.map +1 -0
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.js +137 -0
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.js.map +1 -0
- package/dist/plugins/agents/opencode/serve-manager.d.ts +27 -0
- package/dist/plugins/agents/opencode/serve-manager.d.ts.map +1 -0
- package/dist/plugins/agents/opencode/serve-manager.js +194 -0
- package/dist/plugins/agents/opencode/serve-manager.js.map +1 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.d.ts +57 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.js +409 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.js.map +1 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-client.d.ts +48 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-client.d.ts.map +1 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-client.js +236 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-client.js.map +1 -0
- package/dist/plugins/messengers/dingtalk/index.d.ts +3 -0
- package/dist/plugins/messengers/dingtalk/index.d.ts.map +1 -0
- package/dist/plugins/messengers/dingtalk/index.js +3 -0
- package/dist/plugins/messengers/dingtalk/index.js.map +1 -0
- package/dist/plugins/messengers/dingtalk/link-coords.d.ts +23 -0
- package/dist/plugins/messengers/dingtalk/link-coords.d.ts.map +1 -0
- package/dist/plugins/messengers/dingtalk/link-coords.js +89 -0
- package/dist/plugins/messengers/dingtalk/link-coords.js.map +1 -0
- package/dist/plugins/messengers/dingtalk/media-store.d.ts +16 -0
- package/dist/plugins/messengers/dingtalk/media-store.d.ts.map +1 -0
- package/dist/plugins/messengers/dingtalk/media-store.js +77 -0
- package/dist/plugins/messengers/dingtalk/media-store.js.map +1 -0
- package/dist/plugins/messengers/dingtalk/types.d.ts +82 -0
- package/dist/plugins/messengers/dingtalk/types.d.ts.map +1 -0
- package/dist/plugins/messengers/dingtalk/types.js +14 -0
- package/dist/plugins/messengers/dingtalk/types.js.map +1 -0
- package/dist/plugins/messengers/discord/discord-adapter.d.ts +21 -0
- package/dist/plugins/messengers/discord/discord-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/discord/discord-adapter.js +238 -0
- package/dist/plugins/messengers/discord/discord-adapter.js.map +1 -0
- package/dist/plugins/messengers/discord/index.d.ts +4 -0
- package/dist/plugins/messengers/discord/index.d.ts.map +1 -0
- package/dist/plugins/messengers/discord/index.js +4 -0
- package/dist/plugins/messengers/discord/index.js.map +1 -0
- package/dist/plugins/messengers/discord/markdown-to-discord.d.ts +11 -0
- package/dist/plugins/messengers/discord/markdown-to-discord.d.ts.map +1 -0
- package/dist/plugins/messengers/discord/markdown-to-discord.js +59 -0
- package/dist/plugins/messengers/discord/markdown-to-discord.js.map +1 -0
- package/dist/plugins/messengers/discord/types.d.ts +9 -0
- package/dist/plugins/messengers/discord/types.d.ts.map +1 -0
- package/dist/plugins/messengers/discord/types.js +3 -0
- package/dist/plugins/messengers/discord/types.js.map +1 -0
- package/dist/plugins/messengers/email/email-adapter.d.ts +33 -0
- package/dist/plugins/messengers/email/email-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/email/email-adapter.js +137 -0
- package/dist/plugins/messengers/email/email-adapter.js.map +1 -0
- package/dist/plugins/messengers/feishu/card-builder.d.ts +23 -0
- package/dist/plugins/messengers/feishu/card-builder.d.ts.map +1 -0
- package/dist/plugins/messengers/feishu/card-builder.js +89 -0
- package/dist/plugins/messengers/feishu/card-builder.js.map +1 -0
- package/dist/plugins/messengers/feishu/feishu-adapter.d.ts +23 -0
- package/dist/plugins/messengers/feishu/feishu-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/feishu/feishu-adapter.js +250 -0
- package/dist/plugins/messengers/feishu/feishu-adapter.js.map +1 -0
- package/dist/plugins/messengers/feishu/feishu-client.d.ts +43 -0
- package/dist/plugins/messengers/feishu/feishu-client.d.ts.map +1 -0
- package/dist/plugins/messengers/feishu/feishu-client.js +118 -0
- package/dist/plugins/messengers/feishu/feishu-client.js.map +1 -0
- package/dist/plugins/messengers/feishu/index.d.ts +4 -0
- package/dist/plugins/messengers/feishu/index.d.ts.map +1 -0
- package/dist/plugins/messengers/feishu/index.js +4 -0
- package/dist/plugins/messengers/feishu/index.js.map +1 -0
- package/dist/plugins/messengers/feishu/types.d.ts +113 -0
- package/dist/plugins/messengers/feishu/types.d.ts.map +1 -0
- package/dist/plugins/messengers/feishu/types.js +4 -0
- package/dist/plugins/messengers/feishu/types.js.map +1 -0
- package/dist/plugins/messengers/telegram/index.d.ts +4 -0
- package/dist/plugins/messengers/telegram/index.d.ts.map +1 -0
- package/dist/plugins/messengers/telegram/index.js +4 -0
- package/dist/plugins/messengers/telegram/index.js.map +1 -0
- package/dist/plugins/messengers/telegram/markdown-to-html.d.ts +5 -0
- package/dist/plugins/messengers/telegram/markdown-to-html.d.ts.map +1 -0
- package/dist/plugins/messengers/telegram/markdown-to-html.js +186 -0
- package/dist/plugins/messengers/telegram/markdown-to-html.js.map +1 -0
- package/dist/plugins/messengers/telegram/media-download.d.ts +59 -0
- package/dist/plugins/messengers/telegram/media-download.d.ts.map +1 -0
- package/dist/plugins/messengers/telegram/media-download.js +228 -0
- package/dist/plugins/messengers/telegram/media-download.js.map +1 -0
- package/dist/plugins/messengers/telegram/telegram-adapter.d.ts +77 -0
- package/dist/plugins/messengers/telegram/telegram-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/telegram/telegram-adapter.js +880 -0
- package/dist/plugins/messengers/telegram/telegram-adapter.js.map +1 -0
- package/dist/plugins/messengers/telegram/types.d.ts +47 -0
- package/dist/plugins/messengers/telegram/types.d.ts.map +1 -0
- package/dist/plugins/messengers/telegram/types.js +3 -0
- package/dist/plugins/messengers/telegram/types.js.map +1 -0
- package/dist/plugins/messengers/wechat/context-store.d.ts +18 -0
- package/dist/plugins/messengers/wechat/context-store.d.ts.map +1 -0
- package/dist/plugins/messengers/wechat/context-store.js +105 -0
- package/dist/plugins/messengers/wechat/context-store.js.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-adapter.d.ts +71 -0
- package/dist/plugins/messengers/wechat/ilink-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-adapter.js +664 -0
- package/dist/plugins/messengers/wechat/ilink-adapter.js.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-client.d.ts +75 -0
- package/dist/plugins/messengers/wechat/ilink-client.d.ts.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-client.js +331 -0
- package/dist/plugins/messengers/wechat/ilink-client.js.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-types.d.ts +181 -0
- package/dist/plugins/messengers/wechat/ilink-types.d.ts.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-types.js +22 -0
- package/dist/plugins/messengers/wechat/ilink-types.js.map +1 -0
- package/dist/plugins/messengers/wechat/media-download.d.ts +32 -0
- package/dist/plugins/messengers/wechat/media-download.d.ts.map +1 -0
- package/dist/plugins/messengers/wechat/media-download.js +78 -0
- package/dist/plugins/messengers/wechat/media-download.js.map +1 -0
- package/dist/scripts/migrate-gcj02-to-wgs84.d.ts +3 -0
- package/dist/scripts/migrate-gcj02-to-wgs84.d.ts.map +1 -0
- package/dist/scripts/migrate-gcj02-to-wgs84.js +52 -0
- package/dist/scripts/migrate-gcj02-to-wgs84.js.map +1 -0
- package/dist/utils/backoff.d.ts +35 -0
- package/dist/utils/backoff.d.ts.map +1 -0
- package/dist/utils/backoff.js +59 -0
- package/dist/utils/backoff.js.map +1 -0
- package/dist/utils/cross-platform.d.ts +26 -0
- package/dist/utils/cross-platform.d.ts.map +1 -0
- package/dist/utils/cross-platform.js +58 -0
- package/dist/utils/cross-platform.js.map +1 -0
- package/dist/utils/message-split.d.ts +14 -0
- package/dist/utils/message-split.d.ts.map +1 -0
- package/dist/utils/message-split.js +65 -0
- package/dist/utils/message-split.js.map +1 -0
- package/dist/utils/safe-equal.d.ts +2 -0
- package/dist/utils/safe-equal.d.ts.map +1 -0
- package/dist/utils/safe-equal.js +11 -0
- package/dist/utils/safe-equal.js.map +1 -0
- package/dist/web/public/_app.js +196 -0
- package/dist/web/public/index.html +936 -0
- package/dist/web/public/loc.html +305 -0
- package/dist/web/public/login.html +106 -0
- package/dist/web/public/memos.html +271 -0
- package/dist/web/public/reminders.html +234 -0
- package/dist/web/public/settings.html +1355 -0
- package/dist/web/public/tasks.html +1835 -0
- package/dist/web/server.d.ts +12 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +2399 -0
- package/dist/web/server.js.map +1 -0
- package/package.json +92 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
// Discord Bot API Adapter using discord.js
|
|
2
|
+
// Implements MessengerAdapter interface with typing indicator support
|
|
3
|
+
import { Client, GatewayIntentBits, Partials, ChannelType, } from 'discord.js';
|
|
4
|
+
import { markdownToDiscord } from './markdown-to-discord.js';
|
|
5
|
+
import { splitMessage } from '../../../utils/message-split.js';
|
|
6
|
+
import { logger as rootLogger } from '../../../core/logger.js';
|
|
7
|
+
const log = rootLogger.child({ component: 'discord' });
|
|
8
|
+
// Discord message limit is 2000 characters
|
|
9
|
+
const DISCORD_MAX_LENGTH = 2000;
|
|
10
|
+
export class DiscordAdapter {
|
|
11
|
+
name = 'discord';
|
|
12
|
+
client = null;
|
|
13
|
+
config = null;
|
|
14
|
+
messageHandler;
|
|
15
|
+
typingIntervals = new Map();
|
|
16
|
+
/** L7: companion AbortController per typing thread. Lets the periodic
|
|
17
|
+
* refresh callback bail BEFORE invoking sendTyping when stop() has
|
|
18
|
+
* fired, instead of racing against client.destroy(). */
|
|
19
|
+
typingAbortControllers = new Map();
|
|
20
|
+
async start() {
|
|
21
|
+
// Load config
|
|
22
|
+
const { readFile } = await import('node:fs/promises');
|
|
23
|
+
const { join } = await import('node:path');
|
|
24
|
+
const { AGIM_HOME } = await import('../../../core/agim-paths.js');
|
|
25
|
+
const configPath = join(AGIM_HOME, 'config.json');
|
|
26
|
+
try {
|
|
27
|
+
const data = await readFile(configPath, 'utf-8');
|
|
28
|
+
const config = JSON.parse(data);
|
|
29
|
+
this.config = config.discord;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
throw new Error('Discord config not found. Run "im-hub config discord" first.');
|
|
33
|
+
}
|
|
34
|
+
if (!this.config?.botToken) {
|
|
35
|
+
throw new Error('Discord bot token not configured. Run "im-hub config discord" first.');
|
|
36
|
+
}
|
|
37
|
+
// Initialize Discord client with required intents
|
|
38
|
+
this.client = new Client({
|
|
39
|
+
intents: [
|
|
40
|
+
GatewayIntentBits.Guilds,
|
|
41
|
+
GatewayIntentBits.GuildMessages,
|
|
42
|
+
GatewayIntentBits.MessageContent, // Privileged intent - must enable in Developer Portal
|
|
43
|
+
GatewayIntentBits.DirectMessages, // For DM support
|
|
44
|
+
],
|
|
45
|
+
partials: [
|
|
46
|
+
Partials.Channel, // Required for DM support
|
|
47
|
+
Partials.Message,
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
// Ready event
|
|
51
|
+
this.client.on('ready', (client) => {
|
|
52
|
+
log.info({ user: client.user.tag, guilds: client.guilds.cache.size }, `Discord bot logged in as ${client.user.tag}`);
|
|
53
|
+
});
|
|
54
|
+
// Set up message handler
|
|
55
|
+
this.client.on('messageCreate', async (message) => {
|
|
56
|
+
await this.handleDiscordMessage(message);
|
|
57
|
+
});
|
|
58
|
+
// Error handling
|
|
59
|
+
this.client.on('error', (error) => {
|
|
60
|
+
log.error({ err: error.message }, 'Discord client error');
|
|
61
|
+
});
|
|
62
|
+
this.client.on('warn', (warning) => {
|
|
63
|
+
log.warn({ warning }, 'Discord client warning');
|
|
64
|
+
});
|
|
65
|
+
// Login to Discord
|
|
66
|
+
await this.client.login(this.config.botToken);
|
|
67
|
+
log.info('Discord adapter started');
|
|
68
|
+
}
|
|
69
|
+
async stop() {
|
|
70
|
+
// L7: abort first (signal in-flight refresh callbacks to bail) then
|
|
71
|
+
// clearInterval (prevent new ticks). Doing it in the other order would
|
|
72
|
+
// leave one tick that already entered the callback racing with
|
|
73
|
+
// client.destroy(); even though sendTyping errors are caught, the
|
|
74
|
+
// log line is noise and the API call wastes a request.
|
|
75
|
+
for (const ac of this.typingAbortControllers.values()) {
|
|
76
|
+
ac.abort();
|
|
77
|
+
}
|
|
78
|
+
this.typingAbortControllers.clear();
|
|
79
|
+
for (const interval of this.typingIntervals.values()) {
|
|
80
|
+
clearInterval(interval);
|
|
81
|
+
}
|
|
82
|
+
this.typingIntervals.clear();
|
|
83
|
+
if (this.client) {
|
|
84
|
+
this.client.destroy();
|
|
85
|
+
this.client = null;
|
|
86
|
+
}
|
|
87
|
+
log.info('Discord adapter stopped');
|
|
88
|
+
}
|
|
89
|
+
onMessage(handler) {
|
|
90
|
+
this.messageHandler = handler;
|
|
91
|
+
}
|
|
92
|
+
async sendMessage(threadId, text) {
|
|
93
|
+
if (!this.client) {
|
|
94
|
+
throw new Error('Discord adapter not started');
|
|
95
|
+
}
|
|
96
|
+
const channel = await this.fetchSendableChannel(threadId);
|
|
97
|
+
if (!channel) {
|
|
98
|
+
throw new Error(`Channel ${threadId} not found or not text-based`);
|
|
99
|
+
}
|
|
100
|
+
// Convert markdown and split into chunks
|
|
101
|
+
const discordText = markdownToDiscord(text);
|
|
102
|
+
const chunks = splitMessage(discordText, {
|
|
103
|
+
maxLength: DISCORD_MAX_LENGTH,
|
|
104
|
+
addContinuationMarker: false,
|
|
105
|
+
});
|
|
106
|
+
for (const chunk of chunks) {
|
|
107
|
+
await channel.send(chunk);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async sendTyping(threadId, isTyping) {
|
|
111
|
+
if (!this.client) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (isTyping) {
|
|
115
|
+
const channel = await this.fetchSendableChannel(threadId);
|
|
116
|
+
if (!channel) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// Send initial typing indicator
|
|
120
|
+
try {
|
|
121
|
+
await channel.sendTyping();
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Ignore errors during typing
|
|
125
|
+
}
|
|
126
|
+
// Clear any existing interval + abort signal — both per-thread.
|
|
127
|
+
const existing = this.typingIntervals.get(threadId);
|
|
128
|
+
if (existing)
|
|
129
|
+
clearInterval(existing);
|
|
130
|
+
const existingAc = this.typingAbortControllers.get(threadId);
|
|
131
|
+
if (existingAc)
|
|
132
|
+
existingAc.abort();
|
|
133
|
+
// Discord typing indicator lasts ~10 seconds, refresh every 8 seconds.
|
|
134
|
+
// L7: AbortController gates each tick — when stop() (or a subsequent
|
|
135
|
+
// sendTyping(false)) aborts, in-flight callbacks bail early instead
|
|
136
|
+
// of racing client.destroy().
|
|
137
|
+
const ac = new AbortController();
|
|
138
|
+
const interval = setInterval(async () => {
|
|
139
|
+
if (ac.signal.aborted)
|
|
140
|
+
return;
|
|
141
|
+
try {
|
|
142
|
+
await channel.sendTyping();
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Ignore errors during typing refresh
|
|
146
|
+
}
|
|
147
|
+
}, 8000);
|
|
148
|
+
this.typingIntervals.set(threadId, interval);
|
|
149
|
+
this.typingAbortControllers.set(threadId, ac);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// Clear the refresh interval + abort signal
|
|
153
|
+
const interval = this.typingIntervals.get(threadId);
|
|
154
|
+
if (interval) {
|
|
155
|
+
clearInterval(interval);
|
|
156
|
+
this.typingIntervals.delete(threadId);
|
|
157
|
+
}
|
|
158
|
+
const ac = this.typingAbortControllers.get(threadId);
|
|
159
|
+
if (ac) {
|
|
160
|
+
ac.abort();
|
|
161
|
+
this.typingAbortControllers.delete(threadId);
|
|
162
|
+
}
|
|
163
|
+
// Note: Discord has no "cancel typing" API - it just expires naturally
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// ============================================
|
|
167
|
+
// Internal methods
|
|
168
|
+
// ============================================
|
|
169
|
+
async fetchSendableChannel(threadId) {
|
|
170
|
+
if (!this.client)
|
|
171
|
+
return null;
|
|
172
|
+
const channel = await this.client.channels.fetch(threadId).catch(() => null);
|
|
173
|
+
if (!channel)
|
|
174
|
+
return null;
|
|
175
|
+
if (channel.type === ChannelType.GuildText || channel.type === ChannelType.DM) {
|
|
176
|
+
return channel;
|
|
177
|
+
}
|
|
178
|
+
// Also support announcement/thread channels
|
|
179
|
+
if (channel.isTextBased() && 'send' in channel) {
|
|
180
|
+
return channel;
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
async handleDiscordMessage(message) {
|
|
185
|
+
// Ignore bot messages (including our own)
|
|
186
|
+
if (message.author.bot) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
// Guild whitelist filter
|
|
190
|
+
if (this.config?.allowedGuilds?.length && message.guildId) {
|
|
191
|
+
if (!this.config.allowedGuilds.includes(message.guildId)) {
|
|
192
|
+
log.debug({ guildId: message.guildId }, 'Message from non-whitelisted guild, ignoring');
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// Channel whitelist filter
|
|
197
|
+
if (this.config?.allowedChannels?.length) {
|
|
198
|
+
if (!this.config.allowedChannels.includes(message.channelId)) {
|
|
199
|
+
log.debug({ channelId: message.channelId }, 'Message from non-whitelisted channel, ignoring');
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// Skip empty messages (e.g. image-only, embed-only)
|
|
204
|
+
if (!message.content && !message.attachments.size) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (!this.messageHandler) {
|
|
208
|
+
log.debug('No message handler registered');
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
const msg = {
|
|
213
|
+
id: message.id,
|
|
214
|
+
threadId: message.channelId,
|
|
215
|
+
userId: message.author.id,
|
|
216
|
+
text: message.content || '',
|
|
217
|
+
timestamp: message.createdAt,
|
|
218
|
+
channelId: this.config?.channelId || 'default',
|
|
219
|
+
};
|
|
220
|
+
const msgCtx = {
|
|
221
|
+
message: msg,
|
|
222
|
+
platform: 'discord',
|
|
223
|
+
channelId: this.config?.channelId || 'default',
|
|
224
|
+
};
|
|
225
|
+
log.debug({ threadId: msg.threadId, userId: msg.userId }, 'Calling message handler');
|
|
226
|
+
await this.messageHandler(msgCtx);
|
|
227
|
+
log.debug({ threadId: msg.threadId }, 'Message handler completed');
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
231
|
+
const stack = err instanceof Error ? err.stack : undefined;
|
|
232
|
+
log.error({ err: errMsg, stack }, 'Error in message handler');
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// Singleton instance
|
|
237
|
+
export const discordAdapter = new DiscordAdapter();
|
|
238
|
+
//# sourceMappingURL=discord-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discord-adapter.js","sourceRoot":"","sources":["../../../../src/plugins/messengers/discord/discord-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/plugins/messengers/discord/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/plugins/messengers/discord/index.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAE1B,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAErE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert standard Markdown to Discord-compatible Markdown.
|
|
3
|
+
*
|
|
4
|
+
* Discord already supports most GFM, so the main job here is:
|
|
5
|
+
* 1. Strip unsupported HTML tags (Discord ignores them)
|
|
6
|
+
* 2. Convert <b>/<i>/<s> to Discord markdown equivalents
|
|
7
|
+
* 3. Ensure code blocks are preserved
|
|
8
|
+
* 4. Convert headings to bold (Discord doesn't render # in regular messages)
|
|
9
|
+
*/
|
|
10
|
+
export declare function markdownToDiscord(markdown: string): string;
|
|
11
|
+
//# sourceMappingURL=markdown-to-discord.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-to-discord.d.ts","sourceRoot":"","sources":["../../../../src/plugins/messengers/discord/markdown-to-discord.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA4D1D"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Markdown to Discord format converter
|
|
2
|
+
// Discord natively supports: **bold**, *italic*, ~~strikethrough~~, `code`, ```code blocks```, > blockquote
|
|
3
|
+
// For long messages, we can use Embeds for richer formatting
|
|
4
|
+
/**
|
|
5
|
+
* Convert standard Markdown to Discord-compatible Markdown.
|
|
6
|
+
*
|
|
7
|
+
* Discord already supports most GFM, so the main job here is:
|
|
8
|
+
* 1. Strip unsupported HTML tags (Discord ignores them)
|
|
9
|
+
* 2. Convert <b>/<i>/<s> to Discord markdown equivalents
|
|
10
|
+
* 3. Ensure code blocks are preserved
|
|
11
|
+
* 4. Convert headings to bold (Discord doesn't render # in regular messages)
|
|
12
|
+
*/
|
|
13
|
+
export function markdownToDiscord(markdown) {
|
|
14
|
+
let result = markdown;
|
|
15
|
+
// Convert HTML bold/strong to Discord **bold**
|
|
16
|
+
result = result.replace(/<\/?(?:b|strong)>/gi, '**');
|
|
17
|
+
// Convert HTML italic/em to Discord *italic*
|
|
18
|
+
result = result.replace(/<\/?(?:i|em)>/gi, '*');
|
|
19
|
+
// Convert HTML strikethrough to Discord ~~strike~~
|
|
20
|
+
result = result.replace(/<\/?(?:s|del|strike)>/gi, '~~');
|
|
21
|
+
// Convert HTML underline to Discord __underline__
|
|
22
|
+
result = result.replace(/<\/?(?:u|ins)>/gi, '__');
|
|
23
|
+
// Convert HTML code to Discord `code`
|
|
24
|
+
result = result.replace(/<code>([^<]*)<\/code>/gi, '`$1`');
|
|
25
|
+
// Convert HTML links to Discord links
|
|
26
|
+
result = result.replace(/<a[^>]*href="([^"]*)"[^>]*>([^<]*)<\/a>/gi, '[$2]($1)');
|
|
27
|
+
// Convert HTML lists to plain text bullets
|
|
28
|
+
result = result.replace(/<ul[^>]*>([\s\S]*?)<\/ul>/gi, '\n$1');
|
|
29
|
+
result = result.replace(/<ol[^>]*>([\s\S]*?)<\/ol>/gi, '\n$1');
|
|
30
|
+
result = result.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, '- $1\n');
|
|
31
|
+
// Convert HTML blockquotes to Discord > blockquote
|
|
32
|
+
result = result.replace(/<blockquote[^>]*>([\s\S]*?)<\/blockquote>/gi, (_match, content) => {
|
|
33
|
+
return content
|
|
34
|
+
.split('\n')
|
|
35
|
+
.map((line) => `> ${line}`)
|
|
36
|
+
.join('\n');
|
|
37
|
+
});
|
|
38
|
+
// Convert headings (# syntax) to bold text for regular messages
|
|
39
|
+
// (Discord doesn't render heading syntax in normal messages)
|
|
40
|
+
result = result.replace(/^(#{1,6})\s+(.+)$/gm, (_match, _hashes, text) => {
|
|
41
|
+
return `**${text}**`;
|
|
42
|
+
});
|
|
43
|
+
// Convert <hr> to separator
|
|
44
|
+
result = result.replace(/<hr\s*\/?>/gi, '\n---\n');
|
|
45
|
+
// Convert <br> to newline
|
|
46
|
+
result = result.replace(/<br\s*\/?>/gi, '\n');
|
|
47
|
+
// Strip remaining HTML tags
|
|
48
|
+
result = result.replace(/<\/?[a-zA-Z][^>]*>/g, '');
|
|
49
|
+
// Decode common HTML entities
|
|
50
|
+
result = result.replace(/&/g, '&');
|
|
51
|
+
result = result.replace(/</g, '<');
|
|
52
|
+
result = result.replace(/>/g, '>');
|
|
53
|
+
result = result.replace(/"/g, '"');
|
|
54
|
+
result = result.replace(/'/g, "'");
|
|
55
|
+
// Clean up excess blank lines
|
|
56
|
+
result = result.replace(/\n{3,}/g, '\n\n');
|
|
57
|
+
return result.trim();
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=markdown-to-discord.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-to-discord.js","sourceRoot":"","sources":["../../../../src/plugins/messengers/discord/markdown-to-discord.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,4GAA4G;AAC5G,6DAA6D;AAE7D;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,IAAI,MAAM,GAAG,QAAQ,CAAA;IAErB,+CAA+C;IAC/C,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,qBAAqB,EAAE,IAAI,CAAC,CAAA;IAEpD,6CAA6C;IAC7C,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAA;IAE/C,mDAAmD;IACnD,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,yBAAyB,EAAE,IAAI,CAAC,CAAA;IAExD,kDAAkD;IAClD,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAA;IAEjD,sCAAsC;IACtC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,yBAAyB,EAAE,MAAM,CAAC,CAAA;IAE1D,sCAAsC;IACtC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,2CAA2C,EAAE,UAAU,CAAC,CAAA;IAEhF,2CAA2C;IAC3C,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAA;IAC9D,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAA;IAC9D,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,6BAA6B,EAAE,QAAQ,CAAC,CAAA;IAEhE,mDAAmD;IACnD,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,6CAA6C,EAAE,CAAC,MAAM,EAAE,OAAe,EAAE,EAAE;QACjG,OAAO,OAAO;aACX,KAAK,CAAC,IAAI,CAAC;aACX,GAAG,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;aAClC,IAAI,CAAC,IAAI,CAAC,CAAA;IACf,CAAC,CAAC,CAAA;IAEF,gEAAgE;IAChE,6DAA6D;IAC7D,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,qBAAqB,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QACvE,OAAO,KAAK,IAAI,IAAI,CAAA;IACtB,CAAC,CAAC,CAAA;IAEF,4BAA4B;IAC5B,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,cAAc,EAAE,SAAS,CAAC,CAAA;IAElD,0BAA0B;IAC1B,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,CAAA;IAE7C,4BAA4B;IAC5B,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,qBAAqB,EAAE,EAAE,CAAC,CAAA;IAElD,8BAA8B;IAC9B,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;IACtC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;IACrC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;IACrC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;IACvC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;IAEtC,8BAA8B;IAC9B,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;IAE1C,OAAO,MAAM,CAAC,IAAI,EAAE,CAAA;AACtB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface DiscordConfig {
|
|
2
|
+
botToken: string;
|
|
3
|
+
channelId?: string;
|
|
4
|
+
/** Only respond in these guilds (server IDs). Empty = all guilds. */
|
|
5
|
+
allowedGuilds?: string[];
|
|
6
|
+
/** Only respond in these channels. Empty = all channels. */
|
|
7
|
+
allowedChannels?: string[];
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/plugins/messengers/discord/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,4DAA4D;IAC5D,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAC3B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/plugins/messengers/discord/types.ts"],"names":[],"mappings":"AAAA,wBAAwB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type Transporter } from 'nodemailer';
|
|
2
|
+
import type { MessengerAdapter, MessageContext } from '../../../core/types.js';
|
|
3
|
+
interface SmtpConfig {
|
|
4
|
+
host: string;
|
|
5
|
+
port: number;
|
|
6
|
+
secure: boolean;
|
|
7
|
+
user: string;
|
|
8
|
+
pass: string;
|
|
9
|
+
from: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class EmailAdapter implements MessengerAdapter {
|
|
12
|
+
readonly name = "email";
|
|
13
|
+
private transporter;
|
|
14
|
+
private config;
|
|
15
|
+
private started;
|
|
16
|
+
start(): Promise<void>;
|
|
17
|
+
stop(): Promise<void>;
|
|
18
|
+
onMessage(_handler: (ctx: MessageContext) => Promise<void>): void;
|
|
19
|
+
/**
|
|
20
|
+
* Send the message body to the email address in `threadId`. Subject is
|
|
21
|
+
* derived from the first line (capped at 100 chars). When SMTP isn't
|
|
22
|
+
* configured we throw a clear "not configured" error so the reminder
|
|
23
|
+
* engine writes it as the failure reason.
|
|
24
|
+
*/
|
|
25
|
+
sendMessage(threadId: string, text: string): Promise<void>;
|
|
26
|
+
/** Test/inspection hook — used by unit tests to verify env reading. */
|
|
27
|
+
getEffectiveConfig(): SmtpConfig | null;
|
|
28
|
+
/** Test hook — inject a mocked transporter to bypass SMTP. */
|
|
29
|
+
_setTransporterForTest(t: Transporter, cfg: SmtpConfig): void;
|
|
30
|
+
}
|
|
31
|
+
export declare const emailAdapter: EmailAdapter;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=email-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-adapter.d.ts","sourceRoot":"","sources":["../../../../src/plugins/messengers/email/email-adapter.ts"],"names":[],"mappings":"AAmBA,OAAmB,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAA;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAK9E,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAwBD,qBAAa,YAAa,YAAW,gBAAgB;IACnD,QAAQ,CAAC,IAAI,WAAU;IACvB,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,OAAO,CAAQ;IAEjB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAuCtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAW3B,SAAS,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAIjE;;;;;OAKG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBhE,uEAAuE;IACvE,kBAAkB,IAAI,UAAU,GAAG,IAAI;IAIvC,8DAA8D;IAC9D,sBAAsB,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI;CAK9D;AAED,eAAO,MAAM,YAAY,cAAqB,CAAA"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// Email messenger adapter (push-only).
|
|
2
|
+
//
|
|
3
|
+
// Purpose: deliver reminders / notifications to an email address. This
|
|
4
|
+
// adapter never receives messages — onMessage is a no-op — so /remind etc.
|
|
5
|
+
// addressed to an email arrive as a one-way notification.
|
|
6
|
+
//
|
|
7
|
+
// SMTP config is read from env at start():
|
|
8
|
+
// IMHUB_SMTP_HOST SMTP server (required)
|
|
9
|
+
// IMHUB_SMTP_PORT Port (default: 465 if secure else 587)
|
|
10
|
+
// IMHUB_SMTP_USER Auth username (required)
|
|
11
|
+
// IMHUB_SMTP_PASS Auth password / app-password (required)
|
|
12
|
+
// IMHUB_SMTP_FROM From address (default: USER value)
|
|
13
|
+
// IMHUB_SMTP_SECURE '1'/'true' for TLS-from-start (port 465); else
|
|
14
|
+
// STARTTLS on port 587. Default: secure if port 465.
|
|
15
|
+
//
|
|
16
|
+
// If any of HOST/USER/PASS are missing, start() does NOT throw; the adapter
|
|
17
|
+
// stays "registered but disabled" and sendMessage will throw a clear error
|
|
18
|
+
// at call time. Same fail-soft model as wechat-credentials.
|
|
19
|
+
import nodemailer from 'nodemailer';
|
|
20
|
+
import { logger as rootLogger } from '../../../core/logger.js';
|
|
21
|
+
const log = rootLogger.child({ component: 'email' });
|
|
22
|
+
function readSmtpConfig() {
|
|
23
|
+
const host = process.env.IMHUB_SMTP_HOST?.trim();
|
|
24
|
+
const user = process.env.IMHUB_SMTP_USER?.trim();
|
|
25
|
+
const pass = process.env.IMHUB_SMTP_PASS;
|
|
26
|
+
if (!host || !user || !pass)
|
|
27
|
+
return null;
|
|
28
|
+
const portRaw = process.env.IMHUB_SMTP_PORT?.trim();
|
|
29
|
+
const port = portRaw ? Number.parseInt(portRaw, 10) : 465;
|
|
30
|
+
if (!Number.isFinite(port) || port <= 0 || port > 65535) {
|
|
31
|
+
log.warn({ portRaw }, 'IMHUB_SMTP_PORT invalid, falling back to 465');
|
|
32
|
+
}
|
|
33
|
+
const validPort = Number.isFinite(port) && port > 0 && port <= 65535 ? port : 465;
|
|
34
|
+
// Default secure: yes for 465 (SMTPS), no for 587/25 (STARTTLS).
|
|
35
|
+
const secureRaw = process.env.IMHUB_SMTP_SECURE?.trim().toLowerCase();
|
|
36
|
+
const secure = secureRaw !== undefined
|
|
37
|
+
? (secureRaw === '1' || secureRaw === 'true' || secureRaw === 'yes')
|
|
38
|
+
: validPort === 465;
|
|
39
|
+
const from = process.env.IMHUB_SMTP_FROM?.trim() || user;
|
|
40
|
+
return { host, port: validPort, secure, user, pass, from };
|
|
41
|
+
}
|
|
42
|
+
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
43
|
+
export class EmailAdapter {
|
|
44
|
+
name = 'email';
|
|
45
|
+
transporter = null;
|
|
46
|
+
config = null;
|
|
47
|
+
started = false;
|
|
48
|
+
async start() {
|
|
49
|
+
this.config = readSmtpConfig();
|
|
50
|
+
if (!this.config) {
|
|
51
|
+
log.warn({
|
|
52
|
+
event: 'email.disabled',
|
|
53
|
+
hint: 'set IMHUB_SMTP_HOST / IMHUB_SMTP_USER / IMHUB_SMTP_PASS to enable',
|
|
54
|
+
}, 'Email adapter disabled — SMTP env vars not set');
|
|
55
|
+
this.started = true;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
this.transporter = nodemailer.createTransport({
|
|
59
|
+
host: this.config.host,
|
|
60
|
+
port: this.config.port,
|
|
61
|
+
secure: this.config.secure,
|
|
62
|
+
auth: { user: this.config.user, pass: this.config.pass },
|
|
63
|
+
});
|
|
64
|
+
// Verify connection eagerly so misconfig surfaces at startup instead of
|
|
65
|
+
// at first send. Failure is logged but doesn't block startup — same
|
|
66
|
+
// fail-soft contract as the wechat credentials check.
|
|
67
|
+
try {
|
|
68
|
+
await this.transporter.verify();
|
|
69
|
+
log.info({
|
|
70
|
+
event: 'email.ready',
|
|
71
|
+
host: this.config.host,
|
|
72
|
+
port: this.config.port,
|
|
73
|
+
secure: this.config.secure,
|
|
74
|
+
from: this.config.from,
|
|
75
|
+
}, 'Email adapter ready');
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
log.warn({
|
|
79
|
+
event: 'email.verify_failed',
|
|
80
|
+
err: err instanceof Error ? err.message : String(err),
|
|
81
|
+
}, 'SMTP verify failed — sends will likely fail until config is fixed');
|
|
82
|
+
}
|
|
83
|
+
this.started = true;
|
|
84
|
+
}
|
|
85
|
+
async stop() {
|
|
86
|
+
if (this.transporter) {
|
|
87
|
+
this.transporter.close();
|
|
88
|
+
this.transporter = null;
|
|
89
|
+
}
|
|
90
|
+
this.started = false;
|
|
91
|
+
}
|
|
92
|
+
// onMessage is required by the MessengerAdapter interface, but email is a
|
|
93
|
+
// push-only channel — we never poll an inbox, so the handler is intentionally
|
|
94
|
+
// discarded. The signature is preserved for interface conformance.
|
|
95
|
+
onMessage(_handler) {
|
|
96
|
+
// no-op
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Send the message body to the email address in `threadId`. Subject is
|
|
100
|
+
* derived from the first line (capped at 100 chars). When SMTP isn't
|
|
101
|
+
* configured we throw a clear "not configured" error so the reminder
|
|
102
|
+
* engine writes it as the failure reason.
|
|
103
|
+
*/
|
|
104
|
+
async sendMessage(threadId, text) {
|
|
105
|
+
if (!this.started)
|
|
106
|
+
throw new Error('email adapter not started');
|
|
107
|
+
if (!this.transporter || !this.config) {
|
|
108
|
+
throw new Error('Email adapter not configured (set IMHUB_SMTP_HOST / USER / PASS)');
|
|
109
|
+
}
|
|
110
|
+
const to = threadId.trim();
|
|
111
|
+
if (!EMAIL_RE.test(to)) {
|
|
112
|
+
throw new Error(`Invalid email address: "${to}"`);
|
|
113
|
+
}
|
|
114
|
+
// Subject = first non-empty line, stripped of bot icon prefixes, capped.
|
|
115
|
+
const firstLine = text.split('\n').map((s) => s.trim()).find((s) => s.length > 0) || 'im-hub 通知';
|
|
116
|
+
const subject = firstLine.replace(/^(?:🔔|🔁|⏰)\s*/u, '').slice(0, 100);
|
|
117
|
+
await this.transporter.sendMail({
|
|
118
|
+
from: this.config.from,
|
|
119
|
+
to,
|
|
120
|
+
subject,
|
|
121
|
+
text,
|
|
122
|
+
});
|
|
123
|
+
log.info({ event: 'email.sent', to, subjectLen: subject.length, bodyLen: text.length }, 'email delivered');
|
|
124
|
+
}
|
|
125
|
+
/** Test/inspection hook — used by unit tests to verify env reading. */
|
|
126
|
+
getEffectiveConfig() {
|
|
127
|
+
return this.config;
|
|
128
|
+
}
|
|
129
|
+
/** Test hook — inject a mocked transporter to bypass SMTP. */
|
|
130
|
+
_setTransporterForTest(t, cfg) {
|
|
131
|
+
this.transporter = t;
|
|
132
|
+
this.config = cfg;
|
|
133
|
+
this.started = true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export const emailAdapter = new EmailAdapter();
|
|
137
|
+
//# sourceMappingURL=email-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-adapter.js","sourceRoot":"","sources":["../../../../src/plugins/messengers/email/email-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { FeishuCard } from './types.js';
|
|
2
|
+
export declare class CardBuilder {
|
|
3
|
+
private header;
|
|
4
|
+
private elements;
|
|
5
|
+
withHeader(title: string, template?: string): this;
|
|
6
|
+
addMarkdown(content: string): this;
|
|
7
|
+
addDiv(text: string): this;
|
|
8
|
+
addCode(code: string, language?: string): this;
|
|
9
|
+
addDivider(): this;
|
|
10
|
+
addButtons(buttons: Array<{
|
|
11
|
+
text: string;
|
|
12
|
+
type: 'primary' | 'default' | 'danger';
|
|
13
|
+
value: Record<string, string>;
|
|
14
|
+
}>): this;
|
|
15
|
+
addAgentBadge(agent: string): this;
|
|
16
|
+
build(): FeishuCard;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Convert markdown text to Feishu-compatible format
|
|
20
|
+
* Feishu supports most standard markdown in the markdown element
|
|
21
|
+
*/
|
|
22
|
+
export declare function markdownToFeishu(text: string): string;
|
|
23
|
+
//# sourceMappingURL=card-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-builder.d.ts","sourceRoot":"","sources":["../../../../src/plugins/messengers/feishu/card-builder.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAuC,MAAM,YAAY,CAAA;AAEjF,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,QAAQ,CAA0B;IAE1C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAQlD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQlC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQ1B,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAS9C,UAAU,IAAI,IAAI;IAKlB,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC;QACxB,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAA;QACtC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAC9B,CAAC,GAAG,IAAI;IAeT,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAmBlC,KAAK,IAAI,UAAU;CAUpB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIrD"}
|