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:
11
.cursor/mcp.json
Normal file
11
.cursor/mcp.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"sproutclaw-cron": {
|
||||
"command": "python",
|
||||
"args": ["mcp-server/server.py"],
|
||||
"env": {
|
||||
"SPROUTCLAW_CRON_ROOT": "${workspaceFolder}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
88
.cursor/skills/sproutclaw-cron/SKILL.md
Normal file
88
.cursor/skills/sproutclaw-cron/SKILL.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
name: sproutclaw-cron
|
||||
description: >-
|
||||
Manage SproutClaw Cron scheduled tasks: list/enable/disable/run tasks, read logs,
|
||||
update schedules, create tasks from templates. Use when the user mentions cronctl,
|
||||
sproutclaw-cron, scheduled tasks, cron jobs, task enable/disable, or creating
|
||||
new cron tasks. Prefer MCP tools (cron_*) when available; fall back to cronctl.py CLI.
|
||||
---
|
||||
|
||||
# SproutClaw Cron 定时任务技能
|
||||
|
||||
## 何时启用
|
||||
|
||||
用户提到:`cronctl`、定时任务、开关任务、试跑任务、新建 cron 任务、`sproutclaw-cron`、WebUI 管理面板,或需要查看任务日志/调度时。
|
||||
|
||||
## 优先顺序
|
||||
|
||||
1. **MCP 工具**(已配置 `.cursor/mcp.json`):`cron_list_tasks`、`cron_get_task`、`cron_run_task` 等
|
||||
2. **CLI 兜底**:`python cronctl.py <action> [task-id]`
|
||||
3. **WebUI**:`start-webui.bat`(Windows)或 `webui/start.sh`(Linux)
|
||||
|
||||
## 项目路径
|
||||
|
||||
- 根目录:仓库根(`cronctl.py` 所在目录)
|
||||
- 可通过环境变量 `SPROUTCLAW_CRON_ROOT` 覆盖
|
||||
- Linux 生产路径示例:`/shumengya/project/agent/sproutclaw-cron`
|
||||
|
||||
## MCP 工具速查
|
||||
|
||||
| 场景 | 工具 |
|
||||
|------|------|
|
||||
| 看有哪些任务 | `cron_list_tasks` |
|
||||
| 看单个任务详情 | `cron_get_task` |
|
||||
| 开/关/切换 | `cron_enable_task` / `cron_disable_task` / `cron_toggle_task` |
|
||||
| 试跑 | `cron_run_task` → `cron_get_log` |
|
||||
| 改调度 | `cron_update_schedule` |
|
||||
| 新建任务 | `cron_list_templates` → `cron_create_task` |
|
||||
| 同步系统 cron | `cron_sync_cron` |
|
||||
|
||||
## 新建任务流程
|
||||
|
||||
1. 确认 `task_id` 命名:`<主机名>-<功能描述>`(如 `smallmengya-gitea-repo-sync`)
|
||||
2. `cron_create_task(task_id=..., runtime="python")` — **默认禁用**
|
||||
3. 编辑 `<task-id>/run.py`(或对应入口)与 `schedule.cron`
|
||||
4. `cron_run_task` 试跑,`cron_get_log` 确认
|
||||
5. 用户明确要求后再 `cron_enable_task`
|
||||
|
||||
模板与约定详见根目录 [AGENTS.md](../../AGENTS.md)。
|
||||
|
||||
## CLI 兜底命令
|
||||
|
||||
```bash
|
||||
python cronctl.py status
|
||||
python cronctl.py status <task-id>
|
||||
python cronctl.py enable|disable|toggle <task-id>
|
||||
python cronctl.py run <task-id>
|
||||
python cronctl.py sync-cron <task-id>
|
||||
python cronctl.py enable all
|
||||
```
|
||||
|
||||
Windows 将 `python` 换为实际 Python 路径;Linux 可用 `python3`。
|
||||
|
||||
## Agent 原则
|
||||
|
||||
- **默认新建任务保持禁用**,除非用户明确要求启用
|
||||
- **不要修改** `_template*` 示例目录(除非用户要求)
|
||||
- **schedule.cron** 调度入口保持 `cronctl.py run <task-id>` 形式
|
||||
- Python 任务保留 `task_is_disabled` / `task_logging` / `acquire_cron_lock` 结构
|
||||
- 非 Python 任务只改入口脚本;锁/日志/disable 由 `cronctl run` 统一处理
|
||||
- 改完业务逻辑后先 `run` 再 `enable`
|
||||
|
||||
## 任务目录结构
|
||||
|
||||
```
|
||||
<task-id>/
|
||||
├── task.json # 可选:runtime + entry + tags
|
||||
├── run.py|run.js|run.sh|run.ps1
|
||||
├── schedule.cron
|
||||
├── logs/<task-id>.log
|
||||
└── *.json # 可选配置
|
||||
```
|
||||
|
||||
禁用任务位于 `.disabled/<task-id>/`。
|
||||
|
||||
## 附加资源
|
||||
|
||||
- CLI 与 API 详情:[reference.md](reference.md)
|
||||
- 环境检查脚本:[scripts/check_cron.py](scripts/check_cron.py)
|
||||
83
.cursor/skills/sproutclaw-cron/reference.md
Normal file
83
.cursor/skills/sproutclaw-cron/reference.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# SproutClaw Cron 参考
|
||||
|
||||
## cronctl.py 子命令
|
||||
|
||||
| 子命令 | 说明 | 示例 |
|
||||
|--------|------|------|
|
||||
| `status` | 列出或查看任务状态 | `cronctl.py status` |
|
||||
| `enable` | 启用并同步 cron | `cronctl.py enable my-task` |
|
||||
| `disable` | 禁用(移入 `.disabled/`) | `cronctl.py disable my-task` |
|
||||
| `toggle` | 切换状态 | `cronctl.py toggle my-task` |
|
||||
| `run` | 同步执行一次 | `cronctl.py run my-task` |
|
||||
| `sync-cron` | 仅同步 cron.d / schtasks | `cronctl.py sync-cron my-task` |
|
||||
|
||||
别名:`on` → `enable`,`off` → `disable`。批量操作传 `all`。
|
||||
|
||||
## task.json
|
||||
|
||||
```json
|
||||
{
|
||||
"runtime": "python",
|
||||
"entry": "run.py",
|
||||
"tags": ["标签1", "标签2"]
|
||||
}
|
||||
```
|
||||
|
||||
`runtime`:`python` | `javascript` | `bash` | `powershell`
|
||||
|
||||
## schedule.cron 格式
|
||||
|
||||
- 首行注释为任务描述(WebUI / MCP 会读取)
|
||||
- cron 五段 + 用户 + 命令
|
||||
- 命令应调用:`python3 <CRON_ROOT>/cronctl.py run <task-id>`
|
||||
|
||||
示例:
|
||||
|
||||
```cron
|
||||
# 每天 08:00 同步仓库
|
||||
0 8 * * * root /usr/bin/python3 /path/to/sproutclaw-cron/cronctl.py run my-task >/dev/null 2>&1
|
||||
```
|
||||
|
||||
## WebUI API(FastAPI,端口见 start 脚本)
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/api/tasks` | 任务列表 |
|
||||
| GET | `/api/tasks/{id}` | 任务详情 |
|
||||
| POST | `/api/tasks/{id}/enable` | 启用 |
|
||||
| POST | `/api/tasks/{id}/disable` | 禁用 |
|
||||
| POST | `/api/tasks/{id}/run` | 后台试跑 |
|
||||
| GET | `/api/tasks/{id}/log?lines=200` | 日志 |
|
||||
| PATCH | `/api/tasks/{id}/schedule` | 更新调度 |
|
||||
|
||||
## 语言模板
|
||||
|
||||
| 模板目录 | runtime | 入口 |
|
||||
|----------|---------|------|
|
||||
| `_template` | python | `run.py` |
|
||||
| `_template-javascript` | javascript | `run.js` |
|
||||
| `_template-bash` | bash | `run.sh` |
|
||||
| `_template-powershell` | powershell | `run.ps1` |
|
||||
|
||||
## 公共库(Python 任务)
|
||||
|
||||
从 `lib/runner.py` 导入:
|
||||
|
||||
- `TaskContext.from_task_id(task_id)`
|
||||
- `task_is_disabled(ctx)` / `task_logging(ctx)` / `acquire_cron_lock(...)`
|
||||
|
||||
从 `lib/notify.py` 导入:
|
||||
|
||||
- `TaskResult`、`send_task_summary(...)`
|
||||
|
||||
## 开关机制
|
||||
|
||||
- 启用:`.disabled/<id>/` → `<id>/`
|
||||
- 禁用:`<id>/` → `.disabled/<id>/`
|
||||
- 禁用后 cron 仍可触发,但 `cronctl run` 会直接跳过
|
||||
|
||||
## MCP 服务器
|
||||
|
||||
- 入口:`mcp-server/server.py`
|
||||
- 配置:`.cursor/mcp.json`
|
||||
- 依赖:`pip install -r mcp-server/requirements.txt`
|
||||
55
.cursor/skills/sproutclaw-cron/scripts/check_cron.py
Normal file
55
.cursor/skills/sproutclaw-cron/scripts/check_cron.py
Normal file
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
"""SproutClaw Cron 环境检查(跨平台,仅标准库 + 可选 fastmcp)。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def main() -> int:
|
||||
root = Path(__file__).resolve().parents[4]
|
||||
lib = root / "lib"
|
||||
cronctl = root / "cronctl.py"
|
||||
mcp_server = root / "mcp-server" / "server.py"
|
||||
|
||||
checks: list[dict[str, object]] = []
|
||||
|
||||
def add(name: str, ok: bool, detail: str = "") -> None:
|
||||
checks.append({"name": name, "ok": ok, "detail": detail})
|
||||
|
||||
add("cron_root", root.is_dir(), str(root))
|
||||
add("cronctl.py", cronctl.is_file(), str(cronctl))
|
||||
add("lib/", lib.is_dir(), str(lib))
|
||||
add("mcp-server/server.py", mcp_server.is_file(), str(mcp_server))
|
||||
|
||||
try:
|
||||
import fastmcp # noqa: F401
|
||||
|
||||
add("fastmcp", True, "已安装")
|
||||
except ImportError:
|
||||
add("fastmcp", False, "pip install -r mcp-server/requirements.txt")
|
||||
|
||||
if cronctl.is_file():
|
||||
proc = subprocess.run(
|
||||
[sys.executable, str(cronctl), "status"],
|
||||
cwd=str(root),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30,
|
||||
)
|
||||
add(
|
||||
"cronctl status",
|
||||
proc.returncode == 0,
|
||||
(proc.stdout or proc.stderr).strip()[:500],
|
||||
)
|
||||
|
||||
ok_all = all(c["ok"] for c in checks if c["name"] != "fastmcp")
|
||||
print(json.dumps({"ok": ok_all, "checks": checks}, ensure_ascii=False, indent=2))
|
||||
return 0 if ok_all else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user