@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.
Files changed (142) hide show
  1. package/README.md +44 -44
  2. package/README.zh-CN.md +44 -44
  3. package/lib/defaults.json +7 -9
  4. package/lib/init.js +1 -0
  5. package/lib/update.js +13 -1
  6. package/package.json +3 -3
  7. package/templates/.agents/QUICKSTART.md +7 -7
  8. package/templates/.agents/QUICKSTART.zh-CN.md +13 -13
  9. package/templates/.agents/README.md +31 -18
  10. package/templates/.agents/README.zh-CN.md +33 -20
  11. package/templates/.agents/rules/issue-sync.md +185 -0
  12. package/templates/.agents/rules/issue-sync.zh-CN.md +185 -0
  13. package/templates/.agents/scripts/validate-artifact.js +1280 -0
  14. package/templates/.agents/skills/analyze-task/SKILL.md +24 -1
  15. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +24 -1
  16. package/templates/.agents/skills/analyze-task/config/verify.json +41 -0
  17. package/templates/.agents/skills/archive-tasks/SKILL.md +40 -0
  18. package/templates/.agents/skills/archive-tasks/SKILL.zh-CN.md +40 -0
  19. package/templates/.agents/skills/archive-tasks/scripts/archive-tasks.sh +403 -0
  20. package/templates/.agents/skills/block-task/SKILL.md +25 -37
  21. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +25 -37
  22. package/templates/.agents/skills/block-task/config/verify.json +28 -0
  23. package/templates/.agents/skills/close-codescan/SKILL.md +7 -0
  24. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +7 -0
  25. package/templates/.agents/skills/close-dependabot/SKILL.md +7 -0
  26. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +7 -0
  27. package/templates/.agents/skills/commit/SKILL.md +17 -0
  28. package/templates/.agents/skills/commit/SKILL.zh-CN.md +17 -0
  29. package/templates/.agents/skills/commit/config/verify.json +22 -0
  30. package/templates/.agents/skills/commit/reference/task-status-update.md +3 -3
  31. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +3 -3
  32. package/templates/.agents/skills/complete-task/SKILL.md +24 -10
  33. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +24 -10
  34. package/templates/.agents/skills/complete-task/config/verify.json +30 -0
  35. package/templates/.agents/skills/create-issue/SKILL.md +41 -5
  36. package/templates/.agents/skills/create-issue/SKILL.zh-CN.md +41 -5
  37. package/templates/.agents/skills/create-issue/config/verify.json +27 -0
  38. package/templates/.agents/skills/create-issue/reference/label-and-type.md +10 -11
  39. package/templates/.agents/skills/create-issue/reference/label-and-type.zh-CN.md +10 -11
  40. package/templates/.agents/skills/create-pr/SKILL.md +59 -16
  41. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +59 -16
  42. package/templates/.agents/skills/create-pr/config/verify.json +26 -0
  43. package/templates/.agents/skills/create-pr/reference/branch-strategy.md +3 -3
  44. package/templates/.agents/skills/create-pr/reference/branch-strategy.zh-CN.md +3 -3
  45. package/templates/.agents/skills/{sync-pr → create-pr}/reference/comment-publish.md +6 -6
  46. package/templates/.agents/skills/{sync-pr → create-pr}/reference/comment-publish.zh-CN.md +10 -10
  47. package/templates/.agents/skills/create-pr/reference/pr-body-template.md +15 -6
  48. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +15 -6
  49. package/templates/.agents/skills/create-task/SKILL.md +25 -3
  50. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +25 -3
  51. package/templates/.agents/skills/create-task/config/verify.json +24 -0
  52. package/templates/.agents/skills/implement-task/SKILL.md +44 -8
  53. package/templates/.agents/skills/implement-task/SKILL.zh-CN.md +44 -8
  54. package/templates/.agents/skills/implement-task/config/verify.json +41 -0
  55. package/templates/.agents/skills/implement-task/reference/branch-management.md +48 -0
  56. package/templates/.agents/skills/implement-task/reference/branch-management.zh-CN.md +49 -0
  57. package/templates/.agents/skills/implement-task/reference/output-template.md +20 -0
  58. package/templates/.agents/skills/implement-task/reference/output-template.zh-CN.md +20 -0
  59. package/templates/.agents/skills/import-codescan/SKILL.md +18 -7
  60. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +18 -7
  61. package/templates/.agents/skills/import-codescan/config/verify.json +24 -0
  62. package/templates/.agents/skills/import-dependabot/SKILL.md +18 -7
  63. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +18 -7
  64. package/templates/.agents/skills/import-dependabot/config/verify.json +24 -0
  65. package/templates/.agents/skills/import-issue/SKILL.md +19 -1
  66. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +19 -1
  67. package/templates/.agents/skills/import-issue/config/verify.json +27 -0
  68. package/templates/.agents/skills/init-labels/SKILL.md +40 -10
  69. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +40 -10
  70. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +1 -22
  71. package/templates/.agents/skills/init-milestones/SKILL.md +13 -0
  72. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +13 -0
  73. package/templates/.agents/skills/plan-task/SKILL.md +29 -75
  74. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +29 -75
  75. package/templates/.agents/skills/plan-task/config/verify.json +42 -0
  76. package/templates/.agents/skills/refine-task/SKILL.md +51 -4
  77. package/templates/.agents/skills/refine-task/SKILL.zh-CN.md +51 -4
  78. package/templates/.agents/skills/refine-task/config/verify.json +37 -0
  79. package/templates/.agents/skills/refine-title/SKILL.md +10 -2
  80. package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +10 -2
  81. package/templates/.agents/skills/restore-task/SKILL.md +159 -0
  82. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +159 -0
  83. package/templates/.agents/skills/restore-task/config/verify.json +24 -0
  84. package/templates/.agents/skills/review-task/SKILL.md +25 -1
  85. package/templates/.agents/skills/review-task/SKILL.zh-CN.md +25 -1
  86. package/templates/.agents/skills/review-task/config/verify.json +40 -0
  87. package/templates/.agents/skills/update-agent-infra/SKILL.md +11 -0
  88. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +11 -0
  89. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +8 -10
  90. package/templates/.claude/commands/archive-tasks.md +9 -0
  91. package/templates/.claude/commands/archive-tasks.zh-CN.md +9 -0
  92. package/templates/.claude/commands/create-pr.md +1 -1
  93. package/templates/.claude/commands/create-pr.zh-CN.md +1 -1
  94. package/templates/.claude/commands/restore-task.md +9 -0
  95. package/templates/.claude/commands/restore-task.zh-CN.md +9 -0
  96. package/templates/.gemini/commands/_project_/archive-tasks.toml +10 -0
  97. package/templates/.gemini/commands/_project_/archive-tasks.zh-CN.toml +10 -0
  98. package/templates/.gemini/commands/_project_/restore-task.toml +8 -0
  99. package/templates/.gemini/commands/_project_/restore-task.zh-CN.toml +8 -0
  100. package/templates/.github/workflows/status-label.yml +82 -0
  101. package/templates/.opencode/commands/archive-tasks.md +11 -0
  102. package/templates/.opencode/commands/archive-tasks.zh-CN.md +11 -0
  103. package/templates/.opencode/commands/restore-task.md +11 -0
  104. package/templates/.opencode/commands/restore-task.zh-CN.md +11 -0
  105. package/templates/.agents/skills/sync-issue/SKILL.md +0 -91
  106. package/templates/.agents/skills/sync-issue/SKILL.zh-CN.md +0 -91
  107. package/templates/.agents/skills/sync-issue/reference/comment-publish.md +0 -88
  108. package/templates/.agents/skills/sync-issue/reference/comment-publish.zh-CN.md +0 -88
  109. package/templates/.agents/skills/sync-issue/reference/delivery-detection.md +0 -42
  110. package/templates/.agents/skills/sync-issue/reference/delivery-detection.zh-CN.md +0 -42
  111. package/templates/.agents/skills/sync-issue/reference/label-sync.md +0 -63
  112. package/templates/.agents/skills/sync-issue/reference/label-sync.zh-CN.md +0 -63
  113. package/templates/.agents/skills/sync-issue/reference/milestone-sync.md +0 -37
  114. package/templates/.agents/skills/sync-issue/reference/milestone-sync.zh-CN.md +0 -37
  115. package/templates/.agents/skills/sync-pr/SKILL.md +0 -72
  116. package/templates/.agents/skills/sync-pr/SKILL.zh-CN.md +0 -72
  117. package/templates/.agents/skills/sync-pr/reference/delivery-detection.md +0 -54
  118. package/templates/.agents/skills/sync-pr/reference/delivery-detection.zh-CN.md +0 -54
  119. package/templates/.claude/CLAUDE.md +0 -138
  120. package/templates/.claude/CLAUDE.zh-CN.md +0 -138
  121. package/templates/.claude/commands/sync-issue.md +0 -8
  122. package/templates/.claude/commands/sync-issue.zh-CN.md +0 -8
  123. package/templates/.claude/commands/sync-pr.md +0 -8
  124. package/templates/.claude/commands/sync-pr.zh-CN.md +0 -8
  125. package/templates/.claude/project-rules.md +0 -65
  126. package/templates/.claude/project-rules.zh-CN.md +0 -65
  127. package/templates/.codex/README.md +0 -38
  128. package/templates/.codex/README.zh-CN.md +0 -37
  129. package/templates/.gemini/commands/_project_/sync-issue.toml +0 -8
  130. package/templates/.gemini/commands/_project_/sync-issue.zh-CN.toml +0 -8
  131. package/templates/.gemini/commands/_project_/sync-pr.toml +0 -8
  132. package/templates/.gemini/commands/_project_/sync-pr.zh-CN.toml +0 -8
  133. package/templates/.opencode/COMMAND_STYLE_GUIDE.md +0 -232
  134. package/templates/.opencode/COMMAND_STYLE_GUIDE.zh-CN.md +0 -232
  135. package/templates/.opencode/README.md +0 -76
  136. package/templates/.opencode/README.zh-CN.md +0 -77
  137. package/templates/.opencode/commands/sync-issue.md +0 -11
  138. package/templates/.opencode/commands/sync-issue.zh-CN.md +0 -11
  139. package/templates/.opencode/commands/sync-pr.md +0 -11
  140. package/templates/.opencode/commands/sync-pr.zh-CN.md +0 -11
  141. package/templates/AGENTS.md +0 -112
  142. 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
- ### 7. Inform User
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
- ### 7. 告知用户
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 an `issue_number` field whose value is neither empty nor `N/A`. If not, **skip this step and output nothing**.
71
+ Check whether `task.md` includes a valid `issue_number`. If not, skip this step.
72
72
 
73
- If a valid `issue_number` exists, suggest syncing:
73
+ > Status-label sync rules live in `.agents/rules/issue-sync.md`. Read that file before syncing.
74
74
 
75
- > **IMPORTANT**: All TUI command formats listed below must be output in full. Do not show only the format for the current AI agent.
75
+ If a valid `issue_number` exists, set `status: blocked` directly.
76
76
 
77
- ```
78
- (Optional) Sync the blocking status to the Issue:
79
- - Claude Code / OpenCode: /sync-issue {issue_number}
80
- - Gemini CLI: /{{project}}:sync-issue {issue_number}
81
- - Codex CLI: $sync-issue {issue_number}
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
- ### 7. Inform User
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
- ### Alternative Plans
125
- {Any workarounds or alternative approaches considered}
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