harness-gateway 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- harness_gateway-0.7.0/.codebuddy/commands/ship.md +47 -0
- harness_gateway-0.7.0/.codebuddy/rules/python-code-quality.mdc +113 -0
- harness_gateway-0.7.0/.codebuddy/skills/pypi-publish/SKILL.md +307 -0
- harness_gateway-0.7.0/.env.example +55 -0
- harness_gateway-0.7.0/.github/pull_request_template.md +23 -0
- harness_gateway-0.7.0/.github/workflows/ci.yml +38 -0
- harness_gateway-0.7.0/.github/workflows/codeql.yml +30 -0
- harness_gateway-0.7.0/.github/workflows/release.yml +101 -0
- harness_gateway-0.7.0/.gitignore +42 -0
- harness_gateway-0.7.0/.pre-commit-config.yaml +7 -0
- harness_gateway-0.7.0/AGENTS.md +596 -0
- harness_gateway-0.7.0/CHANGELOG.md +36 -0
- harness_gateway-0.7.0/CONTRIBUTING.md +81 -0
- harness_gateway-0.7.0/LICENSE +21 -0
- harness_gateway-0.7.0/Makefile +168 -0
- harness_gateway-0.7.0/PKG-INFO +491 -0
- harness_gateway-0.7.0/README.md +434 -0
- harness_gateway-0.7.0/README_CN.md +443 -0
- harness_gateway-0.7.0/SECURITY.md +23 -0
- harness_gateway-0.7.0/assets/images/banner.jpeg +0 -0
- harness_gateway-0.7.0/docs/superpowers/specs/2026-05-26-engineering-enhancement-design.md +345 -0
- harness_gateway-0.7.0/docs/superpowers/specs/2026-05-27-harness-agent-v2-design.md +97 -0
- harness_gateway-0.7.0/examples/advanced/feishu_advanced.py +61 -0
- harness_gateway-0.7.0/examples/advanced/push_scheduler.py +65 -0
- harness_gateway-0.7.0/examples/advanced/qq_advanced.py +76 -0
- harness_gateway-0.7.0/examples/all_channels.py +103 -0
- harness_gateway-0.7.0/examples/backends/__init__.py +1 -0
- harness_gateway-0.7.0/examples/backends/harness_agent.py +631 -0
- harness_gateway-0.7.0/examples/feishu_bot.py +59 -0
- harness_gateway-0.7.0/examples/mqtt_bot.py +77 -0
- harness_gateway-0.7.0/examples/qq_bot.py +59 -0
- harness_gateway-0.7.0/examples/telegram_bot.py +41 -0
- harness_gateway-0.7.0/examples/wecom_bot.py +60 -0
- harness_gateway-0.7.0/examples/weixin_bot.py +67 -0
- harness_gateway-0.7.0/examples/xiaoyi_bot.py +41 -0
- harness_gateway-0.7.0/pyproject.toml +147 -0
- harness_gateway-0.7.0/src/harness_gateway/__init__.py +65 -0
- harness_gateway-0.7.0/src/harness_gateway/channel.py +960 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/__init__.py +103 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/dingtalk.py +727 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/feishu.py +842 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/mqtt.py +283 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/qq.py +1195 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/telegram/__init__.py +5 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/telegram/channel.py +317 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/telegram/format_html.py +75 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/wecom.py +532 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/weixin/__init__.py +26 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/weixin/channel.py +416 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/weixin/login_qr.py +243 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/xiaoyi/__init__.py +5 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/xiaoyi/auth.py +26 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/xiaoyi/channel.py +720 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/xiaoyi/constants.py +12 -0
- harness_gateway-0.7.0/src/harness_gateway/channels/yuanbao.py +243 -0
- harness_gateway-0.7.0/src/harness_gateway/constraints.py +283 -0
- harness_gateway-0.7.0/src/harness_gateway/manager.py +831 -0
- harness_gateway-0.7.0/src/harness_gateway/media.py +75 -0
- harness_gateway-0.7.0/src/harness_gateway/models.py +309 -0
- harness_gateway-0.7.0/src/harness_gateway/py.typed +0 -0
- harness_gateway-0.7.0/src/harness_gateway/utils.py +158 -0
- harness_gateway-0.7.0/tests/__init__.py +0 -0
- harness_gateway-0.7.0/tests/channels/__init__.py +0 -0
- harness_gateway-0.7.0/tests/channels/test_dingtalk.py +130 -0
- harness_gateway-0.7.0/tests/channels/test_feishu.py +441 -0
- harness_gateway-0.7.0/tests/channels/test_mqtt.py +33 -0
- harness_gateway-0.7.0/tests/channels/test_qq.py +916 -0
- harness_gateway-0.7.0/tests/channels/test_send_local_media.py +270 -0
- harness_gateway-0.7.0/tests/channels/test_telegram.py +41 -0
- harness_gateway-0.7.0/tests/channels/test_typing_indicator.py +279 -0
- harness_gateway-0.7.0/tests/channels/test_wecom.py +351 -0
- harness_gateway-0.7.0/tests/channels/test_weixin.py +266 -0
- harness_gateway-0.7.0/tests/channels/test_xiaoyi.py +44 -0
- harness_gateway-0.7.0/tests/conftest.py +18 -0
- harness_gateway-0.7.0/tests/test_channel.py +701 -0
- harness_gateway-0.7.0/tests/test_constraints.py +461 -0
- harness_gateway-0.7.0/tests/test_harness_agent_backend.py +758 -0
- harness_gateway-0.7.0/tests/test_manager.py +485 -0
- harness_gateway-0.7.0/tests/test_media.py +59 -0
- harness_gateway-0.7.0/tests/test_media_integration.py +153 -0
- harness_gateway-0.7.0/tests/test_models.py +145 -0
- harness_gateway-0.7.0/tests/test_utils.py +191 -0
- harness_gateway-0.7.0/uv.lock +3570 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
Analyze the current git changes, run code quality checks, create a well-structured commit, and push to the remote. Follow these steps precisely:
|
|
2
|
+
|
|
3
|
+
## Step 1: Analyze Changes
|
|
4
|
+
|
|
5
|
+
Run `git status` and `git diff --stat` to understand the scope of changes. If there are unstaged changes, stage them with `git add -A`.
|
|
6
|
+
|
|
7
|
+
If there are no changes to commit, inform me and stop.
|
|
8
|
+
|
|
9
|
+
## Step 2: Code Quality Checks (Python only)
|
|
10
|
+
|
|
11
|
+
If any staged changes include `.py` files, run the following checks **before committing**:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
ruff check . --fix
|
|
15
|
+
ruff format .
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- If `ruff check --fix` auto-fixes issues, re-stage the affected files with `git add -A`.
|
|
19
|
+
- If `ruff check` still reports errors after `--fix` (i.e., errors that require manual intervention), **stop and report the errors**. Do not proceed with the commit until all errors are resolved.
|
|
20
|
+
- If there are no `.py` files in the staged changes, skip this step.
|
|
21
|
+
|
|
22
|
+
## Step 3: Generate Commit Message
|
|
23
|
+
|
|
24
|
+
Run `git diff --cached` to inspect the staged changes in detail.
|
|
25
|
+
|
|
26
|
+
Write a **Conventional Commits** message following this format:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
<type>(<scope>): <concise summary>
|
|
30
|
+
|
|
31
|
+
<optional body — bullet points explaining key changes>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Rules for the commit message:
|
|
35
|
+
- **type**: one of `feat`, `fix`, `refactor`, `chore`, `docs`, `style`, `perf`, `test`, `build`, `ci`
|
|
36
|
+
- **scope**: the primary module or area affected (e.g., `agent`, `dashboard`, `memory`, `config`)
|
|
37
|
+
- **summary**: imperative mood, lowercase, no period, ≤ 72 characters
|
|
38
|
+
- **body**: include only when there are multiple logical changes; use bullet points
|
|
39
|
+
- The commit message (including body) must be in **English**
|
|
40
|
+
|
|
41
|
+
## Step 4: Commit and Push
|
|
42
|
+
|
|
43
|
+
1. Create the commit with the generated message.
|
|
44
|
+
2. Push to the remote tracking branch (usually `origin/<current-branch>`).
|
|
45
|
+
3. Show me the final `git log --oneline -1` and confirm success.
|
|
46
|
+
|
|
47
|
+
$ARGUMENTS
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
description:
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
enabled: true
|
|
5
|
+
updatedAt: 2026-03-17T06:54:46.604Z
|
|
6
|
+
provider:
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Python Code Quality Standards — LightClaw
|
|
10
|
+
|
|
11
|
+
## 1. Pre-commit: ruff check & ruff format
|
|
12
|
+
|
|
13
|
+
Every Python change **must** pass the following before commit:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
ruff check . --fix # lint + auto-fix
|
|
17
|
+
ruff format . # deterministic formatting
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- If `ruff check` reports errors that `--fix` cannot resolve, fix them **manually** before proceeding.
|
|
21
|
+
- Never suppress a warning with `# noqa` unless there is a clear, documented reason (e.g., an import purely for availability detection).
|
|
22
|
+
- When generating or editing Python code, ensure the result is **ruff-clean** — run `ruff check` mentally against your output.
|
|
23
|
+
|
|
24
|
+
## 2. Modern Type Annotations (PEP 585 / PEP 604)
|
|
25
|
+
|
|
26
|
+
### Banned legacy aliases
|
|
27
|
+
|
|
28
|
+
| ❌ Legacy (do NOT use) | ✅ Modern replacement |
|
|
29
|
+
|------------------------|----------------------|
|
|
30
|
+
| `Optional[X]` | `X \| None` |
|
|
31
|
+
| `Union[X, Y]` | `X \| Y` |
|
|
32
|
+
| `Dict[K, V]` | `dict[K, V]` |
|
|
33
|
+
| `List[T]` | `list[T]` |
|
|
34
|
+
| `Tuple[T, ...]` | `tuple[T, ...]` |
|
|
35
|
+
| `Set[T]` | `set[T]` |
|
|
36
|
+
| `FrozenSet[T]` | `frozenset[T]` |
|
|
37
|
+
| `Type[T]` | `type[T]` |
|
|
38
|
+
| `Any` | Avoid — prefer `object`, `Protocol`, `TypedDict`, or a concrete union |
|
|
39
|
+
|
|
40
|
+
### Rules
|
|
41
|
+
|
|
42
|
+
- **Always** use lowercase built-in generics: `list[str]`, `dict[str, int]`, `tuple[int, ...]`.
|
|
43
|
+
- **Always** use `X | None` instead of `Optional[X]`.
|
|
44
|
+
- Add `from __future__ import annotations` when forward references are needed, but prefer it in all new files for consistency.
|
|
45
|
+
- `typing.TYPE_CHECKING` is fine for import-cycle breaking; keep runtime imports lean.
|
|
46
|
+
- If `Any` is truly unavoidable, add a brief comment explaining why.
|
|
47
|
+
|
|
48
|
+
## 3. Comments & Docstrings — English Only
|
|
49
|
+
|
|
50
|
+
### Comments
|
|
51
|
+
|
|
52
|
+
- **All comments must be in English.** No Chinese in `#` comments or inline remarks.
|
|
53
|
+
- Keep comments concise: explain *why*, not *what* (the code shows *what*).
|
|
54
|
+
- Use `# TODO(author): description` / `# FIXME(author): description` for action items.
|
|
55
|
+
- Avoid redundant comments that merely restate the code:
|
|
56
|
+
```python
|
|
57
|
+
# Bad — restates the code
|
|
58
|
+
# Increment counter by one
|
|
59
|
+
counter += 1
|
|
60
|
+
|
|
61
|
+
# Good — explains intent
|
|
62
|
+
# Retry once more before giving up
|
|
63
|
+
counter += 1
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Docstrings
|
|
67
|
+
|
|
68
|
+
- Use triple double-quotes `"""` exclusively.
|
|
69
|
+
- First line: short imperative summary (≤ 79 chars), ending with a period.
|
|
70
|
+
- Blank line, then detailed description if needed.
|
|
71
|
+
- Document parameters, return values, and raised exceptions for public APIs.
|
|
72
|
+
- Prefer reStructuredText or Google-style format — be consistent within a module.
|
|
73
|
+
- Docstrings must also be in **English**.
|
|
74
|
+
|
|
75
|
+
## 4. Import Hygiene
|
|
76
|
+
|
|
77
|
+
- One import per line; no `import os, sys`.
|
|
78
|
+
- Order: stdlib → third-party → local, separated by blank lines, sorted alphabetically within each group.
|
|
79
|
+
- Never use `from module import *`.
|
|
80
|
+
- Remove unused imports immediately — ruff rule `F401` will catch these.
|
|
81
|
+
- Place `from __future__ import annotations` before all other imports.
|
|
82
|
+
|
|
83
|
+
## 5. PEP 8 Essentials (enforced by ruff)
|
|
84
|
+
|
|
85
|
+
- **Indentation**: 4 spaces, no tabs.
|
|
86
|
+
- **Line length**: 120 characters max (matches project `.editorconfig`).
|
|
87
|
+
- **Trailing whitespace**: forbidden.
|
|
88
|
+
- **Blank lines**: 2 between top-level definitions, 1 between methods.
|
|
89
|
+
- **File endings**: exactly one trailing newline, LF only.
|
|
90
|
+
- **Variable naming**: `snake_case` for functions/variables, `PascalCase` for classes, `UPPER_SNAKE` for constants.
|
|
91
|
+
- **Avoid ambiguous names**: no single-char `l`, `O`, `I` (ruff `E741`).
|
|
92
|
+
|
|
93
|
+
## 6. Common Pitfalls to Avoid
|
|
94
|
+
|
|
95
|
+
| Rule | Example |
|
|
96
|
+
|------|---------|
|
|
97
|
+
| No mutable default args | `def f(items=None):` not `def f(items=[]):` |
|
|
98
|
+
| No bare `except:` | Always catch a specific exception |
|
|
99
|
+
| Use `is not` instead of `not ... is` | `if x is not None:` |
|
|
100
|
+
| Sequence truthiness | `if seq:` not `if len(seq):` |
|
|
101
|
+
| Use `with` for resources | Files, sockets, locks |
|
|
102
|
+
| No `lambda` assignment | Use `def` instead of `fn = lambda x: ...` |
|
|
103
|
+
| No string concat in loops | Use `"".join(parts)` |
|
|
104
|
+
|
|
105
|
+
## 7. Quick Checklist Before Commit
|
|
106
|
+
|
|
107
|
+
- [ ] `ruff check . --fix` — zero errors
|
|
108
|
+
- [ ] `ruff format .` — no diff
|
|
109
|
+
- [ ] No `Optional`, `Dict`, `List`, `Any` in new/modified code
|
|
110
|
+
- [ ] All comments and docstrings are in English
|
|
111
|
+
- [ ] No unused imports or variables
|
|
112
|
+
- [ ] Type hints on all new public functions
|
|
113
|
+
- [ ] `from __future__ import annotations` in new files
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: publish
|
|
3
|
+
description: 当需要发布 Python 包到 PyPI 时使用 — 创建 release 分支、升版本号、更新 CHANGELOG、发布到 PyPI、打 tag、并创建合并请求到 main
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Publish
|
|
7
|
+
|
|
8
|
+
自动化 Python 包的完整发布流程。
|
|
9
|
+
|
|
10
|
+
**开始时宣告:** "正在使用 publish 技能发布版本 {VERSION}。"
|
|
11
|
+
|
|
12
|
+
## 配置项
|
|
13
|
+
|
|
14
|
+
以下配置有默认值,可在项目的 `.codebuddy/skills/publish/SKILL.md` 中覆盖。
|
|
15
|
+
|
|
16
|
+
| 配置项 | 默认值 | 说明 |
|
|
17
|
+
|--------|--------|------|
|
|
18
|
+
| `PUBLISH_CMD` | 自动检测(见步骤 5) | 发布到 PyPI 的命令 |
|
|
19
|
+
| `CHANGELOG_FILE` | `CHANGELOG.md` | 相对于仓库根目录的路径,文件不存在则跳过 |
|
|
20
|
+
| `VERSION_FILE` | `pyproject.toml` | 包含版本号的文件 |
|
|
21
|
+
| `VERSION_PATTERN` | `^\s*version\s*=\s*"[^"]+"` | 匹配版本行的正则表达式 |
|
|
22
|
+
| `TAG_PREFIX` | ``(空) | Git tag 前缀,设为 `v` 则生成 `v0.1.14` 风格标签 |
|
|
23
|
+
| `REMOTE` | `origin` | Git 远程仓库名 |
|
|
24
|
+
| `TARGET_BRANCH` | `main` | 合并请求的目标分支 |
|
|
25
|
+
| `RELEASE_BRANCH_PREFIX` | `release/` | release 分支名前缀 |
|
|
26
|
+
|
|
27
|
+
## 调用方式
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
/publish 0.1.14
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
目标版本号是唯一必填参数,其余均从配置或自动检测获取。
|
|
34
|
+
|
|
35
|
+
## 发布流程
|
|
36
|
+
|
|
37
|
+
### 步骤 1 — 读取配置并确认版本
|
|
38
|
+
|
|
39
|
+
1. 获取仓库根目录:`git rev-parse --show-toplevel`
|
|
40
|
+
2. 从 `VERSION_FILE` 读取当前版本:
|
|
41
|
+
```bash
|
|
42
|
+
grep -E '^\s*version\s*=\s*"[^"]+"' pyproject.toml
|
|
43
|
+
```
|
|
44
|
+
3. 检查未提交的更改:
|
|
45
|
+
```bash
|
|
46
|
+
git status --short
|
|
47
|
+
```
|
|
48
|
+
如果存在未提交的更改,它们将被包含在步骤 4 的发布提交中。这是有意为之 — 所有待处理的工作随版本一起发布。
|
|
49
|
+
4. 查找最近的 git tag:
|
|
50
|
+
```bash
|
|
51
|
+
git tag --sort=-creatordate | head -1
|
|
52
|
+
```
|
|
53
|
+
如果没有 tag,视为首次发布(在步骤 3 中使用从仓库初始到 HEAD 的所有提交)。
|
|
54
|
+
5. 展示确认信息:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
当前版本 (pyproject.toml): X.Y.Z
|
|
58
|
+
目标版本: A.B.C
|
|
59
|
+
上次发布 tag: X.Y.Z (YYYY-MM-DD)
|
|
60
|
+
Release 分支: release/A.B.C
|
|
61
|
+
目标分支 (MR): main
|
|
62
|
+
|
|
63
|
+
确认发布 X.Y.Z → A.B.C?[y/N]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
如果用户未输入 `y` 确认,立即中止。
|
|
67
|
+
|
|
68
|
+
### 步骤 2 — 创建 release 分支
|
|
69
|
+
|
|
70
|
+
从当前 HEAD 创建并切换到新的 release 分支:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git checkout -b {RELEASE_BRANCH_PREFIX}{version}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
如果分支已存在,中止:
|
|
77
|
+
```
|
|
78
|
+
✗ 分支 {RELEASE_BRANCH_PREFIX}{version} 已存在。
|
|
79
|
+
请手动删除:git branch -D {RELEASE_BRANCH_PREFIX}{version}
|
|
80
|
+
然后重新运行 /publish。
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 步骤 3 — 分析变更并生成 CHANGELOG 草稿
|
|
84
|
+
|
|
85
|
+
1. 获取上次 tag 以来的提交:
|
|
86
|
+
```bash
|
|
87
|
+
git log {last_tag}..HEAD --oneline
|
|
88
|
+
# 首次发布时:
|
|
89
|
+
git log --oneline
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
2. 如果没有找到提交:
|
|
93
|
+
```
|
|
94
|
+
⚠ 自上次发布 tag ({last_tag}) 以来没有新提交。
|
|
95
|
+
是否继续?[y/N]
|
|
96
|
+
```
|
|
97
|
+
用户未确认则中止。
|
|
98
|
+
|
|
99
|
+
3. 按提交前缀分类,生成 Keep a Changelog 格式的条目。
|
|
100
|
+
|
|
101
|
+
**CHANGELOG 内容必须用中文书写。** 将每个提交总结为简洁的中文要点 — 不要逐字翻译提交信息。适当合并相关提交。
|
|
102
|
+
|
|
103
|
+
分类规则:
|
|
104
|
+
- 以 `feat:` 或 `feat(` 开头 → **新增**
|
|
105
|
+
- 以 `fix:` 或 `fix(` 开头 → **修复**
|
|
106
|
+
- 以 `refactor:` 或 `perf:` 开头 → **变更**
|
|
107
|
+
- 包含 `!:` 或提交正文含 `BREAKING CHANGE:` → **变更**,加 `**Breaking:**` 前缀
|
|
108
|
+
- 以 `docs:` 开头 → **变更**
|
|
109
|
+
- 以 `chore:`、`test:`、`ci:` 开头 → 忽略(基础设施噪音)
|
|
110
|
+
- 其他所有提交 → **变更**
|
|
111
|
+
- 移除的功能 → **移除**
|
|
112
|
+
- 安全修复 → **安全**
|
|
113
|
+
|
|
114
|
+
输出格式:
|
|
115
|
+
```markdown
|
|
116
|
+
## [A.B.C] - YYYY-MM-DD
|
|
117
|
+
|
|
118
|
+
### 新增
|
|
119
|
+
- 中文描述新增功能
|
|
120
|
+
|
|
121
|
+
### 修复
|
|
122
|
+
- 中文描述修复内容
|
|
123
|
+
|
|
124
|
+
### 变更
|
|
125
|
+
- 中文描述行为变更
|
|
126
|
+
|
|
127
|
+
### 移除
|
|
128
|
+
- 中文描述移除内容
|
|
129
|
+
|
|
130
|
+
### 安全
|
|
131
|
+
- 中文描述安全修复
|
|
132
|
+
```
|
|
133
|
+
省略空的分类。日期使用 ISO 8601 格式(当天日期)。日期行与第一个分类之间、各分类之间保留空行。
|
|
134
|
+
|
|
135
|
+
4. 向用户展示草稿并请求确认:
|
|
136
|
+
```
|
|
137
|
+
CHANGELOG 草稿:
|
|
138
|
+
|
|
139
|
+
{draft}
|
|
140
|
+
|
|
141
|
+
添加到 CHANGELOG.md?[y/N/edit]
|
|
142
|
+
```
|
|
143
|
+
- `y` → 继续
|
|
144
|
+
- `n` → 中止
|
|
145
|
+
- `edit` 或其他反馈 → 询问用户:"需要什么修改?" — 等待回复后重新生成,再次展示确认。循环直到 `y` 或 `n`。
|
|
146
|
+
|
|
147
|
+
5. 如果 `CHANGELOG_FILE` 不存在,跳过此步骤(无需警告)。
|
|
148
|
+
|
|
149
|
+
### 步骤 4 — 更新文件、提交并推送 release 分支
|
|
150
|
+
|
|
151
|
+
按顺序执行:
|
|
152
|
+
|
|
153
|
+
**4a. 更新 CHANGELOG:**
|
|
154
|
+
|
|
155
|
+
在 `CHANGELOG_FILE` 中找到 `## [Unreleased]` 标题,在其后插入新版本条目(保持 `[Unreleased]` 为空):
|
|
156
|
+
|
|
157
|
+
```markdown
|
|
158
|
+
## [Unreleased]
|
|
159
|
+
|
|
160
|
+
## [A.B.C] - YYYY-MM-DD
|
|
161
|
+
### 新增
|
|
162
|
+
- ...
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
如果 `## [Unreleased]` 标题不存在,在 `# Changelog` 标题行之后插入新条目(若无标题则插入到文件顶部)。
|
|
166
|
+
|
|
167
|
+
**4b. 升级 VERSION_FILE 中的版本号:**
|
|
168
|
+
|
|
169
|
+
替换 `VERSION_PATTERN` 匹配到的版本行。对于 `pyproject.toml`:
|
|
170
|
+
```bash
|
|
171
|
+
# 查找当前行:
|
|
172
|
+
grep -n '^\s*version\s*=\s*"[^"]+"' pyproject.toml
|
|
173
|
+
# 用 Edit 工具将该行的 "X.Y.Z" 替换为 "A.B.C"
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**4c. 提交:**
|
|
177
|
+
|
|
178
|
+
检查工作树状态:
|
|
179
|
+
```bash
|
|
180
|
+
git status --short
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
- 如果有更改(已暂存或未暂存):暂存所有文件并提交:
|
|
184
|
+
```bash
|
|
185
|
+
git add -A
|
|
186
|
+
git commit -m "chore: release {version}"
|
|
187
|
+
```
|
|
188
|
+
- 如果工作树已干净:无需提交,跳过。
|
|
189
|
+
|
|
190
|
+
**4d. 推送 release 分支:**
|
|
191
|
+
```bash
|
|
192
|
+
git push -u {REMOTE} {RELEASE_BRANCH_PREFIX}{version}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
推送失败则中止。
|
|
196
|
+
|
|
197
|
+
### 步骤 5 — 发布到 PyPI
|
|
198
|
+
|
|
199
|
+
**自动检测 PUBLISH_CMD**(仅在配置未覆盖时):
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# 检查 Makefile 是否有 publish 目标
|
|
203
|
+
grep -q '^\s*publish\s*:' Makefile 2>/dev/null && echo "make publish" || echo "python -m build && python -m twine upload dist/*"
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
- 如果 `make publish` 目标存在 → `PUBLISH_CMD=make publish`
|
|
207
|
+
- 否则 → `PUBLISH_CMD=python -m build && python -m twine upload dist/*`
|
|
208
|
+
- 如果 `python -m build` 或 `python -m twine` 未安装,中止:"缺少构建工具。请安装:`pip install build twine`"
|
|
209
|
+
|
|
210
|
+
执行:
|
|
211
|
+
```bash
|
|
212
|
+
{PUBLISH_CMD}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
实时输出。如果退出码非零:
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
✗ 发布失败(退出码 N)。已停止 — 不会创建 tag。
|
|
219
|
+
请检查上方输出,解决问题后重新运行 /publish。
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**不继续执行步骤 6。**
|
|
223
|
+
|
|
224
|
+
### 步骤 6 — 打 tag 并推送
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
git tag {TAG_PREFIX}{version}
|
|
228
|
+
git push {REMOTE} {TAG_PREFIX}{version}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
如果 `git tag` 因 tag 已存在而失败:
|
|
232
|
+
```
|
|
233
|
+
✗ Tag {TAG_PREFIX}{version} 已存在。
|
|
234
|
+
请手动删除:git tag -d {TAG_PREFIX}{version}
|
|
235
|
+
然后重新运行 /publish 从此步骤重试。
|
|
236
|
+
```
|
|
237
|
+
中止。
|
|
238
|
+
|
|
239
|
+
### 步骤 7 — 创建合并请求
|
|
240
|
+
|
|
241
|
+
使用工丰 MCP 工具从 release 分支创建到 `TARGET_BRANCH` 的合并请求:
|
|
242
|
+
|
|
243
|
+
1. 从 git remote 检测项目路径:
|
|
244
|
+
```bash
|
|
245
|
+
git remote get-url {REMOTE} | sed -E 's|.*[:/](.+/.+)\.git$|\1|'
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
2. 使用 `mcp__gongfeng__create_merge_request` 创建 MR:
|
|
249
|
+
- `project_id`:项目完整路径(如 `orcakit/finnie`)
|
|
250
|
+
- `title`:`chore: release {version}`
|
|
251
|
+
- `source_branch`:`{RELEASE_BRANCH_PREFIX}{version}`
|
|
252
|
+
- `target_branch`:`{TARGET_BRANCH}`
|
|
253
|
+
- `description`:步骤 3 生成的 CHANGELOG 条目
|
|
254
|
+
|
|
255
|
+
3. 成功时展示:
|
|
256
|
+
```
|
|
257
|
+
✓ 已发布 {package_name} {version} 到 PyPI
|
|
258
|
+
✓ 已创建并推送 tag {TAG_PREFIX}{version} 到 {REMOTE}
|
|
259
|
+
✓ 已创建合并请求:{RELEASE_BRANCH_PREFIX}{version} → {TARGET_BRANCH}
|
|
260
|
+
链接:{mr_url}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
4. MR 创建失败时展示警告(非致命 — 发布已成功):
|
|
264
|
+
```
|
|
265
|
+
⚠ 发布成功,但合并请求创建失败。
|
|
266
|
+
请手动创建:{RELEASE_BRANCH_PREFIX}{version} → {TARGET_BRANCH}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### 步骤 8 — 切回原分支
|
|
270
|
+
|
|
271
|
+
返回创建 release 分支之前所在的分支:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
git checkout {original_branch}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
确保流程结束后用户不会停留在 release 分支上。
|
|
278
|
+
|
|
279
|
+
## 错误处理参考
|
|
280
|
+
|
|
281
|
+
| 场景 | 行为 |
|
|
282
|
+
|------|------|
|
|
283
|
+
| `VERSION_FILE` 未找到 | 中止:"找不到 VERSION_FILE:{path}" |
|
|
284
|
+
| 文件中未匹配到版本号 | 中止:"在 {VERSION_FILE} 中找不到匹配 {VERSION_PATTERN} 的版本行" |
|
|
285
|
+
| 没有 git tag(首次发布) | 使用从仓库初始到 HEAD 的所有提交;提示"首次发布 — 使用完整 git 历史" |
|
|
286
|
+
| 上次 tag 以来无提交 | 警告并询问是否继续 |
|
|
287
|
+
| Release 分支已存在 | 中止并给出删除指令 |
|
|
288
|
+
| 步骤 4 推送失败 | 中止:文件已在本地更新但未推送 |
|
|
289
|
+
| 步骤 5 发布失败 | 中止:不创建 tag、不创建 MR |
|
|
290
|
+
| 步骤 6 tag 已存在 | 中止并给出删除指令 |
|
|
291
|
+
| 步骤 7 MR 创建失败 | 仅警告(发布已成功) |
|
|
292
|
+
|
|
293
|
+
## 红线规则
|
|
294
|
+
|
|
295
|
+
**绝不:**
|
|
296
|
+
- 在发布成功前创建 tag
|
|
297
|
+
- 在发布成功前创建合并请求
|
|
298
|
+
- 跳过步骤 1 的用户确认
|
|
299
|
+
- 跳过步骤 3 的 CHANGELOG 确认
|
|
300
|
+
- 在任何步骤失败后继续执行(步骤 7 MR 失败除外)
|
|
301
|
+
- 流程结束后让用户留在 release 分支
|
|
302
|
+
|
|
303
|
+
**始终:**
|
|
304
|
+
- 任何失败立即中止(步骤 7 除外)
|
|
305
|
+
- 中止前展示完整错误输出
|
|
306
|
+
- 插入新版本条目后保持 `[Unreleased]` 为空
|
|
307
|
+
- 流程结束时切回原分支
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# OpenAI API Configuration
|
|
2
|
+
# Copy this file to .env and fill in your credentials
|
|
3
|
+
|
|
4
|
+
OPENAI_API_KEY=your_api_key_here
|
|
5
|
+
OPENAI_BASE_URL=https://api.openai.com/v1
|
|
6
|
+
OPENAI_MODEL_NAME=gpt-4o-mini
|
|
7
|
+
|
|
8
|
+
# ---------------------------------------------------------------------------
|
|
9
|
+
# XiaoYi (小艺 / Huawei OpenClaw)
|
|
10
|
+
# ---------------------------------------------------------------------------
|
|
11
|
+
XIAOYI_AK=
|
|
12
|
+
XIAOYI_SK=
|
|
13
|
+
XIAOYI_AGENT_ID=
|
|
14
|
+
# Show thinking / tool messages (true/false)
|
|
15
|
+
XIAOYI_SHOW_THINKING=false
|
|
16
|
+
XIAOYI_SHOW_TOOL_HINTS=true
|
|
17
|
+
|
|
18
|
+
# ---------------------------------------------------------------------------
|
|
19
|
+
# MQTT (EMQX Cloud example)
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
MQTT_HOST=c14633a9.ala.cn-shenzhen.emqxsl.cn
|
|
22
|
+
MQTT_PORT=8883
|
|
23
|
+
MQTT_USERNAME=
|
|
24
|
+
MQTT_PASSWORD=
|
|
25
|
+
MQTT_SUBSCRIBE_TOPIC=devices/+/in
|
|
26
|
+
MQTT_PUBLISH_TOPIC=devices/{client_id}/out
|
|
27
|
+
MQTT_TLS_ENABLED=true
|
|
28
|
+
# Path to CA PEM file, or set tls_ca_pem inline in code
|
|
29
|
+
MQTT_TLS_CA_FILE=
|
|
30
|
+
MQTT_SHOW_THINKING=false
|
|
31
|
+
MQTT_SHOW_TOOL_HINTS=true
|
|
32
|
+
|
|
33
|
+
# ---------------------------------------------------------------------------
|
|
34
|
+
# Telegram
|
|
35
|
+
# ---------------------------------------------------------------------------
|
|
36
|
+
TELEGRAM_BOT_TOKEN=
|
|
37
|
+
TELEGRAM_HTTP_PROXY=
|
|
38
|
+
TELEGRAM_SHOW_TYPING=true
|
|
39
|
+
TELEGRAM_SHOW_THINKING=false
|
|
40
|
+
TELEGRAM_SHOW_TOOL_HINTS=true
|
|
41
|
+
|
|
42
|
+
# ---------------------------------------------------------------------------
|
|
43
|
+
# Other IM platforms (examples)
|
|
44
|
+
# ---------------------------------------------------------------------------
|
|
45
|
+
FEISHU_APP_ID=
|
|
46
|
+
FEISHU_APP_SECRET=
|
|
47
|
+
QQ_APP_ID=
|
|
48
|
+
QQ_TOKEN=
|
|
49
|
+
QQ_SECRET=
|
|
50
|
+
DINGTALK_APP_KEY=
|
|
51
|
+
DINGTALK_APP_SECRET=
|
|
52
|
+
WECOM_BOT_ID=
|
|
53
|
+
WECOM_SECRET=
|
|
54
|
+
WEIXIN_ACCOUNT_ID=
|
|
55
|
+
WEIXIN_TOKEN=
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- What does this PR change and why? -->
|
|
4
|
+
|
|
5
|
+
## Type of change
|
|
6
|
+
|
|
7
|
+
- [ ] Bug fix
|
|
8
|
+
- [ ] New feature
|
|
9
|
+
- [ ] Breaking change
|
|
10
|
+
- [ ] Documentation
|
|
11
|
+
- [ ] Refactor / chore
|
|
12
|
+
|
|
13
|
+
## Test plan
|
|
14
|
+
|
|
15
|
+
<!-- How did you verify this? Include commands run (e.g. `make all`). -->
|
|
16
|
+
|
|
17
|
+
- [ ] `make all` passes locally
|
|
18
|
+
- [ ] Added/updated tests
|
|
19
|
+
|
|
20
|
+
## Checklist
|
|
21
|
+
|
|
22
|
+
- [ ] Updated `CHANGELOG.md` (if user-facing)
|
|
23
|
+
- [ ] README / docs updated (if needed)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ci-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
quality:
|
|
14
|
+
name: "Python ${{ matrix.python-version }}"
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
python-version: ["3.11", "3.12"]
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- uses: astral-sh/setup-uv@v4
|
|
24
|
+
with:
|
|
25
|
+
enable-cache: true
|
|
26
|
+
python-version: ${{ matrix.python-version }}
|
|
27
|
+
|
|
28
|
+
- name: Install dependencies
|
|
29
|
+
run: make install
|
|
30
|
+
|
|
31
|
+
- name: Lint
|
|
32
|
+
run: make lint
|
|
33
|
+
|
|
34
|
+
- name: Type check
|
|
35
|
+
run: make typecheck
|
|
36
|
+
|
|
37
|
+
- name: Test
|
|
38
|
+
run: make test
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: CodeQL
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: "0 3 * * 1"
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
security-events: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
analyze:
|
|
16
|
+
name: Analyze
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Initialize CodeQL
|
|
22
|
+
uses: github/codeql-action/init@v3
|
|
23
|
+
with:
|
|
24
|
+
languages: python
|
|
25
|
+
|
|
26
|
+
- name: Autobuild
|
|
27
|
+
uses: github/codeql-action/autobuild@v3
|
|
28
|
+
|
|
29
|
+
- name: Perform CodeQL Analysis
|
|
30
|
+
uses: github/codeql-action/analyze@v3
|