Files
sap-cli-skill/docs/assets/architecture.drawio
T
吴让宇 c5905a5b1e refactor: 本仓升为唯一源(原 sap-cli 源码仓归档)
方向反转:此前 SKILL.md 是「模板渲染产物」、sap-cli 是源;现 sap-cli 归档,
sap-cli-skill 承接开发与分发,SKILL.md 回归手工维护的正本。

迁移(来自 sap-cli,共 104 文件):
- tests/           692 例测试(15 个文件的内联 sys.path 改指 assets/)
- openspec/        SDD 规格与归档变更(42 文件)
- docs/            开发文档与 ADT 原理(含 dev/CLAUDE.md、AGENTS.md)
- .claude/         rules 副本 + settings.json(供 Claude Code)
- .github/ .hermes/ .pre-commit-config.yaml .editorconfig CLAUDE.md
- scripts/ 保持仅 setup.py(pack_skill.py 已随旧仓归档,不迁)

修复(迁移暴露的真实缺陷):
- assets/pyproject.toml 的 build-backend 写作 `setuptools.backends._legacy:_Backend`,
  该模块在 setuptools 中不存在 → `pip install -e` 从来装不上。改为 build_meta。
  实测:临时 venv 安装成功,sap-cli --help 正常列出 31 个命令
- pyproject readme 指向不存在的 assets/README.md(editable 安装会失败)→ 改内联文本
- pyproject urls 改指 sap-cli-skill

机制调整:
- .github/workflows/ci.yml 适配 assets/ 布局;顶部注明该工作流仅 GitHub 执行,
  本仓在 Gitee 不会自动跑
- pre-commit 增本地测试门禁(Gitee 上真正生效的那道)
- .gitignore 合并旧仓完整规则(保留 log/ 下 md 知识库入库,只忽略运行日志)
- 大文件上限 100KB→1MB(架构图 512KB)

守卫测试 tests/unit/test_repo_guards.py(10 → 18 例):
- SKILL.md 须记录 parser 全部 CLI 命令 / 铁律 1-5 须为真实小节标题 / 示例不得违反铁律 5
- references/ 规则齐备;.claude/rules 与 references 必须一致(实测抓到一次真实漂移)
- VERSION == sapcli.__version__ == README 版本
- 仓内不得再出现 pack_skill.py / skill-src(防废弃流程回潮)

698 tests OK;editable 安装与 CLI 入口经临时 venv 实测通过。
docs/RELEASING.md 重写为单源开发流程。
2026-09-11 00:40:15 +08:00

116 lines
8.1 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<mxfile host="drawio" version="26.0.0">
<diagram name="Architecture" id="arch1">
<mxGraphModel dx="1200" dy="900" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="800" math="0" shadow="1">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<!-- ============================================ -->
<!-- Layer 1: User Terminal -->
<!-- ============================================ -->
<mxCell id="2" value="main.py&#xa;CLI 入口" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DAEAF6;strokeColor=#4A90D9;strokeWidth=2;fontStyle=1;fontSize=14;shadow=1;arcSize=12;" vertex="1" parent="1">
<mxGeometry x="390" y="30" width="280" height="70" as="geometry" />
</mxCell>
<!-- ============================================ -->
<!-- Layer 2: sapadt/ Core Package Container -->
<!-- ============================================ -->
<mxCell id="3" value="sapadt/ 核心包" style="swimlane;startSize=35;fillColor=#E8F5E9;strokeColor=#4CAF50;strokeWidth=2;rounded=1;shadow=1;fontStyle=1;fontSize=14;arcSize=8;swimlaneLine=1;" vertex="1" parent="1">
<mxGeometry x="230" y="170" width="600" height="310" as="geometry" />
</mxCell>
<!-- Top row: utility modules -->
<mxCell id="4" value="config.py&#xa;配置加载" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#C8E6C9;strokeColor=#66BB6A;fontSize=12;arcSize=15;" vertex="1" parent="3">
<mxGeometry x="15" y="50" width="180" height="70" as="geometry" />
</mxCell>
<mxCell id="5" value="types.py&#xa;对象类型定义" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#C8E6C9;strokeColor=#66BB6A;fontSize=12;arcSize=15;" vertex="1" parent="3">
<mxGeometry x="210" y="50" width="180" height="70" as="geometry" />
</mxCell>
<mxCell id="6" value="exceptions.py&#xa;自定义异常" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#C8E6C9;strokeColor=#66BB6A;fontSize=12;arcSize=15;" vertex="1" parent="3">
<mxGeometry x="405" y="50" width="180" height="70" as="geometry" />
</mxCell>
<!-- Bottom row: core modules (emphasized) -->
<mxCell id="7" value="client.py (ADTClient)&#xa;REST API 通信层" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#A5D6A7;strokeColor=#43A047;strokeWidth=2;fontSize=13;fontStyle=1;arcSize=12;" vertex="1" parent="3">
<mxGeometry x="25" y="170" width="260" height="90" as="geometry" />
</mxCell>
<mxCell id="8" value="commands.py&#xa;download · sync · info ·&#xa;create · delete" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#A5D6A7;strokeColor=#43A047;strokeWidth=2;fontSize=13;fontStyle=1;arcSize=12;" vertex="1" parent="3">
<mxGeometry x="315" y="170" width="260" height="90" as="geometry" />
</mxCell>
<!-- ============================================ -->
<!-- Layer 3: SAP NetWeaver System -->
<!-- ============================================ -->
<mxCell id="9" value="SAP NetWeaver — ADT REST API 端点" style="swimlane;startSize=35;fillColor=#FFF3E0;strokeColor=#FF9800;strokeWidth=2;rounded=1;shadow=1;fontStyle=1;fontSize=14;arcSize=8;swimlaneLine=1;" vertex="1" parent="1">
<mxGeometry x="230" y="560" width="600" height="160" as="geometry" />
</mxCell>
<mxCell id="10" value="Programs&#xa;报表/程序" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFE0B2;strokeColor=#FB8C00;fontSize=11;arcSize=15;" vertex="1" parent="9">
<mxGeometry x="10" y="50" width="135" height="65" as="geometry" />
</mxCell>
<mxCell id="11" value="OO Objects&#xa;类/接口" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFE0B2;strokeColor=#FB8C00;fontSize=11;arcSize=15;" vertex="1" parent="9">
<mxGeometry x="160" y="50" width="135" height="65" as="geometry" />
</mxCell>
<mxCell id="12" value="DDIC&#xa;域/元素/表" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFE0B2;strokeColor=#FB8C00;fontSize=11;arcSize=15;" vertex="1" parent="9">
<mxGeometry x="310" y="50" width="135" height="65" as="geometry" />
</mxCell>
<mxCell id="13" value="CTS&#xa;传输请求" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFE0B2;strokeColor=#FB8C00;fontSize=11;arcSize=15;" vertex="1" parent="9">
<mxGeometry x="460" y="50" width="135" height="65" as="geometry" />
</mxCell>
<!-- ============================================ -->
<!-- External files on the left -->
<!-- ============================================ -->
<mxCell id="14" value="config.ini&#xa;连接配置" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ECEFF1;strokeColor=#9E9E9E;dashed=1;strokeWidth=1;fontSize=11;shadow=1;arcSize=10;" vertex="1" parent="1">
<mxGeometry x="20" y="210" width="155" height="55" as="geometry" />
</mxCell>
<mxCell id="15" value=".abap 文件&#xa;本地源代码" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ECEFF1;strokeColor=#9E9E9E;dashed=1;strokeWidth=1;fontSize=11;shadow=1;arcSize=10;" vertex="1" parent="1">
<mxGeometry x="20" y="330" width="155" height="55" as="geometry" />
</mxCell>
<mxCell id="16" value="log/&#xa;运行日志" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ECEFF1;strokeColor=#9E9E9E;dashed=1;strokeWidth=1;fontSize=11;shadow=1;arcSize=10;" vertex="1" parent="1">
<mxGeometry x="20" y="430" width="155" height="55" as="geometry" />
</mxCell>
<!-- ============================================ -->
<!-- Edges -->
<!-- ============================================ -->
<!-- Edge 1: main.py to sapadt container (vertical) -->
<mxCell id="20" value="argparse 参数解析" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;strokeColor=#4A90D9;fontSize=11;fontStyle=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="2" target="3">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<!-- Edge 2: client.py to SAP container (vertical, through container boundary) -->
<mxCell id="21" value="HTTP/REST (Basic Auth + CSRF Token)" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;strokeColor=#FF9800;fontSize=11;fontStyle=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="7" target="9">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<!-- Edge 3: config.ini to sapadt container (horizontal) -->
<mxCell id="22" value="读取配置" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;strokeWidth=1;strokeColor=#9E9E9E;fontSize=10;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.18;entryDx=0;entryDy=0;" edge="1" parent="1" source="14" target="3">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<!-- Edge 4: .abap files to sapadt container (horizontal) -->
<mxCell id="23" value="读写源码" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;strokeWidth=1;strokeColor=#9E9E9E;fontSize=10;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="15" target="3">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<!-- Edge 5: log/ to sapadt container (horizontal) -->
<mxCell id="24" value="写入日志" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;strokeWidth=1;strokeColor=#9E9E9E;fontSize=10;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.82;entryDx=0;entryDy=0;" edge="1" parent="1" source="16" target="3">
<mxGeometry relative="1" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>