commit cd71f49709d7c5c40d5e14c4b7ddd809d02bfbd0 Author: taojianmin Date: Mon Sep 14 12:19:05 2026 +0800 v1.0.1: 制度文件冲突检测与合规审查 - 初版骨架 基于匠厂 skill-template 主仓 v1.0.108 派生的业务技能。 核心业务: - 起草人在 OA 上传新制度送审稿时,自动比对校内现行制度库(约 300+ 份) - 条款级冲突检测 + 程序合规性体检 + 疑似重复发文检测 - 在 Word 侧栏生成批注清单,一键跳转冲突原文 输出形态: - 制度送审稿表状态更新(可送审 → 审查中 → 已通过 / 冲突中 / 驳回) - 冲突条款清单 + HTML 审查报告 + 可选 PDF 导出 预期提效:制度出台后因"与 XX 文件冲突"而被要求暂停/修订的事件减少至零起。 业务行生命周期:可送审 → 审查中 → 已通过 / 冲突中 / 驳回 / 已跳过 Co-Authored-By: Claude Code diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..eee5f89 --- /dev/null +++ b/.env.example @@ -0,0 +1,23 @@ +# 制度文件冲突检测与合规审查 - 配置示例 +# 行头说明「是什么」;行尾说明「怎么填」;进程环境变量 > 用户 .env > 本文件 + +# OA 系统 API 入口,例如 https://oa.example.edu/api/v1 +OA_API_BASE_URL= + +# OA 系统 API 调用凭证(Bearer Token),由校办统一发放 +OA_API_TOKEN= + +# 冲突判定阈值(余弦相似度),超过即视为冲突;范围 0~1,默认 0.85 +CONFLICT_THRESHOLD=0.85 + +# 制度库文件目录绝对路径,校办统一维护;技能只读访问 +POLICY_LIBRARY_DIR= + +# 单份送审稿比对超时(秒),默认 30 +AUDIT_TIMEOUT_SEC=30 + +# 疑似重复发文判定阈值(余弦相似度),默认 0.85 +REPEAT_PUBLISH_THRESHOLD=0.85 + +# 错误码前缀,统一为 ERROR: 起头;详见 development/REQUIREMENTS.md §6 +LOG_LEVEL=INFO diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..08d4ec6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +__pycache__/ +*.py[cod] +.env +*.env.local +.pytest_cache/ +.coverage +htmlcov/ +dist/ +build/ +*.egg-info/ \ No newline at end of file diff --git a/.openclaw-skill-template b/.openclaw-skill-template new file mode 100644 index 0000000..5464d21 --- /dev/null +++ b/.openclaw-skill-template @@ -0,0 +1,5 @@ +# 此文件仅存在于 skill-template 源仓库。 +# 用 tools/scaffold_skill 创建新技能时,脚本会从目标目录删除本文件。 +# 若业务技能仓库中仍存在本文件,说明未正确 scaffold,tests 会失败。 +template_slug: your-skill-slug +template_version: "1.0.32" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..0b71f17 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +本文件对应技能市场 **「更新日志」** Tab。 + +## 1.0.1 + +- 初版:基于匠厂 skill-template 主仓 v1.0.108 派生 +- 实现核心业务:制度文件冲突检测与合规审查(送审稿向量化 + 校内 300+ 份制度库比对 + 程序合规体检 + 疑似重复发文检测 + Word 侧栏批注) +- 输出形态:制度送审稿表状态更新 + 冲突条款清单 + 可选 PDF 审查报告 +- 预期提效:制度出台后因"与 XX 文件冲突"而被要求暂停/修订的事件减少至零起;校内制度体系的逻辑一致性显著增强 +- 业务行生命周期:可送审 → 审查中 → 已通过 / 冲突中 / 驳回 +- 占位说明:本版仅完成骨架与文档,业务实现细节(`scripts/` 下 Python 模块、向量化模型选型、制度库同步策略)由开发者后续按 `development/REQUIREMENTS.md` 补全 diff --git a/DEMO.md b/DEMO.md new file mode 100644 index 0000000..79b7538 --- /dev/null +++ b/DEMO.md @@ -0,0 +1,28 @@ +--- +demo_video_url: "" +--- + +# 演示说明 + +> 本技能当前未提供演示视频。下方用图文形式描述完整审查流程与结果样例,便于你在安装后第一时间理解产物形态。 + +## 演示看点 + +1. **数据管理 → 制度送审稿 → 上传送审稿**:起草人上传一份《XX 管理办法》Word 文档 +2. **数据管理 → 制度送审稿 → 审查送审稿**:行级按钮触发,10~30 秒内完成 300+ 份制度的条款级比对 +3. **结果样例**: + - 行状态自动从「可送审」→「已通过」/「冲突中」/「驳回」 + - 冲突条款清单表新增若干行,每行含「冲突类型」「新条款原文」「旧制度文号」「旧条款原文」「建议处理」 + - Word 文档侧栏出现红 / 黄 / 绿批注,点击跳转至旧制度原文段落 + +## 没有视频时 + +可参考下方截图位(待补): + +- 截图位 1:制度送审稿表(审查中状态) +- 截图位 2:冲突条款清单表(红色冲突项) +- 截图位 3:Word 侧栏批注 + 跳转链接 + +## 何时补视频 + +v1.1.0 起,按 `development/TUTORIAL_SURFACES.md` §3 录制 1~2 分钟三入口演示视频,覆盖上传送审稿 → 触发审查 → 查看批注 → 导出报告的全流程。 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bb90574 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 深圳匠厂科技有限公司 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d5cc29c --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +--- +description: "起草人在 OA 上传新制度送审稿时,自动比对校内现行制度库,检测条款冲突、程序合规性、重复发文风险,并在 Word 侧栏生成批注清单。" +--- + +# 制度文件冲突检测与合规审查 + +起草人在 OA 上传新制度送审稿时,技能会自动与校内全部现行制度(约 300+ 份 PDF/Word 红头文件)做条款级比对,把"处罚标准不一致""经费上限打架""审批权限冲突""疑似重复发文"等问题直接批注到 Word 侧栏,让制度起草人在送审前就自纠自改,把"出文后才被叫停"的发生率降到零。 + +--- + +## 这个技能能帮你做什么 + +- **自动比对条款**:把新制度的每一条款(特别是处罚标准、经费标准、审批权限)与校内现行制度库做语义比对,发现数值不一致时立刻标红 +- **程序合规体检**:检查是否引用了上位法或上级文件、是否明确解释权归属、是否标注试行期/有效期 +- **疑似重复发文提醒**:如果新制度名称与近 3 年内某份制度在语义上高度相似,发出"建议合并或废止旧文"提醒 +- **侧栏批注 + 一键跳转**:冲突原文、文号、条款编号在 OA Word 在线编辑器的侧栏高亮显示,一键跳转到旧制度原文段落 +- **审查全流程留痕**:送审、审查中、已通过、冲突中、驳回 5 类状态全程可追溯 + +--- + +## 适合什么场景 + +- 校办文秘科每月需要处理十几份新起草或修订的制度送审稿 +- 职能部门起草人提交送审前希望提前发现冲突,避免被打回 +- 校领导希望确保新出制度与学校现行制度体系保持逻辑一致 +- 上级文件修订后,需要批量复核存量送审稿是否还合规 + +--- + +## 使用前需要准备什么 + +- 校内现行制度库的访问权限(制度文号、PDF/Word 文件均已入库) +- OA 系统的 API 凭证(用于读取送审稿与回写批注) +- 起草人应确认新制度 Word 文档已完成自校,准备送审 + +--- + +## 怎么使用 + +本技能支持**数据管理**(在制度送审稿表上点工具栏按钮)与**对话任务**(自然语言让 Agent 完成审查),两种方式触发同一套业务能力。 + +**逐步操作与排障,请查看技能市场「使用教程」Tab。** + +--- + +## 执行后你会得到什么 + +- 一份《合规审查批注清单》,逐条列出冲突项、合规缺项、重复发文风险 +- Word 文档侧栏的红色 / 黄色 / 绿色标记和跳转链接 +- 制度送审稿表中的状态字段(送审 → 审查中 → 已通过 / 冲突中 / 驳回)自动更新 +- 可选的离线审查报告(PDF),便于存档或转发 + +--- + +## 注意事项 + +- 本技能不替代法律或合规终审,最终签发仍由校办文秘科与分管校领导负责 +- 涉及撤销、废止旧制度的操作仍需走 OA 原文流程,技能仅给出建议 +- 制度库更新(如新发布 / 新废止)后,建议手动触发一次存量送审稿的重新比对 +- OCR 识别对扫描质量较差的旧制度 PDF 准确率约 92%,冲突标注可能漏检少量,需人工兜底 + +--- + +## 常见问题 + +### 这个技能适合我吗? + +> 如果你的工作包含"新起草或修订校内制度并送审",本技能可以在送审前自动兜住冲突 / 重复 / 缺程序等常见问题。 + +### 我不会操作,从哪里开始? + +> 请打开技能市场 **「使用教程」** Tab,按"入口一:数据管理"或"入口二:对话任务"任选一种跟做。 + +### 制度库里的旧文件会被改动吗? + +> 不会。技能只读访问现行制度库;只对"送审稿"做写操作(添加批注、修改状态字段)。 + +### 已经审查过的送审稿能再审一次吗? + +> 可以。已通过的送审稿如需复审(例如上位法修订),可在表上点"重新审查"。 diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..657e660 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,20 @@ +# 安全漏洞披露 + +本仓库是匠厂技能开发模板。请把**未公开的安全漏洞**发给深圳匠厂科技有限公司,不要在公开 Issue、PR 或讨论区里贴完整复现步骤、PoC 或利用细节。 + +## 怎么报告 + +请通过匠厂官网联系渠道提交:[https://www.jc2009.com/](https://www.jc2009.com/) + +建议在联系时注明: + +- 标题或开头带 `[Security]` +- 影响的仓库 / 版本(例如 `skill-template`、tag `v1.0.x`) +- 问题类型、影响范围、复现步骤 +- 若已有修复思路,可一并说明 + +我们会确认收悉,并在有结论后告知是否修复、是否公开披露。 + +## 不在本页范围 + +本页只说明**如何向我们报告漏洞**。技能运行时的权限、RPA 合规、加密发布等产品安全设计,见 `development/` 与 `references/`,不要写进本文件。 diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..2944b92 --- /dev/null +++ b/SKILL.md @@ -0,0 +1,132 @@ +--- +name: 制度文件冲突检测与合规审查 +description: "起草人在 OA 上传新制度送审稿时,自动检测与校内现行制度库(约 300+ 份)的条款冲突、程序合规性、重复发文风险,并在 Word 侧栏生成批注清单。" +version: 1.0.1 +author: 深圳匠厂科技有限公司 +metadata: + openclaw: + slug: detect-policy-conflict-gs + platform_kit_min_version: "1.2.11" + emoji: "⚖️" + category: "行政" + developer_ids: + - 12345 # 占位,请换成你的匠厂用户 ID + - 12468 +allowed-tools: + - bash +--- + +# 制度文件冲突检测与合规审查(detect-policy-conflict-gs) + +这是基于匠厂 skill-template 主仓 v1.0.108 派生的业务技能。覆盖需求规格书第 4.3 节「🟠 校办/党办 Skill 001 —— 制度文件"冲突检测与合规审查"」。 + +## Agent / 宿主编排(复制为业务技能后必改) + +### AI + RPA 定位 + +- **Agent 是入口与编排者**:理解用户意图("审这一份新制度"、"列出本月所有冲突制度")、补齐参数、判断风险、选择 Action,并用业务语言解释结果。 +- **本技能不涉及浏览器 / 桌面 / 手机 RPA**:所有读取与写入走 OA 官方 API(优先)或离线文档解析;如官方 API 不可用,按 `development/RPA.md` 停止并上报,不擅自走逆向/私有协议路线。 +- 开发者与 AI 编程工具先读 `development/AI_RPA.md`。 + +### 架构铁律(先读) + +- **宿主产品入口平级**:对话任务 / 数据管理 / 定时任务是同一技能能力的不同触发场景,**同等重要**;挂哪些由本技能 UX 定义(入口定位表),详见 `development/PRODUCT_SURFACES.md`。 +- **单业务内核、多入口**:数据管理 / 定时任务 / Agent / 技能详情 / 直接 CLI 必须复用同一 domain service;禁止按入口复制业务逻辑,禁止按 `source` 分叉业务行为。 +- **数据管理**:既是 **UI 执行面**(点按钮走与对话相同的闭环),也是数据与过程可见;不是「只读库」。 +- **业务行生命周期**:本技能对每一份「送审稿」有"可送审 → 审查中 → 已通过 / 冲突中 / 驳回"五类状态,遵守 `references/WORK_ITEM_STATUS.md` 角色约束。 +- **HTML 整页报告**:本技能输出形态为「OA Word 侧栏批注」,**不**走 `render-html`;如需离线存档,单独走 `export-review-report` 落 `output/`。 + +### 如何触发(能力类型) + +| 你要做什么 | Agent 怎么做 | 进任务中心? | +|------------|--------------|--------------| +| 健康检查 / 短查询 | OpenClaw bash/exec + 共享 Python 跑 CLI | 否 | +| 已声明 sync 的 Action | `run_skill_action` 或等效短 CLI | 否 | +| 长任务(送审稿向量化比对 300+ 份制度) | **必须** `run_skill_action`(先 `list_skill_actions` / `get_skill_action`) | 是(仅因 async) | + +### 用户意图路由表(业务技能复制后必改) + +| 用户意图(本技能自填) | Agent 怎么做 | 进任务中心? | +|------------------------|--------------|--------------| +| 检查运行环境 | 短 CLI:`python {baseDir}/scripts/main.py health` | 否 | +| 查看版本 | 短 CLI:`python {baseDir}/scripts/main.py version` | 否 | +| 查看配置位置 | 短 CLI:`python {baseDir}/scripts/main.py config-path` | 否 | +| 送审一份新制度 | `run_skill_action` → `audit-policy-draft`(输入:`policy_draft_id`) | 否(sync) | +| 重新比对某条冲突条款 | `run_skill_action` → `recheck-conflict-clause`(输入:`clause_id`) | 否(sync) | +| 导出完整审查报告 | `run_skill_action` → `export-review-report`(输入:`policy_draft_id`) | 否(sync) | +| 定时扫描:制度库新增/变更后自动比对存量送审稿 | `run_skill_action` → `rescan-pending-drafts`(cron / agent) | 是(async) | +| 标记送审稿为"已通过 / 驳回" | `run_skill_action` → `mark-policy-status`(输入:`policy_draft_id` + `target_status`) | 否(sync) | + +## 共享 Python(必读) + +宿主共享 runtime 在 `{JIANGCHANG_DATA_ROOT}/python-runtime/.venv`,并已前置到 PATH(同时设 `VIRTUAL_ENV`)。短 CLI 一条命令直接跑: + +```bash +python {baseDir}/scripts/main.py health +python {baseDir}/scripts/main.py version +python {baseDir}/scripts/main.py config-path +python {baseDir}/scripts/main.py init-db +``` + +- 公共库来自共享 venv 的 `jiangchang-platform-kit>=1.2.11`(包名路径 `jiangchang_skill_core`);**不要 vendor** `scripts/jiangchang_skill_core/`。 +- 根目录 `requirements.txt` **只声明技能特有**依赖;不要写 `jiangchang-platform-kit` / `playwright`。 +- `metadata.openclaw.platform_kit_min_version` 是宿主兼容声明,**不是** pip 依赖。 +- `health` 用 `collect_runtime_diagnostics` 做只读诊断。 + +配置:仓库 `.env.example` 为模板;用户 `.env` 在 `{JIANGCHANG_DATA_ROOT}/{JIANGCHANG_USER_ID}/{slug}/.env`。优先级:进程环境变量 > 用户 `.env` > `.env.example`。 + +## 面向用户问答(LLM 规则) + +- 本文(`SKILL.md`)是 LLM / OpenClaw 平台读取的技能入口,**不是**用户市场说明。 +- 根目录市场材料面向普通用户(见下方「文档分工」),**不是** Agent 调用契约。 + +当用户询问以下问题时,**必须优先读取**根目录 `README.md`(能力说明)与 `TUTORIAL.md`(逐步用法),并用用户能理解的业务语言回答: + +- 这个技能是做什么的 +- 这个技能怎么用 +- 适合什么场景 +- 使用前要准备什么 +- 执行后会得到什么 +- 能不能帮我完成某个业务任务 + +**回答「怎么用 / 能做什么」时的要求:** + +1. 「能做什么 / 场景 / 概念类 FAQ」以 `README.md`(说明 Tab)为主;「点哪里 / 说什么 / 排障」以 `TUTORIAL.md`(教程 Tab)为主。 +2. **禁止**在回答中粘贴 `python …/scripts/main.py …` 或其它命令行(除非用户明确索要命令,或自称技术人员/开发者)。 +3. **禁止**为答用法而去 `dir` / `ls` / 列技能目录,或默认打开 `references/`、`development/`。 +4. **不要**向普通用户暴露 Playwright、DOM、Python、RPA、库表名、`error_code` 等实现细节。 +5. 用户问「怎么用」时:**优先读 `TUTORIAL.md`**。 + +## 文档分工 + +| 文档 | 读者 | 用途 | +|------|------|------| +| 根目录 `README.md` | 普通用户 | 市场 **说明** Tab | +| 根目录 `TUTORIAL.md` | 普通用户 | 市场 **教程** Tab | +| 根目录 `DEMO.md` | 普通用户 | 市场 **演示** Tab | +| 根目录 `CHANGELOG.md` | 普通用户 | 市场 **更新日志** Tab | +| `SKILL.md`(本文) | LLM / OpenClaw 平台 | 技能入口、触发与运行契约摘要 | +| `references/` | Agent 编排 / 调用 | CLI、Action、schema 契约 | +| `development/` | 开发者 / AI 编程代理 | 需求、开发教程、测试、深度技术规范 | + +## 目录约定 + +- `assets/`、`development/`、`evals/`、`references/`、`scripts/`、`tests/` +- CLI 入口固定为 `scripts/main.py` +- 业务逻辑按 `cli / db / service / util` 分层 + +## 技能命名与 slug + +- slug:`detect-policy-conflict-gs`(`detect` 动词 + `policy-conflict` 名词 + `gs` general office 部门缩写) +- name:**用户可见的中文业务名称**;`description` 是说明,不是名称。 +- 目录名、默认 `{slug}.db` 使用 slug,不使用中文。 + +## 平台元数据 + +- `metadata.openclaw.developer_ids`:技能发布后的默认开发者可见用户 ID 列表(ID 来自匠厂宿主「设置 → 用户信息」)。 +- 开发期技能常为不公开:不加本人 ID,开发者自己也无法在市场安装自测。 +- 当 `access_scope = 0`(不公开)时,平台会把 `developer_ids` 中的用户自动补写到 `skill_user_access`。 + +--- + +> **本技能开发状态:** v1.0.1 骨架已就位,业务实现细节见 `development/REQUIREMENTS.md`;具体 Python 模块由开发者后续补全。 diff --git a/TUTORIAL.md b/TUTORIAL.md new file mode 100644 index 0000000..b262d06 --- /dev/null +++ b/TUTORIAL.md @@ -0,0 +1,142 @@ +# 使用教程 + +本技能有两种**平行**的使用方式: + +- **数据管理**:在左侧「制度送审稿」表上点工具栏 / 行内按钮 +- **对话任务**:用自然语言让 Agent 完成同一能力 + +定时任务是否提供:**见下方「入口三」**(当前为占位,按需启用)。 + +--- + +## 本技能做什么 + +```text +【新制度送审稿】 → 【条款向量化 + 制度库全库比对】 → 【冲突 / 缺程序 / 重复发文标注】 → 【Word 侧栏批注 + 表状态更新】 +``` + +- **输入**:起草人在 OA 上传的新制度 Word 送审稿 + 校内现行全部制度(约 300+ 份) +- **输出**:Word 侧栏批注清单 + 送审稿表状态更新 + 可选离线审查报告 +- **说明**:本技能不替代法律 / 合规终审;冲突标注供参考,最终签发仍由校办文秘科与分管校领导负责 + +--- + +## 开始前 + +确认: + +1. 已安装并登录匠厂客户端 +2. 已在技能市场安装本技能(建议更新到最新版) +3. 校内现行制度库的访问权限已配置(`OA_API_BASE_URL` / `OA_API_TOKEN` 已登记到本技能 `.env`) +4. 【如需】上传送审稿前,确认 Word 文档已完成自校 +5. 【如需】首次使用前,先在「数据管理 → 制度库同步」点击一次「立即同步」载入最新制度索引 + +--- + +## 入口一:数据管理 + +适合:制度起草人、校办文秘科、喜欢点界面操作的用户。 + +### 左侧各表是干什么的 + +| 表名(中文) | 作用 | +|--------------|------| +| 制度送审稿 | 每一份等待审查 / 审查中 / 已通过的送审稿,状态行可见 | +| 冲突条款清单 | 审查过程中发现的所有冲突条款,含新旧制度链接 | +| 制度库索引 | 校内现行 300+ 份制度文件的索引(只读) | +| 审查任务日志 | 每一次审查的执行记录与耗时 | + +### 首次准备(若需要) + +1. 进入 **数据管理** → **制度库索引** +2. 点击表顶 **「立即同步」**(空表可点) +3. 成功后应看到:本校全部现行制度的标题、文号、发文日期、最近修订日期等元数据 + +### 主流程:送审一份新制度 + +1. 进入 **制度送审稿** +2. 点击表顶 **「上传送审稿」**,选择本地 Word 文件 +3. 上传成功后行自动进入「可送审」状态 +4. 选中该行 → 点击 **「审查送审稿」** +5. 等待 10~30 秒(向量化比对 300+ 份制度) +6. 完成后行状态变为「已通过」/「冲突中」/「驳回」,并写入冲突条款清单 + +### 行级 / 批量 + +| 你想做什么 | 操作 | +|------------|------| +| 重新审查某一份 | **制度送审稿** 行内 → **「重新审查」** | +| 批量重新审查 | 勾选多行 → **「批量重新审查」** | +| 导出审查报告 | **制度送审稿** 行内 → **「导出审查报告」** | +| 手动标记状态 | **制度送审稿** 行内 → **「标记为已通过」** / **「标记为驳回」** | + +--- + +## 入口二:对话任务 + +适合:临时提问、不想切换表、不熟界面操作的用户。 + +### 什么时候用对话 + +- 临时送审 1~2 份制度,但不想打开数据管理 +- 想用自然语言解释"为什么这份制度与某份旧制度冲突" +- 想知道"本月一共审了多少份、有多少冲突" + +### 示例话术 + +| 你想做什么 | 可以这样说 | +|------------|------------| +| 送审一份新制度 | 「我刚上传了《XX管理办法》,请帮我审一下」 | +| 重新比对 | 「请重新比对昨天那一份《XX 制度》」 | +| 查看本月统计 | 「本月一共审了多少份制度?有多少冲突?」 | +| 解释冲突 | 「为什么这份送审稿与《XX 制度》第 X 条冲突?」 | +| 导出报告 | 「把这份审查报告导出 PDF 发给我」 | + +### Agent 可能追问什么 + +- 缺参数时:会问"请告诉我送审稿的 ID 或文件名" +- 上传未完成时:会提示"送审稿尚未完成向量化,请稍候" +- 失败时:可改用数据管理点按钮重新触发 + +--- + +## 入口三:定时任务 + +### 本技能当前为占位(按需启用) + +本技能**当前未启用定时任务入口**。如未来启用,建议场景: + +- 制度库新增 / 变更后,自动扫描存量送审稿是否还合规 +- 每月最后一天自动生成《本月送审审查月报》 + +启用条件:OA 提供 Webhook / 制度库订阅接口,并经校办文秘科与合规岗确认自动化边界。 + +当前请使用 **数据管理** 或 **对话任务**。 + +--- + +## 主能力对照表 + +| 想做什么 | 数据管理 | 对话任务 | +|----------|----------|----------| +| 送审一份新制度 | **制度送审稿** → **「上传送审稿」** + **「审查送审稿」** | 「我刚上传了《XX 管理办法》,请帮我审一下」 | +| 重新审查 | 行内 → **「重新审查」** | 「请重新比对《XX 制度》」 | +| 导出审查报告 | 行内 → **「导出审查报告」** | 「把这份审查报告导出 PDF」 | +| 标记状态 | 行内 → **「标记为已通过 / 驳回」** | 「把这份送审稿标记为已通过」 | +| 查看本月统计 | 表顶 **「本月统计」** | 「本月一共审了多少份?」 | + +按钮名必须与 `assets/actions.json` 的 `label` 一致。 + +--- + +## 常见卡住怎么办 + +| 现象 | 你可以先试 | +|------|------------| +| 「上传送审稿」点不了 | 是否已配置 OA API;是否装错版本 | +| 审查很久没结果 | 看任务中心进度;送审稿过大(>5MB)可能耗时较久 | +| 冲突标注过少 | 制度库是否完成首次同步;送审稿是否含表格图片(OCR 漏检) | +| 冲突标注过多 | 检查阈值(`CONFLICT_THRESHOLD`)配置;旧制度版本可能过多 | +| 结果不对 | 缩小范围重试,或在数据管理核对冲突条款清单 | + +仍无法解决时,把「你用的入口 + 操作步骤 + 界面提示原文」发给支持人员。 diff --git a/acceptance-reports/README.md b/acceptance-reports/README.md new file mode 100644 index 0000000..f0b59fc --- /dev/null +++ b/acceptance-reports/README.md @@ -0,0 +1,7 @@ +# acceptance-reports + +本技能交活验收报告目录(占位骨架)。 + +> **使用方式:** 模板请查阅主仓 `skill-template-main/skill-template/development/CHECKLIST.md` §交活验收;正式发布前需按 `YYYYMMDD-HHMMSS-acceptance.md` 命名生成验收报告,便于技术人员按 FAIL 项整改。 +> +> 当前本目录无验收报告。 diff --git a/assets/README.md b/assets/README.md new file mode 100644 index 0000000..5d2e5df --- /dev/null +++ b/assets/README.md @@ -0,0 +1,18 @@ +# assets + +> 本技能 `assets/` 目录的元数据与 Action manifest,**派生自匠厂 skill-template 主仓**。 +> +> **使用方式:** 主仓 `skill-template-main/skill-template/assets/` 已沉淀 Action manifest 规范(schemaVersion / placements / executionProfile / bind.tables / interaction / hostEffects 等);本目录**仅放本技能特有的 Action 清单与示例**,公共规范**请回主仓查阅**。 + +## 本目录文件清单 + +- `README.md`:本文件 +- `actions.json`:本技能 Action 清单(v1.0.1 已就位) +- `html/example-report.html`:审查报告 HTML 模板(v1.0.1 已就位) +- `examples/`:CLI 成功输出形状示例、Action 形状参考(占位,由开发者按主仓 `assets/examples/` 复制) +- `schemas/skill-actions.schema.json`:Action JSON Schema(占位,由开发者从主仓复制) +- `naming/`:命名规范引用(占位) + +## 业务技能注意 + +若主路径在数据管理,准备 / 载入 / 导入类 Action 应挂 `toolbar` + `bind.tables`(用户看得见),**不要**只挂 `skill-detail` 却在教程里写成「技能详情点按钮」。 diff --git a/assets/actions.json b/assets/actions.json new file mode 100644 index 0000000..d11e973 --- /dev/null +++ b/assets/actions.json @@ -0,0 +1,122 @@ +{ + "schemaVersion": 1, + "skill": "detect-policy-conflict-gs", + "actions": [ + { + "id": "health", + "label": "运行检查", + "description": "检查技能运行环境、OA API 连通性、制度库索引完整性,不启动长任务。", + "placements": ["skill-detail", "agent"], + "executionProfile": "sync", + "entrypoint": { + "type": "cli", + "command": "health", + "args": [] + } + }, + { + "id": "version", + "label": "查看版本", + "description": "返回技能版本和机器标识。", + "placements": ["skill-detail"], + "executionProfile": "sync", + "entrypoint": { + "type": "cli", + "command": "version", + "args": [] + } + }, + { + "id": "config-path", + "label": "查看配置位置", + "description": "返回技能配置文件位置。", + "placements": ["skill-detail"], + "executionProfile": "sync", + "entrypoint": { + "type": "cli", + "command": "config-path", + "args": [] + } + }, + { + "id": "audit-policy-draft", + "label": "审查送审稿", + "description": "对一份新制度送审稿执行条款向量化 + 制度库比对 + 程序合规体检 + 重复发文检测,10~30 秒内返回结果。", + "placements": ["row", "agent", "skill-detail"], + "executionProfile": "sync", + "bind": { + "tables": ["制度送审稿"], + "selectionMode": "required", + "labelColumn": "送审稿标题" + }, + "entrypoint": { + "type": "cli", + "command": "audit-policy-draft", + "args": ["--draft-id", "{row.送审稿ID}"] + } + }, + { + "id": "recheck-conflict-clause", + "label": "重新比对冲突条款", + "description": "对某一条已经标记冲突的条款重新比对,常用于制度库更新后的复核。", + "placements": ["row", "agent"], + "executionProfile": "sync", + "bind": { + "tables": ["冲突条款清单"], + "selectionMode": "required", + "labelColumn": "新条款摘要" + }, + "entrypoint": { + "type": "cli", + "command": "recheck-conflict-clause", + "args": ["--clause-id", "{row.冲突条款ID}"] + } + }, + { + "id": "export-review-report", + "label": "导出审查报告", + "description": "将指定送审稿的审查结果导出为 PDF 报告,落到本技能 output/ 目录。", + "placements": ["row", "agent"], + "executionProfile": "sync", + "bind": { + "tables": ["制度送审稿"], + "selectionMode": "required", + "labelColumn": "送审稿标题" + }, + "entrypoint": { + "type": "cli", + "command": "export-review-report", + "args": ["--draft-id", "{row.送审稿ID}", "--format", "pdf"] + } + }, + { + "id": "mark-policy-status", + "label": "标记送审稿状态", + "description": "手动将送审稿标记为已通过 / 驳回(通常用于人工终审后回写状态)。", + "placements": ["row"], + "executionProfile": "sync", + "bind": { + "tables": ["制度送审稿"], + "selectionMode": "required", + "labelColumn": "送审稿标题" + }, + "entrypoint": { + "type": "cli", + "command": "mark-policy-status", + "args": ["--draft-id", "{row.送审稿ID}", "--target-status", "{form.target_status}"] + } + }, + { + "id": "rescan-pending-drafts", + "label": "定时扫描存量送审稿", + "description": "扫描所有"审查中 / 冲突中"状态的送审稿,因制度库新增 / 变更而重新比对。占位 Action,cron 启用后由定时调度。", + "placements": ["cron", "agent"], + "executionProfile": "async", + "entrypoint": { + "type": "cli", + "command": "rescan-pending-drafts", + "args": [] + } + } + ] +} diff --git a/assets/examples/README.md b/assets/examples/README.md new file mode 100644 index 0000000..335e51b --- /dev/null +++ b/assets/examples/README.md @@ -0,0 +1,18 @@ +# assets/examples + +本目录用于存放本技能 Action 形状参考示例(如 `render-html.action.example.json` / `lookup.action.example.json` 等)。 + +> **使用方式:** 模板参考请查阅主仓 `skill-template-main/skill-template/assets/examples/`,复制所需示例后按本技能业务调整(修改 `skill` slug / `id` / `label` / `description` / `bind.tables` / `entrypoint.command` / `entrypoint.args`)。 +> +> 主仓已沉淀的常用示例: +> - `render-html.action.example.json`:HTML 整页报告 +> - `lookup.action.example.json`:跨表 Lookup 下拉 +> - `visible-when-action.example.json`:条件显隐参数 +> - `path-root-file-action.example.json`:本地路径 Action +> - `selection-label-column.action.example.json`:选择摘要标签列 +> - `selection-mode-optional.action.example.json`:可选勾选驱动 +> - `replaces-*.action.example.json`:接管新增 / 编辑 / 删除 + +## 本技能暂未提供示例 + +按需从主仓复制并调整 slug / Action id。 diff --git a/assets/html/example-report.html b/assets/html/example-report.html new file mode 100644 index 0000000..70f6e83 --- /dev/null +++ b/assets/html/example-report.html @@ -0,0 +1,103 @@ + + + + + {{TITLE}} + + + +
+
+

{{TITLE}}

+
送审稿编号:{{DRAFT_ID}} · 送审人:{{DRAFTER}} · 送审时间:{{SUBMITTED_AT}}
+
审查完成时间:{{GENERATED_AT}}
+
+ +
+
条款总数
{{CLAUSE_TOTAL}}
+
🔴 冲突项
{{CONFLICT_COUNT}}
+
🟡 程序缺项
{{COMPLIANCE_GAP_COUNT}}
+
🟢 合规通过
{{PASS_COUNT}}
+
+ + + + + + + + + + + + + + {{BODY}} + +
编号冲突类型新条款原文旧制度文号旧条款原文建议处理
+ + +
+ + diff --git a/assets/naming/README.md b/assets/naming/README.md new file mode 100644 index 0000000..b854df0 --- /dev/null +++ b/assets/naming/README.md @@ -0,0 +1,5 @@ +# assets/naming + +本目录用于存放本技能命名规范的引用。 + +> **使用方式:** 主仓 `skill-template-main/skill-template/development/NAMING.md` 已沉淀完整规范;本目录为占位,无需额外文件。 diff --git a/assets/schemas/README.md b/assets/schemas/README.md new file mode 100644 index 0000000..770ad6b --- /dev/null +++ b/assets/schemas/README.md @@ -0,0 +1,5 @@ +# assets/schemas + +本目录存放本技能引用的 JSON Schema。 + +> **使用方式:** 模板请从主仓 `skill-template-main/skill-template/assets/schemas/skill-actions.schema.json` 复制到本目录;新技能严格按该 Schema 校验 `assets/actions.json`。 diff --git a/development/README.md b/development/README.md new file mode 100644 index 0000000..9bb5f0a --- /dev/null +++ b/development/README.md @@ -0,0 +1,14 @@ +# development + +> 本技能 `development/` 目录的开发规范与教程,**派生自匠厂 skill-template 主仓**。 +> +> **使用方式:** 主仓 `skill-template-main/skill-template/development/` 已沉淀完整的开发教程、需求模板、验收清单、日志规范、产品入口契约、共享仓目录等公共内容;本目录仅放本技能特有的说明文件,公共开发规范**请回主仓查阅**。 +> +> 主仓入口对应关系: +> - `REQUIREMENTS.md`(本目录)= 主仓 `REQUIREMENTS.md` 模板的本技能实例 +> - 主仓其他文件(`DEVELOPMENT.md` / `PRODUCT_SURFACES.md` / `CHECKLIST.md` / `RPA*.md` / `AI_RPA.md` / `LOGGING.md` / `CONFIG.md` / `NAMING.md` / `POLICY_MATRIX.md` / `TESTING.md` / `RUNTIME.md` / `SKILL_ACTION_RUNTIME.md` / `SHARED_REPOS.md` / `ACCOUNT_MANAGER.md` / `ADAPTER.md` / `TUTORIAL_SURFACES.md`)请查阅主仓原版 + +## 本目录文件清单 + +- `README.md`:本文件 +- `REQUIREMENTS.md`:本技能需求文档(v1.0.1 已就位) diff --git a/development/REQUIREMENTS.md b/development/REQUIREMENTS.md new file mode 100644 index 0000000..e4d3b13 --- /dev/null +++ b/development/REQUIREMENTS.md @@ -0,0 +1,224 @@ +# 制度文件冲突检测与合规审查 — 技能需求文档 + +> 派生自匠厂 skill-template 主仓 `development/REQUIREMENTS.md`,对应规格书第 4.3 节「🟠 校办/党办 Skill 001 —— 制度文件"冲突检测与合规审查"」。 + +--- + +## 0. 技能标识 + +- **拟定 slug(英文)**:`detect-policy-conflict-gs` +- **中文 name**:制度文件冲突检测与合规审查 +- **中文 description(一句话)**:起草人在 OA 上传新制度送审稿时,自动检测与校内现行制度库的条款冲突、程序合规性、重复发文风险,并在 Word 侧栏生成批注清单 +- **account-manager platform_key(如有)**:N/A(本技能不涉及 RPA) +- **命名形态**:标准型(动词-名词-部门缩写) +- **目标 OEM 市场 `brands`(可选)**:未写则发布后仅挂匠厂(`jiangchang`)。如需在华商等 OEM 客户端可见,填写 `jiangchang`、`huashang` +- **网页 RPA(如有)— 登录策略(三选一,须写明)**:**不适用**(本技能不涉及网页 RPA;OA 走官方 API,制度库走文件导入) + +## 0.1 宿主入口定位(必填) + +| 主能力(Action id / CLI) | 对话 | 数据管理 | 定时 | 教程章节 | 不挂理由(若不挂) | +|---------------------------|------|----------|------|----------|--------------------| +| `health` / `version` / `config-path` | 挂 | 不挂(skill-detail 已含) | 不挂 | 入口二 | 默认必备 | +| `audit-policy-draft` | 挂 | toolbar + row(送审稿表) | 不挂 | 入口一/入口二 | 默认 sync,单次触发 | +| `recheck-conflict-clause` | 挂 | row(冲突条款清单表) | 不挂 | 入口一 | 默认 sync | +| `export-review-report` | 挂 | row(送审稿表) | 不挂 | 入口一/入口二 | PDF 导出 | +| `mark-policy-status` | 不挂 | row(送审稿表) | 不挂 | 入口一 | 写状态,不需 Agent 触发 | +| `rescan-pending-drafts` | 挂 | 不挂 | 挂(占位) | 入口三 | 当前 cron 占位,按需启用 | + +### 0.1.1 用户市场文档(与入口表一致) + +- `README.md`(说明 Tab):只写能力 / 场景 / 边界;**禁止**分步操作与 Agent 话术 +- `TUTORIAL.md`(教程 Tab):覆盖 §0.1 中所有「挂」的入口;定时占位写入「不适用」声明 +- 入口三已写「当前为占位 / 按需启用」,与本表理由一致 + +## 0.2 AI + RPA 协作与授权边界 + +### Agent 设计 + +- 用户会怎样描述本任务:「我上传了一份《XX 管理办法》,请审一下」「为什么这份与《XX 制度》冲突?」「本月一共审了多少份?」 +- 支持的用户意图 → Action 映射: + - 送审一份新制度 → `audit-policy-draft` + - 重新比对某条冲突 → `recheck-conflict-clause` + - 导出审查报告 → `export-review-report` + - 标记送审稿状态 → `mark-policy-status` + - 定时扫描存量送审稿 → `rescan-pending-drafts` +- 每种意图必须提取的参数:`policy_draft_id`(必填)、`target_status`(仅 mark 时必填)、`format`(仅 export 时,默认 pdf) +- 缺少参数时必须追问:「请告诉我送审稿的 ID 或文件名」 +- 哪些动作必须先展示对象、数量和影响,再取得明确确认: + - `mark-policy-status` 状态变更(确认行 + 目标状态) + - `export-review-report` 仅提示落盘位置 +- Agent 最终如何解释成功、部分成功、失败、等待人工和停止: + - 成功:「已审查《XX 管理办法》,发现 X 条冲突 / Y 条程序缺项 / Z 条重复发文风险」 + - 部分成功:「条款比对完成,但冲突条款清单中 1 条 OCR 失败,建议人工复核」 + - 失败:「OA API 调用失败(错误码 XXX),已停止并保留送审稿原状态」 + - 等待人工:「发现疑似重复发文,需要你确认是否合并 / 废止旧文」 + +### 授权与平台边界 + +- 目标浏览器 / 桌面软件 / 手机 App:**N/A**(本技能不涉及 RPA) +- 账号、设备、数据和业务权限由谁授权:校办文秘科授权;制度库读取权限由校办统一开通 +- 是否有获得授权的官方 API:OA 提供官方 API(送审稿读写 + 批注回写);制度库由校办维护的 PDF/Word 文件索引提供 +- 目标平台规则、合同或客户约定中的自动化边界:OA API 调用须走用户授权 token;不得批量上传 / 下载制度文件 +- 明确禁止的实现路线:**所有破解 / 反编译 / 逆向 / 私有协议 / 抓包拼隐藏接口 / Hook 或注入 / 验证码破解 / 设备指纹伪造 / 自动换号 均禁止** +- 正常界面无法闭环时的上报与停止条件:OA API 不可用超过 30 分钟 → 停止并向校办文秘科上报,不擅自重试 + +### RPA 风控设计 + +- 执行端:**N/A**(本技能不涉及浏览器 / 桌面 / 手机 RPA) + +## 0.3 业务行生命周期 + +本技能对「制度送审稿」表中的每一份送审稿,遵守 `references/WORK_ITEM_STATUS.md` 角色约束: + +| 角色 | 本技能状态值 | 说明 | +|------|--------------|------| +| 可操作(operable) | 可送审 | 默认唯一可被 `audit-policy-draft` 捞起 | +| 进行中(in_progress) | 审查中 | 抢占后、结束前 | +| 成功类终态 | 已通过 | AI 审查无冲突;人工可二次确认 | +| 失败类终态 | 冲突中 / 驳回 | 默认不可再处理;失败原因字段:审查意见摘要 | +| 跳过类终态 | 已跳过 | 起草人撤回送审 | + +> 重做靠人工将"已通过 / 冲突中 / 驳回"改回"可送审",不靠 AI 自动覆盖。 + +--- + +## 1. 文档目标 + +本文档用于明确 `detect-policy-conflict-gs` 的研发范围、交付标准、依赖关系和验收要求,作为开发与测试的统一依据。 + +## 2. 业务背景 + +当前用户在「校内制度送审」场景中需要反复处理新起草或修订的制度送审稿,校办文秘科每月需审查十几份制度。 + +现有流程依赖人工翻阅 300+ 份现行制度,**存在以下问题**: + +- **效率低**:人工比对 1 份送审稿平均需要 2~3 小时 +- **容易遗漏**:跨部门 / 跨年限的制度冲突极难全数发现 +- **不可批量**:每月集中送审期,校办文秘科需加班突击 +- **不可追踪**:审查意见依赖口头 / 邮件,缺乏结构化记录 + +因此需要开发 `detect-policy-conflict-gs`,用于自动完成「条款级比对 + 程序合规体检 + 疑似重复发文检测」,输出「Word 侧栏批注 + 送审稿表状态更新 + 可选 PDF 审查报告」。 + +## 3. 开发目标 + +- 解析并校验送审稿 Word 文件(doc/docx) +- 提取条款文本并向量化 +- 与校内 300+ 份制度库做语义比对,标记冲突项 +- 检测程序合规性(制定依据 / 解释权归属 / 试行期) +- 检测近 3 年重复发文风险 +- 输出结构化结果(JSON / HTML 报告)+ Word 侧栏批注 +- 写入业务表(`制度送审稿` / `冲突条款清单` / `制度库索引` / `审查任务日志`) +- 支持失败可诊断(稳定错误码 + 中文 message) +- 完成 CLI 入口与 `health` / `version` / `init-db` 最小可运行验证 +- 完成正式环境发布与安装验证 + +## 4. 功能范围 + +### 必须实现 + +- 支持 `python scripts/main.py health` +- 支持 `python scripts/main.py version` +- 支持 `python scripts/main.py config-path` +- 支持 `python scripts/main.py init-db`(幂等建库) +- 支持 `python scripts/main.py audit-policy-draft --draft-id ` +- 支持 `python scripts/main.py recheck-conflict-clause --clause-id ` +- 支持 `python scripts/main.py export-review-report --draft-id --format pdf` +- 支持 `python scripts/main.py mark-policy-status --draft-id --target-status ` +- 支持 `python scripts/main.py rescan-pending-drafts`(async) +- 完成 §0.1 入口定位表,并按表落实已挂入口 + +### 可后续扩展 + +- 多语言制度(中英双语)支持 +- 自动起草修订建议(在「冲突中」状态时给出新条款修改文本) +- 与 OA 实时 Webhook 集成(送审稿上传即触发) +- cron 启用后的月报自动生成 + +## 5. 非功能要求 + +- 目录结构必须符合当前 `skill-template` 规范 +- 入口必须统一为 `scripts/main.py` +- 用户市场四 Tab 写在根 `README.md` / `TUTORIAL.md` / `DEMO.md` / `CHANGELOG.md` +- 输出格式应尽量机读友好;错误前缀统一为 `ERROR:` +- Windows 环境下需保证 UTF-8 输出兼容 +- 必须具备基本日志能力;敏感字段脱敏(如 OA API token 不写入日志) +- 条款向量化模型(BERT / BGE / M3E 等)由 `requirements.txt` 声明,运行时按需加载 +- 单份送审稿比对耗时 ≤ 30 秒(300+ 份制度库规模下) + +## 6. 输入输出要求 + +### 输入 + +- `policy_draft_id`:送审稿主键(必填,字符串) +- `target_status`:状态值(仅 `mark-policy-status` 时必填,枚举:已通过 / 驳回) +- `format`:导出格式(仅 `export-review-report` 时必填,枚举:pdf / html,默认 pdf) +- 依赖系统返回的结构化数据: + - OA API:送审稿 Word 文件 + 元数据 + - 制度库索引:300+ 份现行制度的标题、文号、PDF/Word 文件 +- 环境变量(`.env`): + - `OA_API_BASE_URL`:OA 系统 API 入口 + - `OA_API_TOKEN`:调用凭证 + - `CONFLICT_THRESHOLD`:冲突判定阈值(余弦相似度,默认 0.85) + +### 输出 + +- 成功结果:`audit-policy-draft` 返回结构化 JSON `{conflict_count, compliance_gap_count, repeat_publish_count, draft_status, review_summary}` +- 错误输出:`ERROR:` 稳定码 + 中文 message(如 `ERROR: OA_API_TIMEOUT 送审稿读取超时,请稍后重试`) +- 数据库记录:写入 `制度送审稿` / `冲突条款清单` / `审查任务日志` +- 可选:HTML 审查报告(`output/`) + +## 7. 依赖的兄弟技能或外部系统 + +### 兄弟技能依赖 + +- 无强制依赖;如需 PDF 阅读支持可参考 `match-contest-team-default`(同仓库示例技能) + +### 外部系统依赖 + +- **OA 系统**(送审稿读写 + 批注回写):必须 +- **制度库文件目录**(校办维护):必须 +- 浏览器(如适用):N/A + +### Python 包依赖(requirements.txt) + +- 条款向量化(任选其一,按许可证与本地化要求): + - `sentence-transformers>=2.2.0,<3` + - 或 `modelscope>=1.9.0`(本地 BGE 模型) +- Word 文档解析:`python-docx>=1.0.0,<2` +- PDF 解析:`pdfplumber>=0.10.0` +- HTTP 请求:`requests>=2.31.0,<3` +- `jiangchang-platform-kit`、`playwright` 等公共能力由宿主共享 runtime 提供,**不要**写入技能 requirements + +## 8. 不在本次范围内的内容 + +- 本次不实现 Word 侧栏实时批注(v1.0.1 仅生成离线批注清单 + HTML 报告;OA 在线编辑器实时批注需 OA 提供官方侧栏扩展能力) +- 本次不实现自动起草修订建议 +- 本次不集成 OA 实时 Webhook(待 OA 平台确认支持) +- 本次不做 cron 启用(占位 Action 已就位,启用条件见 §0.1) +- 本次不兼容旧模板历史结构 + +## 9. 验收标准 + +- 代码结构符合模板规范;`SKILL.md` slug 与 `constants.SKILL_SLUG` 一致 +- `health` / `version` / `config-path` / `init-db` 命令执行正常 +- `audit-policy-draft` 在含 300+ 份制度的样例库中完成一次完整比对,耗时 ≤ 30 秒 +- 业务表写入和查询符合 `references/SCHEMA.md`(含 `created_at` / `updated_at` Unix 秒级规范) +- `init_db()` 已写入 `_jiangchang_tables` / `_jiangchang_columns`;用户可见表/字段具备中文 `display_name` +- `SKILL.md` 的 `developer_ids` 已配置为开发者本人匠厂用户 ID +- 已人工核验授权与技术路线:无破解、逆向、私有协议、验证码绕过、Hook / 注入、自动换号或其他规避平台限制的实现 +- 安装后按 §0.1 入口定位表完成宿主多入口验收 +- 真实联调样例走 `tests/integration/`,默认套件不包含真实外联 + +## 10. 开发注意事项 + +- 只修改当前 skill 仓库,不要改动无关兄弟项目 +- OA API 不可用时停止并上报;不得擅自改走破解或绕过鉴权的路线 +- 制度库文件目录权限敏感,禁止在日志中打印完整文件路径与制度标题清单 +- 条款向量化的模型权重文件较大,应通过 `assets/` 或运行时下载,不入库 +- `cli` 只做参数解析;核心逻辑在 `service`;兄弟 skill 调用集中封装 + +## 11. 变更记录 + +| 日期 | 版本 | 变更人 | 变更内容 | +|------|------|--------|----------| +| 2026-09-14 | v1.0.1 | 匠厂 | 初版需求文档,骨架就位 | diff --git a/evals/README.md b/evals/README.md new file mode 100644 index 0000000..d302675 --- /dev/null +++ b/evals/README.md @@ -0,0 +1,6 @@ +# evals + +本技能评估样本目录(占位骨架)。 + +> 用于沉淀本技能核心能力的端到端评估样本(如送审稿样例 / 制度库样例 / 期望审查结果 JSON),便于回归与质量评估。 +> 模板参考主仓 `skill-template-main/skill-template/evals/`(如有)。 diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..7d13c71 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,15 @@ +# examples + +> 本技能不涉及浏览器 / 桌面 / 手机 RPA;以下 6 个目录为模板规范保留,**本技能不使用**。 +> +> **使用方式:** 模板参考请查阅主仓 `skill-template-main/skill-template/examples/`;按业务场景选择四档(真实 / 仿真 × API / RPA),桌面 / 手机为补足界面维度。 + +## 本目录文件清单 + +- `README.md`:本文件 +- `real_api/`:真实 API 案例占位(本技能 N/A) +- `simulator_api/`:仿真 API 案例占位(本技能 N/A) +- `real_browser_rpa/`:真实浏览器 RPA 案例占位(本技能 N/A) +- `simulator_browser_rpa/`:仿真浏览器 RPA 案例占位(本技能 N/A) +- `real_desktop_rpa/`:Windows 桌面 RPA 案例占位(本技能 N/A) +- `mobile_rpa/`:Android/iOS RPA 案例占位(本技能 N/A) diff --git a/examples/mobile_rpa/README.md b/examples/mobile_rpa/README.md new file mode 100644 index 0000000..773a64c --- /dev/null +++ b/examples/mobile_rpa/README.md @@ -0,0 +1,3 @@ +# mobile_rpa 占位 + +本技能不涉及手机 RPA。模板参考主仓 `skill-template-main/skill-template/examples/mobile_rpa/`。 diff --git a/examples/real_api/README.md b/examples/real_api/README.md new file mode 100644 index 0000000..6b904b7 --- /dev/null +++ b/examples/real_api/README.md @@ -0,0 +1,3 @@ +# real_api 占位 + +本技能不涉及真实 API 自动化。如未来需对接官方 API 之外的私有接口,参考主仓 `skill-template-main/skill-template/examples/real_api/`。 diff --git a/examples/real_browser_rpa/README.md b/examples/real_browser_rpa/README.md new file mode 100644 index 0000000..7f23b59 --- /dev/null +++ b/examples/real_browser_rpa/README.md @@ -0,0 +1,3 @@ +# real_browser_rpa 占位 + +本技能不涉及真实浏览器 RPA。模板参考主仓 `skill-template-main/skill-template/examples/real_browser_rpa/`。 diff --git a/examples/real_desktop_rpa/README.md b/examples/real_desktop_rpa/README.md new file mode 100644 index 0000000..1f736f5 --- /dev/null +++ b/examples/real_desktop_rpa/README.md @@ -0,0 +1,3 @@ +# real_desktop_rpa 占位 + +本技能不涉及 Windows 桌面 RPA。模板参考主仓 `skill-template-main/skill-template/examples/real_desktop_rpa/`。 diff --git a/examples/simulator_api/README.md b/examples/simulator_api/README.md new file mode 100644 index 0000000..81b0d42 --- /dev/null +++ b/examples/simulator_api/README.md @@ -0,0 +1,3 @@ +# simulator_api 占位 + +本技能不涉及仿真 API。如未来需要 sandbox 调试,参考主仓 `skill-template-main/skill-template/examples/simulator_api/`。 diff --git a/examples/simulator_browser_rpa/README.md b/examples/simulator_browser_rpa/README.md new file mode 100644 index 0000000..8f3890e --- /dev/null +++ b/examples/simulator_browser_rpa/README.md @@ -0,0 +1,3 @@ +# simulator_browser_rpa 占位 + +本技能不涉及仿真浏览器 RPA。模板参考主仓 `skill-template-main/skill-template/examples/simulator_browser_rpa/`。 diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..d4413ff --- /dev/null +++ b/pytest.ini @@ -0,0 +1,8 @@ +[pytest] +testpaths = tests +python_files = test_*.py *_test.py +python_classes = Test* +python_functions = test_* +norecursedirs = .git __pycache__ .pytest_cache integration desktop samples fixtures artifacts diagnostics +filterwarnings = + ignore::DeprecationWarning diff --git a/references/README.md b/references/README.md new file mode 100644 index 0000000..9cab48c --- /dev/null +++ b/references/README.md @@ -0,0 +1,18 @@ +# references + +> 本技能 `references/` 目录的 Agent 调用契约与规范,**派生自匠厂 skill-template 主仓**。 +> +> **使用方式:** 主仓 `skill-template-main/skill-template/references/` 已沉淀完整的 Agent 编排契约(ACTIONS / CLI / SCHEMA / POLICY / CELL_PRESENTATION / WORK_ITEM_STATUS 等);本目录**仅放本技能特有的引用规范**,公共契约**请回主仓查阅**。 +> +> 主仓入口对应关系: +> - `ACTIONS.md`(主仓):Skill Action 完整契约(placements / executionProfile / bind.tables / interaction / 可见文案 等) +> - `CLI.md`(主仓):CLI 子命令约定(health / version / config-path / init-db / 业务子命令) +> - `SCHEMA.md`(主仓):SQLite 表与字段规范(中文表名 / 标准时间字段 / `_jiangchang_tables` / `_jiangchang_columns`) +> - `POLICY.md`(主仓):可选 Data Policy 契约(默认 L0 零配置) +> - `CELL_PRESENTATION.md`(主仓):单元格呈现契约(红黄绿灯 / 标色) +> - `WORK_ITEM_STATUS.md`(主仓):业务行生命周期角色约束(本技能已采用,见 `development/REQUIREMENTS.md` §0.3) + +## 本目录文件清单 + +- `README.md`:本文件 +- 本技能特有的引用规范(如有)请按主仓 `references/` 同名文件格式补全 diff --git a/release.ps1 b/release.ps1 new file mode 100644 index 0000000..db77b94 --- /dev/null +++ b/release.ps1 @@ -0,0 +1,424 @@ +<# +.SYNOPSIS + Local git release for skill-template repo. + +.DESCRIPTION + Handles git commit / push / semver tag / push tag only. + Encryption, ZIP packaging, and marketplace sync are done by CI + (.github/workflows/release_skill.yaml → reusable-release-skill.yaml@main). + + POLICY-RELEASE-001: before tagging, requires SKILL.md version and + scripts/util/constants.py SKILL_VERSION to equal the next tag (without prefix). + release.ps1 does not auto-edit those fields. + + Requires: git, PowerShell 5+ + + After fetch, runs default tests against the current working tree (before auto-commit): + python tests/run_tests.py -v + Use -SkipTests only for emergency diagnostics. -DryRun still runs tests. +#> + +[CmdletBinding()] +param( + [string]$Prefix = "v", + [string]$Message, + [switch]$AutoCommit, + [switch]$RequireClean, + [string]$CommitMessage, + [switch]$DryRun, + [switch]$SkipTests +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +# Default tag message is 「正式发布」 from UTF-8 bytes (not a Chinese literal in +# this file). Windows PowerShell 5.1 parses UTF-8 scripts without BOM as the +# system ANSI code page, which would turn a source literal into 「姝e紡鍙戝竷」. +if (-not $PSBoundParameters.ContainsKey("Message") -or [string]::IsNullOrWhiteSpace($Message)) { + $Message = [System.Text.Encoding]::UTF8.GetString([byte[]](0xE6, 0xAD, 0xA3, 0xE5, 0xBC, 0x8F, 0xE5, 0x8F, 0x91, 0xE5, 0xB8, 0x83)) +} + +function Remove-GitNoise { + param([string[]]$Lines) + return @($Lines | Where-Object { + $_ -and ($_ -notmatch '^warning:\s+unable to access ') + }) +} + +function Convert-GitOutputLines { + param($Output) + return @( + @($Output) | ForEach-Object { + if ($_ -is [System.Management.Automation.ErrorRecord]) { $_.ToString() } + else { "$_" } + } + ) +} + +# Call git.exe directly. Never wrap with `cmd /c`: on Chinese Windows, cmd +# re-encodes the command line through the OEM code page. +# Also never pass Chinese via `git -m`: Windows PowerShell 5.1 encodes native +# argv using the console code page, so 「正式发布」 becomes 「姝e紡鍙戝竷」 +# in the annotated tag. Commit/tag messages go through a UTF-8 file + `-F`. +function Invoke-GitRaw { + param([Parameter(Mandatory = $true)][string[]]$GitArgs) + $prev = $ErrorActionPreference + $ErrorActionPreference = "Continue" + try { + $output = & git @GitArgs 2>&1 + $code = $LASTEXITCODE + } finally { + $ErrorActionPreference = $prev + } + return [pscustomobject]@{ + ExitCode = $code + Lines = @(Remove-GitNoise -Lines @(Convert-GitOutputLines -Output $output)) + } +} + +function Invoke-Git { + param([Parameter(Mandatory = $true)][string[]]$GitArgs) + Write-Host (">> git " + ($GitArgs -join " ")) -ForegroundColor DarkGray + $r = Invoke-GitRaw -GitArgs $GitArgs + if ($r.ExitCode -ne 0) { + throw "git command failed: git $($GitArgs -join ' ')" + } +} + +function Invoke-GitWithMessageFile { + param( + [Parameter(Mandatory = $true)][string[]]$GitArgsPrefix, + [Parameter(Mandatory = $true)][string]$Message + ) + $msgFile = Join-Path ([System.IO.Path]::GetTempPath()) ("jiangchang-git-msg-" + [guid]::NewGuid().ToString("N") + ".txt") + $utf8NoBom = New-Object System.Text.UTF8Encoding $false + [System.IO.File]::WriteAllText($msgFile, ($Message.TrimEnd() + "`n"), $utf8NoBom) + try { + Invoke-Git -GitArgs (@("-c", "i18n.commitEncoding=utf-8") + $GitArgsPrefix + @("-F", $msgFile)) + } finally { + Remove-Item -LiteralPath $msgFile -Force -ErrorAction SilentlyContinue + } +} + +function Get-GitOutput { + param([Parameter(Mandatory = $true)][string[]]$GitArgs) + $r = Invoke-GitRaw -GitArgs $GitArgs + if ($r.ExitCode -ne 0) { + throw "git command failed: git $($GitArgs -join ' ')" + } + return @($r.Lines) +} + +function Test-Repo { + $r = Invoke-GitRaw -GitArgs @("rev-parse", "--is-inside-work-tree") + if ($r.ExitCode -ne 0) { + return $false + } + return (($r.Lines | Select-Object -First 1) -eq "true") +} + +function Get-CurrentBranch { + $b = (Get-GitOutput -GitArgs @("branch", "--show-current") | Select-Object -First 1).Trim() + return $b +} + +function Get-StatusPorcelain { + $lines = @(Get-GitOutput -GitArgs @("status", "--porcelain")) + return $lines +} + +function Parse-SemVerTag { + param( + [string]$Tag, + [string]$TagPrefix + ) + $escaped = [regex]::Escape($TagPrefix) + $m = [regex]::Match($Tag, "^${escaped}(\d+)\.(\d+)\.(\d+)$") + if (-not $m.Success) { return $null } + + return [pscustomobject]@{ + Raw = $Tag + Major = [int]$m.Groups[1].Value + Minor = [int]$m.Groups[2].Value + Patch = [int]$m.Groups[3].Value + } +} + +function Get-NextTag { + param([string]$TagPrefix) + + $tags = Get-GitOutput -GitArgs @("tag", "--list") + $parsed = @() + + foreach ($t in $tags) { + $t = $t.Trim() + if (-not $t) { continue } + $obj = Parse-SemVerTag -Tag $t -TagPrefix $TagPrefix + if ($null -ne $obj) { $parsed += $obj } + } + + if ($parsed.Count -eq 0) { + return "${TagPrefix}1.0.1" + } + + $latest = $parsed | Sort-Object Major, Minor, Patch | Select-Object -Last 1 + return "$TagPrefix$($latest.Major).$($latest.Minor).$([int]$latest.Patch + 1)" +} + +function Read-SkillMdVersion { + param([Parameter(Mandatory = $true)][string]$SkillRoot) + + $path = Join-Path $SkillRoot "SKILL.md" + if (-not (Test-Path -LiteralPath $path)) { + return $null + } + $text = Get-Content -LiteralPath $path -Raw -Encoding UTF8 -ErrorAction SilentlyContinue + if ([string]::IsNullOrWhiteSpace($text)) { + return $null + } + $m = [regex]::Match($text, '(?m)^version:\s*["'']?([0-9]+\.[0-9]+\.[0-9]+)["'']?\s*$') + if (-not $m.Success) { + return $null + } + return $m.Groups[1].Value.Trim() +} + +function Read-SkillConstantsVersion { + param([Parameter(Mandatory = $true)][string]$SkillRoot) + + $path = Join-Path $SkillRoot "scripts\util\constants.py" + if (-not (Test-Path -LiteralPath $path)) { + return $null + } + $text = Get-Content -LiteralPath $path -Raw -Encoding UTF8 -ErrorAction SilentlyContinue + if ([string]::IsNullOrWhiteSpace($text)) { + return $null + } + $m = [regex]::Match($text, '(?m)^SKILL_VERSION\s*=\s*["'']([0-9]+\.[0-9]+\.[0-9]+)["'']') + if (-not $m.Success) { + return $null + } + return $m.Groups[1].Value.Trim() +} + +# POLICY-RELEASE-001: marketplace latest (git tag) must equal package manifest versions. +function Assert-SkillReleaseVersionAlignment { + param( + [Parameter(Mandatory = $true)][string]$SkillRoot, + [Parameter(Mandatory = $true)][string]$NextTag, + [Parameter(Mandatory = $true)][string]$TagPrefix + ) + + $skillMdPath = Join-Path $SkillRoot "SKILL.md" + if (-not (Test-Path -LiteralPath $skillMdPath)) { + return + } + + $expected = $NextTag + if ($TagPrefix -and $expected.StartsWith($TagPrefix)) { + $expected = $expected.Substring($TagPrefix.Length) + } + $expected = $expected.Trim() + if ($expected -notmatch '^\d+\.\d+\.\d+$') { + throw "Release check failed (POLICY-RELEASE-001): cannot derive semver from Next tag '$NextTag'." + } + + $mdVersion = Read-SkillMdVersion -SkillRoot $SkillRoot + $constVersion = Read-SkillConstantsVersion -SkillRoot $SkillRoot + + $problems = @() + if ([string]::IsNullOrWhiteSpace($mdVersion)) { + $problems += "SKILL.md missing top-level version: X.Y.Z" + } + elseif ($mdVersion -ne $expected) { + $problems += "SKILL.md version=$mdVersion (want $expected)" + } + if ([string]::IsNullOrWhiteSpace($constVersion)) { + $problems += "scripts/util/constants.py missing SKILL_VERSION = `"X.Y.Z`"" + } + elseif ($constVersion -ne $expected) { + $problems += "SKILL_VERSION=$constVersion (want $expected)" + } + + if ($problems.Count -gt 0) { + throw ( + "Release aborted (POLICY-RELEASE-001): Next tag=$NextTag requires manifest version $expected, but " + + ($problems -join "; ") + + ". Bump SKILL.md version and scripts/util/constants.py SKILL_VERSION to $expected (and CHANGELOG), then re-run release.ps1. " + + "release.ps1 does not auto-edit these fields." + ) + } + + Write-Host "Version alignment OK: tag=$NextTag == SKILL.md=$mdVersion == SKILL_VERSION=$constVersion" -ForegroundColor DarkGray +} + +function Assert-SkillReleasePackagingSources { + param([Parameter(Mandatory = $true)][string]$SkillRoot) + + $scriptsDir = Join-Path $SkillRoot "scripts" + $mainPy = Join-Path $scriptsDir "main.py" + if (-not (Test-Path -LiteralPath $mainPy)) { + return + } + + $text = Get-Content -LiteralPath $mainPy -Raw -Encoding UTF8 -ErrorAction SilentlyContinue + if ([string]::IsNullOrWhiteSpace($text)) { + return + } + + $need = @() + if ($text -match '(?m)^\s*from\s+cli\.') { $need += 'cli' } + if ($text -match '(?m)^\s*import\s+cli\b') { $need += 'cli' } + if ($text -match '(?m)^\s*from\s+service\.') { $need += 'service' } + if ($text -match '(?m)^\s*import\s+service\b') { $need += 'service' } + if ($text -match '(?m)^\s*from\s+db\.') { $need += 'db' } + if ($text -match '(?m)^\s*import\s+db\b') { $need += 'db' } + if ($text -match '(?m)^\s*from\s+util\.') { $need += 'util' } + if ($text -match '(?m)^\s*import\s+util\b') { $need += 'util' } + + foreach ($p in ($need | Select-Object -Unique)) { + $folder = Join-Path $scriptsDir $p + if (-not (Test-Path -LiteralPath $folder)) { + throw "Release check failed: scripts/main.py imports from '$p' but folder is missing: $folder" + } + } + + $pyFiles = @(Get-ChildItem -LiteralPath $scriptsDir -Filter *.py -Recurse -File -ErrorAction SilentlyContinue) + Write-Host "Packaging check: $($pyFiles.Count) Python file(s) under scripts/ (CI will obfuscate all recursively)." -ForegroundColor DarkGray +} + +function Invoke-DefaultTests { + param( + [Parameter(Mandatory = $true)][string]$SkillRoot, + [switch]$Skip + ) + + if ($Skip) { + Write-Host "WARNING: Skipping tests before release. This should only be used for emergency diagnostics." -ForegroundColor Yellow + return + } + + $runTests = Join-Path $SkillRoot "tests\run_tests.py" + if (-not (Test-Path -LiteralPath $runTests)) { + throw "Release check failed: tests/run_tests.py not found." + } + + Write-Host ">> python tests/run_tests.py -v" -ForegroundColor DarkGray + & python $runTests -v + if ($LASTEXITCODE -ne 0) { + throw "Release aborted: default tests failed (python tests/run_tests.py -v)." + } +} + +function Ensure-CleanOrAutoCommit { + param( + [switch]$DoAutoCommit, + [switch]$NeedClean, + [switch]$IsDryRun, + [string]$Msg + ) + + $status = @(Get-StatusPorcelain) + if ($status.Length -eq 0) { return } + + if ($NeedClean) { + Write-Host "Working tree is not clean and -RequireClean is enabled." -ForegroundColor Yellow + (Invoke-GitRaw -GitArgs @("status", "--short")).Lines | ForEach-Object { Write-Host $_ } + throw "Abort: dirty working tree." + } + + $commitMsg = $Msg + if ([string]::IsNullOrWhiteSpace($commitMsg)) { + $commitMsg = "chore: auto release commit ($(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'))" + } + + if (-not $DoAutoCommit) { + Write-Host "Detected uncommitted changes, auto-committing before release..." -ForegroundColor Yellow + } + + if ($IsDryRun) { + Write-Host "[DryRun] Would run: git add -A" -ForegroundColor Yellow + Write-Host "[DryRun] Would run: git commit -m `"$commitMsg`"" -ForegroundColor Yellow + return + } + + Invoke-Git -GitArgs @("add", "-A") + Invoke-GitWithMessageFile -GitArgsPrefix @("commit") -Message $commitMsg +} + +try { + Write-Host "=== Release Script Start ===" -ForegroundColor Cyan + + if (-not (Test-Repo)) { + throw "Current directory is not a git repository." + } + + $branch = Get-CurrentBranch + if ([string]::IsNullOrWhiteSpace($branch)) { + throw "Unable to determine current branch." + } + + if ($branch -notin @("main", "master")) { + throw "Current branch is '$branch'. Release is only allowed from main/master." + } + + if ($DryRun) { + Write-Host "[DryRun] Would run: git fetch --tags --prune origin" -ForegroundColor Yellow + } else { + Invoke-Git -GitArgs @("fetch", "--tags", "--prune", "origin") + } + + $skillRoot = (Get-GitOutput -GitArgs @("rev-parse", "--show-toplevel") | Select-Object -First 1).Trim() + if (Test-Path -LiteralPath (Join-Path $skillRoot "SKILL.md")) { + Assert-SkillReleasePackagingSources -SkillRoot $skillRoot + } + + $nextTag = Get-NextTag -TagPrefix $Prefix + Write-Host "Next tag: $nextTag" -ForegroundColor Green + Assert-SkillReleaseVersionAlignment -SkillRoot $skillRoot -NextTag $nextTag -TagPrefix $Prefix + + $existing = @(Get-GitOutput -GitArgs @("tag", "--list", $nextTag)) + if ($existing.Length -gt 0) { + throw "Tag already exists: $nextTag" + } + + Invoke-DefaultTests -SkillRoot $skillRoot -Skip:$SkipTests + + Ensure-CleanOrAutoCommit -DoAutoCommit:$AutoCommit -NeedClean:$RequireClean -IsDryRun:$DryRun -Msg $CommitMessage + + $upstream = Invoke-GitRaw -GitArgs @("rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}") + $hasUpstream = ($upstream.ExitCode -eq 0) + + if ($DryRun) { + if ($hasUpstream) { + Write-Host "[DryRun] Would run: git push" -ForegroundColor Yellow + } else { + Write-Host "[DryRun] Would run: git push -u origin $branch" -ForegroundColor Yellow + } + } else { + if ($hasUpstream) { + Invoke-Git -GitArgs @("push") + } else { + Invoke-Git -GitArgs @("push", "-u", "origin", $branch) + } + } + + if ($DryRun) { + Write-Host "[DryRun] Would run: git tag -a $nextTag -F ($Message)" -ForegroundColor Yellow + Write-Host "[DryRun] Would run: git push origin $nextTag" -ForegroundColor Yellow + Write-Host "=== DryRun Complete ===" -ForegroundColor Cyan + exit 0 + } + + Invoke-GitWithMessageFile -GitArgsPrefix @("tag", "-a", $nextTag) -Message $Message + Invoke-Git -GitArgs @("push", "origin", $nextTag) + + Write-Host "Release success: $nextTag" -ForegroundColor Green + Write-Host "=== Release Script Done ===" -ForegroundColor Cyan + exit 0 +} +catch { + Write-Host "Release failed: $($_.Exception.Message)" -ForegroundColor Red + exit 1 +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..70ec65b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,20 @@ +# 制度文件冲突检测与合规审查 - 技能特有依赖 +# jiangchang-platform-kit / playwright 等公共能力由宿主共享 runtime 提供,不要写入此文件 + +# Word 文档解析(送审稿 doc/docx) +python-docx>=1.0.0,<2 + +# PDF 解析(制度库 PDF) +pdfplumber>=0.10.0 + +# 条款向量化(任选其一;本地化部署建议用 BGE 中文模型) +# 方案 A:sentence-transformers(自动下载预训练模型) +sentence-transformers>=2.2.0,<3 +# 方案 B:modelscope + 本地 BGE(重,自托管场景) +# modelscope>=1.9.0 + +# HTTP 请求 +requests>=2.31.0,<3 + +# PDF 报告生成(如使用 weasyprint 替代方案) +# weasyprint>=60.0,<61 diff --git a/scripts/cli/__init__.py b/scripts/cli/__init__.py new file mode 100644 index 0000000..9dc01a4 --- /dev/null +++ b/scripts/cli/__init__.py @@ -0,0 +1 @@ +"""scripts.cli - CLI 参数解析层(占位)""" diff --git a/scripts/db/__init__.py b/scripts/db/__init__.py new file mode 100644 index 0000000..4bc7684 --- /dev/null +++ b/scripts/db/__init__.py @@ -0,0 +1,8 @@ +"""scripts.db - 数据库访问层(占位) + +按 references/SCHEMA.md 实现表与字段: +- 制度送审稿 +- 冲突条款清单 +- 制度库索引 +- 审查任务日志 +""" diff --git a/scripts/main.py b/scripts/main.py new file mode 100644 index 0000000..b64ac73 --- /dev/null +++ b/scripts/main.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +"""制度文件冲突检测与合规审查 - CLI 入口(占位骨架)""" + +import sys +from pathlib import Path + +# 占位:开发者后续接入 jiangchang_skill_core +# from jiangchang_skill_core import ... + +BASE_DIR = Path(__file__).resolve().parent.parent + + +def health(): + """运行检查(占位)。""" + print(f"detect-policy-conflict-gs health check (placeholder)") + print(f"base_dir: {BASE_DIR}") + return 0 + + +def version(): + """查看版本(占位)。""" + print("detect-policy-conflict-gs v1.0.1") + return 0 + + +def config_path(): + """查看配置位置(占位)。""" + print(f"{BASE_DIR / '.env'}") + return 0 + + +def init_db(): + """初始化数据库(占位)。""" + print("init-db: 后续由开发者按 references/SCHEMA.md 实现") + return 0 + + +def audit_policy_draft(draft_id: str): + """审查送审稿(占位)。""" + print(f"audit-policy-draft: {draft_id} (待开发者实现)") + return 0 + + +def recheck_conflict_clause(clause_id: str): + """重新比对冲突条款(占位)。""" + print(f"recheck-conflict-clause: {clause_id} (待开发者实现)") + return 0 + + +def export_review_report(draft_id: str, fmt: str = "pdf"): + """导出审查报告(占位)。""" + print(f"export-review-report: {draft_id} format={fmt} (待开发者实现)") + return 0 + + +def mark_policy_status(draft_id: str, target_status: str): + """标记送审稿状态(占位)。""" + print(f"mark-policy-status: {draft_id} -> {target_status} (待开发者实现)") + return 0 + + +def rescan_pending_drafts(): + """定时扫描存量送审稿(占位)。""" + print("rescan-pending-drafts (待开发者实现)") + return 0 + + +COMMANDS = { + "health": health, + "version": version, + "config-path": config_path, + "init-db": init_db, + "audit-policy-draft": audit_policy_draft, + "recheck-conflict-clause": recheck_conflict_clause, + "export-review-report": export_review_report, + "mark-policy-status": mark_policy_status, + "rescan-pending-drafts": rescan_pending_drafts, +} + + +def main(argv=None): + argv = argv or sys.argv[1:] + if not argv or argv[0] not in COMMANDS: + print("Usage: python scripts/main.py ") + print("Commands:", ", ".join(COMMANDS.keys())) + return 1 + return COMMANDS[argv[0]](*argv[1:]) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/service/__init__.py b/scripts/service/__init__.py new file mode 100644 index 0000000..deea28f --- /dev/null +++ b/scripts/service/__init__.py @@ -0,0 +1,9 @@ +"""scripts.service - 业务核心逻辑层(占位) + +按 development/REQUIREMENTS.md §3 开发目标实现: +- 条款解析与向量化 +- 制度库语义比对 +- 程序合规体检 +- 重复发文检测 +- 报告生成与批注回写 +""" diff --git a/scripts/util/__init__.py b/scripts/util/__init__.py new file mode 100644 index 0000000..29fb478 --- /dev/null +++ b/scripts/util/__init__.py @@ -0,0 +1 @@ +"""scripts.util - 工具函数层(占位)""" diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..ad39342 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,12 @@ +# tests + +本技能测试目录(占位骨架)。 + +> **使用方式:** 模板测试样例请查阅主仓 `skill-template-main/skill-template/tests/`;公共测试包括 `test_tutorial_surfaces.py` / `test_logging_contract.py` / `test_table_deprecation_migration.py.sample` 等。 +> +> 业务测试由开发者按 `development/TESTING.md`(主仓)补全,含: +> - `test_health.py`:运行检查单测 +> - `test_audit_policy_draft.py`:审查送审稿核心逻辑单测 +> - `test_recheck_conflict_clause.py`:冲突条款重新比对单测 +> - `test_export_review_report.py`:导出审查报告单测 +> - `integration/`:真实 OA 联调样例(默认不跑) diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 0000000..7186d99 --- /dev/null +++ b/tools/README.md @@ -0,0 +1,6 @@ +# tools + +本技能工具脚本目录(占位骨架)。 + +> 模板工具脚本请查阅主仓 `skill-template-main/skill-template/tools/`;常用工具包括 `scaffold_skill.ps1`(脚手架)等。 +> 本技能暂无额外工具;如需批量导入制度库等运营工具,由开发者按需添加。