@fitlab-ai/agent-infra 0.3.1 → 0.4.0
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.
- package/README.md +29 -39
- package/README.zh-CN.md +29 -39
- package/bin/cli.js +1 -1
- package/lib/defaults.json +3 -12
- package/lib/init.js +13 -24
- package/lib/paths.js +3 -42
- package/lib/update.js +98 -32
- package/lib/version.js +2 -1
- package/package.json +2 -1
- package/templates/.agents/QUICKSTART.md +7 -7
- package/templates/.agents/QUICKSTART.zh-CN.md +7 -7
- package/templates/.agents/README.md +16 -4
- package/templates/.agents/README.zh-CN.md +16 -4
- package/templates/.agents/skills/analyze-task/SKILL.md +106 -105
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +6 -6
- package/templates/.agents/skills/block-task/SKILL.md +8 -8
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/check-task/SKILL.md +3 -3
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/close-codescan/SKILL.md +64 -63
- package/templates/.agents/skills/close-dependabot/SKILL.md +71 -70
- package/templates/.agents/skills/commit/SKILL.md +1 -1
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-task/SKILL.md +7 -7
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +7 -7
- package/templates/.agents/skills/create-issue/SKILL.md +57 -12
- package/templates/.agents/skills/create-issue/SKILL.zh-CN.md +57 -12
- package/templates/.agents/skills/create-pr/SKILL.md +44 -7
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +44 -7
- package/templates/.agents/skills/create-release-note/SKILL.md +18 -11
- package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +18 -11
- package/templates/.agents/skills/create-task/SKILL.md +80 -78
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +11 -10
- package/templates/.agents/skills/implement-task/SKILL.md +15 -18
- package/templates/.agents/skills/implement-task/SKILL.zh-CN.md +15 -18
- package/templates/.agents/skills/import-codescan/SKILL.md +54 -53
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.md +57 -56
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/import-issue/SKILL.md +58 -58
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/init-labels/SKILL.md +8 -0
- package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -0
- package/templates/.agents/skills/plan-task/SKILL.md +151 -149
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +6 -6
- package/templates/.agents/skills/refine-task/SKILL.md +3 -3
- package/templates/.agents/skills/refine-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/release/SKILL.md +55 -14
- package/templates/.agents/skills/release/SKILL.zh-CN.md +55 -14
- package/templates/.agents/skills/review-task/SKILL.md +9 -9
- package/templates/.agents/skills/review-task/SKILL.zh-CN.md +9 -9
- package/templates/.agents/skills/sync-issue/SKILL.md +258 -279
- package/templates/.agents/skills/sync-issue/SKILL.zh-CN.md +34 -56
- package/templates/.agents/skills/sync-pr/SKILL.md +8 -28
- package/templates/.agents/skills/sync-pr/SKILL.zh-CN.md +7 -27
- package/templates/.agents/skills/update-agent-infra/SKILL.md +6 -6
- package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +6 -6
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +61 -116
- package/templates/.agents/templates/handoff.md +1 -1
- package/templates/.agents/templates/handoff.zh-CN.md +1 -1
- package/templates/.agents/workflows/bug-fix.yaml +71 -71
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +1 -1
- package/templates/.agents/workflows/feature-development.yaml +71 -71
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +1 -1
- package/templates/.agents/workflows/refactoring.yaml +76 -76
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +1 -1
- package/templates/{.agent-workspace → .agents/workspace}/README.md +1 -1
- package/templates/{.agent-workspace → .agents/workspace}/README.zh-CN.md +1 -1
- package/templates/.claude/CLAUDE.md +14 -1
- package/templates/.claude/CLAUDE.zh-CN.md +14 -1
- package/templates/.claude/hooks/check-version-format.sh +44 -0
- package/templates/.claude/settings.json +14 -0
- package/templates/.opencode/COMMAND_STYLE_GUIDE.md +6 -6
- package/templates/.opencode/COMMAND_STYLE_GUIDE.zh-CN.md +6 -6
- package/templates/AGENTS.md +14 -1
- package/templates/AGENTS.zh-CN.md +14 -1
- package/templates/.editorconfig +0 -15
- package/templates/.github/ISSUE_TEMPLATE/01_bug_report.yml +0 -149
- package/templates/.github/ISSUE_TEMPLATE/02_question.yml +0 -101
- package/templates/.github/ISSUE_TEMPLATE/03_feature_request.yml +0 -131
- package/templates/.github/ISSUE_TEMPLATE/04_documentation.yml +0 -165
- package/templates/.github/ISSUE_TEMPLATE/05_other.yml +0 -147
- package/templates/.github/ISSUE_TEMPLATE/config.yml +0 -11
- package/templates/.github/PULL_REQUEST_TEMPLATE.md +0 -123
- package/templates/.github/dependabot.yml +0 -17
- package/templates/.github/hooks/check-utf8-encoding.sh +0 -25
- package/templates/.github/release.yml +0 -27
- package/templates/.github/workflows/pr-title-check.yml +0 -42
- package/templates/.mailmap +0 -4
- package/templates/CONTRIBUTING.md +0 -126
- package/templates/CONTRIBUTING.zh-CN.md +0 -124
- package/templates/SECURITY.md +0 -131
- package/templates/SECURITY.zh-CN.md +0 -131
|
@@ -1,70 +1,71 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sync-issue
|
|
3
3
|
description: >
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
Sync task progress to comments on the related GitHub Issue.
|
|
5
|
+
Triggered when the user asks to sync progress to an Issue.
|
|
6
|
+
Argument: task-id or issue-number.
|
|
6
7
|
---
|
|
7
8
|
|
|
8
|
-
#
|
|
9
|
+
# Sync Progress to Issue
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
Sync task progress to the related GitHub Issue. Argument: task-id or issue-number.
|
|
11
12
|
|
|
12
|
-
##
|
|
13
|
+
## Execution Flow
|
|
13
14
|
|
|
14
|
-
### 1.
|
|
15
|
+
### 1. Parse the Argument
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
- `TASK-`
|
|
17
|
+
Identify the argument provided by the user:
|
|
18
|
+
- plain number (`123`) or `#` + number (`#123`) -> treat as an issue number
|
|
19
|
+
- Starts with `TASK-` -> treat as a task-id (current format)
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
If the argument is an issue number, use Bash to search for the related task (note: `.agents/workspace` is a hidden directory, so Grep/Glob tools may skip it; you must use Bash):
|
|
21
22
|
|
|
22
23
|
```bash
|
|
23
24
|
grep -rl "^issue_number: {issue-number}$" \
|
|
24
|
-
.
|
|
25
|
-
.
|
|
26
|
-
.
|
|
25
|
+
.agents/workspace/active/ \
|
|
26
|
+
.agents/workspace/blocked/ \
|
|
27
|
+
.agents/workspace/completed/ \
|
|
27
28
|
2>/dev/null | head -1
|
|
28
29
|
```
|
|
29
30
|
|
|
30
|
-
-
|
|
31
|
-
-
|
|
31
|
+
- If a file path is returned (for example `.agents/workspace/completed/TASK-xxx/task.md`), extract `{task-id}` and the task directory from the path, then continue to Step 2
|
|
32
|
+
- If nothing is returned, output `No task found associated with Issue #{issue-number}`
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
If the argument is a task-id, continue with the normal Step 2 flow.
|
|
34
35
|
|
|
35
|
-
### 2.
|
|
36
|
+
### 2. Verify the Task Exists
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
- `.
|
|
39
|
-
- `.
|
|
40
|
-
- `.
|
|
38
|
+
For a `task-id`, search for the task in this order:
|
|
39
|
+
- `.agents/workspace/active/{task-id}/task.md`
|
|
40
|
+
- `.agents/workspace/blocked/{task-id}/task.md`
|
|
41
|
+
- `.agents/workspace/completed/{task-id}/task.md`
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
Note: `{task-id}` format is `TASK-{yyyyMMdd-HHmmss}`, for example `TASK-20260306-143022`
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
If Step 1 already found a matching task through the issue number, use that task directory directly for the remaining steps without scanning again.
|
|
45
46
|
|
|
46
|
-
### 3.
|
|
47
|
+
### 3. Read Task Information
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
- `issue_number
|
|
49
|
+
Extract from task.md:
|
|
50
|
+
- `issue_number` (required; if missing, prompt the user)
|
|
50
51
|
- `type`
|
|
51
|
-
-
|
|
52
|
-
- `current_step
|
|
52
|
+
- task title, description, and status
|
|
53
|
+
- `current_step`, `created_at`, `updated_at`, and `last_synced_at` (if present)
|
|
53
54
|
|
|
54
|
-
### 4.
|
|
55
|
+
### 4. Read Context Files
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
- `implementation.md
|
|
60
|
-
- `refinement.md
|
|
61
|
-
- `review.md
|
|
57
|
+
Check and read these files if they exist:
|
|
58
|
+
- highest-round `analysis.md` / `analysis-r{N}.md` - requirements analysis
|
|
59
|
+
- highest-round `plan.md` / `plan-r{N}.md` - technical plan
|
|
60
|
+
- `implementation.md`, `implementation-r*.md` - implementation reports
|
|
61
|
+
- `refinement.md`, `refinement-r*.md` - refinement reports
|
|
62
|
+
- `review.md`, `review-r*.md` - review reports
|
|
62
63
|
|
|
63
|
-
### 5.
|
|
64
|
+
### 5. Detect Delivery Status
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
Run the following checks in order. If any step fails, fall back to "Mode C: In development". Do not invent anything you cannot verify.
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
Before starting detection, first resolve repository coordinates and the absolute URL prefix:
|
|
68
69
|
|
|
69
70
|
```bash
|
|
70
71
|
repo="$(gh repo view --json nameWithOwner --jq '.nameWithOwner')"
|
|
@@ -72,204 +73,171 @@ owner="${repo%%/*}"
|
|
|
72
73
|
repo_url="https://github.com/$repo"
|
|
73
74
|
```
|
|
74
75
|
|
|
75
|
-
**a)
|
|
76
|
+
**a) Extract the commit hash**
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
Match the last `**Commit** by` record in `## Activity Log` in task.md. The Activity Log format is:
|
|
78
79
|
|
|
79
80
|
```text
|
|
80
81
|
**Commit** by {agent} — {hash} {subject}
|
|
81
82
|
```
|
|
82
83
|
|
|
83
|
-
|
|
84
|
+
Extract the first word as the commit hash. If none is found, mark it as "no commit".
|
|
84
85
|
|
|
85
|
-
**b)
|
|
86
|
+
**b) Detect whether the commit is on a protected branch**
|
|
86
87
|
|
|
87
|
-
|
|
88
|
+
If a commit hash exists, run:
|
|
88
89
|
|
|
89
90
|
```bash
|
|
90
91
|
git branch -a --contains {commit-hash} 2>/dev/null
|
|
91
92
|
```
|
|
92
93
|
|
|
93
|
-
|
|
94
|
-
-
|
|
95
|
-
-
|
|
96
|
-
-
|
|
94
|
+
Decision rules:
|
|
95
|
+
- output contains `main` or `master` -> merged into the main branch; record the branch name
|
|
96
|
+
- output matches a `{major}.{minor}.x` branch name -> merged into a release branch; record the branch name
|
|
97
|
+
- neither matches -> not merged into a protected branch
|
|
97
98
|
|
|
98
|
-
**c)
|
|
99
|
+
**c) Detect the linked PR**
|
|
99
100
|
|
|
100
|
-
|
|
101
|
+
Check the `pr_number` field in task.md. If it exists, run:
|
|
101
102
|
|
|
102
103
|
```bash
|
|
103
104
|
gh pr view {pr-number} --json state,mergedAt
|
|
104
105
|
```
|
|
105
106
|
|
|
106
|
-
|
|
107
|
+
Use the result to determine whether the PR is `OPEN`, `MERGED`, or another state.
|
|
107
108
|
|
|
108
|
-
**d)
|
|
109
|
+
**d) Determine the delivery mode**
|
|
109
110
|
|
|
110
|
-
|
|
111
|
+
Choose the summary mode with this priority:
|
|
111
112
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
**e) 综合判定交付模式**
|
|
119
|
-
|
|
120
|
-
按以下优先级确定摘要模式:
|
|
121
|
-
|
|
122
|
-
| 条件 | 模式 |
|
|
123
|
-
|------|------|
|
|
124
|
-
| commit 已在受保护分支上 | 模式 A:已完成 |
|
|
125
|
-
| 有 PR,且状态为 `OPEN` 或 `MERGED` | 模式 B:PR 阶段 |
|
|
126
|
-
| 其他情况 | 模式 C:开发中 |
|
|
113
|
+
| Condition | Mode |
|
|
114
|
+
|---|---|
|
|
115
|
+
| commit is already on a protected branch | Mode A: Completed |
|
|
116
|
+
| PR exists and its state is `OPEN` or `MERGED` | Mode B: PR stage |
|
|
117
|
+
| anything else | Mode C: In development |
|
|
127
118
|
|
|
128
|
-
|
|
119
|
+
The priority must be `Mode A > Mode B > Mode C`. Even if a PR exists, treat it as "Completed" when the commit is already on a protected branch.
|
|
129
120
|
|
|
130
|
-
|
|
121
|
+
All later commit and PR links must use absolute URLs:
|
|
131
122
|
- `https://github.com/{owner}/{repo}/commit/{commit-hash}`
|
|
132
123
|
- `https://github.com/{owner}/{repo}/pull/{pr-number}`
|
|
133
124
|
|
|
134
|
-
|
|
125
|
+
Do not use relative paths such as `../../commit/...` or `../../pull/...`.
|
|
135
126
|
|
|
136
|
-
### 6.
|
|
127
|
+
### 6. Sync Labels and Issue Type
|
|
137
128
|
|
|
138
|
-
|
|
129
|
+
Sync Issue labels based on the detection result from Step 5.
|
|
139
130
|
|
|
140
|
-
**a)
|
|
131
|
+
**a) Check whether the label system has been initialized**
|
|
141
132
|
|
|
142
|
-
|
|
133
|
+
Run:
|
|
143
134
|
|
|
144
135
|
```bash
|
|
145
136
|
gh label list --search "type:" --limit 1 --json name --jq 'length'
|
|
146
137
|
```
|
|
147
138
|
|
|
148
|
-
|
|
149
|
-
-
|
|
150
|
-
-
|
|
151
|
-
|
|
152
|
-
**b) 同步 type label**
|
|
153
|
-
|
|
154
|
-
根据 task.md 的 `type` 字段按下表映射:
|
|
155
|
-
|
|
156
|
-
| task.md type | GitHub label |
|
|
157
|
-
|---|---|
|
|
158
|
-
| bug、bugfix | `type: bug` |
|
|
159
|
-
| feature | `type: feature` |
|
|
160
|
-
| enhancement | `type: enhancement` |
|
|
161
|
-
| refactor、refactoring | `type: enhancement` |
|
|
162
|
-
| documentation | `type: documentation` |
|
|
163
|
-
| dependency-upgrade | `type: dependency-upgrade` |
|
|
164
|
-
| task | `type: task` |
|
|
165
|
-
| 其他 | 跳过 |
|
|
166
|
-
|
|
167
|
-
如果映射到具体 label,执行:
|
|
168
|
-
|
|
169
|
-
```bash
|
|
170
|
-
gh issue edit {issue-number} --add-label "{type-label}"
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
未映射到标准 type label 时跳过,不创建新 label。
|
|
139
|
+
Decision rules:
|
|
140
|
+
- returns `0` -> the standard label system is missing; run the `init-labels` skill first (idempotent), then retry this step
|
|
141
|
+
- returns non-zero -> continue with label sync
|
|
174
142
|
|
|
175
|
-
**
|
|
143
|
+
**b) Sync the `status:` label**
|
|
176
144
|
|
|
177
|
-
|
|
145
|
+
First read existing `status:` labels on the Issue:
|
|
178
146
|
|
|
179
147
|
```bash
|
|
180
148
|
gh issue view {issue-number} --json labels --jq '.labels[].name | select(startswith("status:"))'
|
|
181
149
|
```
|
|
182
150
|
|
|
183
|
-
|
|
151
|
+
Remove each existing `status:` label:
|
|
184
152
|
|
|
185
153
|
```bash
|
|
186
154
|
gh issue edit {issue-number} --remove-label "{status-label}"
|
|
187
155
|
```
|
|
188
156
|
|
|
189
|
-
|
|
157
|
+
Then decide whether to add a new `status:` label using this priority:
|
|
190
158
|
|
|
191
|
-
|
|
|
159
|
+
| Condition | Action |
|
|
192
160
|
|---|---|
|
|
193
|
-
|
|
|
194
|
-
|
|
|
195
|
-
|
|
|
196
|
-
|
|
|
197
|
-
|
|
|
198
|
-
|
|
|
161
|
+
| task is under the `blocked/` directory | add `status: blocked` |
|
|
162
|
+
| Mode A: Completed | do not add a new status label |
|
|
163
|
+
| Mode B: PR is MERGED | do not add a new status label |
|
|
164
|
+
| Mode B: PR is OPEN | add `status: in-progress` |
|
|
165
|
+
| Mode C + `current_step` ∈ {`requirement-analysis`, `technical-design`} | add `status: pending-design-work` |
|
|
166
|
+
| Mode C + `current_step` ∈ {`implementation`, `code-review`, `refinement`} | add `status: in-progress` |
|
|
199
167
|
|
|
200
|
-
|
|
168
|
+
If a new label needs to be added, run:
|
|
201
169
|
|
|
202
170
|
```bash
|
|
203
171
|
gh issue edit {issue-number} --add-label "{status-label}"
|
|
204
172
|
```
|
|
205
173
|
|
|
206
|
-
**
|
|
174
|
+
**c) Sync the `in:` label**
|
|
207
175
|
|
|
208
|
-
|
|
209
|
-
-
|
|
210
|
-
-
|
|
176
|
+
Extract affected file paths from implementation reports first, or from `analysis.md` as a fallback:
|
|
177
|
+
- prefer file paths listed under `## Modified Files`, especially `### New Files` / `### Modified Files`, in `implementation.md` and `implementation-r{N}.md`
|
|
178
|
+
- if no implementation report exists, fall back to the affected file list in the analysis report
|
|
211
179
|
|
|
212
|
-
|
|
213
|
-
1.
|
|
214
|
-
2.
|
|
215
|
-
3.
|
|
180
|
+
For each file path:
|
|
181
|
+
1. take the first-level directory as the module name
|
|
182
|
+
2. deduplicate
|
|
183
|
+
3. check whether the corresponding label exists in the repository:
|
|
216
184
|
|
|
217
185
|
```bash
|
|
218
186
|
gh label list --search "in: {module}" --limit 10 --json name --jq '.[].name'
|
|
219
187
|
```
|
|
220
188
|
|
|
221
|
-
4.
|
|
189
|
+
4. only when the exact `in: {module}` label exists, run:
|
|
222
190
|
|
|
223
191
|
```bash
|
|
224
192
|
gh issue edit {issue-number} --add-label "in: {module}"
|
|
225
193
|
```
|
|
226
194
|
|
|
227
|
-
5.
|
|
195
|
+
5. **Only add; do not remove** existing `in:` labels
|
|
228
196
|
|
|
229
|
-
**
|
|
197
|
+
**d) Sync the Issue Type field**
|
|
230
198
|
|
|
231
|
-
|
|
199
|
+
Map the `type` field in task.md to the native GitHub Issue Type:
|
|
232
200
|
|
|
233
201
|
| task.md type | GitHub Issue Type |
|
|
234
202
|
|---|---|
|
|
235
|
-
| `bug
|
|
236
|
-
| `feature
|
|
237
|
-
| `task
|
|
203
|
+
| `bug`, `bugfix` | `Bug` |
|
|
204
|
+
| `feature`, `enhancement` | `Feature` |
|
|
205
|
+
| `task`, `documentation`, `dependency-upgrade`, `chore`, `docs`, `refactor`, `refactoring`, and any other value | `Task` |
|
|
238
206
|
|
|
239
|
-
|
|
207
|
+
First query the Issue Types available in the organization:
|
|
240
208
|
|
|
241
209
|
```bash
|
|
242
210
|
gh api "orgs/$owner/issue-types" --jq '.[].name'
|
|
243
211
|
```
|
|
244
212
|
|
|
245
|
-
|
|
213
|
+
Then execute this only when the target type exists:
|
|
246
214
|
|
|
247
215
|
```bash
|
|
248
216
|
gh api "repos/$repo/issues/{issue-number}" -X PATCH -f type="{name}"
|
|
249
217
|
```
|
|
250
218
|
|
|
251
|
-
|
|
252
|
-
-
|
|
253
|
-
-
|
|
254
|
-
-
|
|
219
|
+
Fault-tolerance requirements:
|
|
220
|
+
- If the API returns `404`, the repo owner is not an organization, or Issue Types are not enabled for the repo, record `Issue Type: skipped (not enabled)` and continue; do not fail the whole sync
|
|
221
|
+
- If the target type does not exist, record `Issue Type: skipped (type not available)`
|
|
222
|
+
- Do not try to create new Issue Types; only use names that already exist in the organization
|
|
255
223
|
|
|
256
|
-
### 7.
|
|
224
|
+
### 7. Sync Development
|
|
257
225
|
|
|
258
|
-
|
|
226
|
+
If task.md contains `pr_number`, ensure the PR body links the current Issue.
|
|
259
227
|
|
|
260
|
-
1.
|
|
228
|
+
1. Read the PR body:
|
|
261
229
|
|
|
262
230
|
```bash
|
|
263
231
|
gh pr view {pr-number} --json body --jq '.body // ""'
|
|
264
232
|
```
|
|
265
233
|
|
|
266
|
-
2.
|
|
234
|
+
2. Check whether the body already contains any of:
|
|
267
235
|
- `Closes #{issue-number}`
|
|
268
236
|
- `Fixes #{issue-number}`
|
|
269
237
|
- `Resolves #{issue-number}`
|
|
270
238
|
|
|
271
|
-
3.
|
|
272
|
-
4.
|
|
239
|
+
3. If any keyword already exists, skip the update
|
|
240
|
+
4. Otherwise append this to the end of the body:
|
|
273
241
|
|
|
274
242
|
```bash
|
|
275
243
|
gh pr edit {pr-number} --body "$(cat <<'EOF'
|
|
@@ -280,85 +248,85 @@ EOF
|
|
|
280
248
|
)"
|
|
281
249
|
```
|
|
282
250
|
|
|
283
|
-
5.
|
|
251
|
+
5. If task.md does not contain `pr_number`, record `Development: N/A`
|
|
284
252
|
|
|
285
|
-
### 8.
|
|
253
|
+
### 8. Sync the Milestone
|
|
286
254
|
|
|
287
|
-
|
|
255
|
+
Assign a line milestone to the Issue based on the current Issue state, explicit task configuration, and branch strategy.
|
|
288
256
|
|
|
289
|
-
**a)
|
|
257
|
+
**a) Check whether the Issue already has a milestone**
|
|
290
258
|
|
|
291
|
-
|
|
259
|
+
Run:
|
|
292
260
|
|
|
293
261
|
```bash
|
|
294
262
|
gh issue view {issue-number} --json milestone --jq '.milestone.title // empty'
|
|
295
263
|
```
|
|
296
264
|
|
|
297
|
-
|
|
265
|
+
If the result is non-empty, preserve the existing milestone and record `Milestone: {existing} (preserved)`, then skip the remaining milestone-sync steps.
|
|
298
266
|
|
|
299
|
-
**b)
|
|
267
|
+
**b) Check whether task.md explicitly sets `milestone`**
|
|
300
268
|
|
|
301
|
-
|
|
302
|
-
|
|
269
|
+
If the frontmatter in task.md contains a non-empty `milestone` field, use it as the target milestone.
|
|
270
|
+
This field should contain a line milestone title or `General Backlog`; do not automatically set a specific version milestone here.
|
|
303
271
|
|
|
304
|
-
**c)
|
|
272
|
+
**c) Infer the target line milestone**
|
|
305
273
|
|
|
306
|
-
|
|
274
|
+
When task.md does not explicitly set `milestone`, infer it in this order:
|
|
307
275
|
|
|
308
|
-
1.
|
|
276
|
+
1. Detect the current branch:
|
|
309
277
|
|
|
310
278
|
```bash
|
|
311
279
|
git branch --show-current
|
|
312
280
|
```
|
|
313
281
|
|
|
314
|
-
-
|
|
282
|
+
- If the branch name matches `{major}.{minor}.x`, the target milestone is the same line milestone `{major}.{minor}.x`
|
|
315
283
|
|
|
316
|
-
2.
|
|
284
|
+
2. If the current branch is `main` or `master`, detect existing release branches:
|
|
317
285
|
|
|
318
286
|
```bash
|
|
319
287
|
git branch -a | grep -oE '[0-9]+\.[0-9]+\.x' | sort -V | tail -1
|
|
320
288
|
```
|
|
321
289
|
|
|
322
|
-
-
|
|
323
|
-
-
|
|
290
|
+
- If the highest release branch is `X.Y.x`, the target milestone is `(X+1).0.x`
|
|
291
|
+
- If no release branch exists, read the latest tag:
|
|
324
292
|
|
|
325
293
|
```bash
|
|
326
294
|
git tag --list 'v*' --sort=-v:refname | head -1
|
|
327
295
|
```
|
|
328
296
|
|
|
329
|
-
-
|
|
297
|
+
- When the latest tag exists and can be parsed as `X.Y.Z`, the target milestone is `X.Y.x`
|
|
330
298
|
|
|
331
|
-
3.
|
|
299
|
+
3. If none of the above yields a result, fall back to `General Backlog`
|
|
332
300
|
|
|
333
|
-
**d)
|
|
301
|
+
**d) Find the target milestone number**
|
|
334
302
|
|
|
335
|
-
|
|
303
|
+
Run:
|
|
336
304
|
|
|
337
305
|
```bash
|
|
338
306
|
gh api "repos/$repo/milestones" --paginate \
|
|
339
307
|
--jq '.[] | select(.title=="{target}") | .number'
|
|
340
308
|
```
|
|
341
309
|
|
|
342
|
-
-
|
|
343
|
-
-
|
|
310
|
+
- If the target milestone does not exist, fall back to `General Backlog`
|
|
311
|
+
- If `General Backlog` also does not exist, record `Milestone: skipped (not found)` and skip assignment
|
|
344
312
|
|
|
345
|
-
**e)
|
|
313
|
+
**e) Assign the Issue to the milestone**
|
|
346
314
|
|
|
347
|
-
|
|
315
|
+
Once a target milestone number is found, run:
|
|
348
316
|
|
|
349
317
|
```bash
|
|
350
318
|
gh api "repos/$repo/issues/{issue-number}" -X PATCH -F milestone={milestone-number}
|
|
351
319
|
```
|
|
352
320
|
|
|
353
|
-
|
|
354
|
-
- `Milestone: {target} (assigned)`
|
|
321
|
+
Record:
|
|
322
|
+
- `Milestone: {target} (assigned)` or
|
|
355
323
|
- `Milestone: General Backlog (fallback)`
|
|
356
324
|
|
|
357
|
-
### 9.
|
|
325
|
+
### 9. Fetch Existing Comments and Build the Published Artifact Set
|
|
358
326
|
|
|
359
|
-
|
|
327
|
+
Fetch all Issue comments in one pass, then build the set of published artifact stems from hidden markers and construct the local timeline of artifacts to publish.
|
|
360
328
|
|
|
361
|
-
|
|
329
|
+
First fetch comments (preserving comment id and body):
|
|
362
330
|
|
|
363
331
|
```bash
|
|
364
332
|
comments_jsonl="$(mktemp)"
|
|
@@ -368,38 +336,38 @@ gh api "repos/$repo/issues/{issue-number}/comments" \
|
|
|
368
336
|
--jq '.[] | {id, body}' > "$comments_jsonl"
|
|
369
337
|
```
|
|
370
338
|
|
|
371
|
-
|
|
339
|
+
Extract all Activity Log records in `task.md` that end with `→ {filename}`.
|
|
372
340
|
|
|
373
|
-
|
|
374
|
-
-
|
|
375
|
-
-
|
|
376
|
-
-
|
|
377
|
-
- `summary`
|
|
378
|
-
- `summary`
|
|
341
|
+
Parsing rules:
|
|
342
|
+
- Use the regex `/→\s+(\S+\.md)\s*$/` to extract filenames
|
|
343
|
+
- remove the `.md` suffix to get `{file-stem}`
|
|
344
|
+
- build the artifact timeline in Activity Log order
|
|
345
|
+
- append `summary` as a fixed final artifact at the end of the timeline
|
|
346
|
+
- `summary` is always last
|
|
379
347
|
|
|
380
|
-
|
|
348
|
+
Only include files that still exist in the task directory in the publish set. Skip missing files without error.
|
|
381
349
|
|
|
382
|
-
|
|
350
|
+
The first line of every sync comment must include a hidden marker:
|
|
383
351
|
|
|
384
352
|
```html
|
|
385
353
|
<!-- sync-issue:{task-id}:{file-stem} -->
|
|
386
354
|
```
|
|
387
355
|
|
|
388
|
-
|
|
356
|
+
Where `{file-stem}` is the filename without the `.md` suffix, for example `analysis`, `plan`, `implementation`, `implementation-r2`, or `review-r3`. `summary` still uses the literal `summary`.
|
|
389
357
|
|
|
390
|
-
|
|
358
|
+
Timeline example:
|
|
391
359
|
`analysis → plan → implementation → review → refinement → analysis-r2 → plan-r2 → implementation-r2 → review-r2 → summary`
|
|
392
360
|
|
|
393
|
-
|
|
361
|
+
For each `{file-stem}`, determine whether it has already been published with a local check:
|
|
394
362
|
|
|
395
363
|
```bash
|
|
396
364
|
grep -qF "<!-- sync-issue:{task-id}:{file-stem} -->" "$comments_jsonl"
|
|
397
365
|
```
|
|
398
366
|
|
|
399
|
-
-
|
|
400
|
-
-
|
|
367
|
+
- match found: this artifact has already been published and should be skipped by default
|
|
368
|
+
- no match: this artifact has not been published yet and can create a new comment
|
|
401
369
|
|
|
402
|
-
|
|
370
|
+
For the `summary` artifact, also extract the comment id for later updates:
|
|
403
371
|
|
|
404
372
|
```bash
|
|
405
373
|
summary_comment_id="$(
|
|
@@ -408,92 +376,92 @@ summary_comment_id="$(
|
|
|
408
376
|
)"
|
|
409
377
|
```
|
|
410
378
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
-
|
|
415
|
-
-
|
|
379
|
+
Before finishing Step 9, precompute `has_unpublished_artifacts` from the published/unpublished results above: whether any non-`summary` artifact remains unpublished. Keep this value fixed during Step 10. It is only used to decide whether `summary` should be updated in place or deleted and rebuilt at the end.
|
|
380
|
+
|
|
381
|
+
Idempotency requirements:
|
|
382
|
+
- On the first run, publish comments only for artifacts that currently exist
|
|
383
|
+
- On the second run, skip already published files and only publish new artifacts (for example `implementation-r2`, `review-r2`)
|
|
384
|
+
- If all artifact file comments have already been published and the `summary` content has not changed, publish no new comments
|
|
385
|
+
- If `summary` is already published but the delivery state has changed: delete the old `summary` and recreate it at the end when new artifacts are published this run; otherwise update the existing comment in place when no new artifacts are published
|
|
416
386
|
|
|
417
|
-
### 10.
|
|
387
|
+
### 10. Publish Context Files One by One in Timeline Order
|
|
418
388
|
|
|
419
|
-
|
|
389
|
+
Process the sorted artifact list from Step 9 one item at a time. Do not fall back to a fixed 5-step order, and do not merge multiple rounds of the same artifact type into a single comment.
|
|
420
390
|
|
|
421
|
-
**a)
|
|
391
|
+
**a) Prepare comment content for each artifact**
|
|
422
392
|
|
|
423
|
-
- `analysis
|
|
424
|
-
- `plan
|
|
425
|
-
- `analysis-r{N}
|
|
426
|
-
- `implementation
|
|
427
|
-
- `refinement
|
|
428
|
-
- `review
|
|
429
|
-
- `summary
|
|
393
|
+
- `analysis`: publish the full text of `analysis.md`
|
|
394
|
+
- `plan`: publish the full text of `plan.md`
|
|
395
|
+
- `analysis-r{N}`, `plan-r{N}`: publish one comment per file, using the artifact's original content as the comment body
|
|
396
|
+
- `implementation`, `implementation-r{N}`: publish one comment per file, using the corresponding implementation report as-is
|
|
397
|
+
- `refinement`, `refinement-r{N}`: publish one comment per file, using the corresponding refinement report as-is
|
|
398
|
+
- `review`, `review-r{N}`: publish one comment per file, using the corresponding review report as-is
|
|
399
|
+
- `summary`: generate a concise delivery summary that includes only the current delivery state and absolute GitHub links
|
|
430
400
|
|
|
431
|
-
|
|
401
|
+
All artifacts except `summary` must publish the original content directly. Do not compress them into another summary.
|
|
432
402
|
|
|
433
|
-
|
|
403
|
+
Use the same format for every comment:
|
|
434
404
|
|
|
435
405
|
```markdown
|
|
436
406
|
<!-- sync-issue:{task-id}:{file-stem} -->
|
|
437
|
-
## {
|
|
407
|
+
## {artifact title}
|
|
438
408
|
|
|
439
|
-
{
|
|
409
|
+
{original content or summary content}
|
|
440
410
|
|
|
441
411
|
---
|
|
442
|
-
|
|
443
|
-
```
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
- `analysis` ->
|
|
447
|
-
- `analysis-r2` ->
|
|
448
|
-
- `analysis-r{N}` ->
|
|
449
|
-
- `plan` ->
|
|
450
|
-
- `plan-r2` ->
|
|
451
|
-
- `plan-r{N}` ->
|
|
452
|
-
- `implementation` ->
|
|
453
|
-
- `implementation-r2` ->
|
|
454
|
-
- `implementation-r{N}` ->
|
|
455
|
-
- `refinement` ->
|
|
456
|
-
- `refinement-r2` ->
|
|
457
|
-
- `refinement-r{N}` ->
|
|
458
|
-
- `review` ->
|
|
459
|
-
- `review-r2` ->
|
|
460
|
-
- `review-r{N}` ->
|
|
461
|
-
- `summary` ->
|
|
462
|
-
|
|
463
|
-
`summary`
|
|
412
|
+
*Generated by AI · Internal tracking: {task-id}*
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
Recommended title mapping:
|
|
416
|
+
- `analysis` -> `Requirements Analysis`
|
|
417
|
+
- `analysis-r2` -> `Requirements Analysis (Round 2)`
|
|
418
|
+
- `analysis-r{N}` -> `Requirements Analysis (Round {N})`
|
|
419
|
+
- `plan` -> `Technical Plan`
|
|
420
|
+
- `plan-r2` -> `Technical Plan (Round 2)`
|
|
421
|
+
- `plan-r{N}` -> `Technical Plan (Round {N})`
|
|
422
|
+
- `implementation` -> `Implementation Report (Round 1)`
|
|
423
|
+
- `implementation-r2` -> `Implementation Report (Round 2)`
|
|
424
|
+
- `implementation-r{N}` -> `Implementation Report (Round {N})`
|
|
425
|
+
- `refinement` -> `Refinement Report (Round 1)`
|
|
426
|
+
- `refinement-r2` -> `Refinement Report (Round 2)`
|
|
427
|
+
- `refinement-r{N}` -> `Refinement Report (Round {N})`
|
|
428
|
+
- `review` -> `Review Report (Round 1)`
|
|
429
|
+
- `review-r2` -> `Review Report (Round 2)`
|
|
430
|
+
- `review-r{N}` -> `Review Report (Round {N})`
|
|
431
|
+
- `summary` -> `Delivery Summary`
|
|
432
|
+
|
|
433
|
+
Recommended `summary` comment format:
|
|
464
434
|
|
|
465
435
|
```markdown
|
|
466
436
|
<!-- sync-issue:{task-id}:summary -->
|
|
467
|
-
##
|
|
437
|
+
## Delivery Summary
|
|
468
438
|
|
|
469
|
-
|
|
470
|
-
|
|
439
|
+
**Updated at**: {current time}
|
|
440
|
+
**Status**: {formatted status description}
|
|
471
441
|
|
|
472
|
-
|
|
|
442
|
+
| Type | Content |
|
|
473
443
|
|---|---|
|
|
474
|
-
|
|
|
475
|
-
| Commit | [`{commit-short}`](https://github.com/{owner}/{repo}/commit/{commit-hash})
|
|
476
|
-
| PR | [#{pr-number}](https://github.com/{owner}/{repo}/pull/{pr-number}) 或 `N/A` |
|
|
477
|
-
| Issue | `{issue-state}` |
|
|
444
|
+
| Branch | `{branch or N/A}` |
|
|
445
|
+
| Commit | [`{commit-short}`](https://github.com/{owner}/{repo}/commit/{commit-hash}) or `N/A` |
|
|
478
446
|
|
|
479
447
|
---
|
|
480
|
-
|
|
448
|
+
*Generated by AI · Internal tracking: {task-id}*
|
|
481
449
|
```
|
|
482
450
|
|
|
483
|
-
|
|
484
|
-
-
|
|
485
|
-
-
|
|
486
|
-
-
|
|
451
|
+
Formatted status description rules:
|
|
452
|
+
- Mode A: `✅ Completed`
|
|
453
|
+
- Mode B: `PR stage`
|
|
454
|
+
- Mode C: `In development, current step is {current_step}`
|
|
487
455
|
|
|
488
|
-
**b)
|
|
456
|
+
**b) Skip already-published or missing artifacts**
|
|
489
457
|
|
|
490
|
-
-
|
|
491
|
-
-
|
|
492
|
-
-
|
|
458
|
+
- For `analysis.md`, `plan.md`, `implementation*.md`, and `review*.md`: skip directly if the corresponding file does not exist, without error
|
|
459
|
+
- For any artifact: skip by default if its marker already exists
|
|
460
|
+
- For `summary`: regenerate candidate content even if its marker already exists, so you can compare whether an update is needed
|
|
493
461
|
|
|
494
|
-
**c)
|
|
462
|
+
**c) Publish a new comment**
|
|
495
463
|
|
|
496
|
-
|
|
464
|
+
When an artifact has not been published yet, run:
|
|
497
465
|
|
|
498
466
|
```bash
|
|
499
467
|
gh issue comment {issue-number} --body "$(cat <<'EOF'
|
|
@@ -502,69 +470,80 @@ EOF
|
|
|
502
470
|
)"
|
|
503
471
|
```
|
|
504
472
|
|
|
505
|
-
**d)
|
|
473
|
+
**d) Publish or rebuild the `summary` comment**
|
|
474
|
+
|
|
475
|
+
`summary` must always remain the last comment. Choose the handling strategy with these rules:
|
|
506
476
|
|
|
507
|
-
|
|
477
|
+
- `summary` does not exist: publish a new `summary` comment using Step 10c
|
|
478
|
+
- `summary` exists and `has_unpublished_artifacts=true`: delete the old `summary` comment first, then publish a new `summary` comment using Step 10c
|
|
479
|
+
- `summary` exists, `has_unpublished_artifacts=false`, and the newly generated content differs from the existing one: update the existing comment in place
|
|
480
|
+
- `summary` exists, `has_unpublished_artifacts=false`, and the content is the same: do nothing
|
|
481
|
+
|
|
482
|
+
To delete the old `summary` comment, run:
|
|
483
|
+
|
|
484
|
+
```bash
|
|
485
|
+
gh api "repos/$repo/issues/comments/{summary_comment_id}" -X DELETE
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
To update an existing `summary` comment in place, run:
|
|
508
489
|
|
|
509
490
|
```bash
|
|
510
|
-
gh api "repos/$repo/issues/comments/{
|
|
491
|
+
gh api "repos/$repo/issues/comments/{summary_comment_id}" -X PATCH -f body="$(cat <<'EOF'
|
|
511
492
|
{comment-body}
|
|
512
493
|
EOF
|
|
513
494
|
)"
|
|
514
495
|
```
|
|
515
496
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
**e) 零操作场景**
|
|
497
|
+
**e) No-op scenario**
|
|
519
498
|
|
|
520
|
-
|
|
521
|
-
-
|
|
522
|
-
-
|
|
499
|
+
If all artifacts are already synced and `summary` does not need an update:
|
|
500
|
+
- publish no new comments
|
|
501
|
+
- explicitly tell the user at the end: `All artifacts are already synced, no new content`
|
|
523
502
|
|
|
524
|
-
### 11.
|
|
503
|
+
### 11. Update Task Status
|
|
525
504
|
|
|
526
|
-
|
|
505
|
+
Get the current time:
|
|
527
506
|
|
|
528
507
|
```bash
|
|
529
508
|
date "+%Y-%m-%d %H:%M:%S"
|
|
530
509
|
```
|
|
531
510
|
|
|
532
|
-
|
|
533
|
-
-
|
|
511
|
+
Add or update the `last_synced_at` field in task.md with `{current time}`.
|
|
512
|
+
- **Append** to `## Activity Log` (do NOT overwrite previous entries):
|
|
534
513
|
```
|
|
535
514
|
- {yyyy-MM-dd HH:mm:ss} — **Sync to Issue** by {agent} — Progress synced to Issue #{issue-number}
|
|
536
515
|
```
|
|
537
516
|
|
|
538
|
-
### 12.
|
|
517
|
+
### 12. Inform User
|
|
539
518
|
|
|
540
519
|
```
|
|
541
|
-
|
|
520
|
+
Progress synced to Issue #{issue-number}.
|
|
542
521
|
|
|
543
|
-
|
|
544
|
-
-
|
|
545
|
-
-
|
|
546
|
-
-
|
|
547
|
-
-
|
|
548
|
-
- Labels
|
|
549
|
-
- Issue Type
|
|
550
|
-
- Milestone
|
|
551
|
-
- Development
|
|
522
|
+
Sync result:
|
|
523
|
+
- New comments published: {count}
|
|
524
|
+
- Comments updated: {count}
|
|
525
|
+
- Steps skipped: {step list or `none`}
|
|
526
|
+
- Current status: {status}
|
|
527
|
+
- Labels: status={status-label or cleared}, in:={added count}
|
|
528
|
+
- Issue Type: {Bug / Feature / Task / skipped}
|
|
529
|
+
- Milestone: {preserved / assigned / fallback / skipped}
|
|
530
|
+
- Development: {Closes link appended / link already existed / no PR, skipped}
|
|
552
531
|
|
|
553
|
-
|
|
532
|
+
View: https://github.com/{owner}/{repo}/issues/{issue-number}
|
|
554
533
|
|
|
555
|
-
|
|
534
|
+
If no comments were published or updated in this run, clearly state: all steps are already synced, no new content.
|
|
556
535
|
```
|
|
557
536
|
|
|
558
|
-
##
|
|
537
|
+
## Notes
|
|
559
538
|
|
|
560
|
-
1.
|
|
561
|
-
2.
|
|
562
|
-
3.
|
|
563
|
-
4.
|
|
539
|
+
1. **Requires an issue number**: task.md must contain `issue_number`. If missing, prompt the user.
|
|
540
|
+
2. **Audience**: `sync-issue` is for stakeholders, while `sync-pr` is for code reviewers. They have different focus areas.
|
|
541
|
+
3. **When to sync**: sync after major stages (analysis, design, implementation, review) or when blocked.
|
|
542
|
+
4. **Avoid noise**: do not sync too frequently. Although this skill uses hidden markers for idempotency, avoid meaningless repeated syncs.
|
|
564
543
|
|
|
565
|
-
##
|
|
544
|
+
## Error Handling
|
|
566
545
|
|
|
567
|
-
-
|
|
568
|
-
-
|
|
569
|
-
- Issue
|
|
570
|
-
- gh
|
|
546
|
+
- Task not found: output "Task {task-id} not found"
|
|
547
|
+
- Missing issue number: output "Task has no issue_number field"
|
|
548
|
+
- Issue not found: output "Issue #{number} not found"
|
|
549
|
+
- `gh` authentication failed: output "Please check GitHub CLI authentication"
|