@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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// frontmatter, ledger, Git snapshot and platform domains are imported below.
|
|
1
2
|
import fs from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import process from "node:process";
|
|
@@ -11,13 +12,13 @@ import {
|
|
|
11
12
|
findAuthoritativeReviewCodeArtifact,
|
|
12
13
|
parseReviewVerdict,
|
|
13
14
|
resolvePostReviewGlobs
|
|
14
|
-
} from "./
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
};
|
|
15
|
+
} from "./verification-review.ts";
|
|
16
|
+
import { check as checkPlatformSync } from "../platform/verification-sync.ts";
|
|
17
|
+
import { check as checkRequiredChecks } from "../platform/verification-required.ts";
|
|
18
|
+
import { parseTypedTaskFrontmatter } from "./frontmatter.ts";
|
|
19
|
+
import { parseLedger } from "./ledger.ts";
|
|
20
|
+
import { loadVerificationConfig } from "./verification-config.ts";
|
|
21
|
+
import { snapshotReview } from "../git/review-snapshot.ts";
|
|
21
22
|
|
|
22
23
|
const TASK_ENUMS = {
|
|
23
24
|
type: ["feature", "bugfix", "refactor", "docs", "chore"],
|
|
@@ -37,7 +38,6 @@ const DEFAULT_REQUIRED_FIELDS = [
|
|
|
37
38
|
"assigned_to"
|
|
38
39
|
];
|
|
39
40
|
|
|
40
|
-
const DEFAULT_FRESHNESS_MINUTES = 30;
|
|
41
41
|
const DATE_TIME_PATTERN = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?$/;
|
|
42
42
|
const AGENT_INFRA_VERSION_PATTERN = /^v\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
43
43
|
const ACTIVITY_LOG_PATTERN = /^- (\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?) — \*\*(.+?)\*\* by (.+?) — (.+)$/;
|
|
@@ -70,25 +70,14 @@ const WORKFLOW_WARNING_SEVERITIES = new Set(["IMPORTANT", "ACTION_REQUIRED"]);
|
|
|
70
70
|
const WORKFLOW_WARNING_ID_PATTERN = /^WW-\d+$/;
|
|
71
71
|
|
|
72
72
|
const scriptPath = fileURLToPath(import.meta.url);
|
|
73
|
-
|
|
73
|
+
let repoRoot = path.resolve(path.dirname(scriptPath), "..", "..");
|
|
74
74
|
|
|
75
|
-
const PLATFORM_ADAPTERS = {
|
|
75
|
+
const PLATFORM_ADAPTERS: Record<string, (context: any, shared: any) => any> = {
|
|
76
|
+
"platform-sync": checkPlatformSync,
|
|
77
|
+
"platform-sync-preflight": (context: any, shared: any) => ({ ...checkPlatformSync(context, shared), type: "platform-sync-preflight" }),
|
|
78
|
+
"required-checks": checkRequiredChecks
|
|
79
|
+
};
|
|
76
80
|
const OPTIONAL_PLATFORM_CHECKS = new Set(["platform-sync"]);
|
|
77
|
-
const adaptersDir = path.join(path.dirname(scriptPath), "platform-adapters");
|
|
78
|
-
|
|
79
|
-
if (fs.existsSync(adaptersDir)) {
|
|
80
|
-
for (const file of fs.readdirSync(adaptersDir)) {
|
|
81
|
-
if (!file.endsWith(".js")) {
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const adapterName = path.basename(file, ".js");
|
|
86
|
-
const mod = await import(new URL(`./platform-adapters/${file}`, import.meta.url));
|
|
87
|
-
if (typeof mod.check === "function") {
|
|
88
|
-
PLATFORM_ADAPTERS[adapterName] = mod.check;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
81
|
|
|
93
82
|
const sharedUtils = {
|
|
94
83
|
loadTask,
|
|
@@ -101,125 +90,17 @@ const sharedUtils = {
|
|
|
101
90
|
blockedResult,
|
|
102
91
|
safeStat,
|
|
103
92
|
parseIssueNumber,
|
|
104
|
-
parsePrNumber
|
|
105
|
-
repoRoot
|
|
93
|
+
parsePrNumber
|
|
106
94
|
};
|
|
107
95
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
function main(argv) {
|
|
111
|
-
const [mode, ...rest] = argv;
|
|
112
|
-
|
|
113
|
-
if (mode === "gate") {
|
|
114
|
-
runGate(rest);
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (mode === "check") {
|
|
119
|
-
runSingleCheck(rest);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
printUsageAndExit();
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function runGate(args) {
|
|
127
|
-
const { value: formatValue, rest: positional } = extractOption(args, "--format");
|
|
128
|
-
const format = normalizeFormat(formatValue);
|
|
129
|
-
const [skillName, taskDirArg, artifactFile] = positional;
|
|
130
|
-
|
|
131
|
-
if (!skillName || !taskDirArg) {
|
|
132
|
-
printUsageAndExit();
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const taskDir = path.resolve(taskDirArg);
|
|
136
|
-
const verifyConfig = loadVerifyConfig(skillName);
|
|
137
|
-
const checks = [];
|
|
138
|
-
|
|
139
|
-
for (const [type, checkConfig] of Object.entries(verifyConfig.checks || {})) {
|
|
140
|
-
if (checkConfig === null) {
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const result = runCheck(type, {
|
|
145
|
-
skillName,
|
|
146
|
-
taskDir,
|
|
147
|
-
artifactFile,
|
|
148
|
-
config: checkConfig
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
checks.push(result);
|
|
152
|
-
|
|
153
|
-
if (result.status === "blocked") {
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const gate = summarizeGate(checks);
|
|
159
|
-
const output = {
|
|
160
|
-
gate,
|
|
161
|
-
skill: skillName,
|
|
162
|
-
checks,
|
|
163
|
-
summary: summarizeChecks(checks),
|
|
164
|
-
action: buildAction(gate, checks)
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
writeOutput(output, format);
|
|
168
|
-
process.exit(EXIT_CODE[gate]);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function runSingleCheck(args) {
|
|
172
|
-
const { value: formatValue, rest: formatArgs } = extractOption(args, "--format");
|
|
173
|
-
const format = normalizeFormat(formatValue);
|
|
174
|
-
const { value: skillName, rest: positional } = extractOption(formatArgs, "--skill");
|
|
175
|
-
|
|
176
|
-
if (!skillName) {
|
|
177
|
-
printUsageAndExit();
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const [type, taskDirArg, artifactFile] = positional;
|
|
181
|
-
|
|
182
|
-
if (!type || !taskDirArg) {
|
|
183
|
-
printUsageAndExit();
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const verifyConfig = loadVerifyConfig(skillName);
|
|
187
|
-
const config = (verifyConfig.checks || {})[type];
|
|
188
|
-
|
|
189
|
-
if (config === undefined) {
|
|
190
|
-
failUsage(`Unknown check type '${type}' for skill '${skillName}'.`);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (config === null) {
|
|
194
|
-
writeOutput({
|
|
195
|
-
type,
|
|
196
|
-
skill: skillName,
|
|
197
|
-
status: "pass",
|
|
198
|
-
message: `Check '${type}' is disabled for skill '${skillName}'.`
|
|
199
|
-
}, format);
|
|
200
|
-
process.exit(0);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const result = runCheck(type, {
|
|
204
|
-
skillName,
|
|
205
|
-
taskDir: path.resolve(taskDirArg),
|
|
206
|
-
artifactFile,
|
|
207
|
-
config
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
writeOutput({
|
|
211
|
-
skill: skillName,
|
|
212
|
-
...result
|
|
213
|
-
}, format);
|
|
214
|
-
process.exit(EXIT_CODE[result.status] ?? 1);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
function runCheck(type, context) {
|
|
96
|
+
function runCheck(type: any, context: any, shared: any): any {
|
|
218
97
|
switch (type) {
|
|
219
98
|
case "task-meta":
|
|
220
99
|
return checkTaskMeta(context);
|
|
221
100
|
case "artifact":
|
|
222
101
|
return checkArtifact(context);
|
|
102
|
+
case "implementation-input":
|
|
103
|
+
return checkImplementationInput(context);
|
|
223
104
|
case "activity-log":
|
|
224
105
|
return checkActivityLog(context);
|
|
225
106
|
case "completion-checklist":
|
|
@@ -240,14 +121,14 @@ function runCheck(type, context) {
|
|
|
240
121
|
return failResult(type, `Unsupported check type '${type}'.`);
|
|
241
122
|
}
|
|
242
123
|
|
|
243
|
-
return adapter(context,
|
|
124
|
+
return adapter(context, shared);
|
|
244
125
|
}
|
|
245
126
|
}
|
|
246
127
|
}
|
|
247
128
|
|
|
248
129
|
// === Check Functions ===
|
|
249
130
|
|
|
250
|
-
function checkTaskMeta({ taskDir, config }) {
|
|
131
|
+
function checkTaskMeta({ taskDir, config }: any): any {
|
|
251
132
|
const task = loadTask(taskDir);
|
|
252
133
|
if (!task.ok) {
|
|
253
134
|
return failResult("task-meta", task.message);
|
|
@@ -255,8 +136,8 @@ function checkTaskMeta({ taskDir, config }) {
|
|
|
255
136
|
|
|
256
137
|
const metadata = task.metadata;
|
|
257
138
|
const requiredFields = config.required_fields || DEFAULT_REQUIRED_FIELDS;
|
|
258
|
-
const missingFields = requiredFields.filter((field) => isBlank(metadata[field]));
|
|
259
|
-
const blockingMissingFields = missingFields.filter((field) => field !== "agent_infra_version");
|
|
139
|
+
const missingFields = requiredFields.filter((field: any) => isBlank(metadata[field]));
|
|
140
|
+
const blockingMissingFields = missingFields.filter((field: any) => field !== "agent_infra_version");
|
|
260
141
|
const warnings = [];
|
|
261
142
|
if (missingFields.includes("agent_infra_version")) {
|
|
262
143
|
warnings.push("field 'agent_infra_version' missing — historical task or skipped version stamp");
|
|
@@ -349,11 +230,11 @@ function checkTaskMeta({ taskDir, config }) {
|
|
|
349
230
|
return passResult(
|
|
350
231
|
"task-meta",
|
|
351
232
|
`Task metadata valid (${requiredFields.length} required fields checked${warningSuffix})`,
|
|
352
|
-
warnings
|
|
233
|
+
warnings as string[]
|
|
353
234
|
);
|
|
354
235
|
}
|
|
355
236
|
|
|
356
|
-
function validateTaskBranch(metadata) {
|
|
237
|
+
function validateTaskBranch(metadata: any): any {
|
|
357
238
|
if (isBlank(metadata.branch)) {
|
|
358
239
|
return null;
|
|
359
240
|
}
|
|
@@ -373,7 +254,7 @@ function validateTaskBranch(metadata) {
|
|
|
373
254
|
return null;
|
|
374
255
|
}
|
|
375
256
|
|
|
376
|
-
function loadProjectName() {
|
|
257
|
+
function loadProjectName(): any {
|
|
377
258
|
const configPath = path.join(repoRoot, ".agents", ".airc.json");
|
|
378
259
|
if (!fs.existsSync(configPath)) {
|
|
379
260
|
return "";
|
|
@@ -387,7 +268,7 @@ function loadProjectName() {
|
|
|
387
268
|
}
|
|
388
269
|
}
|
|
389
270
|
|
|
390
|
-
function loadReviewConfig() {
|
|
271
|
+
function loadReviewConfig(): any {
|
|
391
272
|
const configPath = path.join(repoRoot, ".agents", ".airc.json");
|
|
392
273
|
if (!fs.existsSync(configPath)) {
|
|
393
274
|
return {};
|
|
@@ -401,7 +282,7 @@ function loadReviewConfig() {
|
|
|
401
282
|
}
|
|
402
283
|
}
|
|
403
284
|
|
|
404
|
-
function checkArtifact({ taskDir, config, artifactFile }) {
|
|
285
|
+
function checkArtifact({ taskDir, config, artifactFile }: any): any {
|
|
405
286
|
const resolvedArtifact = resolveArtifactPath(taskDir, config.file_pattern, artifactFile);
|
|
406
287
|
if (!resolvedArtifact.ok) {
|
|
407
288
|
return failResult("artifact", resolvedArtifact.message);
|
|
@@ -420,7 +301,7 @@ function checkArtifact({ taskDir, config, artifactFile }) {
|
|
|
420
301
|
const content = fs.readFileSync(artifactPath, "utf8");
|
|
421
302
|
const requiredSections = config.required_sections || [];
|
|
422
303
|
const missingSections = requiredSections.filter(
|
|
423
|
-
(section) => !new RegExp(`^##\\s+${escapeRegExp(section)}\\s*$`, "m").test(content)
|
|
304
|
+
(section: any) => !new RegExp(`^##\\s+${escapeRegExp(section)}\\s*$`, "m").test(content)
|
|
424
305
|
);
|
|
425
306
|
|
|
426
307
|
if (missingSections.length > 0) {
|
|
@@ -437,22 +318,80 @@ function checkArtifact({ taskDir, config, artifactFile }) {
|
|
|
437
318
|
}
|
|
438
319
|
}
|
|
439
320
|
|
|
440
|
-
const freshnessMinutes = Number(config.freshness_minutes ?? DEFAULT_FRESHNESS_MINUTES);
|
|
441
|
-
const ageMinutes = (Date.now() - stat.mtimeMs) / 60000;
|
|
442
|
-
if (Number.isFinite(freshnessMinutes) && ageMinutes > freshnessMinutes) {
|
|
443
|
-
return failResult(
|
|
444
|
-
"artifact",
|
|
445
|
-
`${path.basename(artifactPath)} is stale (${ageMinutes.toFixed(1)}m old, limit ${freshnessMinutes}m)`
|
|
446
|
-
);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
321
|
return passResult(
|
|
450
322
|
"artifact",
|
|
451
|
-
`${path.basename(artifactPath)} passed (${requiredSections.length} sections
|
|
323
|
+
`${path.basename(artifactPath)} passed (${requiredSections.length} sections)`
|
|
452
324
|
);
|
|
453
325
|
}
|
|
454
326
|
|
|
455
|
-
function
|
|
327
|
+
function checkImplementationInput({ taskDir, artifactFile }: any): any {
|
|
328
|
+
const task = loadTask(taskDir);
|
|
329
|
+
if (!task.ok) return failResult("implementation-input", task.message);
|
|
330
|
+
if (!artifactFile) return failResult("implementation-input", "Artifact file is required");
|
|
331
|
+
const artifactPath = path.join(taskDir, artifactFile);
|
|
332
|
+
if (!safeStat(artifactPath)?.isFile()) return failResult("implementation-input", `Artifact not found: ${artifactFile}`);
|
|
333
|
+
|
|
334
|
+
const inputSection = getSectionContent(task.content, ["实现输入", "Implementation Inputs"]);
|
|
335
|
+
const rows = [];
|
|
336
|
+
if (inputSection) {
|
|
337
|
+
const table = inputSection.split(/\r?\n/).filter((line: any) => line.trim().startsWith("|"));
|
|
338
|
+
const cells = (line: any) => line.split("|").slice(1, -1).map((cell: any) => cell.trim());
|
|
339
|
+
const expected = ["id", "ledger_id", "decision_evidence", "stage", "needs_implementation", "decided_at", "status", "consumed_by"];
|
|
340
|
+
if (table.length < 2 || JSON.stringify(cells(table[0])) !== JSON.stringify(expected)) {
|
|
341
|
+
return failResult("implementation-input", "Implementation Inputs table schema is invalid");
|
|
342
|
+
}
|
|
343
|
+
const seen = new Set();
|
|
344
|
+
for (const line of table.slice(2)) {
|
|
345
|
+
const row = cells(line);
|
|
346
|
+
if (row.length !== 8 || !/^II-[1-9]\d*$/.test(row[0]) || seen.has(row[0])) {
|
|
347
|
+
return failResult("implementation-input", "Implementation Inputs table contains an invalid or duplicate id");
|
|
348
|
+
}
|
|
349
|
+
seen.add(row[0]);
|
|
350
|
+
rows.push({ id: row[0], ledgerId: row[1], evidence: row[2], stage: row[3], needs: row[4], status: row[6], consumedBy: row[7] });
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const logSection = getSectionContent(task.content, ["活动日志", "Activity Log"]);
|
|
355
|
+
const doneActions = logSection.split(/\r?\n/).flatMap((line: any) => {
|
|
356
|
+
const match = line.trim().match(ACTIVITY_LOG_PATTERN);
|
|
357
|
+
return match && !ACTIVITY_LOG_STARTED_RE.test(match[2]) ? [match[2]] : [];
|
|
358
|
+
});
|
|
359
|
+
const latestAction = doneActions.at(-1) || "";
|
|
360
|
+
const actionDecision = /(?:Code Task|Code) \(Round \d+, decision (II-[1-9]\d*)\)/.exec(latestAction)?.[1] || null;
|
|
361
|
+
const report = fs.readFileSync(artifactPath, "utf8");
|
|
362
|
+
const reportSection = getSectionContent(report, ["实现输入", "Implementation Input"]);
|
|
363
|
+
if (!reportSection) return failResult("implementation-input", "Implementation Input report section not found");
|
|
364
|
+
const field = (zh: any, en: any) => {
|
|
365
|
+
const pattern = "^- \\*\\*(?:" + escapeRegExp(zh) + "|" + escapeRegExp(en) + ")\\*\\*[::]\\s*`?([^`\\n]+)`?\\s*$";
|
|
366
|
+
const match = new RegExp(pattern, "m").exec(reportSection);
|
|
367
|
+
return match?.[1]?.trim() || "";
|
|
368
|
+
};
|
|
369
|
+
const reportInput = field("裁决输入", "Decision Input");
|
|
370
|
+
const reportLedger = field("账本 ID", "Ledger ID");
|
|
371
|
+
const reportEvidence = field("裁决证据", "Decision Evidence");
|
|
372
|
+
|
|
373
|
+
if (!actionDecision) {
|
|
374
|
+
if (reportInput && reportInput !== "N/A") {
|
|
375
|
+
return failResult("implementation-input", "Non-decision code action must report Decision Input as N/A");
|
|
376
|
+
}
|
|
377
|
+
return passResult("implementation-input", "Non-decision implementation input identity is consistent");
|
|
378
|
+
}
|
|
379
|
+
if (reportInput !== actionDecision) {
|
|
380
|
+
return failResult("implementation-input", `Report decision input '${reportInput}' does not match Activity Log ${actionDecision}`);
|
|
381
|
+
}
|
|
382
|
+
const matches = rows.filter((row) => row.id === actionDecision);
|
|
383
|
+
if (matches.length !== 1) return failResult("implementation-input", `${actionDecision} is missing or duplicated in task table`);
|
|
384
|
+
const row = matches[0]!;
|
|
385
|
+
if (row.stage !== "code" || row.needs !== "true" || row.status !== "consumed" || row.consumedBy !== artifactFile || !row.evidence) {
|
|
386
|
+
return failResult("implementation-input", `${actionDecision} is not a consumed input for ${artifactFile}`);
|
|
387
|
+
}
|
|
388
|
+
if (reportLedger !== row.ledgerId || reportEvidence !== row.evidence) {
|
|
389
|
+
return failResult("implementation-input", `${actionDecision} report identity does not match task table evidence`);
|
|
390
|
+
}
|
|
391
|
+
return passResult("implementation-input", `${actionDecision} matches Activity Log, report, and task table`);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function checkActivityLog({ taskDir, config }: any): any {
|
|
456
395
|
const task = loadTask(taskDir);
|
|
457
396
|
if (!task.ok) {
|
|
458
397
|
return failResult("activity-log", task.message);
|
|
@@ -465,8 +404,8 @@ function checkActivityLog({ taskDir, config }) {
|
|
|
465
404
|
|
|
466
405
|
const entries = logSection
|
|
467
406
|
.split(/\r?\n/)
|
|
468
|
-
.map((line) => line.trim())
|
|
469
|
-
.filter((line) => line.startsWith("- "));
|
|
407
|
+
.map((line: any) => line.trim())
|
|
408
|
+
.filter((line: any) => line.startsWith("- "));
|
|
470
409
|
|
|
471
410
|
if (entries.length === 0) {
|
|
472
411
|
return failResult("activity-log", "Activity Log has no entries");
|
|
@@ -490,7 +429,7 @@ function checkActivityLog({ taskDir, config }) {
|
|
|
490
429
|
previousTimestamp = timestamp;
|
|
491
430
|
// Ascending order is checked over every entry, but a `[started]` marker is
|
|
492
431
|
// not a terminal action: keep latestAction/latestTimestamp on the most
|
|
493
|
-
// recent done entry so expected_action_pattern
|
|
432
|
+
// recent done entry so expected_action_pattern sees it.
|
|
494
433
|
if (!ACTIVITY_LOG_STARTED_RE.test(action)) {
|
|
495
434
|
latestTimestamp = timestamp;
|
|
496
435
|
latestAction = action;
|
|
@@ -504,21 +443,10 @@ function checkActivityLog({ taskDir, config }) {
|
|
|
504
443
|
);
|
|
505
444
|
}
|
|
506
445
|
|
|
507
|
-
const freshnessMinutes = Number(config.freshness_minutes ?? DEFAULT_FRESHNESS_MINUTES);
|
|
508
|
-
if (Number.isFinite(freshnessMinutes)) {
|
|
509
|
-
const ageMinutes = minutesSinceTimestamp(latestTimestamp);
|
|
510
|
-
if (ageMinutes > freshnessMinutes) {
|
|
511
|
-
return failResult(
|
|
512
|
-
"activity-log",
|
|
513
|
-
`Latest Activity Log entry is stale (${ageMinutes.toFixed(1)}m old, limit ${freshnessMinutes}m)`
|
|
514
|
-
);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
446
|
return passResult("activity-log", `Latest entry '${latestAction}' at ${latestTimestamp}`);
|
|
519
447
|
}
|
|
520
448
|
|
|
521
|
-
function checkCompletionChecklist({ taskDir, config }) {
|
|
449
|
+
function checkCompletionChecklist({ taskDir, config }: any): any {
|
|
522
450
|
const task = loadTask(taskDir);
|
|
523
451
|
if (!task.ok) {
|
|
524
452
|
return failResult("completion-checklist", task.message);
|
|
@@ -531,8 +459,8 @@ function checkCompletionChecklist({ taskDir, config }) {
|
|
|
531
459
|
|
|
532
460
|
const items = checklist
|
|
533
461
|
.split(/\r?\n/)
|
|
534
|
-
.map((line) => line.trim())
|
|
535
|
-
.filter((line) => /^- \[(?: |x|X)\] .+$/.test(line));
|
|
462
|
+
.map((line: any) => line.trim())
|
|
463
|
+
.filter((line: any) => /^- \[(?: |x|X)\] .+$/.test(line));
|
|
536
464
|
|
|
537
465
|
if (items.length === 0) {
|
|
538
466
|
return failResult("completion-checklist", "Completion Checklist has no checkbox items");
|
|
@@ -540,9 +468,9 @@ function checkCompletionChecklist({ taskDir, config }) {
|
|
|
540
468
|
|
|
541
469
|
if (config.require_all_checked) {
|
|
542
470
|
const unchecked = items
|
|
543
|
-
.map((line) => line.match(/^- \[ \] (.+)$/))
|
|
471
|
+
.map((line: any) => line.match(/^- \[ \] (.+)$/))
|
|
544
472
|
.filter(Boolean)
|
|
545
|
-
.map((match) => match[1].trim());
|
|
473
|
+
.map((match: any) => match[1].trim());
|
|
546
474
|
|
|
547
475
|
if (unchecked.length > 0) {
|
|
548
476
|
return failResult(
|
|
@@ -555,27 +483,7 @@ function checkCompletionChecklist({ taskDir, config }) {
|
|
|
555
483
|
return passResult("completion-checklist", `Completion Checklist valid (${items.length} items checked)`);
|
|
556
484
|
}
|
|
557
485
|
|
|
558
|
-
function
|
|
559
|
-
const rows = [];
|
|
560
|
-
for (const rawLine of String(section || "").split(/\r?\n/)) {
|
|
561
|
-
const line = rawLine.trim();
|
|
562
|
-
if (!line.startsWith("|")) {
|
|
563
|
-
continue;
|
|
564
|
-
}
|
|
565
|
-
if (/^\|[\s:|-]+\|?$/.test(line)) {
|
|
566
|
-
continue; // separator row
|
|
567
|
-
}
|
|
568
|
-
const inner = line.replace(/^\|/, "").replace(/\|$/, "");
|
|
569
|
-
const cells = inner.split("|").map((cell) => cell.trim());
|
|
570
|
-
if ((cells[0] || "").toLowerCase() === "id") {
|
|
571
|
-
continue; // header row
|
|
572
|
-
}
|
|
573
|
-
rows.push(cells);
|
|
574
|
-
}
|
|
575
|
-
return rows;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
function splitMarkdownTableRow(line) {
|
|
486
|
+
function splitMarkdownTableRow(line: any): any {
|
|
579
487
|
let value = String(line || "").trim();
|
|
580
488
|
if (!value.startsWith("|")) {
|
|
581
489
|
return [];
|
|
@@ -597,7 +505,7 @@ function splitMarkdownTableRow(line) {
|
|
|
597
505
|
return cells;
|
|
598
506
|
}
|
|
599
507
|
|
|
600
|
-
function unescapeMarkdownTableCell(value) {
|
|
508
|
+
function unescapeMarkdownTableCell(value: any): any {
|
|
601
509
|
let output = "";
|
|
602
510
|
for (let index = 0; index < value.length; index += 1) {
|
|
603
511
|
const char = value[index];
|
|
@@ -612,7 +520,7 @@ function unescapeMarkdownTableCell(value) {
|
|
|
612
520
|
return output;
|
|
613
521
|
}
|
|
614
522
|
|
|
615
|
-
function isEscapedAt(value, index) {
|
|
523
|
+
function isEscapedAt(value: any, index: any): any {
|
|
616
524
|
let backslashes = 0;
|
|
617
525
|
for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
|
|
618
526
|
backslashes += 1;
|
|
@@ -620,7 +528,7 @@ function isEscapedAt(value, index) {
|
|
|
620
528
|
return backslashes % 2 === 1;
|
|
621
529
|
}
|
|
622
530
|
|
|
623
|
-
function parseWorkflowWarningRows(section) {
|
|
531
|
+
function parseWorkflowWarningRows(section: any): any {
|
|
624
532
|
const rows = [];
|
|
625
533
|
for (const rawLine of String(section || "").split(/\r?\n/)) {
|
|
626
534
|
const cells = splitMarkdownTableRow(rawLine);
|
|
@@ -630,7 +538,7 @@ function parseWorkflowWarningRows(section) {
|
|
|
630
538
|
if ((cells[0] || "").toLowerCase() === "id") {
|
|
631
539
|
continue;
|
|
632
540
|
}
|
|
633
|
-
if (cells.every((cell) => /^:?-{3,}:?$/.test(cell))) {
|
|
541
|
+
if (cells.every((cell: any) => /^:?-{3,}:?$/.test(cell))) {
|
|
634
542
|
continue;
|
|
635
543
|
}
|
|
636
544
|
rows.push(cells);
|
|
@@ -638,7 +546,7 @@ function parseWorkflowWarningRows(section) {
|
|
|
638
546
|
return rows;
|
|
639
547
|
}
|
|
640
548
|
|
|
641
|
-
function validateWorkflowWarnings(content) {
|
|
549
|
+
function validateWorkflowWarnings(content: any): any {
|
|
642
550
|
const section = getSectionContent(content, WORKFLOW_WARNING_SECTION_NAMES);
|
|
643
551
|
if (!section.trim()) {
|
|
644
552
|
return [];
|
|
@@ -686,7 +594,7 @@ function validateWorkflowWarnings(content) {
|
|
|
686
594
|
return errors;
|
|
687
595
|
}
|
|
688
596
|
|
|
689
|
-
function resolveReviewSetting(config, key, fallback) {
|
|
597
|
+
function resolveReviewSetting(config: any, key: any, fallback: any): any {
|
|
690
598
|
if (config && config[key] !== undefined && config[key] !== null) {
|
|
691
599
|
return config[key];
|
|
692
600
|
}
|
|
@@ -697,7 +605,7 @@ function resolveReviewSetting(config, key, fallback) {
|
|
|
697
605
|
return fallback;
|
|
698
606
|
}
|
|
699
607
|
|
|
700
|
-
function checkReviewLedger({ taskDir, config }) {
|
|
608
|
+
function checkReviewLedger({ taskDir, config }: any): any {
|
|
701
609
|
const task = loadTask(taskDir);
|
|
702
610
|
if (!task.ok) {
|
|
703
611
|
return failResult("review-ledger", task.message);
|
|
@@ -708,7 +616,14 @@ function checkReviewLedger({ taskDir, config }) {
|
|
|
708
616
|
return passResult("review-ledger", "No disagreement ledger section; treated as no open disagreements");
|
|
709
617
|
}
|
|
710
618
|
|
|
711
|
-
|
|
619
|
+
let rows;
|
|
620
|
+
try {
|
|
621
|
+
rows = parseLedger(task.content).map((row) => [
|
|
622
|
+
row.id, row.stage, row.round, row.severity, row.status, row.evidence
|
|
623
|
+
]);
|
|
624
|
+
} catch (error) {
|
|
625
|
+
return failResult("review-ledger", `Invalid disagreement ledger: ${error instanceof Error ? error.message : String(error)}`);
|
|
626
|
+
}
|
|
712
627
|
if (rows.length === 0) {
|
|
713
628
|
return passResult("review-ledger", "Disagreement ledger has no entries");
|
|
714
629
|
}
|
|
@@ -736,23 +651,23 @@ function checkReviewLedger({ taskDir, config }) {
|
|
|
736
651
|
}
|
|
737
652
|
inScopeCount += 1;
|
|
738
653
|
|
|
739
|
-
if (!LEDGER_STATUSES.has(status)) {
|
|
654
|
+
if (!LEDGER_STATUSES.has(status!)) {
|
|
740
655
|
problems.push(`${id}: illegal status '${status}'`);
|
|
741
656
|
continue;
|
|
742
657
|
}
|
|
743
658
|
if (status !== "open" && evidence === "") {
|
|
744
659
|
problems.push(`${id}: status '${status}' requires evidence`);
|
|
745
660
|
}
|
|
746
|
-
const round = Number.parseInt(roundRaw
|
|
661
|
+
const round = Number.parseInt(roundRaw!, 10);
|
|
747
662
|
if (
|
|
748
663
|
Number.isFinite(round) &&
|
|
749
664
|
round >= maxRounds &&
|
|
750
|
-
!LEDGER_TERMINAL_OK.has(status) &&
|
|
665
|
+
!LEDGER_TERMINAL_OK.has(status!) &&
|
|
751
666
|
status !== "needs-human-decision"
|
|
752
667
|
) {
|
|
753
668
|
problems.push(`${id}: round ${round} reached limit ${maxRounds} without convergence; escalate to needs-human-decision`);
|
|
754
669
|
}
|
|
755
|
-
if (!LEDGER_TERMINAL_OK.has(status)) {
|
|
670
|
+
if (!LEDGER_TERMINAL_OK.has(status!)) {
|
|
756
671
|
problems.push(`${id}: unresolved (status '${status}')`);
|
|
757
672
|
}
|
|
758
673
|
}
|
|
@@ -765,7 +680,7 @@ function checkReviewLedger({ taskDir, config }) {
|
|
|
765
680
|
return passResult("review-ledger", `Disagreement ledger clean (${inScopeCount} in-scope entries terminal${scopeLabel})`);
|
|
766
681
|
}
|
|
767
682
|
|
|
768
|
-
function checkPostReviewCommit({ taskDir, config }) {
|
|
683
|
+
function checkPostReviewCommit({ taskDir, config }: any): any {
|
|
769
684
|
const reviewArtifact = findAuthoritativeReviewCodeArtifact(taskDir);
|
|
770
685
|
if (!reviewArtifact.ok) {
|
|
771
686
|
return passResult("post-review-commit", "No review-code artifact; check inactive");
|
|
@@ -779,7 +694,7 @@ function checkPostReviewCommit({ taskDir, config }) {
|
|
|
779
694
|
}
|
|
780
695
|
|
|
781
696
|
const task = loadTask(taskDir);
|
|
782
|
-
const content = fs.readFileSync(reviewArtifact.path
|
|
697
|
+
const content = fs.readFileSync(reviewArtifact.path!, "utf8");
|
|
783
698
|
const lastReviewedCommit = task.ok ? (task.metadata.last_reviewed_commit || "").trim() : "";
|
|
784
699
|
const baselineSource = resolvePostReviewBaseline({
|
|
785
700
|
gitRoot,
|
|
@@ -804,10 +719,14 @@ function checkPostReviewCommit({ taskDir, config }) {
|
|
|
804
719
|
return passResult("post-review-commit", `No post-review commits to code/rule paths since ${sha.slice(0, 8)}`);
|
|
805
720
|
}
|
|
806
721
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
722
|
+
let exempt = false;
|
|
723
|
+
try {
|
|
724
|
+
exempt = task.ok && parseLedger(task.content).some(
|
|
725
|
+
(row) => row.stage === POST_REVIEW_COMMIT_STAGE && row.status === "human-decided"
|
|
726
|
+
);
|
|
727
|
+
} catch {
|
|
728
|
+
return failResult("post-review-commit", "Invalid disagreement ledger");
|
|
729
|
+
}
|
|
811
730
|
if (exempt) {
|
|
812
731
|
return passResult(
|
|
813
732
|
"post-review-commit",
|
|
@@ -821,7 +740,7 @@ function checkPostReviewCommit({ taskDir, config }) {
|
|
|
821
740
|
);
|
|
822
741
|
}
|
|
823
742
|
|
|
824
|
-
function checkReviewFact({ taskDir, artifactFile }) {
|
|
743
|
+
function checkReviewFact({ taskDir, artifactFile }: any): any {
|
|
825
744
|
const resolvedArtifact = resolveArtifactPath(
|
|
826
745
|
taskDir,
|
|
827
746
|
"review-code.md|review-code-r{N}.md",
|
|
@@ -869,11 +788,7 @@ function checkReviewFact({ taskDir, artifactFile }) {
|
|
|
869
788
|
|
|
870
789
|
let actualSnapshot;
|
|
871
790
|
try {
|
|
872
|
-
actualSnapshot =
|
|
873
|
-
process.execPath,
|
|
874
|
-
[path.join(repoRoot, ".agents", "scripts", "review-diff-fingerprint.js"), "worktree", baseline, "--format", "json"],
|
|
875
|
-
{ cwd: gitRoot, encoding: "utf8" }
|
|
876
|
-
));
|
|
791
|
+
actualSnapshot = snapshotReview({ cwd: gitRoot, mode: "worktree", baseline, globs: resolvePostReviewGlobs({}, loadReviewConfig()) });
|
|
877
792
|
} catch {
|
|
878
793
|
return blockedResult(
|
|
879
794
|
"review-fact",
|
|
@@ -922,7 +837,7 @@ function checkReviewFact({ taskDir, artifactFile }) {
|
|
|
922
837
|
);
|
|
923
838
|
}
|
|
924
839
|
|
|
925
|
-
function resolvePostReviewBaseline({ gitRoot, lastReviewedCommit, reviewArtifact }) {
|
|
840
|
+
function resolvePostReviewBaseline({ gitRoot, lastReviewedCommit, reviewArtifact }: any): any {
|
|
926
841
|
if (SHA_PATTERN.test(lastReviewedCommit) && gitCommitExists(gitRoot, lastReviewedCommit)) {
|
|
927
842
|
return { ok: true, sha: lastReviewedCommit };
|
|
928
843
|
}
|
|
@@ -936,7 +851,7 @@ function resolvePostReviewBaseline({ gitRoot, lastReviewedCommit, reviewArtifact
|
|
|
936
851
|
};
|
|
937
852
|
}
|
|
938
853
|
|
|
939
|
-
function gitCommitExists(gitRoot, sha) {
|
|
854
|
+
function gitCommitExists(gitRoot: any, sha: any): any {
|
|
940
855
|
try {
|
|
941
856
|
execFileSync("git", ["-C", gitRoot, "cat-file", "-e", `${sha}^{commit}`], { encoding: "utf8" });
|
|
942
857
|
return true;
|
|
@@ -947,31 +862,24 @@ function gitCommitExists(gitRoot, sha) {
|
|
|
947
862
|
|
|
948
863
|
// === File & Config Loaders ===
|
|
949
864
|
|
|
950
|
-
function
|
|
951
|
-
const verifyPath = path.join(repoRoot, ".agents", "skills", skillName, "config", "verify.json");
|
|
952
|
-
if (!fs.existsSync(verifyPath)) {
|
|
953
|
-
failUsage(`config/verify.json not found for skill '${skillName}'`);
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
return JSON.parse(fs.readFileSync(verifyPath, "utf8"));
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
function loadTask(taskDir) {
|
|
865
|
+
function loadTask(taskDir: any): any {
|
|
960
866
|
const taskPath = path.join(taskDir, "task.md");
|
|
961
867
|
if (!fs.existsSync(taskPath)) {
|
|
962
868
|
return { ok: false, message: `Task file not found: ${taskPath}` };
|
|
963
869
|
}
|
|
964
870
|
|
|
965
871
|
const content = fs.readFileSync(taskPath, "utf8");
|
|
966
|
-
|
|
967
|
-
|
|
872
|
+
let metadata;
|
|
873
|
+
try {
|
|
874
|
+
metadata = Object.fromEntries(Object.entries(parseTypedTaskFrontmatter(content)).map(([key, value]) => [key, value === null ? "" : String(value)]));
|
|
875
|
+
} catch {
|
|
968
876
|
return { ok: false, message: "task.md frontmatter not found or invalid" };
|
|
969
877
|
}
|
|
970
878
|
|
|
971
879
|
return { ok: true, content, metadata };
|
|
972
880
|
}
|
|
973
881
|
|
|
974
|
-
function resolveArtifactPath(taskDir, filePattern, artifactFile) {
|
|
882
|
+
function resolveArtifactPath(taskDir: any, filePattern: any, artifactFile: any): any {
|
|
975
883
|
if (artifactFile) {
|
|
976
884
|
return { ok: true, path: path.join(taskDir, artifactFile) };
|
|
977
885
|
}
|
|
@@ -983,7 +891,7 @@ function resolveArtifactPath(taskDir, filePattern, artifactFile) {
|
|
|
983
891
|
const entries = fs.existsSync(taskDir) ? fs.readdirSync(taskDir) : [];
|
|
984
892
|
const matches = [];
|
|
985
893
|
|
|
986
|
-
for (const pattern of filePattern.split("|").map((value) => value.trim()).filter(Boolean)) {
|
|
894
|
+
for (const pattern of filePattern.split("|").map((value: any) => value.trim()).filter(Boolean)) {
|
|
987
895
|
const regex = new RegExp(`^${escapePattern(pattern)}$`);
|
|
988
896
|
for (const entry of entries) {
|
|
989
897
|
const match = entry.match(regex);
|
|
@@ -1003,33 +911,13 @@ function resolveArtifactPath(taskDir, filePattern, artifactFile) {
|
|
|
1003
911
|
}
|
|
1004
912
|
|
|
1005
913
|
matches.sort((left, right) => right.round - left.round || left.fileName.localeCompare(right.fileName));
|
|
1006
|
-
return { ok: true, path: path.join(taskDir, matches[0]
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
|
-
function parseFrontmatter(content) {
|
|
1010
|
-
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
|
1011
|
-
if (!match) {
|
|
1012
|
-
return null;
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
const metadata = {};
|
|
1016
|
-
for (const line of match[1].split(/\r?\n/)) {
|
|
1017
|
-
const parsed = line.match(/^([A-Za-z0-9_]+):\s*(.*)$/);
|
|
1018
|
-
if (!parsed) {
|
|
1019
|
-
continue;
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
|
-
const [, key, rawValue] = parsed;
|
|
1023
|
-
metadata[key] = rawValue.trim().replace(/^['"]|['"]$/g, "");
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
return metadata;
|
|
914
|
+
return { ok: true, path: path.join(taskDir, matches[0]!.fileName) };
|
|
1027
915
|
}
|
|
1028
916
|
|
|
1029
|
-
function getSectionContent(content, names) {
|
|
917
|
+
function getSectionContent(content: any, names: any): any {
|
|
1030
918
|
const lines = content.split(/\r?\n/);
|
|
1031
919
|
|
|
1032
|
-
function visibleHeadings() {
|
|
920
|
+
function visibleHeadings(): any {
|
|
1033
921
|
const headings = [];
|
|
1034
922
|
let fence = null;
|
|
1035
923
|
for (let index = 0; index < lines.length; index += 1) {
|
|
@@ -1057,11 +945,11 @@ function getSectionContent(content, names) {
|
|
|
1057
945
|
|
|
1058
946
|
for (const name of names) {
|
|
1059
947
|
const heading = `## ${name}`;
|
|
1060
|
-
const position = headings.findIndex((item) => item.text === heading);
|
|
948
|
+
const position = headings.findIndex((item: any) => item.text === heading);
|
|
1061
949
|
if (position === -1) {
|
|
1062
950
|
continue;
|
|
1063
951
|
}
|
|
1064
|
-
const startIndex = headings[position]
|
|
952
|
+
const startIndex = headings[position]!.index;
|
|
1065
953
|
const endIndex = headings[position + 1]?.index ?? lines.length;
|
|
1066
954
|
return lines.slice(startIndex + 1, endIndex).join("\n").trim();
|
|
1067
955
|
}
|
|
@@ -1069,7 +957,7 @@ function getSectionContent(content, names) {
|
|
|
1069
957
|
return "";
|
|
1070
958
|
}
|
|
1071
959
|
|
|
1072
|
-
function getCheckedRequirements(content) {
|
|
960
|
+
function getCheckedRequirements(content: any): any {
|
|
1073
961
|
const section = getSectionContent(content, ["需求", "Requirements"]);
|
|
1074
962
|
if (!section) {
|
|
1075
963
|
return [];
|
|
@@ -1077,13 +965,13 @@ function getCheckedRequirements(content) {
|
|
|
1077
965
|
|
|
1078
966
|
return section
|
|
1079
967
|
.split(/\r?\n/)
|
|
1080
|
-
.map((line) => line.trim())
|
|
1081
|
-
.map((line) => line.match(/^- \[x\] (.+)$/i))
|
|
968
|
+
.map((line: any) => line.trim())
|
|
969
|
+
.map((line: any) => line.match(/^- \[x\] (.+)$/i))
|
|
1082
970
|
.filter(Boolean)
|
|
1083
|
-
.map((match) => match[1].trim());
|
|
971
|
+
.map((match: any) => match[1].trim());
|
|
1084
972
|
}
|
|
1085
973
|
|
|
1086
|
-
function parseIssueNumber(value) {
|
|
974
|
+
function parseIssueNumber(value: any): any {
|
|
1087
975
|
if (isBlank(value) || value === "N/A") {
|
|
1088
976
|
return null;
|
|
1089
977
|
}
|
|
@@ -1092,53 +980,43 @@ function parseIssueNumber(value) {
|
|
|
1092
980
|
return match ? Number(match[0]) : null;
|
|
1093
981
|
}
|
|
1094
982
|
|
|
1095
|
-
function parsePrNumber(value) {
|
|
983
|
+
function parsePrNumber(value: any): any {
|
|
1096
984
|
return parseIssueNumber(value);
|
|
1097
985
|
}
|
|
1098
986
|
|
|
1099
987
|
// === Utilities ===
|
|
1100
988
|
|
|
1101
|
-
function normalizeContent(text) {
|
|
989
|
+
function normalizeContent(text: any): any {
|
|
1102
990
|
return String(text || "")
|
|
1103
991
|
.replace(/\r\n/g, "\n")
|
|
1104
992
|
.replace(/\n{3,}/g, "\n\n")
|
|
1105
993
|
.trim();
|
|
1106
994
|
}
|
|
1107
995
|
|
|
1108
|
-
function
|
|
1109
|
-
const normalized = timestamp.includes("T") ? timestamp : timestamp.replace(" ", "T");
|
|
1110
|
-
const parsed = Date.parse(normalized);
|
|
1111
|
-
if (Number.isNaN(parsed)) {
|
|
1112
|
-
return Number.POSITIVE_INFINITY;
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
return (Date.now() - parsed) / 60000;
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
function interpolate(template, taskDir, artifactFile) {
|
|
996
|
+
function interpolate(template: any, taskDir: any, artifactFile: any): any {
|
|
1119
997
|
const artifactStem = artifactFile ? path.basename(artifactFile, path.extname(artifactFile)) : "";
|
|
1120
998
|
return template
|
|
1121
999
|
.replace(/\{task-id\}/g, path.basename(taskDir))
|
|
1122
1000
|
.replace(/\{artifact-stem\}/g, artifactStem);
|
|
1123
1001
|
}
|
|
1124
1002
|
|
|
1125
|
-
function summarizeGate(checks) {
|
|
1126
|
-
if (checks.some((check) => check.status === "blocked")) {
|
|
1003
|
+
function summarizeGate(checks: any): any {
|
|
1004
|
+
if (checks.some((check: any) => check.status === "blocked")) {
|
|
1127
1005
|
return "blocked";
|
|
1128
1006
|
}
|
|
1129
1007
|
|
|
1130
|
-
if (checks.some((check) => check.status === "fail")) {
|
|
1008
|
+
if (checks.some((check: any) => check.status === "fail")) {
|
|
1131
1009
|
return "fail";
|
|
1132
1010
|
}
|
|
1133
1011
|
|
|
1134
1012
|
return "pass";
|
|
1135
1013
|
}
|
|
1136
1014
|
|
|
1137
|
-
function summarizeChecks(checks) {
|
|
1015
|
+
function summarizeChecks(checks: any): any {
|
|
1138
1016
|
const counts = {
|
|
1139
|
-
pass: checks.filter((check) => check.status === "pass").length,
|
|
1140
|
-
fail: checks.filter((check) => check.status === "fail").length,
|
|
1141
|
-
blocked: checks.filter((check) => check.status === "blocked").length
|
|
1017
|
+
pass: checks.filter((check: any) => check.status === "pass").length,
|
|
1018
|
+
fail: checks.filter((check: any) => check.status === "fail").length,
|
|
1019
|
+
blocked: checks.filter((check: any) => check.status === "blocked").length
|
|
1142
1020
|
};
|
|
1143
1021
|
|
|
1144
1022
|
if (counts.blocked > 0) {
|
|
@@ -1148,12 +1026,12 @@ function summarizeChecks(checks) {
|
|
|
1148
1026
|
return `${counts.pass} passed, ${counts.fail} failed`;
|
|
1149
1027
|
}
|
|
1150
1028
|
|
|
1151
|
-
function buildAction(gate, checks) {
|
|
1029
|
+
function buildAction(gate: any, checks: any): any {
|
|
1152
1030
|
if (gate === "pass") {
|
|
1153
1031
|
return "All declared checks passed";
|
|
1154
1032
|
}
|
|
1155
1033
|
|
|
1156
|
-
const firstFailure = checks.find((check) => check.status !== "pass");
|
|
1034
|
+
const firstFailure = checks.find((check: any) => check.status !== "pass");
|
|
1157
1035
|
if (!firstFailure) {
|
|
1158
1036
|
return "Review validation output";
|
|
1159
1037
|
}
|
|
@@ -1165,47 +1043,23 @@ function buildAction(gate, checks) {
|
|
|
1165
1043
|
return `Fix ${firstFailure.type} issues and re-run gate`;
|
|
1166
1044
|
}
|
|
1167
1045
|
|
|
1168
|
-
function
|
|
1169
|
-
|
|
1170
|
-
return "Requested check passed";
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
if (result.status === "blocked") {
|
|
1174
|
-
return `Resolve blocked ${result.type} check and re-run check`;
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
return `Fix ${result.type} issues and re-run check`;
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
function buildSingleCheckSummary(status) {
|
|
1181
|
-
if (status === "pass") {
|
|
1182
|
-
return "1 passed, 0 failed";
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
if (status === "blocked") {
|
|
1186
|
-
return "0 passed, 0 failed, 1 blocked";
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
return "0 passed, 1 failed";
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
function passResult(type, message, warnings = []) {
|
|
1193
|
-
const result = { type, status: "pass", message };
|
|
1046
|
+
function passResult(type: any, message: any, warnings: string[] = []): any {
|
|
1047
|
+
const result: { type: any; status: string; message: any; warnings?: string[] } = { type, status: "pass", message };
|
|
1194
1048
|
if (warnings.length > 0) {
|
|
1195
1049
|
result.warnings = warnings;
|
|
1196
1050
|
}
|
|
1197
1051
|
return result;
|
|
1198
1052
|
}
|
|
1199
1053
|
|
|
1200
|
-
function failResult(type, message, failType = "check_failed") {
|
|
1054
|
+
function failResult(type: any, message: any, failType = "check_failed"): any {
|
|
1201
1055
|
return { type, status: "fail", fail_type: failType, message };
|
|
1202
1056
|
}
|
|
1203
1057
|
|
|
1204
|
-
function blockedResult(type, message, failType = "network_error") {
|
|
1058
|
+
function blockedResult(type: any, message: any, failType = "network_error"): any {
|
|
1205
1059
|
return { type, status: "blocked", fail_type: failType, message };
|
|
1206
1060
|
}
|
|
1207
1061
|
|
|
1208
|
-
function safeStat(filePath) {
|
|
1062
|
+
function safeStat(filePath: any): any {
|
|
1209
1063
|
try {
|
|
1210
1064
|
return fs.statSync(filePath);
|
|
1211
1065
|
} catch {
|
|
@@ -1213,105 +1067,44 @@ function safeStat(filePath) {
|
|
|
1213
1067
|
}
|
|
1214
1068
|
}
|
|
1215
1069
|
|
|
1216
|
-
function escapePattern(pattern) {
|
|
1070
|
+
function escapePattern(pattern: any): any {
|
|
1217
1071
|
return escapeRegExp(pattern)
|
|
1218
1072
|
.replace(/\\\{N\\\}/g, "(\\d+)");
|
|
1219
1073
|
}
|
|
1220
1074
|
|
|
1221
|
-
function escapeRegExp(value) {
|
|
1075
|
+
function escapeRegExp(value: any): any {
|
|
1222
1076
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1223
1077
|
}
|
|
1224
1078
|
|
|
1225
|
-
function isBlank(value) {
|
|
1079
|
+
function isBlank(value: any): any {
|
|
1226
1080
|
return value === undefined || value === null || String(value).trim() === "";
|
|
1227
1081
|
}
|
|
1228
1082
|
|
|
1229
|
-
function
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
if (arg === name) {
|
|
1236
|
-
value = args[index + 1];
|
|
1237
|
-
index += 1;
|
|
1238
|
-
continue;
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
const inlinePrefix = `${name}=`;
|
|
1242
|
-
if (arg.startsWith(inlinePrefix)) {
|
|
1243
|
-
value = arg.slice(inlinePrefix.length);
|
|
1244
|
-
continue;
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
|
-
rest.push(arg);
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
return { value, rest };
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
function normalizeFormat(value) {
|
|
1254
|
-
return value === "text" ? "text" : "json";
|
|
1255
|
-
}
|
|
1256
|
-
|
|
1257
|
-
function formatStatusLabel(status) {
|
|
1258
|
-
if (status === "fail") {
|
|
1259
|
-
return "FAIL";
|
|
1083
|
+
function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: requestedChecks, repositoryRoot }: any): any {
|
|
1084
|
+
if (repositoryRoot) repoRoot = path.resolve(repositoryRoot);
|
|
1085
|
+
else {
|
|
1086
|
+
let cursor = path.resolve(taskDir);
|
|
1087
|
+
while (path.dirname(cursor) !== cursor && !fs.existsSync(path.join(cursor, ".agents"))) cursor = path.dirname(cursor);
|
|
1088
|
+
if (fs.existsSync(path.join(cursor, ".agents"))) repoRoot = cursor;
|
|
1260
1089
|
}
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
if (format === "text") {
|
|
1271
|
-
writeText(value);
|
|
1272
|
-
return;
|
|
1273
|
-
}
|
|
1274
|
-
|
|
1275
|
-
writeJson(value);
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
|
-
function writeText(value) {
|
|
1279
|
-
const lines = [];
|
|
1280
|
-
|
|
1281
|
-
if (Array.isArray(value.checks)) {
|
|
1282
|
-
lines.push(`Verification: ${value.gate} | Skill: ${value.skill}`);
|
|
1283
|
-
lines.push("");
|
|
1284
|
-
for (const check of value.checks) {
|
|
1285
|
-
lines.push(` [${formatStatusLabel(check.status)}] ${check.type} - ${check.message}`);
|
|
1090
|
+
const verifyConfig = loadVerificationConfig(repoRoot, skillName);
|
|
1091
|
+
const shared = { ...sharedUtils, repoRoot };
|
|
1092
|
+
if (mode === "gate") {
|
|
1093
|
+
const checks = [];
|
|
1094
|
+
for (const [type, checkConfig] of Object.entries(verifyConfig.checks || {})) {
|
|
1095
|
+
if (checkConfig === null) continue;
|
|
1096
|
+
const result = runCheck(type, { skillName, taskDir: path.resolve(taskDir), artifactFile, config: checkConfig }, shared);
|
|
1097
|
+
checks.push(result);
|
|
1098
|
+
if (result.status === "blocked") break;
|
|
1286
1099
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
} else {
|
|
1290
|
-
lines.push(`Check: ${value.status} | Skill: ${value.skill} | Type: ${value.type}`);
|
|
1291
|
-
lines.push("");
|
|
1292
|
-
lines.push(` [${formatStatusLabel(value.status)}] ${value.type} - ${value.message}`);
|
|
1293
|
-
lines.push("");
|
|
1294
|
-
lines.push(`Result: ${buildSingleCheckSummary(value.status)} - ${buildCheckAction(value)}`);
|
|
1100
|
+
const gate = summarizeGate(checks);
|
|
1101
|
+
return { gate, skill: skillName, checks, summary: summarizeChecks(checks), action: buildAction(gate, checks) };
|
|
1295
1102
|
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
function printUsageAndExit() {
|
|
1305
|
-
failUsage(
|
|
1306
|
-
"Usage:\n" +
|
|
1307
|
-
" node .agents/scripts/validate-artifact.js gate <skill-name> <task-dir> [artifact-file] [--format json|text]\n" +
|
|
1308
|
-
" node .agents/scripts/validate-artifact.js check <type> <task-dir> [artifact-file] --skill <skill-name> [--format json|text]"
|
|
1309
|
-
);
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
function failUsage(message) {
|
|
1313
|
-
process.stderr.write(`${message}\n`);
|
|
1314
|
-
process.exit(1);
|
|
1103
|
+
const type = requestedChecks[0];
|
|
1104
|
+
const config = (verifyConfig.checks || {})[type];
|
|
1105
|
+
if (config === undefined) return { skill: skillName, ...failResult(type, `Unknown check type '${type}' for skill '${skillName}'.`) };
|
|
1106
|
+
if (config === null) return { skill: skillName, ...passResult(type, `Check '${type}' is disabled for skill '${skillName}'.`) };
|
|
1107
|
+
return { skill: skillName, ...runCheck(type, { skillName, taskDir: path.resolve(taskDir), artifactFile, config }, shared) };
|
|
1315
1108
|
}
|
|
1316
1109
|
|
|
1317
|
-
|
|
1110
|
+
export { verifyInProcess };
|