@fitlab-ai/agent-infra 0.5.1 → 0.5.2
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 +15 -1
- package/README.zh-CN.md +15 -1
- package/lib/defaults.json +3 -0
- package/lib/init.js +15 -5
- package/lib/render.js +77 -15
- package/lib/sandbox/commands/enter.js +22 -7
- package/lib/sandbox/runtimes/base.dockerfile +10 -0
- package/lib/update.js +19 -5
- package/package.json +2 -1
- package/templates/.agents/{README.md → README.en.md} +13 -3
- package/templates/.agents/README.zh-CN.md +13 -3
- package/templates/.agents/rules/issue-pr-commands.github.en.md +111 -0
- package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +111 -0
- package/templates/.agents/rules/label-milestone-setup.github.en.md +50 -0
- package/templates/.agents/rules/label-milestone-setup.github.zh-CN.md +50 -0
- package/templates/.agents/rules/release-commands.github.en.md +30 -0
- package/templates/.agents/rules/release-commands.github.zh-CN.md +30 -0
- package/templates/.agents/rules/security-alerts.github.en.md +43 -0
- package/templates/.agents/rules/security-alerts.github.zh-CN.md +43 -0
- package/templates/.agents/scripts/validate-artifact.js +0 -2
- package/templates/.agents/skills/cancel-task/{SKILL.md → SKILL.en.md} +7 -6
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +7 -6
- package/templates/.agents/skills/close-codescan/{SKILL.md → SKILL.en.md} +3 -11
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +3 -11
- package/templates/.agents/skills/close-dependabot/{SKILL.md → SKILL.en.md} +5 -13
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +5 -13
- package/templates/.agents/skills/create-issue/{SKILL.md → SKILL.en.md} +2 -5
- package/templates/.agents/skills/create-issue/SKILL.zh-CN.md +2 -5
- package/templates/.agents/skills/create-issue/reference/{label-and-type.md → label-and-type.en.md} +4 -16
- package/templates/.agents/skills/create-issue/reference/label-and-type.zh-CN.md +4 -16
- package/templates/.agents/skills/create-pr/{SKILL.md → SKILL.en.md} +3 -4
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +3 -4
- package/templates/.agents/skills/create-pr/reference/{pr-body-template.md → pr-body-template.en.md} +8 -13
- package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +8 -13
- package/templates/.agents/skills/create-release-note/{SKILL.md → SKILL.en.md} +6 -18
- package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +6 -18
- package/templates/.agents/skills/import-codescan/{SKILL.md → SKILL.en.md} +1 -3
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -3
- package/templates/.agents/skills/import-dependabot/{SKILL.md → SKILL.en.md} +1 -3
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -3
- package/templates/.agents/skills/import-issue/{SKILL.md → SKILL.en.md} +2 -10
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +2 -10
- package/templates/.agents/skills/init-labels/{SKILL.md → SKILL.en.md} +9 -13
- package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +9 -13
- package/templates/.agents/skills/init-milestones/{SKILL.md → SKILL.en.md} +5 -6
- package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +5 -6
- package/templates/.agents/skills/refine-title/{SKILL.md → SKILL.en.md} +7 -17
- package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +6 -16
- package/templates/.agents/skills/release/{SKILL.md → SKILL.en.md} +2 -1
- package/templates/.agents/skills/release/SKILL.zh-CN.md +2 -1
- package/templates/.agents/skills/restore-task/{SKILL.md → SKILL.en.md} +5 -11
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +5 -11
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +219 -59
- /package/templates/.agents/{QUICKSTART.md → QUICKSTART.en.md} +0 -0
- /package/templates/.agents/rules/{commit-and-pr.md → commit-and-pr.en.md} +0 -0
- /package/templates/.agents/rules/{issue-sync.md → issue-sync.github.en.md} +0 -0
- /package/templates/.agents/rules/{issue-sync.zh-CN.md → issue-sync.github.zh-CN.md} +0 -0
- /package/templates/.agents/rules/{milestone-inference.md → milestone-inference.github.en.md} +0 -0
- /package/templates/.agents/rules/{milestone-inference.zh-CN.md → milestone-inference.github.zh-CN.md} +0 -0
- /package/templates/.agents/rules/{pr-sync.md → pr-sync.github.en.md} +0 -0
- /package/templates/.agents/rules/{pr-sync.zh-CN.md → pr-sync.github.zh-CN.md} +0 -0
- /package/templates/.agents/rules/{task-management.md → task-management.en.md} +0 -0
- /package/templates/.agents/skills/analyze-task/{SKILL.md → SKILL.en.md} +0 -0
- /package/templates/.agents/skills/archive-tasks/{SKILL.md → SKILL.en.md} +0 -0
- /package/templates/.agents/skills/block-task/{SKILL.md → SKILL.en.md} +0 -0
- /package/templates/.agents/skills/check-task/{SKILL.md → SKILL.en.md} +0 -0
- /package/templates/.agents/skills/commit/{SKILL.md → SKILL.en.md} +0 -0
- /package/templates/.agents/skills/commit/reference/{commit-message.md → commit-message.en.md} +0 -0
- /package/templates/.agents/skills/commit/reference/{copyright-check.md → copyright-check.en.md} +0 -0
- /package/templates/.agents/skills/commit/reference/{pr-summary-sync.md → pr-summary-sync.en.md} +0 -0
- /package/templates/.agents/skills/commit/reference/{task-status-update.md → task-status-update.en.md} +0 -0
- /package/templates/.agents/skills/complete-task/{SKILL.md → SKILL.en.md} +0 -0
- /package/templates/.agents/skills/create-issue/reference/{template-matching.md → template-matching.en.md} +0 -0
- /package/templates/.agents/skills/create-pr/reference/{branch-strategy.md → branch-strategy.en.md} +0 -0
- /package/templates/.agents/skills/create-pr/reference/{comment-publish.md → comment-publish.en.md} +0 -0
- /package/templates/.agents/skills/create-task/{SKILL.md → SKILL.en.md} +0 -0
- /package/templates/.agents/skills/implement-task/{SKILL.md → SKILL.en.md} +0 -0
- /package/templates/.agents/skills/implement-task/reference/{branch-management.md → branch-management.en.md} +0 -0
- /package/templates/.agents/skills/implement-task/reference/{implementation-rules.md → implementation-rules.en.md} +0 -0
- /package/templates/.agents/skills/implement-task/reference/{output-template.md → output-template.en.md} +0 -0
- /package/templates/.agents/skills/implement-task/reference/{report-template.md → report-template.en.md} +0 -0
- /package/templates/.agents/skills/init-labels/scripts/{init-labels.sh → init-labels.github.sh} +0 -0
- /package/templates/.agents/skills/init-milestones/scripts/{init-milestones.sh → init-milestones.github.sh} +0 -0
- /package/templates/.agents/skills/plan-task/{SKILL.md → SKILL.en.md} +0 -0
- /package/templates/.agents/skills/refine-task/{SKILL.md → SKILL.en.md} +0 -0
- /package/templates/.agents/skills/refine-task/reference/{fix-workflow.md → fix-workflow.en.md} +0 -0
- /package/templates/.agents/skills/refine-task/reference/{report-template.md → report-template.en.md} +0 -0
- /package/templates/.agents/skills/release/scripts/{manage-milestones.sh → manage-milestones.github.sh} +0 -0
- /package/templates/.agents/skills/review-task/{SKILL.md → SKILL.en.md} +0 -0
- /package/templates/.agents/skills/review-task/reference/{output-templates.md → output-templates.en.md} +0 -0
- /package/templates/.agents/skills/review-task/reference/{report-template.md → report-template.en.md} +0 -0
- /package/templates/.agents/skills/review-task/reference/{review-criteria.md → review-criteria.en.md} +0 -0
- /package/templates/.agents/skills/test/{SKILL.md → SKILL.en.md} +0 -0
- /package/templates/.agents/skills/test-integration/{SKILL.md → SKILL.en.md} +0 -0
- /package/templates/.agents/skills/update-agent-infra/{SKILL.md → SKILL.en.md} +0 -0
- /package/templates/.agents/skills/upgrade-dependency/{SKILL.md → SKILL.en.md} +0 -0
- /package/templates/.agents/templates/{handoff.md → handoff.en.md} +0 -0
- /package/templates/.agents/templates/{review-report.md → review-report.en.md} +0 -0
- /package/templates/.agents/templates/{task.md → task.en.md} +0 -0
- /package/templates/.agents/workflows/{bug-fix.yaml → bug-fix.en.yaml} +0 -0
- /package/templates/.agents/workflows/{code-review.yaml → code-review.en.yaml} +0 -0
- /package/templates/.agents/workflows/{feature-development.yaml → feature-development.en.yaml} +0 -0
- /package/templates/.agents/workflows/{refactoring.yaml → refactoring.en.yaml} +0 -0
- /package/templates/.agents/workspace/{README.md → README.en.md} +0 -0
- /package/templates/.claude/commands/{analyze-task.md → analyze-task.en.md} +0 -0
- /package/templates/.claude/commands/{archive-tasks.md → archive-tasks.en.md} +0 -0
- /package/templates/.claude/commands/{block-task.md → block-task.en.md} +0 -0
- /package/templates/.claude/commands/{cancel-task.md → cancel-task.en.md} +0 -0
- /package/templates/.claude/commands/{check-task.md → check-task.en.md} +0 -0
- /package/templates/.claude/commands/{close-codescan.md → close-codescan.en.md} +0 -0
- /package/templates/.claude/commands/{close-dependabot.md → close-dependabot.en.md} +0 -0
- /package/templates/.claude/commands/{commit.md → commit.en.md} +0 -0
- /package/templates/.claude/commands/{complete-task.md → complete-task.en.md} +0 -0
- /package/templates/.claude/commands/{create-issue.md → create-issue.en.md} +0 -0
- /package/templates/.claude/commands/{create-pr.md → create-pr.en.md} +0 -0
- /package/templates/.claude/commands/{create-release-note.md → create-release-note.en.md} +0 -0
- /package/templates/.claude/commands/{create-task.md → create-task.en.md} +0 -0
- /package/templates/.claude/commands/{implement-task.md → implement-task.en.md} +0 -0
- /package/templates/.claude/commands/{import-codescan.md → import-codescan.en.md} +0 -0
- /package/templates/.claude/commands/{import-dependabot.md → import-dependabot.en.md} +0 -0
- /package/templates/.claude/commands/{import-issue.md → import-issue.en.md} +0 -0
- /package/templates/.claude/commands/{init-labels.md → init-labels.en.md} +0 -0
- /package/templates/.claude/commands/{init-milestones.md → init-milestones.en.md} +0 -0
- /package/templates/.claude/commands/{plan-task.md → plan-task.en.md} +0 -0
- /package/templates/.claude/commands/{refine-task.md → refine-task.en.md} +0 -0
- /package/templates/.claude/commands/{refine-title.md → refine-title.en.md} +0 -0
- /package/templates/.claude/commands/{release.md → release.en.md} +0 -0
- /package/templates/.claude/commands/{restore-task.md → restore-task.en.md} +0 -0
- /package/templates/.claude/commands/{review-task.md → review-task.en.md} +0 -0
- /package/templates/.claude/commands/{test-integration.md → test-integration.en.md} +0 -0
- /package/templates/.claude/commands/{test.md → test.en.md} +0 -0
- /package/templates/.claude/commands/{update-agent-infra.md → update-agent-infra.en.md} +0 -0
- /package/templates/.claude/commands/{upgrade-dependency.md → upgrade-dependency.en.md} +0 -0
- /package/templates/.gemini/commands/_project_/{analyze-task.toml → analyze-task.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{archive-tasks.toml → archive-tasks.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{block-task.toml → block-task.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{cancel-task.toml → cancel-task.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{check-task.toml → check-task.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{close-codescan.toml → close-codescan.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{close-dependabot.toml → close-dependabot.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{commit.toml → commit.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{complete-task.toml → complete-task.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{create-issue.toml → create-issue.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{create-pr.toml → create-pr.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{create-release-note.toml → create-release-note.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{create-task.toml → create-task.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{implement-task.toml → implement-task.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{import-codescan.toml → import-codescan.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{import-dependabot.toml → import-dependabot.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{import-issue.toml → import-issue.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{init-labels.toml → init-labels.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{init-milestones.toml → init-milestones.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{plan-task.toml → plan-task.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{refine-task.toml → refine-task.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{refine-title.toml → refine-title.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{release.toml → release.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{restore-task.toml → restore-task.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{review-task.toml → review-task.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{test-integration.toml → test-integration.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{test.toml → test.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{update-agent-infra.toml → update-agent-infra.en.toml} +0 -0
- /package/templates/.gemini/commands/_project_/{upgrade-dependency.toml → upgrade-dependency.en.toml} +0 -0
- /package/templates/.opencode/commands/{analyze-task.md → analyze-task.en.md} +0 -0
- /package/templates/.opencode/commands/{archive-tasks.md → archive-tasks.en.md} +0 -0
- /package/templates/.opencode/commands/{block-task.md → block-task.en.md} +0 -0
- /package/templates/.opencode/commands/{cancel-task.md → cancel-task.en.md} +0 -0
- /package/templates/.opencode/commands/{check-task.md → check-task.en.md} +0 -0
- /package/templates/.opencode/commands/{close-codescan.md → close-codescan.en.md} +0 -0
- /package/templates/.opencode/commands/{close-dependabot.md → close-dependabot.en.md} +0 -0
- /package/templates/.opencode/commands/{commit.md → commit.en.md} +0 -0
- /package/templates/.opencode/commands/{complete-task.md → complete-task.en.md} +0 -0
- /package/templates/.opencode/commands/{create-issue.md → create-issue.en.md} +0 -0
- /package/templates/.opencode/commands/{create-pr.md → create-pr.en.md} +0 -0
- /package/templates/.opencode/commands/{create-release-note.md → create-release-note.en.md} +0 -0
- /package/templates/.opencode/commands/{create-task.md → create-task.en.md} +0 -0
- /package/templates/.opencode/commands/{implement-task.md → implement-task.en.md} +0 -0
- /package/templates/.opencode/commands/{import-codescan.md → import-codescan.en.md} +0 -0
- /package/templates/.opencode/commands/{import-dependabot.md → import-dependabot.en.md} +0 -0
- /package/templates/.opencode/commands/{import-issue.md → import-issue.en.md} +0 -0
- /package/templates/.opencode/commands/{init-labels.md → init-labels.en.md} +0 -0
- /package/templates/.opencode/commands/{init-milestones.md → init-milestones.en.md} +0 -0
- /package/templates/.opencode/commands/{plan-task.md → plan-task.en.md} +0 -0
- /package/templates/.opencode/commands/{refine-task.md → refine-task.en.md} +0 -0
- /package/templates/.opencode/commands/{refine-title.md → refine-title.en.md} +0 -0
- /package/templates/.opencode/commands/{release.md → release.en.md} +0 -0
- /package/templates/.opencode/commands/{restore-task.md → restore-task.en.md} +0 -0
- /package/templates/.opencode/commands/{review-task.md → review-task.en.md} +0 -0
- /package/templates/.opencode/commands/{test-integration.md → test-integration.en.md} +0 -0
- /package/templates/.opencode/commands/{test.md → test.en.md} +0 -0
- /package/templates/.opencode/commands/{update-agent-infra.md → update-agent-infra.en.md} +0 -0
- /package/templates/.opencode/commands/{upgrade-dependency.md → upgrade-dependency.en.md} +0 -0
package/README.md
CHANGED
|
@@ -35,6 +35,20 @@ agent-infra standardizes that collaboration surface. It gives every supported AI
|
|
|
35
35
|
|
|
36
36
|
## See it in Action
|
|
37
37
|
|
|
38
|
+
### Install & Initialize
|
|
39
|
+
|
|
40
|
+
<p align="center">
|
|
41
|
+
<img src="./assets/demo-init.gif" alt="CLI install and initialize demo" width="100%" style="max-width: 720px;">
|
|
42
|
+
</p>
|
|
43
|
+
|
|
44
|
+
Once initialized, open the project in your AI TUI and install the latest skills:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
/update-agent-infra
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
> AI reads `.agents/.airc.json`, auto-locates the installed template root, and syncs the latest skill manifests, managed files, and registry deterministically via `sync-templates.js`.
|
|
51
|
+
|
|
38
52
|
**Scenario**: Issue #42 reports *"Login API returns 500 when email contains a plus sign"*. Here is the full fix lifecycle — AI does the heavy lifting, you stay in control:
|
|
39
53
|
|
|
40
54
|
```bash
|
|
@@ -396,7 +410,7 @@ The generated `.agents/.airc.json` file is the central contract between the boot
|
|
|
396
410
|
"project": "my-project",
|
|
397
411
|
"org": "my-org",
|
|
398
412
|
"language": "en",
|
|
399
|
-
"templateVersion": "v0.5.
|
|
413
|
+
"templateVersion": "v0.5.2",
|
|
400
414
|
"files": {
|
|
401
415
|
"managed": [
|
|
402
416
|
".agents/workspace/README.md",
|
package/README.zh-CN.md
CHANGED
|
@@ -35,6 +35,20 @@ agent-infra 的目标就是把这层协作面标准化。它为所有支持的 A
|
|
|
35
35
|
|
|
36
36
|
## 实战演示
|
|
37
37
|
|
|
38
|
+
### 安装与初始化
|
|
39
|
+
|
|
40
|
+
<p align="center">
|
|
41
|
+
<img src="./assets/demo-init.gif" alt="CLI 安装初始化演示" width="100%" style="max-width: 720px;">
|
|
42
|
+
</p>
|
|
43
|
+
|
|
44
|
+
完成初始化后,在你的 AI TUI 中打开项目并安装最新 skills:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
/update-agent-infra
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
> AI 读取 `.agents/.airc.json`,自动定位已安装的模板根目录,并通过 `sync-templates.js` 确定性地同步最新的 skill 清单、managed 文件和注册表。
|
|
51
|
+
|
|
38
52
|
**场景**:Issue #42 报告 *"登录接口在邮箱包含加号时返回 500"*。以下是完整的修复流程 —— AI 执行主要工作,你掌控方向:
|
|
39
53
|
|
|
40
54
|
```bash
|
|
@@ -396,7 +410,7 @@ import-issue #42 从 GitHub Issue 导入任务
|
|
|
396
410
|
"project": "my-project",
|
|
397
411
|
"org": "my-org",
|
|
398
412
|
"language": "en",
|
|
399
|
-
"templateVersion": "v0.5.
|
|
413
|
+
"templateVersion": "v0.5.2",
|
|
400
414
|
"files": {
|
|
401
415
|
"managed": [
|
|
402
416
|
".agents/workspace/README.md",
|
package/lib/defaults.json
CHANGED
package/lib/init.js
CHANGED
|
@@ -92,14 +92,22 @@ async function cmdInit() {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
let language = await prompt('Language (en / zh)', 'zh');
|
|
95
|
-
closePrompt();
|
|
96
95
|
if (language === 'zh') language = 'zh-CN';
|
|
97
96
|
if (language !== 'en' && language !== 'zh-CN') {
|
|
97
|
+
closePrompt();
|
|
98
98
|
err(`Language must be 'en' or 'zh'. Got: ${language}`);
|
|
99
99
|
process.exitCode = 1;
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
const platformType = (await prompt('Platform type', 'github')).trim() || 'github';
|
|
104
|
+
closePrompt();
|
|
105
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(platformType)) {
|
|
106
|
+
err(`Platform type must match /^[a-z0-9][a-z0-9-]*$/. Got: ${platformType}`);
|
|
107
|
+
process.exitCode = 1;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
103
111
|
const project = projectName;
|
|
104
112
|
const replacements = { project, org: orgName };
|
|
105
113
|
|
|
@@ -118,9 +126,9 @@ async function cmdInit() {
|
|
|
118
126
|
geminiSrc = 'update-agent-infra.zh-CN.toml';
|
|
119
127
|
opencodeSrc = 'update-agent-infra.zh-CN.md';
|
|
120
128
|
} else {
|
|
121
|
-
claudeSrc = 'update-agent-infra.md';
|
|
122
|
-
geminiSrc = 'update-agent-infra.toml';
|
|
123
|
-
opencodeSrc = 'update-agent-infra.md';
|
|
129
|
+
claudeSrc = 'update-agent-infra.en.md';
|
|
130
|
+
geminiSrc = 'update-agent-infra.en.toml';
|
|
131
|
+
opencodeSrc = 'update-agent-infra.en.md';
|
|
124
132
|
}
|
|
125
133
|
|
|
126
134
|
// install skill
|
|
@@ -128,7 +136,8 @@ async function cmdInit() {
|
|
|
128
136
|
path.join(templateDir, '.agents', 'skills', 'update-agent-infra'),
|
|
129
137
|
path.join('.agents', 'skills', 'update-agent-infra'),
|
|
130
138
|
replacements,
|
|
131
|
-
language
|
|
139
|
+
language,
|
|
140
|
+
platformType
|
|
132
141
|
);
|
|
133
142
|
ok('Installed .agents/skills/update-agent-infra/');
|
|
134
143
|
|
|
@@ -161,6 +170,7 @@ async function cmdInit() {
|
|
|
161
170
|
project: projectName,
|
|
162
171
|
org: orgName,
|
|
163
172
|
language,
|
|
173
|
+
platform: { type: platformType },
|
|
164
174
|
templateVersion: VERSION,
|
|
165
175
|
sandbox: structuredClone(defaults.sandbox),
|
|
166
176
|
labels: structuredClone(defaults.labels),
|
package/lib/render.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
+
// Add a new identifier here only after shipping matching .{platform}. template variants.
|
|
5
|
+
const KNOWN_PLATFORMS = new Set(['github']);
|
|
6
|
+
const KNOWN_LANGUAGES = new Set(['en', 'zh-CN']);
|
|
7
|
+
|
|
4
8
|
function renderFile(src, dst, replacements) {
|
|
5
9
|
if (!fs.existsSync(src)) {
|
|
6
10
|
throw new Error(`Template file not found: ${src}`);
|
|
@@ -50,37 +54,95 @@ function containsPlaceholders(src) {
|
|
|
50
54
|
return content.includes('{{project}}') || content.includes('{{org}}');
|
|
51
55
|
}
|
|
52
56
|
|
|
53
|
-
function
|
|
54
|
-
|
|
57
|
+
function variantExt(relativePath) {
|
|
58
|
+
return path.extname(relativePath);
|
|
59
|
+
}
|
|
55
60
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
function variantBase(relativePath) {
|
|
62
|
+
const ext = variantExt(relativePath);
|
|
63
|
+
return relativePath.slice(0, -ext.length);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function withVariant(relativePath, variant) {
|
|
67
|
+
const ext = variantExt(relativePath);
|
|
68
|
+
const base = variantBase(relativePath);
|
|
69
|
+
return `${base}.${variant}${ext}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function stripVariant(relativePath, variant) {
|
|
73
|
+
return relativePath.replace(new RegExp(`\\.${variant.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\.`), '.');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function isPlatformVariant(relativePath, platform) {
|
|
77
|
+
const platforms = new Set([...KNOWN_PLATFORMS, platform]);
|
|
78
|
+
for (const candidate of platforms) {
|
|
79
|
+
if (relativePath.includes(`.${candidate}.`)) {
|
|
80
|
+
return true;
|
|
60
81
|
}
|
|
61
|
-
selected.set(relativePath, src);
|
|
62
82
|
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function isLangVariant(relativePath) {
|
|
87
|
+
for (const lang of KNOWN_LANGUAGES) {
|
|
88
|
+
if (relativePath.includes(`.${lang}.`)) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function langSelect(relativePaths, language) {
|
|
96
|
+
const selected = new Map();
|
|
63
97
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
98
|
+
for (const relativePath of relativePaths) {
|
|
99
|
+
if (relativePath.includes(`.${language}.`)) {
|
|
100
|
+
selected.set(stripVariant(relativePath, language), relativePath);
|
|
101
|
+
} else if (!isLangVariant(relativePath)) {
|
|
102
|
+
if (!selected.has(relativePath)) {
|
|
103
|
+
selected.set(relativePath, relativePath);
|
|
69
104
|
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return selected;
|
|
109
|
+
}
|
|
70
110
|
|
|
71
|
-
|
|
111
|
+
function platformSelect(entries, platform) {
|
|
112
|
+
const selected = new Map();
|
|
113
|
+
|
|
114
|
+
for (const [relativePath, src] of entries) {
|
|
115
|
+
if (!relativePath.includes(`.${platform}.`)) {
|
|
116
|
+
continue;
|
|
72
117
|
}
|
|
118
|
+
selected.set(stripVariant(relativePath, platform), src);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
for (const [relativePath, src] of entries) {
|
|
122
|
+
if (selected.has(relativePath)) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (isPlatformVariant(relativePath, platform)) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
selected.set(relativePath, src);
|
|
73
129
|
}
|
|
74
130
|
|
|
75
131
|
return selected;
|
|
76
132
|
}
|
|
77
133
|
|
|
78
|
-
function
|
|
134
|
+
function selectLocalizedFiles(srcDir, language, platform = 'github') {
|
|
135
|
+
const relativePaths = walkFiles(srcDir).map((src) => path.relative(srcDir, src));
|
|
136
|
+
return platformSelect(langSelect(relativePaths, language), platform);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function copySkillDir(srcDir, dstDir, replacements, language, platform = 'github') {
|
|
79
140
|
if (!fs.existsSync(srcDir)) {
|
|
80
141
|
throw new Error(`Template directory not found: ${srcDir}`);
|
|
81
142
|
}
|
|
82
143
|
|
|
83
|
-
for (const [relativePath,
|
|
144
|
+
for (const [relativePath, selectedRelativePath] of selectLocalizedFiles(srcDir, language, platform)) {
|
|
145
|
+
const src = path.join(srcDir, selectedRelativePath);
|
|
84
146
|
const dst = path.join(dstDir, relativePath);
|
|
85
147
|
if (containsPlaceholders(src)) {
|
|
86
148
|
renderFile(src, dst, replacements);
|
|
@@ -4,12 +4,28 @@ import { runInteractive, runSafe } from '../shell.js';
|
|
|
4
4
|
import { resolveTaskBranch } from '../task-resolver.js';
|
|
5
5
|
|
|
6
6
|
const USAGE = `Usage: ai sandbox exec <branch> [cmd...]`;
|
|
7
|
-
export const
|
|
8
|
-
|
|
7
|
+
export const TMUX_ENTRY_SCRIPT = `
|
|
8
|
+
SESSION=work
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
if ! command -v tmux >/dev/null 2>&1; then
|
|
11
|
+
exec bash
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
if ! tmux has-session -t "$SESSION" 2>/dev/null; then
|
|
15
|
+
exec tmux new-session -s "$SESSION"
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
tmux list-sessions -F '#{session_name} #{session_attached}' 2>/dev/null | \\
|
|
19
|
+
while read -r name attached; do
|
|
20
|
+
[ "$name" = "$SESSION" ] && continue
|
|
21
|
+
case "$name" in
|
|
22
|
+
''|*[!0-9]*) continue ;;
|
|
23
|
+
esac
|
|
24
|
+
[ "$attached" = "0" ] && tmux kill-session -t "$name" 2>/dev/null || true
|
|
25
|
+
done
|
|
26
|
+
|
|
27
|
+
exec tmux new-session -t "$SESSION"
|
|
28
|
+
`.trim();
|
|
13
29
|
|
|
14
30
|
// Terminal-detection variables that interactive TUIs (e.g. claude-code)
|
|
15
31
|
// inspect to enable progressive enhancements such as the kitty keyboard
|
|
@@ -56,8 +72,7 @@ export function enter(args) {
|
|
|
56
72
|
|
|
57
73
|
const envFlags = terminalEnvFlags();
|
|
58
74
|
if (cmd.length === 0) {
|
|
59
|
-
|
|
60
|
-
return runInteractive('docker', ['exec', '-it', ...envFlags, container, 'bash']);
|
|
75
|
+
return runInteractive('docker', ['exec', '-it', ...envFlags, container, 'bash', '-c', TMUX_ENTRY_SCRIPT]);
|
|
61
76
|
}
|
|
62
77
|
|
|
63
78
|
return runInteractive('docker', ['exec', '-it', ...envFlags, container, ...cmd]);
|
|
@@ -22,6 +22,16 @@ RUN apt-get update && apt-get install -y \
|
|
|
22
22
|
&& apt-get update && apt-get install -y gh \
|
|
23
23
|
&& rm -rf /var/lib/apt/lists/*
|
|
24
24
|
|
|
25
|
+
# Enable extended keys in CSI u format so Shift+Enter and other modified
|
|
26
|
+
# keys are forwarded through tmux. Preserve terminal-detection variables
|
|
27
|
+
# injected at `docker exec` time when new tmux sessions are created.
|
|
28
|
+
RUN printf '%s\n' \
|
|
29
|
+
'set -g extended-keys always' \
|
|
30
|
+
'set -g extended-keys-format csi-u' \
|
|
31
|
+
"set -as terminal-features 'xterm*:extkeys'" \
|
|
32
|
+
"set -ga update-environment 'TERM_PROGRAM TERM_PROGRAM_VERSION LC_TERMINAL LC_TERMINAL_VERSION'" \
|
|
33
|
+
> /etc/tmux.conf
|
|
34
|
+
|
|
25
35
|
ENV LANG=en_US.UTF-8
|
|
26
36
|
ENV LC_ALL=en_US.UTF-8
|
|
27
37
|
ENV TERM=xterm-256color
|
package/lib/update.js
CHANGED
|
@@ -81,6 +81,7 @@ async function cmdUpdate() {
|
|
|
81
81
|
// read project config
|
|
82
82
|
const config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
|
|
83
83
|
const { project, org, language } = config;
|
|
84
|
+
const platformType = config.platform?.type || defaults.platform.type;
|
|
84
85
|
const replacements = { project, org };
|
|
85
86
|
|
|
86
87
|
info(`Updating seed files for: ${project}`);
|
|
@@ -93,9 +94,9 @@ async function cmdUpdate() {
|
|
|
93
94
|
geminiSrc = 'update-agent-infra.zh-CN.toml';
|
|
94
95
|
opencodeSrc = 'update-agent-infra.zh-CN.md';
|
|
95
96
|
} else {
|
|
96
|
-
claudeSrc = 'update-agent-infra.md';
|
|
97
|
-
geminiSrc = 'update-agent-infra.toml';
|
|
98
|
-
opencodeSrc = 'update-agent-infra.md';
|
|
97
|
+
claudeSrc = 'update-agent-infra.en.md';
|
|
98
|
+
geminiSrc = 'update-agent-infra.en.toml';
|
|
99
|
+
opencodeSrc = 'update-agent-infra.en.md';
|
|
99
100
|
}
|
|
100
101
|
|
|
101
102
|
// update skill
|
|
@@ -103,7 +104,8 @@ async function cmdUpdate() {
|
|
|
103
104
|
path.join(templateDir, '.agents', 'skills', 'update-agent-infra'),
|
|
104
105
|
path.join('.agents', 'skills', 'update-agent-infra'),
|
|
105
106
|
replacements,
|
|
106
|
-
language
|
|
107
|
+
language,
|
|
108
|
+
platformType
|
|
107
109
|
);
|
|
108
110
|
ok('Updated .agents/skills/update-agent-infra/');
|
|
109
111
|
try {
|
|
@@ -139,10 +141,16 @@ async function cmdUpdate() {
|
|
|
139
141
|
// sync file registry
|
|
140
142
|
const { added, changed } = syncFileRegistry(config);
|
|
141
143
|
const hasNewEntries = added.managed.length > 0 || added.merged.length > 0;
|
|
144
|
+
const platformAdded = !config.platform;
|
|
142
145
|
const sandboxAdded = !config.sandbox;
|
|
143
146
|
const labelsAdded = !config.labels;
|
|
144
147
|
let configChanged = changed;
|
|
145
148
|
|
|
149
|
+
if (platformAdded) {
|
|
150
|
+
config.platform = structuredClone(defaults.platform);
|
|
151
|
+
configChanged = true;
|
|
152
|
+
}
|
|
153
|
+
|
|
146
154
|
if (sandboxAdded) {
|
|
147
155
|
config.sandbox = structuredClone(defaults.sandbox);
|
|
148
156
|
configChanged = true;
|
|
@@ -163,7 +171,10 @@ async function cmdUpdate() {
|
|
|
163
171
|
for (const entry of added.merged) {
|
|
164
172
|
ok(` merged: ${entry}`);
|
|
165
173
|
}
|
|
166
|
-
} else if (sandboxAdded || labelsAdded) {
|
|
174
|
+
} else if (platformAdded || sandboxAdded || labelsAdded) {
|
|
175
|
+
if (platformAdded) {
|
|
176
|
+
info(`Default platform config added to ${CONFIG_PATH}.`);
|
|
177
|
+
}
|
|
167
178
|
if (sandboxAdded) {
|
|
168
179
|
info(`Default sandbox config added to ${CONFIG_PATH}.`);
|
|
169
180
|
}
|
|
@@ -179,6 +190,9 @@ async function cmdUpdate() {
|
|
|
179
190
|
if (hasNewEntries && labelsAdded) {
|
|
180
191
|
info(`Default labels.in config added to ${CONFIG_PATH}.`);
|
|
181
192
|
}
|
|
193
|
+
if (hasNewEntries && platformAdded) {
|
|
194
|
+
info(`Default platform config added to ${CONFIG_PATH}.`);
|
|
195
|
+
}
|
|
182
196
|
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
183
197
|
ok(`Updated ${CONFIG_PATH}`);
|
|
184
198
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fitlab-ai/agent-infra",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
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",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"build": "node scripts/build-inline.js",
|
|
49
|
+
"demo:regen": "vhs assets/demo-init.tape",
|
|
49
50
|
"prepare": "git config core.hooksPath .github/hooks || true",
|
|
50
51
|
"test": "node scripts/build-inline.js --check && node --test tests/cli/*.test.js tests/templates/*.test.js tests/core/*.test.js",
|
|
51
52
|
"prepublishOnly": "node scripts/build-inline.js --check && node --test tests/cli/*.test.js tests/templates/*.test.js tests/core/*.test.js"
|
|
@@ -100,15 +100,25 @@ Each AI tool has different strengths. Use them accordingly:
|
|
|
100
100
|
|
|
101
101
|
## Label Conventions
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
This project uses the following collaboration label prefixes, each with a defined scope:
|
|
104
104
|
|
|
105
105
|
| Label prefix | Issue | PR | Notes |
|
|
106
106
|
|---|---|---|---|
|
|
107
|
-
| `type:` | — | Yes | Issues use the native
|
|
107
|
+
| `type:` | — | Yes | Issues use the platform's native type/category field when available; PRs use `type:` labels for changelog generation and categorization |
|
|
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
|
-
|
|
111
|
+
The default GitHub setup initializes these labels with the `/init-labels` command.
|
|
112
|
+
|
|
113
|
+
## Private Platform Extensions
|
|
114
|
+
|
|
115
|
+
To adapt agent-infra to a private code-hosting platform:
|
|
116
|
+
|
|
117
|
+
1. Set `.agents/.airc.json` `platform.type` to a stable identifier such as `my-platform`.
|
|
118
|
+
2. Copy the generated rule files in `.agents/rules/` and adapt them to your platform's CLI or API while keeping the runtime filenames unchanged.
|
|
119
|
+
3. Add the customized rule files to `.agents/.airc.json` `files.ejected` so future `agent-infra update` runs do not overwrite them.
|
|
120
|
+
4. If you maintain a fork of the template source, add matching `.{platform}.` template variants before adding that platform identifier to the sync logic.
|
|
121
|
+
5. Validate the customized workflow on a test task before rolling it out broadly.
|
|
112
122
|
|
|
113
123
|
## Skill Authoring Conventions
|
|
114
124
|
|
|
@@ -100,15 +100,25 @@
|
|
|
100
100
|
|
|
101
101
|
## Label 规范
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
本项目的协作 labels 按以下前缀分类,各前缀有明确的适用范围:
|
|
104
104
|
|
|
105
105
|
| Label 前缀 | Issue | PR | 说明 |
|
|
106
106
|
|---|---|---|---|
|
|
107
|
-
| `type:` | — | Yes | Issue
|
|
107
|
+
| `type:` | — | Yes | Issue 优先使用平台原生的类型/分类字段;PR 无原生类型字段时,通过 `type:` label 驱动 changelog 和分类 |
|
|
108
108
|
| `status:` | Yes | — | PR 有自身状态流转(Open / Draft / Merged / Closed);Issue 使用 `status:` label 标记等待反馈、已确认等项目管理状态 |
|
|
109
109
|
| `in:` | Yes | Yes | Issue 和 PR 均可按模块筛选 |
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
默认 GitHub 配置下,可使用 `/init-labels` 命令一次性创建标准 labels。
|
|
112
|
+
|
|
113
|
+
## 私有平台扩展
|
|
114
|
+
|
|
115
|
+
如需将 agent-infra 接入私有代码托管平台:
|
|
116
|
+
|
|
117
|
+
1. 在 `.agents/.airc.json` 中把 `platform.type` 设为稳定标识,例如 `my-platform`。
|
|
118
|
+
2. 以 `.agents/rules/` 下已生成的规则文件为起点,改写为你的平台 CLI 或 API 调用,同时保持运行时文件名不变。
|
|
119
|
+
3. 将这些自定义规则文件加入 `.agents/.airc.json` 的 `files.ejected`,避免后续执行 `agent-infra update` 时被覆盖。
|
|
120
|
+
4. 如果你维护的是模板源码分支或私有 fork,需要先补齐对应的 `.{platform}.` 模板变体,再把该平台标识加入模板同步逻辑。
|
|
121
|
+
5. 在正式推广前,先用一个测试任务完整验证工作流和 gate 校验。
|
|
112
122
|
|
|
113
123
|
## Skill 编写规范
|
|
114
124
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Issue / PR Platform Commands
|
|
2
|
+
|
|
3
|
+
Read this file before verifying platform authentication, reading Issues / PRs, or creating and updating Issues / PRs.
|
|
4
|
+
|
|
5
|
+
## Authentication and Repository Info
|
|
6
|
+
|
|
7
|
+
Verify that GitHub CLI is available and authenticated:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
gh auth status
|
|
11
|
+
gh repo view --json nameWithOwner
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
If either command fails, stop or degrade according to the calling skill.
|
|
15
|
+
|
|
16
|
+
## Read and Create Issues
|
|
17
|
+
|
|
18
|
+
Read an Issue:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
gh issue view {issue-number} --json number,title,body,labels,state,milestone,url
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Create an Issue:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
gh issue create --title "{title}" --body "{body}" --assignee @me {label-args} {milestone-arg}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- expand `{label-args}` into repeated `--label` flags from the validated label list
|
|
31
|
+
- omit all `--label` flags when nothing valid remains
|
|
32
|
+
- omit `{milestone-arg}` entirely when no milestone should be set
|
|
33
|
+
|
|
34
|
+
Set the Issue Type:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
gh api "orgs/{owner}/issue-types" --jq '.[].name'
|
|
38
|
+
gh api "repos/{owner}/{repo}/issues/{issue-number}" -X PATCH -f type="{issue-type}" --silent
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Update Issues
|
|
42
|
+
|
|
43
|
+
Use this shape when updating titles, labels, assignees, or milestones:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
gh issue edit {issue-number} {edit-args}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Common arguments:
|
|
50
|
+
- `--title "{title}"`
|
|
51
|
+
- `--add-label "{label}"`
|
|
52
|
+
- `--remove-label "{label}"`
|
|
53
|
+
- `--add-assignee @me`
|
|
54
|
+
- `--milestone "{milestone}"`
|
|
55
|
+
|
|
56
|
+
Close an Issue:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
gh issue close {issue-number} --reason "{reason}"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Read Issue Comments
|
|
63
|
+
|
|
64
|
+
Read Issue comments or search for existing hidden markers:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
gh api "repos/{owner}/{repo}/issues/{issue-number}/comments" --paginate
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Read and Create PRs
|
|
71
|
+
|
|
72
|
+
Read a PR:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
gh pr view {pr-number} --json number,title,body,labels,state,milestone,url,files
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
List PRs:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
gh pr list --state {state} --base {base-branch} --json number,title,url,headRefName,baseRefName
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Create a PR:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
gh pr create --base "{target-branch}" --title "{title}" --assignee @me --body "$(cat <<'EOF'
|
|
88
|
+
{pr-body}
|
|
89
|
+
EOF
|
|
90
|
+
)"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Update PRs
|
|
94
|
+
|
|
95
|
+
Update PR titles, labels, or milestones with:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
gh pr edit {pr-number} {edit-args}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Common arguments:
|
|
102
|
+
- `--title "{title}"`
|
|
103
|
+
- `--add-label "{label}"`
|
|
104
|
+
- `--remove-label "{label}"`
|
|
105
|
+
- `--milestone "{milestone}"`
|
|
106
|
+
|
|
107
|
+
## Error Handling
|
|
108
|
+
|
|
109
|
+
- read failures: stop or skip based on the calling skill
|
|
110
|
+
- update failures: warn and continue when the caller marks the action as best-effort
|
|
111
|
+
- `@me` is resolved by `gh` CLI to the authenticated user
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Issue / PR 平台命令
|
|
2
|
+
|
|
3
|
+
在需要验证平台认证、读取 Issue / PR,或执行 Issue / PR 创建与更新前先读取本文件。
|
|
4
|
+
|
|
5
|
+
## 认证与仓库信息
|
|
6
|
+
|
|
7
|
+
先验证 GitHub CLI 可用且已认证:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
gh auth status
|
|
11
|
+
gh repo view --json nameWithOwner
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
如果任一命令失败,按调用该规则的 skill 约定停止或降级。
|
|
15
|
+
|
|
16
|
+
## Issue 读取与创建
|
|
17
|
+
|
|
18
|
+
读取 Issue:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
gh issue view {issue-number} --json number,title,body,labels,state,milestone,url
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
创建 Issue:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
gh issue create --title "{title}" --body "{body}" --assignee @me {label-args} {milestone-arg}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- `{label-args}` 由调用方按有效 label 列表展开为多个 `--label`
|
|
31
|
+
- 没有有效 label 时省略全部 `--label`
|
|
32
|
+
- `{milestone-arg}` 为空时整体省略
|
|
33
|
+
|
|
34
|
+
设置 Issue Type:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
gh api "orgs/{owner}/issue-types" --jq '.[].name'
|
|
38
|
+
gh api "repos/{owner}/{repo}/issues/{issue-number}" -X PATCH -f type="{issue-type}" --silent
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Issue 更新
|
|
42
|
+
|
|
43
|
+
更新标题、label、assignee 或 milestone 时使用:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
gh issue edit {issue-number} {edit-args}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
常见参数:
|
|
50
|
+
- `--title "{title}"`
|
|
51
|
+
- `--add-label "{label}"`
|
|
52
|
+
- `--remove-label "{label}"`
|
|
53
|
+
- `--add-assignee @me`
|
|
54
|
+
- `--milestone "{milestone}"`
|
|
55
|
+
|
|
56
|
+
关闭 Issue:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
gh issue close {issue-number} --reason "{reason}"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Issue 评论读取
|
|
63
|
+
|
|
64
|
+
读取 Issue 评论或按隐藏标记查找已有评论:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
gh api "repos/{owner}/{repo}/issues/{issue-number}/comments" --paginate
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## PR 读取与创建
|
|
71
|
+
|
|
72
|
+
读取 PR:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
gh pr view {pr-number} --json number,title,body,labels,state,milestone,url,files
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
列出 PR:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
gh pr list --state {state} --base {base-branch} --json number,title,url,headRefName,baseRefName
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
创建 PR:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
gh pr create --base "{target-branch}" --title "{title}" --assignee @me --body "$(cat <<'EOF'
|
|
88
|
+
{pr-body}
|
|
89
|
+
EOF
|
|
90
|
+
)"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## PR 更新
|
|
94
|
+
|
|
95
|
+
更新 PR 标题、label 或 milestone:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
gh pr edit {pr-number} {edit-args}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
常见参数:
|
|
102
|
+
- `--title "{title}"`
|
|
103
|
+
- `--add-label "{label}"`
|
|
104
|
+
- `--remove-label "{label}"`
|
|
105
|
+
- `--milestone "{milestone}"`
|
|
106
|
+
|
|
107
|
+
## 错误处理
|
|
108
|
+
|
|
109
|
+
- 读取失败:按调用方规则决定停止还是跳过
|
|
110
|
+
- 更新失败:如果调用方标记为 best-effort,输出警告并继续
|
|
111
|
+
- `@me` 由 `gh` CLI 解析为当前认证用户
|