@fitlab-ai/agent-infra 0.6.0 → 0.6.2-alpha.1

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.
Files changed (93) hide show
  1. package/README.md +12 -12
  2. package/README.zh-CN.md +12 -12
  3. package/bin/cli.ts +5 -1
  4. package/dist/bin/cli.js +6 -1
  5. package/dist/lib/defaults.json +5 -4
  6. package/dist/lib/sandbox/config.js +25 -7
  7. package/dist/lib/sandbox/runtime-engines.js +27 -0
  8. package/dist/package.json +1 -1
  9. package/lib/defaults.json +5 -4
  10. package/lib/sandbox/config.ts +35 -7
  11. package/lib/sandbox/runtime-engines.ts +39 -0
  12. package/package.json +5 -3
  13. package/templates/.agents/README.en.md +8 -8
  14. package/templates/.agents/README.zh-CN.md +8 -8
  15. package/templates/{.claude → .agents}/hooks/check-version-format.sh +3 -3
  16. package/templates/.agents/rules/create-issue.github.en.md +6 -0
  17. package/templates/.agents/rules/create-issue.github.zh-CN.md +6 -0
  18. package/templates/.agents/rules/issue-fields.github.en.md +155 -0
  19. package/templates/.agents/rules/issue-fields.github.zh-CN.md +155 -0
  20. package/templates/.agents/rules/issue-pr-commands.github.en.md +1 -0
  21. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +1 -0
  22. package/templates/.agents/rules/issue-sync.github.en.md +2 -1
  23. package/templates/.agents/rules/issue-sync.github.zh-CN.md +2 -1
  24. package/templates/.agents/rules/release-commands.github.en.md +9 -3
  25. package/templates/.agents/rules/release-commands.github.zh-CN.md +9 -3
  26. package/templates/.agents/rules/task-management.en.md +17 -9
  27. package/templates/.agents/rules/task-management.zh-CN.md +17 -9
  28. package/templates/.agents/rules/testing-discipline.en.md +40 -0
  29. package/templates/.agents/rules/testing-discipline.zh-CN.md +40 -0
  30. package/templates/.agents/rules/version-stamp.en.md +29 -0
  31. package/templates/.agents/rules/version-stamp.zh-CN.md +29 -0
  32. package/templates/.agents/scripts/platform-adapters/platform-sync.github.js +143 -6
  33. package/templates/.agents/scripts/validate-artifact.js +32 -5
  34. package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -0
  35. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -0
  36. package/templates/.agents/skills/analyze-task/config/verify.json +2 -0
  37. package/templates/.agents/skills/block-task/SKILL.en.md +3 -0
  38. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +3 -0
  39. package/templates/.agents/skills/block-task/config/verify.json +1 -0
  40. package/templates/.agents/skills/cancel-task/SKILL.en.md +3 -0
  41. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +3 -0
  42. package/templates/.agents/skills/cancel-task/config/verify.json +1 -0
  43. package/templates/.agents/skills/commit/SKILL.en.md +10 -0
  44. package/templates/.agents/skills/commit/SKILL.zh-CN.md +10 -0
  45. package/templates/.agents/skills/commit/config/verify.json +1 -0
  46. package/templates/.agents/skills/commit/reference/task-status-update.en.md +5 -0
  47. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +5 -0
  48. package/templates/.agents/skills/complete-task/SKILL.en.md +4 -0
  49. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +4 -0
  50. package/templates/.agents/skills/complete-task/config/verify.json +2 -0
  51. package/templates/.agents/skills/create-pr/SKILL.en.md +5 -1
  52. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +5 -1
  53. package/templates/.agents/skills/create-pr/config/verify.json +1 -0
  54. package/templates/.agents/skills/create-release-note/SKILL.en.md +8 -11
  55. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +8 -11
  56. package/templates/.agents/skills/create-task/SKILL.en.md +9 -0
  57. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +9 -0
  58. package/templates/.agents/skills/create-task/config/verify.json +1 -0
  59. package/templates/.agents/skills/implement-task/SKILL.en.md +16 -1
  60. package/templates/.agents/skills/implement-task/SKILL.zh-CN.md +16 -1
  61. package/templates/.agents/skills/implement-task/config/verify.json +2 -0
  62. package/templates/.agents/skills/import-codescan/config/verify.json +1 -0
  63. package/templates/.agents/skills/import-dependabot/config/verify.json +1 -0
  64. package/templates/.agents/skills/import-issue/SKILL.en.md +10 -0
  65. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +10 -0
  66. package/templates/.agents/skills/import-issue/config/verify.json +1 -0
  67. package/templates/.agents/skills/plan-task/SKILL.en.md +3 -0
  68. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +3 -0
  69. package/templates/.agents/skills/plan-task/config/verify.json +2 -0
  70. package/templates/.agents/skills/refine-task/SKILL.en.md +15 -1
  71. package/templates/.agents/skills/refine-task/SKILL.zh-CN.md +15 -1
  72. package/templates/.agents/skills/refine-task/config/verify.json +2 -0
  73. package/templates/.agents/skills/refine-task/reference/fix-workflow.en.md +9 -0
  74. package/templates/.agents/skills/refine-task/reference/fix-workflow.zh-CN.md +9 -0
  75. package/templates/.agents/skills/refine-task/reference/report-template.en.md +11 -0
  76. package/templates/.agents/skills/refine-task/reference/report-template.zh-CN.md +11 -0
  77. package/templates/.agents/skills/restore-task/SKILL.en.md +3 -0
  78. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +3 -0
  79. package/templates/.agents/skills/restore-task/config/verify.json +1 -0
  80. package/templates/.agents/skills/review-task/SKILL.en.md +16 -1
  81. package/templates/.agents/skills/review-task/SKILL.zh-CN.md +16 -1
  82. package/templates/.agents/skills/review-task/config/verify.json +3 -0
  83. package/templates/.agents/skills/review-task/reference/output-templates.en.md +20 -5
  84. package/templates/.agents/skills/review-task/reference/output-templates.zh-CN.md +20 -5
  85. package/templates/.agents/skills/review-task/reference/report-template.en.md +13 -0
  86. package/templates/.agents/skills/review-task/reference/report-template.zh-CN.md +13 -0
  87. package/templates/.agents/skills/review-task/reference/review-criteria.en.md +18 -0
  88. package/templates/.agents/skills/review-task/reference/review-criteria.zh-CN.md +18 -0
  89. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +5 -4
  90. package/templates/.agents/templates/task.en.md +5 -0
  91. package/templates/.agents/templates/task.zh-CN.md +5 -0
  92. package/templates/.claude/settings.json +1 -1
  93. package/templates/.codex/hooks.json +17 -0
@@ -0,0 +1,155 @@
1
+ # Issue Fields
2
+
3
+ Read this file before writing or verifying Issue Type pinned custom fields.
4
+
5
+ ## Boundary
6
+
7
+ - Use this rule only after `upstream_repo`, `has_push`, and the Issue number are known.
8
+ - If `has_push=false`, skip direct field writes and continue.
9
+ - Fetch the organization's current Issue Type schema before each write; do not hard-code the field set.
10
+ - Missing, empty, or unresolvable values are skipped. Field writes are best-effort and must not block the workflow.
11
+
12
+ ## Supported Task Frontmatter
13
+
14
+ All fields are optional:
15
+
16
+ | task.md field | Issue field | Value format |
17
+ |---|---|---|
18
+ | `priority` | `Priority` | `Urgent`, `High`, `Medium`, or `Low` |
19
+ | `effort` | `Effort` | `High`, `Medium`, or `Low` |
20
+ | `start_date` | `Start date` | `YYYY-MM-DD` |
21
+ | `target_date` | `Target date` | `YYYY-MM-DD` |
22
+
23
+ Localized option input may be normalized before writing:
24
+
25
+ | Input | Stored option |
26
+ |---|---|
27
+ | `紧急` | `Urgent` |
28
+ | `高` | `High` |
29
+ | `中` | `Medium` |
30
+ | `低` | `Low` |
31
+
32
+ AI agents may infer `priority` and `effort` from the title and description when creating or refining tasks, but must keep date fields empty unless the user or source Issue provides explicit dates. Human edits in `task.md` take precedence.
33
+
34
+ ## GraphQL Reference
35
+
36
+ Read Issue Type pinned fields:
37
+
38
+ ```graphql
39
+ query($owner:String!){
40
+ organization(login:$owner){ issueTypes(first:20){ nodes{
41
+ id name
42
+ pinnedFields{
43
+ __typename
44
+ ... on IssueFieldSingleSelect{ id name options{ id name } }
45
+ ... on IssueFieldDate{ id name }
46
+ ... on IssueFieldText{ id name }
47
+ ... on IssueFieldNumber{ id name }
48
+ }
49
+ } } }
50
+ }
51
+ ```
52
+
53
+ Read one Issue's current type and field values:
54
+
55
+ ```graphql
56
+ query($owner:String!,$name:String!,$number:Int!){
57
+ repository(owner:$owner,name:$name){ issue(number:$number){
58
+ id
59
+ issueType{ name pinnedFields{
60
+ __typename
61
+ ... on IssueFieldSingleSelect{ id name options{ id name } }
62
+ ... on IssueFieldDate{ id name }
63
+ ... on IssueFieldText{ id name }
64
+ ... on IssueFieldNumber{ id name }
65
+ } }
66
+ issueFieldValues(first:50){ nodes{
67
+ __typename
68
+ ... on IssueFieldSingleSelectValue{ name optionId field{ ... on IssueFieldSingleSelect{ name } } }
69
+ ... on IssueFieldDateValue{ value field{ ... on IssueFieldDate{ name } } }
70
+ ... on IssueFieldTextValue{ value field{ ... on IssueFieldText{ name } } }
71
+ ... on IssueFieldNumberValue{ value field{ ... on IssueFieldNumber{ name } } }
72
+ } }
73
+ } }
74
+ }
75
+ ```
76
+
77
+ Write or clear fields and update Issue Type:
78
+
79
+ ```graphql
80
+ mutation($issueId:ID!,$issueFields:[IssueFieldCreateOrUpdateInput!]!){
81
+ setIssueFieldValue(input:{issueId:$issueId,issueFields:$issueFields}){ issue{ id } }
82
+ }
83
+
84
+ mutation($issueId:ID!,$issueTypeId:ID){
85
+ updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$issueTypeId}){ issue{ id } }
86
+ }
87
+ ```
88
+
89
+ `IssueFieldCreateOrUpdateInput` supports `fieldId`, `singleSelectOptionId`, `dateValue`, `textValue`, `numberValue`, and `delete`.
90
+
91
+ Minimal command shells:
92
+
93
+ ```bash
94
+ gh api graphql \
95
+ -f query='query($owner:String!){organization(login:$owner){issueTypes(first:20){nodes{id name pinnedFields{__typename ... on IssueFieldSingleSelect{id name options{id name}} ... on IssueFieldDate{id name} ... on IssueFieldText{id name} ... on IssueFieldNumber{id name}}}}}}' \
96
+ -F owner="{owner}"
97
+
98
+ gh api graphql \
99
+ -f query='query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){issue(number:$number){id issueType{name pinnedFields{__typename ... on IssueFieldSingleSelect{id name options{id name}} ... on IssueFieldDate{id name} ... on IssueFieldText{id name} ... on IssueFieldNumber{id name}}} issueFieldValues(first:50){nodes{__typename ... on IssueFieldSingleSelectValue{name optionId field{... on IssueFieldSingleSelect{name}}} ... on IssueFieldDateValue{value field{... on IssueFieldDate{name}}} ... on IssueFieldTextValue{value field{... on IssueFieldText{name}}} ... on IssueFieldNumberValue{value field{... on IssueFieldNumber{name}}}}}}}}' \
100
+ -F owner="{owner}" -F name="{repo}" -F number="{issue-number}"
101
+
102
+ gh api graphql --input - <<'JSON'
103
+ {
104
+ "query": "mutation($issueId:ID!,$issueFields:[IssueFieldCreateOrUpdateInput!]!){setIssueFieldValue(input:{issueId:$issueId,issueFields:$issueFields}){issue{id}}}",
105
+ "variables": {
106
+ "issueId": "{issue-id}",
107
+ "issueFields": [
108
+ { "fieldId": "{field-id}", "singleSelectOptionId": "{option-id}" },
109
+ { "fieldId": "{date-field-id}", "dateValue": "YYYY-MM-DD" },
110
+ { "fieldId": "{old-field-id}", "delete": true }
111
+ ]
112
+ }
113
+ }
114
+ JSON
115
+
116
+ gh api graphql --input - <<'JSON'
117
+ {
118
+ "query": "mutation($issueId:ID!,$issueTypeId:ID){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$issueTypeId}){issue{id}}}",
119
+ "variables": {
120
+ "issueId": "{issue-id}",
121
+ "issueTypeId": "{issue-type-id}"
122
+ }
123
+ }
124
+ JSON
125
+ ```
126
+
127
+ Values not listed in the localization table are treated as literal option names, which is intended for canonical English input.
128
+
129
+ ## Flow A: Write Fields After Issue Creation
130
+
131
+ 1. Stop if `has_push` is not `true`.
132
+ 2. Resolve `{owner}` from `$upstream_repo` and query `organization.issueTypes`.
133
+ 3. Select the target Issue Type's `pinnedFields`.
134
+ 4. Read non-empty `priority`, `effort`, `start_date`, and `target_date` values from `task.md`.
135
+ 5. For each value:
136
+ - Skip it when the target type does not pin a same-name field.
137
+ - For single-select fields, normalize localized input and match the option by name.
138
+ - For date fields, write only `YYYY-MM-DD` values.
139
+ 6. Submit one `setIssueFieldValue` mutation with all resolved inputs. If no input remains, skip.
140
+
141
+ ## Flow B: Set Type And Migrate Fields
142
+
143
+ Use this flow whenever an existing Issue Type is changed.
144
+
145
+ 1. Stop if `has_push` is not `true`.
146
+ 2. Read the Issue id, current Issue Type, pinned fields, and current field values.
147
+ 3. Query the organization Issue Type list and resolve the target Issue Type id.
148
+ 4. Run `updateIssueIssueType` with the target Issue Type id.
149
+ 5. Resolve the target type's pinned fields.
150
+ 6. For each old field value:
151
+ - If the target type has a same-name field, write the value again. For single-select values, resolve the target option id by option name.
152
+ - If the target type does not have a same-name field, send `{ fieldId, delete: true }` for the old field.
153
+ 7. Submit one `setIssueFieldValue` mutation with all migration inputs. Empty migrations are skipped.
154
+
155
+ Both flows are idempotent. Rewriting an unchanged value or deleting an already empty field is acceptable.
@@ -0,0 +1,155 @@
1
+ # Issue 字段
2
+
3
+ 写入或校验 Issue Type pinned custom fields 前先读取本文件。
4
+
5
+ ## 边界
6
+
7
+ - 仅在已知 `upstream_repo`、`has_push` 和 Issue 编号后使用本规则。
8
+ - 如果 `has_push=false`,跳过直接字段写入并继续流程。
9
+ - 每次写入前都读取组织当前 Issue Type schema;不要硬编码字段集合。
10
+ - 缺失、空值或无法解析的值直接跳过。字段写入是 best-effort,不应阻断工作流。
11
+
12
+ ## 支持的 task.md frontmatter
13
+
14
+ 所有字段均可选:
15
+
16
+ | task.md 字段 | Issue 字段 | 值格式 |
17
+ |---|---|---|
18
+ | `priority` | `Priority` | `Urgent`、`High`、`Medium` 或 `Low` |
19
+ | `effort` | `Effort` | `High`、`Medium` 或 `Low` |
20
+ | `start_date` | `Start date` | `YYYY-MM-DD` |
21
+ | `target_date` | `Target date` | `YYYY-MM-DD` |
22
+
23
+ 写入前可规范化本地化选项:
24
+
25
+ | 输入 | 写入选项 |
26
+ |---|---|
27
+ | `紧急` | `Urgent` |
28
+ | `高` | `High` |
29
+ | `中` | `Medium` |
30
+ | `低` | `Low` |
31
+
32
+ AI agent 在创建或修订任务时可根据标题与描述推断 `priority` 和 `effort`,但除非用户或来源 Issue 明确提供日期,否则必须保持日期字段为空。`task.md` 中人工填写的值优先。
33
+
34
+ ## GraphQL 参考
35
+
36
+ 读取 Issue Type pinned fields:
37
+
38
+ ```graphql
39
+ query($owner:String!){
40
+ organization(login:$owner){ issueTypes(first:20){ nodes{
41
+ id name
42
+ pinnedFields{
43
+ __typename
44
+ ... on IssueFieldSingleSelect{ id name options{ id name } }
45
+ ... on IssueFieldDate{ id name }
46
+ ... on IssueFieldText{ id name }
47
+ ... on IssueFieldNumber{ id name }
48
+ }
49
+ } } }
50
+ }
51
+ ```
52
+
53
+ 读取单个 Issue 的当前 type 与字段值:
54
+
55
+ ```graphql
56
+ query($owner:String!,$name:String!,$number:Int!){
57
+ repository(owner:$owner,name:$name){ issue(number:$number){
58
+ id
59
+ issueType{ name pinnedFields{
60
+ __typename
61
+ ... on IssueFieldSingleSelect{ id name options{ id name } }
62
+ ... on IssueFieldDate{ id name }
63
+ ... on IssueFieldText{ id name }
64
+ ... on IssueFieldNumber{ id name }
65
+ } }
66
+ issueFieldValues(first:50){ nodes{
67
+ __typename
68
+ ... on IssueFieldSingleSelectValue{ name optionId field{ ... on IssueFieldSingleSelect{ name } } }
69
+ ... on IssueFieldDateValue{ value field{ ... on IssueFieldDate{ name } } }
70
+ ... on IssueFieldTextValue{ value field{ ... on IssueFieldText{ name } } }
71
+ ... on IssueFieldNumberValue{ value field{ ... on IssueFieldNumber{ name } } }
72
+ } }
73
+ } }
74
+ }
75
+ ```
76
+
77
+ 写入或清空字段,以及更新 Issue Type:
78
+
79
+ ```graphql
80
+ mutation($issueId:ID!,$issueFields:[IssueFieldCreateOrUpdateInput!]!){
81
+ setIssueFieldValue(input:{issueId:$issueId,issueFields:$issueFields}){ issue{ id } }
82
+ }
83
+
84
+ mutation($issueId:ID!,$issueTypeId:ID){
85
+ updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$issueTypeId}){ issue{ id } }
86
+ }
87
+ ```
88
+
89
+ `IssueFieldCreateOrUpdateInput` 支持 `fieldId`、`singleSelectOptionId`、`dateValue`、`textValue`、`numberValue` 和 `delete`。
90
+
91
+ 最小命令壳:
92
+
93
+ ```bash
94
+ gh api graphql \
95
+ -f query='query($owner:String!){organization(login:$owner){issueTypes(first:20){nodes{id name pinnedFields{__typename ... on IssueFieldSingleSelect{id name options{id name}} ... on IssueFieldDate{id name} ... on IssueFieldText{id name} ... on IssueFieldNumber{id name}}}}}}' \
96
+ -F owner="{owner}"
97
+
98
+ gh api graphql \
99
+ -f query='query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){issue(number:$number){id issueType{name pinnedFields{__typename ... on IssueFieldSingleSelect{id name options{id name}} ... on IssueFieldDate{id name} ... on IssueFieldText{id name} ... on IssueFieldNumber{id name}}} issueFieldValues(first:50){nodes{__typename ... on IssueFieldSingleSelectValue{name optionId field{... on IssueFieldSingleSelect{name}}} ... on IssueFieldDateValue{value field{... on IssueFieldDate{name}}} ... on IssueFieldTextValue{value field{... on IssueFieldText{name}}} ... on IssueFieldNumberValue{value field{... on IssueFieldNumber{name}}}}}}}}' \
100
+ -F owner="{owner}" -F name="{repo}" -F number="{issue-number}"
101
+
102
+ gh api graphql --input - <<'JSON'
103
+ {
104
+ "query": "mutation($issueId:ID!,$issueFields:[IssueFieldCreateOrUpdateInput!]!){setIssueFieldValue(input:{issueId:$issueId,issueFields:$issueFields}){issue{id}}}",
105
+ "variables": {
106
+ "issueId": "{issue-id}",
107
+ "issueFields": [
108
+ { "fieldId": "{field-id}", "singleSelectOptionId": "{option-id}" },
109
+ { "fieldId": "{date-field-id}", "dateValue": "YYYY-MM-DD" },
110
+ { "fieldId": "{old-field-id}", "delete": true }
111
+ ]
112
+ }
113
+ }
114
+ JSON
115
+
116
+ gh api graphql --input - <<'JSON'
117
+ {
118
+ "query": "mutation($issueId:ID!,$issueTypeId:ID){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$issueTypeId}){issue{id}}}",
119
+ "variables": {
120
+ "issueId": "{issue-id}",
121
+ "issueTypeId": "{issue-type-id}"
122
+ }
123
+ }
124
+ JSON
125
+ ```
126
+
127
+ 未列入本地化映射表的值会按字面量 option name 处理;这是为了支持规范英文输入。
128
+
129
+ ## 流程 A:创建 Issue 后写入字段
130
+
131
+ 1. 如果 `has_push` 不是 `true`,停止本流程。
132
+ 2. 从 `$upstream_repo` 解析 `{owner}`,查询 `organization.issueTypes`。
133
+ 3. 选择目标 Issue Type 的 `pinnedFields`。
134
+ 4. 从 `task.md` 读取非空的 `priority`、`effort`、`start_date` 和 `target_date`。
135
+ 5. 对每个值:
136
+ - 目标 type 未 pin 同名字段时跳过。
137
+ - single-select 字段先规范化本地化输入,再按 option name 匹配。
138
+ - date 字段只写入 `YYYY-MM-DD` 值。
139
+ 6. 用所有已解析 input 一次性提交 `setIssueFieldValue` mutation。没有 input 时跳过。
140
+
141
+ ## 流程 B:设置 Type 并迁移字段
142
+
143
+ 现有 Issue Type 发生变更时使用本流程。
144
+
145
+ 1. 如果 `has_push` 不是 `true`,停止本流程。
146
+ 2. 读取 Issue id、当前 Issue Type、pinned fields 和当前字段值。
147
+ 3. 查询组织 Issue Type 列表,解析目标 Issue Type id。
148
+ 4. 用目标 Issue Type id 执行 `updateIssueIssueType`。
149
+ 5. 解析目标 type 的 pinned fields。
150
+ 6. 对每个旧字段值:
151
+ - 目标 type 有同名字段时重新写入该值。single-select 值按 option name 在目标 type 中重新解析 option id。
152
+ - 目标 type 没有同名字段时,对旧字段发送 `{ fieldId, delete: true }`。
153
+ 7. 用所有迁移 input 一次性提交 `setIssueFieldValue` mutation。迁移 input 为空时跳过。
154
+
155
+ 两个流程均应保持幂等。重复写入未变化的值或删除已为空字段都是可接受的。
@@ -88,6 +88,7 @@ gh api "repos/$upstream_repo/issues/{issue-number}" -X PATCH -f type="{issue-typ
88
88
  ```
89
89
 
90
90
  - set the Issue Type only when `has_push=true`; otherwise skip and continue
91
+ - when changing an existing Issue Type, read `.agents/rules/issue-fields.md` and use Flow B so same-name pinned fields are migrated and fields absent from the new type are cleared
91
92
 
92
93
  ## Update Issues
93
94
 
@@ -88,6 +88,7 @@ gh api "repos/$upstream_repo/issues/{issue-number}" -X PATCH -f type="{issue-typ
88
88
  ```
89
89
 
90
90
  - 仅当 `has_push=true` 时执行 Issue Type 设置;否则跳过并继续
91
+ - 变更现有 Issue Type 时,先读取 `.agents/rules/issue-fields.md` 并使用流程 B,确保同名 pinned fields 迁移,且新 type 不包含的字段被清空
91
92
 
92
93
  ## Issue 更新
93
94
 
@@ -48,6 +48,7 @@ Operation-to-permission mapping:
48
48
  | add/remove milestones | `has_triage` | same as above |
49
49
  | edit Issue body | `has_triage` | used by requirement checkbox sync |
50
50
  | set Issue Type | `has_push` | requires write permission |
51
+ | set Issue fields | `has_push` | pinned custom fields; failures are non-blocking |
51
52
  | set assignee | no check | skip directly when it fails |
52
53
  | publish/update comments | no check | allowed for authenticated users in public repositories |
53
54
 
@@ -55,7 +56,7 @@ Operation-to-permission mapping:
55
56
 
56
57
  | Level | Operation type | With permission | Without permission |
57
58
  |------|---------|--------|--------|
58
- | silent degradation | label / milestone / Issue Type | run the `gh` command directly and also update the task comment | skip direct `gh` writes, update only the task comment, let the bot backfill |
59
+ | silent degradation | label / milestone / Issue Type / Issue fields | run the `gh` command directly and also update the task comment | skip direct `gh` writes, update only the task comment, let the bot backfill |
59
60
  | direct skip | assignee | run the `gh` command directly | do nothing else |
60
61
  | normal execution | comments | run normally | run normally |
61
62
 
@@ -48,6 +48,7 @@ has_push=$(printf '%s' "$repo_perms" | grep -q '"push":true' 2>/dev/null && echo
48
48
  | 设置/移除 milestone | `has_triage` | 同上 |
49
49
  | 编辑 Issue body | `has_triage` | 需求复选框同步使用 |
50
50
  | 设置 Issue Type | `has_push` | 需要 write 权限 |
51
+ | 设置 Issue 字段 | `has_push` | pinned custom fields;失败不阻断 |
51
52
  | 设置 assignee | 不检测 | 无权限时直接跳过 |
52
53
  | 发布/更新评论 | 无需检测 | 公开仓库中认证用户可执行 |
53
54
 
@@ -55,7 +56,7 @@ has_push=$(printf '%s' "$repo_perms" | grep -q '"push":true' 2>/dev/null && echo
55
56
 
56
57
  | 层级 | 操作类型 | 有权限 | 无权限 |
57
58
  |------|---------|--------|--------|
58
- | 静默降级 | label / milestone / Issue Type | 直接执行 `gh` 命令,同时更新 task 留言 | 跳过 `gh` 直接操作,仅更新 task 留言,由 bot 补位 |
59
+ | 静默降级 | label / milestone / Issue Type / Issue 字段 | 直接执行 `gh` 命令,同时更新 task 留言 | 跳过 `gh` 直接操作,仅更新 task 留言,由 bot 补位 |
59
60
  | 直接跳过 | assignee | 直接执行 `gh` 命令 | 不做任何替代 |
60
61
  | 正常执行 | 评论 | 正常执行 | 正常执行 |
61
62
 
@@ -1,6 +1,6 @@
1
1
  # Release Platform Commands
2
2
 
3
- Read this file before loading release history, querying merged PRs, or creating a draft release.
3
+ Read this file before loading release history, querying merged PRs, or publishing the Release notes.
4
4
 
5
5
  ## Query Releases
6
6
 
@@ -37,10 +37,16 @@ gh issue view {issue-number} --json number,title,labels,url,author
37
37
 
38
38
  Map GitHub no-reply emails with this rule: if `Name <email>` contains an email matching `(\d+\+)?(\S+?)@users\.noreply\.github\.com`, use the second capture group lowercased as the login. This covers both `{id}+{login}@users.noreply.github.com` and `{login}@users.noreply.github.com`.
39
39
 
40
- ## Create a Draft Release
40
+ ## Publish the Release Notes
41
+
42
+ The GitHub Release for `v{version}` is created and published automatically by the release workflow so Homebrew bottles have a stable upload target. This command writes the curated notes onto that existing Release, falling back to creating it if it does not exist yet.
41
43
 
42
44
  ```bash
43
- gh release create "v{version}" --draft --title "v{version}" --notes-file "{notes-file}"
45
+ if gh release view "v{version}" >/dev/null 2>&1; then
46
+ gh release edit "v{version}" --notes-file "{notes-file}"
47
+ else
48
+ gh release create "v{version}" --title "v{version}" --notes-file "{notes-file}"
49
+ fi
44
50
  ```
45
51
 
46
52
  If commands fail, stop or escalate according to the calling skill.
@@ -1,6 +1,6 @@
1
1
  # Release 平台命令
2
2
 
3
- 在读取历史 release、查询已合并 PR,或创建 draft release 前先读取本文件。
3
+ 在读取历史 release、查询已合并 PR,或发布 Release notes 前先读取本文件。
4
4
 
5
5
  ## Release 查询
6
6
 
@@ -37,10 +37,16 @@ gh issue view {issue-number} --json number,title,labels,url,author
37
37
 
38
38
  GitHub no-reply 邮箱映射规则:如果 `Name <email>` 中的 email 匹配 `(\d+\+)?(\S+?)@users\.noreply\.github\.com`,使用第二个捕获组的小写形式作为 login。该规则同时覆盖 `{id}+{login}@users.noreply.github.com` 和 `{login}@users.noreply.github.com`。
39
39
 
40
- ## 创建 Draft Release
40
+ ## 发布 Release notes
41
+
42
+ `v{version}` 的 GitHub Release 由 release 工作流自动创建并发布,为 Homebrew bottle 提供稳定的上传落点。本命令把精修后的 notes 写到这个已存在的 Release 上;若 Release 尚不存在则兜底创建。
41
43
 
42
44
  ```bash
43
- gh release create "v{version}" --draft --title "v{version}" --notes-file "{notes-file}"
45
+ if gh release view "v{version}" >/dev/null 2>&1; then
46
+ gh release edit "v{version}" --notes-file "{notes-file}"
47
+ else
48
+ gh release create "v{version}" --title "v{version}" --notes-file "{notes-file}"
49
+ fi
44
50
  ```
45
51
 
46
52
  失败时按调用方规则停止或提示人工介入。
@@ -13,16 +13,24 @@ Map user intent to the corresponding workflow command:
13
13
  ## Task State Management
14
14
 
15
15
  - Update the corresponding `task.md` immediately after every workflow command
16
- - At minimum, synchronize `current_step`, `updated_at`, `assigned_to`, and the current-round artifact reference
16
+ - At minimum, synchronize `current_step`, `updated_at`, `assigned_to`, `agent_infra_version`, and the current-round artifact reference
17
+ - Before updating `agent_infra_version`, read `.agents/rules/version-stamp.md`
17
18
  - Activity Log entries are append-only and must never overwrite history
18
19
 
19
20
  ## Required State Updates by Command
20
21
 
21
- - `import-issue`: update `current_step`, `updated_at`, `assigned_to`
22
- - `analyze-task`: update `current_step`, `updated_at`, `assigned_to`
23
- - `plan-task`: update `current_step`, `updated_at`
24
- - `implement-task`: update `current_step`, `updated_at`
25
- - `review-task`: update `current_step`, `updated_at`
26
- - `refine-task`: update `current_step`, `updated_at`
27
- - `complete-task`: update `status`, `completed_at`, `updated_at`
28
- - `block-task`: update `status`, `blocked_at`, `blocked_reason`
22
+ - `create-task`: create `branch`, `workflow`, `status`, `created_at`, `updated_at`, `assigned_to`, `agent_infra_version`
23
+ - `import-issue`: update `current_step`, `updated_at`, `assigned_to`, `agent_infra_version`
24
+ - `import-codescan`: update `current_step`, `updated_at`, `assigned_to`, `agent_infra_version`
25
+ - `import-dependabot`: update `current_step`, `updated_at`, `assigned_to`, `agent_infra_version`
26
+ - `restore-task`: update `status`, `updated_at`, `assigned_to`, `agent_infra_version`
27
+ - `analyze-task`: update `current_step`, `updated_at`, `assigned_to`, `agent_infra_version`
28
+ - `plan-task`: update `current_step`, `updated_at`, `agent_infra_version`
29
+ - `implement-task`: update `current_step`, `updated_at`, `agent_infra_version`
30
+ - `review-task`: update `current_step`, `updated_at`, `agent_infra_version`
31
+ - `refine-task`: update `current_step`, `updated_at`, `agent_infra_version`
32
+ - `create-pr`: update `pr_number`, `updated_at`, `agent_infra_version`
33
+ - `commit`: update `updated_at`, `agent_infra_version`; update `current_step` when needed (see `commit/reference/task-status-update.md`)
34
+ - `complete-task`: update `status`, `current_step`, `completed_at`, `updated_at`, `agent_infra_version`
35
+ - `block-task`: update `status`, `blocked_at`, `blocked_reason`, `updated_at`, `agent_infra_version`
36
+ - `cancel-task`: update `status`, `cancelled_at`, `cancel_reason`, `updated_at`, `agent_infra_version`
@@ -13,16 +13,24 @@
13
13
  ## 任务状态管理
14
14
 
15
15
  - 每次执行工作流命令后,必须立即更新对应任务的 `task.md`
16
- - 至少同步 `current_step`、`updated_at`、`assigned_to`,以及本轮产物引用
16
+ - 至少同步 `current_step`、`updated_at`、`assigned_to`、`agent_infra_version`,以及本轮产物引用
17
+ - 更新 `agent_infra_version` 前,先读取 `.agents/rules/version-stamp.md`
17
18
  - Activity Log 只能追加,不能覆盖历史记录
18
19
 
19
20
  ## 常见命令的状态更新要求
20
21
 
21
- - `import-issue`:更新 `current_step`、`updated_at`、`assigned_to`
22
- - `analyze-task`:更新 `current_step`、`updated_at`、`assigned_to`
23
- - `plan-task`:更新 `current_step`、`updated_at`
24
- - `implement-task`:更新 `current_step`、`updated_at`
25
- - `review-task`:更新 `current_step`、`updated_at`
26
- - `refine-task`:更新 `current_step`、`updated_at`
27
- - `complete-task`:更新 `status`、`completed_at`、`updated_at`
28
- - `block-task`:更新 `status`、`blocked_at`、`blocked_reason`
22
+ - `create-task`:创建 `branch`、`workflow`、`status`、`created_at`、`updated_at`、`assigned_to`、`agent_infra_version`
23
+ - `import-issue`:更新 `current_step`、`updated_at`、`assigned_to`、`agent_infra_version`
24
+ - `import-codescan`:更新 `current_step`、`updated_at`、`assigned_to`、`agent_infra_version`
25
+ - `import-dependabot`:更新 `current_step`、`updated_at`、`assigned_to`、`agent_infra_version`
26
+ - `restore-task`:更新 `status`、`updated_at`、`assigned_to`、`agent_infra_version`
27
+ - `analyze-task`:更新 `current_step`、`updated_at`、`assigned_to`、`agent_infra_version`
28
+ - `plan-task`:更新 `current_step`、`updated_at`、`agent_infra_version`
29
+ - `implement-task`:更新 `current_step`、`updated_at`、`agent_infra_version`
30
+ - `review-task`:更新 `current_step`、`updated_at`、`agent_infra_version`
31
+ - `refine-task`:更新 `current_step`、`updated_at`、`agent_infra_version`
32
+ - `create-pr`:更新 `pr_number`、`updated_at`、`agent_infra_version`
33
+ - `commit`:更新 `updated_at`、`agent_infra_version`;必要时更新 `current_step`(详见 `commit/reference/task-status-update.md`)
34
+ - `complete-task`:更新 `status`、`current_step`、`completed_at`、`updated_at`、`agent_infra_version`
35
+ - `block-task`:更新 `status`、`blocked_at`、`blocked_reason`、`updated_at`、`agent_infra_version`
36
+ - `cancel-task`:更新 `status`、`cancelled_at`、`cancel_reason`、`updated_at`、`agent_infra_version`
@@ -0,0 +1,40 @@
1
+ # Common Rule - Testing Discipline
2
+
3
+ > This file carries detailed examples for test-writing discipline. AGENTS.md (and CLAUDE.md) keep only concise testing rules and point here to avoid inflating high-frequency context.
4
+
5
+ ## Background
6
+
7
+ A batch of fragile keyword-matching assertions once had to be replaced with structural checks (valid frontmatter, step numbering, reference integrity, zh-CN variants, and size thresholds). Lesson: binding tests to natural-language wording, or using assertions to "remember a deleted concept", creates endless test debt.
8
+
9
+ ## Example: do not add negative assertions when a positive assertion already covers the behavior
10
+
11
+ When a positive assertion already covers the expected behavior, do not add another negative assertion for "the opposite should not appear".
12
+
13
+ Bad:
14
+ ```ts
15
+ assert.match(content, /^name: implement-task$/m); // The positive assertion already covers the expected value.
16
+ assert.doesNotMatch(content, /^name: wrong-name$/m); // Redundant: permanently remembers a value that should not appear.
17
+ ```
18
+
19
+ Good:
20
+ ```ts
21
+ assert.match(content, /^name: implement-task$/m); // The positive assertion is enough.
22
+ ```
23
+
24
+ If the positive assertion passes, the value is correct. The extra negative assertion adds no protection, only maintenance cost, and can become a test that permanently remembers a concept after the feature is gone.
25
+
26
+ ## RED-GREEN-REFACTOR rhythm
27
+
28
+ During implementation, turn the requirement into a test for observable behavior before writing the code:
29
+
30
+ 1. **RED**: First write a failing test that reproduces the requirement or defect, and confirm that it really fails. The test should cover business behavior, inputs and outputs, or user-visible results, not internal implementation details.
31
+ 2. **GREEN**: Write the smallest amount of code needed to make the failing test pass. Do not expand behavior that is not covered by the test or the requirement.
32
+ 3. **REFACTOR**: After the tests are green, clean up names, structure, or duplication; keep the same test set passing before and after the refactor.
33
+
34
+ This mirrors "Goal-Driven Execution" in AGENTS.md: define a verifiable success criterion first, then make the implementation satisfy it.
35
+
36
+ ## Test anti-patterns
37
+
38
+ - **Over-mocking**: Stub only real boundaries such as network, filesystem, time, or randomness; do not mock the logic of the unit under test, or the test only proves that the mock followed the script.
39
+ - **Testing implementation details**: Prefer assertions on public APIs, artifacts, state changes, or error results; avoid assertions on private functions, internal call order, or temporary data structures.
40
+ - **Insufficient assertions**: Assertions must pin down concrete expected values; do not replace checks on key fields, counts, and boundaries with "does not throw" or "result exists".
@@ -0,0 +1,40 @@
1
+ # 通用规则 - 测试编写纪律
2
+
3
+ > 本文件承载测试编写的正反例细节;AGENTS.md(及 CLAUDE.md)的「测试编写规约」只保留精简条目并指向此处,避免高频上下文膨胀。
4
+
5
+ ## 背景
6
+
7
+ 曾有一批脆弱的关键词匹配断言需要整体替换为结构性检查(frontmatter 合法性、步骤编号、引用完整性、zh-CN 变体、体积阈值)。教训:绑定自然语言措辞、或用断言"记住一个已删除概念",都会形成无止境的测试债务。
8
+
9
+ ## 正反例:正向断言已覆盖时,不应再加反向断言
10
+
11
+ 当正向断言已覆盖期望行为,就不要再为"反面不应出现"补一条反向断言。
12
+
13
+ ❌ 反例:
14
+ ```ts
15
+ assert.match(content, /^name: implement-task$/m); // 正向已覆盖期望值
16
+ assert.doesNotMatch(content, /^name: wrong-name$/m); // 多余:永久记住一个不该出现的值
17
+ ```
18
+
19
+ ✅ 正例:
20
+ ```ts
21
+ assert.match(content, /^name: implement-task$/m); // 正向断言已足够
22
+ ```
23
+
24
+ 正向断言通过即证明值正确;额外的反向断言不增加保护,只增加维护成本,并会在功能删除后退化为"测试永久记住一个不再存在的概念"。
25
+
26
+ ## RED-GREEN-REFACTOR 节奏
27
+
28
+ 实现阶段先把需求转成可观察行为的测试,再写代码:
29
+
30
+ 1. **RED**:先写一个能复现需求或缺陷的失败用例,并确认它确实失败。测试应覆盖业务行为、输入输出或用户可见结果,不绑定内部实现细节。
31
+ 2. **GREEN**:写最少代码让失败用例通过。不要顺手扩展未被测试和未被需求覆盖的行为。
32
+ 3. **REFACTOR**:在测试全绿后整理命名、结构或重复代码;重构前后保持同一组测试通过。
33
+
34
+ 这与 AGENTS.md 的「目标驱动执行」一致:先定义可验证成功标准,再让实现满足它。
35
+
36
+ ## 测试反模式
37
+
38
+ - **mock 过度**:只在网络、文件系统、时间、随机数等真实边界打桩;不要 mock 被测对象自身逻辑,否则测试只验证 mock 是否按预设运行。
39
+ - **测试实现细节**:优先断言公开接口、产物、状态变化或错误结果;避免断言私有函数、内部调用顺序、临时数据结构。
40
+ - **断言不充分**:断言必须锁定具体期望值;不要用"只要不抛异常""结果存在即可"替代对关键字段、数量和边界的验证。
@@ -0,0 +1,29 @@
1
+ # General Rule - agent-infra Version Stamp
2
+
3
+ ## When to Write
4
+
5
+ Every time a workflow creates or updates `task.md` frontmatter, also write `agent_infra_version`.
6
+
7
+ This field records the `agent-infra` CLI version that last wrote the task metadata, and is refreshed together with `updated_at`.
8
+
9
+ ## Value Command
10
+
11
+ ```bash
12
+ agent_infra_version=$(ai version --raw 2>/dev/null || echo "unknown")
13
+ ```
14
+
15
+ - On success, write the command output directly, for example `vX.Y.Z` or `vX.Y.Z-alpha.0`
16
+ - Do not add the `v` prefix in the writer
17
+ - If the command fails, write `unknown`
18
+
19
+ ## Frontmatter Field
20
+
21
+ ```yaml
22
+ agent_infra_version: {agent_infra_version}
23
+ ```
24
+
25
+ ## Compatibility
26
+
27
+ - Historical tasks may not have this field; reading or restoring tasks must not block on that alone
28
+ - When present, the value must be `vX.Y.Z`, `vX.Y.Z-prerelease`, a version with SemVer build metadata, or `unknown`
29
+ - Issue / PR comment sync does not need special handling; frontmatter mirroring naturally includes this field
@@ -0,0 +1,29 @@
1
+ # 通用规则 - agent-infra 版本戳
2
+
3
+ ## 写入时机
4
+
5
+ 每次创建或更新 `task.md` frontmatter 时,同步写入 `agent_infra_version`。
6
+
7
+ 该字段表示最后一次写入该任务元数据的 `agent-infra` CLI 版本,与 `updated_at` 同步刷新。
8
+
9
+ ## 取值命令
10
+
11
+ ```bash
12
+ agent_infra_version=$(ai version --raw 2>/dev/null || echo "unknown")
13
+ ```
14
+
15
+ - 命令成功时,值必须直接使用输出结果,例如 `vX.Y.Z` 或 `vX.Y.Z-alpha.0`
16
+ - 不要在写入端自行拼接 `v` 前缀
17
+ - 命令失败时写入 `unknown`
18
+
19
+ ## frontmatter 字段
20
+
21
+ ```yaml
22
+ agent_infra_version: {agent_infra_version}
23
+ ```
24
+
25
+ ## 兼容性
26
+
27
+ - 历史任务可能缺少该字段;读取或恢复任务时不得因此阻塞
28
+ - 字段存在时,值必须是 `vX.Y.Z`、`vX.Y.Z-prerelease`、带 SemVer build 元数据的版本,或 `unknown`
29
+ - 同步 Issue / PR 评论时无需额外处理;frontmatter 镜像会自然包含该字段