From 76e40f51d5bc776eb233620a97b51838227815cc Mon Sep 17 00:00:00 2001 From: nles1214 Date: Wed, 20 May 2026 11:50:01 +0800 Subject: [PATCH] feat: add Windows (PowerShell) daemon support - Add scripts/daemon.ps1 for Windows service management (start/stop/status/logs) - Add npm run daemon:ps script for PowerShell-based daemon control - Update README with Windows installation and management instructions - Update SKILL.md with platform-aware status check and subcommands --- README.md | 21 ++++++++- README_zh.md | 22 ++++++++-- SKILL.md | 25 +++++++++-- package.json | 3 +- scripts/daemon.ps1 | 104 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 165 insertions(+), 10 deletions(-) create mode 100644 scripts/daemon.ps1 diff --git a/README.md b/README.md index 62bce6e..f7da10b 100644 --- a/README.md +++ b/README.md @@ -15,14 +15,14 @@ A [Claude Code](https://claude.ai/claude-code) Skill that bridges personal WeCha - Permission approval — reply `y`/`n` in WeChat to approve Claude's tool use - Slash commands — `/help`, `/clear`, `/model`, `/prompt`, `/status`, `/skills`, and more - Launch any installed Claude Code skill from WeChat -- Cross-platform — macOS (launchd), Linux (systemd + nohup fallback) +- Cross-platform — macOS (launchd), Linux (systemd + nohup fallback), Windows (PowerShell daemon) - Session persistence — resume conversations across messages - Rate-limit safe — automatic exponential backoff on WeChat API throttling ## Prerequisites - Node.js >= 18 -- macOS or Linux +- **Windows 10+** / macOS / Linux - Personal WeChat account (QR code binding required) - [Claude Code](https://docs.anthropic.com/en/docs/claude-code) with `@anthropic-ai/claude-agent-sdk` installed > **Note:** The SDK supports third-party API providers (e.g. OpenRouter, AWS Bedrock, custom OpenAI-compatible endpoints) — set `ANTHROPIC_BASE_URL` and `ANTHROPIC_API_KEY` accordingly. @@ -54,6 +54,7 @@ A QR code image will open — scan it with WeChat. Then configure your working d ### 2. Start the daemon +**macOS / Linux:** ```bash npm run daemon -- start ``` @@ -61,12 +62,20 @@ npm run daemon -- start - **macOS**: registers a launchd agent for auto-start and auto-restart - **Linux**: uses systemd user service (falls back to nohup if systemd unavailable) +**Windows (PowerShell):** +```powershell +npm run daemon:ps -- start +``` + +Runs the Node.js daemon in background. Logs are written to `~/.wechat-claude-code/logs/`. + ### 3. Chat in WeChat Send any message in WeChat to start chatting with Claude Code. ### 4. Manage the service +**macOS / Linux:** ```bash npm run daemon -- status # Check if running npm run daemon -- stop # Stop the daemon @@ -74,6 +83,14 @@ npm run daemon -- restart # Restart (after code updates) npm run daemon -- logs # View recent logs ``` +**Windows (PowerShell):** +```powershell +npm run daemon:ps -- status # Check if running +npm run daemon:ps -- stop # Stop the daemon +npm run daemon:ps -- restart # Restart +npm run daemon:ps -- logs # View recent logs +``` + ## WeChat Commands | Command | Description | diff --git a/README_zh.md b/README_zh.md index cd9af94..12643d6 100644 --- a/README_zh.md +++ b/README_zh.md @@ -15,14 +15,14 @@ - 权限审批——在微信中回复 `y`/`n` 控制工具执行 - 斜杠命令——`/help`、`/clear`、`/model`、`/prompt`、`/status`、`/skills` 等 - 在微信中触发任意已安装的 Claude Code Skill -- 跨平台——macOS(launchd)、Linux(systemd + nohup 回退) +- 跨平台——macOS(launchd)、Linux(systemd + nohup 回退)、Windows(PowerShell 守护进程) - 会话持久化——跨消息恢复上下文 - 限频保护——微信 API 限频时自动指数退避重试 ## 前置条件 - Node.js >= 18 -- macOS 或 Linux +- **Windows 10+** / macOS / Linux - 个人微信账号(需扫码绑定) - 已安装 [Claude Code](https://docs.anthropic.com/en/docs/claude-code)(含 `@anthropic-ai/claude-agent-sdk`) > **注意:** 该 SDK 支持第三方 API 提供商(如 OpenRouter、AWS Bedrock、自定义 OpenAI 兼容接口)——按需设置 `ANTHROPIC_BASE_URL` 与 `ANTHROPIC_API_KEY` 即可。 @@ -54,6 +54,7 @@ npm run setup ### 2. 启动服务 +**macOS / Linux:** ```bash npm run daemon -- start ``` @@ -61,12 +62,17 @@ npm run daemon -- start - **macOS**:注册 launchd 代理,实现开机自启和自动重启 - **Linux**:使用 systemd 用户服务(无 systemd 时回退到 nohup) -### 3. 在微信中聊天 +**Windows(PowerShell):** +```powershell +npm run daemon:ps -- start +``` -直接在微信中发消息即可与 Claude Code 对话。 +后台运行 Node.js 守护进程,日志输出到 `~/.wechat-claude-code/logs/`。 +### 3. 在微信中聊天 ### 4. 管理服务 +**macOS / Linux:** ```bash npm run daemon -- status # 查看运行状态 npm run daemon -- stop # 停止服务 @@ -74,6 +80,14 @@ npm run daemon -- restart # 重启服务(代码更新后使用) npm run daemon -- logs # 查看最近日志 ``` +**Windows(PowerShell):** +```powershell +npm run daemon:ps -- status # 查看运行状态 +npm run daemon:ps -- stop # 停止服务 +npm run daemon:ps -- restart # 重启服务 +npm run daemon:ps -- logs # 查看最近日志 +``` + ## 微信端命令 | 命令 | 说明 | diff --git a/SKILL.md b/SKILL.md index 714aaf1..bdac06d 100644 --- a/SKILL.md +++ b/SKILL.md @@ -10,7 +10,7 @@ description: 微信消息桥接 - 在微信中与 Claude Code 聊天。支持文 ## 前置条件 - Node.js >= 18 -- macOS(daemon 使用 launchd 管理) +- **Windows 10+** / macOS / Linux - 个人微信账号(需扫码绑定) - 已安装 Claude Code(`@anthropic-ai/claude-agent-sdk`) @@ -52,10 +52,16 @@ ls ~/.wechat-claude-code/accounts/*.json 2>/dev/null | head -1 ### 第 3 步:检查 daemon 运行状态 +**macOS / Linux:** ```bash cd ~/.claude/skills/wechat-claude-code && npm run daemon -- status ``` +**Windows:** +```powershell +cd ~/.claude/skills/wechat-claude-code && npm run daemon:ps -- status +``` + ### 第 4 步:根据状态展示信息 **如果 daemon 未运行:** @@ -93,14 +99,27 @@ cd ~/.claude/skills/wechat-claude-code && npm run daemon -- status 所有命令的工作目录为 `~/.claude/skills/wechat-claude-code`。 +### macOS / Linux + | 命令 | 执行 | 说明 | |------|------|------| | setup | `npm run setup` | 首次安装向导:生成 QR 码 → 微信扫码 → 配置工作目录 | -| start | `npm run daemon -- start` | 启动 launchd 守护进程(开机自启、自动重启) | +| start | `npm run daemon -- start` | 启动守护进程(launchd/systemd) | | stop | `npm run daemon -- stop` | 停止守护进程 | | restart | `npm run daemon -- restart` | 重启守护进程 | | status | `npm run daemon -- status` | 查看运行状态 | -| logs | `npm run daemon -- logs` | 查看最近日志(tail -100) | +| logs | `npm run daemon -- logs` | 查看最近日志 | + +### Windows (PowerShell) + +| 命令 | 执行 | 说明 | +|------|------|------| +| setup | `npm run setup` | 首次安装向导:生成 QR 码 → 微信扫码 → 配置工作目录 | +| start | `npm run daemon:ps -- start` | 启动后台守护进程 | +| stop | `npm run daemon:ps -- stop` | 停止守护进程 | +| restart | `npm run daemon:ps -- restart` | 重启守护进程 | +| status | `npm run daemon:ps -- status` | 查看运行状态 | +| logs | `npm run daemon:ps -- logs` | 查看最近日志 | ## 权限审批 diff --git a/package.json b/package.json index 1ec8c88..16c245f 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "dev": "tsc --watch", "test": "node --test dist/tests/*.test.js", "setup": "node dist/main.js setup", - "daemon": "bash scripts/daemon.sh" + "daemon": "bash scripts/daemon.sh", + "daemon:ps": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/daemon.ps1" }, "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.1.0", diff --git a/scripts/daemon.ps1 b/scripts/daemon.ps1 new file mode 100644 index 0000000..f63c136 --- /dev/null +++ b/scripts/daemon.ps1 @@ -0,0 +1,104 @@ +param( + [Parameter(Position=0)] + [ValidateSet("start","stop","restart","status","logs")] + [string]$Command = "status" +) + +$ProjectDir = Resolve-Path "$PSScriptRoot/.." +$DataDir = "$env:USERPROFILE\.wechat-claude-code" +$PidFile = "$DataDir\wechat-claude-code.pid" +$LogDir = "$DataDir\logs" +$StdoutLog = "$LogDir\stdout.log" +$StderrLog = "$LogDir\stderr.log" + +function Get-SavedPid { + if (Test-Path $PidFile) { + return [int](Get-Content $PidFile -Raw).Trim() + } + return $null +} + +function Is-Running($procId) { + if (-not $procId) { return $false } + try { return (Get-Process -Id $procId -ErrorAction Stop) -ne $null } + catch { return $false } +} + +function Write-StartupEnv { + $env:NODE_PATH = "$ProjectDir/node_modules" +} + +switch ($Command) { + "start" { + $savedPid = Get-SavedPid + if ((Is-Running $savedPid)) { + Write-Host "Already running (PID: $savedPid)" + exit 0 + } + if (Test-Path $PidFile) { Remove-Item $PidFile -Force } + + New-Item -ItemType Directory -Force -Path $LogDir | Out-Null + + Write-Host "Starting wechat-claude-code daemon..." + Write-StartupEnv + + $p = Start-Process -FilePath "node" -ArgumentList "dist/main.js start" -WorkingDirectory $ProjectDir -WindowStyle Hidden -PassThru -RedirectStandardOutput $StdoutLog -RedirectStandardError $StderrLog + $p.Id | Out-File -FilePath $PidFile -Encoding utf8 + + Write-Host "Started (PID: $($p.Id))" + Write-Host "Logs: $StdoutLog" + } + + "stop" { + $procId = Get-SavedPid + if (-not $procId) { + Write-Host "Not running (no PID file)" + exit 0 + } + + if (Is-Running $procId) { + Write-Host "Stopping (PID: $procId)..." + try { + Stop-Process -Id $procId -Force -ErrorAction Stop + Write-Host "Stopped (PID: $procId)" + } catch { + Write-Host "Failed to stop process: $_" + } + } else { + Write-Host "Not running (stale PID file)" + } + + if (Test-Path $PidFile) { Remove-Item $PidFile -Force } + } + + "restart" { + & $PSCommandPath stop + Start-Sleep -Seconds 2 + & $PSCommandPath start + } + + "status" { + $procId = Get-SavedPid + if ((Is-Running $procId)) { + $proc = Get-Process -Id $procId + $uptime = (Get-Date) - $proc.StartTime + Write-Host "Running (PID: $procId, started: $($proc.StartTime), uptime: $([math]::Floor($uptime.TotalHours))h $($uptime.Minutes)m)" + } else { + Write-Host "Not running" + } + } + + "logs" { + if (Test-Path $StdoutLog) { + Write-Host "=== stdout.log (last 100 lines) ===" + Get-Content $StdoutLog -Tail 100 + } + if (Test-Path $StderrLog) { + Write-Host "=== stderr.log (last 100 lines) ===" + Get-Content $StderrLog -Tail 100 + } + if (-not (Test-Path $StdoutLog) -and -not (Test-Path $StderrLog)) { + Write-Host "No logs found" + } + } +}