20 Commits

Author SHA1 Message Date
37d4ebfc1c chore: auto release commit (2026-09-12 15:12:53)
All checks were successful
技能自动化发布 / release (push) Successful in 6s
2026-09-12 15:12:53 +08:00
18223d5a26 chore: auto release commit (2026-09-11 16:25:24)
All checks were successful
技能自动化发布 / release (push) Successful in 6s
2026-09-11 16:25:24 +08:00
6786a19953 chore: auto release commit (2026-09-11 15:24:58)
All checks were successful
技能自动化发布 / release (push) Successful in 6s
2026-09-11 15:24:58 +08:00
d10db1d667 chore: auto release commit (2026-09-11 15:12:31)
All checks were successful
技能自动化发布 / release (push) Successful in 8s
2026-09-11 15:12:31 +08:00
26efbf7f82 chore: auto release commit (2026-09-11 00:17:16)
All checks were successful
技能自动化发布 / release (push) Successful in 6s
2026-09-11 00:17:16 +08:00
cb9bb4342f chore: auto release commit (2026-09-11 00:04:36)
All checks were successful
技能自动化发布 / release (push) Successful in 5s
2026-09-11 00:04:37 +08:00
21242cdd6d chore: auto release commit (2026-09-10 23:57:26)
All checks were successful
技能自动化发布 / release (push) Successful in 5s
2026-09-10 23:57:26 +08:00
05a71cff9b chore: auto release commit (2026-09-10 23:56:06)
All checks were successful
技能自动化发布 / release (push) Successful in 5s
2026-09-10 23:56:06 +08:00
f7290d5563 chore: auto release commit (2026-09-10 23:53:22)
All checks were successful
技能自动化发布 / release (push) Successful in 5s
2026-09-10 23:53:22 +08:00
848bd537ed chore: auto release commit (2026-09-10 23:51:10)
All checks were successful
技能自动化发布 / release (push) Successful in 6s
2026-09-10 23:51:10 +08:00
1e623e5c0f chore: auto release commit (2026-09-10 23:35:50)
All checks were successful
技能自动化发布 / release (push) Successful in 7s
2026-09-10 23:35:50 +08:00
2be083c0c9 chore: auto release commit (2026-09-10 23:28:38)
All checks were successful
技能自动化发布 / release (push) Successful in 9s
2026-09-10 23:28:38 +08:00
828437779c chore: auto release commit (2026-09-10 23:22:36)
All checks were successful
技能自动化发布 / release (push) Successful in 7s
2026-09-10 23:22:36 +08:00
abe4ea80a0 chore: auto release commit (2026-09-10 23:21:28)
All checks were successful
技能自动化发布 / release (push) Successful in 7s
2026-09-10 23:21:28 +08:00
e14cb97232 chore: auto release commit (2026-09-10 23:15:15)
All checks were successful
技能自动化发布 / release (push) Successful in 7s
2026-09-10 23:15:15 +08:00
2c7b23ac77 chore: auto release commit (2026-09-10 23:12:07)
All checks were successful
技能自动化发布 / release (push) Successful in 5s
2026-09-10 23:12:07 +08:00
cdd8b663f4 chore: auto release commit (2026-09-10 22:59:50)
All checks were successful
技能自动化发布 / release (push) Successful in 7s
2026-09-10 22:59:50 +08:00
285138ebf4 chore: auto release commit (2026-09-10 18:05:47)
All checks were successful
技能自动化发布 / release (push) Successful in 6s
2026-09-10 18:05:47 +08:00
4cde7ea739 chore: auto release commit (2026-09-10 17:58:00)
All checks were successful
技能自动化发布 / release (push) Successful in 6s
2026-09-10 17:58:00 +08:00
2b3fdda61e chore: auto release commit (2026-09-10 17:49:40)
All checks were successful
技能自动化发布 / release (push) Successful in 6s
2026-09-10 17:49:40 +08:00
6 changed files with 291 additions and 30 deletions

View File

@@ -6,7 +6,10 @@
"id": "health",
"label": "运行检查",
"description": "检查技能运行环境并返回结构化结果,不启动浏览器。",
"placements": ["skill-detail", "agent"],
"placements": [
"skill-detail",
"agent"
],
"executionProfile": "sync",
"entrypoint": {
"type": "cli",
@@ -18,7 +21,9 @@
"id": "version",
"label": "查看版本",
"description": "返回技能版本和机器标识。",
"placements": ["skill-detail"],
"placements": [
"skill-detail"
],
"executionProfile": "sync",
"entrypoint": {
"type": "cli",
@@ -30,13 +35,256 @@
"id": "config-path",
"label": "查看配置位置",
"description": "返回技能配置文件位置。",
"placements": ["skill-detail"],
"placements": [
"skill-detail"
],
"executionProfile": "sync",
"entrypoint": {
"type": "cli",
"command": "config-path",
"args": []
}
},
{
"id": "add-todo",
"label": "添加待办",
"description": "添加待办事项。",
"placements": [
"skill-detail",
"toolbar"
],
"executionProfile": "sync",
"entrypoint": {
"type": "cli",
"command": "todo",
"args": [
"add",
"--title",
"{{title}}",
"--priority",
"{{priority}}",
"--due-at",
"{{due-at}}"
]
},
"interaction": "form",
"bind": {
"tables": [
"todos"
]
},
"inputSchema": {
"type": "object",
"properties": {
"title": {
"type": "string",
"title": "待办标题",
"description": "待办事项的标题,必填。"
},
"priority": {
"type": "string",
"title": "优先级",
"description": "待办事项的优先级,可选。",
"default": "normal",
"enum": [
"high",
"normal",
"low"
]
},
"due-at": {
"type": "number",
"title": "提醒时间",
"description": "格式 YYYY-MM-DD HH:MM,如 2026-08-01。",
"display_type": "datetime_unix_seconds"
}
},
"required": [
"title",
"priority"
]
},
"hostEffects": {
"onSuccess": [
"reloadTable"
]
}
},
{
"id": "item-create",
"label": "新增记录",
"description": "添加待办事项。",
"replaces": "create",
"placements": [],
"executionProfile": "sync",
"interaction": "form",
"bind": {
"tables": [
"todos"
]
},
"hostEffects": {
"onSuccess": [
"reloadTable"
]
},
"inputSchema": {
"type": "object",
"properties": {
"title": {
"type": "string",
"title": "待办标题",
"description": "待办事项的标题,必填。"
},
"priority": {
"type": "string",
"title": "优先级",
"description": "待办事项的优先级,可选。",
"default": "normal",
"enum": [
"high",
"normal",
"low"
]
},
"due-at": {
"type": "number",
"title": "提醒时间",
"description": "格式 YYYY-MM-DD HH:MM,如 2026-08-01。",
"display_type": "datetime_unix_seconds"
}
},
"required": [
"title",
"priority"
]
},
"entrypoint": {
"type": "cli",
"command": "todo",
"args": [
"add",
"--title",
"{{title}}",
"--priority",
"{{priority}}",
"--due-at",
"{{due-at}}"
]
}
},
{
"id": "todo-done-row",
"label": "完成本行",
"description": "将当前待办标记为已完成。",
"placements": [
"row"
],
"executionProfile": "sync",
"interaction": "direct",
"bind": {
"tables": [
"todos"
]
},
"inputSchema": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "number",
"title": "编号",
"readOnly": true
}
}
},
"hostEffects": {
"onSuccess": [
"reloadTable"
]
},
"entrypoint": {
"type": "cli",
"command": "todo",
"args": [
"done",
"{{id}}"
]
}
},
{
"id": "todo-delete",
"label": "删除记录",
"description": "删除待办事项。",
"replaces": "delete",
"placements": [],
"executionProfile": "sync",
"interaction": "confirm",
"confirmation": {
"message": "确定删除该记录?关联数据将一并清理。"
},
"bind": {
"tables": [
"todos"
]
},
"hostEffects": {
"onSuccess": [
"reloadTable",
"clearSelection"
]
},
"inputSchema": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "number",
"title": "编号",
"readOnly": true
}
}
},
"entrypoint": {
"type": "cli",
"command": "todo",
"args": [
"delete",
"ids",
"{{id}}"
]
}
},
{
"id": "todo-remind",
"placements": [
"agent",
"cron"
],
"executionProfile": "async",
"inputSchema": {
"type": "object",
"properties": {
"seconds": {
"type": "number",
"default": 3
}
}
},
"label": "到期提醒",
"description": "在指定时间提醒到期的待办事项。",
"entrypoint": {
"type": "cli",
"command": "remind",
"args": [
"--seconds",
"{{seconds}}"
]
}
}
]
}

View File

@@ -13,12 +13,11 @@
## 0.1 宿主入口定位
| 主能力(Action id / CLI) | 对话 | 数据管理 | 定时 | 不挂理由(若不挂) |
|---------------------------|------|----------|------|--------------------|
| `todo add` | 挂 | toolbar(新增按钮) | 不挂 | 定时无意义 |
| `todo list` | 挂 | 仅展示表 | 不挂 | 定时无意义 |
| `todo done` | 挂 | row + batch(标记完成) | 不挂 | 定时无意义 |
| `todo delete` | 挂 | row + batch(删除) | 不挂 | 定时无意义 |
| `todo list` | 挂 | row | 不挂 | 定时无意义 |
| `todo done`(Action `todo-done-row`) | 挂(短 CLI 直调) | row(「完成」按钮) | 不挂 | 定时无意义;batch 批量完成暂未声明 |
| `todo delete` | 挂 | row(「删除」按钮)) + batch(删除) | 不挂 | 定时无意义 |
| `todo stats` | 挂 | toolbar(统计) | 不挂 | 定时无意义 |
| `remind` | 挂 | toolbar | 挂 | 定时扫描到期/待办项并提醒 |
| `init-db` | 不挂 | 不挂 | 不挂 | 宿主安装/更新时静默调用,不对用户暴露 |
@@ -28,7 +27,6 @@
说明:
- `todos` 表在数据管理中为**整表只读**(`readonly=1`),所有增删改必须通过技能 Action(`todo add/done/delete`)走,宿主不直写业务表。
- 数据管理页面默认展示列:`title`、`status`、`priority`、`due_at`、`created_at`;默认按 `created_at` 倒序。
- `status` 与 `priority` 字段在数据管理中以下拉枚举展示(pending=待办/done=完成;high=高/normal=中/low=低)。
@@ -225,3 +223,4 @@
| 日期 | 版本 | 变更人 | 变更内容 |
|------|------|--------|----------|
| 2026-09-07 | v0.1.0 | - | 初版需求文档 |
| 2026-09-11 | v0.1.1 | - | 入口定位表登记行级 Action `todo-done-row`(todos 表操作列「完成本行」,sync/direct,`$row.$pk` 预填) |

View File

@@ -57,7 +57,7 @@ def _add_run_subparser(sub) -> None:
todo_sub = sp.add_subparsers(dest="todo_cmd", required=True, parser_class=ZhArgumentParser)
p = todo_sub.add_parser("add", help="新增一条待办")
p.add_argument("title", help="待办标题(必填)")
p.add_argument("-t","--title", help="待办标题(必填)")
p.add_argument("-p", "--priority", default="normal",
choices=["high", "normal", "low"], help="优先级,默认 normal")
p.add_argument("-d", "--due-at", type=int, default=None,

View File

@@ -56,7 +56,7 @@ def _seed_todos_display_metadata(cursor) -> None:
table_name="todos",
display_name="待办事项",
description="本技能的核心业务表:每条待办事项一行。",
grid_help="状态变更走技能 CLI(todo done / todo delete),不要在表里直接改。",
grid_help="所有的待办事项,包括待办、已办、已删除。",
visible=1,
readonly=1, # 整表只读:增删改通过技能 Action 走,宿主不直写
default_sort_json='[{"column":"created_at","direction":"desc"}]',
@@ -69,21 +69,21 @@ def _seed_todos_display_metadata(cursor) -> None:
{"column_name": "id", "display_name": "编号", "description": "主键",
"visible": 1, "searchable": 1, "editable": 0, "display_type": "number"},
{"column_name": "title", "display_name": "标题", "description": "待办事项内容",
"grid_help": "简明描述要做的事", "visible": 1, "searchable": 1, "editable": 0,
"grid_help": "简明描述要做的事", "visible": 1, "searchable": 1, "editable": 1,
"display_type": "text"},
{"column_name": "status", "display_name": "状态", "description": "pending/done",
"grid_help": "pending=待办,done=完成", "visible": 1, "searchable": 1, "editable": 0,
"display_type": "enum",
"options_json": '[{"value":"pending","label":"待办"},{"value":"done","label":"完成"}]'},
{"column_name": "priority", "display_name": "优先级", "description": "high/normal/low",
"visible": 1, "searchable": 1, "editable": 0, "display_type": "enum",
"visible": 1, "searchable": 1, "editable": 1, "display_type": "enum",
"options_json": '[{"value":"high","label":"高"},{"value":"normal","label":"中"},{"value":"low","label":"低"}]'},
{"column_name": "due_at", "display_name": "截止时间", "description": "Unix 秒;可空",
"visible": 1, "searchable": 1, "editable": 0, "display_type": "datetime_unix_seconds","default":"(unixepoch())"},
"visible": 1, "searchable": 1, "editable": 1, "display_type": "datetime_unix_seconds"},
{"column_name": "created_at", "display_name": "创建时间", "description": "Unix 秒",
"visible": 1, "searchable": 0, "editable": 0, "display_type": "datetime_unix_seconds","default":"(unixepoch())"},
"visible": 1, "searchable": 0, "editable": 0, "display_type": "datetime_unix_seconds"},
{"column_name": "updated_at", "display_name": "更新时间", "description": "Unix 秒",
"visible": 0, "searchable": 0, "editable": 0, "display_type": "datetime_unix_seconds","default":"(unixepoch())"},
"visible": 0, "searchable": 0, "editable": 0, "display_type": "datetime_unix_seconds"},
],
)

View File

@@ -69,7 +69,7 @@ async def _run_template_demo(target: Optional[str], input_id: Optional[str]) ->
def cmd_run(target: Optional[str] = None, input_id: Optional[str] = None) -> int:
"""通用任务执行入口模板。复制后请实现真实业务逻辑。"""
log = _get_task_logger()
task_type = "demo"
task_type = "cmd_run"
with job_context(skill=SKILL_SLUG):
log.info(
@@ -261,33 +261,31 @@ def cmd_stats() -> int:
# ---------------- async 任务范式(demo) ----------------
async def _run_remind_async(*, seconds: int) -> dict[str, Any]:
"""模拟长耗时任务:每秒 emit 一次进度,最后 finish 终态。
真实平台会推送到任务中心 UI 并支持取消;本 demo 在 stdout 打印 JSON Lines。
"""
steps = max(1, int(seconds))
for i in range(1, steps + 1):
await interruptible_sleep(1)
emit(f"提醒任务进度 {i}/{steps}", skill=SKILL_SLUG, stage="remind", progress=i, total=steps)
# 真实业务在这里会查 todos 表挑出 due/pending 项发出提醒;demo 不做真实推送
真实平台会推送到任务中心 UI 并支持取消;
"""
todos = todo_service.get_current_remind_todos()
for todo in todos:
todo_service.mark_done(todo.id)
emit(f"提醒待办 {todo.title}", skill=SKILL_SLUG, stage="remind")
summary = todo_service.stats()
return {"remind": True, "duration_seconds": steps, "stats": summary}
return {"remind": True, "duration_seconds": len(todos), "stats": summary}
def cmd_remind(*, seconds: int = 3) -> int:
"""演示 async 任务编排。CLI 入口仍走同一内核;Agent 真实调度时
通过 ``run_skill_action``(executionProfile: async)触发。"""
log = _get_task_logger()
task_type = "remind"
task_type = "cron"
with job_context(skill=SKILL_SLUG):
log.info("task_start task_type=%s stage=remind seconds=%s", task_type, seconds)
log.info("task_start task_type=%s stage=remind", task_type)
emit("开始执行提醒任务", skill=SKILL_SLUG, stage="remind")
try:
result = asyncio.run(_run_remind_async(seconds=seconds))
log.info("task_done task_type=%s status=ok", task_type)
finish(
status="ok",
message=f"提醒任务完成,处理 {seconds} 秒",
status="success",
message=f"提醒任务完成",
skill=SKILL_SLUG,
stage="remind",
**result,

View File

@@ -157,6 +157,22 @@ def delete_todo(todo_id: int) -> bool:
finally:
conn.close()
def get_current_remind_todos() -> list[Todo]:
"""获取当前需要提醒的待办。"""
now = _now()
conn = get_conn()
try:
cur = conn.cursor()
cur.execute(
"SELECT id, title, status, priority, due_at, created_at, updated_at "
"FROM todos WHERE due_at <= ? AND status = ?",
(int(now / 60) * 60 + 59, STATUS_PENDING),
)
rows = cur.fetchall()
return [Todo(*row) for row in rows]
finally:
conn.close()
def stats() -> dict:
"""简单统计:用于 ``todo stats`` 命令与 demo 报告。"""