im-hub-pro 0.2.29
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/LICENSE +21 -0
- package/README.md +497 -0
- package/README.zh-CN.md +496 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +921 -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 +374 -0
- package/dist/core/agent-base.js.map +1 -0
- package/dist/core/agent-cwd.d.ts +45 -0
- package/dist/core/agent-cwd.d.ts.map +1 -0
- package/dist/core/agent-cwd.js +178 -0
- package/dist/core/agent-cwd.js.map +1 -0
- package/dist/core/agent-cwd.test.d.ts +2 -0
- package/dist/core/agent-cwd.test.d.ts.map +1 -0
- package/dist/core/agent-cwd.test.js +149 -0
- package/dist/core/agent-cwd.test.js.map +1 -0
- package/dist/core/approval-bus.d.ts +232 -0
- package/dist/core/approval-bus.d.ts.map +1 -0
- package/dist/core/approval-bus.js +703 -0
- package/dist/core/approval-bus.js.map +1 -0
- package/dist/core/approval-bus.synthetic.test.d.ts +2 -0
- package/dist/core/approval-bus.synthetic.test.d.ts.map +1 -0
- package/dist/core/approval-bus.synthetic.test.js +182 -0
- package/dist/core/approval-bus.synthetic.test.js.map +1 -0
- package/dist/core/approval-bus.test.d.ts +2 -0
- package/dist/core/approval-bus.test.d.ts.map +1 -0
- package/dist/core/approval-bus.test.js +537 -0
- package/dist/core/approval-bus.test.js.map +1 -0
- package/dist/core/approval-router.d.ts +95 -0
- package/dist/core/approval-router.d.ts.map +1 -0
- package/dist/core/approval-router.js +450 -0
- package/dist/core/approval-router.js.map +1 -0
- package/dist/core/approval-router.test.d.ts +2 -0
- package/dist/core/approval-router.test.d.ts.map +1 -0
- package/dist/core/approval-router.test.js +413 -0
- package/dist/core/approval-router.test.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/bgjob-reader.test.d.ts +2 -0
- package/dist/core/bgjob-reader.test.d.ts.map +1 -0
- package/dist/core/bgjob-reader.test.js +178 -0
- package/dist/core/bgjob-reader.test.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 +21 -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 +44 -0
- package/dist/core/commands/approval.js.map +1 -0
- package/dist/core/commands/approval.test.d.ts +2 -0
- package/dist/core/commands/approval.test.d.ts.map +1 -0
- package/dist/core/commands/approval.test.js +85 -0
- package/dist/core/commands/approval.test.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 +26 -0
- package/dist/core/commands/builtin.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/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/plan.test.d.ts +2 -0
- package/dist/core/commands/plan.test.d.ts.map +1 -0
- package/dist/core/commands/plan.test.js +122 -0
- package/dist/core/commands/plan.test.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/schedule.d.ts +3 -0
- package/dist/core/commands/schedule.d.ts.map +1 -0
- package/dist/core/commands/schedule.js +123 -0
- package/dist/core/commands/schedule.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 +58 -0
- package/dist/core/config-schema.d.ts.map +1 -0
- package/dist/core/config-schema.js +63 -0
- package/dist/core/config-schema.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 +84 -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/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/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 +94 -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/onboarding.test.d.ts +2 -0
- package/dist/core/onboarding.test.d.ts.map +1 -0
- package/dist/core/onboarding.test.js +112 -0
- package/dist/core/onboarding.test.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 +122 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/router.d.ts +41 -0
- package/dist/core/router.d.ts.map +1 -0
- package/dist/core/router.js +431 -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 +316 -0
- package/dist/core/schedule.js.map +1 -0
- package/dist/core/session-subtasks.test.d.ts +2 -0
- package/dist/core/session-subtasks.test.d.ts.map +1 -0
- package/dist/core/session-subtasks.test.js +88 -0
- package/dist/core/session-subtasks.test.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 +774 -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/transcribe.test.d.ts +2 -0
- package/dist/core/transcribe.test.d.ts.map +1 -0
- package/dist/core/transcribe.test.js +163 -0
- package/dist/core/transcribe.test.js.map +1 -0
- package/dist/core/types.d.ts +352 -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 +175 -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 +109 -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/adapter.test.d.ts +2 -0
- package/dist/plugins/agents/claude-code/adapter.test.d.ts.map +1 -0
- package/dist/plugins/agents/claude-code/adapter.test.js +195 -0
- package/dist/plugins/agents/claude-code/adapter.test.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 +42 -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 +235 -0
- package/dist/plugins/agents/claude-code/mcp-approval-server.js.map +1 -0
- package/dist/plugins/agents/claude-code/mcp-approval-server.test.d.ts +2 -0
- package/dist/plugins/agents/claude-code/mcp-approval-server.test.d.ts.map +1 -0
- package/dist/plugins/agents/claude-code/mcp-approval-server.test.js +188 -0
- package/dist/plugins/agents/claude-code/mcp-approval-server.test.js.map +1 -0
- package/dist/plugins/agents/codex/adapter.test.d.ts +2 -0
- package/dist/plugins/agents/codex/adapter.test.d.ts.map +1 -0
- package/dist/plugins/agents/codex/adapter.test.js +192 -0
- package/dist/plugins/agents/codex/adapter.test.js.map +1 -0
- package/dist/plugins/agents/codex/index.d.ts +37 -0
- package/dist/plugins/agents/codex/index.d.ts.map +1 -0
- package/dist/plugins/agents/codex/index.js +254 -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/adapter.test.d.ts +2 -0
- package/dist/plugins/agents/opencode/adapter.test.d.ts.map +1 -0
- package/dist/plugins/agents/opencode/adapter.test.js +139 -0
- package/dist/plugins/agents/opencode/adapter.test.js.map +1 -0
- package/dist/plugins/agents/opencode/http-adapter.test.d.ts +2 -0
- package/dist/plugins/agents/opencode/http-adapter.test.d.ts.map +1 -0
- package/dist/plugins/agents/opencode/http-adapter.test.js +492 -0
- package/dist/plugins/agents/opencode/http-adapter.test.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 +138 -0
- package/dist/plugins/agents/opencode/opencode-http-adapter.d.ts.map +1 -0
- package/dist/plugins/agents/opencode/opencode-http-adapter.js +549 -0
- package/dist/plugins/agents/opencode/opencode-http-adapter.js.map +1 -0
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.d.ts +24 -0
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.d.ts.map +1 -0
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.js +103 -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 +190 -0
- package/dist/plugins/agents/opencode/serve-manager.js.map +1 -0
- package/dist/plugins/messengers/discord/discord-adapter.d.ts +22 -0
- package/dist/plugins/messengers/discord/discord-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/discord/discord-adapter.js +241 -0
- package/dist/plugins/messengers/discord/discord-adapter.js.map +1 -0
- package/dist/plugins/messengers/discord/discord-adapter.test.d.ts +2 -0
- package/dist/plugins/messengers/discord/discord-adapter.test.d.ts.map +1 -0
- package/dist/plugins/messengers/discord/discord-adapter.test.js +332 -0
- package/dist/plugins/messengers/discord/discord-adapter.test.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/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 +33 -0
- package/dist/plugins/messengers/feishu/feishu-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/feishu/feishu-adapter.js +195 -0
- package/dist/plugins/messengers/feishu/feishu-adapter.js.map +1 -0
- package/dist/plugins/messengers/feishu/feishu-client.d.ts +44 -0
- package/dist/plugins/messengers/feishu/feishu-client.d.ts.map +1 -0
- package/dist/plugins/messengers/feishu/feishu-client.js +120 -0
- package/dist/plugins/messengers/feishu/feishu-client.js.map +1 -0
- package/dist/plugins/messengers/feishu/feishu-dedup.test.d.ts +2 -0
- package/dist/plugins/messengers/feishu/feishu-dedup.test.d.ts.map +1 -0
- package/dist/plugins/messengers/feishu/feishu-dedup.test.js +70 -0
- package/dist/plugins/messengers/feishu/feishu-dedup.test.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 +51 -0
- package/dist/plugins/messengers/telegram/media-download.d.ts.map +1 -0
- package/dist/plugins/messengers/telegram/media-download.js +224 -0
- package/dist/plugins/messengers/telegram/media-download.js.map +1 -0
- package/dist/plugins/messengers/telegram/media-download.test.d.ts +2 -0
- package/dist/plugins/messengers/telegram/media-download.test.d.ts.map +1 -0
- package/dist/plugins/messengers/telegram/media-download.test.js +125 -0
- package/dist/plugins/messengers/telegram/media-download.test.js.map +1 -0
- package/dist/plugins/messengers/telegram/telegram-adapter.d.ts +62 -0
- package/dist/plugins/messengers/telegram/telegram-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/telegram/telegram-adapter.js +653 -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/ilink-adapter.d.ts +68 -0
- package/dist/plugins/messengers/wechat/ilink-adapter.d.ts.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-adapter.js +483 -0
- package/dist/plugins/messengers/wechat/ilink-adapter.js.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-client.d.ts +66 -0
- package/dist/plugins/messengers/wechat/ilink-client.d.ts.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-client.js +288 -0
- package/dist/plugins/messengers/wechat/ilink-client.js.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-types.d.ts +173 -0
- package/dist/plugins/messengers/wechat/ilink-types.d.ts.map +1 -0
- package/dist/plugins/messengers/wechat/ilink-types.js +12 -0
- package/dist/plugins/messengers/wechat/ilink-types.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 +935 -0
- package/dist/web/public/settings.html +1181 -0
- package/dist/web/public/tasks.html +1827 -0
- package/dist/web/server.d.ts +11 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +1820 -0
- package/dist/web/server.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// Markdown to Telegram HTML converter
|
|
2
|
+
// Telegram supports a subset of HTML: <b>, <i>, <u>, <s>, <code>, <pre>, <a>
|
|
3
|
+
import { marked } from 'marked';
|
|
4
|
+
/**
|
|
5
|
+
* Process math/LaTeX formulas - convert to code blocks
|
|
6
|
+
*/
|
|
7
|
+
function processMath(markdown) {
|
|
8
|
+
// Block math $$ ... $$ -> code block
|
|
9
|
+
let result = markdown.replace(/\$\$([\s\S]*?)\$\$/g, (_, formula) => {
|
|
10
|
+
return `\`\`\`math\n${formula.trim()}\n\`\`\``;
|
|
11
|
+
});
|
|
12
|
+
// Inline math $ ... $ -> inline code (be careful not to match currency)
|
|
13
|
+
result = result.replace(/\$([^$\n]+)\$/g, (_, formula) => {
|
|
14
|
+
// Skip if it looks like currency (e.g., $100, $5.00)
|
|
15
|
+
if (/^\d+(\.\d+)?$/.test(formula.trim())) {
|
|
16
|
+
return `$${formula}$`;
|
|
17
|
+
}
|
|
18
|
+
return `\`${formula.trim()}\``;
|
|
19
|
+
});
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Convert HTML to Telegram-compatible HTML
|
|
24
|
+
* Telegram only supports: b, i, u, s, del, strike, code, pre, a, span (tg-spoiler, tg-emoji)
|
|
25
|
+
*/
|
|
26
|
+
function htmlToTelegramHtml(html) {
|
|
27
|
+
let result = html;
|
|
28
|
+
// Convert tables to pre-formatted text
|
|
29
|
+
result = result.replace(/<table[^>]*>([\s\S]*?)<\/table>/gi, (_, tableContent) => {
|
|
30
|
+
const rows = [];
|
|
31
|
+
// Extract header rows
|
|
32
|
+
const theadMatch = tableContent.match(/<thead[^>]*>([\s\S]*?)<\/thead>/i);
|
|
33
|
+
if (theadMatch) {
|
|
34
|
+
const headerRow = extractRowCells(theadMatch[1]);
|
|
35
|
+
if (headerRow.length > 0)
|
|
36
|
+
rows.push(headerRow);
|
|
37
|
+
}
|
|
38
|
+
// Extract body rows
|
|
39
|
+
const tbodyMatch = tableContent.match(/<tbody[^>]*>([\s\S]*?)<\/tbody>/i);
|
|
40
|
+
const bodyContent = tbodyMatch ? tbodyMatch[1] : tableContent;
|
|
41
|
+
// Match all tr elements
|
|
42
|
+
const trMatches = bodyContent.matchAll(/<tr[^>]*>([\s\S]*?)<\/tr>/gi);
|
|
43
|
+
for (const trMatch of trMatches) {
|
|
44
|
+
const row = extractRowCells(trMatch[1]);
|
|
45
|
+
if (row.length > 0)
|
|
46
|
+
rows.push(row);
|
|
47
|
+
}
|
|
48
|
+
if (rows.length === 0)
|
|
49
|
+
return '';
|
|
50
|
+
// Calculate column widths
|
|
51
|
+
const colCount = Math.max(...rows.map(r => r.length));
|
|
52
|
+
const widths = Array(colCount).fill(0);
|
|
53
|
+
for (const row of rows) {
|
|
54
|
+
row.forEach((cell, i) => {
|
|
55
|
+
widths[i] = Math.max(widths[i], cell.length);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// Cap widths at 20 for mobile
|
|
59
|
+
const cappedWidths = widths.map(w => Math.min(w, 20));
|
|
60
|
+
// Format as text table
|
|
61
|
+
const lines = [];
|
|
62
|
+
rows.forEach((row, rowIdx) => {
|
|
63
|
+
const cells = row.map((cell, i) => {
|
|
64
|
+
const width = cappedWidths[i] || 10;
|
|
65
|
+
const truncated = cell.length > width ? cell.slice(0, width - 1) + '…' : cell;
|
|
66
|
+
return truncated.padEnd(width);
|
|
67
|
+
});
|
|
68
|
+
// Pad missing cells
|
|
69
|
+
while (cells.length < colCount) {
|
|
70
|
+
cells.push(' '.repeat(cappedWidths[cells.length] || 10));
|
|
71
|
+
}
|
|
72
|
+
lines.push('| ' + cells.join(' | ') + ' |');
|
|
73
|
+
// Add separator after header
|
|
74
|
+
if (rowIdx === 0) {
|
|
75
|
+
const separator = cappedWidths.map(w => '-'.repeat(w));
|
|
76
|
+
lines.push('| ' + separator.join(' | ') + ' |');
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
return `<pre>${escapeHtml(lines.join('\n'))}</pre>`;
|
|
80
|
+
});
|
|
81
|
+
// Helper to extract cells from a row
|
|
82
|
+
function extractRowCells(rowHtml) {
|
|
83
|
+
const cells = [];
|
|
84
|
+
const cellMatches = rowHtml.matchAll(/<t[dh][^>]*>([\s\S]*?)<\/t[dh]>/gi);
|
|
85
|
+
for (const match of cellMatches) {
|
|
86
|
+
// Strip HTML tags and get plain text
|
|
87
|
+
const text = match[1].replace(/<[^>]+>/g, '').trim();
|
|
88
|
+
cells.push(text);
|
|
89
|
+
}
|
|
90
|
+
return cells;
|
|
91
|
+
}
|
|
92
|
+
// Convert <kbd> to <code>
|
|
93
|
+
result = result.replace(/<kbd>([^<]*)<\/kbd>/gi, '<code>$1</code>');
|
|
94
|
+
// Convert headers to bold
|
|
95
|
+
result = result.replace(/<h[1-6][^>]*>([\s\S]*?)<\/h[1-6]>/gi, '\n<b>$1</b>\n\n');
|
|
96
|
+
// Convert lists to bullet points
|
|
97
|
+
result = result.replace(/<ul[^>]*>([\s\S]*?)<\/ul>/gi, '\n$1\n');
|
|
98
|
+
result = result.replace(/<ol[^>]*>([\s\S]*?)<\/ol>/gi, '\n$1\n');
|
|
99
|
+
result = result.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, '• $1\n');
|
|
100
|
+
// Convert blockquotes to italic
|
|
101
|
+
result = result.replace(/<blockquote[^>]*>([\s\S]*?)<\/blockquote>/gi, '<i>$1</i>\n\n');
|
|
102
|
+
// Fix code blocks: convert <pre><code class="lang"> to <pre language="lang">
|
|
103
|
+
result = result.replace(/<pre><code(?:\s+class="language-(\w+)")?>([\s\S]*?)<\/code><\/pre>/gi, (_, lang, code) => {
|
|
104
|
+
if (lang) {
|
|
105
|
+
return `<pre language="${lang}">${code}</pre>`;
|
|
106
|
+
}
|
|
107
|
+
return `<pre>${code}</pre>`;
|
|
108
|
+
});
|
|
109
|
+
// Convert <mark>, <highlight> to <b>
|
|
110
|
+
result = result.replace(/<mark[^>]*>([^<]*)<\/mark>/gi, '<b>$1</b>');
|
|
111
|
+
result = result.replace(/<highlight[^>]*>([^<]*)<\/highlight>/gi, '<b>$1</b>');
|
|
112
|
+
// Strip <sub>, <sup> (no good equivalent)
|
|
113
|
+
result = result.replace(/<su[bp][^>]*>([^<]*)<\/su[bp]>/gi, '$1');
|
|
114
|
+
// Convert semantic tags to Telegram equivalents
|
|
115
|
+
result = result.replace(/<(\/?)strong>/gi, '<$1b>');
|
|
116
|
+
result = result.replace(/<(\/?)em>/gi, '<$1i>');
|
|
117
|
+
result = result.replace(/<(\/?)ins>/gi, '<$1u>');
|
|
118
|
+
result = result.replace(/<(\/?)del>/gi, '<$1s>');
|
|
119
|
+
result = result.replace(/<(\/?)strike>/gi, '<$1s>');
|
|
120
|
+
// Replace <hr> with separator
|
|
121
|
+
result = result.replace(/<hr\s*\/?>/gi, '\n―――\n');
|
|
122
|
+
// Replace <br> with newline
|
|
123
|
+
result = result.replace(/<br\s*\/?>/gi, '\n');
|
|
124
|
+
// Convert images to links
|
|
125
|
+
result = result.replace(/<img[^>]*alt="([^"]*)"[^>]*src="([^"]*)"[^>]*\/?>/gi, '<a href="$2">$1</a>');
|
|
126
|
+
result = result.replace(/<img[^>]*src="([^"]*)"[^>]*alt="([^"]*)"[^>]*\/?>/gi, '<a href="$1">$2</a>');
|
|
127
|
+
result = result.replace(/<img[^>]*src="([^"]*)"[^>]*\/?>/gi, '<a href="$1">Image</a>');
|
|
128
|
+
// Strip all other unsupported HTML tags but keep content
|
|
129
|
+
const supportedTags = new Set(['b', 'i', 'u', 's', 'code', 'pre', 'a', 'span', 'tg-spoiler', 'tg-emoji']);
|
|
130
|
+
result = result.replace(/<(\/?)([a-zA-Z][a-zA-Z0-9-]*)\b[^>]*>/g, (match, isClosing, tagName) => {
|
|
131
|
+
const tag = tagName.toLowerCase();
|
|
132
|
+
if (supportedTags.has(tag)) {
|
|
133
|
+
// For <a>, keep only href attribute
|
|
134
|
+
if (tag === 'a' && !isClosing) {
|
|
135
|
+
const hrefMatch = match.match(/href="([^"]*)"/i) || match.match(/href='([^']*)'/i);
|
|
136
|
+
if (hrefMatch) {
|
|
137
|
+
return `<a href="${hrefMatch[1]}">`;
|
|
138
|
+
}
|
|
139
|
+
return '<a href="#">';
|
|
140
|
+
}
|
|
141
|
+
// For <pre>, keep only language attribute (check both class="language-X" and language="X")
|
|
142
|
+
if (tag === 'pre' && !isClosing) {
|
|
143
|
+
// Check for language="X" first (already converted)
|
|
144
|
+
const directLangMatch = match.match(/language="([^"]*)"/i) || match.match(/language='([^']*)'/i);
|
|
145
|
+
if (directLangMatch) {
|
|
146
|
+
return `<pre language="${directLangMatch[1]}">`;
|
|
147
|
+
}
|
|
148
|
+
// Then check for class="language-X" (from marked)
|
|
149
|
+
const classLangMatch = match.match(/class="language-([^"]*)"/i) || match.match(/class='language-([^']*)'/i);
|
|
150
|
+
if (classLangMatch) {
|
|
151
|
+
return `<pre language="${classLangMatch[1]}">`;
|
|
152
|
+
}
|
|
153
|
+
return '<pre>';
|
|
154
|
+
}
|
|
155
|
+
// Keep supported tags without attributes
|
|
156
|
+
return isClosing ? `</${tag}>` : `<${tag}>`;
|
|
157
|
+
}
|
|
158
|
+
// Remove unsupported tag
|
|
159
|
+
return '';
|
|
160
|
+
});
|
|
161
|
+
// Clean up multiple blank lines
|
|
162
|
+
result = result.replace(/\n{3,}/g, '\n\n');
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
function escapeHtml(text) {
|
|
166
|
+
return text
|
|
167
|
+
.replace(/&/g, '&')
|
|
168
|
+
.replace(/</g, '<')
|
|
169
|
+
.replace(/>/g, '>');
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Convert Markdown to Telegram-compatible HTML
|
|
173
|
+
*/
|
|
174
|
+
export function markdownToTelegramHtml(markdown) {
|
|
175
|
+
// Pre-process: convert math formulas
|
|
176
|
+
const processed = processMath(markdown);
|
|
177
|
+
// Parse markdown to HTML
|
|
178
|
+
const html = marked.parse(processed, {
|
|
179
|
+
gfm: true,
|
|
180
|
+
breaks: false,
|
|
181
|
+
});
|
|
182
|
+
// Convert to Telegram-compatible HTML
|
|
183
|
+
const telegramHtml = htmlToTelegramHtml(html);
|
|
184
|
+
return telegramHtml.trim();
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=markdown-to-html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-to-html.js","sourceRoot":"","sources":["../../../../src/plugins/messengers/telegram/markdown-to-html.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** Root for downloaded media. Always resolved absolute so the safety check
|
|
2
|
+
* `path.startsWith(MEDIA_ROOT)` is robust. Override via env for tests. */
|
|
3
|
+
export declare const MEDIA_ROOT: string;
|
|
4
|
+
/** Hard upper bound on a single download. Telegram photo max is ~10 MB and
|
|
5
|
+
* document max is 50 MB on the bot API; we cap at 20 MB so a runaway upload
|
|
6
|
+
* can't fill the disk. */
|
|
7
|
+
export declare const MAX_BYTES: number;
|
|
8
|
+
/** Default cleanup TTL — 7 days. Long enough that a multi-day conversation
|
|
9
|
+
* can re-reference an image, short enough that the directory doesn't grow
|
|
10
|
+
* without bound. Override via env for ops. */
|
|
11
|
+
export declare const DEFAULT_TTL_MS: number;
|
|
12
|
+
export interface DownloadParams {
|
|
13
|
+
/** TG file URL — must be on api.telegram.org. */
|
|
14
|
+
url: string;
|
|
15
|
+
/** Destination folder under MEDIA_ROOT, typically `${platform}/${chatId}`. */
|
|
16
|
+
subdir: string;
|
|
17
|
+
/** Filename (no path components). */
|
|
18
|
+
filename: string;
|
|
19
|
+
}
|
|
20
|
+
export interface DownloadResult {
|
|
21
|
+
path: string;
|
|
22
|
+
bytes: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Download `url` and write it to `<MEDIA_ROOT>/<subdir>/<filename>`. Returns
|
|
26
|
+
* the absolute path on success. Errors out (and writes nothing) on:
|
|
27
|
+
* - non-https or non-telegram host
|
|
28
|
+
* - HTTP non-2xx
|
|
29
|
+
* - body larger than MAX_BYTES
|
|
30
|
+
* - destination resolves outside MEDIA_ROOT (path-injection guard)
|
|
31
|
+
*
|
|
32
|
+
* Best-effort cleanup: if write fails partway through, the partial file is
|
|
33
|
+
* removed so a half-saved image never reaches the agent.
|
|
34
|
+
*/
|
|
35
|
+
export declare function downloadToMediaRoot(params: DownloadParams): Promise<DownloadResult>;
|
|
36
|
+
/**
|
|
37
|
+
* Walk MEDIA_ROOT recursively, removing regular files older than `maxAgeMs`.
|
|
38
|
+
* Empty directories are also pruned. Errors on a single file are logged and
|
|
39
|
+
* ignored — cleanup must never block the IM pipeline.
|
|
40
|
+
*/
|
|
41
|
+
export declare function cleanupOldMedia(maxAgeMs?: number): Promise<{
|
|
42
|
+
deleted: number;
|
|
43
|
+
kept: number;
|
|
44
|
+
}>;
|
|
45
|
+
/**
|
|
46
|
+
* Pick a filename extension from a TG `file_path` (e.g. "photos/file_123.jpg")
|
|
47
|
+
* or a mime-type like "image/png". Falls back to "bin" so we always have an
|
|
48
|
+
* extension on disk for easier debugging.
|
|
49
|
+
*/
|
|
50
|
+
export declare function pickExtension(filePath: string | undefined, mime: string | undefined): string;
|
|
51
|
+
//# sourceMappingURL=media-download.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-download.d.ts","sourceRoot":"","sources":["../../../../src/plugins/messengers/telegram/media-download.ts"],"names":[],"mappings":"AAmBA;2EAC2E;AAC3E,eAAO,MAAM,UAAU,EAAE,MAExB,CAAA;AAED;;2BAE2B;AAC3B,eAAO,MAAM,SAAS,QAAmB,CAAA;AAEzC;;+CAE+C;AAC/C,eAAO,MAAM,cAAc,EAAE,MAKzB,CAAA;AAEJ,MAAM,WAAW,cAAc;IAC7B,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAA;IACX,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAA;IACd,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CA6CzF;AAsDD;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,QAAQ,GAAE,MAAuB,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAsCnH;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAsB5F"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
// Telegram media download helper.
|
|
2
|
+
//
|
|
3
|
+
// Downloads photo / document attachments to ~/.im-hub/media/telegram/<chatId>/
|
|
4
|
+
// so the claude-code agent (multimodal) can Read them by path. Decoupled from
|
|
5
|
+
// the adapter class so it's testable in isolation.
|
|
6
|
+
//
|
|
7
|
+
// Lifetime: cleanupOldMedia() prunes files older than the configured TTL,
|
|
8
|
+
// invoked hourly + at startup by the adapter. We do not delete on a per-thread
|
|
9
|
+
// basis — same image may be referenced across turns within a 30-min imhub
|
|
10
|
+
// session.
|
|
11
|
+
import { spawn } from 'child_process';
|
|
12
|
+
import { mkdir, readdir, rm, stat } from 'fs/promises';
|
|
13
|
+
import { homedir } from 'os';
|
|
14
|
+
import { join, resolve } from 'path';
|
|
15
|
+
import { logger as rootLogger } from '../../../core/logger.js';
|
|
16
|
+
const log = rootLogger.child({ component: 'telegram.media' });
|
|
17
|
+
/** Root for downloaded media. Always resolved absolute so the safety check
|
|
18
|
+
* `path.startsWith(MEDIA_ROOT)` is robust. Override via env for tests. */
|
|
19
|
+
export const MEDIA_ROOT = resolve(process.env.IMHUB_MEDIA_ROOT ?? join(homedir(), '.im-hub', 'media'));
|
|
20
|
+
/** Hard upper bound on a single download. Telegram photo max is ~10 MB and
|
|
21
|
+
* document max is 50 MB on the bot API; we cap at 20 MB so a runaway upload
|
|
22
|
+
* can't fill the disk. */
|
|
23
|
+
export const MAX_BYTES = 20 * 1024 * 1024;
|
|
24
|
+
/** Default cleanup TTL — 7 days. Long enough that a multi-day conversation
|
|
25
|
+
* can re-reference an image, short enough that the directory doesn't grow
|
|
26
|
+
* without bound. Override via env for ops. */
|
|
27
|
+
export const DEFAULT_TTL_MS = (() => {
|
|
28
|
+
const raw = process.env.IMHUB_MEDIA_TTL_MS;
|
|
29
|
+
if (!raw)
|
|
30
|
+
return 7 * 24 * 60 * 60 * 1000;
|
|
31
|
+
const n = Number(raw);
|
|
32
|
+
return Number.isFinite(n) && n > 0 ? n : 7 * 24 * 60 * 60 * 1000;
|
|
33
|
+
})();
|
|
34
|
+
/**
|
|
35
|
+
* Download `url` and write it to `<MEDIA_ROOT>/<subdir>/<filename>`. Returns
|
|
36
|
+
* the absolute path on success. Errors out (and writes nothing) on:
|
|
37
|
+
* - non-https or non-telegram host
|
|
38
|
+
* - HTTP non-2xx
|
|
39
|
+
* - body larger than MAX_BYTES
|
|
40
|
+
* - destination resolves outside MEDIA_ROOT (path-injection guard)
|
|
41
|
+
*
|
|
42
|
+
* Best-effort cleanup: if write fails partway through, the partial file is
|
|
43
|
+
* removed so a half-saved image never reaches the agent.
|
|
44
|
+
*/
|
|
45
|
+
export async function downloadToMediaRoot(params) {
|
|
46
|
+
// Path-injection guard: filename must not contain separators / .. so the
|
|
47
|
+
// join + resolve stays inside MEDIA_ROOT/subdir. subdir itself is built by
|
|
48
|
+
// the adapter from numeric chatId, so we trust the caller there but still
|
|
49
|
+
// do the post-resolve check below.
|
|
50
|
+
if (params.filename.includes('/') || params.filename.includes('\\') || params.filename.includes('..')) {
|
|
51
|
+
throw new Error(`unsafe filename: ${params.filename}`);
|
|
52
|
+
}
|
|
53
|
+
const u = new URL(params.url);
|
|
54
|
+
if (u.protocol !== 'https:' || u.hostname !== 'api.telegram.org') {
|
|
55
|
+
throw new Error(`refusing to download from ${u.host}: only api.telegram.org allowed`);
|
|
56
|
+
}
|
|
57
|
+
const dir = resolve(MEDIA_ROOT, params.subdir);
|
|
58
|
+
const path = resolve(dir, params.filename);
|
|
59
|
+
if (!path.startsWith(MEDIA_ROOT + '/')) {
|
|
60
|
+
throw new Error(`destination escapes MEDIA_ROOT: ${path}`);
|
|
61
|
+
}
|
|
62
|
+
await mkdir(dir, { recursive: true });
|
|
63
|
+
// Implementation note: we shell out to curl rather than using Node's fetch.
|
|
64
|
+
// Observed in production: undici's fetch hits intermittent ETIMEDOUT against
|
|
65
|
+
// api.telegram.org from this VM (3 retries all fail in ~2s while curl from
|
|
66
|
+
// the same shell succeeds in <1s). Root cause unclear (HTTP/2 vs 1.1
|
|
67
|
+
// negotiation, DNS warm-up, or a VM-specific routing quirk). curl is a
|
|
68
|
+
// boring, well-tested OS tool — pragmatic answer is to use it.
|
|
69
|
+
//
|
|
70
|
+
// Size cap is enforced via curl's --max-filesize plus a post-download stat
|
|
71
|
+
// (the flag relies on Content-Length when the server provides it; the stat
|
|
72
|
+
// covers the case where the server omits it).
|
|
73
|
+
await runCurl(params.url, path);
|
|
74
|
+
let bytes;
|
|
75
|
+
try {
|
|
76
|
+
bytes = (await stat(path)).size;
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
throw new Error(`download appeared to succeed but file missing: ${err.message}`);
|
|
80
|
+
}
|
|
81
|
+
if (bytes > MAX_BYTES) {
|
|
82
|
+
await rm(path, { force: true }).catch(() => { });
|
|
83
|
+
throw new Error(`payload exceeds ${MAX_BYTES} bytes (got ${bytes})`);
|
|
84
|
+
}
|
|
85
|
+
log.info({ event: 'media.downloaded', path, bytes }, 'media saved');
|
|
86
|
+
return { path, bytes };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Spawn curl to fetch `url` directly to `outPath`. Resolves on exit code 0,
|
|
90
|
+
* rejects with an Error containing curl's stderr on any other exit. Hard
|
|
91
|
+
* timeout 60 s so a hung connection can't wedge the calling handler.
|
|
92
|
+
*
|
|
93
|
+
* Exposed only inside this module — callers stick to {@link downloadToMediaRoot}.
|
|
94
|
+
*/
|
|
95
|
+
async function runCurl(url, outPath) {
|
|
96
|
+
const args = [
|
|
97
|
+
'--silent',
|
|
98
|
+
'--show-error',
|
|
99
|
+
'--fail', // non-2xx → exit code 22
|
|
100
|
+
'--location', // follow redirects
|
|
101
|
+
'--max-time', '60',
|
|
102
|
+
'--max-filesize', String(MAX_BYTES),
|
|
103
|
+
'--output', outPath,
|
|
104
|
+
url,
|
|
105
|
+
];
|
|
106
|
+
return new Promise((resolve, reject) => {
|
|
107
|
+
const child = spawn('curl', args, { stdio: ['ignore', 'ignore', 'pipe'] });
|
|
108
|
+
const stderr = [];
|
|
109
|
+
let settled = false;
|
|
110
|
+
const settle = (fn) => {
|
|
111
|
+
if (settled)
|
|
112
|
+
return;
|
|
113
|
+
settled = true;
|
|
114
|
+
fn();
|
|
115
|
+
};
|
|
116
|
+
const timer = setTimeout(() => {
|
|
117
|
+
try {
|
|
118
|
+
child.kill('SIGKILL');
|
|
119
|
+
}
|
|
120
|
+
catch { /* ignore */ }
|
|
121
|
+
// Best-effort partial-file cleanup
|
|
122
|
+
void rm(outPath, { force: true }).catch(() => { });
|
|
123
|
+
settle(() => reject(new Error('curl wall-clock timeout (60s)')));
|
|
124
|
+
}, 65 * 1000);
|
|
125
|
+
child.stderr.on('data', (b) => stderr.push(b));
|
|
126
|
+
child.on('error', (e) => {
|
|
127
|
+
clearTimeout(timer);
|
|
128
|
+
void rm(outPath, { force: true }).catch(() => { });
|
|
129
|
+
settle(() => reject(new Error(`curl spawn failed: ${e.message}`)));
|
|
130
|
+
});
|
|
131
|
+
child.on('close', (code) => {
|
|
132
|
+
clearTimeout(timer);
|
|
133
|
+
if (code === 0) {
|
|
134
|
+
settle(() => resolve());
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
void rm(outPath, { force: true }).catch(() => { });
|
|
138
|
+
const msg = Buffer.concat(stderr).toString().trim().slice(0, 400) || `curl exit ${code}`;
|
|
139
|
+
settle(() => reject(new Error(msg)));
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Walk MEDIA_ROOT recursively, removing regular files older than `maxAgeMs`.
|
|
145
|
+
* Empty directories are also pruned. Errors on a single file are logged and
|
|
146
|
+
* ignored — cleanup must never block the IM pipeline.
|
|
147
|
+
*/
|
|
148
|
+
export async function cleanupOldMedia(maxAgeMs = DEFAULT_TTL_MS) {
|
|
149
|
+
let deleted = 0;
|
|
150
|
+
let kept = 0;
|
|
151
|
+
const cutoff = Date.now() - maxAgeMs;
|
|
152
|
+
const walk = async (dir) => {
|
|
153
|
+
let entries;
|
|
154
|
+
try {
|
|
155
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
for (const entry of entries) {
|
|
161
|
+
const full = join(dir, entry.name);
|
|
162
|
+
if (entry.isDirectory()) {
|
|
163
|
+
await walk(full);
|
|
164
|
+
// Try to remove dir if it became empty; ignore failures.
|
|
165
|
+
try {
|
|
166
|
+
const left = await readdir(full);
|
|
167
|
+
if (left.length === 0)
|
|
168
|
+
await rm(full, { recursive: true });
|
|
169
|
+
}
|
|
170
|
+
catch { /* ignore */ }
|
|
171
|
+
}
|
|
172
|
+
else if (entry.isFile()) {
|
|
173
|
+
try {
|
|
174
|
+
const st = await stat(full);
|
|
175
|
+
if (st.mtimeMs < cutoff) {
|
|
176
|
+
await rm(full, { force: true });
|
|
177
|
+
deleted += 1;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
kept += 1;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch { /* ignore */ }
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
await walk(MEDIA_ROOT);
|
|
188
|
+
if (deleted > 0) {
|
|
189
|
+
log.info({ event: 'media.cleanup', deleted, kept, maxAgeMs }, 'media cleanup pass');
|
|
190
|
+
}
|
|
191
|
+
return { deleted, kept };
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Pick a filename extension from a TG `file_path` (e.g. "photos/file_123.jpg")
|
|
195
|
+
* or a mime-type like "image/png". Falls back to "bin" so we always have an
|
|
196
|
+
* extension on disk for easier debugging.
|
|
197
|
+
*/
|
|
198
|
+
export function pickExtension(filePath, mime) {
|
|
199
|
+
if (filePath) {
|
|
200
|
+
const m = /\.([a-z0-9]+)$/i.exec(filePath);
|
|
201
|
+
if (m)
|
|
202
|
+
return m[1].toLowerCase();
|
|
203
|
+
}
|
|
204
|
+
if (mime) {
|
|
205
|
+
const map = {
|
|
206
|
+
'image/jpeg': 'jpg',
|
|
207
|
+
'image/jpg': 'jpg',
|
|
208
|
+
'image/png': 'png',
|
|
209
|
+
'image/gif': 'gif',
|
|
210
|
+
'image/webp': 'webp',
|
|
211
|
+
'image/heic': 'heic',
|
|
212
|
+
'audio/ogg': 'ogg',
|
|
213
|
+
'audio/mpeg': 'mp3',
|
|
214
|
+
'audio/mp4': 'm4a',
|
|
215
|
+
};
|
|
216
|
+
if (map[mime.toLowerCase()])
|
|
217
|
+
return map[mime.toLowerCase()];
|
|
218
|
+
const m = /\/([a-z0-9]+)$/i.exec(mime);
|
|
219
|
+
if (m)
|
|
220
|
+
return m[1].toLowerCase();
|
|
221
|
+
}
|
|
222
|
+
return 'bin';
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=media-download.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-download.js","sourceRoot":"","sources":["../../../../src/plugins/messengers/telegram/media-download.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-download.test.d.ts","sourceRoot":"","sources":["../../../../src/plugins/messengers/telegram/media-download.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// media-download — focuses on the safety checks (path injection, host
|
|
2
|
+
// allowlist, size cap) and the cleanup walker. We don't test the happy-path
|
|
3
|
+
// download against the real TG API (network); a per-test override of `fetch`
|
|
4
|
+
// drives the URL-fetcher behavior.
|
|
5
|
+
import { describe, it, expect, beforeEach, beforeAll, afterAll } from 'bun:test';
|
|
6
|
+
import { mkdir, readdir, rm, stat, writeFile, utimes } from 'fs/promises';
|
|
7
|
+
import { tmpdir } from 'os';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
const TEST_ROOT = join(tmpdir(), `imhub-media-test-${process.pid}-${Math.random().toString(36).slice(2)}`);
|
|
10
|
+
process.env.IMHUB_MEDIA_ROOT = TEST_ROOT;
|
|
11
|
+
// Import AFTER setting env so MEDIA_ROOT picks it up at module-eval time.
|
|
12
|
+
const { MEDIA_ROOT, MAX_BYTES, downloadToMediaRoot, cleanupOldMedia, pickExtension } = await import('./media-download.js');
|
|
13
|
+
describe('media-download — pickExtension', () => {
|
|
14
|
+
it('extracts ext from file_path', () => {
|
|
15
|
+
expect(pickExtension('photos/file_123.jpg', undefined)).toBe('jpg');
|
|
16
|
+
expect(pickExtension('docs/X.PNG', undefined)).toBe('png');
|
|
17
|
+
});
|
|
18
|
+
it('falls back to mime when file_path has none', () => {
|
|
19
|
+
expect(pickExtension(undefined, 'image/png')).toBe('png');
|
|
20
|
+
expect(pickExtension('noext', 'image/jpeg')).toBe('jpg');
|
|
21
|
+
expect(pickExtension(undefined, 'audio/ogg')).toBe('ogg');
|
|
22
|
+
});
|
|
23
|
+
it('returns "bin" when nothing matches', () => {
|
|
24
|
+
expect(pickExtension(undefined, undefined)).toBe('bin');
|
|
25
|
+
// octet-stream contains a hyphen which our minimal regex doesn't capture;
|
|
26
|
+
// fallback to "bin" is fine — generic binary anyway.
|
|
27
|
+
expect(pickExtension(undefined, 'application/octet-stream')).toBe('bin');
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe('media-download — safety guards', () => {
|
|
31
|
+
it('uses the env-overridden MEDIA_ROOT', () => {
|
|
32
|
+
expect(MEDIA_ROOT).toBe(TEST_ROOT);
|
|
33
|
+
});
|
|
34
|
+
it('rejects unsafe filenames (slashes / dotdot)', async () => {
|
|
35
|
+
await expect(downloadToMediaRoot({
|
|
36
|
+
url: 'https://api.telegram.org/file/botX/Y',
|
|
37
|
+
subdir: 'telegram/123',
|
|
38
|
+
filename: '../escape.jpg',
|
|
39
|
+
})).rejects.toThrow(/unsafe filename/);
|
|
40
|
+
await expect(downloadToMediaRoot({
|
|
41
|
+
url: 'https://api.telegram.org/file/botX/Y',
|
|
42
|
+
subdir: 'telegram/123',
|
|
43
|
+
filename: 'a/b.jpg',
|
|
44
|
+
})).rejects.toThrow(/unsafe filename/);
|
|
45
|
+
});
|
|
46
|
+
it('rejects non-telegram hosts', async () => {
|
|
47
|
+
await expect(downloadToMediaRoot({
|
|
48
|
+
url: 'https://evil.example.com/x.jpg',
|
|
49
|
+
subdir: 'telegram/123',
|
|
50
|
+
filename: '1.jpg',
|
|
51
|
+
})).rejects.toThrow(/api\.telegram\.org/);
|
|
52
|
+
});
|
|
53
|
+
it('rejects non-https schemes', async () => {
|
|
54
|
+
await expect(downloadToMediaRoot({
|
|
55
|
+
url: 'http://api.telegram.org/file/botX/Y',
|
|
56
|
+
subdir: 'telegram/123',
|
|
57
|
+
filename: '1.jpg',
|
|
58
|
+
})).rejects.toThrow(/api\.telegram\.org/);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
describe('media-download — cleanupOldMedia', () => {
|
|
62
|
+
beforeAll(async () => {
|
|
63
|
+
await mkdir(TEST_ROOT, { recursive: true });
|
|
64
|
+
});
|
|
65
|
+
afterAll(async () => {
|
|
66
|
+
await rm(TEST_ROOT, { recursive: true, force: true }).catch(() => { });
|
|
67
|
+
});
|
|
68
|
+
beforeEach(async () => {
|
|
69
|
+
// Fresh tree each test
|
|
70
|
+
await rm(TEST_ROOT, { recursive: true, force: true }).catch(() => { });
|
|
71
|
+
await mkdir(TEST_ROOT, { recursive: true });
|
|
72
|
+
});
|
|
73
|
+
it('deletes only files older than the TTL', async () => {
|
|
74
|
+
const dir = join(TEST_ROOT, 'telegram', '111');
|
|
75
|
+
await mkdir(dir, { recursive: true });
|
|
76
|
+
const oldPath = join(dir, 'old.jpg');
|
|
77
|
+
const newPath = join(dir, 'new.jpg');
|
|
78
|
+
await writeFile(oldPath, 'old');
|
|
79
|
+
await writeFile(newPath, 'new');
|
|
80
|
+
// Make oldPath 10 days old
|
|
81
|
+
const tenDaysAgo = Date.now() - 10 * 24 * 60 * 60 * 1000;
|
|
82
|
+
await utimes(oldPath, tenDaysAgo / 1000, tenDaysAgo / 1000);
|
|
83
|
+
const result = await cleanupOldMedia(7 * 24 * 60 * 60 * 1000);
|
|
84
|
+
expect(result.deleted).toBe(1);
|
|
85
|
+
expect(result.kept).toBe(1);
|
|
86
|
+
// Verify which is which
|
|
87
|
+
await expect(stat(oldPath)).rejects.toThrow();
|
|
88
|
+
const newStat = await stat(newPath);
|
|
89
|
+
expect(newStat.isFile()).toBe(true);
|
|
90
|
+
});
|
|
91
|
+
it('removes empty directories left behind after cleanup', async () => {
|
|
92
|
+
const dir = join(TEST_ROOT, 'telegram', '222');
|
|
93
|
+
await mkdir(dir, { recursive: true });
|
|
94
|
+
const filePath = join(dir, 'old.png');
|
|
95
|
+
await writeFile(filePath, 'x');
|
|
96
|
+
const longAgo = Date.now() - 100 * 24 * 60 * 60 * 1000;
|
|
97
|
+
await utimes(filePath, longAgo / 1000, longAgo / 1000);
|
|
98
|
+
await cleanupOldMedia(7 * 24 * 60 * 60 * 1000);
|
|
99
|
+
// Directory should be pruned
|
|
100
|
+
const left = await readdir(TEST_ROOT).catch(() => []);
|
|
101
|
+
expect(left).not.toContain('telegram');
|
|
102
|
+
});
|
|
103
|
+
it('is a no-op when MEDIA_ROOT does not exist', async () => {
|
|
104
|
+
await rm(TEST_ROOT, { recursive: true, force: true });
|
|
105
|
+
const result = await cleanupOldMedia(1000);
|
|
106
|
+
expect(result.deleted).toBe(0);
|
|
107
|
+
expect(result.kept).toBe(0);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe('media-download — downloadToMediaRoot (real curl against local server)', () => {
|
|
111
|
+
// The HTTPS-only / api.telegram.org-only host check fires BEFORE we reach
|
|
112
|
+
// curl, so we can't easily exercise the curl path against a local plain-
|
|
113
|
+
// HTTP server through downloadToMediaRoot directly. The safety guards
|
|
114
|
+
// above already cover the most important policy. Rather than spinning up
|
|
115
|
+
// a local TLS-terminating server with a self-signed cert just for unit
|
|
116
|
+
// tests, we lean on:
|
|
117
|
+
// - the safety-guard tests above
|
|
118
|
+
// - manual end-to-end verification via a real TG voice / image upload
|
|
119
|
+
//
|
|
120
|
+
// If this path regresses, expect to see "[图片附件下载失败:...]" or
|
|
121
|
+
// "[语音附件下载失败:...]" markers on the user's screen — that's the
|
|
122
|
+
// observable contract.
|
|
123
|
+
it('runs', () => { expect(true).toBe(true); });
|
|
124
|
+
});
|
|
125
|
+
//# sourceMappingURL=media-download.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-download.test.js","sourceRoot":"","sources":["../../../../src/plugins/messengers/telegram/media-download.test.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,4EAA4E;AAC5E,6EAA6E;AAC7E,mCAAmC;AAEnC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAa,SAAS,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAC3F,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAA;AAC3B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,oBAAoB,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;AAC1G,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,SAAS,CAAA;AAExC,0EAA0E;AAC1E,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,mBAAmB,EAAE,eAAe,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAA;AAE1H,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,aAAa,CAAC,qBAAqB,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACnE,MAAM,CAAC,aAAa,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC5D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACzD,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACxD,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC3D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACvD,0EAA0E;QAC1E,qDAAqD;QACrD,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,0BAA0B,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACpC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,MAAM,CACV,mBAAmB,CAAC;YAClB,GAAG,EAAE,sCAAsC;YAC3C,MAAM,EAAE,cAAc;YACtB,QAAQ,EAAE,eAAe;SAC1B,CAAC,CACH,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAA;QACpC,MAAM,MAAM,CACV,mBAAmB,CAAC;YAClB,GAAG,EAAE,sCAAsC;YAC3C,MAAM,EAAE,cAAc;YACtB,QAAQ,EAAE,SAAS;SACpB,CAAC,CACH,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAA;IACtC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,MAAM,CACV,mBAAmB,CAAC;YAClB,GAAG,EAAE,gCAAgC;YACrC,MAAM,EAAE,cAAc;YACtB,QAAQ,EAAE,OAAO;SAClB,CAAC,CACH,CAAC,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAA;IACzC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,MAAM,CACV,mBAAmB,CAAC;YAClB,GAAG,EAAE,qCAAqC;YAC1C,MAAM,EAAE,cAAc;YACtB,QAAQ,EAAE,OAAO;SAClB,CAAC,CACH,CAAC,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAA;IACzC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAChD,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7C,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,KAAK,IAAI,EAAE;QAClB,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;IACvE,CAAC,CAAC,CAAA;IAEF,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,uBAAuB;QACvB,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACrE,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,KAAK,CAAC,CAAA;QAC9C,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;QACpC,MAAM,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QAC/B,MAAM,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QAC/B,2BAA2B;QAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;QACxD,MAAM,MAAM,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC,CAAA;QAE3D,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;QAC7D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC9B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAE3B,wBAAwB;QACxB,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAA;QAC7C,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAA;QACnC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,KAAK,CAAC,CAAA;QAC9C,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;QACrC,MAAM,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;QACtD,MAAM,MAAM,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC,CAAA;QAEtD,MAAM,eAAe,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;QAE9C,6BAA6B;QAC7B,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAA;QACrD,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACrD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAA;QAC1C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC9B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC7B,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,uEAAuE,EAAE,GAAG,EAAE;IACrF,0EAA0E;IAC1E,yEAAyE;IACzE,sEAAsE;IACtE,yEAAyE;IACzE,uEAAuE;IACvE,qBAAqB;IACrB,mCAAmC;IACnC,wEAAwE;IACxE,EAAE;IACF,4DAA4D;IAC5D,6DAA6D;IAC7D,uBAAuB;IACvB,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;AAC/C,CAAC,CAAC,CAAA"}
|