@fitlab-ai/agent-infra 0.8.5 → 0.9.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.
- package/bin/cli.ts +2 -2
- package/dist/bin/cli.js +2 -2
- package/dist/bin/internal-cli.js +98 -0
- package/dist/lib/decide.js +81 -90
- package/dist/lib/defaults.json +1 -0
- package/dist/lib/git/review-snapshot.js +79 -0
- package/dist/lib/git/workflow.js +101 -0
- package/dist/lib/internal/git-workflow.js +42 -0
- package/dist/lib/internal/platform-checks.js +119 -0
- package/dist/lib/internal/platform-comment.js +129 -0
- package/dist/lib/internal/platform-context.js +46 -0
- package/dist/lib/internal/platform-issue.js +142 -0
- package/dist/lib/internal/platform-pr.js +146 -0
- package/dist/lib/internal/release-workflow.js +217 -0
- package/dist/lib/internal/task-artifact.js +67 -0
- package/dist/lib/internal/task-context.js +43 -0
- package/dist/lib/internal/task-event.js +70 -0
- package/dist/lib/internal/task-ledger.js +114 -0
- package/dist/lib/internal/task-lifecycle.js +58 -0
- package/dist/lib/internal/task-short-id.js +83 -0
- package/dist/lib/internal/task-snapshot.js +47 -0
- package/dist/lib/internal/task-verify.js +50 -0
- package/dist/lib/internal/task-warning.js +74 -0
- package/dist/lib/platform/adapters.js +14 -0
- package/dist/lib/platform/context.js +146 -0
- package/dist/lib/platform/github-client.js +124 -0
- package/dist/lib/platform/issue-comments.js +409 -0
- package/dist/lib/platform/issue-metadata.js +183 -0
- package/dist/lib/platform/issues.js +617 -0
- package/dist/lib/platform/metadata-labels.js +28 -0
- package/dist/lib/platform/pr-checks.js +216 -0
- package/dist/lib/platform/pr-summary.js +88 -0
- package/dist/lib/platform/pull-request-metadata.js +38 -0
- package/dist/lib/platform/pull-requests.js +338 -0
- package/dist/lib/platform/releases.js +82 -0
- package/dist/lib/platform/types.js +22 -0
- package/dist/lib/platform/verification-required.js +78 -0
- package/dist/lib/platform/verification-sync.js +1014 -0
- package/dist/lib/platform/verification.js +6 -0
- package/dist/lib/release/channels.js +31 -0
- package/dist/lib/release/workflow.js +32 -0
- package/dist/lib/render.js +3 -2
- package/dist/lib/run/index.js +24 -7
- package/dist/lib/sandbox/capture.js +25 -3
- package/dist/lib/sandbox/commands/create.js +36 -22
- package/dist/lib/sandbox/commands/enter.js +34 -11
- package/dist/lib/sandbox/commands/list-running.js +10 -8
- package/dist/lib/sandbox/commands/show.js +2 -2
- package/dist/lib/sandbox/commands/start.js +53 -15
- package/dist/lib/sandbox/index.js +6 -6
- package/dist/lib/sandbox/mounts.js +36 -0
- package/dist/lib/sandbox/recovery.js +562 -0
- package/dist/lib/sandbox/task-resolver.js +5 -1
- package/dist/lib/sandbox/tools.js +19 -0
- package/dist/lib/server/protocol.js +5 -5
- package/dist/lib/task/activity-log.js +61 -0
- package/dist/lib/task/artifact-lifecycle.js +427 -0
- package/dist/lib/task/command-options.js +30 -0
- package/dist/lib/task/commands/cat.js +36 -6
- package/dist/lib/task/commands/decisions.js +80 -46
- package/dist/lib/task/commands/files.js +21 -7
- package/dist/lib/task/commands/grep.js +55 -7
- package/dist/lib/task/commands/issue-body.js +23 -14
- package/dist/lib/task/commands/log.js +27 -70
- package/dist/lib/task/commands/show.js +20 -7
- package/dist/lib/task/commands/status.js +18 -8
- package/dist/lib/task/decision-intents.js +154 -0
- package/dist/lib/task/decision-items.js +53 -0
- package/dist/lib/task/events.js +318 -0
- package/dist/lib/task/frontmatter.js +159 -1
- package/dist/lib/task/implementation-inputs.js +117 -0
- package/dist/lib/task/index.js +12 -9
- package/dist/lib/task/issue-form.js +19 -6
- package/dist/lib/task/ledger-intents.js +185 -0
- package/dist/lib/task/ledger.js +65 -35
- package/dist/lib/task/lifecycle.js +484 -0
- package/dist/lib/task/resolve-ref.js +152 -32
- package/dist/lib/task/review-artifacts.js +101 -0
- package/dist/lib/task/review-fingerprint.js +46 -0
- package/dist/lib/task/sections.js +358 -4
- package/dist/lib/task/short-id.js +292 -7
- package/dist/lib/task/snapshot.js +95 -0
- package/dist/lib/task/verification-checks.js +8 -0
- package/dist/lib/task/verification-config.js +14 -0
- package/dist/lib/task/verification-engine.js +906 -0
- package/dist/lib/task/verification-review.js +3 -0
- package/dist/lib/task/verification-types.js +2 -0
- package/dist/lib/task/verification.js +113 -0
- package/dist/lib/task/workflow-warning-intents.js +131 -0
- package/dist/lib/task/workflow-warnings.js +10 -78
- package/dist/lib/task/write.js +241 -0
- package/lib/decide.ts +57 -97
- package/lib/defaults.json +1 -0
- package/lib/git/review-snapshot.ts +73 -0
- package/lib/git/workflow.ts +101 -0
- package/lib/internal/git-workflow.ts +37 -0
- package/lib/internal/platform-checks.ts +101 -0
- package/lib/internal/platform-comment.ts +99 -0
- package/lib/internal/platform-context.ts +33 -0
- package/lib/internal/platform-issue.ts +116 -0
- package/lib/internal/platform-pr.ts +119 -0
- package/lib/internal/release-workflow.ts +186 -0
- package/lib/internal/task-artifact.ts +47 -0
- package/lib/internal/task-context.ts +35 -0
- package/lib/internal/task-event.ts +51 -0
- package/lib/internal/task-ledger.ts +86 -0
- package/lib/internal/task-lifecycle.ts +41 -0
- package/lib/internal/task-short-id.ts +55 -0
- package/lib/internal/task-snapshot.ts +32 -0
- package/lib/internal/task-verify.ts +33 -0
- package/lib/internal/task-warning.ts +50 -0
- package/lib/platform/adapters.ts +30 -0
- package/lib/platform/context.ts +164 -0
- package/lib/platform/github-client.ts +146 -0
- package/lib/platform/issue-comments.ts +479 -0
- package/lib/platform/issue-metadata.ts +250 -0
- package/lib/platform/issues.ts +691 -0
- package/lib/platform/metadata-labels.ts +33 -0
- package/lib/platform/pr-checks.ts +246 -0
- package/lib/platform/pr-summary.ts +90 -0
- package/lib/platform/pull-request-metadata.ts +69 -0
- package/lib/platform/pull-requests.ts +380 -0
- package/lib/platform/releases.ts +71 -0
- package/lib/platform/types.ts +74 -0
- package/lib/platform/verification-required.ts +83 -0
- package/{runtime/platform-adapters/platform-sync.github.js → lib/platform/verification-sync.ts} +198 -367
- package/lib/platform/verification.ts +11 -0
- package/lib/release/channels.ts +30 -0
- package/lib/release/workflow.ts +31 -0
- package/lib/render.ts +3 -2
- package/lib/run/index.ts +25 -7
- package/lib/sandbox/capture.ts +29 -3
- package/lib/sandbox/commands/create.ts +43 -25
- package/lib/sandbox/commands/enter.ts +38 -11
- package/lib/sandbox/commands/list-running.ts +10 -8
- package/lib/sandbox/commands/show.ts +2 -2
- package/lib/sandbox/commands/start.ts +50 -16
- package/lib/sandbox/index.ts +6 -6
- package/lib/sandbox/mounts.ts +55 -0
- package/lib/sandbox/recovery.ts +828 -0
- package/lib/sandbox/task-resolver.ts +5 -1
- package/lib/sandbox/tools.ts +31 -0
- package/lib/server/protocol.ts +5 -5
- package/lib/task/activity-log.ts +62 -0
- package/lib/task/artifact-lifecycle.ts +484 -0
- package/lib/task/command-options.ts +32 -0
- package/lib/task/commands/cat.ts +22 -9
- package/lib/task/commands/decisions.ts +49 -47
- package/lib/task/commands/files.ts +14 -6
- package/lib/task/commands/grep.ts +34 -7
- package/lib/task/commands/issue-body.ts +16 -16
- package/lib/task/commands/log.ts +17 -70
- package/lib/task/commands/show.ts +14 -6
- package/lib/task/commands/status.ts +17 -7
- package/lib/task/decision-intents.ts +163 -0
- package/lib/task/decision-items.ts +64 -0
- package/lib/task/events.ts +320 -0
- package/lib/task/frontmatter.ts +202 -2
- package/lib/task/implementation-inputs.ts +137 -0
- package/lib/task/index.ts +12 -9
- package/lib/task/issue-form.ts +20 -6
- package/lib/task/ledger-intents.ts +201 -0
- package/lib/task/ledger.ts +77 -31
- package/lib/task/lifecycle.ts +458 -0
- package/lib/task/resolve-ref.ts +197 -36
- package/{templates/.agents/scripts/lib/review-artifacts.js → lib/task/review-artifacts.ts} +11 -12
- package/{templates/.agents/scripts/lib/post-review-commit.js → lib/task/review-fingerprint.ts} +17 -12
- package/lib/task/sections.ts +486 -4
- package/lib/task/short-id.ts +403 -9
- package/lib/task/snapshot.ts +143 -0
- package/lib/task/verification-checks.ts +9 -0
- package/lib/task/verification-config.ts +20 -0
- package/{templates/.agents/scripts/validate-artifact.js → lib/task/verification-engine.ts} +199 -406
- package/lib/task/verification-review.ts +9 -0
- package/lib/task/verification-types.ts +29 -0
- package/lib/task/verification.ts +156 -0
- package/lib/task/workflow-warning-intents.ts +142 -0
- package/lib/task/workflow-warnings.ts +10 -78
- package/lib/task/write.ts +468 -0
- package/package.json +4 -2
- package/templates/.agents/README.en.md +4 -3
- package/templates/.agents/README.zh-CN.md +4 -3
- package/templates/.agents/rules/README.en.md +6 -5
- package/templates/.agents/rules/README.zh-CN.md +6 -5
- package/templates/.agents/rules/create-issue.en.md +1 -1
- package/templates/.agents/rules/create-issue.github.en.md +5 -184
- package/templates/.agents/rules/create-issue.github.zh-CN.md +12 -178
- package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
- package/templates/.agents/rules/human-decision-context.en.md +36 -0
- package/templates/.agents/rules/human-decision-context.zh-CN.md +36 -0
- package/templates/.agents/rules/issue-fields.github.en.md +4 -148
- package/templates/.agents/rules/issue-fields.github.zh-CN.md +9 -144
- package/templates/.agents/rules/issue-pr-commands.en.md +43 -3
- package/templates/.agents/rules/issue-pr-commands.github.en.md +15 -220
- package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +23 -213
- package/templates/.agents/rules/issue-pr-commands.zh-CN.md +45 -3
- package/templates/.agents/rules/issue-sync.en.md +1 -1
- package/templates/.agents/rules/issue-sync.github.en.md +14 -301
- package/templates/.agents/rules/issue-sync.github.zh-CN.md +36 -287
- package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
- package/templates/.agents/rules/milestone-inference.en.md +1 -1
- package/templates/.agents/rules/milestone-inference.github.en.md +7 -119
- package/templates/.agents/rules/milestone-inference.github.zh-CN.md +8 -108
- package/templates/.agents/rules/milestone-inference.zh-CN.md +1 -1
- package/templates/.agents/rules/next-step-output.en.md +12 -11
- package/templates/.agents/rules/next-step-output.zh-CN.md +12 -11
- package/templates/.agents/rules/no-mid-flow-questions.en.md +3 -3
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +3 -3
- package/templates/.agents/rules/pr-checks-commands.en.md +16 -3
- package/templates/.agents/rules/pr-checks-commands.github.en.md +10 -54
- package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +19 -47
- package/templates/.agents/rules/pr-checks-commands.zh-CN.md +30 -3
- package/templates/.agents/rules/pr-sync.en.md +30 -3
- package/templates/.agents/rules/pr-sync.github.en.md +12 -115
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +26 -104
- package/templates/.agents/rules/pr-sync.zh-CN.md +43 -3
- package/templates/.agents/rules/review-handshake.en.md +8 -5
- package/templates/.agents/rules/review-handshake.zh-CN.md +8 -5
- package/templates/.agents/rules/task-management.en.md +11 -2
- package/templates/.agents/rules/task-management.zh-CN.md +11 -3
- package/templates/.agents/rules/task-short-id.en.md +25 -29
- package/templates/.agents/rules/task-short-id.zh-CN.md +20 -23
- package/templates/.agents/scripts/lib/agent-infra-package.js +1 -9
- package/templates/.agents/scripts/task-short-id.js +71 -533
- package/templates/.agents/skills/analyze-task/SKILL.en.md +22 -55
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +26 -59
- package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -3
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -3
- package/templates/.agents/skills/block-task/SKILL.en.md +21 -47
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +23 -47
- package/templates/.agents/skills/block-task/config/verify.json +1 -2
- package/templates/.agents/skills/cancel-task/SKILL.en.md +16 -45
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +16 -45
- package/templates/.agents/skills/cancel-task/config/verify.json +1 -2
- package/templates/.agents/skills/check-task/SKILL.en.md +6 -3
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +6 -3
- package/templates/.agents/skills/close-codescan/SKILL.en.md +6 -24
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +6 -24
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +6 -24
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +6 -24
- package/templates/.agents/skills/code-task/SKILL.en.md +22 -35
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +28 -44
- package/templates/.agents/skills/code-task/config/verify.en.json +3 -3
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +3 -3
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +13 -9
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +13 -9
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/reference/report-template.en.md +11 -1
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +11 -1
- package/templates/.agents/skills/commit/SKILL.en.md +13 -11
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +13 -11
- package/templates/.agents/skills/commit/config/verify.json +1 -2
- package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -11
- package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -11
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +4 -8
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +4 -8
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +6 -18
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +5 -17
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +13 -0
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +13 -0
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +13 -36
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +13 -36
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -3
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -3
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +10 -54
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +10 -79
- package/templates/.agents/skills/complete-task/SKILL.en.md +59 -63
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +59 -63
- package/templates/.agents/skills/complete-task/config/verify.en.json +11 -7
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +11 -7
- package/templates/.agents/skills/create-pr/SKILL.en.md +19 -44
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +19 -43
- package/templates/.agents/skills/create-pr/config/verify.json +1 -2
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +8 -12
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +7 -11
- package/templates/.agents/skills/create-task/SKILL.en.md +12 -13
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +12 -13
- package/templates/.agents/skills/create-task/config/verify.json +1 -2
- package/templates/.agents/skills/import-codescan/SKILL.en.md +2 -2
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/import-codescan/config/verify.json +1 -2
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +2 -2
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/import-dependabot/config/verify.json +1 -2
- package/templates/.agents/skills/import-issue/SKILL.en.md +9 -13
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +10 -14
- package/templates/.agents/skills/import-issue/config/verify.json +1 -2
- package/templates/.agents/skills/plan-task/SKILL.en.md +17 -42
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +22 -49
- package/templates/.agents/skills/plan-task/config/verify.en.json +1 -3
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -3
- package/templates/.agents/skills/post-release/SKILL.en.md +11 -81
- package/templates/.agents/skills/post-release/SKILL.zh-CN.md +8 -78
- package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
- package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/release/SKILL.en.md +16 -163
- package/templates/.agents/skills/release/SKILL.zh-CN.md +15 -162
- package/templates/.agents/skills/restore-task/SKILL.en.md +11 -29
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +11 -29
- package/templates/.agents/skills/restore-task/config/verify.json +1 -2
- package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -25
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +13 -33
- package/templates/.agents/skills/review-analysis/config/verify.en.json +3 -4
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +3 -4
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +9 -12
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +9 -12
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +9 -2
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +9 -2
- package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +7 -0
- package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +7 -0
- package/templates/.agents/skills/review-code/SKILL.en.md +22 -36
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +23 -41
- package/templates/.agents/skills/review-code/config/verify.en.json +3 -4
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +3 -4
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +56 -18
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +56 -18
- package/templates/.agents/skills/review-code/reference/report-template.en.md +11 -4
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +11 -4
- package/templates/.agents/skills/review-code/reference/review-criteria.en.md +7 -0
- package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +7 -0
- package/templates/.agents/skills/review-plan/SKILL.en.md +13 -25
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +13 -33
- package/templates/.agents/skills/review-plan/config/verify.en.json +3 -4
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +3 -4
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +9 -12
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +9 -12
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +9 -2
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +9 -2
- package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +7 -0
- package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +7 -0
- package/templates/.agents/skills/update-agent-infra/SKILL.en.md +1 -2
- package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +1 -2
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +3 -15
- package/templates/.agents/skills/watch-pr/SKILL.en.md +24 -14
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +25 -15
- package/templates/.agents/skills/watch-pr/config/verify.json +1 -2
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +2 -2
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +2 -2
- package/templates/.agents/templates/task.en.md +6 -1
- package/templates/.agents/templates/task.zh-CN.md +6 -1
- package/templates/.claude/commands/analyze-task.en.md +1 -1
- package/templates/.claude/commands/analyze-task.zh-CN.md +1 -1
- package/templates/.claude/commands/block-task.en.md +1 -1
- package/templates/.claude/commands/block-task.zh-CN.md +1 -1
- package/templates/.claude/commands/cancel-task.en.md +1 -1
- package/templates/.claude/commands/cancel-task.zh-CN.md +1 -1
- package/templates/.claude/commands/check-task.en.md +1 -1
- package/templates/.claude/commands/check-task.zh-CN.md +1 -1
- package/templates/.claude/commands/code-task.en.md +1 -1
- package/templates/.claude/commands/code-task.zh-CN.md +1 -1
- package/templates/.claude/commands/commit.en.md +1 -0
- package/templates/.claude/commands/commit.zh-CN.md +1 -0
- package/templates/.claude/commands/complete-manual-validation.en.md +1 -1
- package/templates/.claude/commands/complete-manual-validation.zh-CN.md +1 -1
- package/templates/.claude/commands/complete-task.en.md +1 -1
- package/templates/.claude/commands/complete-task.zh-CN.md +1 -1
- package/templates/.claude/commands/create-pr.en.md +1 -1
- package/templates/.claude/commands/create-pr.zh-CN.md +1 -1
- package/templates/.claude/commands/plan-task.en.md +1 -1
- package/templates/.claude/commands/plan-task.zh-CN.md +1 -1
- package/templates/.claude/commands/review-analysis.en.md +1 -1
- package/templates/.claude/commands/review-analysis.zh-CN.md +1 -1
- package/templates/.claude/commands/review-code.en.md +1 -1
- package/templates/.claude/commands/review-code.zh-CN.md +1 -1
- package/templates/.claude/commands/review-plan.en.md +1 -1
- package/templates/.claude/commands/review-plan.zh-CN.md +1 -1
- package/templates/.claude/commands/watch-pr.en.md +1 -1
- package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
- package/templates/.gemini/commands/_project_/analyze-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/block-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/cancel-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/check-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/code-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/commit.en.toml +4 -0
- package/templates/.gemini/commands/_project_/commit.zh-CN.toml +4 -0
- package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +2 -0
- package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/complete-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/create-pr.en.toml +2 -0
- package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/plan-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/review-analysis.en.toml +2 -0
- package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/review-code.en.toml +2 -0
- package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/review-plan.en.toml +2 -0
- package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/watch-pr.en.toml +2 -0
- package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +2 -0
- package/templates/.git-hooks/check-large-files.cjs +92 -0
- package/templates/.git-hooks/check-version-format.sh +5 -1
- package/templates/.git-hooks/pre-commit +1 -0
- package/templates/.opencode/commands/analyze-task.en.md +1 -1
- package/templates/.opencode/commands/analyze-task.zh-CN.md +1 -1
- package/templates/.opencode/commands/check-task.en.md +1 -1
- package/templates/.opencode/commands/check-task.zh-CN.md +1 -1
- package/templates/.opencode/commands/code-task.en.md +1 -1
- package/templates/.opencode/commands/code-task.zh-CN.md +1 -1
- package/templates/.opencode/commands/commit.en.md +2 -0
- package/templates/.opencode/commands/commit.zh-CN.md +2 -0
- package/templates/.opencode/commands/complete-task.en.md +1 -1
- package/templates/.opencode/commands/complete-task.zh-CN.md +1 -1
- package/templates/.opencode/commands/plan-task.en.md +1 -1
- package/templates/.opencode/commands/plan-task.zh-CN.md +1 -1
- package/templates/.opencode/commands/review-analysis.en.md +1 -1
- package/templates/.opencode/commands/review-analysis.zh-CN.md +1 -1
- package/templates/.opencode/commands/review-code.en.md +1 -1
- package/templates/.opencode/commands/review-code.zh-CN.md +1 -1
- package/templates/.opencode/commands/review-plan.en.md +1 -1
- package/templates/.opencode/commands/review-plan.zh-CN.md +1 -1
- package/templates/.agents/scripts/platform-adapters/platform-sync.github.js +0 -40
- package/templates/.agents/scripts/platform-adapters/platform-sync.js +0 -13
- package/templates/.agents/scripts/review-diff-fingerprint.js +0 -170
- package/templates/.agents/scripts/workflow-warnings.js +0 -290
- package/templates/.agents/skills/code-task/scripts/detect-mode.js +0 -257
- package/templates/.agents/skills/release/scripts/manage-milestones.github.sh +0 -80
- package/templates/.agents/skills/release/scripts/manage-milestones.sh +0 -6
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const HEADING_RE = /^##\s+(活动日志|Activity Log)\s*$/;
|
|
2
|
+
const NEXT_H2_RE = /^##\s/;
|
|
3
|
+
const ENTRY_RE = /^- (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}) — \*\*(.+?)\*\* by (.+?) — (.*)$/;
|
|
4
|
+
const STARTED_SUFFIX_RE = /\s*\[started\]\s*$/;
|
|
5
|
+
function parseActivityLog(content) {
|
|
6
|
+
const section = locateActivityLog(content);
|
|
7
|
+
return section ? { sectionFound: true, entries: section.entries } : { sectionFound: false, entries: [] };
|
|
8
|
+
}
|
|
9
|
+
function locateActivityLog(content) {
|
|
10
|
+
const lines = content.split('\n');
|
|
11
|
+
const headings = lines.map((line, index) => HEADING_RE.test(line) ? index : -1).filter((index) => index >= 0);
|
|
12
|
+
if (headings.length !== 1)
|
|
13
|
+
return null;
|
|
14
|
+
const i = headings[0];
|
|
15
|
+
let end = lines.length;
|
|
16
|
+
for (let j = i + 1; j < lines.length; j += 1) {
|
|
17
|
+
if (NEXT_H2_RE.test(lines[j])) {
|
|
18
|
+
end = j;
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const bodyLines = lines.slice(i + 1, end);
|
|
23
|
+
const parsed = [];
|
|
24
|
+
for (const line of bodyLines) {
|
|
25
|
+
const m = ENTRY_RE.exec(line);
|
|
26
|
+
if (!m)
|
|
27
|
+
continue;
|
|
28
|
+
parsed.push({ entry: { time: m[1], step: m[2], agent: m[3], note: m[4] }, epoch: Date.parse(m[1].replace(' ', 'T')), order: parsed.length });
|
|
29
|
+
}
|
|
30
|
+
parsed.sort((a, b) => a.epoch - b.epoch || a.order - b.order);
|
|
31
|
+
return { heading: HEADING_RE.exec(lines[i])[1], body: bodyLines.join('\n').replace(/^\n+|\n+$/g, ''), entries: parsed.map((item) => item.entry) };
|
|
32
|
+
}
|
|
33
|
+
function appendActivityEntry(section, entry) {
|
|
34
|
+
const line = `- ${entry.time} — **${entry.step}** by ${entry.agent} — ${entry.note}`;
|
|
35
|
+
return section.body ? `${section.body}\n${line}` : line;
|
|
36
|
+
}
|
|
37
|
+
function pairEntries(entries) {
|
|
38
|
+
const rows = [];
|
|
39
|
+
const open = new Map();
|
|
40
|
+
for (const entry of entries) {
|
|
41
|
+
const started = STARTED_SUFFIX_RE.test(entry.step);
|
|
42
|
+
const base = entry.step.replace(STARTED_SUFFIX_RE, '');
|
|
43
|
+
if (started) {
|
|
44
|
+
const row = { step: base, agent: entry.agent, started: entry.time, done: '', note: entry.note };
|
|
45
|
+
rows.push(row);
|
|
46
|
+
const queue = open.get(base) ?? [];
|
|
47
|
+
queue.push(row);
|
|
48
|
+
open.set(base, queue);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const pending = open.get(base)?.shift();
|
|
52
|
+
if (pending)
|
|
53
|
+
Object.assign(pending, { done: entry.time, agent: entry.agent, note: entry.note });
|
|
54
|
+
else
|
|
55
|
+
rows.push({ step: base, agent: entry.agent, started: '', done: entry.time, note: entry.note });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return rows;
|
|
59
|
+
}
|
|
60
|
+
export { parseActivityLog, locateActivityLog, appendActivityEntry, pairEntries };
|
|
61
|
+
//# sourceMappingURL=activity-log.js.map
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { resolveTaskRef } from './resolve-ref.js';
|
|
4
|
+
import { locateActivityLog } from './activity-log.js';
|
|
5
|
+
import { parseImplementationInputs, selectPendingImplementationInput } from './implementation-inputs.js';
|
|
6
|
+
import { extractSection, findSectionHeading } from './sections.js';
|
|
7
|
+
const artifactFamilyCatalog = [
|
|
8
|
+
{ family: 'analysis', sectionAliases: ['分析', 'Analysis'], heading: '分析', labels: ['需求分析报告', 'Requirements Analysis'] },
|
|
9
|
+
{ family: 'review-analysis', sectionAliases: ['审查反馈', 'Review Feedback'], heading: '审查反馈', labels: ['需求分析审查', 'Analysis Review'] },
|
|
10
|
+
{ family: 'plan', sectionAliases: ['设计', 'Design'], heading: '设计', labels: ['技术方案', 'Technical Plan'] },
|
|
11
|
+
{ family: 'review-plan', sectionAliases: ['审查反馈', 'Review Feedback'], heading: '审查反馈', labels: ['技术方案审查', 'Plan Review'] },
|
|
12
|
+
{ family: 'code', sectionAliases: ['实现备注', 'Implementation Notes'], heading: '实现备注', labels: ['实现报告', 'Implementation Report'] },
|
|
13
|
+
{ family: 'review-code', sectionAliases: ['审查反馈', 'Review Feedback'], heading: '审查反馈', labels: ['代码审查', 'Code Review'] },
|
|
14
|
+
{ family: 'manual-validation', sectionAliases: ['实现备注', 'Implementation Notes'], heading: '实现备注', labels: ['人工验证', 'Manual Validation'] }
|
|
15
|
+
];
|
|
16
|
+
const FAMILY_SET = new Set(artifactFamilyCatalog.map((item) => item.family));
|
|
17
|
+
const BLOCKING_DIAGNOSTICS = new Set([
|
|
18
|
+
'NONCANONICAL_NAME', 'ROUND_OUT_OF_RANGE', 'MISSING_BASE', 'ROUND_GAP',
|
|
19
|
+
'DUPLICATE_LOGICAL_ROUND', 'NON_REGULAR_FILE', 'SYMBOLIC_LINK',
|
|
20
|
+
'FILESYSTEM_RACE', 'CATALOG_CONFLICT'
|
|
21
|
+
]);
|
|
22
|
+
function familySpec(family) {
|
|
23
|
+
return artifactFamilyCatalog.find((item) => item.family === family) ?? null;
|
|
24
|
+
}
|
|
25
|
+
function artifactName(family, round) {
|
|
26
|
+
if (!FAMILY_SET.has(family))
|
|
27
|
+
throw new Error(`unknown artifact family '${family}'`);
|
|
28
|
+
if (!Number.isSafeInteger(round) || round < 1)
|
|
29
|
+
throw new Error('artifact round must be a safe positive integer');
|
|
30
|
+
return round === 1 ? `${family}.md` : `${family}-r${round}.md`;
|
|
31
|
+
}
|
|
32
|
+
function parseArtifactName(name) {
|
|
33
|
+
if (path.basename(name) !== name)
|
|
34
|
+
return null;
|
|
35
|
+
const matches = [];
|
|
36
|
+
for (const spec of artifactFamilyCatalog) {
|
|
37
|
+
if (name === `${spec.family}.md`)
|
|
38
|
+
matches.push({ family: spec.family, round: 1, name });
|
|
39
|
+
const match = new RegExp(`^${escapeRegExp(spec.family)}-r([1-9]\\d*)\\.md$`).exec(name);
|
|
40
|
+
if (!match)
|
|
41
|
+
continue;
|
|
42
|
+
const round = Number(match[1]);
|
|
43
|
+
if (Number.isSafeInteger(round) && round >= 2 && String(round) === match[1]) {
|
|
44
|
+
matches.push({ family: spec.family, round, name });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return matches.length === 1 ? matches[0] : null;
|
|
48
|
+
}
|
|
49
|
+
function escapeRegExp(value) {
|
|
50
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
51
|
+
}
|
|
52
|
+
function failure(requestRef, family, error, extra = {}) {
|
|
53
|
+
return {
|
|
54
|
+
status: 'failed', changed: false, requestRef, taskId: null, taskDir: null,
|
|
55
|
+
taskState: null, family, artifacts: [], latest: null, next: null,
|
|
56
|
+
reviewedInput: null, diagnostics: [], error, ...extra
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function diagnostic(code, family, name, message) {
|
|
60
|
+
return { code, family, name, message };
|
|
61
|
+
}
|
|
62
|
+
function inspectTaskArtifacts(taskRef, family, options = {}) {
|
|
63
|
+
const spec = familySpec(family);
|
|
64
|
+
if (!spec)
|
|
65
|
+
return failure(taskRef, family, { code: 'ARTIFACT_FAMILY_UNKNOWN', message: `unknown artifact family '${family}'` });
|
|
66
|
+
const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
|
|
67
|
+
if (!resolved.ok)
|
|
68
|
+
return failure(taskRef, family, { code: resolved.code, message: resolved.message }, { taskId: resolved.taskId });
|
|
69
|
+
return inspectArtifactDirectory(resolved.taskDir, spec.family, {
|
|
70
|
+
requestRef: taskRef, taskId: resolved.taskId, taskState: resolved.state
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function inspectArtifactDirectory(taskDir, family, identity = {}) {
|
|
74
|
+
const requestRef = identity.requestRef ?? taskDir;
|
|
75
|
+
let entries;
|
|
76
|
+
try {
|
|
77
|
+
entries = fs.readdirSync(taskDir, { withFileTypes: true });
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
return failure(requestRef, family, { code: 'ARTIFACT_DIRECTORY_READ_FAILED', message: String(error) }, {
|
|
81
|
+
taskId: identity.taskId ?? null, taskDir, taskState: identity.taskState ?? null
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
const artifacts = [];
|
|
85
|
+
const diagnostics = [];
|
|
86
|
+
for (const entry of entries) {
|
|
87
|
+
const parsed = parseArtifactName(entry.name);
|
|
88
|
+
const reserved = entry.name.toLowerCase().startsWith(`${family.toLowerCase()}-r`) || entry.name.toLowerCase() === `${family.toLowerCase()}.md`;
|
|
89
|
+
if (!parsed || parsed.family !== family) {
|
|
90
|
+
if (reserved) {
|
|
91
|
+
const roundText = new RegExp(`^${escapeRegExp(family)}-r(.+)\\.md$`, 'i').exec(entry.name)?.[1];
|
|
92
|
+
const code = roundText && /^\d+$/.test(roundText) && !Number.isSafeInteger(Number(roundText))
|
|
93
|
+
? 'ROUND_OUT_OF_RANGE' : 'NONCANONICAL_NAME';
|
|
94
|
+
diagnostics.push(diagnostic(code, family, entry.name, `noncanonical ${family} artifact candidate '${entry.name}' (verify whether this is an unrelated file with a reserved prefix)`));
|
|
95
|
+
}
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const abs = path.join(taskDir, entry.name);
|
|
99
|
+
try {
|
|
100
|
+
const stat = fs.lstatSync(abs);
|
|
101
|
+
if (stat.isSymbolicLink()) {
|
|
102
|
+
diagnostics.push(diagnostic('SYMBOLIC_LINK', family, entry.name, `symbolic links are not workflow artifacts: ${entry.name}`));
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (!stat.isFile()) {
|
|
106
|
+
diagnostics.push(diagnostic('NON_REGULAR_FILE', family, entry.name, `artifact is not a regular file: ${entry.name}`));
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
fs.accessSync(abs, fs.constants.R_OK);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
diagnostics.push(diagnostic('FILESYSTEM_RACE', family, entry.name, `artifact is not readable: ${entry.name}`));
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
artifacts.push({ ...parsed, path: abs, size: stat.size, mtimeMs: stat.mtimeMs });
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
diagnostics.push(diagnostic('FILESYSTEM_RACE', family, entry.name, String(error)));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
artifacts.sort((left, right) => left.round - right.round);
|
|
123
|
+
const rounds = new Set(artifacts.map((item) => item.round));
|
|
124
|
+
if (artifacts.length > 0 && !rounds.has(1))
|
|
125
|
+
diagnostics.push(diagnostic('MISSING_BASE', family, null, `${family}.md is missing`));
|
|
126
|
+
const max = artifacts.at(-1)?.round ?? 0;
|
|
127
|
+
for (let round = 1; round <= max; round += 1) {
|
|
128
|
+
if (!rounds.has(round))
|
|
129
|
+
diagnostics.push(diagnostic('ROUND_GAP', family, null, `${artifactName(family, round)} is missing`));
|
|
130
|
+
}
|
|
131
|
+
const latest = artifacts.at(-1) ?? null;
|
|
132
|
+
const reviewedInput = family.startsWith('review-') && latest
|
|
133
|
+
? resolveReviewedInput(taskDir, latest, family === 'review-analysis' ? 'analysis' : family === 'review-plan' ? 'plan' : 'code', diagnostics)
|
|
134
|
+
: null;
|
|
135
|
+
return {
|
|
136
|
+
status: 'ready', changed: false, requestRef, taskId: identity.taskId ?? null,
|
|
137
|
+
taskDir, taskState: identity.taskState ?? null, family, artifacts, latest,
|
|
138
|
+
next: { round: max + 1, name: artifactName(family, max + 1) },
|
|
139
|
+
reviewedInput, diagnostics, error: null
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function resolveReviewedInput(taskDir, review, expectedFamily, diagnostics) {
|
|
143
|
+
let content;
|
|
144
|
+
try {
|
|
145
|
+
content = fs.readFileSync(review.path, 'utf8');
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
diagnostics.push(diagnostic('BROKEN_REFERENCE', review.family, review.name, String(error)));
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
const lines = content.split(/\r?\n/);
|
|
152
|
+
const header = lines.findIndex((line) => /\*\*(?:审查输入|Review Input)\*\*[::]/.test(line));
|
|
153
|
+
const referenceBlock = header >= 0 ? lines.slice(header, header + 12).join('\n') : '';
|
|
154
|
+
const candidates = [...referenceBlock.matchAll(/`([^`]+\.md)`/g)].map((match) => match[1]);
|
|
155
|
+
const parsed = candidates.map((name) => parseArtifactName(name)).find((item) => item?.family === expectedFamily);
|
|
156
|
+
if (!parsed) {
|
|
157
|
+
diagnostics.push(diagnostic('BROKEN_REFERENCE', review.family, review.name, `${review.name} does not reference a canonical ${expectedFamily} artifact`));
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
const abs = path.join(taskDir, parsed.name);
|
|
161
|
+
try {
|
|
162
|
+
const stat = fs.lstatSync(abs);
|
|
163
|
+
if (!stat.isFile() || stat.isSymbolicLink())
|
|
164
|
+
throw new Error('referenced input is not a regular file');
|
|
165
|
+
if (stat.mtimeMs > review.mtimeMs) {
|
|
166
|
+
diagnostics.push(diagnostic('BROKEN_REFERENCE', review.family, review.name, `${parsed.name} is newer than ${review.name}`));
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
return { ...parsed, path: abs, size: stat.size, mtimeMs: stat.mtimeMs };
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
diagnostics.push(diagnostic('BROKEN_REFERENCE', review.family, review.name, `${parsed.name}: ${String(error)}`));
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function extractMarkdownSection(content, names) {
|
|
177
|
+
const lines = content.split(/\r?\n/);
|
|
178
|
+
const allowed = new Set(names);
|
|
179
|
+
const start = lines.findIndex((line) => {
|
|
180
|
+
const match = /^##\s+(.+?)\s*$/.exec(line.trim());
|
|
181
|
+
return Boolean(match?.[1] && allowed.has(match[1]));
|
|
182
|
+
});
|
|
183
|
+
if (start === -1)
|
|
184
|
+
return '';
|
|
185
|
+
let end = lines.length;
|
|
186
|
+
for (let index = start + 1; index < lines.length; index += 1) {
|
|
187
|
+
if (/^##\s+/.test(lines[index])) {
|
|
188
|
+
end = index;
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return lines.slice(start + 1, end).join('\n');
|
|
193
|
+
}
|
|
194
|
+
function assertWritableInventory(inventory) {
|
|
195
|
+
if (inventory.status === 'failed')
|
|
196
|
+
return inventory.error;
|
|
197
|
+
const blockers = inventory.diagnostics.filter((item) => BLOCKING_DIAGNOSTICS.has(item.code));
|
|
198
|
+
return blockers.length === 0 ? null : {
|
|
199
|
+
code: 'ARTIFACT_TOPOLOGY_CONFLICT',
|
|
200
|
+
message: blockers.map((item) => `${item.code}: ${item.message}`).join('; ')
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
const REQUIRED_INPUT = {
|
|
204
|
+
'review-analysis': 'analysis', plan: 'analysis', 'review-plan': 'plan', 'review-code': 'code'
|
|
205
|
+
};
|
|
206
|
+
const OPTIONAL_CONTEXT = {
|
|
207
|
+
analysis: { family: 'review-analysis', requireReference: true },
|
|
208
|
+
plan: { family: 'review-plan', requireReference: true },
|
|
209
|
+
'review-code': { family: 'review-plan' },
|
|
210
|
+
'manual-validation': { family: 'review-code' }
|
|
211
|
+
};
|
|
212
|
+
function resolveArtifactContext(taskRef, family, options = {}) {
|
|
213
|
+
const inventory = inspectTaskArtifacts(taskRef, family, options);
|
|
214
|
+
if (inventory.status === 'failed')
|
|
215
|
+
return { ...inventory, inputs: [], codeMode: null };
|
|
216
|
+
const writableError = assertWritableInventory(inventory);
|
|
217
|
+
if (writableError)
|
|
218
|
+
return { ...inventory, status: 'failed', inputs: [], codeMode: null, error: writableError };
|
|
219
|
+
if (inventory.family === 'code')
|
|
220
|
+
return resolveCodeContext(inventory, options);
|
|
221
|
+
const required = REQUIRED_INPUT[inventory.family];
|
|
222
|
+
const inputs = [];
|
|
223
|
+
if (required) {
|
|
224
|
+
const input = inspectTaskArtifacts(taskRef, required, options);
|
|
225
|
+
if (input.status === 'failed' || !input.latest) {
|
|
226
|
+
return { ...inventory, status: 'failed', inputs, codeMode: null, error: { code: 'ARTIFACT_INPUT_MISSING', message: `latest ${required} artifact is required` } };
|
|
227
|
+
}
|
|
228
|
+
inputs.push(input.latest);
|
|
229
|
+
}
|
|
230
|
+
const optional = OPTIONAL_CONTEXT[inventory.family];
|
|
231
|
+
if (optional) {
|
|
232
|
+
const context = inspectTaskArtifacts(taskRef, optional.family, options);
|
|
233
|
+
if (context.status === 'ready' && context.latest) {
|
|
234
|
+
if (optional.requireReference && !context.reviewedInput) {
|
|
235
|
+
return { ...inventory, status: 'failed', inputs, codeMode: null, error: { code: 'ARTIFACT_REFERENCE_INVALID', message: `${context.latest.name} has no valid reviewed input` } };
|
|
236
|
+
}
|
|
237
|
+
inputs.push(context.latest);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return { ...inventory, inputs, codeMode: null };
|
|
241
|
+
}
|
|
242
|
+
function resolveCodeContext(inventory, options) {
|
|
243
|
+
const taskRef = inventory.requestRef;
|
|
244
|
+
const plan = inspectTaskArtifacts(taskRef, 'plan', options);
|
|
245
|
+
if (plan.status === 'failed' || !plan.latest)
|
|
246
|
+
return contextFailure(inventory, 'ARTIFACT_INPUT_MISSING', 'latest plan artifact is required');
|
|
247
|
+
const reviewPlan = inspectTaskArtifacts(taskRef, 'review-plan', options);
|
|
248
|
+
const reviewCode = inspectTaskArtifacts(taskRef, 'review-code', options);
|
|
249
|
+
const latestCode = inventory.latest;
|
|
250
|
+
const codeMax = latestCode?.round ?? 0;
|
|
251
|
+
const reviewMax = reviewCode.latest?.round ?? 0;
|
|
252
|
+
const inputs = [plan.latest];
|
|
253
|
+
if (!latestCode) {
|
|
254
|
+
if (!reviewPlan.latest || reviewPlan.reviewedInput?.name !== plan.latest.name) {
|
|
255
|
+
return contextFailure(inventory, 'ARTIFACT_INPUT_MISSING', `latest plan '${plan.latest.name}' requires a matching approved review-plan`);
|
|
256
|
+
}
|
|
257
|
+
const verdict = parseVerdict(reviewPlan.latest.path);
|
|
258
|
+
if (!verdict.ok)
|
|
259
|
+
return contextFailure(inventory, 'ARTIFACT_REFERENCE_INVALID', verdict.message, reviewPlan.latest.name);
|
|
260
|
+
if (verdict.verdict !== 'Approved') {
|
|
261
|
+
return contextFailure(inventory, 'ARTIFACT_REFERENCE_INVALID', `latest ${reviewPlan.latest.name} is not approved`, reviewPlan.latest.name);
|
|
262
|
+
}
|
|
263
|
+
return withCodeMode(inventory, inputs, 'ready', 'init', codeMax, reviewMax, null, null, 'No prior code artifact. Starting initial implementation (round 1 -> code.md).');
|
|
264
|
+
}
|
|
265
|
+
if (reviewPlan.latest && reviewPlan.reviewedInput?.name === plan.latest.name) {
|
|
266
|
+
const verdict = parseVerdict(reviewPlan.latest.path);
|
|
267
|
+
if (verdict.ok && verdict.verdict === 'Approved' && reviewPlan.latest.mtimeMs > latestCode.mtimeMs) {
|
|
268
|
+
return withCodeMode(inventory, inputs, 'ready', 'init', codeMax, reviewMax, verdict.verdict, reviewPlan.latest.name, `Latest ${reviewPlan.latest.name} is approved and newer than the latest code artifact. Entering replan-driven init.`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (reviewMax < codeMax) {
|
|
272
|
+
const expected = artifactName('review-code', codeMax);
|
|
273
|
+
return contextFailure(inventory, 'ARTIFACT_INPUT_MISSING', `${expected} is required before another code round`, expected);
|
|
274
|
+
}
|
|
275
|
+
const review = reviewCode.latest;
|
|
276
|
+
if (!review)
|
|
277
|
+
return contextFailure(inventory, 'ARTIFACT_INPUT_MISSING', 'latest review-code artifact is required');
|
|
278
|
+
const verdict = parseVerdict(review.path);
|
|
279
|
+
if (!verdict.ok)
|
|
280
|
+
return contextFailure(inventory, 'ARTIFACT_REFERENCE_INVALID', verdict.message);
|
|
281
|
+
if (verdict.verdict === 'Approved') {
|
|
282
|
+
const decision = resolveDecisionImplementationInput(inventory, review);
|
|
283
|
+
if ('error' in decision)
|
|
284
|
+
return contextFailure(inventory, 'ARTIFACT_REFERENCE_INVALID', decision.error, review.name);
|
|
285
|
+
if (decision.input) {
|
|
286
|
+
return withCodeMode(inventory, [...inputs, review], 'ready', 'decision', codeMax, reviewMax, verdict.verdict, review.name, `Implementation input ${decision.input.id} requires a new code round.`, decision.input.id, decision.input.ledgerId, decision.input.decisionEvidence);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (verdict.verdict === 'Approved' || verdict.verdict === 'Rejected') {
|
|
290
|
+
return withCodeMode(inventory, [...inputs, review], 'refused', 'refused', codeMax, reviewMax, verdict.verdict, review.name, verdict.verdict === 'Approved'
|
|
291
|
+
? `Latest ${review.name} verdict is Approved with no findings. Nothing to fix. Run /commit to proceed.`
|
|
292
|
+
: `Latest ${review.name} verdict is Rejected. Re-plan before re-running code-task.`);
|
|
293
|
+
}
|
|
294
|
+
return withCodeMode(inventory, [...inputs, review], 'ready', 'fix', codeMax, reviewMax, verdict.verdict, review.name, `Latest ${review.name} requires or permits fixes. Entering fix mode.`);
|
|
295
|
+
}
|
|
296
|
+
function contextFailure(inventory, code, message, reviewArtifact = null) {
|
|
297
|
+
return { ...inventory, status: 'failed', inputs: [], codeMode: { mode: 'error', codeMax: inventory.latest?.round ?? 0, reviewMax: 0, verdict: null, reviewArtifact, implementationInput: null, decisionId: null, decisionEvidence: null, message }, error: { code, message } };
|
|
298
|
+
}
|
|
299
|
+
function withCodeMode(inventory, inputs, status, mode, codeMax, reviewMax, verdict, reviewArtifact, message, implementationInput = null, decisionId = null, decisionEvidence = null) {
|
|
300
|
+
return { ...inventory, status, inputs, codeMode: { mode, codeMax, reviewMax, verdict, reviewArtifact, implementationInput, decisionId, decisionEvidence, message }, error: status === 'refused' ? { code: 'ARTIFACT_MODE_REFUSED', message } : null };
|
|
301
|
+
}
|
|
302
|
+
function resolveDecisionImplementationInput(inventory, review) {
|
|
303
|
+
if (!inventory.taskDir)
|
|
304
|
+
return { error: 'task directory is unavailable' };
|
|
305
|
+
let content;
|
|
306
|
+
try {
|
|
307
|
+
content = fs.readFileSync(path.join(inventory.taskDir, 'task.md'), 'utf8');
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
return { error: String(error) };
|
|
311
|
+
}
|
|
312
|
+
let rows;
|
|
313
|
+
try {
|
|
314
|
+
rows = parseImplementationInputs(content).rows;
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
return { error: error instanceof Error ? error.message : String(error) };
|
|
318
|
+
}
|
|
319
|
+
const pending = rows.filter((row) => row.needsImplementation && row.status === 'pending');
|
|
320
|
+
if (pending.length === 0)
|
|
321
|
+
return { input: null };
|
|
322
|
+
const activity = locateActivityLog(content);
|
|
323
|
+
if (!activity)
|
|
324
|
+
return { error: 'task has no unique Activity Log section' };
|
|
325
|
+
const reviewEntries = activity.entries.filter((entry) => /^Review Code \(Round \d+\)$/.test(entry.step) && entry.note.includes(`→ ${review.name}`));
|
|
326
|
+
const completed = reviewEntries.at(-1);
|
|
327
|
+
if (!completed)
|
|
328
|
+
return { error: `cannot find completed Activity Log identity for ${review.name}` };
|
|
329
|
+
try {
|
|
330
|
+
return { input: selectPendingImplementationInput(rows, completed.time) };
|
|
331
|
+
}
|
|
332
|
+
catch (error) {
|
|
333
|
+
return { error: error instanceof Error ? error.message : String(error) };
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
function normalizeVerdict(value) {
|
|
337
|
+
const normalized = value.trim().toLowerCase();
|
|
338
|
+
if (normalized === '通过' || normalized === 'approved')
|
|
339
|
+
return 'Approved';
|
|
340
|
+
if (normalized === '需要修改' || normalized === 'changes requested')
|
|
341
|
+
return 'Changes Requested';
|
|
342
|
+
if (normalized === '拒绝' || normalized === 'rejected')
|
|
343
|
+
return 'Rejected';
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
function parseVerdict(file) {
|
|
347
|
+
let content;
|
|
348
|
+
try {
|
|
349
|
+
content = fs.readFileSync(file, 'utf8');
|
|
350
|
+
}
|
|
351
|
+
catch (error) {
|
|
352
|
+
return { ok: false, message: String(error) };
|
|
353
|
+
}
|
|
354
|
+
const summary = extractMarkdownSection(content, ['审查摘要', 'Review Summary']);
|
|
355
|
+
const verdictMatch = /^[-*]?\s*\*\*(?:总体结论|Overall Verdict)\*\*[::]\s*(.+?)\s*$/im.exec(summary);
|
|
356
|
+
const verdict = verdictMatch?.[1] ? normalizeVerdict(verdictMatch[1]) : null;
|
|
357
|
+
if (!verdict)
|
|
358
|
+
return { ok: false, message: `cannot parse verdict in ${path.basename(file)}` };
|
|
359
|
+
if (verdict !== 'Approved')
|
|
360
|
+
return { ok: true, verdict };
|
|
361
|
+
const findings = /^[-*]?\s*\*\*(?:发现(AI 可处理)|Findings \(AI-actionable\))\*\*[::]\s*(.+?)\s*$/im.exec(summary)?.[1];
|
|
362
|
+
const counts = findings?.match(/(\d+)\s*(?:阻塞项|blockers?).*?(\d+)\s*(?:主要|majors?).*?(\d+)\s*(?:次要|minors?)/i);
|
|
363
|
+
if (!counts)
|
|
364
|
+
return { ok: false, message: `cannot parse findings count in ${path.basename(file)}` };
|
|
365
|
+
return { ok: true, verdict: counts.slice(1).some((value) => Number(value) > 0) ? 'Approved-with-issues' : 'Approved' };
|
|
366
|
+
}
|
|
367
|
+
function validateCompletedArtifact(taskDir, family, name, round) {
|
|
368
|
+
if (path.basename(name) !== name)
|
|
369
|
+
return { ok: false, error: { code: 'ARTIFACT_PATH_INVALID', message: 'artifact must be a top-level basename' } };
|
|
370
|
+
const parsed = parseArtifactName(name);
|
|
371
|
+
if (!parsed || parsed.family !== family || (round !== undefined && parsed.round !== round)) {
|
|
372
|
+
return { ok: false, error: { code: 'ARTIFACT_IDENTITY_INVALID', message: `artifact '${name}' does not match ${family}${round ? ` round ${round}` : ''}` } };
|
|
373
|
+
}
|
|
374
|
+
const abs = path.join(taskDir, name);
|
|
375
|
+
let stat;
|
|
376
|
+
try {
|
|
377
|
+
stat = fs.lstatSync(abs);
|
|
378
|
+
}
|
|
379
|
+
catch {
|
|
380
|
+
return { ok: false, error: { code: 'ARTIFACT_NOT_FOUND', message: `artifact '${name}' is not landed` } };
|
|
381
|
+
}
|
|
382
|
+
if (stat.isSymbolicLink() || !stat.isFile())
|
|
383
|
+
return { ok: false, error: { code: 'ARTIFACT_NOT_REGULAR', message: `artifact '${name}' is not a regular file` } };
|
|
384
|
+
try {
|
|
385
|
+
fs.accessSync(abs, fs.constants.R_OK);
|
|
386
|
+
}
|
|
387
|
+
catch {
|
|
388
|
+
return { ok: false, error: { code: 'ARTIFACT_NOT_READABLE', message: `artifact '${name}' is not readable` } };
|
|
389
|
+
}
|
|
390
|
+
const inventory = inspectArtifactDirectory(taskDir, family);
|
|
391
|
+
const topology = assertWritableInventory(inventory);
|
|
392
|
+
if (topology)
|
|
393
|
+
return { ok: false, error: topology };
|
|
394
|
+
const artifact = inventory.artifacts.find((item) => item.name === name);
|
|
395
|
+
return artifact ? { ok: true, artifact } : { ok: false, error: { code: 'ARTIFACT_NOT_FOUND', message: `artifact '${name}' is not in inventory` } };
|
|
396
|
+
}
|
|
397
|
+
function buildArtifactLinkSection(content, artifact) {
|
|
398
|
+
const spec = familySpec(artifact.family);
|
|
399
|
+
const aliases = [...spec.sectionAliases];
|
|
400
|
+
const heading = findSectionHeading(content, aliases);
|
|
401
|
+
const english = heading === spec.sectionAliases[1];
|
|
402
|
+
const label = english
|
|
403
|
+
? `${spec.labels[1]} (Round ${artifact.round})`
|
|
404
|
+
: `${spec.labels[0]}(Round ${artifact.round})`;
|
|
405
|
+
const link = `[${label}](${artifact.name})`;
|
|
406
|
+
let body = extractSection(content, aliases);
|
|
407
|
+
if (body.includes(`](${artifact.name})`))
|
|
408
|
+
return { aliases, heading, body };
|
|
409
|
+
const placeholders = new Set([
|
|
410
|
+
'[分析阶段的发现。哪些文件受影响?范围是什么?]',
|
|
411
|
+
'[Findings from the analysis phase. Which files are affected? What is the scope?]',
|
|
412
|
+
'[技术方案。接口、数据流、架构决策。]',
|
|
413
|
+
'[Technical approach. Interfaces, data flow, architecture decisions.]',
|
|
414
|
+
'[实现阶段的备注。做出的决策、权衡、与设计的偏差。]',
|
|
415
|
+
'[Notes from the code phase. Decisions made, trade-offs, deviations from design.]'
|
|
416
|
+
]);
|
|
417
|
+
const lines = body.split(/\r?\n/);
|
|
418
|
+
const placeholder = lines.findIndex((line) => placeholders.has(line.trim()));
|
|
419
|
+
if (placeholder >= 0)
|
|
420
|
+
lines[placeholder] = link;
|
|
421
|
+
else
|
|
422
|
+
lines.push(...(body ? ['', link] : [link]));
|
|
423
|
+
body = lines.join('\n').replace(/^\n+|\n+$/g, '');
|
|
424
|
+
return { aliases, heading, body };
|
|
425
|
+
}
|
|
426
|
+
export { artifactFamilyCatalog, artifactName, parseArtifactName, familySpec, inspectTaskArtifacts, inspectArtifactDirectory, resolveArtifactContext, assertWritableInventory, validateCompletedArtifact, buildArtifactLinkSection };
|
|
427
|
+
//# sourceMappingURL=artifact-lifecycle.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
function parseTaskScope(args) {
|
|
2
|
+
const positionals = [];
|
|
3
|
+
let taskRef;
|
|
4
|
+
let explicit = false;
|
|
5
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
6
|
+
const arg = args[index];
|
|
7
|
+
let value;
|
|
8
|
+
if (arg === '--task' || arg === '-t') {
|
|
9
|
+
value = args[++index];
|
|
10
|
+
if (value === undefined || value === '' || value.startsWith('-'))
|
|
11
|
+
throw new Error(`${arg} requires a value`);
|
|
12
|
+
}
|
|
13
|
+
else if (arg.startsWith('--task=')) {
|
|
14
|
+
value = arg.slice('--task='.length);
|
|
15
|
+
if (value === '')
|
|
16
|
+
throw new Error('--task requires a value');
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
positionals.push(arg);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (explicit)
|
|
23
|
+
throw new Error("duplicate option '--task'");
|
|
24
|
+
taskRef = value;
|
|
25
|
+
explicit = true;
|
|
26
|
+
}
|
|
27
|
+
return { taskRef, positionals, explicit };
|
|
28
|
+
}
|
|
29
|
+
export { parseTaskScope };
|
|
30
|
+
//# sourceMappingURL=command-options.js.map
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import {
|
|
2
|
+
import { parseTaskScope } from '../command-options.js';
|
|
3
|
+
import { resolveTaskContext } from '../resolve-ref.js';
|
|
3
4
|
import { resolveArtifact } from '../artifacts.js';
|
|
4
|
-
const USAGE = `Usage: ai task cat <
|
|
5
|
+
const USAGE = `Usage: ai task cat <artifact | N>
|
|
6
|
+
ai task cat (--task <ref> | -t <ref>) <artifact | N>
|
|
7
|
+
ai task cat <ref> <artifact | N>
|
|
5
8
|
|
|
6
9
|
Prints a task artifact's raw content to stdout.
|
|
7
|
-
|
|
10
|
+
One positional Uses current task context and treats the operand as the artifact.
|
|
11
|
+
<ref> Bare numeric short id, or a full TASK-YYYYMMDD-HHMMSS id.
|
|
8
12
|
<artifact | N> Artifact filename (with or without '.md'), or the number from 'ai task files'.
|
|
9
13
|
`;
|
|
10
14
|
function cat(args = []) {
|
|
@@ -12,12 +16,38 @@ function cat(args = []) {
|
|
|
12
16
|
process.stdout.write(USAGE);
|
|
13
17
|
return;
|
|
14
18
|
}
|
|
15
|
-
|
|
19
|
+
let scope;
|
|
20
|
+
try {
|
|
21
|
+
scope = parseTaskScope(args);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
process.stderr.write(`ai task cat: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
25
|
+
process.exitCode = 1;
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
let taskRef;
|
|
29
|
+
let artifact;
|
|
30
|
+
if (scope.explicit) {
|
|
31
|
+
if (scope.positionals.length !== 1) {
|
|
32
|
+
process.stdout.write(USAGE);
|
|
33
|
+
process.exitCode = 1;
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
taskRef = scope.taskRef;
|
|
37
|
+
artifact = scope.positionals[0];
|
|
38
|
+
}
|
|
39
|
+
else if (scope.positionals.length === 1) {
|
|
40
|
+
artifact = scope.positionals[0];
|
|
41
|
+
}
|
|
42
|
+
else if (scope.positionals.length === 2) {
|
|
43
|
+
[taskRef, artifact] = scope.positionals;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
16
46
|
process.stdout.write(USAGE);
|
|
17
47
|
process.exitCode = 1;
|
|
18
48
|
return;
|
|
19
49
|
}
|
|
20
|
-
const resolved =
|
|
50
|
+
const resolved = resolveTaskContext(taskRef);
|
|
21
51
|
if (!resolved.ok) {
|
|
22
52
|
process.stderr.write(`ai task cat: ${resolved.message}\n`);
|
|
23
53
|
process.exitCode = 1;
|
|
@@ -25,7 +55,7 @@ function cat(args = []) {
|
|
|
25
55
|
}
|
|
26
56
|
let artifactPath;
|
|
27
57
|
try {
|
|
28
|
-
artifactPath = resolveArtifact(resolved.taskDir,
|
|
58
|
+
artifactPath = resolveArtifact(resolved.taskDir, artifact);
|
|
29
59
|
}
|
|
30
60
|
catch (e) {
|
|
31
61
|
process.stderr.write(`ai task cat: ${e.message}\n`);
|