feat: 多语言任务、WebUI 增强与 Agent MCP 集成

重构 lib 为扁平模块并支持 Windows schtasks;新增 JS/Bash/PowerShell 模板、WebUI 调度编辑,以及 Cursor Skill 与 MCP 工具供 Agent 管理定时任务。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-24 21:45:25 +08:00
parent 6c2db2dfa3
commit c10cacd5c6
59 changed files with 3989 additions and 800 deletions

View File

@@ -10,16 +10,21 @@
/shumengya/project/agent/sproutclaw-cron/
├── cronctl.py # 统一管理 CLIenable/disable/toggle/status
├── AGENTS.md # AI 新建任务规范(必读)
├── _template/ # 示例任务 + 复制模板(每天 08:00 hello world
├── _template/ # Python 示例 + 默认复制模板
├── _template-javascript/ # JavaScript (Node.js) 示例
├── _template-bash/ # Bash 示例
├── _template-powershell/ # PowerShell 示例
├── lib/
│ └── shumengya_cron/
│ ├── runner.py # TaskContext、日志轮转、flock 互斥锁
│ ├── runner.py # TaskContext、日志轮转、互斥锁
│ ├── task_manifest.py # task.json 解析、runtime 推断
│ ├── external_runner.py # 非 Python 任务 subprocess 启动
│ ├── notify.py # 飞书 Markdown 通知 + 邮件降级
│ └── ssh.py # 远端 SSH 辅助bash -lc
├── <task-id>/ # 任务目录(启用状态)
│ ├── run.py # 任务入口(唯一必须文件)
│ ├── task.json # 可选runtime + entry
│ ├── run.py / run.js / run.sh / run.ps1
│ ├── schedule.cron # 系统 cron 配置(复制到 /etc/cron.d/
│ ├── switch.sh # 一键开关(可用 cronctl 替代)
│ ├── targets.json # 可选任务自定义配置JSON
│ ├── logs/<task-id>.log # 运行日志(自动创建)
│ └── <task-id>.lock # flock 互斥锁文件(自动创建)
@@ -31,19 +36,6 @@
---
## 已有任务
| 任务 ID | 状态 | 说明 |
|---|---|---|
| `_template` | 开启 | 示例任务:每天 08:00 输出 hello world也是新任务复制模板 |
| `bigmengya-docker-container-restart` | disabled | SSH 重启 bigmengya 上的数据库类容器 |
| `bigmengya-docker-image-update` | disabled | SSH 拉取并重建 bigmengya 上的 compose 服务 |
| `smallmengya-ai-cli-update` | disabled | 更新本机 codex / claude / opencode |
| `smallmengya-ai-memory-export` | disabled | 导出 AI 记忆数据 |
| `smallmengya-gitea-repo-sync` | 开启 | 同步 Gitea 仓库到本地 |
---
## 快速上手
### 查看状态
@@ -65,32 +57,66 @@ python3 /shumengya/project/agent/sproutclaw-cron/cronctl.py disable all #
# 推荐:通过 cronctl自动识别 .disabled/ 下的任务)
python3 /shumengya/project/agent/sproutclaw-cron/cronctl.py run <任务名>
# 也可直接运行(启用或 .disabled/<任务名> 目录均可)
# 也可直接运行 Python 任务(启用或 .disabled/<任务名> 目录均可)
python3 /shumengya/project/agent/sproutclaw-cron/.disabled/<任务名>/run.py
# 其他语言任务请始终用 cronctl run
```
### 安装到系统 cron
`cronctl enable` 会将 `schedule.cron` 复制到 `/etc/cron.d/<task-id>``disable` **只**把任务目录移入 `.disabled/<task-id>/`**不会**删除 `/etc/cron.d/` 条目。cron 到点仍会触发,但 `run.py` 检测到禁用后会直接跳过。
**Linux**`cronctl enable` 会将 `schedule.cron` 复制到 `/etc/cron.d/<task-id>``disable` **只**把任务目录移入 `.disabled/<task-id>/`**不会**删除 `/etc/cron.d/` 条目。cron 到点仍会触发,但禁用后任务会自动跳过。
```bash
python3 /shumengya/project/agent/sproutclaw-cron/cronctl.py sync-cron all # 仅同步 cron.d不改开关
```
**Windows**`enable` / `sync-cron` 会通过 `schtasks` 注册任务计划(任务名 `sproutclaw-<task-id>`)。目前自动转换 `分 时 * * *` 形式的 cron 表达式为「每天 HH:MM」复杂表达式需手动创建计划任务。
```powershell
python D:\SmyProjects\AI\sproutclaw-cron\cronctl.py sync-cron all
python D:\SmyProjects\AI\sproutclaw-cron\cronctl.py enable <任务名>
```
开关机制与 Linux 相同:禁用后目录移入 `.disabled/`,计划任务仍会触发,但任务会自动跳过。
---
## 开关机制
- **启用**:从 `.disabled/<task-id>/` 移回 `<task-id>/`
- **关闭**:从 `<task-id>/` 移入 `.disabled/<task-id>/`
- `run.py` 在入口检查 `task_is_disabled(ctx)`,若关闭直接 `return 0`,不写日志、不发通知、不获取锁
- 禁用时 `cronctl run` 会直接跳过,不写日志、不获取锁
- `/etc/cron.d/<task-id>` 可一直保留;`schedule.cron` 通过 `cronctl.py run <task-id>` 调度
---
## 多语言支持
调度入口统一为 `cronctl.py run`Python。业务脚本语言由 `task.json` 或入口文件决定:
| runtime | 入口 | 依赖 |
|---|---|---|
| `python`(默认) | `run.py` | Python 3 |
| `javascript` | `run.js` | Node.js |
| `bash` | `run.sh` | bash |
| `powershell` | `run.ps1` | pwsh / powershell |
### task.json
```json
{
"runtime": "python",
"entry": "run.py"
}
```
`task.json` 时:有 `run.py` 视为 Python 任务(向后兼容)。
---
## 新建任务(模板)
**从 `_template/` 复制**`_template` 本身是可管理的示例任务(每天 08:00 输出 hello world
**默认从 `_template/`Python复制**JavaScript / Bash / PowerShell 见 `_template-javascript` 等目录
```bash
TASK_ID="smallmengya-my-new-task"
@@ -98,7 +124,6 @@ CRON_ROOT="/shumengya/project/agent/sproutclaw-cron"
cp -a "$CRON_ROOT/_template" "$CRON_ROOT/$TASK_ID"
sed -i "s/_template/$TASK_ID/g" "$CRON_ROOT/$TASK_ID/schedule.cron"
chmod +x "$CRON_ROOT/$TASK_ID/switch.sh"
# 编辑 run.py 与 schedule.cron 后试跑
python3 "$CRON_ROOT/cronctl.py" run "$TASK_ID"
@@ -107,6 +132,12 @@ python3 "$CRON_ROOT/cronctl.py" enable "$TASK_ID"
详细约定见 `_template/README.md`AI 代理见根目录 `AGENTS.md`
### AI Agent 集成
- **Skill**`.cursor/skills/sproutclaw-cron/` — Cursor Agent 自动识别定时任务操作规范
- **MCP**`.cursor/mcp.json` + `mcp-server/server.py` — 暴露 `cron_list_tasks``cron_run_task` 等工具
- 首次使用 MCP`pip install -r mcp-server/requirements.txt`,然后在 Cursor 设置中确认 MCP 服务器已启用
---
## 公共库 API
@@ -204,9 +235,6 @@ python3 "$CRON_ROOT/cronctl.py" enable "$TASK_ID"
每个 `run.py` 顶部都有 3 行 `sys.path.insert` 代码,是为了支持 `schedule.cron` 直接调用 `python3 run.py`
若将 `schedule.cron` 改为调用 `cronctl run <task-id>`,则 `run.py` 里的路径注入可以全部删掉。
### 2. `switch.sh` 冗余
每个任务目录都有一份 `switch.sh`,其内部已经是代理调用 `cronctl.py`,新任务可以不再创建它,直接用 `cronctl enable/disable`
---
## 任务配置文件格式JSON
@@ -246,7 +274,7 @@ python3 "$CRON_ROOT/cronctl.py" enable "$TASK_ID"
## 依赖说明
这套系统**只依赖 Python 3 标准库**`fcntl``subprocess``pathlib` 等),无需安装任何 PyPI 包。
这套系统**只依赖 Python 3 标准库**`subprocess``pathlib` 等),无需安装任何 PyPI 包。文件锁在 Linux 用 `fcntl`Windows 用 `msvcrt`;定时调度在 Linux 用 `/etc/cron.d/`Windows 用任务计划程序(`schtasks`)。
通知功能依赖两个本地项目(非 PyPI 依赖,可缺失时降级):
- `lark-notice-api`:飞书通知,路径 `/shumengya/project/python/lark-notice-api/`