Skip to content

Commit 60a0cce

Browse files
authored
Merge pull request #389 from 1024XEngineer/xgopilot/issue-377-1776758171
feat: add in-repo automated issue creation workflow
2 parents 16257af + adc6a47 commit 60a0cce

7 files changed

Lines changed: 405 additions & 0 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
name: "issue-rfc-architecture"
3+
description: "用于创建架构类 Issue(RFC 风格)。当用户需要明确模块边界、核心设计和落地路线时使用。"
4+
---
5+
6+
# Issue RFC Architecture
7+
8+
适用于“架构类”议题,强调边界、职责和关键设计选择。
9+
10+
## 使用步骤
11+
12+
1. 先确认目标问题和影响模块。
13+
2. 运行命令创建 issue:
14+
15+
```bash
16+
./scripts/create_issue.sh --type architecture --title "<架构标题>"
17+
```
18+
19+
3. 如需自定义正文,先准备 markdown 文件,再执行:
20+
21+
```bash
22+
./scripts/create_issue.sh --type architecture --title "<架构标题>" --body-file <path>
23+
```
24+
25+
## 质量要求
26+
27+
- 正文必须包含:目标问题、现状与边界、核心设计、落地清单、验收标准、风险与回滚。
28+
- 设计必须说明“为什么是这个方案”,并给出边界分工。
29+
- 验收项应覆盖正常路径、异常路径、恢复路径。
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
name: "issue-rfc-implementation"
3+
description: "用于创建实现类 Issue(RFC 执行单风格)。当用户要把已确认提案/架构落地成可执行任务时使用。"
4+
---
5+
6+
# Issue RFC Implementation
7+
8+
适用于“实现类”议题,强调关联上游 RFC、改动范围和验证闭环。
9+
10+
## 使用步骤
11+
12+
1. 先确认已关联的提案/架构 issue。
13+
2. 运行命令创建 issue:
14+
15+
```bash
16+
./scripts/create_issue.sh --type implementation --title "<实现标题>"
17+
```
18+
19+
3. 如需自定义正文,先准备 markdown 文件,再执行:
20+
21+
```bash
22+
./scripts/create_issue.sh --type implementation --title "<实现标题>" --body-file <path>
23+
```
24+
25+
## 质量要求
26+
27+
- 正文必须包含:关联 RFC、目标问题、实现设计、任务清单、测试验证、风险与回滚。
28+
- 任务清单要可执行且可追踪,不接受抽象口号。
29+
- 测试清单至少覆盖正常路径、边界条件、异常分支。
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
name: "issue-rfc-proposal"
3+
description: "用于创建提案类 Issue(RFC 风格)。当用户希望在本仓库发起‘目标问题 -> 设计 -> 落地清单’的提案讨论时使用。"
4+
---
5+
6+
# Issue RFC Proposal
7+
8+
适用于“提案类”议题,要求输出遵循:目标问题(Why)-> 设计方案(How)-> 落地清单(What)。
9+
10+
## 使用步骤
11+
12+
1. 先让用户明确提案标题与核心痛点。
13+
2. 运行命令创建 issue:
14+
15+
```bash
16+
./scripts/create_issue.sh --type proposal --title "<提案标题>"
17+
```
18+
19+
3. 如需自定义正文,先准备 markdown 文件,再执行:
20+
21+
```bash
22+
./scripts/create_issue.sh --type proposal --title "<提案标题>" --body-file <path>
23+
```
24+
25+
## 质量要求
26+
27+
- 正文必须包含:目标问题、设计方案、落地清单、验收标准、风险与回滚。
28+
- 非目标必须明确,避免提案发散。
29+
- 验收标准必须可验证,避免空泛表述。

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.PHONY: install-skills
2+
3+
install-skills:
4+
@./scripts/install_skills.sh

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,47 @@ go run ./cmd/neocode --runtime-mode gateway
186186
- 不提交明文密钥、个人配置或会话数据
187187
- 不提交无关改动与临时文件
188188

189+
## 在仓库内直接创建 Issue(Skills + 自动化)
190+
191+
仓库提供三类同前缀 skill(位于 `.skills/`):
192+
193+
- `issue-rfc-proposal`(提案类,RFC 风格)
194+
- `issue-rfc-architecture`(架构类,RFC 风格)
195+
- `issue-rfc-implementation`(实现类,执行单风格)
196+
197+
先安装 skills 到仓库内常见 AI Coding 工具目录:
198+
199+
```bash
200+
make install-skills
201+
```
202+
203+
默认会安装到以下目录(均在仓库内):
204+
205+
- `.codex/skills`
206+
- `.claude/skills`
207+
- `.cursor/skills`
208+
- `.windsurf/skills`
209+
210+
如需自定义安装目标,可设置环境变量 `SKILL_INSTALL_TARGETS`(冒号分隔目录):
211+
212+
```bash
213+
SKILL_INSTALL_TARGETS=".codex/skills:.claude/skills" make install-skills
214+
```
215+
216+
Skill 内部调用脚本 `scripts/create_issue.sh` 创建 issue。你也可以直接执行脚本:
217+
218+
```bash
219+
./scripts/create_issue.sh --type proposal --title "统一会话中断恢复语义"
220+
./scripts/create_issue.sh --type architecture --title "Runtime 与 Session 账本边界梳理"
221+
./scripts/create_issue.sh --type implementation --title "补齐流式中断持久化" --labels "bug,priority-high"
222+
```
223+
224+
脚本可选参数:
225+
226+
- `--repo <owner/repo>`:指定目标仓库(默认自动识别当前仓库)
227+
- `--body-file <path>`:自定义 issue 正文文件(不传则使用内置模板)
228+
- `--labels <a,b,c>`:追加标签(逗号分隔)
229+
189230
## 网关运维与安全(GW-06)
190231

191232
- 静默认证(Silent Auth):

scripts/create_issue.sh

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
#!/usr/bin/env sh
2+
3+
set -eu
4+
5+
usage() {
6+
cat <<'USAGE'
7+
在仓库内直接创建 GitHub Issue。
8+
9+
用法:
10+
./scripts/create_issue.sh --type <proposal|architecture|implementation> --title <标题> [选项]
11+
12+
选项:
13+
--repo <owner/repo> 目标仓库,默认自动检测当前仓库
14+
--body-file <path> 指定 issue 正文文件
15+
--labels <a,b,c> 逗号分隔的标签列表(可选)
16+
--type <type> issue 类型:proposal|architecture|implementation
17+
--title <title> issue 标题(不含类型前缀)
18+
-h, --help 显示帮助
19+
20+
示例:
21+
./scripts/create_issue.sh --type proposal --title "新增会话恢复策略"
22+
./scripts/create_issue.sh --type implementation --title "修复 streaming 中断持久化" --labels "bug,priority-high"
23+
USAGE
24+
}
25+
26+
require_cmd() {
27+
if ! command -v "$1" >/dev/null 2>&1; then
28+
echo "缺少命令: $1" >&2
29+
exit 1
30+
fi
31+
}
32+
33+
default_repo() {
34+
gh repo view --json nameWithOwner -q .nameWithOwner 2>/dev/null || true
35+
}
36+
37+
title_prefix() {
38+
case "$1" in
39+
proposal) echo "【提案】" ;;
40+
architecture) echo "【架构】" ;;
41+
implementation) echo "【实现】" ;;
42+
*) return 1 ;;
43+
esac
44+
}
45+
46+
# trim_label 用于去除标签参数的首尾空白字符,避免传递无效标签值。
47+
trim_label() {
48+
printf '%s' "$1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
49+
}
50+
51+
create_body_file() {
52+
type="$1"
53+
out="$2"
54+
55+
case "$type" in
56+
proposal)
57+
cat >"$out" <<'BODY'
58+
### 目标问题(Why)
59+
- 当前痛点:
60+
- 触发场景:
61+
62+
### 设计方案(How)
63+
- 核心设计:
64+
- 关键机制:
65+
- 边界与非目标:
66+
67+
### 落地清单(What)
68+
- [ ]
69+
- [ ]
70+
71+
### 验收标准(Done)
72+
- [ ]
73+
- [ ]
74+
75+
### 风险与回滚
76+
- 风险:
77+
- 回滚方案:
78+
BODY
79+
;;
80+
architecture)
81+
cat >"$out" <<'BODY'
82+
### 目标问题(Why)
83+
- 当前痛点:
84+
- 影响范围:
85+
86+
### 现状与边界
87+
- TUI:
88+
- Runtime:
89+
- Provider/Tools:
90+
- Session/Context:
91+
92+
### 核心设计(How)
93+
- 核心设计:
94+
- 数据流/事件流:
95+
- 关键取舍:
96+
97+
### 落地清单(What)
98+
- [ ]
99+
- [ ]
100+
101+
### 验收标准(Done)
102+
- [ ]
103+
- [ ]
104+
105+
### 风险与回滚
106+
- 风险:
107+
- 回滚方案:
108+
BODY
109+
;;
110+
implementation)
111+
cat >"$out" <<'BODY'
112+
### 关联 RFC / 架构
113+
- 提案/架构 issue:
114+
- 当前问题:
115+
116+
### 实现设计(How)
117+
- 关键改动点:
118+
- 影响模块:
119+
- 边界与非目标:
120+
121+
### 任务拆解
122+
- [ ]
123+
- [ ]
124+
125+
### 测试与验证(Done)
126+
- [ ] 正常路径
127+
- [ ] 边界条件
128+
- [ ] 异常分支
129+
130+
### 风险与回滚
131+
- 风险:
132+
- 回滚方案:
133+
BODY
134+
;;
135+
*)
136+
echo "不支持的类型: $type" >&2
137+
exit 1
138+
;;
139+
esac
140+
}
141+
142+
REPO=""
143+
BODY_FILE=""
144+
LABELS=""
145+
TYPE=""
146+
TITLE=""
147+
148+
while [ "$#" -gt 0 ]; do
149+
case "$1" in
150+
--repo)
151+
REPO="${2:-}"
152+
shift 2
153+
;;
154+
--body-file)
155+
BODY_FILE="${2:-}"
156+
shift 2
157+
;;
158+
--labels)
159+
LABELS="${2:-}"
160+
shift 2
161+
;;
162+
--type)
163+
TYPE="${2:-}"
164+
shift 2
165+
;;
166+
--title)
167+
TITLE="${2:-}"
168+
shift 2
169+
;;
170+
-h|--help)
171+
usage
172+
exit 0
173+
;;
174+
*)
175+
echo "未知参数: $1" >&2
176+
usage
177+
exit 1
178+
;;
179+
esac
180+
done
181+
182+
require_cmd gh
183+
184+
if [ -z "$TYPE" ] || [ -z "$TITLE" ]; then
185+
echo "--type 和 --title 为必填参数" >&2
186+
usage
187+
exit 1
188+
fi
189+
190+
if [ -z "$REPO" ]; then
191+
REPO="$(default_repo)"
192+
fi
193+
if [ -z "$REPO" ]; then
194+
echo "无法自动识别仓库,请通过 --repo 显式传入 owner/repo" >&2
195+
exit 1
196+
fi
197+
198+
PREFIX="$(title_prefix "$TYPE" || true)"
199+
if [ -z "$PREFIX" ]; then
200+
echo "--type 仅支持: proposal | architecture | implementation" >&2
201+
exit 1
202+
fi
203+
204+
FINAL_TITLE="$PREFIX $TITLE"
205+
TEMP_BODY=""
206+
if [ -n "$BODY_FILE" ]; then
207+
if [ ! -f "$BODY_FILE" ]; then
208+
echo "--body-file 指向的文件不存在: $BODY_FILE" >&2
209+
exit 1
210+
fi
211+
else
212+
TEMP_BODY="$(mktemp -t neocode-issue-body-XXXXXX.md)"
213+
BODY_FILE="$TEMP_BODY"
214+
create_body_file "$TYPE" "$BODY_FILE"
215+
fi
216+
217+
cleanup() {
218+
if [ -n "$TEMP_BODY" ] && [ -f "$TEMP_BODY" ]; then
219+
rm -f "$TEMP_BODY"
220+
fi
221+
}
222+
trap cleanup EXIT INT TERM
223+
224+
set -- issue create --repo "$REPO" --title "$FINAL_TITLE" --body-file "$BODY_FILE"
225+
if [ -n "$LABELS" ]; then
226+
OLD_IFS=$IFS
227+
IFS=','
228+
for label in $LABELS; do
229+
trimmed_label="$(trim_label "$label")"
230+
if [ -n "$trimmed_label" ]; then
231+
set -- "$@" --label "$trimmed_label"
232+
fi
233+
done
234+
IFS=$OLD_IFS
235+
fi
236+
237+
ISSUE_URL="$(gh "$@")"
238+
echo "Issue created: $ISSUE_URL"

0 commit comments

Comments
 (0)