@fitlab-ai/agent-infra 0.6.2-alpha.1 → 0.6.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 (82) hide show
  1. package/README.md +13 -3
  2. package/README.zh-CN.md +10 -3
  3. package/bin/cli.ts +6 -1
  4. package/dist/bin/cli.js +6 -1
  5. package/dist/lib/sandbox/clipboard/bridge.js +216 -0
  6. package/dist/lib/sandbox/clipboard/darwin.js +73 -0
  7. package/dist/lib/sandbox/clipboard/index.js +9 -0
  8. package/dist/lib/sandbox/clipboard/keys.js +58 -0
  9. package/dist/lib/sandbox/clipboard/node-pty.js +13 -0
  10. package/dist/lib/sandbox/clipboard/paths.js +59 -0
  11. package/dist/lib/sandbox/commands/create.js +38 -21
  12. package/dist/lib/sandbox/commands/enter.js +8 -2
  13. package/dist/lib/sandbox/commands/ls.js +19 -4
  14. package/dist/lib/sandbox/commands/prune.js +176 -0
  15. package/dist/lib/sandbox/commands/rm.js +27 -33
  16. package/dist/lib/sandbox/config.js +1 -0
  17. package/dist/lib/sandbox/constants.js +6 -0
  18. package/dist/lib/sandbox/credentials.js +43 -24
  19. package/dist/lib/sandbox/index.js +7 -1
  20. package/dist/lib/sandbox/managed-fs.js +25 -0
  21. package/dist/lib/sandbox/tools.js +1 -1
  22. package/dist/lib/version.js +9 -2
  23. package/lib/sandbox/clipboard/bridge.ts +285 -0
  24. package/lib/sandbox/clipboard/darwin.ts +90 -0
  25. package/lib/sandbox/clipboard/index.ts +13 -0
  26. package/lib/sandbox/clipboard/keys.ts +78 -0
  27. package/lib/sandbox/clipboard/node-pty.d.ts +19 -0
  28. package/lib/sandbox/clipboard/node-pty.ts +34 -0
  29. package/lib/sandbox/clipboard/paths.ts +71 -0
  30. package/lib/sandbox/commands/create.ts +44 -21
  31. package/lib/sandbox/commands/enter.ts +8 -2
  32. package/lib/sandbox/commands/ls.ts +28 -4
  33. package/lib/sandbox/commands/prune.ts +211 -0
  34. package/lib/sandbox/commands/rm.ts +30 -32
  35. package/lib/sandbox/config.ts +2 -0
  36. package/lib/sandbox/constants.ts +9 -0
  37. package/lib/sandbox/credentials.ts +49 -26
  38. package/lib/sandbox/index.ts +7 -1
  39. package/lib/sandbox/managed-fs.ts +27 -0
  40. package/lib/sandbox/tools.ts +1 -1
  41. package/lib/version.ts +11 -4
  42. package/package.json +5 -1
  43. package/templates/.agents/README.en.md +19 -0
  44. package/templates/.agents/README.zh-CN.md +19 -0
  45. package/templates/.agents/rules/create-issue.github.en.md +3 -3
  46. package/templates/.agents/rules/create-issue.github.zh-CN.md +3 -3
  47. package/templates/.agents/skills/analyze-task/SKILL.en.md +29 -0
  48. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +29 -0
  49. package/templates/.agents/skills/analyze-task/config/verify.en.json +51 -0
  50. package/templates/.agents/skills/analyze-task/config/{verify.json → verify.zh-CN.json} +6 -2
  51. package/templates/.agents/skills/complete-task/SKILL.en.md +16 -0
  52. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +16 -0
  53. package/templates/.agents/skills/complete-task/config/{verify.json → verify.en.json} +10 -0
  54. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +48 -0
  55. package/templates/.agents/skills/create-pr/config/verify.json +1 -0
  56. package/templates/.agents/skills/create-task/SKILL.en.md +3 -3
  57. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +3 -3
  58. package/templates/.agents/skills/implement-task/SKILL.en.md +14 -0
  59. package/templates/.agents/skills/implement-task/SKILL.zh-CN.md +14 -0
  60. package/templates/.agents/skills/implement-task/config/verify.en.json +51 -0
  61. package/templates/.agents/skills/implement-task/config/{verify.json → verify.zh-CN.json} +7 -2
  62. package/templates/.agents/skills/implement-task/reference/report-template.en.md +15 -0
  63. package/templates/.agents/skills/implement-task/reference/report-template.zh-CN.md +15 -0
  64. package/templates/.agents/skills/plan-task/SKILL.en.md +24 -0
  65. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +24 -0
  66. package/templates/.agents/skills/plan-task/config/verify.en.json +52 -0
  67. package/templates/.agents/skills/plan-task/config/{verify.json → verify.zh-CN.json} +6 -2
  68. package/templates/.agents/skills/post-release/SKILL.en.md +1 -0
  69. package/templates/.agents/skills/post-release/SKILL.zh-CN.md +1 -0
  70. package/templates/.agents/skills/refine-task/SKILL.en.md +14 -0
  71. package/templates/.agents/skills/refine-task/SKILL.zh-CN.md +14 -0
  72. package/templates/.agents/skills/refine-task/config/verify.en.json +47 -0
  73. package/templates/.agents/skills/refine-task/config/{verify.json → verify.zh-CN.json} +7 -2
  74. package/templates/.agents/skills/refine-task/reference/report-template.en.md +15 -0
  75. package/templates/.agents/skills/refine-task/reference/report-template.zh-CN.md +15 -0
  76. package/templates/.agents/skills/review-task/SKILL.en.md +14 -0
  77. package/templates/.agents/skills/review-task/SKILL.zh-CN.md +14 -0
  78. package/templates/.agents/skills/review-task/config/verify.en.json +50 -0
  79. package/templates/.agents/skills/review-task/config/{verify.json → verify.zh-CN.json} +5 -2
  80. package/templates/.agents/skills/review-task/reference/report-template.en.md +15 -0
  81. package/templates/.agents/skills/review-task/reference/report-template.zh-CN.md +15 -0
  82. package/dist/package.json +0 -5
@@ -92,6 +92,11 @@ type ResolvedTool = {
92
92
  };
93
93
  };
94
94
 
95
+ export type ClaudeCredentialOutcome =
96
+ | { status: 'OK' }
97
+ | { status: 'SKIPPED' }
98
+ | { status: 'NOT_APPLICABLE' };
99
+
95
100
  type CredentialPayload = {
96
101
  claudeAiOauth?: CredentialPayload;
97
102
  scopes?: unknown;
@@ -584,17 +589,17 @@ export function formatRemaining(expiresAt: unknown): string {
584
589
  return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
585
590
  }
586
591
 
587
- export function assertClaudeCredentialsAvailable(
592
+ export function prepareClaudeCredentials(
588
593
  home: string,
589
594
  project: string,
590
595
  resolvedTools: ResolvedTool[],
591
596
  extractFn: (home: string) => string | null = extractClaudeCredentialsBlob,
592
597
  writeFn: (home: string, project: string, blob: string) => void = writeClaudeCredentialsFile,
593
598
  inspectFn: (home: string) => CredentialInspection = inspectClaudeKeychainStatus
594
- ): void {
599
+ ): ClaudeCredentialOutcome {
595
600
  const claudeCodeEntry = resolvedTools.find(({ tool }) => tool.id === 'claude-code');
596
601
  if (!claudeCodeEntry) {
597
- return;
602
+ return { status: 'NOT_APPLICABLE' };
598
603
  }
599
604
 
600
605
  let blob: string | null = null;
@@ -602,33 +607,51 @@ export function assertClaudeCredentialsAvailable(
602
607
  const hasCustomExtractFn = extractFn !== extractClaudeCredentialsBlob;
603
608
  if (hasCustomInspectFn || !hasCustomExtractFn) {
604
609
  const inspection = inspectFn(home);
605
- if (inspection.status === 'KEYCHAIN_LOCKED') {
606
- throw new Error([
607
- 'Claude Code credentials are stored in the macOS keychain, but the keychain is locked.',
608
- '',
609
- buildLockedGuidance()
610
- ].join('\n'));
610
+ switch (inspection.status) {
611
+ case 'OK':
612
+ blob = inspection.blob;
613
+ break;
614
+ case 'MISSING':
615
+ return { status: 'SKIPPED' };
616
+ case 'KEYCHAIN_LOCKED':
617
+ throw new Error([
618
+ 'Claude Code credentials are stored in the macOS keychain, but the keychain is locked.',
619
+ '',
620
+ buildLockedGuidance()
621
+ ].join('\n'));
622
+ case 'STALE_ACCESS':
623
+ throw new Error([
624
+ 'Claude Code credentials on host are invalid or expired.',
625
+ '',
626
+ 'The sandbox needs valid Claude Code OAuth credentials so the container can use Claude Code.',
627
+ '',
628
+ 'To fix:',
629
+ ' 1. On the host, run "claude" once and complete the OAuth login flow.',
630
+ ' 2. Verify with "claude /status" that you see your subscription.',
631
+ ' 3. Re-run "ai sandbox create".'
632
+ ].join('\n'));
633
+ case 'KEYCHAIN_ERROR':
634
+ throw new Error([
635
+ 'Claude Code credentials could not be read from the host keychain.',
636
+ '',
637
+ inspection.detail ? `Detail: ${inspection.detail}` : 'Detail: unknown keychain error',
638
+ '',
639
+ 'To fix:',
640
+ ' 1. Unlock or repair the host keychain, then re-run "ai sandbox create".',
641
+ ' 2. For SSH / CI, set AGENT_INFRA_CLAUDE_CREDENTIALS_FILE to an absolute path containing a valid credentials blob.'
642
+ ].join('\n'));
643
+ default: {
644
+ const _exhaustive: never = inspection;
645
+ throw new Error(`Unhandled Claude Code credential inspection status: ${(_exhaustive as { status: string }).status}`);
646
+ }
611
647
  }
612
- blob = inspection.status === 'OK' ? inspection.blob : null;
613
648
  } else {
614
649
  blob = extractFn(home);
615
- }
616
-
617
- if (!blob) {
618
- throw new Error([
619
- 'Claude Code credentials not found on host.',
620
- '',
621
- 'The sandbox needs your Claude Code OAuth credentials so the container can use Claude Code.',
622
- '',
623
- 'To fix:',
624
- ' 1. On the host, run "claude" once and complete the OAuth login flow.',
625
- ' 2. Verify with "claude /status" that you see your subscription.',
626
- ' 3. Re-run "ai sandbox create".',
627
- '',
628
- 'Alternatively, if you do not need Claude Code in this sandbox,',
629
- 'remove "claude-code" from the "sandbox.tools" array in .agents/.airc.json.'
630
- ].join('\n'));
650
+ if (!blob) {
651
+ return { status: 'SKIPPED' };
652
+ }
631
653
  }
632
654
 
633
655
  writeFn(home, project, blob);
656
+ return { status: 'OK' };
634
657
  }
@@ -6,6 +6,7 @@ Commands:
6
6
  refresh Sync host Claude Code credentials to all sandbox copies
7
7
  ls List sandboxes for the current project
8
8
  rm <branch> [--all] Remove a sandbox or all sandboxes
9
+ prune [--dry-run] Remove orphaned per-branch state dirs
9
10
  vm status|start|stop Manage the sandbox VM (macOS) or check the backend (Windows)
10
11
  rebuild [--quiet] Rebuild the sandbox image
11
12
 
@@ -33,7 +34,7 @@ export async function runSandbox(args: string[]): Promise<void> {
33
34
  }
34
35
  case 'exec': {
35
36
  const { enter } = await import('./commands/enter.ts');
36
- const exitCode = enter(rest);
37
+ const exitCode = await enter(rest);
37
38
  if (typeof exitCode === 'number' && exitCode !== 0) {
38
39
  process.exitCode = exitCode;
39
40
  }
@@ -57,6 +58,11 @@ export async function runSandbox(args: string[]): Promise<void> {
57
58
  await rm(rest);
58
59
  break;
59
60
  }
61
+ case 'prune': {
62
+ const { prune } = await import('./commands/prune.ts');
63
+ await prune(rest);
64
+ break;
65
+ }
60
66
  case 'vm': {
61
67
  const { vm } = await import('./commands/vm.ts');
62
68
  await vm(rest);
@@ -0,0 +1,27 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { run } from './shell.ts';
4
+
5
+ export function assertManagedPath(root: string, target: string): void {
6
+ const resolvedRoot = path.resolve(root);
7
+ const resolvedTarget = path.resolve(target);
8
+ const relative = path.relative(resolvedRoot, resolvedTarget);
9
+ if (relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))) {
10
+ return;
11
+ }
12
+
13
+ throw new Error(`Refusing to remove path outside managed sandbox root: ${target}`);
14
+ }
15
+
16
+ export function removeManagedDir(root: string, dir: string): void {
17
+ assertManagedPath(root, dir);
18
+ fs.rmSync(dir, { recursive: true, force: true });
19
+ }
20
+
21
+ export function removeWorktreeDir(repoRoot: string, worktreeBase: string, dir: string): void {
22
+ try {
23
+ run('git', ['-C', repoRoot, 'worktree', 'remove', dir, '--force']);
24
+ } catch {
25
+ removeManagedDir(worktreeBase, dir);
26
+ }
27
+ }
@@ -28,7 +28,7 @@ function createBuiltinTools(home: string, project: string): Record<string, Sandb
28
28
  'claude-code': {
29
29
  id: 'claude-code',
30
30
  name: 'Claude Code',
31
- npmPackage: '@anthropic-ai/claude-code',
31
+ npmPackage: '@anthropic-ai/claude-code@stable',
32
32
  sandboxBase: hostJoin(home, '.agent-infra', 'sandboxes', 'claude-code'),
33
33
  containerMount: '/home/devuser/.claude',
34
34
  versionCmd: 'claude --version',
package/lib/version.ts CHANGED
@@ -1,8 +1,15 @@
1
- import { readFileSync } from 'node:fs';
1
+ import { existsSync, readFileSync } from 'node:fs';
2
2
 
3
- const { version } = JSON.parse(
4
- readFileSync(new URL('../package.json', import.meta.url), 'utf8')
5
- );
3
+ const packageJsonUrl = [
4
+ new URL('../package.json', import.meta.url),
5
+ new URL('../../package.json', import.meta.url),
6
+ ].find((url) => existsSync(url));
7
+
8
+ if (!packageJsonUrl) {
9
+ throw new Error('Unable to locate package.json for agent-infra version');
10
+ }
11
+
12
+ const { version } = JSON.parse(readFileSync(packageJsonUrl, 'utf8'));
6
13
  const VERSION = `v${version}`;
7
14
 
8
15
  export { VERSION };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fitlab-ai/agent-infra",
3
- "version": "0.6.2-alpha.1",
3
+ "version": "0.6.3",
4
4
  "description": "Bootstrap tool for AI multi-tool collaboration infrastructure — works with Claude Code, Codex, Gemini CLI, and OpenCode",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -57,6 +57,7 @@
57
57
  "test:smoke": "npm run build && node --experimental-strip-types --no-warnings --test tests/templates/*.test.ts tests/core/airc.test.ts tests/core/release.test.ts tests/core/metadata-sync-workflow.test.ts tests/core/pr-label-workflow.test.ts tests/core/status-label-workflow.test.ts tests/core/test-tier-coverage.test.ts tests/cli/lib.test.ts tests/cli/sync-templates.test.ts tests/scripts/sync-templates-platform-gating.test.ts",
58
58
  "test:core": "npm run build && node --experimental-strip-types --no-warnings --test tests/templates/*.test.ts tests/core/airc.test.ts tests/core/release.test.ts tests/core/metadata-sync-workflow.test.ts tests/core/pr-label-workflow.test.ts tests/core/status-label-workflow.test.ts tests/core/test-tier-coverage.test.ts tests/cli/lib.test.ts tests/cli/sync-templates.test.ts tests/scripts/sync-templates-platform-gating.test.ts tests/cli/cli.test.ts tests/cli/merge.test.ts tests/cli/sandbox.test.ts tests/core/custom-skills.test.ts tests/core/custom-tuis.test.ts tests/core/demo-regen.test.ts tests/scripts/find-existing-task.test.ts tests/scripts/platform-adapter-defaults.test.ts",
59
59
  "test": "npm run build && node --experimental-strip-types --no-warnings --test tests/cli/*.test.ts tests/templates/*.test.ts tests/core/*.test.ts tests/scripts/*.test.ts",
60
+ "test:coverage": "npm run build && node --experimental-strip-types --no-warnings --test --experimental-test-coverage --test-coverage-exclude='tests/**' --test-reporter=spec --test-reporter-destination=stdout --test-reporter=lcov --test-reporter-destination=coverage.lcov tests/cli/*.test.ts tests/templates/*.test.ts tests/core/*.test.ts tests/scripts/*.test.ts",
60
61
  "prepublishOnly": "npm run build && node --experimental-strip-types --no-warnings --test tests/cli/*.test.ts tests/templates/*.test.ts tests/core/*.test.ts tests/scripts/*.test.ts"
61
62
  },
62
63
  "devDependencies": {
@@ -64,5 +65,8 @@
64
65
  "@types/node": "^25.9.1",
65
66
  "@types/semver": "^7.7.1",
66
67
  "typescript": "~6.0"
68
+ },
69
+ "optionalDependencies": {
70
+ "@lydell/node-pty": "^1.2.0-beta.12"
67
71
  }
68
72
  }
@@ -193,6 +193,23 @@ Each source should mirror the `.agents/skills/` layout and include `SKILL.md` at
193
193
  - Built-in skills are not overridable by custom sources; if a source skill name conflicts with a built-in skill, the source copy is skipped
194
194
  - Use `files.ejected` if the project must take ownership of a built-in skill or command
195
195
 
196
+ ## File Ownership and Sync Strategy
197
+
198
+ The `files` field in `.agents/.airc.json` groups project files into three categories:
199
+
200
+ | Category | When the template has the file | When the template does not have the file | Cleanup behavior |
201
+ |----------|--------------------------------|------------------------------------------|------------------|
202
+ | `managed` | Write from the template and overwrite | Treat as removed from the template | Delete the local project copy |
203
+ | `merged` | Merge semantically by AI or humans | Do not write from the template | Keep the local project copy |
204
+ | `ejected` | May be created from the template first; skip overwrite once it exists | Do not write from the template | Keep the local project copy |
205
+
206
+ `ejected` has two common uses:
207
+
208
+ 1. **Taking over a built-in file**: the project needs full control over a rule, command, or config file that originally came from the template.
209
+ 2. **Declaring a project-only file**: the project owns a file under a managed directory wildcard, but the template does not contain that file; list it in `files.ejected` so sync does not treat it as a removed template file.
210
+
211
+ `ejected` entries support literal paths or globs, using the same matching rules as `merged`.
212
+
196
213
  ## Custom TUI Configuration
197
214
 
198
215
  Use the top-level `.agents/.airc.json` `customTUIs` array when your team uses an AI TUI that is not one of the built-in command targets. This config lets agent-infra show the correct next-step commands and generate command files for project custom skills by learning from an existing command in the custom TUI directory.
@@ -257,6 +274,7 @@ When writing or updating `.agents/skills/*/SKILL.md` files and their templates,
257
274
 
258
275
  - Keep SKILL.md as concise as possible; move detailed rules, long templates, and large script blocks into a sibling `reference/` or `scripts/` directory.
259
276
  - Store declarative configuration in a sibling `config/` directory, for example `config/verify.json`.
277
+ When `required_sections` or `required_patterns` contain language-specific text, provide `config/verify.en.json` and `config/verify.zh-CN.json`; sync strips the selected language variant back to `config/verify.json`.
260
278
  - Use explicit navigation in the skeleton, such as: `Read reference/xxx.md before executing this step.`
261
279
  - Keep scripts in `scripts/` and execute them instead of inlining long bash blocks.
262
280
 
@@ -269,6 +287,7 @@ node .agents/scripts/validate-artifact.js gate <skill-name> <task-dir> [artifact
269
287
  ```
270
288
 
271
289
  - Each skill declares its own checks in `config/verify.json`; keep the file focused on what that skill must validate
290
+ - For language-specific artifact headings or anchors, keep only `required_sections` and language-specific `required_patterns` different between `config/verify.en.json` and `config/verify.zh-CN.json`
272
291
  - If a skill also prints next-step guidance, run the gate first and only show those instructions after the gate passes
273
292
  - For user-facing final validation, prefer `--format text` so the reply contains a readable summary instead of raw JSON
274
293
  - Shared validation logic belongs in `.agents/scripts/validate-artifact.js`; do not move detailed rules back into SKILL.md
@@ -193,6 +193,23 @@ args: "<task-id>" # 可选
193
193
  - 自定义 source 不能覆盖内置 skill;如果与内置 skill 同名,会跳过该 source skill
194
194
  - 如果项目必须接管某个内置 skill 或命令,请使用 `files.ejected`
195
195
 
196
+ ## 文件归属与同步策略
197
+
198
+ `.agents/.airc.json` 的 `files` 字段把项目文件分为三类:
199
+
200
+ | 类别 | 模板中存在时 | 模板中不存在时 | 清理行为 |
201
+ |------|--------------|----------------|----------|
202
+ | `managed` | 从模板写入并覆盖 | 视为模板已下线 | 删除项目本地副本 |
203
+ | `merged` | 由 AI 或人工语义合并 | 不从模板写入 | 保留项目本地副本 |
204
+ | `ejected` | 首次可从模板创建,已存在时跳过覆盖 | 不从模板写入 | 保留项目本地副本 |
205
+
206
+ `ejected` 有两种常见用法:
207
+
208
+ 1. **接管内置文件**:项目需要完全控制原本来自模板的规则、命令或配置文件,避免后续同步覆盖本地内容。
209
+ 2. **声明项目独占文件**:项目自己的文件落在 managed 目录通配下,但模板中没有同名文件;把它列入 `files.ejected`,避免同步时被当作模板已下线文件删除。
210
+
211
+ `ejected` 条目支持字面路径或 glob,匹配规则与 `merged` 相同。
212
+
196
213
  ## 自定义 TUI 配置
197
214
 
198
215
  当团队使用的 AI TUI 不属于内置命令目标时,可以在 `.agents/.airc.json` 顶层配置 `customTUIs` 数组。该配置用于让 agent-infra 输出正确的下一步命令,并通过学习自定义 TUI 目录中的既有命令文件,为项目自定义 skill 生成同格式命令。
@@ -257,6 +274,7 @@ args: "<task-id>" # 可选
257
274
 
258
275
  - SKILL.md 正文尽可能精简,把详细规则、长模板和大段脚本拆分到同级 `reference/` 或 `scripts/` 目录。
259
276
  - 声明式配置统一放在同级 `config/` 目录,例如 `config/verify.json`。
277
+ 当 `required_sections` 或 `required_patterns` 包含语言相关文案时,提供 `config/verify.en.json` 和 `config/verify.zh-CN.json`;sync 会把选中的语言变体剥离为 `config/verify.json`。
260
278
  - 骨架中使用明确导航,例如:`执行此步骤前,先读取 reference/xxx.md。`
261
279
  - 长脚本继续放在 `scripts/` 目录,优先执行脚本而不是内联大段 bash。
262
280
 
@@ -269,6 +287,7 @@ node .agents/scripts/validate-artifact.js gate <skill-name> <task-dir> [artifact
269
287
  ```
270
288
 
271
289
  - 每个 skill 在自己的 `config/verify.json` 中声明需要检查的事项
290
+ - 对语言相关的产物标题或锚点,`config/verify.en.json` 和 `config/verify.zh-CN.json` 之间只应让 `required_sections` 与语言相关的 `required_patterns` 不同
272
291
  - 如果 skill 还会展示“下一步”提示,必须先通过完成校验,再输出这些指引
273
292
  - 面向用户展示最终校验结果时,优先使用 `--format text` 输出可读摘要,而不是原始 JSON
274
293
  - 共享逻辑集中在 `.agents/scripts/validate-artifact.js`,不要把详细校验规则重新塞回 SKILL.md
@@ -149,13 +149,13 @@ gh api "repos/$upstream_repo/issues/{issue-number}" -X PATCH \
149
149
 
150
150
  Failure is non-blocking.
151
151
 
152
- ### 6.5 Set Issue Fields (Optional)
152
+ ### 7. Set Issue Fields (Optional)
153
153
 
154
154
  If `has_push=true`, read `.agents/rules/issue-fields.md` and follow Flow A to write any applicable non-empty `priority`, `effort`, `start_date`, and `target_date` values from `task.md`.
155
155
 
156
156
  Field write failures are non-blocking.
157
157
 
158
- ### 7. Write Back task.md
158
+ ### 8. Write Back task.md
159
159
 
160
160
  Update task.md:
161
161
 
@@ -164,7 +164,7 @@ Update task.md:
164
164
 
165
165
  > Do NOT append an Activity Log entry here. The Issue creation event is already captured by the GitHub Issue itself and by the frontmatter `issue_number` field; the Activity Log only records the single `create-task` skill execution anchor (`Task Created`), written by the caller SKILL step 3.
166
166
 
167
- ### 8. Return the Result
167
+ ### 9. Return the Result
168
168
 
169
169
  Hand the following back to the caller `create-task`:
170
170
 
@@ -149,13 +149,13 @@ gh api "repos/$upstream_repo/issues/{issue-number}" -X PATCH \
149
149
 
150
150
  设置失败不阻断流程。
151
151
 
152
- ### 6.5 设置 Issue 字段(可选)
152
+ ### 7. 设置 Issue 字段(可选)
153
153
 
154
154
  如果 `has_push=true`,读取 `.agents/rules/issue-fields.md`,按流程 A 写入 `task.md` 中适用且非空的 `priority`、`effort`、`start_date` 和 `target_date`。
155
155
 
156
156
  字段写入失败不阻断流程。
157
157
 
158
- ### 7. 回写 task.md
158
+ ### 8. 回写 task.md
159
159
 
160
160
  更新 task.md:
161
161
 
@@ -164,7 +164,7 @@ gh api "repos/$upstream_repo/issues/{issue-number}" -X PATCH \
164
164
 
165
165
  > 不要在此追加 Activity Log 条目。Issue 创建事件已由 GitHub Issue 自身和 frontmatter `issue_number` 承载;Activity Log 仅记录 `create-task` skill 一次执行的整体锚点(`Task Created`),由调用方 SKILL 步骤 3 写入。
166
166
 
167
- ### 8. 返回结果
167
+ ### 9. 返回结果
168
168
 
169
169
  把以下信息回传给调用方 `create-task`:
170
170
 
@@ -13,6 +13,20 @@ description: "Analyze a task and produce a requirements document"
13
13
 
14
14
  Version stamp rule: when creating or updating `task.md` frontmatter, read `.agents/rules/version-stamp.md` first and write or refresh `agent_infra_version`.
15
15
 
16
+ ## Step 0: State Check (pre-execution hard gate)
17
+
18
+ After loading workflow / skill / rules instructions, and before any task-state judgment or user-visible conclusion, run the state check first. Reading instruction files does not count as an external-state action or conclusion.
19
+
20
+ Run these commands and paste the raw output into both the user-facing reply and this round's `## State Check` section:
21
+
22
+ ```bash
23
+ git status -s
24
+ ls -la .agents/workspace/active/{task-id}/
25
+ tail .agents/workspace/active/{task-id}/task.md
26
+ ```
27
+
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
+
16
30
  ## Steps
17
31
 
18
32
  ### 1. Verify Prerequisites
@@ -49,6 +63,8 @@ If `task.md` contains these source fields, also read the corresponding source in
49
63
 
50
64
  ### 4. Perform Requirements Analysis
51
65
 
66
+ Before analysis begins: if `start_date` in the frontmatter is empty, write today's date immediately (command: `date +%F`, format `YYYY-MM-DD`); keep any existing value. Before writing, read `.agents/rules/version-stamp.md` and refresh `updated_at` / `agent_infra_version` at the same time.
67
+
52
68
  Follow the `analysis` step in `.agents/workflows/feature-development.yaml`:
53
69
 
54
70
  **Required tasks** (analysis only, no business code changes):
@@ -70,6 +86,10 @@ Create `.agents/workspace/active/{task-id}/{analysis-artifact}`.
70
86
  - **Analysis round**: Round {analysis-round}
71
87
  - **Artifact file**: `{analysis-artifact}`
72
88
 
89
+ ## State Check
90
+
91
+ > Paste the raw Step 0 state-check command output; each command starts with `$ `.
92
+
73
93
  ## Requirement Source
74
94
 
75
95
  **Source type**: {User description / Issue / Code Scanning / Dependabot / Other}
@@ -116,6 +136,14 @@ Update `.agents/workspace/active/{task-id}/task.md`:
116
136
  - Record the analysis artifact for this round: `{analysis-artifact}` (Round `{analysis-round}`)
117
137
  - If the task template contains a `## Analysis` section, update it to link to `{analysis-artifact}`
118
138
  - Mark requirement-analysis as complete in workflow progress and include the actual round when the task template supports it
139
+ - Before appending the workflow Activity Log entry, re-estimate `priority` based on the analysis findings (business impact, risks, dependencies, blockers). If the re-estimated value differs from the current value in `task.md`:
140
+ - Overwrite the `priority` field in frontmatter with the new value
141
+ - Prepend an Activity Log entry recording the transition (placed before the `Requirement Analysis (Round N)` entry):
142
+ ```
143
+ - {YYYY-MM-DD HH:mm:ss±HH:MM} — **Analysis Re-estimate** by {agent} — priority {old} → {new} (rationale: {short basis grounded in this analysis})
144
+ ```
145
+ Both entries may share the same timestamp; ordering is conveyed by list position only.
146
+ If the re-estimated value matches the current value, skip the Re-estimate entry. The Flow A sync that follows reads the possibly updated frontmatter and propagates the new value to the Issue automatically.
119
147
  - **Append** to `## Activity Log` (do NOT overwrite previous entries):
120
148
  ```
121
149
  - {YYYY-MM-DD HH:mm:ss±HH:MM} — **Requirement Analysis (Round {N})** by {agent} — Analysis completed → {analysis-artifact}
@@ -126,6 +154,7 @@ If task.md contains a valid `issue_number`, perform these sync actions (skip and
126
154
  - Set `status: pending-design-work` by following issue-sync.md
127
155
  - Create or update the task comment marker defined in `.agents/rules/issue-sync.md` (follow the task.md comment sync rule in issue-sync.md)
128
156
  - Publish the `{analysis-artifact}` comment
157
+ - Read `.agents/rules/issue-fields.md` and follow Flow A to sync every non-empty Issue field (`priority`/`effort`/`start_date`/`target_date`) from `task.md` to the Issue (idempotent; skip without blocking when `has_push=false` or the fetch/write fails)
129
158
 
130
159
  ### 7. Verification Gate
131
160
 
@@ -13,6 +13,20 @@ description: "分析任务并输出需求分析文档"
13
13
 
14
14
  版本戳规则:创建或更新 `task.md` frontmatter 时,先读取 `.agents/rules/version-stamp.md`,并写入或刷新 `agent_infra_version`。
15
15
 
16
+ ## 第 0 步:状态核对(执行前硬约束)
17
+
18
+ 在加载 workflow / skill / rules 指令之后、做任何任务状态判断或用户可见结论之前,必须先执行状态核对。指令类文件读取不算对外动作或结论。
19
+
20
+ 运行以下命令,并把原文粘贴到回复正文和本轮产物的 `## 状态核对` 段:
21
+
22
+ ```bash
23
+ git status -s
24
+ ls -la .agents/workspace/active/{task-id}/
25
+ tail .agents/workspace/active/{task-id}/task.md
26
+ ```
27
+
28
+ 状态核对完成前,禁止任何关于外部状态的断言(例如“代码没变”“测试已通过”“没有其他引用”),包括思考阶段。本门禁只提供结构下限;逐条证据配对和真实性仍需按报告模板与审查要求核对。
29
+
16
30
  ## 执行步骤
17
31
 
18
32
  ### 1. 验证前置条件
@@ -49,6 +63,8 @@ description: "分析任务并输出需求分析文档"
49
63
 
50
64
  ### 4. 执行需求分析
51
65
 
66
+ 开始分析前:若 frontmatter 的 `start_date` 为空,立即写入当日日期(命令 `date +%F`,格式 `YYYY-MM-DD`);已有值则保留。写入前先读取 `.agents/rules/version-stamp.md`,并同步刷新 `updated_at` / `agent_infra_version`。
67
+
52
68
  遵循 `.agents/workflows/feature-development.yaml` 中的 `analysis` 步骤:
53
69
 
54
70
  **必要任务**(仅分析,不编写业务代码):
@@ -70,6 +86,10 @@ description: "分析任务并输出需求分析文档"
70
86
  - **分析轮次**:Round {analysis-round}
71
87
  - **产物文件**:`{analysis-artifact}`
72
88
 
89
+ ## 状态核对
90
+
91
+ > 粘贴第 0 步状态核对命令原文;每条命令以 `$ ` 开头。
92
+
73
93
  ## 需求来源
74
94
 
75
95
  **来源类型**:{用户描述 / Issue / Code Scanning / Dependabot / 其他}
@@ -116,6 +136,14 @@ date "+%Y-%m-%d %H:%M:%S%:z"
116
136
  - 记录本轮分析产物:`{analysis-artifact}`(Round `{analysis-round}`)
117
137
  - 如任务模板包含 `## 分析` 段落,更新为指向 `{analysis-artifact}` 的链接
118
138
  - 在工作流进度中标记 requirement-analysis 为已完成,并注明实际轮次(如果任务模板支持)
139
+ - 在追加工作流 Activity Log 条目之前,基于分析结果(业务影响、风险、依赖、阻塞条件)重估 `priority`。若重估值与 `task.md` 当前值不一致:
140
+ - 用新值覆盖 frontmatter 的 `priority` 字段
141
+ - 在 `Requirement Analysis (Round N)` 条目之前追加一条转移记录:
142
+ ```
143
+ - {YYYY-MM-DD HH:mm:ss±HH:MM} — **Analysis Re-estimate** by {agent} — priority {old} → {new} (rationale: {基于本轮分析的简短依据})
144
+ ```
145
+ 两条条目可共用同一时间戳,顺序仅通过列表位置表达。
146
+ 若重估值与当前值一致,跳过 Re-estimate 条目。后续 Flow A 同步会读取可能更新过的 frontmatter,并自动把新值同步到 Issue。
119
147
  - **追加**到 `## Activity Log`(不要覆盖之前的记录):
120
148
  ```
121
149
  - {YYYY-MM-DD HH:mm:ss±HH:MM} — **Requirement Analysis (Round {N})** by {agent} — Analysis completed → {analysis-artifact}
@@ -126,6 +154,7 @@ date "+%Y-%m-%d %H:%M:%S%:z"
126
154
  - 按 issue-sync.md 设置 `status: pending-design-work`
127
155
  - 创建或更新 `.agents/rules/issue-sync.md` 中定义的 task 评论标记(按 issue-sync.md 的 task.md 评论同步规则)
128
156
  - 发布 `{analysis-artifact}` 评论
157
+ - 读取 `.agents/rules/issue-fields.md`,按流程 A 把 `task.md` 中所有非空的 Issue 字段(`priority`/`effort`/`start_date`/`target_date`)同步到 Issue(幂等;`has_push=false` 或取数/写入失败时跳过,不阻断)
129
158
 
130
159
  ### 7. 完成校验
131
160
 
@@ -0,0 +1,51 @@
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
+ "agent_infra_version",
13
+ "current_step",
14
+ "assigned_to"
15
+ ],
16
+ "expected_step": "requirement-analysis"
17
+ },
18
+ "artifact": {
19
+ "file_pattern": "analysis.md|analysis-r{N}.md",
20
+ "required_sections": [
21
+ "Requirement Source",
22
+ "Requirement Understanding",
23
+ "Related Files",
24
+ "Impact Assessment",
25
+ "Technical Risks",
26
+ "Effort and Complexity Assessment",
27
+ "State Check"
28
+ ],
29
+ "freshness_minutes": 30,
30
+ "required_patterns": [
31
+ "^\\$ "
32
+ ]
33
+ },
34
+ "activity-log": {
35
+ "expected_action_pattern": "Requirement Analysis \\(Round \\d+\\)",
36
+ "freshness_minutes": 30
37
+ },
38
+ "platform-sync": {
39
+ "when": "issue_number_exists",
40
+ "expected_status_label": "status: pending-design-work",
41
+ "expected_comment_marker": "<!-- sync-issue:{task-id}:{artifact-stem} -->",
42
+ "verify_comment_content": true,
43
+ "verify_task_comment_content": true,
44
+ "verify_issue_type": true,
45
+ "verify_issue_fields": false,
46
+ "verify_milestone": true,
47
+ "expected_status_label_key": "pendingDesignWork",
48
+ "expected_comment_marker_key": "artifact"
49
+ }
50
+ }
51
+ }
@@ -23,9 +23,13 @@
23
23
  "相关文件",
24
24
  "影响评估",
25
25
  "技术风险",
26
- "工作量和复杂度评估"
26
+ "工作量和复杂度评估",
27
+ "状态核对"
27
28
  ],
28
- "freshness_minutes": 30
29
+ "freshness_minutes": 30,
30
+ "required_patterns": [
31
+ "^\\$ "
32
+ ]
29
33
  },
30
34
  "activity-log": {
31
35
  "expected_action_pattern": "Requirement Analysis \\(Round \\d+\\)",
@@ -12,6 +12,20 @@ description: "Mark a task as completed and archive it"
12
12
 
13
13
  Version stamp rule: when creating or updating `task.md` frontmatter, read `.agents/rules/version-stamp.md` first and write or refresh `agent_infra_version`.
14
14
 
15
+ ## Step 0: State Check (pre-execution hard gate)
16
+
17
+ After loading workflow / skill / rules instructions, and before any task-state judgment or user-visible conclusion, run the state check first. Reading instruction files does not count as an external-state action or conclusion.
18
+
19
+ Run these commands and paste the raw output into both the user-facing reply and this round's `## State Check` section:
20
+
21
+ ```bash
22
+ git status -s
23
+ ls -la .agents/workspace/active/{task-id}/
24
+ tail .agents/workspace/active/{task-id}/task.md
25
+ ```
26
+
27
+ 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.
28
+
15
29
  ## Steps
16
30
 
17
31
  ### 1. Verify Task Exists
@@ -64,6 +78,7 @@ Update `.agents/workspace/active/{task-id}/task.md`:
64
78
  - `completed_at`: {current timestamp}
65
79
  - `updated_at`: {current timestamp}
66
80
  - `agent_infra_version`: value from `.agents/rules/version-stamp.md`
81
+ - Add or update the `## State Check` section with the raw Step 0 audit command output, including `$ ` prompt lines, before `## Activity Log`
67
82
  - Mark all workflow steps as complete
68
83
  - Verify and check off all items in `## Completion Checklist` (change `- [ ]` to `- [x]`)
69
84
  - **Append** to `## Activity Log` (do NOT overwrite previous entries):
@@ -98,6 +113,7 @@ If a valid `issue_number` exists:
98
113
  - Backfill checked `## Requirements` items to the Issue body by following the requirements-checkbox sync steps in issue-sync.md
99
114
  - Do not set any `status:` label — status labels are automatically cleared when the Issue is closed
100
115
  - Finally create or update the summary comment marked with the summary marker defined in `.agents/rules/issue-sync.md`
116
+ - Read `.agents/rules/issue-fields.md` and follow Flow A to sync every non-empty Issue field (`priority`/`effort`/`start_date`/`target_date`) from `task.md` to the Issue (idempotent; skip without blocking when `has_push=false` or the fetch/write fails)
101
117
 
102
118
  ### 7. Verification Gate
103
119
 
@@ -12,6 +12,20 @@ description: "标记任务完成并归档"
12
12
 
13
13
  版本戳规则:创建或更新 `task.md` frontmatter 时,先读取 `.agents/rules/version-stamp.md`,并写入或刷新 `agent_infra_version`。
14
14
 
15
+ ## 第 0 步:状态核对(执行前硬约束)
16
+
17
+ 在加载 workflow / skill / rules 指令之后、做任何任务状态判断或用户可见结论之前,必须先执行状态核对。指令类文件读取不算对外动作或结论。
18
+
19
+ 运行以下命令,并把原文粘贴到回复正文和本轮产物的 `## 状态核对` 段:
20
+
21
+ ```bash
22
+ git status -s
23
+ ls -la .agents/workspace/active/{task-id}/
24
+ tail .agents/workspace/active/{task-id}/task.md
25
+ ```
26
+
27
+ 状态核对完成前,禁止任何关于外部状态的断言(例如“代码没变”“测试已通过”“没有其他引用”),包括思考阶段。本门禁只提供结构下限;逐条证据配对和真实性仍需按报告模板与审查要求核对。
28
+
15
29
  ## 执行步骤
16
30
 
17
31
  ### 1. 验证任务存在
@@ -64,6 +78,7 @@ date "+%Y-%m-%d %H:%M:%S%:z"
64
78
  - `completed_at`:{当前时间戳}
65
79
  - `updated_at`:{当前时间戳}
66
80
  - `agent_infra_version`:按 `.agents/rules/version-stamp.md` 取值
81
+ - 新增或更新 `## 状态核对` 段,粘贴第 0 步审计命令原文(含 `$ ` 前缀行),放在 `## 活动日志` 之前
67
82
  - 标记所有工作流步骤为已完成
68
83
  - 逐项验证并勾选 `## 完成检查清单` 中的所有条目(将 `- [ ]` 改为 `- [x]`)
69
84
  - **追加**到 `## Activity Log`(不要覆盖之前的记录):
@@ -98,6 +113,7 @@ ls .agents/workspace/completed/{task-id}/task.md
98
113
  - 按 issue-sync.md 的需求复选框同步步骤,兜底同步 `## 需求` 中已勾选的条目到 Issue body
99
114
  - 不要设置 `status:` label — Issue 关闭后 status label 会被自动清除
100
115
  - 最后创建或更新 `.agents/rules/issue-sync.md` 中定义的 summary 评论标记对应的 summary 评论
116
+ - 读取 `.agents/rules/issue-fields.md`,按流程 A 把 `task.md` 中所有非空的 Issue 字段(`priority`/`effort`/`start_date`/`target_date`)同步到 Issue(幂等;`has_push=false` 或取数/写入失败时跳过,不阻断)
101
117
 
102
118
  ### 7. 完成校验
103
119
 
@@ -33,6 +33,16 @@
33
33
  "verify_issue_fields": false,
34
34
  "verify_milestone": true,
35
35
  "expected_comment_marker_key": "summary"
36
+ },
37
+ "artifact": {
38
+ "file_pattern": "task.md",
39
+ "required_sections": [
40
+ "State Check"
41
+ ],
42
+ "required_patterns": [
43
+ "^\\$ "
44
+ ],
45
+ "freshness_minutes": 30
36
46
  }
37
47
  }
38
48
  }