@fitlab-ai/agent-infra 0.4.1 → 0.4.3
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 +44 -44
- package/README.zh-CN.md +44 -44
- package/lib/defaults.json +7 -9
- package/lib/init.js +1 -0
- package/lib/update.js +13 -1
- package/package.json +3 -3
- package/templates/.agents/QUICKSTART.md +7 -7
- package/templates/.agents/QUICKSTART.zh-CN.md +13 -13
- package/templates/.agents/README.md +31 -18
- package/templates/.agents/README.zh-CN.md +33 -20
- package/templates/.agents/rules/issue-sync.md +185 -0
- package/templates/.agents/rules/issue-sync.zh-CN.md +185 -0
- package/templates/.agents/scripts/validate-artifact.js +1280 -0
- package/templates/.agents/skills/analyze-task/SKILL.md +24 -1
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +24 -1
- package/templates/.agents/skills/analyze-task/config/verify.json +41 -0
- package/templates/.agents/skills/archive-tasks/SKILL.md +40 -0
- package/templates/.agents/skills/archive-tasks/SKILL.zh-CN.md +40 -0
- package/templates/.agents/skills/archive-tasks/scripts/archive-tasks.sh +403 -0
- package/templates/.agents/skills/block-task/SKILL.md +25 -37
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +25 -37
- package/templates/.agents/skills/block-task/config/verify.json +28 -0
- package/templates/.agents/skills/close-codescan/SKILL.md +7 -0
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +7 -0
- package/templates/.agents/skills/close-dependabot/SKILL.md +7 -0
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +7 -0
- package/templates/.agents/skills/commit/SKILL.md +17 -0
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +17 -0
- package/templates/.agents/skills/commit/config/verify.json +22 -0
- package/templates/.agents/skills/commit/reference/task-status-update.md +3 -3
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +3 -3
- package/templates/.agents/skills/complete-task/SKILL.md +24 -10
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +24 -10
- package/templates/.agents/skills/complete-task/config/verify.json +30 -0
- package/templates/.agents/skills/create-issue/SKILL.md +41 -5
- package/templates/.agents/skills/create-issue/SKILL.zh-CN.md +41 -5
- package/templates/.agents/skills/create-issue/config/verify.json +27 -0
- package/templates/.agents/skills/create-issue/reference/label-and-type.md +10 -11
- package/templates/.agents/skills/create-issue/reference/label-and-type.zh-CN.md +10 -11
- package/templates/.agents/skills/create-pr/SKILL.md +59 -16
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +59 -16
- package/templates/.agents/skills/create-pr/config/verify.json +26 -0
- package/templates/.agents/skills/create-pr/reference/branch-strategy.md +3 -3
- package/templates/.agents/skills/create-pr/reference/branch-strategy.zh-CN.md +3 -3
- package/templates/.agents/skills/{sync-pr → create-pr}/reference/comment-publish.md +6 -6
- package/templates/.agents/skills/{sync-pr → create-pr}/reference/comment-publish.zh-CN.md +10 -10
- package/templates/.agents/skills/create-pr/reference/pr-body-template.md +15 -6
- package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +15 -6
- package/templates/.agents/skills/create-task/SKILL.md +25 -3
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +25 -3
- package/templates/.agents/skills/create-task/config/verify.json +24 -0
- package/templates/.agents/skills/implement-task/SKILL.md +44 -8
- package/templates/.agents/skills/implement-task/SKILL.zh-CN.md +44 -8
- package/templates/.agents/skills/implement-task/config/verify.json +41 -0
- package/templates/.agents/skills/implement-task/reference/branch-management.md +48 -0
- package/templates/.agents/skills/implement-task/reference/branch-management.zh-CN.md +49 -0
- package/templates/.agents/skills/implement-task/reference/output-template.md +20 -0
- package/templates/.agents/skills/implement-task/reference/output-template.zh-CN.md +20 -0
- package/templates/.agents/skills/import-codescan/SKILL.md +18 -7
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +18 -7
- package/templates/.agents/skills/import-codescan/config/verify.json +24 -0
- package/templates/.agents/skills/import-dependabot/SKILL.md +18 -7
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +18 -7
- package/templates/.agents/skills/import-dependabot/config/verify.json +24 -0
- package/templates/.agents/skills/import-issue/SKILL.md +19 -1
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +19 -1
- package/templates/.agents/skills/import-issue/config/verify.json +27 -0
- package/templates/.agents/skills/init-labels/SKILL.md +40 -10
- package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +40 -10
- package/templates/.agents/skills/init-labels/scripts/init-labels.sh +1 -22
- package/templates/.agents/skills/init-milestones/SKILL.md +13 -0
- package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +13 -0
- package/templates/.agents/skills/plan-task/SKILL.md +29 -75
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +29 -75
- package/templates/.agents/skills/plan-task/config/verify.json +42 -0
- package/templates/.agents/skills/refine-task/SKILL.md +51 -4
- package/templates/.agents/skills/refine-task/SKILL.zh-CN.md +51 -4
- package/templates/.agents/skills/refine-task/config/verify.json +37 -0
- package/templates/.agents/skills/refine-title/SKILL.md +10 -2
- package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +10 -2
- package/templates/.agents/skills/restore-task/SKILL.md +159 -0
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +159 -0
- package/templates/.agents/skills/restore-task/config/verify.json +24 -0
- package/templates/.agents/skills/review-task/SKILL.md +25 -1
- package/templates/.agents/skills/review-task/SKILL.zh-CN.md +25 -1
- package/templates/.agents/skills/review-task/config/verify.json +40 -0
- package/templates/.agents/skills/update-agent-infra/SKILL.md +11 -0
- package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +11 -0
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +8 -10
- package/templates/.claude/commands/archive-tasks.md +9 -0
- package/templates/.claude/commands/archive-tasks.zh-CN.md +9 -0
- package/templates/.claude/commands/create-pr.md +1 -1
- package/templates/.claude/commands/create-pr.zh-CN.md +1 -1
- package/templates/.claude/commands/restore-task.md +9 -0
- package/templates/.claude/commands/restore-task.zh-CN.md +9 -0
- package/templates/.gemini/commands/_project_/archive-tasks.toml +10 -0
- package/templates/.gemini/commands/_project_/archive-tasks.zh-CN.toml +10 -0
- package/templates/.gemini/commands/_project_/restore-task.toml +8 -0
- package/templates/.gemini/commands/_project_/restore-task.zh-CN.toml +8 -0
- package/templates/.github/workflows/status-label.yml +82 -0
- package/templates/.opencode/commands/archive-tasks.md +11 -0
- package/templates/.opencode/commands/archive-tasks.zh-CN.md +11 -0
- package/templates/.opencode/commands/restore-task.md +11 -0
- package/templates/.opencode/commands/restore-task.zh-CN.md +11 -0
- package/templates/.agents/skills/sync-issue/SKILL.md +0 -91
- package/templates/.agents/skills/sync-issue/SKILL.zh-CN.md +0 -91
- package/templates/.agents/skills/sync-issue/reference/comment-publish.md +0 -88
- package/templates/.agents/skills/sync-issue/reference/comment-publish.zh-CN.md +0 -88
- package/templates/.agents/skills/sync-issue/reference/delivery-detection.md +0 -42
- package/templates/.agents/skills/sync-issue/reference/delivery-detection.zh-CN.md +0 -42
- package/templates/.agents/skills/sync-issue/reference/label-sync.md +0 -63
- package/templates/.agents/skills/sync-issue/reference/label-sync.zh-CN.md +0 -63
- package/templates/.agents/skills/sync-issue/reference/milestone-sync.md +0 -37
- package/templates/.agents/skills/sync-issue/reference/milestone-sync.zh-CN.md +0 -37
- package/templates/.agents/skills/sync-pr/SKILL.md +0 -72
- package/templates/.agents/skills/sync-pr/SKILL.zh-CN.md +0 -72
- package/templates/.agents/skills/sync-pr/reference/delivery-detection.md +0 -54
- package/templates/.agents/skills/sync-pr/reference/delivery-detection.zh-CN.md +0 -54
- package/templates/.claude/CLAUDE.md +0 -138
- package/templates/.claude/CLAUDE.zh-CN.md +0 -138
- package/templates/.claude/commands/sync-issue.md +0 -8
- package/templates/.claude/commands/sync-issue.zh-CN.md +0 -8
- package/templates/.claude/commands/sync-pr.md +0 -8
- package/templates/.claude/commands/sync-pr.zh-CN.md +0 -8
- package/templates/.claude/project-rules.md +0 -65
- package/templates/.claude/project-rules.zh-CN.md +0 -65
- package/templates/.codex/README.md +0 -38
- package/templates/.codex/README.zh-CN.md +0 -37
- package/templates/.gemini/commands/_project_/sync-issue.toml +0 -8
- package/templates/.gemini/commands/_project_/sync-issue.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/sync-pr.toml +0 -8
- package/templates/.gemini/commands/_project_/sync-pr.zh-CN.toml +0 -8
- package/templates/.opencode/COMMAND_STYLE_GUIDE.md +0 -232
- package/templates/.opencode/COMMAND_STYLE_GUIDE.zh-CN.md +0 -232
- package/templates/.opencode/README.md +0 -76
- package/templates/.opencode/README.zh-CN.md +0 -77
- package/templates/.opencode/commands/sync-issue.md +0 -11
- package/templates/.opencode/commands/sync-issue.zh-CN.md +0 -11
- package/templates/.opencode/commands/sync-pr.md +0 -11
- package/templates/.opencode/commands/sync-pr.zh-CN.md +0 -11
- package/templates/AGENTS.md +0 -112
- package/templates/AGENTS.zh-CN.md +0 -112
|
@@ -118,7 +118,30 @@ Update `.agents/workspace/active/{task-id}/task.md`:
|
|
|
118
118
|
- {yyyy-MM-dd HH:mm:ss} — **Requirement Analysis (Round {N})** by {agent} — Analysis completed → {analysis-artifact}
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
If task.md contains a valid `issue_number`, perform these sync actions (skip and continue on any failure):
|
|
122
|
+
- Read `.agents/rules/issue-sync.md` before syncing
|
|
123
|
+
- Set `status: pending-design-work`
|
|
124
|
+
- Publish the `{analysis-artifact}` comment
|
|
125
|
+
- Create or update the `<!-- sync-issue:{task-id}:task -->` comment (follow the task.md comment sync rule in issue-sync.md)
|
|
126
|
+
|
|
127
|
+
### 7. Verification Gate
|
|
128
|
+
|
|
129
|
+
Run the verification gate to confirm the task artifact and sync state are valid:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
node .agents/scripts/validate-artifact.js gate analyze-task .agents/workspace/active/{task-id} {analysis-artifact} --format text
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Handle the result as follows:
|
|
136
|
+
- exit code 0 (all checks passed) -> continue to the "Inform User" step
|
|
137
|
+
- exit code 1 (validation failed) -> fix the reported issues and run the gate again
|
|
138
|
+
- exit code 2 (network blocked) -> stop and tell the user that human intervention is required
|
|
139
|
+
|
|
140
|
+
Keep the gate output in your reply as fresh evidence. Do not claim completion without output from this run.
|
|
141
|
+
|
|
142
|
+
### 8. Inform User
|
|
143
|
+
|
|
144
|
+
> Execute this step only after the verification gate passes.
|
|
122
145
|
|
|
123
146
|
> **IMPORTANT**: All TUI command formats listed below must be output in full. Do not show only the format for the current AI agent.
|
|
124
147
|
|
|
@@ -118,7 +118,30 @@ date "+%Y-%m-%d %H:%M:%S"
|
|
|
118
118
|
- {yyyy-MM-dd HH:mm:ss} — **Requirement Analysis (Round {N})** by {agent} — Analysis completed → {analysis-artifact}
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
如果 task.md 中存在有效的 `issue_number`,执行以下同步操作(任一失败则跳过并继续):
|
|
122
|
+
- 执行前先读取 `.agents/rules/issue-sync.md`
|
|
123
|
+
- 设置 `status: pending-design-work`
|
|
124
|
+
- 发布 `{analysis-artifact}` 评论
|
|
125
|
+
- 创建或更新 `<!-- sync-issue:{task-id}:task -->` 评论(按 issue-sync.md 的 task.md 评论同步规则)
|
|
126
|
+
|
|
127
|
+
### 7. 完成校验
|
|
128
|
+
|
|
129
|
+
运行完成校验,确认任务产物和同步状态符合规范:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
node .agents/scripts/validate-artifact.js gate analyze-task .agents/workspace/active/{task-id} {analysis-artifact} --format text
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
处理结果:
|
|
136
|
+
- 退出码 0(全部通过)-> 继续到「告知用户」步骤
|
|
137
|
+
- 退出码 1(校验失败)-> 根据输出修复问题后重新运行校验
|
|
138
|
+
- 退出码 2(网络中断)-> 停止执行并告知用户需要人工介入
|
|
139
|
+
|
|
140
|
+
将校验输出保留在回复中作为当次验证输出。没有当次校验输出,不得声明完成。
|
|
141
|
+
|
|
142
|
+
### 8. 告知用户
|
|
143
|
+
|
|
144
|
+
> 仅在校验通过后执行本步骤。
|
|
122
145
|
|
|
123
146
|
> **重要**:以下「下一步」中列出的所有 TUI 命令格式必须完整输出,不要只展示当前 AI 代理对应的格式。
|
|
124
147
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill": "analyze-task",
|
|
3
|
+
"checks": {
|
|
4
|
+
"task-meta": {
|
|
5
|
+
"required_fields": [
|
|
6
|
+
"id",
|
|
7
|
+
"type",
|
|
8
|
+
"workflow",
|
|
9
|
+
"status",
|
|
10
|
+
"created_at",
|
|
11
|
+
"updated_at",
|
|
12
|
+
"current_step",
|
|
13
|
+
"assigned_to"
|
|
14
|
+
],
|
|
15
|
+
"expected_step": "requirement-analysis"
|
|
16
|
+
},
|
|
17
|
+
"artifact": {
|
|
18
|
+
"file_pattern": "analysis.md|analysis-r{N}.md",
|
|
19
|
+
"required_sections": [
|
|
20
|
+
"需求来源",
|
|
21
|
+
"需求理解",
|
|
22
|
+
"相关文件",
|
|
23
|
+
"影响评估",
|
|
24
|
+
"技术风险",
|
|
25
|
+
"工作量和复杂度评估"
|
|
26
|
+
],
|
|
27
|
+
"freshness_minutes": 30
|
|
28
|
+
},
|
|
29
|
+
"activity-log": {
|
|
30
|
+
"expected_action_pattern": "Requirement Analysis \\(Round \\d+\\)",
|
|
31
|
+
"freshness_minutes": 30
|
|
32
|
+
},
|
|
33
|
+
"github-sync": {
|
|
34
|
+
"when": "issue_number_exists",
|
|
35
|
+
"expected_status_label": "status: pending-design-work",
|
|
36
|
+
"expected_comment_marker": "<!-- sync-issue:{task-id}:{artifact-stem} -->",
|
|
37
|
+
"verify_comment_content": true,
|
|
38
|
+
"verify_task_comment_content": true
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: archive-tasks
|
|
3
|
+
description: "Archive completed tasks into a date-organized workspace directory"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Archive Completed Tasks
|
|
7
|
+
|
|
8
|
+
Move completed tasks from `.agents/workspace/completed/` into `.agents/workspace/archive/YYYY/MM/DD/TASK-xxx/` and rebuild the archive index `manifest.md`.
|
|
9
|
+
|
|
10
|
+
## Execution Flow
|
|
11
|
+
|
|
12
|
+
### 1. Verify the environment
|
|
13
|
+
|
|
14
|
+
Confirm that `.agents/workspace/completed/` exists, then choose one of these four invocation modes:
|
|
15
|
+
- no arguments: archive every completed task
|
|
16
|
+
- `--days N`: keep the most recent `N` days and archive older tasks
|
|
17
|
+
- `--before YYYY-MM-DD`: archive only tasks completed before the given date
|
|
18
|
+
- `TASK-ID...`: archive only the selected tasks
|
|
19
|
+
|
|
20
|
+
### 2. Run the archive script
|
|
21
|
+
|
|
22
|
+
Execute:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
bash .agents/skills/archive-tasks/scripts/archive-tasks.sh [--days N | --before YYYY-MM-DD | TASK-ID...]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The script is responsible for:
|
|
29
|
+
- reading `completed_at` from `task.md` frontmatter and falling back to `updated_at`
|
|
30
|
+
- moving task directories directly into `YYYY/MM/DD/TASK-xxx/` without compression
|
|
31
|
+
- skipping already archived, missing, or malformed tasks
|
|
32
|
+
- rebuilding `.agents/workspace/archive/manifest.md` from all archived tasks
|
|
33
|
+
- printing an archive and skip summary
|
|
34
|
+
|
|
35
|
+
### 3. Inform the user
|
|
36
|
+
|
|
37
|
+
Report:
|
|
38
|
+
- how many tasks were archived
|
|
39
|
+
- how many tasks were skipped and why
|
|
40
|
+
- the path to `manifest.md`
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: archive-tasks
|
|
3
|
+
description: "归档已完成任务到按日期组织的目录"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 归档已完成任务
|
|
7
|
+
|
|
8
|
+
将 `.agents/workspace/completed/` 中的已完成任务移动到 `.agents/workspace/archive/YYYY/MM/DD/TASK-xxx/`,并重建归档索引 `manifest.md`。
|
|
9
|
+
|
|
10
|
+
## 执行流程
|
|
11
|
+
|
|
12
|
+
### 1. 验证环境
|
|
13
|
+
|
|
14
|
+
确认 `.agents/workspace/completed/` 存在,并根据用户输入选择以下四种调用方式之一:
|
|
15
|
+
- 无参数:归档全部已完成任务
|
|
16
|
+
- `--days N`:保留最近 `N` 天,仅归档更早的任务
|
|
17
|
+
- `--before YYYY-MM-DD`:仅归档指定日期之前的任务
|
|
18
|
+
- `TASK-ID...`:仅归档指定任务
|
|
19
|
+
|
|
20
|
+
### 2. 运行归档脚本
|
|
21
|
+
|
|
22
|
+
执行以下命令:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
bash .agents/skills/archive-tasks/scripts/archive-tasks.sh [--days N | --before YYYY-MM-DD | TASK-ID...]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
脚本负责:
|
|
29
|
+
- 解析 `task.md` frontmatter 中的 `completed_at`(缺失时回退到 `updated_at`)
|
|
30
|
+
- 按 `YYYY/MM/DD/TASK-xxx/` 目录直接移动任务,不压缩
|
|
31
|
+
- 跳过已归档、缺少元数据或不存在的任务
|
|
32
|
+
- 全量重建 `.agents/workspace/archive/manifest.md`
|
|
33
|
+
- 输出归档与跳过摘要
|
|
34
|
+
|
|
35
|
+
### 3. 告知用户
|
|
36
|
+
|
|
37
|
+
向用户汇报:
|
|
38
|
+
- 本次归档的任务数量
|
|
39
|
+
- 跳过的任务数量和原因
|
|
40
|
+
- `manifest.md` 的路径
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR=$(CDPATH= cd "$(dirname "$0")" && pwd)
|
|
6
|
+
REPO_ROOT=$(CDPATH= cd "$SCRIPT_DIR/../../../.." && pwd)
|
|
7
|
+
WORKSPACE_ROOT="$REPO_ROOT/.agents/workspace"
|
|
8
|
+
COMPLETED_DIR="$WORKSPACE_ROOT/completed"
|
|
9
|
+
ARCHIVE_DIR="$WORKSPACE_ROOT/archive"
|
|
10
|
+
MANIFEST_PATH="$ARCHIVE_DIR/manifest.md"
|
|
11
|
+
|
|
12
|
+
tmpdir="$(mktemp -d)"
|
|
13
|
+
trap 'rm -rf "$tmpdir"' EXIT HUP INT TERM
|
|
14
|
+
|
|
15
|
+
IDS_FILE="$tmpdir/task-ids.txt"
|
|
16
|
+
: > "$IDS_FILE"
|
|
17
|
+
|
|
18
|
+
usage() {
|
|
19
|
+
cat <<'EOF'
|
|
20
|
+
Usage: bash .agents/skills/archive-tasks/scripts/archive-tasks.sh [--days N | --before YYYY-MM-DD | TASK-ID...]
|
|
21
|
+
EOF
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
trim_value() {
|
|
25
|
+
printf '%s' "$1" | sed "s/^['\"]//; s/['\"]$//"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
extract_field() {
|
|
29
|
+
task_file="$1"
|
|
30
|
+
field_name="$2"
|
|
31
|
+
|
|
32
|
+
awk -v field_name="$field_name" '
|
|
33
|
+
BEGIN {
|
|
34
|
+
frontmatter = 0
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/^---[[:space:]]*$/ {
|
|
38
|
+
frontmatter += 1
|
|
39
|
+
if (frontmatter == 1) {
|
|
40
|
+
next
|
|
41
|
+
}
|
|
42
|
+
exit
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
frontmatter == 1 && index($0, field_name ":") == 1 {
|
|
46
|
+
value = $0
|
|
47
|
+
sub("^" field_name ":[[:space:]]*", "", value)
|
|
48
|
+
print value
|
|
49
|
+
exit
|
|
50
|
+
}
|
|
51
|
+
' "$task_file"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
extract_completed_at() {
|
|
55
|
+
task_file="$1"
|
|
56
|
+
completed_at=$(extract_field "$task_file" "completed_at")
|
|
57
|
+
|
|
58
|
+
if [ -z "$completed_at" ]; then
|
|
59
|
+
completed_at=$(extract_field "$task_file" "updated_at")
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
trim_value "$completed_at"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
extract_type() {
|
|
66
|
+
trim_value "$(extract_field "$1" "type")"
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
extract_title() {
|
|
70
|
+
title=$(
|
|
71
|
+
awk '
|
|
72
|
+
BEGIN {
|
|
73
|
+
frontmatter = 0
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/^---[[:space:]]*$/ {
|
|
77
|
+
frontmatter += 1
|
|
78
|
+
next
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
frontmatter < 2 {
|
|
82
|
+
next
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/^# / {
|
|
86
|
+
sub(/^# /, "")
|
|
87
|
+
print
|
|
88
|
+
exit
|
|
89
|
+
}
|
|
90
|
+
' "$1"
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
printf '%s' "$title" | sed 's/^任务://; s/^Task: //' | tr '\t\r\n' ' ' | sed 's/[[:space:]][[:space:]]*/ /g; s/^ //; s/ $//; s/|/\\|/g'
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
is_valid_date() {
|
|
97
|
+
case "$1" in
|
|
98
|
+
????-??-??)
|
|
99
|
+
return 0
|
|
100
|
+
;;
|
|
101
|
+
*)
|
|
102
|
+
return 1
|
|
103
|
+
;;
|
|
104
|
+
esac
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
date_to_int() {
|
|
108
|
+
printf '%s' "$1" | tr -d '-'
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
cutoff_date() {
|
|
112
|
+
days="$1"
|
|
113
|
+
|
|
114
|
+
if date -v-"$days"d "+%Y-%m-%d" >/dev/null 2>&1; then
|
|
115
|
+
date -v-"$days"d "+%Y-%m-%d"
|
|
116
|
+
return 0
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
date -d "$days days ago" "+%Y-%m-%d"
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
find_archived_task_dir() {
|
|
123
|
+
task_id="$1"
|
|
124
|
+
|
|
125
|
+
for year_dir in "$ARCHIVE_DIR"/[0-9][0-9][0-9][0-9]; do
|
|
126
|
+
[ -d "$year_dir" ] || continue
|
|
127
|
+
|
|
128
|
+
for month_dir in "$year_dir"/[0-9][0-9]; do
|
|
129
|
+
[ -d "$month_dir" ] || continue
|
|
130
|
+
|
|
131
|
+
for day_dir in "$month_dir"/[0-9][0-9]; do
|
|
132
|
+
[ -d "$day_dir" ] || continue
|
|
133
|
+
|
|
134
|
+
archived_dir="$day_dir/$task_id"
|
|
135
|
+
if [ -d "$archived_dir" ]; then
|
|
136
|
+
printf '%s\n' "$archived_dir"
|
|
137
|
+
return 0
|
|
138
|
+
fi
|
|
139
|
+
done
|
|
140
|
+
done
|
|
141
|
+
done
|
|
142
|
+
|
|
143
|
+
return 1
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
log_skip() {
|
|
147
|
+
task_id="$1"
|
|
148
|
+
reason="$2"
|
|
149
|
+
skipped_count=$((skipped_count + 1))
|
|
150
|
+
printf 'Skipped %s (%s)\n' "$task_id" "$reason"
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
archive_task_dir() {
|
|
154
|
+
task_dir="$1"
|
|
155
|
+
task_id=$(basename "$task_dir")
|
|
156
|
+
task_file="$task_dir/task.md"
|
|
157
|
+
|
|
158
|
+
if [ ! -f "$task_file" ]; then
|
|
159
|
+
log_skip "$task_id" "missing task.md"
|
|
160
|
+
return 0
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
completed_at=$(extract_completed_at "$task_file")
|
|
164
|
+
task_date=$(printf '%s' "$completed_at" | cut -c1-10)
|
|
165
|
+
|
|
166
|
+
if ! is_valid_date "$task_date"; then
|
|
167
|
+
log_skip "$task_id" "missing completed_at/updated_at date"
|
|
168
|
+
return 0
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
year=$(printf '%s' "$task_date" | cut -c1-4)
|
|
172
|
+
month=$(printf '%s' "$task_date" | cut -c6-7)
|
|
173
|
+
day=$(printf '%s' "$task_date" | cut -c9-10)
|
|
174
|
+
destination_dir="$ARCHIVE_DIR/$year/$month/$day/$task_id"
|
|
175
|
+
relative_path="$year/$month/$day/$task_id/"
|
|
176
|
+
|
|
177
|
+
if [ -d "$destination_dir" ]; then
|
|
178
|
+
log_skip "$task_id" "already archived at $relative_path"
|
|
179
|
+
return 0
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
mkdir -p "$ARCHIVE_DIR/$year/$month/$day"
|
|
183
|
+
mv "$task_dir" "$destination_dir"
|
|
184
|
+
archived_count=$((archived_count + 1))
|
|
185
|
+
printf 'Archived %s -> %s\n' "$task_id" "$relative_path"
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
should_archive_filtered_task() {
|
|
189
|
+
task_dir="$1"
|
|
190
|
+
task_file="$task_dir/task.md"
|
|
191
|
+
|
|
192
|
+
if [ ! -f "$task_file" ]; then
|
|
193
|
+
return 0
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
completed_at=$(extract_completed_at "$task_file")
|
|
197
|
+
task_date=$(printf '%s' "$completed_at" | cut -c1-10)
|
|
198
|
+
|
|
199
|
+
if ! is_valid_date "$task_date"; then
|
|
200
|
+
return 0
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
task_value=$(date_to_int "$task_date")
|
|
204
|
+
cutoff_value=$(date_to_int "$FILTER_DATE")
|
|
205
|
+
|
|
206
|
+
[ "$task_value" -lt "$cutoff_value" ]
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
rebuild_manifest() {
|
|
210
|
+
entries_file="$tmpdir/manifest.tsv"
|
|
211
|
+
generated_at=$(date "+%Y-%m-%d %H:%M:%S")
|
|
212
|
+
|
|
213
|
+
mkdir -p "$ARCHIVE_DIR"
|
|
214
|
+
: > "$entries_file"
|
|
215
|
+
|
|
216
|
+
for year_dir in "$ARCHIVE_DIR"/[0-9][0-9][0-9][0-9]; do
|
|
217
|
+
[ -d "$year_dir" ] || continue
|
|
218
|
+
year=$(basename "$year_dir")
|
|
219
|
+
|
|
220
|
+
for month_dir in "$year_dir"/[0-9][0-9]; do
|
|
221
|
+
[ -d "$month_dir" ] || continue
|
|
222
|
+
month=$(basename "$month_dir")
|
|
223
|
+
|
|
224
|
+
for day_dir in "$month_dir"/[0-9][0-9]; do
|
|
225
|
+
[ -d "$day_dir" ] || continue
|
|
226
|
+
day=$(basename "$day_dir")
|
|
227
|
+
|
|
228
|
+
for task_dir in "$day_dir"/TASK-*; do
|
|
229
|
+
[ -d "$task_dir" ] || continue
|
|
230
|
+
|
|
231
|
+
task_id=$(basename "$task_dir")
|
|
232
|
+
task_file="$task_dir/task.md"
|
|
233
|
+
relative_path="$year/$month/$day/$task_id/"
|
|
234
|
+
title="$task_id"
|
|
235
|
+
task_type="unknown"
|
|
236
|
+
completed_at="$year-$month-$day"
|
|
237
|
+
|
|
238
|
+
if [ -f "$task_file" ]; then
|
|
239
|
+
file_completed_at=$(extract_completed_at "$task_file")
|
|
240
|
+
file_type=$(extract_type "$task_file")
|
|
241
|
+
file_title=$(extract_title "$task_file")
|
|
242
|
+
|
|
243
|
+
if [ -n "$file_completed_at" ]; then
|
|
244
|
+
completed_at="$file_completed_at"
|
|
245
|
+
fi
|
|
246
|
+
|
|
247
|
+
if [ -n "$file_type" ]; then
|
|
248
|
+
task_type="$file_type"
|
|
249
|
+
fi
|
|
250
|
+
|
|
251
|
+
if [ -n "$file_title" ]; then
|
|
252
|
+
title="$file_title"
|
|
253
|
+
fi
|
|
254
|
+
fi
|
|
255
|
+
|
|
256
|
+
printf '%s\t%s\t%s\t%s\t%s\n' "$completed_at" "$task_id" "$title" "$task_type" "$relative_path" >> "$entries_file"
|
|
257
|
+
done
|
|
258
|
+
done
|
|
259
|
+
done
|
|
260
|
+
done
|
|
261
|
+
|
|
262
|
+
{
|
|
263
|
+
echo "# Archive Manifest"
|
|
264
|
+
echo
|
|
265
|
+
echo "> Auto-generated by archive-tasks. Do not edit manually."
|
|
266
|
+
echo "> Last updated: $generated_at"
|
|
267
|
+
echo
|
|
268
|
+
echo "| Task ID | Title | Type | Completed | Path |"
|
|
269
|
+
echo "| --- | --- | --- | --- | --- |"
|
|
270
|
+
|
|
271
|
+
if [ -s "$entries_file" ]; then
|
|
272
|
+
LC_ALL=C sort -r "$entries_file" | while IFS="$(printf '\t')" read -r completed_at task_id title task_type relative_path; do
|
|
273
|
+
printf '| %s | %s | %s | %s | %s |\n' "$task_id" "$title" "$task_type" "$completed_at" "$relative_path"
|
|
274
|
+
done
|
|
275
|
+
fi
|
|
276
|
+
} > "$MANIFEST_PATH"
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if [ ! -d "$COMPLETED_DIR" ]; then
|
|
280
|
+
echo "Completed task directory not found: $COMPLETED_DIR"
|
|
281
|
+
exit 1
|
|
282
|
+
fi
|
|
283
|
+
|
|
284
|
+
MODE="all"
|
|
285
|
+
FILTER_DATE=""
|
|
286
|
+
|
|
287
|
+
while [ "$#" -gt 0 ]; do
|
|
288
|
+
case "$1" in
|
|
289
|
+
--days)
|
|
290
|
+
if [ "$MODE" != "all" ] || [ -s "$IDS_FILE" ]; then
|
|
291
|
+
echo "Cannot combine --days with other filters or task IDs"
|
|
292
|
+
exit 1
|
|
293
|
+
fi
|
|
294
|
+
|
|
295
|
+
if [ -z "${2:-}" ]; then
|
|
296
|
+
echo "Missing value for --days"
|
|
297
|
+
exit 1
|
|
298
|
+
fi
|
|
299
|
+
|
|
300
|
+
case "$2" in
|
|
301
|
+
''|*[!0-9]*)
|
|
302
|
+
echo "--days expects a non-negative integer"
|
|
303
|
+
exit 1
|
|
304
|
+
;;
|
|
305
|
+
esac
|
|
306
|
+
|
|
307
|
+
FILTER_DATE=$(cutoff_date "$2")
|
|
308
|
+
MODE="days"
|
|
309
|
+
shift 2
|
|
310
|
+
;;
|
|
311
|
+
--before)
|
|
312
|
+
if [ "$MODE" != "all" ] || [ -s "$IDS_FILE" ]; then
|
|
313
|
+
echo "Cannot combine --before with other filters or task IDs"
|
|
314
|
+
exit 1
|
|
315
|
+
fi
|
|
316
|
+
|
|
317
|
+
if [ -z "${2:-}" ]; then
|
|
318
|
+
echo "Missing value for --before"
|
|
319
|
+
exit 1
|
|
320
|
+
fi
|
|
321
|
+
|
|
322
|
+
if ! is_valid_date "$2"; then
|
|
323
|
+
echo "--before expects a date in YYYY-MM-DD format"
|
|
324
|
+
exit 1
|
|
325
|
+
fi
|
|
326
|
+
|
|
327
|
+
FILTER_DATE="$2"
|
|
328
|
+
MODE="before"
|
|
329
|
+
shift 2
|
|
330
|
+
;;
|
|
331
|
+
--help|-h)
|
|
332
|
+
usage
|
|
333
|
+
exit 0
|
|
334
|
+
;;
|
|
335
|
+
-*)
|
|
336
|
+
echo "Unknown option: $1"
|
|
337
|
+
usage
|
|
338
|
+
exit 1
|
|
339
|
+
;;
|
|
340
|
+
*)
|
|
341
|
+
printf '%s\n' "$1" >> "$IDS_FILE"
|
|
342
|
+
shift
|
|
343
|
+
;;
|
|
344
|
+
esac
|
|
345
|
+
done
|
|
346
|
+
|
|
347
|
+
if [ -s "$IDS_FILE" ]; then
|
|
348
|
+
if [ "$MODE" != "all" ]; then
|
|
349
|
+
echo "Cannot combine task IDs with --days or --before"
|
|
350
|
+
exit 1
|
|
351
|
+
fi
|
|
352
|
+
|
|
353
|
+
MODE="ids"
|
|
354
|
+
fi
|
|
355
|
+
|
|
356
|
+
archived_count=0
|
|
357
|
+
skipped_count=0
|
|
358
|
+
|
|
359
|
+
case "$MODE" in
|
|
360
|
+
all)
|
|
361
|
+
for task_dir in "$COMPLETED_DIR"/TASK-*; do
|
|
362
|
+
[ -d "$task_dir" ] || continue
|
|
363
|
+
archive_task_dir "$task_dir"
|
|
364
|
+
done
|
|
365
|
+
;;
|
|
366
|
+
days|before)
|
|
367
|
+
for task_dir in "$COMPLETED_DIR"/TASK-*; do
|
|
368
|
+
[ -d "$task_dir" ] || continue
|
|
369
|
+
|
|
370
|
+
if should_archive_filtered_task "$task_dir"; then
|
|
371
|
+
archive_task_dir "$task_dir"
|
|
372
|
+
fi
|
|
373
|
+
done
|
|
374
|
+
;;
|
|
375
|
+
ids)
|
|
376
|
+
while IFS= read -r task_id; do
|
|
377
|
+
[ -n "$task_id" ] || continue
|
|
378
|
+
task_dir="$COMPLETED_DIR/$task_id"
|
|
379
|
+
|
|
380
|
+
if [ -d "$task_dir" ]; then
|
|
381
|
+
archive_task_dir "$task_dir"
|
|
382
|
+
continue
|
|
383
|
+
fi
|
|
384
|
+
|
|
385
|
+
archived_dir=$(find_archived_task_dir "$task_id" || true)
|
|
386
|
+
if [ -n "$archived_dir" ]; then
|
|
387
|
+
relative_path=${archived_dir#"$ARCHIVE_DIR"/}
|
|
388
|
+
log_skip "$task_id" "already archived at $relative_path/"
|
|
389
|
+
continue
|
|
390
|
+
fi
|
|
391
|
+
|
|
392
|
+
log_skip "$task_id" "not found in completed/"
|
|
393
|
+
done < "$IDS_FILE"
|
|
394
|
+
;;
|
|
395
|
+
esac
|
|
396
|
+
|
|
397
|
+
rebuild_manifest
|
|
398
|
+
|
|
399
|
+
echo
|
|
400
|
+
echo "Summary:"
|
|
401
|
+
printf -- '- Archived: %s\n' "$archived_count"
|
|
402
|
+
printf -- '- Skipped: %s\n' "$skipped_count"
|
|
403
|
+
printf -- '- Manifest: %s\n' ".agents/workspace/archive/manifest.md"
|
|
@@ -68,20 +68,32 @@ ls .agents/workspace/blocked/{task-id}/task.md
|
|
|
68
68
|
|
|
69
69
|
### 6. Sync to Issue (Optional)
|
|
70
70
|
|
|
71
|
-
Check whether `task.md` includes
|
|
71
|
+
Check whether `task.md` includes a valid `issue_number`. If not, skip this step.
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
> Status-label sync rules live in `.agents/rules/issue-sync.md`. Read that file before syncing.
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
If a valid `issue_number` exists, set `status: blocked` directly.
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
### 7. Verification Gate
|
|
78
|
+
|
|
79
|
+
Run the verification gate to confirm the task artifact and sync state are valid:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
node .agents/scripts/validate-artifact.js gate block-task .agents/workspace/blocked/{task-id} --format text
|
|
82
83
|
```
|
|
83
84
|
|
|
84
|
-
|
|
85
|
+
Handle the result as follows:
|
|
86
|
+
- exit code 0 (all checks passed) -> continue to the "Inform User" step
|
|
87
|
+
- exit code 1 (validation failed) -> fix the reported issues and run the gate again
|
|
88
|
+
- exit code 2 (network blocked) -> stop and tell the user that human intervention is required
|
|
89
|
+
|
|
90
|
+
Keep the gate output in your reply as fresh evidence. Do not claim completion without output from this run.
|
|
91
|
+
|
|
92
|
+
### 8. Inform User
|
|
93
|
+
|
|
94
|
+
> Execute this step only after the verification gate passes.
|
|
95
|
+
|
|
96
|
+
> **IMPORTANT**: All TUI command formats listed below must be output in full. Do not show only the format for the current AI agent.
|
|
85
97
|
|
|
86
98
|
Output format:
|
|
87
99
|
```
|
|
@@ -94,35 +106,11 @@ Archived to: .agents/workspace/blocked/{task-id}/
|
|
|
94
106
|
To unblock when the issue is resolved:
|
|
95
107
|
mv .agents/workspace/blocked/{task-id} .agents/workspace/active/{task-id}
|
|
96
108
|
# Then update task.md: status -> active, remove blocked_at
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Output Template
|
|
100
|
-
|
|
101
|
-
Blocking information section to add to task.md:
|
|
102
|
-
|
|
103
|
-
```markdown
|
|
104
|
-
## Blocking Information
|
|
105
|
-
|
|
106
|
-
### Summary
|
|
107
|
-
{One-line description of why the task is blocked}
|
|
108
|
-
|
|
109
|
-
### Problem Description
|
|
110
|
-
{Detailed description of the blocking issue}
|
|
111
|
-
|
|
112
|
-
### Root Cause
|
|
113
|
-
{Analysis of why this is blocking}
|
|
114
|
-
|
|
115
|
-
### Attempted Solutions
|
|
116
|
-
- {What was tried and why it didn't work}
|
|
117
|
-
|
|
118
|
-
### Required to Unblock
|
|
119
|
-
- {What's needed: information, decision, resource, etc.}
|
|
120
|
-
|
|
121
|
-
### Unblocking Conditions
|
|
122
|
-
{Specific conditions that would allow work to resume}
|
|
123
109
|
|
|
124
|
-
|
|
125
|
-
|
|
110
|
+
Next step - check task status after unblocking:
|
|
111
|
+
- Claude Code / OpenCode: /check-task {task-id}
|
|
112
|
+
- Gemini CLI: /{{project}}:check-task {task-id}
|
|
113
|
+
- Codex CLI: $check-task {task-id}
|
|
126
114
|
```
|
|
127
115
|
|
|
128
116
|
## Completion Checklist
|