Files
alert-contract-expiring-hr/scripts/util/runtime_paths.py
taojianmin 06c053d7d7 v1.1.0: 实现核心业务逻辑(扫描/任务书/派发/状态机)
新增(scripts/ 分层完整实现):
- scripts/util/{constants,date_util,runtime_paths,logging_setup}.py
- scripts/db/{connection,seed_data,repository}.py(SQLite + 5 张表 + 50 份样例合同)
- scripts/service/{scanner,task_generator,dispatcher,html_renderer}.py
- scripts/cli/app.py(argparse 子命令)
- scripts/templates/task.html.j2(Jinja2 渲染,无 jinja2 时降级到 str.replace)
- examples/{contracts_sample,performance_sample}.csv(本地样例数据)

修改:
- scripts/main.py:argparse + jiangchang_skill_core 降级
- SKILL.md:version 1.0.1 → 1.1.0
- CHANGELOG.md:加 v1.1.0 条目
- .env.example:加 DB_PATH / HTML_OUTPUT_DIR / JIANGCHANG_DATA_DIR

本地验证(9 个 CLI 命令全部 exit code = 0):
- health / version / config-path / init-db:基础 4 命令
- scan-expiring-contracts --thresholds 90,60,30:42 份可续聘 → 红 10 / 橙 10 / 黄 10,生成 30 任务
- render-html:写 output/<task_id>.html(4.9 KB)
- generate-renewal-task:单份合同任务书生成
- mark-contract-renewed:状态机更新 + 关闭 open alerts
- dispatch-task-notice:按单位/月份派发 payload(dry-run 模式)

业务规则(AI 续聘建议本地版,规则顺序判断):
1. 师德 < 60 → non_renew
2. 近 3 年考核有不合格(< 60)→ observe
3. 全部 >= 80 且逐年上升 → renew
4. 其他 → observe

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-14 14:17:43 +08:00

83 lines
2.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""运行时路径解析。
本地环境:
- 仓库根 = scripts/main.py 的父目录的父目录
- data/ 在仓库根下
- output/ 在仓库根下
- .env 在仓库根下
宿主环境(jiangchang_skill_core 提供)会覆写这些路径到
{JIANGCHANG_DATA_ROOT}/{JIANGCHANG_USER_ID}/{slug}/...
"""
from __future__ import annotations
import os
from pathlib import Path
from util.constants import SKILL_SLUG
# util/runtime_paths.py → scripts/util/ → scripts/ → 仓库根(再上两级)
_THIS_FILE = Path(__file__).resolve()
_SCRIPTS_DIR = _THIS_FILE.parent.parent # scripts/
_SKILL_ROOT = _SCRIPTS_DIR.parent # alert-contract-expiring-hr/
def get_skill_root() -> Path:
"""返回 skill 仓库根目录。"""
# 优先尊重环境变量(宿主设置过)
env_root = os.environ.get("JIANGCHANG_SKILL_ROOT")
if env_root:
return Path(env_root)
return _SKILL_ROOT
def get_data_dir() -> Path:
"""返回 SQLite DB 与种子数据目录。"""
env_dir = os.environ.get("JIANGCHANG_DATA_DIR")
if env_dir:
return Path(env_dir)
return get_skill_root() / "data"
def get_db_path() -> Path:
"""返回 SQLite DB 文件路径。"""
env_db = os.environ.get("DB_PATH")
if env_db:
return Path(env_db)
return get_data_dir() / f"{SKILL_SLUG}.db"
def get_output_dir() -> Path:
"""返回 HTML 报告输出目录。"""
env_out = os.environ.get("HTML_OUTPUT_DIR")
if env_out:
return Path(env_out)
return get_skill_root() / "output"
def get_env_path() -> Path:
"""返回 .env 路径(仓库根 / 当前工作目录)。"""
return get_skill_root() / ".env"
def get_dispatch_dir() -> Path:
"""返回派发 payload JSON 输出目录。"""
return get_data_dir() / "dispatch"
def get_examples_dir() -> Path:
"""返回样例数据目录。"""
return get_skill_root() / "examples"
def get_templates_dir() -> Path:
"""返回 Jinja2 模板目录。"""
return _SCRIPTS_DIR.parent / "scripts" / "templates"
def ensure_dirs() -> None:
"""确保所有需要的目录存在。"""
for d in (get_data_dir(), get_output_dir(), get_dispatch_dir()):
d.mkdir(parents=True, exist_ok=True)