@fitlab-ai/agent-infra 0.7.0 → 0.7.1

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 (73) hide show
  1. package/bin/cli.ts +1 -1
  2. package/dist/bin/cli.js +1 -1
  3. package/dist/lib/builtin-tuis.js +45 -0
  4. package/dist/lib/defaults.json +3 -0
  5. package/dist/lib/init.js +62 -23
  6. package/dist/lib/prompt.js +49 -1
  7. package/dist/lib/sandbox/commands/enter.js +1 -1
  8. package/dist/lib/sandbox/commands/list-running.js +58 -13
  9. package/dist/lib/sandbox/commands/rebuild.js +3 -11
  10. package/dist/lib/sandbox/commands/rm.js +2 -0
  11. package/dist/lib/sandbox/image-prune.js +18 -0
  12. package/dist/lib/sandbox/task-resolver.js +18 -0
  13. package/dist/lib/update.js +59 -18
  14. package/lib/builtin-tuis.ts +55 -0
  15. package/lib/defaults.json +3 -0
  16. package/lib/init.ts +87 -35
  17. package/lib/prompt.ts +54 -1
  18. package/lib/sandbox/commands/enter.ts +1 -1
  19. package/lib/sandbox/commands/list-running.ts +69 -16
  20. package/lib/sandbox/commands/rebuild.ts +3 -12
  21. package/lib/sandbox/commands/rm.ts +3 -0
  22. package/lib/sandbox/image-prune.ts +23 -0
  23. package/lib/sandbox/task-resolver.ts +23 -1
  24. package/lib/update.ts +71 -30
  25. package/package.json +1 -1
  26. package/templates/.agents/README.en.md +32 -0
  27. package/templates/.agents/README.zh-CN.md +32 -0
  28. package/templates/.agents/rules/task-short-id.en.md +141 -0
  29. package/templates/.agents/rules/task-short-id.zh-CN.md +124 -0
  30. package/templates/.agents/scripts/task-short-id.js +713 -0
  31. package/templates/.agents/skills/analyze-task/SKILL.en.md +4 -0
  32. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +4 -1
  33. package/templates/.agents/skills/block-task/SKILL.en.md +12 -0
  34. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +12 -1
  35. package/templates/.agents/skills/cancel-task/SKILL.en.md +12 -0
  36. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +12 -1
  37. package/templates/.agents/skills/check-task/SKILL.en.md +4 -0
  38. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +4 -1
  39. package/templates/.agents/skills/close-codescan/SKILL.en.md +11 -0
  40. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +11 -0
  41. package/templates/.agents/skills/close-dependabot/SKILL.en.md +11 -0
  42. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +11 -0
  43. package/templates/.agents/skills/code-task/SKILL.en.md +4 -0
  44. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +4 -1
  45. package/templates/.agents/skills/commit/SKILL.en.md +4 -0
  46. package/templates/.agents/skills/commit/SKILL.zh-CN.md +4 -0
  47. package/templates/.agents/skills/complete-task/SKILL.en.md +12 -0
  48. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +12 -1
  49. package/templates/.agents/skills/create-pr/SKILL.en.md +4 -0
  50. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +4 -0
  51. package/templates/.agents/skills/create-task/SKILL.en.md +14 -0
  52. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +14 -1
  53. package/templates/.agents/skills/import-codescan/SKILL.en.md +14 -0
  54. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +14 -0
  55. package/templates/.agents/skills/import-dependabot/SKILL.en.md +14 -0
  56. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +14 -0
  57. package/templates/.agents/skills/import-issue/SKILL.en.md +14 -0
  58. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +14 -0
  59. package/templates/.agents/skills/plan-task/SKILL.en.md +4 -0
  60. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +4 -1
  61. package/templates/.agents/skills/restore-task/SKILL.en.md +12 -0
  62. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +12 -1
  63. package/templates/.agents/skills/review-analysis/SKILL.en.md +4 -0
  64. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +4 -1
  65. package/templates/.agents/skills/review-code/SKILL.en.md +4 -0
  66. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +4 -1
  67. package/templates/.agents/skills/review-plan/SKILL.en.md +4 -0
  68. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +4 -1
  69. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +1 -0
  70. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +1 -0
  71. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +112 -21
  72. package/templates/.agents/templates/task.en.md +1 -0
  73. package/templates/.agents/templates/task.zh-CN.md +1 -0
@@ -13,6 +13,10 @@ Import the specified Issue and create a task. Argument: issue number.
13
13
  - Do not write or modify business code; import only
14
14
  - After executing this skill, you **must** immediately update task status
15
15
 
16
+ ## Task id short ref
17
+
18
+ > If `{task-id}` begins with `#`, follow the "SKILL parameter resolver" section of `.agents/rules/task-short-id.md`; treat `{task-id}` as the resolved full `TASK-YYYYMMDD-HHMMSS` form for every downstream command.
19
+
16
20
  ## Execution Flow
17
21
 
18
22
  ### 1. Retrieve Issue Information
@@ -119,6 +123,14 @@ If task.md contains a valid `issue_number`, perform these sync actions (skip and
119
123
 
120
124
  ### 7. Verification Gate
121
125
 
126
+ **Allocate short id first** (writes `short_id` back to task.md and the registry entry; the validation gate will read it):
127
+
128
+ ```bash
129
+ node .agents/scripts/task-short-id.js alloc "$task_id"
130
+ ```
131
+
132
+ If this fails (non-zero exit), follow the message — archive some active tasks or raise `task.shortIdLength` — and do NOT continue.
133
+
122
134
  Run the verification gate to confirm the task artifact and sync state are valid:
123
135
 
124
136
  ```bash
@@ -155,6 +167,8 @@ Next step - run requirements analysis:
155
167
  - Codex CLI: $analyze-task {task-id}
156
168
  ```
157
169
 
170
+
171
+
158
172
  ## Completion Checklist
159
173
 
160
174
  - [ ] Created the task file `.agents/workspace/active/{task-id}/task.md`
@@ -13,6 +13,10 @@ description: "从 Issue 导入并创建任务"
13
13
  - 不要编写或修改业务代码。仅做导入
14
14
  - 执行本技能后,你**必须**立即更新任务状态
15
15
 
16
+ ## 任务入参短号别名
17
+
18
+ > 如果 `{task-id}` 入参以 `#` 开头,先读取 `.agents/rules/task-short-id.md` 的「SKILL 入参解析」段执行解析;后续命令视 `{task-id}` 为解析后的全长 `TASK-YYYYMMDD-HHMMSS` 形式。
19
+
16
20
  ## 执行流程
17
21
 
18
22
  ### 1. 获取 Issue 信息
@@ -119,6 +123,14 @@ date "+%Y-%m-%d %H:%M:%S%:z"
119
123
 
120
124
  ### 7. 完成校验
121
125
 
126
+ **先调用短号分配**(保证 `short_id` 写回 task.md + 注册表 entry 已在;完成校验阶段会读取):
127
+
128
+ ```bash
129
+ node .agents/scripts/task-short-id.js alloc "$task_id"
130
+ ```
131
+
132
+ 如失败(退出码非 0),按提示「归档若干任务」或「调高 task.shortIdLength」处理;不要继续执行后续步骤。
133
+
122
134
  运行完成校验,确认任务产物和同步状态符合规范:
123
135
 
124
136
  ```bash
@@ -155,6 +167,8 @@ Issue #{number} 已导入。
155
167
  - Codex CLI:$analyze-task {task-id}
156
168
  ```
157
169
 
170
+
171
+
158
172
  ## 完成检查清单
159
173
 
160
174
  - [ ] 创建了任务文件 `.agents/workspace/active/{task-id}/task.md`
@@ -27,6 +27,10 @@ tail .agents/workspace/active/{task-id}/task.md
27
27
 
28
28
  Before the state check is complete, do not make external-state assertions such as "the code is unchanged", "tests passed", or "there are no other references", including in reasoning. This gate is only a structural floor; evidence pairing and authenticity still require the report template and review discipline.
29
29
 
30
+ ## Task id short ref
31
+
32
+ > If `{task-id}` begins with `#`, follow the "SKILL parameter resolver" section of `.agents/rules/task-short-id.md`; treat `{task-id}` as the resolved full `TASK-YYYYMMDD-HHMMSS` form for every downstream command.
33
+
30
34
  ## Steps
31
35
 
32
36
  ### 1. Verify Prerequisites
@@ -27,8 +27,11 @@ tail .agents/workspace/active/{task-id}/task.md
27
27
 
28
28
  状态核对完成前,禁止任何关于外部状态的断言(例如“代码没变”“测试已通过”“没有其他引用”),包括思考阶段。本门禁只提供结构下限;逐条证据配对和真实性仍需按报告模板与审查要求核对。
29
29
 
30
- ## 执行步骤
30
+ ## 任务入参短号别名
31
+
32
+ > 如果 `{task-id}` 入参以 `#` 开头,先读取 `.agents/rules/task-short-id.md` 的「SKILL 入参解析」段执行解析;后续命令视 `{task-id}` 为解析后的全长 `TASK-YYYYMMDD-HHMMSS` 形式。
31
33
 
34
+ ## 执行步骤
32
35
  ### 1. 验证前置条件
33
36
 
34
37
  检查必要文件:
@@ -16,6 +16,10 @@ Restore local task workspace files from platform Issue comments that contain syn
16
16
 
17
17
  Version stamp rule: when creating or updating `task.md` frontmatter, read `.agents/rules/version-stamp.md` first and write or refresh `agent_infra_version`.
18
18
 
19
+ ## Task id short ref
20
+
21
+ > If `{task-id}` begins with `#`, follow the "SKILL parameter resolver" section of `.agents/rules/task-short-id.md`; treat `{task-id}` as the resolved full `TASK-YYYYMMDD-HHMMSS` form for every downstream command.
22
+
19
23
  ## Steps
20
24
 
21
25
  ### 1. Verify Input and Environment
@@ -90,10 +94,18 @@ Update the restored `task.md`:
90
94
 
91
95
  Append an Activity Log entry indicating the task was restored from the platform Issue.
92
96
 
97
+ **Re-allocate short id** (the task directory is back under `active/`; alloc a new `#N`, which may differ from the pre-archival value):
98
+
99
+ ```bash
100
+ node .agents/scripts/task-short-id.js alloc "$task_id"
101
+ ```
102
+
93
103
  ### 7. Inform User
94
104
 
95
105
  Report the restored task id, restored file count, and the active task directory.
96
106
 
107
+
108
+
97
109
  ## Completion Checklist
98
110
 
99
111
  - [ ] Fetched Issue comments from the platform
@@ -16,8 +16,11 @@ description: "从平台 Issue 评论还原本地任务文件"
16
16
 
17
17
  版本戳规则:创建或更新 `task.md` frontmatter 时,先读取 `.agents/rules/version-stamp.md`,并写入或刷新 `agent_infra_version`。
18
18
 
19
- ## 执行步骤
19
+ ## 任务入参短号别名
20
+
21
+ > 如果 `{task-id}` 入参以 `#` 开头,先读取 `.agents/rules/task-short-id.md` 的「SKILL 入参解析」段执行解析;后续命令视 `{task-id}` 为解析后的全长 `TASK-YYYYMMDD-HHMMSS` 形式。
20
22
 
23
+ ## 执行步骤
21
24
  ### 1. 验证输入与环境
22
25
 
23
26
  检查:
@@ -90,10 +93,18 @@ date "+%Y-%m-%d %H:%M:%S%:z"
90
93
 
91
94
  追加 Activity Log,说明任务已从平台 Issue 还原。
92
95
 
96
+ **重新分配短号**(已把任务目录写回 `active/`,需要在锁内重新 alloc;新短号可能与归档前不同):
97
+
98
+ ```bash
99
+ node .agents/scripts/task-short-id.js alloc "$task_id"
100
+ ```
101
+
93
102
  ### 7. 告知用户
94
103
 
95
104
  报告已恢复的 task id、恢复文件数量和 active task 目录。
96
105
 
106
+
107
+
97
108
  ## 完成检查清单
98
109
 
99
110
  - [ ] 已从平台获取 Issue 评论
@@ -26,6 +26,10 @@ ls -la .agents/workspace/active/{task-id}/
26
26
  tail .agents/workspace/active/{task-id}/task.md
27
27
  ```
28
28
 
29
+ ## Task id short ref
30
+
31
+ > If `{task-id}` begins with `#`, follow the "SKILL parameter resolver" section of `.agents/rules/task-short-id.md`; treat `{task-id}` as the resolved full `TASK-YYYYMMDD-HHMMSS` form for every downstream command.
32
+
29
33
  ## Steps
30
34
 
31
35
  ### 1. Verify Prerequisites
@@ -28,8 +28,11 @@ tail .agents/workspace/active/{task-id}/task.md
28
28
 
29
29
  状态核对完成前,禁止任何关于外部状态的断言。
30
30
 
31
- ## 执行步骤
31
+ ## 任务入参短号别名
32
+
33
+ > 如果 `{task-id}` 入参以 `#` 开头,先读取 `.agents/rules/task-short-id.md` 的「SKILL 入参解析」段执行解析;后续命令视 `{task-id}` 为解析后的全长 `TASK-YYYYMMDD-HHMMSS` 形式。
32
34
 
35
+ ## 执行步骤
33
36
  ### 1. 验证前置条件
34
37
 
35
38
  要求存在:
@@ -36,6 +36,10 @@ tail .agents/workspace/active/{task-id}/task.md
36
36
 
37
37
  Before the state check is complete, do not make external-state assertions such as "the code is unchanged", "tests passed", or "there are no other references", including in reasoning. This gate is only a structural floor; evidence pairing and authenticity still require the report template and review discipline.
38
38
 
39
+ ## Task id short ref
40
+
41
+ > If `{task-id}` begins with `#`, follow the "SKILL parameter resolver" section of `.agents/rules/task-short-id.md`; treat `{task-id}` as the resolved full `TASK-YYYYMMDD-HHMMSS` form for every downstream command.
42
+
39
43
  ## Steps
40
44
 
41
45
  ### 1. Verify Prerequisites
@@ -36,8 +36,11 @@ tail .agents/workspace/active/{task-id}/task.md
36
36
 
37
37
  状态核对完成前,禁止任何关于外部状态的断言(例如“代码没变”“测试已通过”“没有其他引用”),包括思考阶段。本门禁只提供结构下限;逐条证据配对和真实性仍需按报告模板与审查要求核对。
38
38
 
39
- ## 执行步骤
39
+ ## 任务入参短号别名
40
+
41
+ > 如果 `{task-id}` 入参以 `#` 开头,先读取 `.agents/rules/task-short-id.md` 的「SKILL 入参解析」段执行解析;后续命令视 `{task-id}` 为解析后的全长 `TASK-YYYYMMDD-HHMMSS` 形式。
40
42
 
43
+ ## 执行步骤
41
44
  ### 1. 验证前置条件
42
45
 
43
46
  要求存在:
@@ -26,6 +26,10 @@ ls -la .agents/workspace/active/{task-id}/
26
26
  tail .agents/workspace/active/{task-id}/task.md
27
27
  ```
28
28
 
29
+ ## Task id short ref
30
+
31
+ > If `{task-id}` begins with `#`, follow the "SKILL parameter resolver" section of `.agents/rules/task-short-id.md`; treat `{task-id}` as the resolved full `TASK-YYYYMMDD-HHMMSS` form for every downstream command.
32
+
29
33
  ## Steps
30
34
 
31
35
  ### 1. Verify Prerequisites
@@ -28,8 +28,11 @@ tail .agents/workspace/active/{task-id}/task.md
28
28
 
29
29
  状态核对完成前,禁止任何关于外部状态的断言。
30
30
 
31
- ## 执行步骤
31
+ ## 任务入参短号别名
32
+
33
+ > 如果 `{task-id}` 入参以 `#` 开头,先读取 `.agents/rules/task-short-id.md` 的「SKILL 入参解析」段执行解析;后续命令视 `{task-id}` 为解析后的全长 `TASK-YYYYMMDD-HHMMSS` 形式。
32
34
 
35
+ ## 执行步骤
33
36
  ### 1. 验证前置条件
34
37
 
35
38
  要求存在:
@@ -47,6 +47,7 @@ The script outputs JSON to stdout. Parse and record the report.
47
47
  - `managed.written` / `managed.created`: updated / newly created managed files
48
48
  - `managed.removed`: deleted managed files (including old paths removed during template migrations)
49
49
  - `managed.skippedPlatform`: managed / merged entries skipped because they belong to a different platform
50
+ - `managed.skippedTUI`: managed / merged entries skipped because they are owned by a built-in TUI that is disabled in `tuis` (customTUI command files under the same path prefix are preserved)
50
51
  - `merged.pending`: list of merged files for AI to process
51
52
  - Each item has `target` (project-relative path) and `template` (template-root-relative path)
52
53
  - `registryAdded`: newly added file registry entries
@@ -39,6 +39,7 @@ node .agents/skills/update-agent-infra/scripts/sync-templates.js
39
39
  - `managed.written` / `managed.created`:已更新/新建的 managed 文件
40
40
  - `managed.removed`:被删除的 managed 文件(包括模板迁移时移除的旧路径)
41
41
  - `managed.skippedPlatform`:因归属其他平台而被跳过的 managed / merged 条目
42
+ - `managed.skippedTUI`:因 `tuis` 中未启用对应内建 TUI 而被跳过的 managed / merged 条目(落在同一路径前缀下的 customTUI 命令文件会被保留)
42
43
  - `merged.pending`:需要 AI 处理的 merged 文件列表
43
44
  - 每项包含 `target`(项目中的目标路径)和 `template`(模板根目录下的相对路径)
44
45
  - `registryAdded`:新增的文件注册条目
@@ -42,6 +42,9 @@ const DEFAULTS = {
42
42
  "disk": null
43
43
  }
44
44
  },
45
+ "task": {
46
+ "shortIdLength": 2
47
+ },
45
48
  "labels": {
46
49
  "in": {}
47
50
  },
@@ -88,6 +91,39 @@ const PACKAGE_NAME = '@fitlab-ai/agent-infra';
88
91
  const KNOWN_PLATFORMS = new Set(['github']);
89
92
  const KNOWN_LANGUAGES = new Set(['en', 'zh-CN']);
90
93
 
94
+ // Single source of truth for built-in TUI ids and owned path prefixes.
95
+ // Keep in sync with lib/builtin-tuis.ts (enforced by tests/unit/scripts/sync-templates-consts.test.ts).
96
+ const BUILTIN_TUI_IDS = ['claude-code', 'codex', 'gemini-cli', 'opencode'];
97
+ const BUILTIN_TUI_OWNED_PATH_PREFIXES = {
98
+ 'claude-code': ['.claude/'],
99
+ 'codex': ['.codex/'],
100
+ 'gemini-cli': ['.gemini/'],
101
+ 'opencode': ['.opencode/']
102
+ };
103
+
104
+ function resolveEnabledTUIs(value) {
105
+ // Missing field / null / non-array → full set (backward compat).
106
+ if (!Array.isArray(value)) return new Set(BUILTIN_TUI_IDS);
107
+ // Empty array is a meaningful user choice: no built-in TUI managed.
108
+ const set = new Set();
109
+ for (const v of value) {
110
+ if (typeof v === 'string' && BUILTIN_TUI_IDS.includes(v)) set.add(v);
111
+ }
112
+ return set;
113
+ }
114
+
115
+ function isPathOwnedByDisabledTUI(rel, enabledSet) {
116
+ const normalized = String(rel || '').replace(/\\/g, '/').replace(/^\.\//, '');
117
+ for (const tui of BUILTIN_TUI_IDS) {
118
+ if (enabledSet.has(tui)) continue;
119
+ for (const prefix of BUILTIN_TUI_OWNED_PATH_PREFIXES[tui]) {
120
+ const trimmed = prefix.replace(/\/$/, '');
121
+ if (normalized === trimmed || normalized.startsWith(prefix)) return true;
122
+ }
123
+ }
124
+ return false;
125
+ }
126
+
91
127
  function norm(p) { return p.replace(/\\/g, '/'); }
92
128
 
93
129
  function normDir(p) {
@@ -654,26 +690,32 @@ function learnAndGenerateCommands(projectRoot, customSkills, tool, templateSkill
654
690
  }
655
691
  }
656
692
 
657
- function generateCustomCommands(projectRoot, customSkills, project, lang, report, customTUIs, templateSkillNames) {
693
+ function generateCustomCommands(projectRoot, customSkills, project, lang, report, customTUIs, templateSkillNames, enabledTUIs) {
658
694
  for (const skill of customSkills) {
659
- writeIfChanged(
660
- projectRoot,
661
- `.claude/commands/${skill.dirName}.md`,
662
- generateClaudeCommand(skill, lang),
663
- report.custom.commands
664
- );
665
- writeIfChanged(
666
- projectRoot,
667
- '.gemini/commands/' + project + '/' + skill.dirName + '.toml',
668
- generateGeminiCommand(skill, lang),
669
- report.custom.commands
670
- );
671
- writeIfChanged(
672
- projectRoot,
673
- `.opencode/commands/${skill.dirName}.md`,
674
- generateOpenCodeCommand(skill, lang),
675
- report.custom.commands
676
- );
695
+ if (enabledTUIs.has('claude-code')) {
696
+ writeIfChanged(
697
+ projectRoot,
698
+ `.claude/commands/${skill.dirName}.md`,
699
+ generateClaudeCommand(skill, lang),
700
+ report.custom.commands
701
+ );
702
+ }
703
+ if (enabledTUIs.has('gemini-cli')) {
704
+ writeIfChanged(
705
+ projectRoot,
706
+ '.gemini/commands/' + project + '/' + skill.dirName + '.toml',
707
+ generateGeminiCommand(skill, lang),
708
+ report.custom.commands
709
+ );
710
+ }
711
+ if (enabledTUIs.has('opencode')) {
712
+ writeIfChanged(
713
+ projectRoot,
714
+ `.opencode/commands/${skill.dirName}.md`,
715
+ generateOpenCodeCommand(skill, lang),
716
+ report.custom.commands
717
+ );
718
+ }
677
719
  }
678
720
 
679
721
  const tools = Array.isArray(customTUIs) ? customTUIs : [];
@@ -969,6 +1011,7 @@ function syncTemplates(projectRoot, templateRootOverride) {
969
1011
 
970
1012
  const { project, org, language: lang = 'en' } = cfg;
971
1013
  const platformType = cfg.platform?.type || DEFAULTS.platform.type;
1014
+ const enabledTUIs = resolveEnabledTUIs(cfg.tuis);
972
1015
  const customTUIsConfig = Array.isArray(cfg.customTUIs) ? cfg.customTUIs : [];
973
1016
  const vars = { project, org };
974
1017
  const templateSkillNames = listTemplateSkillNames(templateRoot);
@@ -989,7 +1032,7 @@ function syncTemplates(projectRoot, templateRootOverride) {
989
1032
  errors: [],
990
1033
  conflicts: []
991
1034
  },
992
- managed: { written: [], created: [], unchanged: [], skippedMerged: [], skippedPlatform: [], removed: [] },
1035
+ managed: { written: [], created: [], unchanged: [], skippedMerged: [], skippedPlatform: [], skippedTUI: [], removed: [] },
993
1036
  custom: {
994
1037
  detected: [],
995
1038
  generated: [],
@@ -1016,10 +1059,12 @@ function syncTemplates(projectRoot, templateRootOverride) {
1016
1059
  const known = new Set([...managed, ...merged, ...ejected]);
1017
1060
  for (const e of (DEFAULTS.files.managed || [])) {
1018
1061
  if (isPathOwnedByOtherPlatform(e, platformType)) continue;
1062
+ if (isPathOwnedByDisabledTUI(e, enabledTUIs)) continue;
1019
1063
  if (!known.has(e)) { managed.push(e); known.add(e); report.registryAdded.push({ entry: e, list: 'managed' }); }
1020
1064
  }
1021
1065
  for (const e of (DEFAULTS.files.merged || [])) {
1022
1066
  if (isPathOwnedByOtherPlatform(e, platformType)) continue;
1067
+ if (isPathOwnedByDisabledTUI(e, enabledTUIs)) continue;
1023
1068
  if (!known.has(e)) { merged.push(e); known.add(e); report.registryAdded.push({ entry: e, list: 'merged' }); }
1024
1069
  }
1025
1070
 
@@ -1050,11 +1095,50 @@ function syncTemplates(projectRoot, templateRootOverride) {
1050
1095
  report.managed.removed.push(norm(path.relative(projectRoot, target)));
1051
1096
  }
1052
1097
 
1098
+ // Cleanup files owned by disabled built-in TUIs. Iterates managed + merged
1099
+ // only (ejected entries are explicitly user-retained, see ejected loop below).
1100
+ //
1101
+ // Protection rule: only skip files registered as customTUI command targets
1102
+ // (e.g. a customTUI configured with dir=.codex/commands/ when codex is
1103
+ // disabled). Built-in TUI custom-skill commands like
1104
+ // .gemini/commands/<project>/<dirName>.toml are intentionally NOT protected
1105
+ // here so that disabling gemini-cli actually frees the gemini directory —
1106
+ // they will be regenerated only for still-enabled TUIs (see
1107
+ // generateCustomCommands).
1108
+ for (const entry of [...managed, ...merged]) {
1109
+ if (!isPathOwnedByDisabledTUI(entry, enabledTUIs)) continue;
1110
+
1111
+ if (entry.endsWith('/')) {
1112
+ const dir = path.join(projectRoot, entry);
1113
+ if (!fs.existsSync(dir)) continue;
1114
+
1115
+ for (const filePath of walkDir(dir)) {
1116
+ const relProj = norm(path.relative(projectRoot, filePath));
1117
+ if (customTUICommandTargets.has(relProj)) continue;
1118
+ fs.unlinkSync(filePath);
1119
+ report.managed.removed.push(relProj);
1120
+ }
1121
+ removeEmptyDirs(dir);
1122
+ continue;
1123
+ }
1124
+
1125
+ const target = path.join(projectRoot, renderPathname(entry, project));
1126
+ if (!fs.existsSync(target)) continue;
1127
+ const relProj = norm(path.relative(projectRoot, target));
1128
+ if (customTUICommandTargets.has(relProj)) continue;
1129
+ fs.unlinkSync(target);
1130
+ report.managed.removed.push(relProj);
1131
+ }
1132
+
1053
1133
  for (const entry of managed) {
1054
1134
  if (isPathOwnedByOtherPlatform(entry, platformType)) {
1055
1135
  report.managed.skippedPlatform.push(entry);
1056
1136
  continue;
1057
1137
  }
1138
+ if (isPathOwnedByDisabledTUI(entry, enabledTUIs)) {
1139
+ report.managed.skippedTUI.push(entry);
1140
+ continue;
1141
+ }
1058
1142
 
1059
1143
  const isDir = entry.endsWith('/');
1060
1144
  let entryRels;
@@ -1140,7 +1224,7 @@ function syncTemplates(projectRoot, templateRootOverride) {
1140
1224
 
1141
1225
  const customSkills = detectCustomSkills(projectRoot, templateSkillNames);
1142
1226
  report.custom.detected = customSkills.map((skill) => skill.dirName);
1143
- generateCustomCommands(projectRoot, customSkills, project, lang, report, customTUIs, templateSkillNames);
1227
+ generateCustomCommands(projectRoot, customSkills, project, lang, report, customTUIs, templateSkillNames, enabledTUIs);
1144
1228
 
1145
1229
  for (const entry of ejected) {
1146
1230
  const dstFull = path.join(projectRoot, entry);
@@ -1148,6 +1232,9 @@ function syncTemplates(projectRoot, templateRootOverride) {
1148
1232
  report.ejected.skipped.push(entry);
1149
1233
  continue;
1150
1234
  }
1235
+ // Do not (re)create ejected files for disabled TUIs. Existing files are
1236
+ // never touched by sync (handled above); this guard only blocks creation.
1237
+ if (isPathOwnedByDisabledTUI(entry, enabledTUIs)) continue;
1151
1238
 
1152
1239
  const selected = platformSelect(langSelect(entryVariantRels(entry, allSet, platformType), lang, allSet, project), platformType, project);
1153
1240
  const target = norm(renderPathname(entry, project));
@@ -1168,6 +1255,10 @@ function syncTemplates(projectRoot, templateRootOverride) {
1168
1255
  report.managed.skippedPlatform.push(entry);
1169
1256
  continue;
1170
1257
  }
1258
+ if (isPathOwnedByDisabledTUI(entry, enabledTUIs)) {
1259
+ report.managed.skippedTUI.push(entry);
1260
+ continue;
1261
+ }
1171
1262
 
1172
1263
  if (entry.includes('*')) {
1173
1264
  const hits = allRels.filter(r => {
@@ -7,6 +7,7 @@ status: open # open | in-progress | review | blocked | complet
7
7
  created_at: YYYY-MM-DDTHH:mm:ss±HH:MM
8
8
  updated_at: YYYY-MM-DDTHH:mm:ss±HH:MM
9
9
  agent_infra_version: v0.0.0 # Current agent-infra version; refreshed by workflow commands
10
+ short_id: # Allocated by create-task / import-* in active window; kept as historical value after archival
10
11
  priority: # Optional Issue field: Urgent | High | Medium | Low
11
12
  effort: # Optional Issue field: High | Medium | Low
12
13
  start_date: # Optional Issue field for Feature: YYYY-MM-DD
@@ -7,6 +7,7 @@ status: open # open | in-progress | review | blocked | complet
7
7
  created_at: YYYY-MM-DDTHH:mm:ss±HH:MM
8
8
  updated_at: YYYY-MM-DDTHH:mm:ss±HH:MM
9
9
  agent_infra_version: v0.0.0 # 当前 agent-infra 版本;由工作流命令刷新
10
+ short_id: # 由 create-task / import-* 在 active 期内写入;归档后保留历史值
10
11
  priority: # 可选 Issue 字段:Urgent | High | Medium | Low
11
12
  effort: # 可选 Issue 字段:High | Medium | Low
12
13
  start_date: # Feature 可选 Issue 字段:YYYY-MM-DD