v1.0.1: 制度文件冲突检测与合规审查 - 初版骨架

基于匠厂 skill-template 主仓 v1.0.108 派生的业务技能。

核心业务:
- 起草人在 OA 上传新制度送审稿时,自动比对校内现行制度库(约 300+ 份)
- 条款级冲突检测 + 程序合规性体检 + 疑似重复发文检测
- 在 Word 侧栏生成批注清单,一键跳转冲突原文

输出形态:
- 制度送审稿表状态更新(可送审 → 审查中 → 已通过 / 冲突中 / 驳回)
- 冲突条款清单 + HTML 审查报告 + 可选 PDF 导出

预期提效:制度出台后因"与 XX 文件冲突"而被要求暂停/修订的事件减少至零起。

业务行生命周期:可送审 → 审查中 → 已通过 / 冲突中 / 驳回 / 已跳过

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
2026-09-14 12:19:05 +08:00
commit cd71f49709
38 changed files with 1626 additions and 0 deletions

23
.env.example Normal file
View File

@@ -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

10
.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
__pycache__/
*.py[cod]
.env
*.env.local
.pytest_cache/
.coverage
htmlcov/
dist/
build/
*.egg-info/

5
.openclaw-skill-template Normal file
View File

@@ -0,0 +1,5 @@
# 此文件仅存在于 skill-template 源仓库。
# 用 tools/scaffold_skill 创建新技能时,脚本会从目标目录删除本文件。
# 若业务技能仓库中仍存在本文件,说明未正确 scaffold,tests 会失败。
template_slug: your-skill-slug
template_version: "1.0.32"

12
CHANGELOG.md Normal file
View File

@@ -0,0 +1,12 @@
# Changelog
本文件对应技能市场 **「更新日志」** Tab。
## 1.0.1
- 初版:基于匠厂 skill-template 主仓 v1.0.108 派生
- 实现核心业务:制度文件冲突检测与合规审查(送审稿向量化 + 校内 300+ 份制度库比对 + 程序合规体检 + 疑似重复发文检测 + Word 侧栏批注)
- 输出形态:制度送审稿表状态更新 + 冲突条款清单 + 可选 PDF 审查报告
- 预期提效:制度出台后因"与 XX 文件冲突"而被要求暂停/修订的事件减少至零起;校内制度体系的逻辑一致性显著增强
- 业务行生命周期:可送审 → 审查中 → 已通过 / 冲突中 / 驳回
- 占位说明:本版仅完成骨架与文档,业务实现细节(`scripts/` 下 Python 模块、向量化模型选型、制度库同步策略)由开发者后续按 `development/REQUIREMENTS.md` 补全

28
DEMO.md Normal file
View File

@@ -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 分钟三入口演示视频,覆盖上传送审稿 → 触发审查 → 查看批注 → 导出报告的全流程。

21
LICENSE Normal file
View File

@@ -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.

80
README.md Normal file
View File

@@ -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,按"入口一:数据管理"或"入口二:对话任务"任选一种跟做。
### 制度库里的旧文件会被改动吗?
> 不会。技能只读访问现行制度库;只对"送审稿"做写操作(添加批注、修改状态字段)。
### 已经审查过的送审稿能再审一次吗?
> 可以。已通过的送审稿如需复审(例如上位法修订),可在表上点"重新审查"。

20
SECURITY.md Normal file
View File

@@ -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/`,不要写进本文件。

132
SKILL.md Normal file
View File

@@ -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 模块由开发者后续补全。

142
TUTORIAL.md Normal file
View File

@@ -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`)配置;旧制度版本可能过多 |
| 结果不对 | 缩小范围重试,或在数据管理核对冲突条款清单 |
仍无法解决时,把「你用的入口 + 操作步骤 + 界面提示原文」发给支持人员。

View File

@@ -0,0 +1,7 @@
# acceptance-reports
本技能交活验收报告目录(占位骨架)。
> **使用方式:** 模板请查阅主仓 `skill-template-main/skill-template/development/CHECKLIST.md` §交活验收;正式发布前需按 `YYYYMMDD-HHMMSS-acceptance.md` 命名生成验收报告,便于技术人员按 FAIL 项整改。
>
> 当前本目录无验收报告。

18
assets/README.md Normal file
View File

@@ -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` 却在教程里写成「技能详情点按钮」。

122
assets/actions.json Normal file
View File

@@ -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": []
}
}
]
}

18
assets/examples/README.md Normal file
View File

@@ -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。

View File

@@ -0,0 +1,103 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>{{TITLE}}</title>
<style>
/* 数据管理 iframe 预览布局基线:流体铺满、禁横向滚动 */
html, body {
margin: 0;
padding: 16px;
font-family: -apple-system, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
color: #1f2329;
background: #fafbfc;
line-height: 1.6;
}
.report { max-width: 100%; }
.header {
padding: 16px 20px;
background: #fff;
border: 1px solid #e5e6eb;
border-radius: 8px;
margin-bottom: 16px;
}
.header h1 { margin: 0 0 8px; font-size: 20px; }
.header .meta { color: #646a73; font-size: 13px; }
.summary {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 12px;
margin-bottom: 16px;
}
.stat {
padding: 12px 16px;
background: #fff;
border: 1px solid #e5e6eb;
border-radius: 8px;
}
.stat .label { color: #8c959f; font-size: 12px; }
.stat .value { font-size: 22px; font-weight: 600; margin-top: 4px; }
.stat.danger .value { color: #c53030; }
.stat.warning .value { color: #d97706; }
.stat.success .value { color: #059669; }
table {
width: 100%;
border-collapse: collapse;
background: #fff;
border: 1px solid #e5e6eb;
border-radius: 8px;
overflow: hidden;
table-layout: fixed;
word-break: break-word;
}
th, td { padding: 10px 14px; text-align: left; border-bottom: 1px solid #f0f1f3; font-size: 14px; }
th { background: #f5f6f7; color: #4e5969; font-weight: 600; }
tr:last-child td { border-bottom: 0; }
.pill {
display: inline-block;
padding: 2px 8px;
border-radius: 10px;
font-size: 12px;
font-weight: 500;
}
.pill.red { background: #fef2f2; color: #c53030; }
.pill.yellow { background: #fffbeb; color: #d97706; }
.pill.green { background: #ecfdf5; color: #059669; }
.footer { margin-top: 16px; color: #8c959f; font-size: 12px; text-align: right; }
</style>
</head>
<body>
<div class="report">
<div class="header">
<h1>{{TITLE}}</h1>
<div class="meta">送审稿编号:{{DRAFT_ID}} · 送审人:{{DRAFTER}} · 送审时间:{{SUBMITTED_AT}}</div>
<div class="meta">审查完成时间:{{GENERATED_AT}}</div>
</div>
<div class="summary">
<div class="stat"><div class="label">条款总数</div><div class="value">{{CLAUSE_TOTAL}}</div></div>
<div class="stat danger"><div class="label">🔴 冲突项</div><div class="value">{{CONFLICT_COUNT}}</div></div>
<div class="stat warning"><div class="label">🟡 程序缺项</div><div class="value">{{COMPLIANCE_GAP_COUNT}}</div></div>
<div class="stat success"><div class="label">🟢 合规通过</div><div class="value">{{PASS_COUNT}}</div></div>
</div>
<table>
<thead>
<tr>
<th style="width: 8%">编号</th>
<th style="width: 12%">冲突类型</th>
<th style="width: 25%">新条款原文</th>
<th style="width: 12%">旧制度文号</th>
<th style="width: 25%">旧条款原文</th>
<th style="width: 18%">建议处理</th>
</tr>
</thead>
<tbody>
{{BODY}}
</tbody>
</table>
<div class="footer">本报告由「制度文件冲突检测与合规审查」技能自动生成 · 仅供合规参考,不替代法律终审</div>
</div>
</body>
</html>

5
assets/naming/README.md Normal file
View File

@@ -0,0 +1,5 @@
# assets/naming
本目录用于存放本技能命名规范的引用。
> **使用方式:** 主仓 `skill-template-main/skill-template/development/NAMING.md` 已沉淀完整规范;本目录为占位,无需额外文件。

5
assets/schemas/README.md Normal file
View File

@@ -0,0 +1,5 @@
# assets/schemas
本目录存放本技能引用的 JSON Schema。
> **使用方式:** 模板请从主仓 `skill-template-main/skill-template/assets/schemas/skill-actions.schema.json` 复制到本目录;新技能严格按该 Schema 校验 `assets/actions.json`。

14
development/README.md Normal file
View File

@@ -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 已就位)

224
development/REQUIREMENTS.md Normal file
View File

@@ -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 <id>`
- 支持 `python scripts/main.py recheck-conflict-clause --clause-id <id>`
- 支持 `python scripts/main.py export-review-report --draft-id <id> --format pdf`
- 支持 `python scripts/main.py mark-policy-status --draft-id <id> --target-status <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 | 匠厂 | 初版需求文档,骨架就位 |

6
evals/README.md Normal file
View File

@@ -0,0 +1,6 @@
# evals
本技能评估样本目录(占位骨架)。
> 用于沉淀本技能核心能力的端到端评估样本(如送审稿样例 / 制度库样例 / 期望审查结果 JSON),便于回归与质量评估。
> 模板参考主仓 `skill-template-main/skill-template/evals/`(如有)。

15
examples/README.md Normal file
View File

@@ -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)

View File

@@ -0,0 +1,3 @@
# mobile_rpa 占位
本技能不涉及手机 RPA。模板参考主仓 `skill-template-main/skill-template/examples/mobile_rpa/`。

View File

@@ -0,0 +1,3 @@
# real_api 占位
本技能不涉及真实 API 自动化。如未来需对接官方 API 之外的私有接口,参考主仓 `skill-template-main/skill-template/examples/real_api/`。

View File

@@ -0,0 +1,3 @@
# real_browser_rpa 占位
本技能不涉及真实浏览器 RPA。模板参考主仓 `skill-template-main/skill-template/examples/real_browser_rpa/`。

View File

@@ -0,0 +1,3 @@
# real_desktop_rpa 占位
本技能不涉及 Windows 桌面 RPA。模板参考主仓 `skill-template-main/skill-template/examples/real_desktop_rpa/`。

View File

@@ -0,0 +1,3 @@
# simulator_api 占位
本技能不涉及仿真 API。如未来需要 sandbox 调试,参考主仓 `skill-template-main/skill-template/examples/simulator_api/`。

View File

@@ -0,0 +1,3 @@
# simulator_browser_rpa 占位
本技能不涉及仿真浏览器 RPA。模板参考主仓 `skill-template-main/skill-template/examples/simulator_browser_rpa/`。

8
pytest.ini Normal file
View File

@@ -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

18
references/README.md Normal file
View File

@@ -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/` 同名文件格式补全

424
release.ps1 Normal file
View File

@@ -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 <utf8-msg-file> ($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
}

20
requirements.txt Normal file
View File

@@ -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

1
scripts/cli/__init__.py Normal file
View File

@@ -0,0 +1 @@
"""scripts.cli - CLI 参数解析层(占位)"""

8
scripts/db/__init__.py Normal file
View File

@@ -0,0 +1,8 @@
"""scripts.db - 数据库访问层(占位)
按 references/SCHEMA.md 实现表与字段:
- 制度送审稿
- 冲突条款清单
- 制度库索引
- 审查任务日志
"""

91
scripts/main.py Normal file
View File

@@ -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 <command>")
print("Commands:", ", ".join(COMMANDS.keys()))
return 1
return COMMANDS[argv[0]](*argv[1:])
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,9 @@
"""scripts.service - 业务核心逻辑层(占位)
按 development/REQUIREMENTS.md §3 开发目标实现:
- 条款解析与向量化
- 制度库语义比对
- 程序合规体检
- 重复发文检测
- 报告生成与批注回写
"""

1
scripts/util/__init__.py Normal file
View File

@@ -0,0 +1 @@
"""scripts.util - 工具函数层(占位)"""

12
tests/README.md Normal file
View File

@@ -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 联调样例(默认不跑)

6
tools/README.md Normal file
View File

@@ -0,0 +1,6 @@
# tools
本技能工具脚本目录(占位骨架)。
> 模板工具脚本请查阅主仓 `skill-template-main/skill-template/tools/`;常用工具包括 `scaffold_skill.ps1`(脚手架)等。
> 本技能暂无额外工具;如需批量导入制度库等运营工具,由开发者按需添加。