From 693a5e4a5368a6dafcc64f7f337ae3674dbe7973 Mon Sep 17 00:00:00 2001 From: taojianmin Date: Mon, 14 Sep 2026 23:55:58 +0800 Subject: [PATCH] chore: auto release commit (2026-09-14 23:55:58) --- CHANGELOG.md | 6 +++++ SKILL.md | 2 +- assets/actions.json | 15 +++++++++++ references/WORK_ITEM_STATUS.md | 14 +++++++++++ scripts/cli/app.py | 13 ++++++---- scripts/util/constants.py | 2 +- tests/run_tests.py | 46 ++++++++++++++++++++++++++++++++++ 7 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 references/WORK_ITEM_STATUS.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c29075..37097b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ 本文件对应技能市场 **「更新日志」** Tab。 +## 1.1.17 + +- 补齐数据管理的“立即同步合同台账”工具栏入口,调用 SmartCampus 平台采集能力。 +- 补齐合同业务行状态规范,并增加 Action 声明与 CLI 命令一致性的发布前校验。 +- 平台采集默认显示浏览器,登录态失效时可直接手工登录;自动化任务须显式传 `--headless`。 + ## 1.1.16 - 修复续聘建议中的趋势判定:仅近三年考核分数严格递增才建议续聘;成绩持平或回落均进入常规续聘评审。 diff --git a/SKILL.md b/SKILL.md index 2889b8c..2877f4d 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,7 +1,7 @@ --- name: 合同到期智能预警与续聘辅助 description: "当用户说要扫描即将到期的合同、查 90/60/30 天预警名单、给某位教师生成续聘任务书、下发单位版续聘清单、从 SmartCampus HR 平台抓合同数据、解析续聘材料 PDF/Word、查看本月合同到期人员清单时,加载本技能。支持定时扫描(每日凌晨)+ 数据管理 + Agent 三入口,覆盖合同到期智能预警与续聘辅助全流程。" -version: 1.1.16 +version: 1.1.17 author: 深圳匠厂科技有限公司 metadata: openclaw: diff --git a/assets/actions.json b/assets/actions.json index 0fdf4f0..73510ae 100644 --- a/assets/actions.json +++ b/assets/actions.json @@ -53,6 +53,21 @@ "args": ["--thresholds", "90,60,30"] } }, + { + "id": "collect-from-platform", + "label": "立即同步合同台账", + "description": "从 SmartCampus HR 平台同步最新合同台账与续聘材料包到本技能数据目录。", + "placements": ["toolbar", "agent"], + "executionProfile": "async", + "bind": { + "tables": ["合同台账"] + }, + "entrypoint": { + "type": "cli", + "command": "collect-from-platform", + "args": [] + } + }, { "id": "generate-renewal-task", "label": "生成续聘任务书", diff --git a/references/WORK_ITEM_STATUS.md b/references/WORK_ITEM_STATUS.md new file mode 100644 index 0000000..1891ac0 --- /dev/null +++ b/references/WORK_ITEM_STATUS.md @@ -0,0 +1,14 @@ +# 合同台账业务行状态规范 + +本规范定义“合同台账”中每条合同可由数据管理动作处理的状态边界。 + +| 状态 | 角色 | 允许的动作 | 说明 | +| --- | --- | --- | --- | +| 可续聘 | 可操作 | 同步、扫描、生成续聘任务书、下发通知、标记已续签 | 默认初始状态。 | +| 预警中 | 进行中 | 同步、生成续聘任务书、下发通知、标记已续签 | 已产生黄、橙或红色预警。 | +| 已续签 | 成功终态 | 同步 | 续签材料已确认,关联 open 预警必须关闭。 | +| 已驳回 | 失败终态 | 同步 | 不再自动生成任务或派发通知。 | +| 已过期 | 失败终态 | 同步 | 合同已到期,保留记录供人工处置。 | +| 已撤回 | 跳过终态 | 同步 | 教师或单位撤回续聘申请。 | + +状态由人事处人工复核后可回退至“可续聘”;自动任务不得覆盖成功、失败或撤回终态。 \ No newline at end of file diff --git a/scripts/cli/app.py b/scripts/cli/app.py index f0a8699..fa884ce 100644 --- a/scripts/cli/app.py +++ b/scripts/cli/app.py @@ -198,8 +198,8 @@ def cmd_render_html(args: argparse.Namespace) -> int: def cmd_collect_platform(args: argparse.Namespace) -> int: """Playwright RPA 抓 SmartCampus HR 平台数据 → 落库。 - 首次需用户手工登录保存 cookie(默认 headless=False 便于交互); - 后续可用 headless=True 复用 profile。 + 默认显示浏览器,以便登录态失效时可立即手工登录; + 传 --headless 可复用已保存的 profile 进行无头采集。 退出码: 0 = 成功(即使抓到 0 行也返回 0,错误信息在 output["error"]) @@ -209,7 +209,7 @@ def cmd_collect_platform(args: argparse.Namespace) -> int: try: result = platform_collector.collect_all( limit=args.limit, - headless=not args.show_browser, + headless=args.headless, human_wait_timeout=args.human_wait_timeout or HUMAN_WAIT_TIMEOUT, ) except platform_collector.RPAError as e: @@ -344,8 +344,11 @@ def build_parser() -> argparse.ArgumentParser: ) sp.add_argument("--limit", type=int, default=0, help="限制抓取行数(0=全量)") - sp.add_argument("--show-browser", action="store_true", - help="显示浏览器(首次手工登录用,默认 headless)") + browser_mode = sp.add_mutually_exclusive_group() + browser_mode.add_argument("--headless", action="store_true", + help="无头运行(仅适合已保存有效登录态的自动化任务)") + browser_mode.add_argument("--show-browser", dest="headless", action="store_false", + help=argparse.SUPPRESS) sp.add_argument("--human-wait-timeout", type=int, default=None, help="手工登录 fallback 等待秒数(默认 180 = HUMAN_WAIT_TIMEOUT)") sp.set_defaults(handler=cmd_collect_platform) diff --git a/scripts/util/constants.py b/scripts/util/constants.py index cd860dd..c812ee2 100644 --- a/scripts/util/constants.py +++ b/scripts/util/constants.py @@ -6,7 +6,7 @@ """ SKILL_SLUG = "alert-contract-expiring-hr" -SKILL_VERSION = "1.1.16" +SKILL_VERSION = "1.1.17" LOG_LOGGER_NAME = "openclaw.skill.alert_contract_expiring_hr" PLATFORM_KIT_MIN_VERSION = "1.2.11" diff --git a/tests/run_tests.py b/tests/run_tests.py index fa3b3cd..4101d88 100644 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -18,6 +18,7 @@ test_* 返回 (False, msg) 即 abort 发布。 from __future__ import annotations import argparse +import json import os import re import shutil @@ -217,6 +218,49 @@ def test_skill_md_slug_alignment() -> tuple[bool, str]: return True, f"slug={md_slug}" +def test_data_management_actions() -> tuple[bool, str]: + """数据管理动作必须绑定业务表,并映射到实际 CLI 命令。""" + actions_path = _REPO_ROOT / "assets" / "actions.json" + actions = json.loads(actions_path.read_text(encoding="utf-8"))["actions"] + by_id = {action["id"]: action for action in actions} + + expected = { + "scan-expiring-contracts": "toolbar", + "collect-from-platform": "toolbar", + "generate-renewal-task": "row", + "dispatch-task-notice": "batch", + "mark-contract-renewed": "row", + } + for action_id, placement in expected.items(): + action = by_id.get(action_id) + if not action: + return False, f"缺少数据管理动作 {action_id}" + if placement not in action.get("placements", []): + return False, f"{action_id} 缺少 {placement} placement" + if "合同台账" not in action.get("bind", {}).get("tables", []): + return False, f"{action_id} 未绑定合同台账" + if action.get("entrypoint", {}).get("command") != action_id: + return False, f"{action_id} CLI command 映射错误" + return True, "5 个数据管理动作均绑定合同台账并映射到 CLI" + + +def test_collect_platform_defaults_to_browser() -> tuple[bool, str]: + """平台采集默认显示浏览器;--headless 仅用于已登录自动化。""" + from cli.app import build_parser + + parser = build_parser() + default_args = parser.parse_args(["collect-from-platform"]) + if default_args.headless: + return False, "collect-from-platform 默认不应使用无头模式" + headless_args = parser.parse_args(["collect-from-platform", "--headless"]) + if not headless_args.headless: + return False, "--headless 未启用无头模式" + legacy_args = parser.parse_args(["collect-from-platform", "--show-browser"]) + if legacy_args.headless: + return False, "--show-browser 兼容别名未保留浏览器模式" + return True, "默认浏览器模式,--headless 和 --show-browser 行为正确" + + # ---------- db.repository:v1.1.2 新增的 sandbox card 解析 ---------- def test_parse_sandbox_card_row_format() -> tuple[bool, str]: @@ -716,6 +760,8 @@ def main() -> int: _run("util/month_match", test_month_match) _run("constants/skill_md_version_alignment", test_skill_md_version_alignment) _run("constants/skill_md_slug_alignment", test_skill_md_slug_alignment) + _run("assets/data_management_actions", test_data_management_actions) + _run("cli/collect_platform_browser_default", test_collect_platform_defaults_to_browser) _run("db/parse_sandbox_card_row", test_parse_sandbox_card_row_format) _run("db/parse_sandbox_card_narrative", test_parse_sandbox_card_narrative_format) _run("db/parse_sandbox_card_empty_invalid", test_parse_sandbox_card_empty_and_invalid)