
Claude To Im
- 6.9k installs
- 2.8k repo stars
- Updated March 23, 2026
- op7418/claude-to-im-skill
A daemon-based bridge that forwards Claude Code or Codex agent sessions to messaging platforms, enabling mobile chat and remote tool permission approval through platform-specific interfaces.
About
claude-to-im bridges active Claude Code or Codex sessions to messaging platforms, letting developers chat with Claude from mobile devices. It forwards Claude replies to Telegram, Discord, Feishu/Lark, QQ, or WeChat and handles permission approval through inline buttons or text commands. The skill manages a background daemon that maintains WebSocket or long-polling connections to both the messaging platform and the local Claude SDK. Developers use subcommands (setup, start, stop, status, logs, reconfigure, doctor) to configure credentials, start/stop the bridge, and diagnose issues. Setup requires platform-specific bot tokens or QR login and validates credentials before writing config. The daemon persists across terminal sessions and stores data at ~/.claude-to-im/. Each platform has different capabilities: Telegram and Feishu support streaming previews and inline permission buttons, while QQ and WeChat use text commands only.
- Bridges Claude Code/Codex to Telegram, Discord, Feishu, QQ, WeChat for mobile chat and remote permission approval
- Manages background daemon with start/stop/status/logs/doctor subcommands and credential validation during setup
- Supports streaming previews and inline permission buttons on Telegram/Feishu; text-based permissions on QQ/WeChat
- Interactive setup wizard (Claude Code) collects tokens one at a time, masks secrets in output, validates credentials bef
- Feishu requires two-phase setup: publish permissions/bot first, then configure events/callbacks after bridge starts
Claude To Im by the numbers
- 6,929 all-time installs (skills.sh)
- +26 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #114 of 16,659 AI & Agent Building skills by installs in the Skillselion catalog
- Security screen: HIGH risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
claude-to-im capabilities & compatibility
Free (requires bot tokens or QR login from messaging platforms; Claude/Codex runtime costs separate)
- Capabilities
- bridge claude sessions to telegram/discord/feish · interactive credential setup with one field at a · token validation before writing config · daemon process management (start/stop/status/log · platform specific permission approval (inline bu · streaming preview support on telegram and feishu · diagnostic tooling with doctor subcommand · credential reconfiguration with masked secret di
- Works with
- openai
- Use cases
- orchestration · memory · planning
- Platforms
- macOS · Linux · Windows
- Runs
- Runs locally
- Pricing
- Free
What claude-to-im says it does
Bridge THIS Claude Code or Codex session to Telegram, Discord, Feishu/Lark, QQ, or WeChat so the user can chat with Claude from their phone.
Always mask secrets in output (show only last 4 characters) — users often share terminal output in bug reports, so exposed tokens would be a security incident.
npx skills add https://github.com/op7418/claude-to-im-skill --skill claude-to-imAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 6.9k |
|---|---|
| repo stars | ★ 2.8k |
| Security audit | 2 / 3 scanners passed |
| Last updated | March 23, 2026 |
| Repository | op7418/claude-to-im-skill ↗ |
What it does
Bridge Claude Code/Codex sessions to messaging platforms (Telegram, Discord, Feishu, QQ, WeChat) so developers can chat with Claude from their phone and approve tool permissions remotely.
Who is it for?
Developers who need mobile access to Claude agent sessions, remote approval of tool permissions during long-running tasks, or team-based Claude interactions through messaging platforms.
Skip if: Building standalone chatbots unrelated to Claude sessions, webhook integrations, or coding with messaging platform SDKs (those are regular programming tasks).
When should I use this skill?
Setting up a bridge between Claude and a messaging platform, starting or stopping the bridge daemon, diagnosing connection issues, or reconfiguring credentials after platform changes.
What you get
Developers can chat with Claude and approve tool permissions from their phone via Telegram/Discord/Feishu/QQ/WeChat while the agent session runs on their desktop.
- Background daemon process forwarding messages between Claude and messaging platform
- Config file at ~/.claude-to-im/config.env with validated credentials
- Platform-specific bot or linked account receiving Claude replies
By the numbers
- Supports 5 messaging platforms: Telegram, Discord, Feishu/Lark, QQ, WeChat
- 7 subcommands: setup, start, stop, status, logs, reconfigure, doctor
- Feishu requires 6 additional permissions for full functionality (cardkit:card:write, cardkit:card:read, im:message:updat
Files
Claude-to-IM Bridge Skill
You are managing the Claude-to-IM bridge. User data is stored at ~/.claude-to-im/.
The skill directory (SKILL_DIR) is at ~/.claude/skills/claude-to-im. In Codex installs it may instead be ~/.codex/skills/Claude-to-IM-skill. If neither path exists, fall back to Glob with pattern **/skills/**/claude-to-im/SKILL.md or **/skills/**/Claude-to-IM-skill/SKILL.md and derive the root from the result.
Command parsing
Parse the user's intent from $ARGUMENTS into one of these subcommands:
| User says (examples) | Subcommand |
|---|---|
setup, configure, 配置, 我想在飞书上用 Claude, 帮我连接 Telegram, 帮我接微信 | setup |
start, start bridge, 启动, 启动桥接 | start |
stop, stop bridge, 停止, 停止桥接 | stop |
status, bridge status, 状态, 运行状态, 怎么看桥接的运行状态 | status |
logs, logs 200, 查看日志, 查看日志 200 | logs |
reconfigure, 修改配置, 帮我改一下 token, 换个 bot | reconfigure |
doctor, diagnose, 诊断, 挂了, 没反应了, bot 没反应, 出问题了 | doctor |
Disambiguation: `status` vs `doctor` — Use status when the user just wants to check if the bridge is running (informational). Use doctor when the user reports a problem or suspects something is broken (diagnostic). When in doubt and the user describes a symptom (e.g., "没反应了", "挂了"), prefer doctor.
Extract optional numeric argument for logs (default 50).
Before asking users for any platform credentials, read SKILL_DIR/references/setup-guides.md internally so you know where to find each credential. Do NOT dump the full guide to the user upfront — only mention the specific next step they need to do (e.g., "Go to https://open.feishu.cn → your app → Credentials to find the App ID"). If the user says they don't know how, then show the relevant section of the guide.
Runtime detection
Before executing any subcommand, detect which environment you are running in:
1. Claude Code — AskUserQuestion tool is available. Use it for interactive setup wizards. 2. Codex / other — AskUserQuestion is NOT available. Fall back to non-interactive guidance: explain the steps, show SKILL_DIR/config.env.example, and ask the user to create ~/.claude-to-im/config.env manually.
You can test this by checking if AskUserQuestion is in your available tools list.
Config check (applies to start, stop, status, logs, reconfigure, doctor)
Before running any subcommand other than setup, check if ~/.claude-to-im/config.env exists:
- If it does NOT exist:
- In Claude Code: tell the user "No configuration found" and automatically start the
setupwizard using AskUserQuestion. - In Codex: tell the user "No configuration found. Please create
~/.claude-to-im/config.envbased on the example:" then show the contents ofSKILL_DIR/config.env.exampleand stop. Don't attempt to start the daemon — without config.env the process will crash on startup and leave behind a stale PID file that blocks future starts. - If it exists: proceed with the requested subcommand.
Subcommands
setup
Run an interactive setup wizard. This subcommand requires AskUserQuestion. If it is not available (Codex environment), instead show the contents of SKILL_DIR/config.env.example with field-by-field explanations and instruct the user to create the config file manually.
When AskUserQuestion IS available, collect input one field at a time. After each answer, confirm the value back to the user (masking secrets to last 4 chars only) before moving to the next question.
Step 1 — Choose channels
Ask which channels to enable (telegram, discord, feishu, qq, weixin). Accept comma-separated input. Briefly describe each:
- telegram — Best for personal use. Streaming preview, inline permission buttons.
- discord — Good for team use. Server/channel/user-level access control.
- feishu (Lark) — For Feishu/Lark teams. Streaming cards, tool progress, inline permission buttons.
- qq — QQ C2C private chat only. No inline permission buttons, no streaming preview. Permissions use text
/perm ...commands. - weixin — WeChat QR login. Single linked account only; a new login replaces the previous one. No inline permission buttons, no streaming preview. Permissions use text
/perm ...commands or quick1/2/3replies. Voice messages only use WeChat's own speech-to-text text; raw voice audio is not transcribed by the bridge.
Step 2 — Collect tokens per channel
For each enabled channel, collect one credential at a time. Tell the user where to find each value in one sentence. Only show the full guide section (from SKILL_DIR/references/setup-guides.md) if the user asks for help or says they don't know how:
- Telegram: Bot Token → confirm (masked) → Chat ID (see guide for how to get it) → confirm → Allowed User IDs (optional). Important: At least one of Chat ID or Allowed User IDs must be set, otherwise the bot will reject all messages.
- Discord: Bot Token → confirm (masked) → Allowed User IDs → Allowed Channel IDs (optional) → Allowed Guild IDs (optional). Important: At least one of Allowed User IDs or Allowed Channel IDs must be set, otherwise the bot will reject all messages (default-deny).
- Feishu: App ID → confirm → App Secret → confirm (masked) → Domain (optional) → Allowed User IDs (optional). After collecting credentials, explain the two-phase setup the user must complete:
- Phase 1 (before starting bridge): (A) batch-add permissions, (B) enable bot capability, (C) publish first version + admin approve. This makes permissions and bot effective.
- Phase 2 (requires running bridge): (D) run
/claude-to-im start, (E) configure events (im.message.receive_v1) and callback (card.action.trigger) with long connection mode, (F) publish second version + admin approve. - Why two phases: Feishu validates WebSocket connection when saving event subscription — if the bridge isn't running, saving will fail. The bridge needs published permissions to connect.
- Keep this to a short checklist — show the full guide only if asked.
- QQ: Collect two required fields, then optional ones:
1. QQ App ID (required) → confirm 2. QQ App Secret (required) → confirm (masked)
- Tell the user: these two values can be found at https://q.qq.com/qqbot/openclaw
3. Allowed User OpenIDs (optional, press Enter to skip) — note: this is user_openid, NOT QQ number. If the user doesn't have openid yet, they can leave it empty. 4. Image Enabled (optional, default true, press Enter to skip) — if the underlying provider doesn't support image input, set to false 5. Max Image Size MB (optional, default 20, press Enter to skip)
- Remind user: QQ first version only supports C2C private chat sandbox access. No group/channel support, no inline buttons, no streaming preview.
- Weixin: Do not ask for a static token. Instead:
1. Tell the user this channel uses QR login, not manual credential entry. 2. Run cd SKILL_DIR && npm run weixin:login 3. The helper writes ~/.claude-to-im/runtime/weixin-login.html and tries to open it automatically in the local browser. 4. If auto-open fails, tell the user to open that HTML file manually and scan the QR code with WeChat. 5. Wait for the helper to report success, then confirm that the linked account was saved locally.
- Explain briefly: the linked Weixin account is stored in
~/.claude-to-im/data/weixin-accounts.json. Running the helper again replaces the previously linked account. - Explain briefly:
CTI_WEIXIN_MEDIA_ENABLEDonly controls inbound image/file/video downloads. For voice messages, the bridge only accepts the text returned by WeChat's built-in speech-to-text. If WeChat does not provide a transcript, the bridge replies with an error instead of downloading/transcribing raw audio.
Step 3 — General settings
Ask for runtime, default working directory, model, and mode:
- Runtime:
claude(default),codex,auto claude— uses Claude Code CLI + Claude Agent SDK (requiresclaudeCLI installed)codex— uses OpenAI Codex SDK (requirescodexCLI; auth viacodex auth loginorOPENAI_API_KEY)auto— tries Claude first, falls back to Codex if Claude CLI not found- Working Directory: default
$CWD - Model (optional): Leave blank to inherit the runtime's own default model. If the user wants to override, ask them to enter a model name. Do NOT hardcode or suggest specific model names — the available models change over time.
- Mode:
code(default),plan,ask
Step 4 — Write config and validate
1. Show a final summary table with all settings (secrets masked to last 4 chars) 2. Ask user to confirm before writing 3. Use Bash to create directory structure: mkdir -p ~/.claude-to-im/{data,logs,runtime,data/messages} 4. Use Write to create ~/.claude-to-im/config.env with all settings in KEY=VALUE format 5. Use Bash to set permissions: chmod 600 ~/.claude-to-im/config.env 6. Validate tokens — read SKILL_DIR/references/token-validation.md for the exact commands and expected responses for each platform. This catches typos and wrong credentials before the user tries to start the daemon. For Weixin, a successful QR login already counts as validation. 7. Report results with a summary table. If any validation fails, explain what might be wrong and how to fix it. 8. On success, tell the user: "Setup complete! Run /claude-to-im start to start the bridge."
start
Pre-check: Verify ~/.claude-to-im/config.env exists (see "Config check" above). Without it, the daemon will crash immediately and leave a stale PID file.
Run: bash "SKILL_DIR/scripts/daemon.sh" start
Show the output to the user. If it fails, tell the user:
- Run
doctorto diagnose:/claude-to-im doctor - Check recent logs:
/claude-to-im logs
stop
Run: bash "SKILL_DIR/scripts/daemon.sh" stop
status
Run: bash "SKILL_DIR/scripts/daemon.sh" status
logs
Extract optional line count N from arguments (default 50). Run: bash "SKILL_DIR/scripts/daemon.sh" logs N
reconfigure
1. Read current config from ~/.claude-to-im/config.env 2. Show current settings in a clear table format, with all secrets masked (only last 4 chars visible) 3. Use AskUserQuestion to ask what the user wants to change 4. When collecting new values, tell the user where to find the value; only show the full guide from SKILL_DIR/references/setup-guides.md if they ask for help 5. Update the config file atomically (write to tmp, rename) 6. Re-validate any changed tokens 7. Remind user: "Run /claude-to-im stop then /claude-to-im start to apply the changes."
If the user wants to switch Weixin accounts during reconfigure, run cd SKILL_DIR && npm run weixin:login again. Each successful scan replaces the previously linked local account.
doctor
Run: bash "SKILL_DIR/scripts/doctor.sh"
Show results and suggest fixes for any failures. Common fixes:
- SDK cli.js missing →
cd SKILL_DIR && npm install - dist/daemon.mjs stale →
cd SKILL_DIR && npm run build - Config missing → run
setup - Weixin account missing / expired →
cd SKILL_DIR && npm run weixin:login - Weixin voice message reports missing speech-to-text → enable WeChat's own voice transcription and resend; the bridge does not transcribe raw voice audio itself
For more complex issues (messages not received, permission timeouts, high memory, stale PID files), read SKILL_DIR/references/troubleshooting.md for detailed diagnosis steps.
Feishu upgrade note: If the user upgraded from an older version of this skill and Feishu is returning permission errors (e.g. streaming cards not working, typing indicators failing, permission buttons unresponsive), the root cause is almost certainly missing permissions or callbacks in the Feishu backend. Refer the user to the "Upgrading from a previous version" section in SKILL_DIR/references/setup-guides.md — they need to add new scopes (cardkit:card:write, cardkit:card:read, im:message:update, im:message.reactions:read, im:message.reactions:write_only), add the card.action.trigger callback, and re-publish the app. The upgrade requires two publish cycles because adding the callback needs an active WebSocket connection (bridge must be running).
Notes
- Always mask secrets in output (show only last 4 characters) — users often share terminal output in bug reports, so exposed tokens would be a security incident.
- Always check for config.env before starting the daemon — without it the process crashes on startup and leaves a stale PID file that blocks future starts (requiring manual cleanup).
- The daemon runs as a background Node.js process managed by platform supervisor (launchd on macOS, setsid on Linux, WinSW/NSSM on Windows).
- Config persists at
~/.claude-to-im/config.env— survives across sessions.
node_modules/
dist/
*.tgz
.env
config.env
CLAUDE.md — Project Guidelines for claude-to-im-skill
Replying to GitHub Issues
When replying to user-reported issues, always include a self-help prompt at the end of the reply. Guide users to use their AI coding assistant (Claude Code / Codex) to diagnose and fix the problem themselves. Example:
自助排查提示: 你可以直接在 Claude Code(或 Codex)中发送以下提示,让 AI 帮你诊断问题:
>
```
请帮我排查 claude-to-im 桥接服务的问题。
1. 读取 ~/.claude-to-im/logs/bridge.log 最近 50 行日志
2. 读取 ~/.claude-to-im/config.env 检查配置是否正确
3. 运行 bash ~/.claude/skills/claude-to-im/scripts/doctor.sh 并分析输出
4. 根据日志和配置给出具体的修复建议
```
This approach:
- Reduces maintainer burden by enabling users to self-diagnose
- Leverages the fact that users already have an AI coding assistant installed
- Provides actionable next steps rather than just error explanations
# Claude-to-IM Bridge Configuration
# Copy to ~/.claude-to-im/config.env and edit
# Runtime backend: claude | codex | auto
# claude (default) — uses Claude Code CLI + @anthropic-ai/claude-agent-sdk
# codex — uses @openai/codex-sdk (auth: codex auth login, or OPENAI_API_KEY)
# auto — tries Claude first, falls back to Codex if CLI not found
CTI_RUNTIME=claude
# Enabled channels (comma-separated: telegram,discord,feishu,qq,weixin)
CTI_ENABLED_CHANNELS=telegram
# Default working directory for Claude Code sessions
CTI_DEFAULT_WORKDIR=/path/to/your/project
# Default model (optional — inherits from runtime's own default if not set)
# CTI_DEFAULT_MODEL=
# Default mode (code, plan, ask)
CTI_DEFAULT_MODE=code
# ── Claude CLI path (optional) ──
# Override if you have multiple `claude` versions in PATH, or the daemon
# picks the wrong one (e.g. an npm-installed 1.x instead of the native 2.x).
# CTI_CLAUDE_CODE_EXECUTABLE=/path/to/claude
# ── Third-party API provider (optional) ──
# If you use Claude through a third-party API provider (not the default
# Anthropic API), set these so the daemon forwards them to the CLI subprocess.
# They are automatically passed through in both inherit and strict env modes.
# All ANTHROPIC_* vars in this file are forwarded to the launchd/setsid daemon.
# ANTHROPIC_API_KEY=your-third-party-api-key
# ANTHROPIC_BASE_URL=https://your-api-provider.com/v1
# ANTHROPIC_AUTH_TOKEN=your-auth-token
# ── Codex auth (optional — only if not using `codex auth login`) ──
# Priority: CTI_CODEX_API_KEY > CODEX_API_KEY > OPENAI_API_KEY
# CTI_CODEX_API_KEY=
# CTI_CODEX_BASE_URL=
# Allow Codex to run when CTI_DEFAULT_WORKDIR is not inside a trusted Git repo.
# Keep this off unless you intentionally want Codex to work in arbitrary folders.
# CTI_CODEX_SKIP_GIT_REPO_CHECK=true
# ── Telegram ──
CTI_TG_BOT_TOKEN=your-telegram-bot-token
# Chat ID for authorization (at least one of CHAT_ID or ALLOWED_USERS is required)
# Get it: send a message to the bot, then visit https://api.telegram.org/botYOUR_TOKEN/getUpdates
CTI_TG_CHAT_ID=your-chat-id
# CTI_TG_ALLOWED_USERS=user_id_1,user_id_2
# ── Discord ──
# CTI_DISCORD_BOT_TOKEN=your-discord-bot-token
# CTI_DISCORD_ALLOWED_USERS=user_id_1,user_id_2
# CTI_DISCORD_ALLOWED_CHANNELS=channel_id_1
# CTI_DISCORD_ALLOWED_GUILDS=guild_id_1
# ── Feishu / Lark ──
# CTI_FEISHU_APP_ID=your-app-id
# CTI_FEISHU_APP_SECRET=your-app-secret
# CTI_FEISHU_DOMAIN=https://open.feishu.cn
# CTI_FEISHU_ALLOWED_USERS=user_id_1,user_id_2
# ── QQ ──
# Required: obtain from https://q.qq.com/qqbot/openclaw
# CTI_QQ_APP_ID=your-qq-app-id
# CTI_QQ_APP_SECRET=your-qq-app-secret
# Allowed users — comma-separated user_openid values (NOT QQ numbers)
# CTI_QQ_ALLOWED_USERS=openid_1,openid_2
# Image input — set to false if the underlying provider doesn't support image input
# CTI_QQ_IMAGE_ENABLED=true
# Max image size in MB (default 20)
# CTI_QQ_MAX_IMAGE_SIZE=20
# ── WeChat / 微信 ──
# No static token is required here. Use the QR login helper to add accounts:
# npm run weixin:login
# Optional protocol overrides (normally leave unset)
# CTI_WEIXIN_BASE_URL=https://ilinkai.weixin.qq.com
# CTI_WEIXIN_CDN_BASE_URL=https://novac2c.cdn.weixin.qq.com/c2c
# Enable inbound media download/processing for image/file/video messages.
# Voice messages do not use raw audio download/transcription here: the bridge
# only accepts WeChat-provided speech-to-text text and otherwise returns an error.
# (default false for safety in CLI setups)
# CTI_WEIXIN_MEDIA_ENABLED=false
# ── Permission ──
# Auto-approve all tool permission requests without user confirmation.
# Useful for channels that lack interactive permission UI (e.g. Feishu
# WebSocket long-connection mode, where there is no HTTP webhook to
# render clickable approve/deny buttons).
# ⚠️ Only enable this in trusted, access-controlled environments.
# CTI_AUTO_APPROVE=true
{
"skill_name": "claude-to-im",
"evals": [
{
"id": 1,
"prompt": "帮我设置 Telegram 机器人,我想用手机给 Claude 发消息",
"expected_output": "Should trigger the skill, identify 'setup' subcommand, read setup-guides.md, and start the interactive Telegram setup wizard asking for Bot Token",
"files": []
},
{
"id": 2,
"prompt": "start bridge",
"expected_output": "Should trigger the skill, identify 'start' subcommand, check for config.env existence, and attempt to run daemon.sh start",
"files": []
},
{
"id": 3,
"prompt": "桥接服务好像挂了,帮我看看怎么回事",
"expected_output": "Should trigger the skill, identify 'doctor' subcommand, and run doctor.sh to diagnose issues",
"files": []
},
{
"id": 4,
"prompt": "查看日志 200",
"expected_output": "Should trigger the skill, identify 'logs' subcommand with N=200, and run daemon.sh logs 200",
"files": []
}
]
}
MIT License
Copyright (c) 2024-2025 op7418
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
{
"name": "claude-to-im-skill",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "claude-to-im-skill",
"version": "0.1.0",
"dependencies": {
"@anthropic-ai/claude-agent-sdk": "^0.2.62",
"claude-to-im": "file:../Claude-to-IM",
"qrcode": "^1.5.4"
},
"devDependencies": {
"@types/node": "^22",
"esbuild": "^0.25.0",
"tsx": "^4.21.0",
"typescript": "^5"
},
"engines": {
"node": ">=20"
},
"optionalDependencies": {
"@openai/codex-sdk": "^0.110.0"
}
},
"../Claude-to-IM": {
"name": "claude-to-im",
"version": "0.1.0",
"dependencies": {
"@anthropic-ai/claude-agent-sdk": "^0.2.62",
"@larksuiteoapi/node-sdk": "^1.59.0",
"discord.js": "^14.25.1",
"markdown-it": "^14.1.1",
"ws": "^8.18.0"
},
"devDependencies": {
"@types/markdown-it": "^14.1.2",
"@types/node": "^22.0.0",
"@types/ws": "^8.5.0",
"tsx": "^4.21.0",
"typescript": "^5"
},
"engines": {
"node": ">=20"
}
},
"node_modules/@anthropic-ai/claude-agent-sdk": {
"version": "0.2.69",
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.2.69.tgz",
"integrity": "sha512-d1ZadIwC5PUBMQRK4Y/EC/Fm9xv/nvZ4g0XXa+vC0p+vKOCxhf4USdVKjuDzPM0z0f2qqZZZdxMjFuwa7paKRA==",
"license": "SEE LICENSE IN README.md",
"engines": {
"node": ">=18.0.0"
},
"optionalDependencies": {
"@img/sharp-darwin-arm64": "^0.34.2",
"@img/sharp-darwin-x64": "^0.34.2",
"@img/sharp-linux-arm": "^0.34.2",
"@img/sharp-linux-arm64": "^0.34.2",
"@img/sharp-linux-x64": "^0.34.2",
"@img/sharp-linuxmusl-arm64": "^0.34.2",
"@img/sharp-linuxmusl-x64": "^0.34.2",
"@img/sharp-win32-arm64": "^0.34.2",
"@img/sharp-win32-x64": "^0.34.2"
},
"peerDependencies": {
"zod": "^4.0.0"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
"integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
"integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
"integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
"integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
"integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
"integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
"integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
"integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
"integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
"integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
"integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
"integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
"integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
"integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
"integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
"integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
"integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
"integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
"integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
"integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
"integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
"integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
"integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
"integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
"integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
"integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@img/sharp-darwin-arm64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
"integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
"cpu": [
"arm64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-darwin-arm64": "1.2.4"
}
},
"node_modules/@img/sharp-darwin-x64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
"integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
"cpu": [
"x64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-darwin-x64": "1.2.4"
}
},
"node_modules/@img/sharp-libvips-darwin-arm64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
"integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
"cpu": [
"arm64"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"darwin"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-darwin-x64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
"integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
"cpu": [
"x64"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"darwin"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-arm": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
"integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
"cpu": [
"arm"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-arm64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
"integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
"cpu": [
"arm64"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-x64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
"integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
"cpu": [
"x64"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
"integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
"cpu": [
"arm64"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
"integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
"cpu": [
"x64"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-linux-arm": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
"integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
"cpu": [
"arm"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-arm": "1.2.4"
}
},
"node_modules/@img/sharp-linux-arm64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
"integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
"cpu": [
"arm64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-arm64": "1.2.4"
}
},
"node_modules/@img/sharp-linux-x64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
"integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
"cpu": [
"x64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-x64": "1.2.4"
}
},
"node_modules/@img/sharp-linuxmusl-arm64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
"integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
"cpu": [
"arm64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
}
},
"node_modules/@img/sharp-linuxmusl-x64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
"integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
"cpu": [
"x64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-x64": "1.2.4"
}
},
"node_modules/@img/sharp-win32-arm64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
"integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
"cpu": [
"arm64"
],
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-x64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
"integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
"cpu": [
"x64"
],
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@openai/codex": {
"version": "0.110.0",
"resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.110.0.tgz",
"integrity": "sha512-BhhiFkLAWwFZ4vo2WK7rlV5PoicndbIjONamPsHyp6xz5bvLQC5l2IgB4FgGpkuRywLxc5MnNlrziyhABNblcg==",
"license": "Apache-2.0",
"optional": true,
"bin": {
"codex": "bin/codex.js"
},
"engines": {
"node": ">=16"
},
"optionalDependencies": {
"@openai/codex-darwin-arm64": "npm:@openai/codex@0.110.0-darwin-arm64",
"@openai/codex-darwin-x64": "npm:@openai/codex@0.110.0-darwin-x64",
"@openai/codex-linux-arm64": "npm:@openai/codex@0.110.0-linux-arm64",
"@openai/codex-linux-x64": "npm:@openai/codex@0.110.0-linux-x64",
"@openai/codex-win32-arm64": "npm:@openai/codex@0.110.0-win32-arm64",
"@openai/codex-win32-x64": "npm:@openai/codex@0.110.0-win32-x64"
}
},
"node_modules/@openai/codex-darwin-arm64": {
"name": "@openai/codex",
"version": "0.110.0-darwin-arm64",
"resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.110.0-darwin-arm64.tgz",
"integrity": "sha512-yCrO3HLpohNM5zqqEzJhqtBBAH4r9nHb+h7F0+2/T0qbCJwxzL6XtgjQonvKW9Ol6qc3kqlW7uQVFEX+z13Ydg==",
"cpu": [
"arm64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=16"
}
},
"node_modules/@openai/codex-darwin-x64": {
"name": "@openai/codex",
"version": "0.110.0-darwin-x64",
"resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.110.0-darwin-x64.tgz",
"integrity": "sha512-UgDkVR+9Ffky60Paygc48NjGjMpEi8HBl/GtVFuhYprvcFep0qodjcL6/K3NmmIpDOBoF4PtkjUFB/sATklfvw==",
"cpu": [
"x64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=16"
}
},
"node_modules/@openai/codex-linux-arm64": {
"name": "@openai/codex",
"version": "0.110.0-linux-arm64",
"resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.110.0-linux-arm64.tgz",
"integrity": "sha512-Mswcq2dmt1S+d2DeaxLUOu9AfVjs0O5b4M8fqvNzSeWozY6dw905JnU+nOKPlqP4xN4K6OK+H+zjSDFJXsmS6w==",
"cpu": [
"arm64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=16"
}
},
"node_modules/@openai/codex-linux-x64": {
"name": "@openai/codex",
"version": "0.110.0-linux-x64",
"resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.110.0-linux-x64.tgz",
"integrity": "sha512-o9xIcgU9U5mpljQx2b6v763qz3dU3eugxWCZMid6YU8hc1VZvR9hkWMFL0kaboYOKFkpZPLGg1bUFSWfsmZN+A==",
"cpu": [
"x64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=16"
}
},
"node_modules/@openai/codex-sdk": {
"version": "0.110.0",
"resolved": "https://registry.npmjs.org/@openai/codex-sdk/-/codex-sdk-0.110.0.tgz",
"integrity": "sha512-UT8OaFAOWBP6uXdpJkpKO1vPO/AqUqaCJMrIbazOuRC92zrMqhdX2DlyJJ+lN6ewHXLgNZBQ6yh/WUaoPXj/2w==",
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"@openai/codex": "0.110.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@openai/codex-win32-arm64": {
"name": "@openai/codex",
"version": "0.110.0-win32-arm64",
"resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.110.0-win32-arm64.tgz",
"integrity": "sha512-eFJtx66V+ohXbHPGz2aRdhYMfIFOL1dLwLvdGcBELBQu5CfNzsJNq+r1YKntHV2BwdwkUHcJYe+8B9/bzGXDXg==",
"cpu": [
"arm64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=16"
}
},
"node_modules/@openai/codex-win32-x64": {
"name": "@openai/codex",
"version": "0.110.0-win32-x64",
"resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.110.0-win32-x64.tgz",
"integrity": "sha512-kPdxMh6xDhn7kgknHzC6X0nOr5y5gE9HP/d5GcI95yN1jEGmY2maMGuB2iT2ZyWrD/8xknkaAXY+S9NMVKWbdQ==",
"cpu": [
"x64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=16"
}
},
"node_modules/@types/node": {
"version": "22.19.13",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.13.tgz",
"integrity": "sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/claude-to-im": {
"resolved": "../Claude-to-IM",
"link": true
},
"node_modules/cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
"license": "ISC",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^6.2.0"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
"node_modules/decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/dijkstrajs": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
"integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==",
"license": "MIT"
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"node_modules/esbuild": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
"integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.25.12",
"@esbuild/android-arm": "0.25.12",
"@esbuild/android-arm64": "0.25.12",
"@esbuild/android-x64": "0.25.12",
"@esbuild/darwin-arm64": "0.25.12",
"@esbuild/darwin-x64": "0.25.12",
"@esbuild/freebsd-arm64": "0.25.12",
"@esbuild/freebsd-x64": "0.25.12",
"@esbuild/linux-arm": "0.25.12",
"@esbuild/linux-arm64": "0.25.12",
"@esbuild/linux-ia32": "0.25.12",
"@esbuild/linux-loong64": "0.25.12",
"@esbuild/linux-mips64el": "0.25.12",
"@esbuild/linux-ppc64": "0.25.12",
"@esbuild/linux-riscv64": "0.25.12",
"@esbuild/linux-s390x": "0.25.12",
"@esbuild/linux-x64": "0.25.12",
"@esbuild/netbsd-arm64": "0.25.12",
"@esbuild/netbsd-x64": "0.25.12",
"@esbuild/openbsd-arm64": "0.25.12",
"@esbuild/openbsd-x64": "0.25.12",
"@esbuild/openharmony-arm64": "0.25.12",
"@esbuild/sunos-x64": "0.25.12",
"@esbuild/win32-arm64": "0.25.12",
"@esbuild/win32-ia32": "0.25.12",
"@esbuild/win32-x64": "0.25.12"
}
},
"node_modules/find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"license": "MIT",
"dependencies": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"license": "ISC",
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
},
"node_modules/get-tsconfig": {
"version": "4.13.6",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz",
"integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==",
"dev": true,
"license": "MIT",
"dependencies": {
"resolve-pkg-maps": "^1.0.0"
},
"funding": {
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
}
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"license": "MIT",
"dependencies": {
"p-locate": "^4.1.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"license": "MIT",
"dependencies": {
"p-try": "^2.0.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"license": "MIT",
"dependencies": {
"p-limit": "^2.2.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/pngjs": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
"integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
"license": "MIT",
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/qrcode": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz",
"integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
"license": "MIT",
"dependencies": {
"dijkstrajs": "^1.0.1",
"pngjs": "^5.0.0",
"yargs": "^15.3.1"
},
"bin": {
"qrcode": "bin/qrcode"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"license": "ISC"
},
"node_modules/resolve-pkg-maps": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
}
},
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"license": "ISC"
},
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/tsx": {
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz",
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "~0.27.0",
"get-tsconfig": "^4.7.5"
},
"bin": {
"tsx": "dist/cli.mjs"
},
"engines": {
"node": ">=18.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.3"
}
},
"node_modules/tsx/node_modules/@esbuild/aix-ppc64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz",
"integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/android-arm": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz",
"integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/android-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz",
"integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/android-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz",
"integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/darwin-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz",
"integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/darwin-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz",
"integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/freebsd-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz",
"integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/freebsd-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz",
"integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-arm": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz",
"integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz",
"integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-ia32": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz",
"integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-loong64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz",
"integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-mips64el": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz",
"integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-ppc64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz",
"integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-riscv64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz",
"integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-s390x": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz",
"integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz",
"integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/netbsd-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz",
"integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/netbsd-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz",
"integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/openbsd-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz",
"integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/openbsd-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz",
"integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/openharmony-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz",
"integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/sunos-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz",
"integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/win32-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz",
"integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/win32-ia32": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz",
"integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/win32-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz",
"integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/esbuild": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz",
"integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.27.3",
"@esbuild/android-arm": "0.27.3",
"@esbuild/android-arm64": "0.27.3",
"@esbuild/android-x64": "0.27.3",
"@esbuild/darwin-arm64": "0.27.3",
"@esbuild/darwin-x64": "0.27.3",
"@esbuild/freebsd-arm64": "0.27.3",
"@esbuild/freebsd-x64": "0.27.3",
"@esbuild/linux-arm": "0.27.3",
"@esbuild/linux-arm64": "0.27.3",
"@esbuild/linux-ia32": "0.27.3",
"@esbuild/linux-loong64": "0.27.3",
"@esbuild/linux-mips64el": "0.27.3",
"@esbuild/linux-ppc64": "0.27.3",
"@esbuild/linux-riscv64": "0.27.3",
"@esbuild/linux-s390x": "0.27.3",
"@esbuild/linux-x64": "0.27.3",
"@esbuild/netbsd-arm64": "0.27.3",
"@esbuild/netbsd-x64": "0.27.3",
"@esbuild/openbsd-arm64": "0.27.3",
"@esbuild/openbsd-x64": "0.27.3",
"@esbuild/openharmony-arm64": "0.27.3",
"@esbuild/sunos-x64": "0.27.3",
"@esbuild/win32-arm64": "0.27.3",
"@esbuild/win32-ia32": "0.27.3",
"@esbuild/win32-x64": "0.27.3"
}
},
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true,
"license": "MIT"
},
"node_modules/which-module": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
"license": "ISC"
},
"node_modules/wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/y18n": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
"license": "ISC"
},
"node_modules/yargs": {
"version": "15.4.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
"license": "MIT",
"dependencies": {
"cliui": "^6.0.0",
"decamelize": "^1.2.0",
"find-up": "^4.1.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^18.1.2"
},
"engines": {
"node": ">=8"
}
},
"node_modules/yargs-parser": {
"version": "18.1.3",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
"license": "ISC",
"dependencies": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/zod": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
}
}
}
{
"name": "claude-to-im-skill",
"version": "0.1.0",
"description": "Claude Code Skill: Bridge IM platforms (Telegram, Discord, Feishu, QQ, WeChat) to Claude Code sessions",
"type": "module",
"scripts": {
"build": "node scripts/build.js",
"typecheck": "tsc --noEmit",
"dev": "tsx src/main.ts",
"weixin:login": "node --import tsx src/weixin-login.ts",
"test": "CTI_HOME=$(mktemp -d) node --test --test-concurrency=1 --import tsx --test-timeout=15000 src/__tests__/*.test.ts"
},
"dependencies": {
"@anthropic-ai/claude-agent-sdk": "^0.2.62",
"claude-to-im": "file:../Claude-to-IM",
"qrcode": "^1.5.4"
},
"optionalDependencies": {
"@openai/codex-sdk": "^0.110.0"
},
"devDependencies": {
"@types/node": "^22",
"esbuild": "^0.25.0",
"tsx": "^4.21.0",
"typescript": "^5"
},
"engines": {
"node": ">=20"
}
}
Claude-to-IM Skill
将 Claude Code / Codex 桥接到 IM 平台 —— 在 Telegram、Discord、飞书、QQ 或微信中与 AI 编程代理对话。
English
想要桌面图形界面? 试试 CodePilot —— 一个功能完整的桌面应用,提供可视化聊天界面、会话管理、文件树预览、权限控制等。本 Skill 从 CodePilot 的 IM 桥接模块中提取而来,适合偏好轻量级纯 CLI 方案的用户。
---
工作原理
本 Skill 运行一个后台守护进程,将你的 IM 机器人连接到 Claude Code 或 Codex 会话。来自 IM 的消息被转发给 AI 编程代理,响应(包括工具调用、权限请求、流式预览)会发回到聊天中。
你 (Telegram/Discord/飞书/QQ/微信)
↕ Bot API
后台守护进程 (Node.js)
↕ Claude Agent SDK 或 Codex SDK(通过 CTI_RUNTIME 配置)
Claude Code / Codex → 读写你的代码库功能特点
- 五大 IM 平台 — Telegram、Discord、飞书、QQ、微信,可任意组合启用
- 交互式配置 — 引导式向导逐步收集 token,附带详细获取说明
- 权限控制 — 工具调用需要在聊天中通过内联按钮(Telegram/Discord)或文本
/perm命令 / 快捷1/2/3回复(飞书/QQ/微信)明确批准 - 流式预览 — 实时查看 Claude 的输出(Telegram 和 Discord 支持)
- 会话持久化 — 对话在守护进程重启后保留
- 密钥保护 — token 以
chmod 600存储,日志中自动脱敏 - 无需编写代码 — 安装 Skill 后运行
/claude-to-im setup,或直接对 Codex 说claude-to-im setup
前置要求
- Node.js >= 20
- Claude Code CLI(
CTI_RUNTIME=claude或auto时需要)— 已安装并完成认证(claude命令可用) - Codex CLI(
CTI_RUNTIME=codex或auto时需要)—npm install -g @openai/codex。鉴权:运行codex auth login,或设置OPENAI_API_KEY(可选,API 模式)
安装
请先按你实际使用的 AI Agent 产品选择对应安装方式。
Claude Code
推荐:npx skills
npx skills add op7418/Claude-to-IM-skill安装完成后,直接对 Claude Code 说:
/claude-to-im setup如果你主要想接微信,也可以直接说:
帮我接微信备选:直接克隆到 Claude Code Skills 目录
git clone https://github.com/op7418/Claude-to-IM-skill.git ~/.claude/skills/claude-to-imClaude Code 会自动发现。
备选:符号链接方式(适合开发)
git clone https://github.com/op7418/Claude-to-IM-skill.git ~/code/Claude-to-IM-skill
mkdir -p ~/.claude/skills
ln -s ~/code/Claude-to-IM-skill ~/.claude/skills/claude-to-imCodex
推荐:使用 Codex 安装脚本
git clone https://github.com/op7418/Claude-to-IM-skill.git ~/code/Claude-to-IM-skill
bash ~/code/Claude-to-IM-skill/scripts/install-codex.sh如果你想保留可开发的本地仓库:
bash ~/code/Claude-to-IM-skill/scripts/install-codex.sh --link安装脚本会把 Skill 放到 ~/.codex/skills/claude-to-im,并自动安装依赖、构建 daemon。
安装完成后,直接对 Codex 说:
claude-to-im setup如果你主要想接微信,也可以直接说:
帮我接微信桥接备选:直接克隆到 Codex skills 目录
git clone https://github.com/op7418/Claude-to-IM-skill.git ~/.codex/skills/claude-to-im
cd ~/.codex/skills/claude-to-im
npm install
npm run build验证安装
Claude Code: 启动新会话,输入 / 应能看到 claude-to-im。也可以直接问 Claude:"What skills are available?"
Codex: 启动新会话,说 claude-to-im setup、start bridge 或 帮我接微信桥接。
更新 Skill
请按你的 AI Agent 产品和安装方式选择对应的更新方式。
Claude Code
如果你是通过 npx skills 安装的,直接重新执行:
npx skills add op7418/Claude-to-IM-skill如果你是通过 git clone 或符号链接安装的:
cd ~/.claude/skills/claude-to-im
git pull
npm install
npm run build更新完成后,对 Claude Code 说:
/claude-to-im doctor
/claude-to-im startCodex
如果你是用 install-codex.sh 的复制模式安装的:
rm -rf ~/.codex/skills/claude-to-im
bash ~/code/Claude-to-IM-skill/scripts/install-codex.sh如果你是用 --link 模式,或者直接克隆到 Codex skills 目录:
cd ~/.codex/skills/claude-to-im
git pull
npm install
npm run build更新完成后,对 Codex 说:
claude-to-im doctor
start bridge快速开始
1. 配置
Claude Code
/claude-to-im setupCodex
claude-to-im setup向导会引导你完成以下步骤:
1. 选择渠道 — 选择 Telegram、Discord、飞书、QQ、微信,或任意组合 2. 输入凭据 — 向导会详细说明如何获取每个 token、需要开启哪些设置、授予哪些权限 3. 设置默认值 — 工作目录、模型、模式 4. 验证 — 立即通过平台 API 验证 token 有效性
2. 启动
Claude Code
/claude-to-im startCodex
start bridge守护进程在后台启动。关闭终端后仍会继续运行。
3. 开始聊天
打开 IM 应用,给你的机器人发消息,Claude Code / Codex 会通过桥接回复。
当 Claude 需要使用工具(编辑文件、运行命令)时,聊天中会弹出带有 允许 / 拒绝 按钮的权限请求(Telegram/Discord),或文本 /perm 命令提示 / 快捷 1/2/3 回复(飞书/QQ/微信)。
命令列表
所有命令在 Claude Code 或 Codex 中执行:
| Claude Code | Codex(自然语言) | 说明 |
|---|---|---|
/claude-to-im setup | "claude-to-im setup" / "配置" | 交互式配置向导 |
/claude-to-im start | "start bridge" / "启动桥接" | 启动桥接守护进程 |
/claude-to-im stop | "stop bridge" / "停止桥接" | 停止守护进程 |
/claude-to-im status | "bridge status" / "状态" | 查看运行状态 |
/claude-to-im logs | "查看日志" | 查看最近 50 行日志 |
/claude-to-im logs 200 | "logs 200" | 查看最近 200 行日志 |
/claude-to-im reconfigure | "reconfigure" / "修改配置" | 交互式修改配置 |
/claude-to-im doctor | "doctor" / "诊断" | 诊断问题 |
平台配置指南
setup 向导会在每一步提供内联指引,以下是概要:
Telegram
1. 在 Telegram 中搜索 @BotFather → 发送 /newbot → 按提示操作 2. 复制 bot token(格式:123456789:AABbCc...) 3. 建议:/setprivacy → Disable(用于群组) 4. 获取 User ID:给 @userinfobot 发消息
Discord
1. 前往 Discord 开发者门户 → 新建应用 2. Bot 标签页 → Reset Token → 复制 token 3. 在 Privileged Gateway Intents 下开启 Message Content Intent 4. OAuth2 → URL Generator → scope 选 bot → 权限选 Send Messages、Read Message History、View Channels → 复制邀请链接
飞书 / Lark
1. 前往飞书开放平台(或 Lark) 2. 创建自建应用 → 获取 App ID 和 App Secret 3. 批量添加权限:进入"权限管理" → 使用批量配置添加所有必需权限(setup 向导提供完整 JSON) 4. 在"添加应用能力"中启用机器人 5. 事件与回调:选择长连接作为事件订阅方式 → 添加 im.message.receive_v1 事件 6. 发布:进入"版本管理与发布" → 创建版本 → 提交审核 → 在管理后台审核通过 7. 注意:版本审核通过并发布后机器人才能使用
QQ 目前仅支持 C2C 私聊(沙箱接入)。不支持群聊/频道、内联权限按钮、流式预览。权限确认使用文本 /perm ... 命令。仅支持图片入站(不支持图片回复)。1. 前往 QQ 机器人 OpenClaw 2. 创建或选择已有 QQ 机器人 → 获取 App ID 和 App Secret(仅需这两个必填项) 3. 配置沙箱接入,用 QQ 扫码添加机器人 4. CTI_QQ_ALLOWED_USERS 填写 user_openid(不是 QQ 号)— 可先留空 5. 如果底层 provider 不支持图片输入,设置 CTI_QQ_IMAGE_ENABLED=false
微信 / Weixin
微信当前采用扫码登录、单账号模式、文本权限确认,不支持流式预览。
1. 在已安装的 Skill 目录里运行本地扫码工具:
- Claude Code 默认安装:
cd ~/.claude/skills/claude-to-im && npm run weixin:login - Codex 默认安装:
cd ~/.codex/skills/claude-to-im && npm run weixin:login
2. 工具会生成 ~/.claude-to-im/runtime/weixin-login.html,并尽量自动用浏览器打开 3. 用微信扫码并在手机上确认 4. 成功后,账号会保存到 ~/.claude-to-im/data/weixin-accounts.json 5. 再次运行扫码工具,会替换当前已绑定的微信账号
补充说明:
CTI_WEIXIN_MEDIA_ENABLED只控制图片 / 文件 / 视频的入站下载- 语音消息只使用微信自带的语音转文字结果
- 如果微信没有提供
voice_item.text,桥会直接报错,不会自行下载或转写原始语音 - 权限确认使用文本
/perm ...命令或快捷1/2/3回复
架构
~/.claude-to-im/
├── config.env ← 凭据与配置 (chmod 600)
├── data/ ← 持久化 JSON 存储
│ ├── sessions.json
│ ├── bindings.json
│ ├── permissions.json
│ └── messages/ ← 按会话分文件的消息历史
├── logs/
│ └── bridge.log ← 自动轮转,密钥脱敏
└── runtime/
├── bridge.pid ← 守护进程 PID 文件
└── status.json ← 当前状态核心组件
| 组件 | 职责 |
|---|---|
src/main.ts | 守护进程入口,组装依赖注入,启动 bridge |
src/config.ts | 加载/保存 config.env,映射为 bridge 设置 |
src/store.ts | JSON 文件 BridgeStore(30 个方法,写穿缓存) |
src/llm-provider.ts | Claude Agent SDK query() → SSE 流 |
src/codex-provider.ts | Codex SDK runStreamed() → SSE 流 |
src/sse-utils.ts | 共享的 SSE 格式化辅助函数 |
src/permission-gateway.ts | 异步桥接:SDK canUseTool ↔ IM 按钮 |
src/logger.ts | 密钥脱敏的文件日志,支持轮转 |
scripts/daemon.sh | 进程管理(start/stop/status/logs) |
scripts/doctor.sh | 诊断检查 |
SKILL.md | Claude Code Skill 定义文件 |
权限流程
1. Claude 想使用工具(如编辑文件)
2. SDK 调用 canUseTool() → LLMProvider 发射 permission_request SSE 事件
3. Bridge 在 IM 聊天中发送内联按钮:[允许] [拒绝]
4. canUseTool() 阻塞等待用户响应(5 分钟超时)
5. 用户点击允许 → Bridge 解除权限等待
6. SDK 继续执行工具 → 结果流式发回 IM故障排查
运行诊断:
/claude-to-im doctor检查项目:Node.js 版本、配置文件是否存在及权限、token 有效性(实时 API 调用)、日志目录、PID 文件一致性、最近的错误。
| 问题 | 解决方案 |
|---|---|
Bridge 无法启动 | 运行 doctor,检查 Node 版本和日志 |
收不到消息 | 用 doctor 验证 token,检查允许用户配置 |
权限超时 | 用户 5 分钟内未响应,工具调用自动拒绝 |
PID 文件残留 | 运行 stop 再 start,脚本会自动清理 |
详见 references/troubleshooting.md。
安全
- 所有凭据存储在
~/.claude-to-im/config.env,权限chmod 600 - 日志输出中 token 自动脱敏(基于正则匹配)
- 允许用户/频道/服务器列表限制谁可以与机器人交互
- 守护进程是本地进程,没有入站网络监听
- 详见 SECURITY.md 了解威胁模型和应急响应
开发
npm install # 安装依赖
npm run dev # 开发模式运行
npm run typecheck # 类型检查
npm test # 运行测试
npm run build # 构建打包许可
MIT
Claude-to-IM Skill
Bridge Claude Code / Codex to IM platforms — chat with AI coding agents from Telegram, Discord, Feishu/Lark, QQ, or WeChat.
中文文档
Want a desktop GUI instead? Check out CodePilot — a full-featured desktop app with visual chat interface, session management, file tree preview, permission controls, and more. This skill was extracted from CodePilot's IM bridge module for users who prefer a lightweight, CLI-only setup.
---
How It Works
This skill runs a background daemon that connects your IM bots to Claude Code or Codex sessions. Messages from IM are forwarded to the AI coding agent, and responses (including tool use, permission requests, streaming previews) are sent back to your chat.
You (Telegram/Discord/Feishu/QQ/WeChat)
↕ Bot API
Background Daemon (Node.js)
↕ Claude Agent SDK or Codex SDK (configurable via CTI_RUNTIME)
Claude Code / Codex → reads/writes your codebaseFeatures
- Five IM platforms — Telegram, Discord, Feishu/Lark, QQ, WeChat — enable any combination
- Interactive setup — guided wizard collects tokens with step-by-step instructions
- Permission control — tool calls require explicit approval via inline buttons (Telegram/Discord) or text
/permcommands / quick1/2/3replies (Feishu/QQ/WeChat) - Streaming preview — see Claude's response as it types (Telegram & Discord)
- Session persistence — conversations survive daemon restarts
- Secret protection — tokens stored with
chmod 600, auto-redacted in all logs - Zero code required — install the skill and run
/claude-to-im setup, or tell Codexclaude-to-im setup
Prerequisites
- Node.js >= 20
- Claude Code CLI (for
CTI_RUNTIME=claudeorauto) — installed and authenticated (claudecommand available) - Codex CLI (for
CTI_RUNTIME=codexorauto) —npm install -g @openai/codex. Auth: runcodex auth login, or setOPENAI_API_KEY(optional, for API mode)
Installation
Choose the section that matches the AI agent product you actually use.
Claude Code
Recommended: npx skills
npx skills add op7418/Claude-to-IM-skillAfter installation, tell Claude Code:
/claude-to-im setupIf you want WeChat specifically, you can also say:
帮我接微信Alternative: clone directly into Claude Code skills
git clone https://github.com/op7418/Claude-to-IM-skill.git ~/.claude/skills/claude-to-imClaude Code discovers it automatically.
Alternative: symlink for development
git clone https://github.com/op7418/Claude-to-IM-skill.git ~/code/Claude-to-IM-skill
mkdir -p ~/.claude/skills
ln -s ~/code/Claude-to-IM-skill ~/.claude/skills/claude-to-imCodex
Recommended: use the Codex install script
git clone https://github.com/op7418/Claude-to-IM-skill.git ~/code/Claude-to-IM-skill
bash ~/code/Claude-to-IM-skill/scripts/install-codex.shFor local development with a live checkout:
bash ~/code/Claude-to-IM-skill/scripts/install-codex.sh --linkThe install script places the skill under ~/.codex/skills/claude-to-im, installs dependencies, and builds the daemon.
After installation, tell Codex:
claude-to-im setupIf you want WeChat specifically, you can also say:
帮我接微信桥接Alternative: clone directly into Codex skills
git clone https://github.com/op7418/Claude-to-IM-skill.git ~/.codex/skills/claude-to-im
cd ~/.codex/skills/claude-to-im
npm install
npm run buildVerify installation
Claude Code: Start a new session and type / — you should see claude-to-im in the skill list. Or ask Claude: "What skills are available?"
Codex: Start a new session and say claude-to-im setup, start bridge, or 帮我接微信桥接.
Updating the Skill
Choose the update flow that matches both your AI agent product and your installation method.
Claude Code
If you installed with npx skills, re-run:
npx skills add op7418/Claude-to-IM-skillIf you installed via git clone or symlink:
cd ~/.claude/skills/claude-to-im
git pull
npm install
npm run buildThen tell Claude Code:
/claude-to-im doctor
/claude-to-im startCodex
If you installed with the Codex install script in copy mode:
rm -rf ~/.codex/skills/claude-to-im
bash ~/code/Claude-to-IM-skill/scripts/install-codex.shIf you installed with --link or cloned directly into the Codex skills directory:
cd ~/.codex/skills/claude-to-im
git pull
npm install
npm run buildThen tell Codex:
claude-to-im doctor
start bridgeQuick Start
1. Setup
Claude Code
/claude-to-im setupCodex
claude-to-im setupThe wizard will guide you through:
1. Choose channels — pick Telegram, Discord, Feishu, QQ, WeChat, or any combination 2. Enter credentials — the wizard explains exactly where to get each token, which settings to enable, and what permissions to grant 3. Set defaults — working directory, model, and mode 4. Validate — tokens are verified against platform APIs immediately
2. Start
Claude Code
/claude-to-im startCodex
start bridgeThe daemon starts in the background. You can close the terminal — it keeps running.
3. Chat
Open your IM app and send a message to your bot. Claude Code / Codex will respond through the bridge.
When Claude needs to use a tool (edit a file, run a command), you'll see a permission prompt with Allow / Deny buttons right in the chat (Telegram/Discord), or a text /perm command prompt / quick 1/2/3 replies (Feishu/QQ/WeChat).
Commands
All commands are run inside Claude Code or Codex:
| Claude Code | Codex (natural language) | Description |
|---|---|---|
/claude-to-im setup | "claude-to-im setup" / "配置" | Interactive setup wizard |
/claude-to-im start | "start bridge" / "启动桥接" | Start the bridge daemon |
/claude-to-im stop | "stop bridge" / "停止桥接" | Stop the bridge daemon |
/claude-to-im status | "bridge status" / "状态" | Show daemon status |
/claude-to-im logs | "查看日志" | Show last 50 log lines |
/claude-to-im logs 200 | "logs 200" | Show last 200 log lines |
/claude-to-im reconfigure | "reconfigure" / "修改配置" | Update config interactively |
/claude-to-im doctor | "doctor" / "诊断" | Diagnose issues |
Platform Setup Guides
The setup wizard provides inline guidance for every step. Here's a summary:
Telegram
1. Message @BotFather on Telegram → /newbot → follow prompts 2. Copy the bot token (format: 123456789:AABbCc...) 3. Recommended: /setprivacy → Disable (for group use) 4. Find your User ID: message @userinfobot
Discord
1. Go to Discord Developer Portal → New Application 2. Bot tab → Reset Token → copy it 3. Enable Message Content Intent under Privileged Gateway Intents 4. OAuth2 → URL Generator → scope bot → permissions: Send Messages, Read Message History, View Channels → copy invite URL
Feishu / Lark
1. Go to Feishu Open Platform (or Lark) 2. Create Custom App → get App ID and App Secret 3. Batch-add permissions: go to "Permissions & Scopes" → use batch configuration to add all required scopes (the setup wizard provides the exact JSON) 4. Enable Bot feature under "Add Features" 5. Events & Callbacks: select "Long Connection" as event dispatch method → add im.message.receive_v1 event 6. Publish: go to "Version Management & Release" → create version → submit for review → approve in Admin Console 7. Important: The bot will NOT work until the version is approved and published
QQ currently supports C2C private chat only. No group/channel support, no inline permission buttons, no streaming preview. Permissions use text /perm ... commands. Image inbound only (no image replies).1. Go to QQ Bot OpenClaw 2. Create a QQ Bot or select an existing one → get App ID and App Secret (only two required fields) 3. Configure sandbox access and scan QR code with QQ to add the bot 4. CTI_QQ_ALLOWED_USERS takes user_openid values (not QQ numbers) — can be left empty initially 5. Set CTI_QQ_IMAGE_ENABLED=false if the underlying provider doesn't support image input
WeChat / Weixin
WeChat currently uses QR login, single-account mode, text-based permissions, and no streaming preview.
1. Run the local QR helper from your installed skill directory:
- Claude Code default install:
cd ~/.claude/skills/claude-to-im && npm run weixin:login - Codex default install:
cd ~/.codex/skills/claude-to-im && npm run weixin:login
2. The helper writes ~/.claude-to-im/runtime/weixin-login.html and tries to open it in your browser automatically 3. Scan the QR code with WeChat and confirm on your phone 4. On success, the linked account is stored in ~/.claude-to-im/data/weixin-accounts.json 5. Running the helper again replaces the previously linked WeChat account
Additional notes:
CTI_WEIXIN_MEDIA_ENABLEDcontrols inbound image/file/video downloads only- Voice messages only use WeChat's own built-in speech-to-text text
- If WeChat does not provide
voice_item.text, the bridge replies with an error instead of downloading/transcribing raw voice audio - Permission approvals use text
/perm ...commands or quick1/2/3replies
Architecture
~/.claude-to-im/
├── config.env ← Credentials & settings (chmod 600)
├── data/ ← Persistent JSON storage
│ ├── sessions.json
│ ├── bindings.json
│ ├── permissions.json
│ └── messages/ ← Per-session message history
├── logs/
│ └── bridge.log ← Auto-rotated, secrets redacted
└── runtime/
├── bridge.pid ← Daemon PID file
└── status.json ← Current statusKey components
| Component | Role |
|---|---|
src/main.ts | Daemon entry — assembles DI, starts bridge |
src/config.ts | Load/save config.env, map to bridge settings |
src/store.ts | JSON file BridgeStore (30 methods, write-through cache) |
src/llm-provider.ts | Claude Agent SDK query() → SSE stream |
src/codex-provider.ts | Codex SDK runStreamed() → SSE stream |
src/sse-utils.ts | Shared SSE formatting helper |
src/permission-gateway.ts | Async bridge: SDK canUseTool ↔ IM buttons |
src/logger.ts | Secret-redacted file logging with rotation |
scripts/daemon.sh | Process management (start/stop/status/logs) |
scripts/doctor.sh | Health checks |
SKILL.md | Claude Code skill definition |
Permission flow
1. Claude wants to use a tool (e.g., Edit file)
2. SDK calls canUseTool() → LLMProvider emits permission_request SSE
3. Bridge sends inline buttons to IM chat: [Allow] [Deny]
4. canUseTool() blocks, waiting for user response (5 min timeout)
5. User taps Allow → bridge resolves the pending permission
6. SDK continues tool execution → result streamed back to IMTroubleshooting
Run diagnostics:
/claude-to-im doctorThis checks: Node.js version, config file existence and permissions, token validity (live API calls), log directory, PID file consistency, and recent errors.
| Issue | Solution |
|---|---|
Bridge won't start | Run doctor. Check if Node >= 20. Check logs. |
Messages not received | Verify token with doctor. Check allowed users config. |
Permission timeout | User didn't respond within 5 min. Tool call auto-denied. |
Stale PID file | Run stop then start. daemon.sh auto-cleans stale PIDs. |
See references/troubleshooting.md for more details.
Security
- All credentials stored in
~/.claude-to-im/config.envwithchmod 600 - Tokens are automatically redacted in all log output (pattern-based masking)
- Allowed user/channel/guild lists restrict who can interact with the bot
- The daemon is a local process with no inbound network listeners
- See SECURITY.md for threat model and incident response
Development
npm install # Install dependencies
npm run dev # Run in dev mode
npm run typecheck # Type check
npm test # Run tests
npm run build # Build bundleLicense
MIT
Platform Setup Guides
Detailed step-by-step guides for each IM platform. Referenced by the setup and reconfigure subcommands.
---
Telegram
Bot Token
How to get a Telegram Bot Token: 1. Open Telegram and search for @BotFather 2. Send /newbot to create a new bot 3. Follow the prompts: choose a display name and a username (must end in bot) 4. BotFather will reply with a token like 7823456789:AAF-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 5. Copy the full token and paste it here
Recommended bot settings (send these commands to @BotFather):
/setprivacy→ choose your bot →Disable(so the bot can read group messages, only needed for group use)/setcommands→ set commands likenew - Start new session,mode - Switch mode
Token format: 数字:字母数字字符串 (e.g. 7823456789:AAF-xxx...xxx)
Chat ID
How to get your Telegram Chat ID: 1. Start a chat with your bot (search for the bot's username and click Start) 2. Send any message to the bot (e.g. "hello") 3. Open this URL in your browser (replace YOUR_BOT_TOKEN with your actual bot token): https://api.telegram.org/botYOUR_BOT_TOKEN/getUpdates 4. In the JSON response, find "chat":{"id":123456789,...} — that number is your Chat ID 5. For group chats, the Chat ID is a negative number (e.g. -1001234567890)
Why this matters: The bot uses Chat ID for authorization. If neither Chat ID nor Allowed User IDs are configured, the bot will reject all incoming messages.
Allowed User IDs (optional)
How to find your Telegram User ID: 1. Search for @userinfobot on Telegram and start a chat 2. It will reply with your User ID (a number like 123456789) 3. Alternatively, forward a message from yourself to @userinfobot
Enter comma-separated IDs to restrict access (recommended for security). Leave empty to allow anyone who can message the bot.
---
Discord
Bot Token
How to create a Discord Bot and get the token: 1. Go to https://discord.com/developers/applications 2. Click "New Application" → give it a name → click "Create" 3. Go to the "Bot" tab on the left sidebar 4. Click "Reset Token" → copy the token (you can only see it once!)
Required bot settings (on the Bot tab):
- Under Privileged Gateway Intents, enable:
- ✅ Message Content Intent (required to read message text)
Invite the bot to your server: 1. Go to the "OAuth2" tab → "URL Generator" 2. Under Scopes, check: bot 3. Under Bot Permissions, check: Send Messages, Read Message History, View Channels 4. Copy the generated URL at the bottom and open it in your browser 5. Select the server and click "Authorize"
Token format: a long base64-like string (e.g. MTIzNDU2Nzg5.Gxxxxx.xxxxxxxxxxxxxxxxxxxxxxxx)
Allowed User IDs
How to find Discord User IDs: 1. In Discord, go to Settings → Advanced → enable Developer Mode 2. Right-click on any user → "Copy User ID"
Enter comma-separated IDs.
Why this matters: The bot uses a default-deny policy. If neither Allowed User IDs nor Allowed Channel IDs are configured, the bot will silently reject all incoming messages. You must set at least one.
Allowed Channel IDs (optional)
How to find Discord Channel IDs: 1. With Developer Mode enabled, right-click on any channel → "Copy Channel ID"
Enter comma-separated IDs to restrict the bot to specific channels. Leave empty to allow all channels the bot can see.
Allowed Guild (Server) IDs (optional)
How to find Discord Server IDs: 1. With Developer Mode enabled, right-click on the server icon → "Copy Server ID"
Enter comma-separated IDs. Leave empty to allow all servers the bot is in.
---
Feishu / Lark
App ID and App Secret
How to create a Feishu/Lark app and get credentials: 1. Go to Feishu: https://open.feishu.cn/app or Lark: https://open.larksuite.com/app 2. Click "Create Custom App" 3. Fill in the app name and description → click "Create" 4. On the app's "Credentials & Basic Info" page, find:
- App ID (like
cli_xxxxxxxxxx) - App Secret (click to reveal, like
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)
Phase 1: Permissions + Bot capability
Complete Phase 1 and publish before moving to Phase 2. Feishu requires a published version for permissions to take effect, and the bridge service needs active permissions to establish its WebSocket connection.
Step A — Batch-add required permissions
1. On the app page, go to "Permissions & Scopes" 2. Use batch configuration (click "Batch switch to configure by dependency" or find the JSON editor) 3. Paste the following JSON (required for streaming cards and interactive buttons):
{
"scopes": {
"tenant": [
"im:message:send_as_bot",
"im:message:readonly",
"im:message.p2p_msg:readonly",
"im:message.group_at_msg:readonly",
"im:message:update",
"im:message.reactions:read",
"im:message.reactions:write_only",
"im:chat:read",
"im:resource",
"cardkit:card:write",
"cardkit:card:read"
],
"user": []
}
}4. Click "Save" to apply all permissions
If the batch import UI is not available, add each scope manually via the search box.
Step B — Enable the bot
1. Go to "Add Features" → enable "Bot" 2. Set the bot name and description
Step C — First publish (makes permissions + bot effective)
1. Go to "Version Management & Release" → click "Create Version" 2. Fill in version 1.0.0 and a description → click "Save" → "Submit for Review" 3. Admin approves in Feishu Admin Console → App Review (self-approve if you are the admin)
The bot will NOT work until this version is approved.
Phase 2: Event subscription (requires running bridge)
The bridge service must be running before configuring events. Feishu validates the WebSocket connection when saving event subscription — if the bridge is not running, you'll get "未检测到应用连接信息" (connection not detected) error.
Step D — Start the bridge service
Run /claude-to-im start in Claude Code. This establishes the WebSocket long connection that Feishu needs to detect.
Step E — Configure Events & Callbacks (long connection)
1. Go to "Events & Callbacks" in the left sidebar 2. Under "Event Dispatch Method", select "Long Connection" (长连接 / WebSocket mode) 3. Click "Add Event" and add:
im.message.receive_v1— Receive messages
4. Click "Add Callback" and add:
card.action.trigger— Card interaction callback (for permission approval buttons)
5. Click "Save"
Step F — Second publish (makes event subscription effective)
1. Go to "Version Management & Release" → click "Create Version" 2. Fill in version 1.1.0 → "Save" → "Submit for Review" → Admin approves 3. After approval, the bot can receive and respond to messages
Ongoing rule: Any change to permissions, events, or capabilities requires a new version publish + admin approval.
Upgrading from a previous version
If you already have a Feishu app configured, you need to:
1. Add new permissions: Go to Permissions & Scopes, add these scopes:
cardkit:card:write,cardkit:card:read— Streaming cardsim:message:update— Real-time card content updatesim:message.reactions:read,im:message.reactions:write_only— Typing indicator
2. Publish a new version — Permission changes only take effect after a new version is approved 3. Start (or restart) the bridge — Run /claude-to-im start so the WebSocket connection is active 4. Add callback: Go to Events & Callbacks, add card.action.trigger callback (card interaction for permission buttons). This step requires the bridge to be running — Feishu validates the WebSocket connection when saving. 5. Publish again — The new callback requires another version publish + admin approval 6. Restart the bridge — Run /claude-to-im stop then /claude-to-im start to pick up the new capabilities
Domain (optional)
Default: https://open.feishu.cn Use https://open.larksuite.com for Lark (international version). Leave empty to use the default Feishu domain.
Allowed User IDs (optional)
Feishu user IDs (open_id format like ou_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx). You can find them in the Feishu Admin Console under user profiles. Leave empty to allow all users who can message the bot.
---
Note: QQ first version only supports C2C private chat (sandbox access). Group chat and channel are not supported yet.
App ID and App Secret (required)
How to get QQ Bot credentials: 1. Go to https://q.qq.com/qqbot/openclaw 2. Log in and enter the QQ Bot / OpenClaw management page 3. Create a new QQ Bot or select an existing one 4. Find App ID and App Secret on the bot's credential page 5. Copy both values
These are the only two required fields for QQ.
Sandbox private chat setup
1. In the QQ Bot management page, configure sandbox access 2. Scan the QR code with QQ to add the bot as a friend 3. Send a message to the bot via QQ private chat to start using it
Allowed User OpenIDs (optional)
Important: The value is user_openid, NOT QQ number.
user_openid is an opaque identifier assigned by the QQ Bot platform to each user. You can obtain it from the bot's message logs after a user sends a message to the bot.
If you don't have the openid yet, leave this field empty. You can add it later via reconfigure.
---
Weixin / 微信
Risk note: this integration follows the same OpenClaw-style WeChat plugin protocol used by CodePilot. Because it connects a non-OpenClaw product to WeChat, there may be account risk. Use with caution.
QR login flow
Weixin does not use a static bot token in config.env.
Instead, run the local QR helper from the installed skill directory:
- Claude Code default install:
cd ~/.claude/skills/claude-to-im
npm run weixin:login- Codex default install:
cd ~/.codex/skills/Claude-to-IM-skill
npm run weixin:loginIf you are running from a checked-out repo instead of an installed skill, use that repo's Claude-to-IM-skill directory.
What happens next:
1. The helper requests a fresh WeChat QR code 2. It writes a local HTML file to: ~/.claude-to-im/runtime/weixin-login.html 3. It tries to open that HTML file in your default browser automatically 4. You scan the QR code with the WeChat app and confirm on your phone 5. On success, the helper stores the linked account in: ~/.claude-to-im/data/weixin-accounts.json
The filename stays plural for backward compatibility, but Weixin currently runs in single-account mode.
If the browser does not open automatically, open the HTML file manually.
Replacing the linked Weixin account
Run the helper again:
cd <skill-dir>
npm run weixin:loginEach successful scan replaces the previously linked Weixin account. Only the most recent account is kept locally and used by the bridge.
Optional config
Most users should leave these unset:
CTI_WEIXIN_BASE_URLCTI_WEIXIN_CDN_BASE_URLCTI_WEIXIN_MEDIA_ENABLED
Defaults:
- Base URL:
https://ilinkai.weixin.qq.com - CDN Base URL:
https://novac2c.cdn.weixin.qq.com/c2c - Media: disabled by default in CLI setups; when enabled, inbound images/files/videos are downloaded and forwarded as attachments
Voice message behavior
Weixin voice messages are handled differently from image/file/video media:
- If WeChat includes built-in speech-to-text text in
voice_item.text, the bridge forwards that text as the user message. - If WeChat does not include a transcript, the bridge returns a user-visible error asking the sender to enable WeChat voice transcription and resend.
- The bridge does not download, decrypt, or transcribe raw voice audio on its own.
This rule applies in both Claude Code and Codex runtimes.
Token Validation Commands
After writing config.env, validate each enabled platform's credentials to catch typos and configuration errors early.
Telegram
curl -s "https://api.telegram.org/bot${TOKEN}/getMe"Expected: response contains "ok":true. If not, the Bot Token is invalid — re-check with @BotFather.
Discord
Verify token format matches: [A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+
A format mismatch means the token was copied incorrectly from the Discord Developer Portal.
Feishu / Lark
curl -s -X POST "${DOMAIN}/open-apis/auth/v3/tenant_access_token/internal" \
-H "Content-Type: application/json" \
-d '{"app_id":"...","app_secret":"..."}'Expected: response contains "code":0. If not, check that App ID and App Secret match the Feishu Developer Console.
Step 1 — Get access token:
curl -s -X POST "https://bots.qq.com/app/getAppAccessToken" \
-H "Content-Type: application/json" \
-d '{"appId":"...","clientSecret":"..."}'Expected: response contains access_token.
Step 2 — Verify gateway connectivity:
curl -s "https://api.sgroup.qq.com/gateway" \
-H "Authorization: QQBot <access_token>"Expected: response contains a gateway URL.
If either step fails, verify the App ID and App Secret from https://q.qq.com.
Troubleshooting
Bridge won't start
Symptoms: /claude-to-im start fails or daemon exits immediately.
Steps:
1. Run /claude-to-im doctor to identify the issue 2. Check that Node.js >= 20 is installed: node --version 3. Check that Claude Code CLI is available: claude --version 4. Verify config exists: ls -la ~/.claude-to-im/config.env 5. Check logs for startup errors: /claude-to-im logs
Common causes:
- Missing or invalid config.env -- run
/claude-to-im setup - Node.js not found or wrong version -- install Node.js >= 20
- Port or resource conflict -- check if another instance is running with
/claude-to-im status
Messages not received
Symptoms: Bot is online but doesn't respond to messages.
Steps:
1. Verify the bot token is valid: /claude-to-im doctor 2. Check allowed user IDs in config -- if set, only listed users can interact 3. For Telegram: ensure you've sent /start to the bot first 4. For Discord: verify the bot has been invited to the server with message read permissions 5. For Feishu: confirm the app has been approved and event subscriptions are configured 6. Check logs for incoming message events: /claude-to-im logs 200
Permission timeout
Symptoms: Claude Code session starts but times out waiting for tool approval.
Steps:
1. The bridge runs Claude Code in non-interactive mode; ensure your Claude Code configuration allows the necessary tools 2. Consider using --allowedTools in your configuration to pre-approve common tools 3. Check network connectivity if the timeout occurs during API calls
High memory usage
Symptoms: The daemon process consumes increasing memory over time.
Steps:
1. Check current memory usage: /claude-to-im status 2. Restart the daemon to reset memory:
/claude-to-im stop
/claude-to-im start3. If the issue persists, check how many concurrent sessions are active -- each Claude Code session consumes memory 4. Review logs for error loops that may cause memory leaks
Stale PID file
Symptoms: Status shows "running" but the process doesn't exist, or start refuses because it thinks a daemon is already running.
The daemon management script (daemon.sh) handles stale PID files automatically. If you still encounter issues:
1. Run /claude-to-im stop -- it will clean up the stale PID file 2. If stop also fails, manually remove the PID file:
rm ~/.claude-to-im/runtime/bridge.pid3. Run /claude-to-im start to launch a fresh instance
Usage Guide
This skill works with both Claude Code (via /claude-to-im slash commands) and Codex (via natural language like "start bridge", "配置", "诊断"). All commands below use Claude Code syntax; Codex users can use equivalent natural language.
setup
Interactive wizard that configures the bridge.
/claude-to-im setupThe wizard will prompt you for:
1. Channels to enable -- Enter comma-separated values: telegram, discord, feishu, qq 2. Platform credentials -- Bot tokens, app IDs, and secrets for each enabled channel 3. Allowed users (optional) -- Restrict which users can interact with the bot 4. Working directory -- Default project directory for Claude Code sessions 5. Model and mode -- Claude model and interaction mode (code/plan/ask)
After collecting input, the wizard validates tokens by calling each platform's API and reports results.
Example interaction:
> /claude-to-im setup
Which channels to enable? telegram,discord
Enter Telegram bot token: <your-token>
Enter Discord bot token: <your-token>
Default working directory [/current/dir]: /Users/me/projects
Model [claude-sonnet-4-20250514]:
Mode [code]:
Validating tokens...
Telegram: OK (bot @MyBotName)
Discord: OK (format valid)
Config written to ~/.claude-to-im/config.envstart
Starts the bridge daemon in the background.
/claude-to-im startThe daemon process ID is stored in ~/.claude-to-im/runtime/bridge.pid. If the daemon is already running, the command reports the existing process.
If startup fails, run /claude-to-im doctor to diagnose issues.
stop
Stops the running bridge daemon.
/claude-to-im stopSends SIGTERM to the daemon process and cleans up the PID file.
status
Shows whether the daemon is running and basic health information.
/claude-to-im statusOutput includes:
- Running/stopped state
- PID (if running)
- Uptime
- Connected channels
logs
Shows recent log output from the daemon.
/claude-to-im logs # Last 50 lines (default)
/claude-to-im logs 200 # Last 200 linesLogs are stored in ~/.claude-to-im/logs/ and are automatically redacted to mask secrets.
reconfigure
Interactively update the current configuration.
/claude-to-im reconfigureDisplays current settings with secrets masked, then prompts for changes. After updating, you must restart the daemon for changes to take effect:
/claude-to-im stop
/claude-to-im startdoctor
Runs diagnostic checks and reports issues.
/claude-to-im doctorChecks performed:
- Node.js version (>= 20 required)
- Claude Code CLI availability
- Config file exists and has correct permissions
- Required tokens are set for enabled channels
- Token validity (API calls)
- QQ credentials and gateway reachability (if QQ enabled)
- Daemon process health
- Log directory writability
QQ notes
QQ currently supports C2C private chat only:
- No inline approval buttons — permissions use text
/perm ...commands - No streaming preview
- Image inbound only (no image replies)
- No group/channel support yet
- Required config:
CTI_QQ_APP_ID,CTI_QQ_APP_SECRET(obtain from https://q.qq.com/qqbot/openclaw) CTI_QQ_ALLOWED_USERStakesuser_openidvalues, not QQ numbers- Set
CTI_QQ_IMAGE_ENABLED=falseif the provider doesn't support image input
import * as esbuild from 'esbuild';
await esbuild.build({
entryPoints: ['src/main.ts'],
bundle: true,
platform: 'node',
format: 'esm',
target: 'node20',
outfile: 'dist/daemon.mjs',
external: [
// SDK must stay external — it spawns a CLI subprocess and resolves
// dist/cli.js relative to its own package location. Bundling it
// breaks that path resolution.
'@anthropic-ai/claude-agent-sdk',
'@openai/codex-sdk',
// discord.js optional native deps
'bufferutil', 'utf-8-validate', 'zlib-sync', 'erlpack',
// Node.js built-ins
'fs', 'path', 'os', 'crypto', 'http', 'https', 'net', 'tls',
'stream', 'events', 'url', 'util', 'child_process', 'worker_threads',
'node:*',
],
banner: { js: "import { createRequire } from 'module'; const require = createRequire(import.meta.url);" },
});
console.log('Built dist/daemon.mjs');
<#
.SYNOPSIS
Windows entry point — delegates to supervisor-windows.ps1.
.DESCRIPTION
Usage: powershell -File scripts\daemon.ps1 start|stop|status|logs|install-service|uninstall-service
#>
param(
[Parameter(Position=0)]
[string]$Command = 'help',
[Parameter(Position=1)]
[int]$LogLines = 50
)
$supervisorScript = Join-Path (Split-Path -Parent $PSCommandPath) 'supervisor-windows.ps1'
& $supervisorScript $Command $LogLines
#!/usr/bin/env bash
set -euo pipefail
# Install claude-to-im skill for Codex.
# Usage: bash scripts/install-codex.sh [--link]
# --link Create a symlink instead of copying (for development)
SKILL_NAME="claude-to-im"
CODEX_SKILLS_DIR="$HOME/.codex/skills"
TARGET_DIR="$CODEX_SKILLS_DIR/$SKILL_NAME"
SOURCE_DIR="$(cd "$(dirname "$0")/.." && pwd)"
echo "Installing $SKILL_NAME skill for Codex..."
# Check source
if [ ! -f "$SOURCE_DIR/SKILL.md" ]; then
echo "Error: SKILL.md not found in $SOURCE_DIR"
exit 1
fi
# Create skills directory
mkdir -p "$CODEX_SKILLS_DIR"
# Check if already installed
if [ -e "$TARGET_DIR" ]; then
if [ -L "$TARGET_DIR" ]; then
EXISTING=$(readlink "$TARGET_DIR")
echo "Already installed as symlink → $EXISTING"
echo "To reinstall, remove it first: rm $TARGET_DIR"
exit 0
else
echo "Already installed at $TARGET_DIR"
echo "To reinstall, remove it first: rm -rf $TARGET_DIR"
exit 0
fi
fi
if [ "${1:-}" = "--link" ]; then
ln -s "$SOURCE_DIR" "$TARGET_DIR"
echo "Symlinked: $TARGET_DIR → $SOURCE_DIR"
else
cp -R "$SOURCE_DIR" "$TARGET_DIR"
echo "Copied to: $TARGET_DIR"
fi
# Ensure dependencies (need devDependencies for build step)
if [ ! -d "$TARGET_DIR/node_modules" ] || [ ! -d "$TARGET_DIR/node_modules/@openai/codex-sdk" ]; then
echo "Installing dependencies..."
(cd "$TARGET_DIR" && npm install)
fi
# Ensure build
if [ ! -f "$TARGET_DIR/dist/daemon.mjs" ]; then
echo "Building daemon bundle..."
(cd "$TARGET_DIR" && npm run build)
fi
# Prune devDependencies after build
echo "Pruning dev dependencies..."
(cd "$TARGET_DIR" && npm prune --production)
echo ""
echo "Done! Start a new Codex session and use:"
echo " claude-to-im setup — configure IM platform credentials"
echo " claude-to-im start — start the bridge daemon"
echo " claude-to-im doctor — diagnose issues"
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { buildQrHtml } from '../weixin-login.js';
describe('weixin-login HTML', () => {
it('embeds inline QR markup without remote CDN scripts', () => {
const html = buildQrHtml(
{
qrcode: 'qr-token',
qrImageUrl: 'weixin://qr-content',
status: 'waiting',
startedAt: Date.now(),
refreshCount: 0,
},
'<svg viewBox="0 0 10 10"><rect width="10" height="10" /></svg>',
);
assert.match(html, /<svg viewBox="0 0 10 10">/);
assert.ok(!html.includes('cdn.jsdelivr.net'));
assert.ok(!html.includes('<script'));
});
});
declare module 'qrcode' {
interface ToStringOptions {
type?: 'svg' | 'utf8' | 'terminal';
errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H';
margin?: number;
width?: number;
}
const QRCode: {
toString(text: string, options?: ToStringOptions): Promise<string>;
};
export default QRCode;
}
Related skills
How it compares
Session bridge for existing Claude Code/Codex installs; not a framework for building custom chatbots.
FAQ
Why does Feishu setup require two publish cycles?
Feishu validates the WebSocket connection when saving event subscription. The bridge needs published permissions to connect, but the event config needs a running bridge. Phase 1 publishes permissions/bot so the bridge can start, Phase 2 adds events/callbacks after the bridge is r
What's the difference between status and doctor subcommands?
status shows if the bridge daemon is currently running (informational). doctor runs diagnostics when something is broken - checks for missing SDK files, stale config, expired Weixin accounts, permission errors, and refers to troubleshooting guides.
How does permission approval work on different platforms?
Telegram and Feishu show inline buttons for immediate approval/rejection. QQ and WeChat use text commands (/perm ...) or quick reply numbers (1/2/3) since they don't support inline interactive elements in the current API version.
Is Claude To Im safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.