@fitlab-ai/agent-infra 0.5.7 → 0.5.8

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 (116) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/lib/defaults.json +4 -2
  4. package/lib/init.js +18 -1
  5. package/lib/sandbox/engine.js +19 -0
  6. package/lib/sandbox/shell.js +36 -2
  7. package/lib/update.js +14 -3
  8. package/package.json +4 -4
  9. package/templates/.agents/QUICKSTART.en.md +2 -2
  10. package/templates/.agents/QUICKSTART.zh-CN.md +2 -2
  11. package/templates/.agents/README.en.md +1 -1
  12. package/templates/.agents/README.zh-CN.md +1 -1
  13. package/templates/.agents/rules/issue-pr-commands.github.en.md +60 -0
  14. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +60 -0
  15. package/templates/.agents/rules/issue-sync.en.md +14 -0
  16. package/templates/.agents/rules/issue-sync.github.en.md +14 -0
  17. package/templates/.agents/rules/issue-sync.github.zh-CN.md +14 -0
  18. package/templates/.agents/rules/issue-sync.zh-CN.md +14 -0
  19. package/templates/.agents/rules/label-milestone-setup.github.en.md +10 -0
  20. package/templates/.agents/rules/label-milestone-setup.github.zh-CN.md +10 -0
  21. package/templates/.agents/rules/release-commands.github.en.md +16 -0
  22. package/templates/.agents/rules/release-commands.github.zh-CN.md +16 -0
  23. package/templates/.agents/scripts/platform-adapters/find-existing-task.github.js +272 -0
  24. package/templates/.agents/scripts/platform-adapters/find-existing-task.js +5 -0
  25. package/templates/.agents/scripts/platform-adapters/platform-sync.github.js +88 -8
  26. package/templates/.agents/scripts/platform-adapters/platform-sync.js +7 -0
  27. package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
  28. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
  29. package/templates/.agents/skills/analyze-task/config/verify.json +3 -1
  30. package/templates/.agents/skills/block-task/config/verify.json +2 -1
  31. package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -2
  32. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +2 -2
  33. package/templates/.agents/skills/cancel-task/config/verify.json +2 -1
  34. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  35. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  36. package/templates/.agents/skills/commit/SKILL.en.md +1 -1
  37. package/templates/.agents/skills/commit/SKILL.zh-CN.md +1 -1
  38. package/templates/.agents/skills/commit/config/verify.json +2 -1
  39. package/templates/.agents/skills/complete-task/SKILL.en.md +1 -1
  40. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +1 -1
  41. package/templates/.agents/skills/complete-task/config/verify.json +2 -1
  42. package/templates/.agents/skills/create-issue/SKILL.en.md +8 -8
  43. package/templates/.agents/skills/create-issue/SKILL.zh-CN.md +8 -8
  44. package/templates/.agents/skills/create-issue/config/verify.json +2 -1
  45. package/templates/.agents/skills/create-issue/reference/label-and-type.en.md +3 -3
  46. package/templates/.agents/skills/create-issue/reference/label-and-type.zh-CN.md +3 -3
  47. package/templates/.agents/skills/create-issue/reference/template-matching.en.md +6 -34
  48. package/templates/.agents/skills/create-issue/reference/template-matching.zh-CN.md +8 -36
  49. package/templates/.agents/skills/create-pr/SKILL.en.md +2 -2
  50. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +2 -2
  51. package/templates/.agents/skills/create-pr/config/verify.json +2 -1
  52. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +7 -17
  53. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +27 -37
  54. package/templates/.agents/skills/create-release-note/SKILL.en.md +9 -9
  55. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +9 -9
  56. package/templates/.agents/skills/create-task/SKILL.en.md +3 -3
  57. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +3 -3
  58. package/templates/.agents/skills/implement-task/SKILL.en.md +1 -1
  59. package/templates/.agents/skills/implement-task/SKILL.zh-CN.md +1 -1
  60. package/templates/.agents/skills/implement-task/config/verify.json +3 -1
  61. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  62. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  63. package/templates/.agents/skills/import-issue/SKILL.en.md +39 -9
  64. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +39 -9
  65. package/templates/.agents/skills/init-labels/SKILL.en.md +9 -9
  66. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +9 -9
  67. package/templates/.agents/skills/init-milestones/SKILL.en.md +7 -7
  68. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +7 -7
  69. package/templates/.agents/skills/plan-task/SKILL.en.md +1 -1
  70. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +1 -1
  71. package/templates/.agents/skills/plan-task/config/verify.json +3 -1
  72. package/templates/.agents/skills/refine-task/SKILL.en.md +1 -1
  73. package/templates/.agents/skills/refine-task/SKILL.zh-CN.md +1 -1
  74. package/templates/.agents/skills/refine-task/config/verify.json +3 -1
  75. package/templates/.agents/skills/restore-task/SKILL.en.md +13 -64
  76. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +13 -64
  77. package/templates/.agents/skills/review-task/SKILL.en.md +1 -1
  78. package/templates/.agents/skills/review-task/SKILL.zh-CN.md +1 -1
  79. package/templates/.agents/skills/review-task/config/verify.json +3 -1
  80. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +2 -0
  81. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +2 -0
  82. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +56 -5
  83. package/templates/.claude/commands/create-issue.en.md +1 -1
  84. package/templates/.claude/commands/create-issue.zh-CN.md +1 -1
  85. package/templates/.claude/commands/import-issue.en.md +1 -1
  86. package/templates/.claude/commands/import-issue.zh-CN.md +1 -1
  87. package/templates/.claude/commands/init-labels.en.md +1 -1
  88. package/templates/.claude/commands/init-labels.zh-CN.md +1 -1
  89. package/templates/.claude/commands/init-milestones.en.md +1 -1
  90. package/templates/.claude/commands/init-milestones.zh-CN.md +1 -1
  91. package/templates/.claude/commands/restore-task.en.md +1 -1
  92. package/templates/.claude/commands/restore-task.zh-CN.md +1 -1
  93. package/templates/.claude/hooks/check-version-format.sh +1 -1
  94. package/templates/.gemini/commands/_project_/create-issue.en.toml +1 -1
  95. package/templates/.gemini/commands/_project_/create-issue.zh-CN.toml +1 -1
  96. package/templates/.gemini/commands/_project_/import-issue.en.toml +1 -1
  97. package/templates/.gemini/commands/_project_/import-issue.zh-CN.toml +1 -1
  98. package/templates/.gemini/commands/_project_/init-labels.en.toml +2 -2
  99. package/templates/.gemini/commands/_project_/init-labels.zh-CN.toml +2 -2
  100. package/templates/.gemini/commands/_project_/init-milestones.en.toml +2 -2
  101. package/templates/.gemini/commands/_project_/init-milestones.zh-CN.toml +2 -2
  102. package/templates/.gemini/commands/_project_/restore-task.en.toml +1 -1
  103. package/templates/.gemini/commands/_project_/restore-task.zh-CN.toml +1 -1
  104. package/templates/{.github/hooks → .git-hooks}/check-version-format.sh +2 -2
  105. package/templates/.github/workflows/pr-label.yml +1 -1
  106. package/templates/.opencode/commands/create-issue.en.md +1 -1
  107. package/templates/.opencode/commands/create-issue.zh-CN.md +1 -1
  108. package/templates/.opencode/commands/import-issue.en.md +1 -1
  109. package/templates/.opencode/commands/import-issue.zh-CN.md +1 -1
  110. package/templates/.opencode/commands/init-labels.en.md +1 -1
  111. package/templates/.opencode/commands/init-labels.zh-CN.md +1 -1
  112. package/templates/.opencode/commands/init-milestones.en.md +1 -1
  113. package/templates/.opencode/commands/init-milestones.zh-CN.md +1 -1
  114. package/templates/.opencode/commands/restore-task.en.md +1 -1
  115. package/templates/.opencode/commands/restore-task.zh-CN.md +1 -1
  116. /package/templates/{.github/hooks → .git-hooks}/pre-commit +0 -0
package/README.md CHANGED
@@ -545,7 +545,7 @@ The generated `.agents/.airc.json` file is the central contract between the boot
545
545
  "project": "my-project",
546
546
  "org": "my-org",
547
547
  "language": "en",
548
- "templateVersion": "v0.5.7",
548
+ "templateVersion": "v0.5.8",
549
549
  "templates": {
550
550
  "sources": [
551
551
  { "type": "local", "path": "~/private-templates" }
package/README.zh-CN.md CHANGED
@@ -545,7 +545,7 @@ import-issue #42 从 GitHub Issue 导入任务
545
545
  "project": "my-project",
546
546
  "org": "my-org",
547
547
  "language": "en",
548
- "templateVersion": "v0.5.7",
548
+ "templateVersion": "v0.5.8",
549
549
  "templates": {
550
550
  "sources": [
551
551
  { "type": "local", "path": "~/private-templates" }
package/lib/defaults.json CHANGED
@@ -36,22 +36,24 @@
36
36
  ".claude/commands/",
37
37
  ".claude/hooks/",
38
38
  ".gemini/commands/",
39
- ".github/hooks/check-version-format.sh",
39
+ ".git-hooks/check-version-format.sh",
40
40
  ".github/scripts/",
41
41
  ".opencode/commands/"
42
42
  ],
43
43
  "merged": [
44
+ "**/post-release.*",
44
45
  "**/release.*",
45
46
  "**/test-integration.*",
46
47
  "**/test.*",
47
48
  "**/upgrade-dependency.*",
49
+ ".agents/skills/post-release/SKILL.*",
48
50
  ".agents/skills/release/SKILL.*",
49
51
  ".agents/skills/test-integration/SKILL.*",
50
52
  ".agents/skills/test/SKILL.*",
51
53
  ".agents/skills/upgrade-dependency/SKILL.*",
52
54
  ".claude/settings.json",
53
55
  ".gemini/settings.json",
54
- ".github/hooks/pre-commit",
56
+ ".git-hooks/pre-commit",
55
57
  ".gitignore"
56
58
  ],
57
59
  "ejected": []
package/lib/init.js CHANGED
@@ -12,6 +12,23 @@ const defaults = JSON.parse(
12
12
  fs.readFileSync(new URL('./defaults.json', import.meta.url), 'utf8')
13
13
  );
14
14
 
15
+ function isPathOwnedByOtherPlatform(relativePath, platformType) {
16
+ const top = String(relativePath || '').replace(/\\/g, '/').replace(/^\.\//, '').split('/')[0];
17
+ if (!top.startsWith('.')) return false;
18
+
19
+ const candidate = top.slice(1);
20
+ if (!KNOWN_PLATFORMS.has(candidate)) return false;
21
+ return candidate !== platformType;
22
+ }
23
+
24
+ function buildDefaultFiles(platformType) {
25
+ return {
26
+ managed: (defaults.files.managed || []).filter((entry) => !isPathOwnedByOtherPlatform(entry, platformType)),
27
+ merged: (defaults.files.merged || []).filter((entry) => !isPathOwnedByOtherPlatform(entry, platformType)),
28
+ ejected: structuredClone(defaults.files.ejected || [])
29
+ };
30
+ }
31
+
15
32
  function detectProjectName() {
16
33
  try {
17
34
  const url = execSync('git remote get-url origin', { stdio: ['pipe', 'pipe', 'pipe'] })
@@ -222,7 +239,7 @@ async function cmdInit() {
222
239
  templateVersion: VERSION,
223
240
  sandbox: structuredClone(defaults.sandbox),
224
241
  labels: structuredClone(defaults.labels),
225
- files: structuredClone(defaults.files)
242
+ files: buildDefaultFiles(platformType)
226
243
  };
227
244
 
228
245
  if (sandboxEngine) {
@@ -8,8 +8,21 @@ export const ENGINES = Object.freeze({
8
8
  DOCKER_DESKTOP: 'docker-desktop'
9
9
  });
10
10
 
11
+ export const ENGINE_DOCKER_CONTEXT = Object.freeze({
12
+ [ENGINES.COLIMA]: 'colima',
13
+ [ENGINES.ORBSTACK]: 'orbstack',
14
+ [ENGINES.DOCKER_DESKTOP]: 'desktop-linux'
15
+ });
16
+
11
17
  const VALID_CONFIG_ENGINES = new Set(Object.values(ENGINES));
12
18
 
19
+ function applyDockerContext(engine) {
20
+ const context = ENGINE_DOCKER_CONTEXT[engine];
21
+ if (context) {
22
+ process.env.DOCKER_CONTEXT = context;
23
+ }
24
+ }
25
+
13
26
  export function validateSandboxEngine(engine) {
14
27
  if (engine === null || engine === undefined) {
15
28
  return null;
@@ -68,6 +81,8 @@ export async function ensureColima(
68
81
  onMessage,
69
82
  { runOkFn = runOk, runSafeFn = runSafe, runVerboseFn = runVerbose } = {}
70
83
  ) {
84
+ applyDockerContext(ENGINES.COLIMA);
85
+
71
86
  if (!runOkFn('which', ['colima'])) {
72
87
  onMessage?.('Installing colima + docker via Homebrew...');
73
88
  runVerboseFn('brew', ['install', 'colima', 'docker']);
@@ -88,6 +103,8 @@ export async function ensureOrbStack(
88
103
  onMessage,
89
104
  { runOkFn = runOk, runVerboseFn = runVerbose } = {}
90
105
  ) {
106
+ applyDockerContext(ENGINES.ORBSTACK);
107
+
91
108
  if (!runOkFn('which', ['orb'])) {
92
109
  onMessage?.('Installing OrbStack via Homebrew...');
93
110
  runVerboseFn('brew', ['install', '--cask', 'orbstack']);
@@ -108,6 +125,8 @@ export async function ensureDockerDesktop(
108
125
  onMessage,
109
126
  { runOkFn = runOk } = {}
110
127
  ) {
128
+ applyDockerContext(ENGINES.DOCKER_DESKTOP);
129
+
111
130
  if (!runOkFn('docker', ['info'])) {
112
131
  throw new Error('Docker Desktop is not running. Please start Docker Desktop manually.');
113
132
  }
@@ -60,10 +60,44 @@ export function runOk(cmd, args, opts = {}) {
60
60
  return result.status === 0;
61
61
  }
62
62
 
63
+ export function restoreTerminal() {
64
+ if (!process.stdout.isTTY) {
65
+ return;
66
+ }
67
+
68
+ try {
69
+ process.stdout.write([
70
+ '\x1b[?1049l',
71
+ '\x1b[?25h',
72
+ '\x1b>',
73
+ '\x1b[?1000l',
74
+ '\x1b[?1002l',
75
+ '\x1b[?1003l',
76
+ '\x1b[?1006l'
77
+ ].join(''));
78
+ } catch {
79
+ // Best-effort cleanup only; preserve the original command result.
80
+ }
81
+
82
+ if (process.platform === 'win32') {
83
+ return;
84
+ }
85
+
86
+ try {
87
+ execFileSync('stty', ['sane'], { stdio: 'inherit' });
88
+ } catch {
89
+ // Some environments do not provide stty or reject sane; ANSI reset still helps.
90
+ }
91
+ }
92
+
63
93
  export function runInteractive(cmd, args, opts = {}) {
64
94
  const resolved = resolveCommand(cmd);
65
- const result = spawnSync(resolved, args, commandOptions(resolved, normalizeOptions(opts, 'inherit')));
66
- return result.status ?? 1;
95
+ try {
96
+ const result = spawnSync(resolved, args, commandOptions(resolved, normalizeOptions(opts, 'inherit')));
97
+ return result.status ?? 1;
98
+ } finally {
99
+ restoreTerminal();
100
+ }
67
101
  }
68
102
 
69
103
  export function runVerbose(cmd, args, opts = {}) {
package/lib/update.js CHANGED
@@ -2,7 +2,7 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { info, ok, err } from './log.js';
4
4
  import { resolveTemplateDir } from './paths.js';
5
- import { renderFile, copySkillDir } from './render.js';
5
+ import { renderFile, copySkillDir, KNOWN_PLATFORMS } from './render.js';
6
6
 
7
7
  const defaults = JSON.parse(
8
8
  fs.readFileSync(new URL('./defaults.json', import.meta.url), 'utf8')
@@ -11,7 +11,16 @@ const defaults = JSON.parse(
11
11
  const CONFIG_DIR = '.agents';
12
12
  const CONFIG_PATH = path.join(CONFIG_DIR, '.airc.json');
13
13
 
14
- function syncFileRegistry(config) {
14
+ function isPathOwnedByOtherPlatform(relativePath, platformType) {
15
+ const top = String(relativePath || '').replace(/\\/g, '/').replace(/^\.\//, '').split('/')[0];
16
+ if (!top.startsWith('.')) return false;
17
+
18
+ const candidate = top.slice(1);
19
+ if (!KNOWN_PLATFORMS.has(candidate)) return false;
20
+ return candidate !== platformType;
21
+ }
22
+
23
+ function syncFileRegistry(config, platformType) {
15
24
  config.files ||= {};
16
25
  const before = JSON.stringify({
17
26
  files: {
@@ -32,12 +41,14 @@ function syncFileRegistry(config) {
32
41
  const added = { managed: [], merged: [] };
33
42
 
34
43
  for (const entry of defaults.files.managed) {
44
+ if (isPathOwnedByOtherPlatform(entry, platformType)) continue;
35
45
  if (!allExisting.includes(entry)) {
36
46
  config.files.managed.push(entry);
37
47
  added.managed.push(entry);
38
48
  }
39
49
  }
40
50
  for (const entry of defaults.files.merged) {
51
+ if (isPathOwnedByOtherPlatform(entry, platformType)) continue;
41
52
  if (!allExisting.includes(entry)) {
42
53
  config.files.merged.push(entry);
43
54
  added.merged.push(entry);
@@ -139,7 +150,7 @@ async function cmdUpdate() {
139
150
  ok('Updated .opencode/commands/update-agent-infra.md');
140
151
 
141
152
  // sync file registry
142
- const { added, changed } = syncFileRegistry(config);
153
+ const { added, changed } = syncFileRegistry(config, platformType);
143
154
  const hasNewEntries = added.managed.length > 0 || added.merged.length > 0;
144
155
  const platformAdded = !config.platform;
145
156
  const sandboxAdded = !config.sandbox;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fitlab-ai/agent-infra",
3
- "version": "0.5.7",
3
+ "version": "0.5.8",
4
4
  "description": "Bootstrap tool for AI multi-tool collaboration infrastructure — works with Claude Code, Codex, Gemini CLI, and OpenCode",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -47,8 +47,8 @@
47
47
  "scripts": {
48
48
  "build": "node scripts/build-inline.js",
49
49
  "demo:regen": "sh scripts/demo-regen.sh",
50
- "prepare": "git config core.hooksPath .github/hooks || true",
51
- "test": "node scripts/build-inline.js --check && node --test tests/cli/*.test.js tests/templates/*.test.js tests/core/*.test.js",
52
- "prepublishOnly": "node scripts/build-inline.js --check && node --test tests/cli/*.test.js tests/templates/*.test.js tests/core/*.test.js"
50
+ "prepare": "git config core.hooksPath .git-hooks || true",
51
+ "test": "node scripts/build-inline.js --check && node --test tests/cli/*.test.js tests/templates/*.test.js tests/core/*.test.js tests/scripts/*.test.js",
52
+ "prepublishOnly": "node scripts/build-inline.js --check && node --test tests/cli/*.test.js tests/templates/*.test.js tests/core/*.test.js tests/scripts/*.test.js"
53
53
  }
54
54
  }
@@ -13,10 +13,10 @@ This guide walks you through using multiple AI coding assistants together on a p
13
13
  Enable the shared Git hooks path before relying on the template hook chain:
14
14
 
15
15
  ```bash
16
- git config core.hooksPath .github/hooks
16
+ git config core.hooksPath .git-hooks
17
17
  ```
18
18
 
19
- This makes Git invoke the hooks synced into `.github/hooks/`, including `pre-commit` and `check-version-format.sh`.
19
+ This makes Git invoke the hooks in the project repository's `.git-hooks/` directory, including `pre-commit` and `check-version-format.sh`.
20
20
 
21
21
  ## External Templates And Skills
22
22
 
@@ -13,10 +13,10 @@
13
13
  在依赖模板中的 Git hook 链路前,先启用共享 hooks 路径:
14
14
 
15
15
  ```bash
16
- git config core.hooksPath .github/hooks
16
+ git config core.hooksPath .git-hooks
17
17
  ```
18
18
 
19
- 这样 Git 才会调用同步到 `.github/hooks/` 下的 hook,包括 `pre-commit` 和 `check-version-format.sh`。
19
+ 这样 Git 才会调用项目仓库 `.git-hooks/` 目录下的 hook,包括 `pre-commit` 和 `check-version-format.sh`。
20
20
 
21
21
  ## 外部模板与 Skill
22
22
 
@@ -108,7 +108,7 @@ This project uses the following collaboration label prefixes, each with a define
108
108
  | `status:` | Yes | — | PRs already have their own state flow (Open / Draft / Merged / Closed); Issues use `status:` labels for project tracking states |
109
109
  | `in:` | Yes | Yes | Both Issues and PRs can be filtered by module |
110
110
 
111
- The default GitHub setup initializes these labels with the `/init-labels` command.
111
+ Run the `/init-labels` command to initialize these labels via the platform adapter.
112
112
 
113
113
  ## Private Platform Extensions
114
114
 
@@ -108,7 +108,7 @@
108
108
  | `status:` | Yes | — | PR 有自身状态流转(Open / Draft / Merged / Closed);Issue 使用 `status:` label 标记等待反馈、已确认等项目管理状态 |
109
109
  | `in:` | Yes | Yes | Issue 和 PR 均可按模块筛选 |
110
110
 
111
- 默认 GitHub 配置下,可使用 `/init-labels` 命令一次性创建标准 labels。
111
+ 使用 `/init-labels` 命令可通过平台适配器一次性创建标准 labels。
112
112
 
113
113
  ## 私有平台扩展
114
114
 
@@ -22,6 +22,44 @@ Before any later `gh issue` or `gh api "repos/..."` call, follow `.agents/rules/
22
22
  - keep `gh pr *` commands on the current repository without adding `-R`
23
23
  - keep organization-scoped commands such as `gh api "orgs/{owner}/..."` unchanged
24
24
 
25
+ ## Issue Template Detection
26
+
27
+ Detect GitHub Issue Forms with:
28
+
29
+ ```bash
30
+ rg --files .github/ISSUE_TEMPLATE -g '*.yml' -g '!config.yml'
31
+ ```
32
+
33
+ Read matching form files locally before creating the Issue. If the directory is missing or no form matches the task, use the caller's fallback body format.
34
+
35
+ Typical candidate templates:
36
+ - `bug_report.yml` for bug work
37
+ - `question.yml` for question or investigation work
38
+ - `feature_request.yml` for feature work
39
+ - `documentation.yml` for documentation work
40
+ - `other.yml` as the general fallback
41
+
42
+ For GitHub Issue Forms, inspect the matched form's:
43
+ - `name`
44
+ - `type:`
45
+ - `labels:`
46
+ - `body:`
47
+
48
+ Field handling rules:
49
+ - `textarea` and `input`: use `attributes.label` as the markdown heading and fill values from task.md
50
+ - `markdown`: skip template explanation prose
51
+ - `dropdown` and `checkboxes`: skip
52
+ - when task.md lacks a suitable value, write `N/A`
53
+
54
+ Suggested field mapping:
55
+
56
+ | Template field hint | task.md source |
57
+ |---|---|
58
+ | `summary`, `title` | task title |
59
+ | `description`, `problem`, `what happened`, `issue-description`, `current-content` | task description |
60
+ | `solution`, `requirements`, `steps`, `suggested-content`, `impact`, `context`, `alternatives`, `expected` | requirements list |
61
+ | other `textarea` / `input` fields | task description, otherwise `N/A` |
62
+
25
63
  ## Read and Create Issues
26
64
 
27
65
  Read an Issue:
@@ -82,6 +120,28 @@ Read Issue comments or search for existing hidden markers:
82
120
  gh api "repos/$upstream_repo/issues/{issue-number}/comments" --paginate
83
121
  ```
84
122
 
123
+ ## PR Template and Metadata Helpers
124
+
125
+ Read a repository PR template when present:
126
+
127
+ ```bash
128
+ cat .github/PULL_REQUEST_TEMPLATE.md
129
+ ```
130
+
131
+ Review recent merged PRs for style:
132
+
133
+ ```bash
134
+ gh pr list --limit 3 --state merged --json number,title,body
135
+ ```
136
+
137
+ Verify that standard type labels exist before PR metadata sync:
138
+
139
+ ```bash
140
+ gh label list --search "type:" --limit 1 --json name --jq 'length'
141
+ ```
142
+
143
+ If the result is `0`, run `init-labels` before retrying PR metadata sync.
144
+
85
145
  ## Read and Create PRs
86
146
 
87
147
  Read a PR:
@@ -22,6 +22,44 @@ gh repo view --json nameWithOwner
22
22
  - `gh pr *` 命令保持作用于当前仓库,不额外加 `-R`
23
23
  - `gh api "orgs/{owner}/..."` 这类 org 级命令保持不变
24
24
 
25
+ ## Issue 模板检测
26
+
27
+ 使用以下命令检测 GitHub Issue Forms:
28
+
29
+ ```bash
30
+ rg --files .github/ISSUE_TEMPLATE -g '*.yml' -g '!config.yml'
31
+ ```
32
+
33
+ 创建 Issue 前先读取匹配的 form 文件。目录不存在或没有匹配 form 时,使用调用方定义的 fallback 正文格式。
34
+
35
+ 常见候选模板:
36
+ - `bug_report.yml`:bug 工作
37
+ - `question.yml`:问题或排查工作
38
+ - `feature_request.yml`:功能工作
39
+ - `documentation.yml`:文档工作
40
+ - `other.yml`:通用 fallback
41
+
42
+ 对 GitHub Issue Forms,检查匹配 form 的:
43
+ - `name`
44
+ - `type:`
45
+ - `labels:`
46
+ - `body:`
47
+
48
+ 字段处理规则:
49
+ - `textarea` 和 `input`:使用 `attributes.label` 作为 markdown 标题,并从 task.md 填充值
50
+ - `markdown`:跳过模板说明文案
51
+ - `dropdown` 和 `checkboxes`:跳过
52
+ - task.md 缺少合适值时,写入 `N/A`
53
+
54
+ 建议字段映射:
55
+
56
+ | 模板字段提示 | task.md 来源 |
57
+ |---|---|
58
+ | `summary`, `title` | 任务标题 |
59
+ | `description`, `problem`, `what happened`, `issue-description`, `current-content` | 任务描述 |
60
+ | `solution`, `requirements`, `steps`, `suggested-content`, `impact`, `context`, `alternatives`, `expected` | 需求列表 |
61
+ | 其他 `textarea` / `input` 字段 | 任务描述,否则 `N/A` |
62
+
25
63
  ## Issue 读取与创建
26
64
 
27
65
  读取 Issue:
@@ -82,6 +120,28 @@ gh issue close {issue-number} -R "$upstream_repo" --reason "{reason}"
82
120
  gh api "repos/$upstream_repo/issues/{issue-number}/comments" --paginate
83
121
  ```
84
122
 
123
+ ## PR 模板与元数据辅助命令
124
+
125
+ 存在仓库 PR 模板时读取:
126
+
127
+ ```bash
128
+ cat .github/PULL_REQUEST_TEMPLATE.md
129
+ ```
130
+
131
+ 参考最近合并的 PR 风格:
132
+
133
+ ```bash
134
+ gh pr list --limit 3 --state merged --json number,title,body
135
+ ```
136
+
137
+ PR 元数据同步前验证标准 type labels 是否存在:
138
+
139
+ ```bash
140
+ gh label list --search "type:" --limit 1 --json name --jq 'length'
141
+ ```
142
+
143
+ 如果结果是 `0`,先运行 `init-labels`,再重试 PR 元数据同步。
144
+
85
145
  ## PR 读取与创建
86
146
 
87
147
  读取 PR:
@@ -1,5 +1,19 @@
1
1
  # Issue Sync
2
2
 
3
+ ## Marker Registry
4
+
5
+ These hidden markers are the canonical registry for Issue synchronization:
6
+
7
+ | Key | Marker |
8
+ |---|---|
9
+ | `task` | `<!-- sync-issue:{task-id}:task -->` |
10
+ | `artifact` | `<!-- sync-issue:{task-id}:{artifact-stem} -->` |
11
+ | `artifactChunk` | `<!-- sync-issue:{task-id}:{artifact-stem}:{part}/{total} -->` |
12
+ | `summary` | `<!-- sync-issue:{task-id}:summary -->` |
13
+ | `cancel` | `<!-- sync-issue:{task-id}:cancel -->` |
14
+
15
+ Callers should refer to the marker key in skill prose and keep concrete marker strings in this rule or the platform adapter defaults.
16
+
3
17
  This code platform does not provide built-in issue synchronization.
4
18
 
5
19
  Issue metadata, labels, milestones, assignees, and comments are skipped for custom platforms unless you provide matching `.{platform}.en.md` rule templates and platform adapters. Continue writing local task artifacts normally.
@@ -1,5 +1,19 @@
1
1
  # Issue Sync Rules
2
2
 
3
+ ## Marker Registry
4
+
5
+ These hidden markers are the canonical registry for Issue synchronization:
6
+
7
+ | Key | Marker |
8
+ |---|---|
9
+ | `task` | `<!-- sync-issue:{task-id}:task -->` |
10
+ | `artifact` | `<!-- sync-issue:{task-id}:{artifact-stem} -->` |
11
+ | `artifactChunk` | `<!-- sync-issue:{task-id}:{artifact-stem}:{part}/{total} -->` |
12
+ | `summary` | `<!-- sync-issue:{task-id}:summary -->` |
13
+ | `cancel` | `<!-- sync-issue:{task-id}:cancel -->` |
14
+
15
+ Callers should refer to the marker key in skill prose and keep concrete marker strings in this rule or the platform adapter defaults.
16
+
3
17
  Read this file before a task skill updates a GitHub Issue.
4
18
 
5
19
  ## Upstream Repository Detection
@@ -1,5 +1,19 @@
1
1
  # Issue 同步规则
2
2
 
3
+ ## Marker 注册表
4
+
5
+ 以下隐藏标记是 Issue 同步的唯一权威注册表:
6
+
7
+ | Key | Marker |
8
+ |---|---|
9
+ | `task` | `<!-- sync-issue:{task-id}:task -->` |
10
+ | `artifact` | `<!-- sync-issue:{task-id}:{artifact-stem} -->` |
11
+ | `artifactChunk` | `<!-- sync-issue:{task-id}:{artifact-stem}:{part}/{total} -->` |
12
+ | `summary` | `<!-- sync-issue:{task-id}:summary -->` |
13
+ | `cancel` | `<!-- sync-issue:{task-id}:cancel -->` |
14
+
15
+ Skill 正文应引用 marker key,具体 marker 字符串只保留在本规则或平台适配器默认值中。
16
+
3
17
  在任务技能需要更新 GitHub Issue 时先读取本文件。
4
18
 
5
19
  ## Upstream 仓库检测
@@ -1,5 +1,19 @@
1
1
  # Issue 同步
2
2
 
3
+ ## Marker 注册表
4
+
5
+ 以下隐藏标记是 Issue 同步的唯一权威注册表:
6
+
7
+ | Key | Marker |
8
+ |---|---|
9
+ | `task` | `<!-- sync-issue:{task-id}:task -->` |
10
+ | `artifact` | `<!-- sync-issue:{task-id}:{artifact-stem} -->` |
11
+ | `artifactChunk` | `<!-- sync-issue:{task-id}:{artifact-stem}:{part}/{total} -->` |
12
+ | `summary` | `<!-- sync-issue:{task-id}:summary -->` |
13
+ | `cancel` | `<!-- sync-issue:{task-id}:cancel -->` |
14
+
15
+ Skill 正文应引用 marker key,具体 marker 字符串只保留在本规则或平台适配器默认值中。
16
+
3
17
  当前代码平台未内置 Issue 同步支持。
4
18
 
5
19
  自定义平台会跳过 Issue 元数据、标签、里程碑、负责人和评论同步,除非你提供匹配的 `.{platform}.zh-CN.md` 规则模板和平台适配器。请继续正常写入本地任务产物。
@@ -43,6 +43,16 @@ Update a milestone:
43
43
  gh api "repos/$repo/milestones/{number}" -X PATCH -f state="{state}" -f description="{description}"
44
44
  ```
45
45
 
46
+ ## Error Prompt Templates
47
+
48
+ Use these normalized prompts when the GitHub setup scripts fail:
49
+
50
+ | Condition | Prompt |
51
+ |---|---|
52
+ | CLI missing | GitHub CLI (`gh`) is not installed |
53
+ | Authentication failed | `GitHub CLI is not authenticated` |
54
+ | API rate limit | `GitHub API rate limit reached, please retry later` |
55
+
46
56
  ## Constraints
47
57
 
48
58
  - use label names as the idempotency key
@@ -43,6 +43,16 @@ gh api "repos/$repo/milestones" -f title="{title}" -f description="{description}
43
43
  gh api "repos/$repo/milestones/{number}" -X PATCH -f state="{state}" -f description="{description}"
44
44
  ```
45
45
 
46
+ ## 错误提示模板
47
+
48
+ GitHub 初始化脚本失败时使用以下标准提示:
49
+
50
+ | 条件 | 提示 |
51
+ |---|---|
52
+ | CLI 缺失 | GitHub CLI (`gh`) is not installed |
53
+ | 认证失败 | `GitHub CLI is not authenticated` |
54
+ | API 限流 | `GitHub API rate limit reached, please retry later` |
55
+
46
56
  ## 约束
47
57
 
48
58
  - label 以名称作为幂等键
@@ -21,6 +21,22 @@ When needed, read the linked Issue:
21
21
  gh issue view {issue-number} --json number,title,labels,url
22
22
  ```
23
23
 
24
+ ## Contributor Mapping Helpers
25
+
26
+ Merged PR queries used for release notes should include authors when contributors are needed:
27
+
28
+ ```bash
29
+ gh pr list --state merged --base "{branch}" --json number,title,mergedAt,labels,author
30
+ ```
31
+
32
+ Linked Issue queries used for reporter attribution should include the author:
33
+
34
+ ```bash
35
+ gh issue view {issue-number} --json number,title,labels,url,author
36
+ ```
37
+
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
+
24
40
  ## Create a Draft Release
25
41
 
26
42
  ```bash
@@ -21,6 +21,22 @@ gh pr list --state merged --base "{branch}" --json number,title,mergedAt,labels
21
21
  gh issue view {issue-number} --json number,title,labels,url
22
22
  ```
23
23
 
24
+ ## Contributor 映射辅助规则
25
+
26
+ release notes 需要 contributors 时,已合并 PR 查询应包含 author:
27
+
28
+ ```bash
29
+ gh pr list --state merged --base "{branch}" --json number,title,mergedAt,labels,author
30
+ ```
31
+
32
+ 关联 Issue 用于 reporter 归因时,查询应包含 author:
33
+
34
+ ```bash
35
+ gh issue view {issue-number} --json number,title,labels,url,author
36
+ ```
37
+
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
+
24
40
  ## 创建 Draft Release
25
41
 
26
42
  ```bash