@fitlab-ai/agent-infra 0.4.5 → 0.5.0

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 (43) hide show
  1. package/README.md +16 -2
  2. package/README.zh-CN.md +16 -2
  3. package/bin/cli.js +19 -0
  4. package/lib/defaults.json +17 -0
  5. package/lib/init.js +1 -0
  6. package/lib/log.js +5 -10
  7. package/lib/merge.js +465 -0
  8. package/lib/sandbox/commands/create.js +1047 -0
  9. package/lib/sandbox/commands/enter.js +31 -0
  10. package/lib/sandbox/commands/ls.js +70 -0
  11. package/lib/sandbox/commands/rebuild.js +102 -0
  12. package/lib/sandbox/commands/rm.js +211 -0
  13. package/lib/sandbox/commands/vm.js +101 -0
  14. package/lib/sandbox/config.js +79 -0
  15. package/lib/sandbox/constants.js +113 -0
  16. package/lib/sandbox/dockerfile.js +95 -0
  17. package/lib/sandbox/engine.js +93 -0
  18. package/lib/sandbox/index.js +64 -0
  19. package/lib/sandbox/runtimes/ai-tools.dockerfile +26 -0
  20. package/lib/sandbox/runtimes/base.dockerfile +30 -0
  21. package/lib/sandbox/runtimes/java17.dockerfile +3 -0
  22. package/lib/sandbox/runtimes/java21.dockerfile +3 -0
  23. package/lib/sandbox/runtimes/node20.dockerfile +3 -0
  24. package/lib/sandbox/runtimes/node22.dockerfile +3 -0
  25. package/lib/sandbox/runtimes/python3.dockerfile +3 -0
  26. package/lib/sandbox/shell.js +48 -0
  27. package/lib/sandbox/task-resolver.js +35 -0
  28. package/lib/sandbox/tools.js +131 -0
  29. package/lib/update.js +16 -2
  30. package/package.json +5 -1
  31. package/templates/.agents/scripts/validate-artifact.js +40 -0
  32. package/templates/.agents/skills/archive-tasks/SKILL.md +6 -3
  33. package/templates/.agents/skills/archive-tasks/SKILL.zh-CN.md +6 -3
  34. package/templates/.agents/skills/archive-tasks/scripts/archive-tasks.sh +91 -8
  35. package/templates/.agents/skills/create-task/SKILL.md +6 -0
  36. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +6 -0
  37. package/templates/.agents/skills/create-task/config/verify.json +1 -0
  38. package/templates/.agents/skills/import-issue/SKILL.md +2 -0
  39. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +2 -0
  40. package/templates/.agents/skills/import-issue/config/verify.json +1 -0
  41. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +18 -1
  42. package/templates/.agents/templates/task.md +5 -4
  43. package/templates/.agents/templates/task.zh-CN.md +5 -4
@@ -5,7 +5,10 @@ description: "Archive completed tasks into a date-organized workspace directory"
5
5
 
6
6
  # Archive Completed Tasks
7
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`.
8
+ Move completed tasks from `.agents/workspace/completed/` into `.agents/workspace/archive/YYYY/MM/DD/TASK-xxx/` and rebuild a three-level archive index:
9
+ - root manifest: `.agents/workspace/archive/manifest.md`
10
+ - yearly manifest: `.agents/workspace/archive/YYYY/manifest.md`
11
+ - monthly manifest: `.agents/workspace/archive/YYYY/MM/manifest.md`
9
12
 
10
13
  ## Execution Flow
11
14
 
@@ -29,7 +32,7 @@ The script is responsible for:
29
32
  - reading `completed_at` from `task.md` frontmatter and falling back to `updated_at`
30
33
  - moving task directories directly into `YYYY/MM/DD/TASK-xxx/` without compression
31
34
  - skipping already archived, missing, or malformed tasks
32
- - rebuilding `.agents/workspace/archive/manifest.md` from all archived tasks
35
+ - rebuilding root, yearly, and monthly manifests from all archived tasks
33
36
  - printing an archive and skip summary
34
37
 
35
38
  ### 3. Inform the user
@@ -37,4 +40,4 @@ The script is responsible for:
37
40
  Report:
38
41
  - how many tasks were archived
39
42
  - how many tasks were skipped and why
40
- - the path to `manifest.md`
43
+ - the path to the root manifest
@@ -5,7 +5,10 @@ description: "归档已完成任务到按日期组织的目录"
5
5
 
6
6
  # 归档已完成任务
7
7
 
8
- 将 `.agents/workspace/completed/` 中的已完成任务移动到 `.agents/workspace/archive/YYYY/MM/DD/TASK-xxx/`,并重建归档索引 `manifest.md`。
8
+ 将 `.agents/workspace/completed/` 中的已完成任务移动到 `.agents/workspace/archive/YYYY/MM/DD/TASK-xxx/`,并重建三级归档索引:
9
+ - 根 manifest:`.agents/workspace/archive/manifest.md`
10
+ - 年 manifest:`.agents/workspace/archive/YYYY/manifest.md`
11
+ - 月 manifest:`.agents/workspace/archive/YYYY/MM/manifest.md`
9
12
 
10
13
  ## 执行流程
11
14
 
@@ -29,7 +32,7 @@ bash .agents/skills/archive-tasks/scripts/archive-tasks.sh [--days N | --before
29
32
  - 解析 `task.md` frontmatter 中的 `completed_at`(缺失时回退到 `updated_at`)
30
33
  - 按 `YYYY/MM/DD/TASK-xxx/` 目录直接移动任务,不压缩
31
34
  - 跳过已归档、缺少元数据或不存在的任务
32
- - 全量重建 `.agents/workspace/archive/manifest.md`
35
+ - 全量重建根 // 月三级 manifest
33
36
  - 输出归档与跳过摘要
34
37
 
35
38
  ### 3. 告知用户
@@ -37,4 +40,4 @@ bash .agents/skills/archive-tasks/scripts/archive-tasks.sh [--days N | --before
37
40
  向用户汇报:
38
41
  - 本次归档的任务数量
39
42
  - 跳过的任务数量和原因
40
- - `manifest.md` 的路径
43
+ - manifest 的路径
@@ -208,6 +208,8 @@ should_archive_filtered_task() {
208
208
 
209
209
  rebuild_manifest() {
210
210
  entries_file="$tmpdir/manifest.tsv"
211
+ month_keys_file="$tmpdir/manifest-months.tsv"
212
+ year_keys_file="$tmpdir/manifest-years.tsv"
211
213
  generated_at=$(date "+%Y-%m-%d %H:%M:%S")
212
214
 
213
215
  mkdir -p "$ARCHIVE_DIR"
@@ -253,26 +255,107 @@ rebuild_manifest() {
253
255
  fi
254
256
  fi
255
257
 
256
- printf '%s\t%s\t%s\t%s\t%s\n' "$completed_at" "$task_id" "$title" "$task_type" "$relative_path" >> "$entries_file"
258
+ printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\n' "$year" "$month" "$completed_at" "$task_id" "$title" "$task_type" "$relative_path" >> "$entries_file"
257
259
  done
258
260
  done
259
261
  done
260
262
  done
261
263
 
264
+ find "$ARCHIVE_DIR" -type f -name 'manifest.md' -exec rm -f {} \;
265
+
266
+ awk -F'\t' '{print $1 "\t" $2}' "$entries_file" | LC_ALL=C sort -u > "$month_keys_file"
267
+ awk -F'\t' '{print $1}' "$entries_file" | LC_ALL=C sort -u > "$year_keys_file"
268
+
269
+ while IFS="$(printf '\t')" read -r year month; do
270
+ [ -n "$year" ] || continue
271
+ [ -n "$month" ] || continue
272
+
273
+ month_entries_file="$tmpdir/manifest-${year}-${month}.tsv"
274
+ month_manifest_path="$ARCHIVE_DIR/$year/$month/manifest.md"
275
+
276
+ awk -F'\t' -v target_year="$year" -v target_month="$month" '
277
+ $1 == target_year && $2 == target_month {
278
+ print $3 "\t" $4 "\t" $5 "\t" $6 "\t" $7
279
+ }
280
+ ' "$entries_file" | LC_ALL=C sort -r > "$month_entries_file"
281
+
282
+ month_entry_count=$(wc -l < "$month_entries_file" | tr -d ' ')
283
+
284
+ {
285
+ echo "# Archive Manifest"
286
+ echo
287
+ echo "> Auto-generated by archive-tasks. Do not edit manually."
288
+ echo "> Last updated: $generated_at"
289
+ echo
290
+ echo "| Task ID | Title | Type | Completed | Path |"
291
+ echo "| --- | --- | --- | --- | --- |"
292
+
293
+ head -n 1000 "$month_entries_file" | while IFS="$(printf '\t')" read -r completed_at task_id title task_type relative_path; do
294
+ [ -n "$task_id" ] || continue
295
+ printf '| %s | %s | %s | %s | %s |\n' "$task_id" "$title" "$task_type" "$completed_at" "$relative_path"
296
+ done
297
+
298
+ if [ "$month_entry_count" -gt 1000 ]; then
299
+ echo
300
+ printf '> Showing 1000 of %s entries.\n' "$month_entry_count"
301
+ fi
302
+ } > "$month_manifest_path"
303
+ done < "$month_keys_file"
304
+
305
+ while IFS= read -r year; do
306
+ [ -n "$year" ] || continue
307
+
308
+ year_manifest_path="$ARCHIVE_DIR/$year/manifest.md"
309
+
310
+ {
311
+ echo "# Archive Manifest"
312
+ echo
313
+ echo "> Auto-generated by archive-tasks. Do not edit manually."
314
+ echo "> Last updated: $generated_at"
315
+ echo
316
+ echo "| Month | Tasks | Manifest |"
317
+ echo "| --- | --- | --- |"
318
+
319
+ awk -F'\t' -v target_year="$year" '
320
+ $1 == target_year {
321
+ counts[$2] += 1
322
+ }
323
+
324
+ END {
325
+ for (month in counts) {
326
+ print month "\t" counts[month]
327
+ }
328
+ }
329
+ ' "$entries_file" | LC_ALL=C sort -r | while IFS="$(printf '\t')" read -r month task_count; do
330
+ [ -n "$month" ] || continue
331
+ printf '| %s | %s | [%s/manifest.md](%s/manifest.md) |\n' "$month" "$task_count" "$month" "$month"
332
+ done
333
+ } > "$year_manifest_path"
334
+ done < "$year_keys_file"
335
+
262
336
  {
263
337
  echo "# Archive Manifest"
264
338
  echo
265
339
  echo "> Auto-generated by archive-tasks. Do not edit manually."
266
340
  echo "> Last updated: $generated_at"
267
341
  echo
268
- echo "| Task ID | Title | Type | Completed | Path |"
269
- echo "| --- | --- | --- | --- | --- |"
342
+ echo "| Year | Tasks | Manifest |"
343
+ echo "| --- | --- | --- |"
270
344
 
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
345
+ awk -F'\t' '
346
+ {
347
+ counts[$1] += 1
348
+ }
349
+
350
+ END {
351
+ for (year in counts) {
352
+ print year "\t" counts[year]
353
+ }
354
+ }
355
+ ' "$entries_file" | LC_ALL=C sort -r | while IFS="$(printf '\t')" read -r year task_count; do
356
+ [ -n "$year" ] || continue
357
+ printf '| %s | %s | [%s/manifest.md](%s/manifest.md) |\n' "$year" "$task_count" "$year" "$year"
358
+ done
276
359
  } > "$MANIFEST_PATH"
277
360
  }
278
361
 
@@ -27,6 +27,10 @@ Extract from the natural-language description:
27
27
  - **Task title**: a concise title (maximum 50 characters), in the same language as the user's description - do not translate it to English or apply Conventional Commits formatting
28
28
  - **Task type**: `feature` | `bugfix` | `refactor` | `docs` | `chore` (infer from the description)
29
29
  - **Workflow**: `feature-development` | `bug-fix` | `refactoring` (infer from the type)
30
+ - **Branch name**: format `<project>-<type>-<slug>`
31
+ - `<project>` comes from the `project` field in `.agents/.airc.json`
32
+ - `<type>` is the inferred task type
33
+ - `<slug>` is a kebab-case slug built from 3-6 English keywords extracted from the task title
30
34
  - **Detailed description**: the cleaned-up original user request
31
35
 
32
36
  If the description is unclear, **ask the user to clarify first**.
@@ -64,6 +68,7 @@ Task metadata (`task.md` YAML front matter):
64
68
  ```yaml
65
69
  id: TASK-{yyyyMMdd-HHmmss}
66
70
  type: feature|bugfix|refactor|docs|chore
71
+ branch: <project>-<type>-<slug>
67
72
  workflow: feature-development|bug-fix|refactoring
68
73
  status: active
69
74
  created_at: {yyyy-MM-dd HH:mm:ss}
@@ -87,6 +92,7 @@ Update `.agents/workspace/active/{task-id}/task.md`:
87
92
  - `current_step`: requirement-analysis
88
93
  - `assigned_to`: {current AI agent}
89
94
  - `updated_at`: {current time}
95
+ - `## Context` -> `- **Branch**:`: update it to the generated branch name
90
96
  - **Append** to `## Activity Log` (do NOT overwrite previous entries):
91
97
  ```
92
98
  - {yyyy-MM-dd HH:mm:ss} — **Task Created** by {agent} — Task created from description
@@ -27,6 +27,10 @@ description: "根据自然语言描述创建任务"
27
27
  - **任务标题**:简洁标题(最多 50 个字符),使用中文——不要翻译为英文,不要套用 Conventional Commits 格式
28
28
  - **任务类型**:`feature` | `bugfix` | `refactor` | `docs` | `chore`(从描述推断)
29
29
  - **工作流**:`feature-development` | `bug-fix` | `refactoring`(从类型推断)
30
+ - **分支名**:格式 `<project>-<type>-<slug>`
31
+ - `<project>` 从 `.agents/.airc.json` 的 `project` 字段读取
32
+ - `<type>` 为推断出的任务类型
33
+ - `<slug>` 从任务标题提取 3-6 个英文关键词并转为 kebab-case
30
34
  - **详细描述**:整理后的用户原始描述
31
35
 
32
36
  如果描述不清晰,**先向用户确认**再继续。
@@ -64,6 +68,7 @@ date +%Y%m%d-%H%M%S
64
68
  ```yaml
65
69
  id: TASK-{yyyyMMdd-HHmmss}
66
70
  type: feature|bugfix|refactor|docs|chore
71
+ branch: <project>-<type>-<slug>
67
72
  workflow: feature-development|bug-fix|refactoring
68
73
  status: active
69
74
  created_at: {yyyy-MM-dd HH:mm:ss}
@@ -87,6 +92,7 @@ date "+%Y-%m-%d %H:%M:%S"
87
92
  - `current_step`:requirement-analysis
88
93
  - `assigned_to`:{当前 AI 代理}
89
94
  - `updated_at`:{当前时间}
95
+ - `## 上下文` 中的 `- **分支**:`:更新为生成的分支名
90
96
  - **追加**到 `## Activity Log`(不要覆盖之前的记录):
91
97
  ```
92
98
  - {yyyy-MM-dd HH:mm:ss} — **Task Created** by {agent} — Task created from description
@@ -5,6 +5,7 @@
5
5
  "required_fields": [
6
6
  "id",
7
7
  "type",
8
+ "branch",
8
9
  "workflow",
9
10
  "status",
10
11
  "created_at",
@@ -44,6 +44,7 @@ Task metadata:
44
44
  id: TASK-{yyyyMMdd-HHmmss}
45
45
  issue_number: <issue-number>
46
46
  type: feature|bugfix|refactor|docs|chore
47
+ branch: <project>-<type>-<slug>
47
48
  workflow: feature-development|bug-fix|refactoring
48
49
  status: active
49
50
  created_at: {yyyy-MM-dd HH:mm:ss}
@@ -65,6 +66,7 @@ Update `.agents/workspace/active/{task-id}/task.md`:
65
66
  - `current_step`: requirement-analysis
66
67
  - `assigned_to`: {current AI agent}
67
68
  - `updated_at`: {current time}
69
+ - `## Context` -> `- **Branch**:`: update it to the generated branch name
68
70
  - **Append** to `## Activity Log` (do NOT overwrite previous entries):
69
71
  ```
70
72
  - {yyyy-MM-dd HH:mm:ss} — **Import Issue** by {agent} — Issue #{number} imported
@@ -44,6 +44,7 @@ date +%Y%m%d-%H%M%S
44
44
  id: TASK-{yyyyMMdd-HHmmss}
45
45
  issue_number: <issue-number>
46
46
  type: feature|bugfix|refactor|docs|chore
47
+ branch: <project>-<type>-<slug>
47
48
  workflow: feature-development|bug-fix|refactoring
48
49
  status: active
49
50
  created_at: {yyyy-MM-dd HH:mm:ss}
@@ -65,6 +66,7 @@ date "+%Y-%m-%d %H:%M:%S"
65
66
  - `current_step`:requirement-analysis
66
67
  - `assigned_to`:{当前 AI 代理}
67
68
  - `updated_at`:{当前时间}
69
+ - `## 上下文` 中的 `- **分支**:`:更新为生成的分支名
68
70
  - **追加**到 `## Activity Log`(不要覆盖之前的记录):
69
71
  ```
70
72
  - {yyyy-MM-dd HH:mm:ss} — **Import Issue** by {agent} — Issue #{number} imported
@@ -5,6 +5,7 @@
5
5
  "required_fields": [
6
6
  "id",
7
7
  "type",
8
+ "branch",
8
9
  "workflow",
9
10
  "status",
10
11
  "created_at",
@@ -20,6 +20,23 @@ import path from 'node:path';
20
20
  import { fileURLToPath } from 'node:url';
21
21
 
22
22
  const DEFAULTS = {
23
+ "sandbox": {
24
+ "runtimes": [
25
+ "node20"
26
+ ],
27
+ "tools": [
28
+ "claude-code",
29
+ "codex",
30
+ "opencode",
31
+ "gemini-cli"
32
+ ],
33
+ "dockerfile": null,
34
+ "vm": {
35
+ "cpu": null,
36
+ "memory": null,
37
+ "disk": null
38
+ }
39
+ },
23
40
  "labels": {
24
41
  "in": {}
25
42
  },
@@ -57,7 +74,7 @@ const DEFAULTS = {
57
74
  }
58
75
  };
59
76
 
60
- const INSTALLER_VERSION = "v0.4.5";
77
+ const INSTALLER_VERSION = "v0.5.0";
61
78
 
62
79
  function norm(p) { return p.replace(/\\/g, '/'); }
63
80
 
@@ -1,12 +1,13 @@
1
1
  ---
2
2
  id: task-XXX
3
- type: feature # feature | bugfix | refactor | docs | review
3
+ type: feature # feature | bugfix | refactor | docs | review
4
+ branch: "" # <project>-<type>-<slug>
4
5
  workflow: feature-development # feature-development | bug-fix | code-review | refactoring
5
- status: open # open | in-progress | review | blocked | completed
6
+ status: open # open | in-progress | review | blocked | completed
6
7
  created_at: YYYY-MM-DD
7
8
  updated_at: YYYY-MM-DD
8
- current_step: analysis # analysis | design | implementation | review | fix | commit
9
- assigned_to: "" # claude | codex | gemini | opencode | human
9
+ current_step: analysis # analysis | design | implementation | review | fix | commit
10
+ assigned_to: "" # claude | codex | gemini | opencode | human
10
11
  ---
11
12
 
12
13
  # Task: [Title]
@@ -1,12 +1,13 @@
1
1
  ---
2
2
  id: task-XXX
3
- type: feature # feature | bugfix | refactor | docs | review
3
+ type: feature # feature | bugfix | refactor | docs | review
4
+ branch: "" # <project>-<type>-<slug>
4
5
  workflow: feature-development # feature-development | bug-fix | code-review | refactoring
5
- status: open # open | in-progress | review | blocked | completed
6
+ status: open # open | in-progress | review | blocked | completed
6
7
  created_at: YYYY-MM-DD
7
8
  updated_at: YYYY-MM-DD
8
- current_step: analysis # analysis | design | implementation | review | fix | commit
9
- assigned_to: "" # claude | codex | gemini | opencode | human
9
+ current_step: analysis # analysis | design | implementation | review | fix | commit
10
+ assigned_to: "" # claude | codex | gemini | opencode | human
10
11
  ---
11
12
 
12
13
  # 任务:[标题]