@fitlab-ai/agent-infra 0.9.13 → 0.9.15
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/README.md +10 -0
- package/README.zh-CN.md +10 -0
- package/bin/cli.ts +26 -9
- package/bin/internal-cli.sh +45 -0
- package/dist/bin/cli.js +173 -157
- package/dist/bin/internal-cli.js +126 -42
- package/dist/lib/agent-client.js +5 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +165 -27
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +3 -2
- package/dist/lib/defaults.json +103 -103
- package/dist/lib/fs/durable-write.js +37 -0
- package/dist/lib/fs/file-lock.js +111 -0
- package/dist/lib/host-control/audit.js +19 -0
- package/dist/lib/host-control/client.js +142 -0
- package/dist/lib/host-control/command.js +49 -0
- package/dist/lib/host-control/path.js +160 -0
- package/dist/lib/host-control/secure-fs.js +140 -0
- package/dist/lib/host-control/server.js +159 -0
- package/dist/lib/host-control/service.js +112 -0
- package/dist/lib/init.js +11 -2
- package/dist/lib/internal/agent-client.js +5 -2
- package/dist/lib/internal/cli-route-inventory.js +154 -0
- package/dist/lib/internal/codex-lifecycle.js +15 -12
- package/dist/lib/internal/codex-sandbox-controller.js +8 -2
- package/dist/lib/internal/demo-promotion.js +322 -0
- package/dist/lib/internal/demo-transcript.js +454 -0
- package/dist/lib/internal/git-workflow.js +10 -6
- package/dist/lib/internal/host-control.js +28 -0
- package/dist/lib/internal/manual-validation.js +322 -0
- package/dist/lib/internal/platform-checks.js +16 -4
- package/dist/lib/internal/platform-comment.js +16 -4
- package/dist/lib/internal/platform-context.js +4 -1
- package/dist/lib/internal/platform-issue.js +12 -4
- package/dist/lib/internal/platform-metadata.js +88 -0
- package/dist/lib/internal/platform-pr-review.js +16 -3
- package/dist/lib/internal/platform-pr.js +42 -14
- package/dist/lib/internal/platform-release-notes.js +6 -3
- package/dist/lib/internal/platform-security.js +93 -0
- package/dist/lib/internal/pr-review-grade.js +14 -3
- package/dist/lib/internal/release-workflow.js +82 -89
- package/dist/lib/internal/sandbox-control.js +171 -7
- package/dist/lib/internal/task-activity.js +13 -4
- package/dist/lib/internal/task-artifact.js +19 -107
- package/dist/lib/internal/task-context.js +4 -1
- package/dist/lib/internal/task-create.js +48 -14
- package/dist/lib/internal/task-delivery.js +4 -1
- package/dist/lib/internal/task-event.js +38 -35
- package/dist/lib/internal/task-finalization.js +4 -1
- package/dist/lib/internal/task-invalidation.js +4 -1
- package/dist/lib/internal/task-ledger.js +12 -1
- package/dist/lib/internal/task-lifecycle.js +4 -1
- package/dist/lib/internal/task-operation-registry.js +519 -0
- package/dist/lib/internal/task-orchestration.js +12 -0
- package/dist/lib/internal/task-override.js +10 -3
- package/dist/lib/internal/task-qualification.js +90 -0
- package/dist/lib/internal/task-review.js +10 -52
- package/dist/lib/internal/task-short-id.js +11 -1
- package/dist/lib/internal/task-snapshot.js +4 -1
- package/dist/lib/internal/task-validate.js +37 -12
- package/dist/lib/internal/task-verify.js +5 -1
- package/dist/lib/internal/task-warning.js +8 -1
- package/dist/lib/owned-path.js +33 -0
- package/dist/lib/platform/check-status.js +11 -0
- package/dist/lib/platform/comment-safety.js +229 -0
- package/dist/lib/platform/completion-backfill.js +1 -1
- package/dist/lib/platform/github-data.js +241 -0
- package/dist/lib/platform/github-provider.js +248 -26
- package/dist/lib/platform/issue-comments.js +146 -34
- package/dist/lib/platform/issues.js +1 -179
- package/dist/lib/platform/pr-change-report.js +6 -12
- package/dist/lib/platform/pr-checks.js +12 -65
- package/dist/lib/platform/pr-summary.js +83 -10
- package/dist/lib/platform/provider-contract.d.ts +67 -1
- package/dist/lib/platform/provider-contract.js +6 -2
- package/dist/lib/platform/provider-validation.js +76 -3
- package/dist/lib/platform/pull-requests.js +117 -275
- package/dist/lib/platform/repository-metadata.js +377 -0
- package/dist/lib/platform/security-alerts.js +155 -0
- package/dist/lib/platform/snapshots.js +2 -0
- package/dist/lib/platform/verification-sync.js +154 -162
- package/dist/lib/process-data/index.js +7 -0
- package/dist/lib/release/workflow.js +1 -1
- package/dist/lib/run/index.js +5 -0
- package/dist/lib/sandbox/commands/control-status.js +22 -0
- package/dist/lib/sandbox/commands/create.js +39 -8
- package/dist/lib/sandbox/commands/ls.js +5 -0
- package/dist/lib/sandbox/commands/rm.js +3 -807
- package/dist/lib/sandbox/commands/show.js +16 -0
- package/dist/lib/sandbox/control/audit.js +203 -0
- package/dist/lib/sandbox/control/client.js +125 -12
- package/dist/lib/sandbox/control/completed-reentry.js +85 -0
- package/dist/lib/sandbox/control/container-identity.js +28 -31
- package/dist/lib/sandbox/control/executor.js +233 -34
- package/dist/lib/sandbox/control/finalization-response.js +27 -0
- package/dist/lib/sandbox/control/identity-sentinel.js +107 -0
- package/dist/lib/sandbox/control/lifecycle.js +656 -128
- package/dist/lib/sandbox/control/native-file-lock.js +85 -0
- package/dist/lib/sandbox/control/protocol.js +55 -4
- package/dist/lib/sandbox/control/server.js +720 -79
- package/dist/lib/sandbox/control/state.js +63 -3
- package/dist/lib/sandbox/control/task-view.js +183 -0
- package/dist/lib/sandbox/control/task-workflow.js +74 -0
- package/dist/lib/sandbox/control/workflow-executor.js +99 -0
- package/dist/lib/sandbox/engines/authority.js +289 -0
- package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
- package/dist/lib/sandbox/index.js +7 -2
- package/dist/lib/sandbox/recovery.js +49 -5
- package/dist/lib/sandbox/removal.js +1717 -0
- package/dist/lib/sandbox/task-cleanup.js +217 -0
- package/dist/lib/sandbox/workspace-view.js +15 -15
- package/dist/lib/sandbox/worktree-safety.js +4 -1
- package/dist/lib/server/index.js +8 -0
- package/dist/lib/task/activity-intent.js +2 -1
- package/dist/lib/task/activity-log.js +30 -24
- package/dist/lib/task/artifact-command.js +101 -0
- package/dist/lib/task/artifact-lifecycle.js +71 -40
- package/dist/lib/task/artifact-name.js +36 -0
- package/dist/lib/task/artifact-operations.js +474 -0
- package/dist/lib/task/artifact-receipts.js +3 -15
- package/dist/lib/task/artifact-repair-intent.js +130 -0
- package/dist/lib/task/artifact-schema.js +127 -0
- package/dist/lib/task/capabilities.js +83 -19
- package/dist/lib/task/codex-orchestration.js +71 -25
- package/dist/lib/task/commit-identity.js +28 -0
- package/dist/lib/task/commit-operation.js +2 -16
- package/dist/lib/task/control-authority.js +375 -5
- package/dist/lib/task/control-recovery.js +128 -0
- package/dist/lib/task/create-service.js +103 -4
- package/dist/lib/task/create.js +80 -2
- package/dist/lib/task/decision-details.js +2 -46
- package/dist/lib/task/events.js +306 -76
- package/dist/lib/task/finalization-state.js +9 -0
- package/dist/lib/task/human-override.js +3 -6
- package/dist/lib/task/implementation-inputs.js +3 -3
- package/dist/lib/task/index.js +11 -3
- package/dist/lib/task/intermediate-cleanup.js +383 -0
- package/dist/lib/task/invalidation.js +18 -65
- package/dist/lib/task/ledger-intents.js +7 -22
- package/dist/lib/task/ledger.js +1 -3
- package/dist/lib/task/lifecycle.js +19 -1
- package/dist/lib/task/local-artifact-finalization.js +190 -290
- package/dist/lib/task/manual-validation-completion.js +26 -0
- package/dist/lib/task/manual-validation-evidence.js +130 -0
- package/dist/lib/task/manual-validation-receipt.js +101 -0
- package/dist/lib/task/manual-validation-shared.js +40 -0
- package/dist/lib/task/manual-validation-transaction.js +243 -0
- package/dist/lib/task/markdown.js +47 -0
- package/dist/lib/task/orchestration.js +206 -69
- package/dist/lib/task/qualification-audit.js +476 -0
- package/dist/lib/task/qualification-confirmation.js +109 -0
- package/dist/lib/task/qualification-intents.js +148 -0
- package/dist/lib/task/review-artifacts.js +23 -40
- package/dist/lib/task/review-command.js +25 -0
- package/dist/lib/task/review-finalization.js +146 -97
- package/dist/lib/task/review-fingerprint.js +2 -2
- package/dist/lib/task/sections.js +34 -54
- package/dist/lib/task/verification-config.js +11 -0
- package/dist/lib/task/verification-engine.js +170 -327
- package/dist/lib/task/verification.js +1 -1
- package/dist/lib/task/workflow-command.js +17 -0
- package/dist/lib/task/workflow-warning-intents.js +0 -16
- package/dist/lib/task/workflow-warnings.js +28 -2
- package/dist/lib/update.js +2 -0
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-client.ts +9 -0
- package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +223 -33
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +3 -2
- package/lib/fs/durable-write.ts +29 -0
- package/lib/fs/file-lock.ts +113 -0
- package/lib/host-control/audit.ts +22 -0
- package/lib/host-control/client.ts +172 -0
- package/lib/host-control/command.ts +60 -0
- package/lib/host-control/path.ts +167 -0
- package/lib/host-control/secure-fs.ts +135 -0
- package/lib/host-control/server.ts +180 -0
- package/lib/host-control/service.ts +133 -0
- package/lib/init.ts +15 -2
- package/lib/internal/agent-client.ts +4 -2
- package/lib/internal/cli-route-inventory.ts +142 -0
- package/lib/internal/codex-lifecycle.ts +14 -12
- package/lib/internal/codex-sandbox-controller.ts +7 -2
- package/lib/internal/demo-promotion.ts +354 -0
- package/lib/internal/demo-transcript.ts +419 -0
- package/lib/internal/git-workflow.ts +9 -6
- package/lib/internal/host-control.ts +28 -0
- package/lib/internal/manual-validation.ts +306 -0
- package/lib/internal/platform-checks.ts +12 -4
- package/lib/internal/platform-comment.ts +12 -4
- package/lib/internal/platform-context.ts +3 -1
- package/lib/internal/platform-issue.ts +11 -4
- package/lib/internal/platform-metadata.ts +70 -0
- package/lib/internal/platform-pr-review.ts +14 -3
- package/lib/internal/platform-pr.ts +38 -14
- package/lib/internal/platform-release-notes.ts +5 -3
- package/lib/internal/platform-security.ts +83 -0
- package/lib/internal/pr-review-grade.ts +10 -3
- package/lib/internal/release-workflow.ts +91 -87
- package/lib/internal/sandbox-control.ts +181 -6
- package/lib/internal/task-activity.ts +12 -4
- package/lib/internal/task-artifact.ts +15 -79
- package/lib/internal/task-context.ts +3 -1
- package/lib/internal/task-create.ts +76 -15
- package/lib/internal/task-delivery.ts +3 -1
- package/lib/internal/task-event.ts +21 -10
- package/lib/internal/task-finalization.ts +3 -1
- package/lib/internal/task-invalidation.ts +3 -1
- package/lib/internal/task-ledger.ts +11 -1
- package/lib/internal/task-lifecycle.ts +3 -1
- package/lib/internal/task-operation-registry.ts +590 -0
- package/lib/internal/task-orchestration.ts +12 -0
- package/lib/internal/task-override.ts +9 -3
- package/lib/internal/task-qualification.ts +61 -0
- package/lib/internal/task-review.ts +7 -50
- package/lib/internal/task-short-id.ts +10 -1
- package/lib/internal/task-snapshot.ts +3 -1
- package/lib/internal/task-validate.ts +32 -12
- package/lib/internal/task-verify.ts +4 -1
- package/lib/internal/task-warning.ts +7 -1
- package/lib/owned-path.ts +26 -0
- package/lib/platform/check-status.ts +9 -0
- package/lib/platform/comment-safety.ts +255 -0
- package/lib/platform/completion-backfill.ts +1 -1
- package/lib/platform/github-data.ts +322 -0
- package/lib/platform/github-provider.ts +244 -27
- package/lib/platform/issue-comments.ts +159 -35
- package/lib/platform/issues.ts +4 -245
- package/lib/platform/pr-change-report.ts +6 -12
- package/lib/platform/pr-checks.ts +13 -77
- package/lib/platform/pr-summary.ts +88 -11
- package/lib/platform/provider-contract.ts +78 -3
- package/lib/platform/provider-validation.ts +85 -3
- package/lib/platform/pull-requests.ts +129 -348
- package/lib/platform/repository-metadata.ts +453 -0
- package/lib/platform/security-alerts.ts +191 -0
- package/lib/platform/snapshots.ts +53 -0
- package/lib/platform/verification-sync.ts +171 -177
- package/lib/process-data/index.ts +7 -0
- package/lib/release/workflow.ts +3 -3
- package/lib/run/index.ts +5 -0
- package/lib/sandbox/commands/control-status.ts +26 -0
- package/lib/sandbox/commands/create.ts +53 -12
- package/lib/sandbox/commands/ls.ts +7 -0
- package/lib/sandbox/commands/rm.ts +3 -996
- package/lib/sandbox/commands/show.ts +16 -0
- package/lib/sandbox/control/audit.ts +253 -0
- package/lib/sandbox/control/client.ts +150 -13
- package/lib/sandbox/control/completed-reentry.ts +98 -0
- package/lib/sandbox/control/container-identity.ts +27 -43
- package/lib/sandbox/control/executor.ts +262 -37
- package/lib/sandbox/control/finalization-response.ts +29 -0
- package/lib/sandbox/control/identity-sentinel.ts +137 -0
- package/lib/sandbox/control/lifecycle.ts +672 -18
- package/lib/sandbox/control/native-file-lock.ts +108 -0
- package/lib/sandbox/control/protocol.ts +80 -8
- package/lib/sandbox/control/server.ts +779 -82
- package/lib/sandbox/control/state.ts +84 -3
- package/lib/sandbox/control/task-view.ts +240 -0
- package/lib/sandbox/control/task-workflow.ts +95 -0
- package/lib/sandbox/control/workflow-executor.ts +102 -0
- package/lib/sandbox/engines/authority.ts +365 -0
- package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
- package/lib/sandbox/index.ts +9 -2
- package/lib/sandbox/recovery.ts +49 -6
- package/lib/sandbox/removal.ts +2144 -0
- package/lib/sandbox/task-cleanup.ts +209 -0
- package/lib/sandbox/workspace-view.ts +26 -18
- package/lib/sandbox/worktree-safety.ts +4 -1
- package/lib/server/index.ts +10 -0
- package/lib/task/activity-intent.ts +2 -2
- package/lib/task/activity-log.ts +27 -19
- package/lib/task/artifact-command.ts +104 -0
- package/lib/task/artifact-lifecycle.ts +66 -39
- package/lib/task/artifact-name.ts +55 -0
- package/lib/task/artifact-operations.ts +580 -0
- package/lib/task/artifact-receipts.ts +3 -14
- package/lib/task/artifact-repair-intent.ts +152 -0
- package/lib/task/artifact-schema.ts +163 -0
- package/lib/task/capabilities.ts +82 -22
- package/lib/task/codex-orchestration.ts +85 -24
- package/lib/task/commit-identity.ts +31 -0
- package/lib/task/commit-operation.ts +2 -16
- package/lib/task/control-authority.ts +513 -6
- package/lib/task/control-recovery.ts +174 -0
- package/lib/task/create-service.ts +131 -6
- package/lib/task/create.ts +83 -1
- package/lib/task/decision-details.ts +3 -71
- package/lib/task/events.ts +292 -75
- package/lib/task/finalization-state.ts +11 -0
- package/lib/task/human-override.ts +3 -8
- package/lib/task/implementation-inputs.ts +3 -3
- package/lib/task/index.ts +16 -3
- package/lib/task/intermediate-cleanup.ts +455 -0
- package/lib/task/invalidation.ts +18 -62
- package/lib/task/ledger-intents.ts +7 -24
- package/lib/task/ledger.ts +1 -3
- package/lib/task/lifecycle.ts +17 -1
- package/lib/task/local-artifact-finalization.ts +223 -388
- package/lib/task/manual-validation-completion.ts +40 -0
- package/lib/task/manual-validation-evidence.ts +209 -0
- package/lib/task/manual-validation-receipt.ts +152 -0
- package/lib/task/manual-validation-shared.ts +50 -0
- package/lib/task/manual-validation-transaction.ts +304 -0
- package/lib/task/markdown.ts +70 -0
- package/lib/task/orchestration.ts +191 -68
- package/lib/task/qualification-audit.ts +588 -0
- package/lib/task/qualification-confirmation.ts +117 -0
- package/lib/task/qualification-intents.ts +150 -0
- package/lib/task/review-artifacts.ts +21 -41
- package/lib/task/review-command.ts +23 -0
- package/lib/task/review-finalization.ts +154 -153
- package/lib/task/review-fingerprint.ts +2 -2
- package/lib/task/sections.ts +33 -52
- package/lib/task/verification-config.ts +12 -0
- package/lib/task/verification-engine.ts +165 -370
- package/lib/task/verification-types.ts +17 -0
- package/lib/task/verification.ts +1 -1
- package/lib/task/workflow-command.ts +18 -0
- package/lib/task/workflow-warning-intents.ts +0 -13
- package/lib/task/workflow-warnings.ts +21 -2
- package/lib/update.ts +6 -0
- package/package.json +7 -2
- package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
- package/templates/.agents/rules/README.en.md +2 -0
- package/templates/.agents/rules/README.zh-CN.md +2 -0
- package/templates/.agents/rules/decision-qualification.en.md +22 -0
- package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
- package/templates/.agents/rules/evidence-reporting.en.md +28 -0
- package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
- package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
- package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
- package/templates/.agents/rules/local-artifact-repair.en.md +5 -1
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +5 -1
- package/templates/.agents/rules/security-alerts.en.md +8 -8
- package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
- package/templates/.agents/rules/testing-discipline.en.md +2 -0
- package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -0
- package/templates/.agents/scripts/package.json +3 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +15 -2
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +19 -2
- package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
- package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +14 -1
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/code-task/config/verify.en.json +5 -14
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +5 -14
- package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
- package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
- package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +37 -21
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +37 -21
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +4 -0
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +4 -0
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +16 -7
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +16 -7
- package/templates/.agents/skills/complete-task/SKILL.en.md +10 -23
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +10 -23
- package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
- package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
- package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
- package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
- package/templates/.agents/skills/plan-task/SKILL.en.md +14 -1
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +16 -1
- package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
- package/templates/.agents/skills/release/SKILL.en.md +7 -3
- package/templates/.agents/skills/release/SKILL.zh-CN.md +7 -3
- package/templates/.agents/skills/review-analysis/SKILL.en.md +14 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
- package/templates/.agents/skills/review-code/SKILL.en.md +14 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
- package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
- package/templates/.agents/skills/review-plan/SKILL.en.md +14 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
- package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
- package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +25 -4
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +25 -4
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +4 -1
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +4 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +5 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +5 -1
- package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/test/SKILL.en.md +29 -7
- package/templates/.agents/skills/test/SKILL.zh-CN.md +29 -7
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
- package/templates/.agents/templates/task.en.md +6 -0
- package/templates/.agents/templates/task.zh-CN.md +6 -0
- package/templates/.claude/commands/run-manual-validation.en.md +1 -1
- package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
- package/dist/lib/platform/adapters.js +0 -56
- package/lib/platform/adapters.ts +0 -197
- package/templates/.agents/scripts/security-alerts.github.sh +0 -151
- package/templates/.agents/scripts/security-alerts.sh +0 -31
- package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
- package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
- package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
- package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { VerificationShared } from "../task/verification-types.ts";
|
|
1
2
|
import fs from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import process from "node:process";
|
|
@@ -7,12 +8,16 @@ import { resolvePlatformProviderContext } from "./context.ts";
|
|
|
7
8
|
import { hasCheckedRequirement, resolveRequirementSection } from "./issue-metadata.ts";
|
|
8
9
|
import { requirementSectionAnchors } from "./issues.ts";
|
|
9
10
|
import { taskTypeLabel } from "./metadata-labels.ts";
|
|
10
|
-
import { planInLabelUpdate, validateInLabelMapping
|
|
11
|
-
import { inspectGitHubPullRequest } from "./pull-requests.ts";
|
|
12
|
-
import { createGitHubClient } from "./github-client.ts";
|
|
11
|
+
import { planInLabelUpdate, validateInLabelMapping } from "./in-label-sync.ts";
|
|
13
12
|
import { readPrDeliveryFact } from "../task/pr-delivery-fact.ts";
|
|
14
13
|
import { providerError, providerOperationContext, resourceIdentityNumber, unsupportedProviderOperation } from "./provider-bridge.ts";
|
|
15
14
|
import { taskIssueIdentity } from "./task-identities.ts";
|
|
15
|
+
import {
|
|
16
|
+
CONTROL_MARKER_PATTERN,
|
|
17
|
+
canonicalizeCommentBody,
|
|
18
|
+
renderSafeCodeFence,
|
|
19
|
+
sanitizeMarkdownDocument
|
|
20
|
+
} from "./comment-safety.ts";
|
|
16
21
|
|
|
17
22
|
const CHECK_TYPE = "platform-sync";
|
|
18
23
|
const VERSION_LINE_REGEX = /^[0-9]+\.[0-9]+\.x$/;
|
|
@@ -29,9 +34,6 @@ const OPTION_LOCALIZATION: Record<string, string> = {
|
|
|
29
34
|
"低": "Low"
|
|
30
35
|
};
|
|
31
36
|
|
|
32
|
-
let activeShared: any = null;
|
|
33
|
-
let repoRoot = "";
|
|
34
|
-
|
|
35
37
|
export function getDefaults(): any {
|
|
36
38
|
return {
|
|
37
39
|
statusLabels: {
|
|
@@ -52,59 +54,18 @@ export function getDefaults(): any {
|
|
|
52
54
|
};
|
|
53
55
|
}
|
|
54
56
|
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return activeShared;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function loadTask(...args: any[]): any {
|
|
64
|
-
return getShared().loadTask(...args);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function getCheckedRequirements(...args: any[]): any {
|
|
68
|
-
return getShared().getCheckedRequirements(...args);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function normalizeContent(...args: any[]): any {
|
|
72
|
-
return getShared().normalizeContent(...args);
|
|
57
|
+
function sanitizeCommentContent(content: string): string | null {
|
|
58
|
+
const result = sanitizeMarkdownDocument(content, { reservedMarkers: [CONTROL_MARKER_PATTERN] });
|
|
59
|
+
return result.ok ? result.value : null;
|
|
73
60
|
}
|
|
74
61
|
|
|
75
|
-
function
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function escapeRegExp(...args: any[]): any {
|
|
80
|
-
return getShared().escapeRegExp(...args);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function passResult(...args: any[]): any {
|
|
84
|
-
return getShared().passResult(...args);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function failResult(...args: any[]): any {
|
|
88
|
-
return getShared().failResult(...args);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function blockedResult(...args: any[]): any {
|
|
92
|
-
return getShared().blockedResult(...args);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function safeStat(...args: any[]): any {
|
|
96
|
-
return getShared().safeStat(...args);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export async function check({ taskDir, config, artifactFile }: any, shared: any): Promise<any> {
|
|
100
|
-
activeShared = shared;
|
|
101
|
-
repoRoot = shared.repoRoot;
|
|
102
|
-
const context = await buildSyncContext({ taskDir, config, artifactFile });
|
|
62
|
+
export async function check({ taskDir, config, artifactFile }: any, shared: VerificationShared): Promise<any> {
|
|
63
|
+
const context = await buildSyncContext({ taskDir, config, artifactFile }, shared);
|
|
103
64
|
if (context.earlyReturn) {
|
|
104
65
|
return context.earlyReturn;
|
|
105
66
|
}
|
|
106
67
|
|
|
107
|
-
const remoteData = await fetchRemoteData(context);
|
|
68
|
+
const remoteData = await fetchRemoteData(context, shared);
|
|
108
69
|
if (remoteData.earlyReturn) {
|
|
109
70
|
return remoteData.earlyReturn;
|
|
110
71
|
}
|
|
@@ -129,57 +90,57 @@ export async function check({ taskDir, config, artifactFile }: any, shared: any)
|
|
|
129
90
|
];
|
|
130
91
|
|
|
131
92
|
for (const subCheck of subChecks) {
|
|
132
|
-
const result = subCheck(context, remoteData);
|
|
93
|
+
const result = subCheck(context, remoteData, shared);
|
|
133
94
|
if (result) {
|
|
134
95
|
return result;
|
|
135
96
|
}
|
|
136
97
|
}
|
|
137
98
|
|
|
138
|
-
return passResult(CHECK_TYPE, `Platform sync checks passed for Issue ${context.issueNumber || "identity"}`);
|
|
99
|
+
return shared.passResult(CHECK_TYPE, `Platform sync checks passed for Issue ${context.issueNumber || "identity"}`);
|
|
139
100
|
}
|
|
140
101
|
|
|
141
|
-
async function buildSyncContext({ taskDir, config, artifactFile }: any): Promise<any> {
|
|
142
|
-
const task = loadTask(taskDir);
|
|
102
|
+
async function buildSyncContext({ taskDir, config, artifactFile }: any, shared: VerificationShared): Promise<any> {
|
|
103
|
+
const task = shared.loadTask(taskDir);
|
|
143
104
|
if (!task.ok) {
|
|
144
|
-
return { earlyReturn: failResult(CHECK_TYPE, task.message) };
|
|
105
|
+
return { earlyReturn: shared.failResult(CHECK_TYPE, task.message) };
|
|
145
106
|
}
|
|
146
107
|
|
|
147
108
|
const issueIdentity = taskIssueIdentity(task.metadata);
|
|
148
109
|
const issueNumber = resourceIdentityNumber(issueIdentity);
|
|
149
110
|
const fact = readPrDeliveryFact(task.metadata);
|
|
150
111
|
if (fact.status === "invalid") {
|
|
151
|
-
return { earlyReturn: failResult(CHECK_TYPE, fact.error.message, "check_failed") };
|
|
112
|
+
return { earlyReturn: shared.failResult(CHECK_TYPE, fact.error.message, "check_failed") };
|
|
152
113
|
}
|
|
153
114
|
const prIdentity = fact.status === "valid" && fact.fact.state === "bound" ? fact.fact.identity.resource : null;
|
|
154
115
|
const prNumber = resourceIdentityNumber(prIdentity);
|
|
155
116
|
if (config.when === "issue_number_exists" && !issueIdentity) {
|
|
156
|
-
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no issue_number") };
|
|
117
|
+
return { earlyReturn: shared.passResult(CHECK_TYPE, "Skipped: task has no issue_number") };
|
|
157
118
|
}
|
|
158
119
|
if (config.when === "pr_fact_bound" && !prIdentity) {
|
|
159
|
-
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no verified bound pull request") };
|
|
120
|
+
return { earlyReturn: shared.passResult(CHECK_TYPE, "Skipped: task has no verified bound pull request") };
|
|
160
121
|
}
|
|
161
122
|
|
|
162
123
|
if (!issueIdentity) {
|
|
163
|
-
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: platform-sync not required for this task") };
|
|
124
|
+
return { earlyReturn: shared.passResult(CHECK_TYPE, "Skipped: platform-sync not required for this task") };
|
|
164
125
|
}
|
|
165
126
|
|
|
166
|
-
const loaded = await resolvePlatformProviderContext({ cwd: repoRoot });
|
|
127
|
+
const loaded = await resolvePlatformProviderContext({ cwd: shared.repoRoot });
|
|
167
128
|
const platformContext = loaded.ok ? loaded.value.context : loaded.context;
|
|
168
129
|
if (platformContext.status === "failed") {
|
|
169
|
-
return { earlyReturn: failResult(CHECK_TYPE, platformContext.error?.message || "Platform context failed", "check_failed") };
|
|
130
|
+
return { earlyReturn: shared.failResult(CHECK_TYPE, platformContext.error?.message || "Platform context failed", "check_failed") };
|
|
170
131
|
}
|
|
171
132
|
if (platformContext.status === "blocked") {
|
|
172
|
-
return { earlyReturn: blockedResult(CHECK_TYPE, platformContext.error?.message || "Platform context blocked", "network_error") };
|
|
133
|
+
return { earlyReturn: shared.blockedResult(CHECK_TYPE, platformContext.error?.message || "Platform context blocked", "network_error") };
|
|
173
134
|
}
|
|
174
135
|
if (!platformContext.platform.repository) {
|
|
175
136
|
if (platformContext.error?.code === "REMOTE_MISSING" || platformContext.error?.code === "REMOTE_INVALID") {
|
|
176
|
-
return { earlyReturn: blockedResult(CHECK_TYPE, platformContext.error.message, "network_error") };
|
|
137
|
+
return { earlyReturn: shared.blockedResult(CHECK_TYPE, platformContext.error.message, "network_error") };
|
|
177
138
|
}
|
|
178
|
-
return { earlyReturn: passResult(CHECK_TYPE, `Skipped: ${platformContext.error?.message || "platform unavailable"}`) };
|
|
139
|
+
return { earlyReturn: shared.passResult(CHECK_TYPE, `Skipped: ${platformContext.error?.message || "platform unavailable"}`) };
|
|
179
140
|
}
|
|
180
141
|
const expectedValues = resolveExpectedValues(config);
|
|
181
142
|
if (!expectedValues.ok) {
|
|
182
|
-
return { earlyReturn: failResult(CHECK_TYPE, expectedValues.message, "check_failed") };
|
|
143
|
+
return { earlyReturn: shared.failResult(CHECK_TYPE, expectedValues.message, "check_failed") };
|
|
183
144
|
}
|
|
184
145
|
|
|
185
146
|
const marker = expectedValues.commentMarker
|
|
@@ -200,7 +161,6 @@ async function buildSyncContext({ taskDir, config, artifactFile }: any): Promise
|
|
|
200
161
|
prIdentity,
|
|
201
162
|
issueNumber,
|
|
202
163
|
prNumber,
|
|
203
|
-
upstreamRepo: platformContext.platform.repository,
|
|
204
164
|
repoOwnerType: String(loaded.ok ? loaded.value.snapshot.metadata?.ownerType || "unknown" : "unknown"),
|
|
205
165
|
hasTriage: platformContext.capabilities.triage,
|
|
206
166
|
hasPush: platformContext.capabilities.push,
|
|
@@ -266,7 +226,7 @@ function resolveDefaultValue({ collection, key, value, configKey }: any): any {
|
|
|
266
226
|
return { ok: true, value: resolvedValue };
|
|
267
227
|
}
|
|
268
228
|
|
|
269
|
-
async function fetchRemoteData(context: any): Promise<any> {
|
|
229
|
+
async function fetchRemoteData(context: any, shared: VerificationShared): Promise<any> {
|
|
270
230
|
const provider = context.provider;
|
|
271
231
|
const operationContext = providerOperationContext(context.loadedContext, context.taskDir);
|
|
272
232
|
const facts = provider?.verification?.fetchRemoteFacts
|
|
@@ -282,8 +242,8 @@ async function fetchRemoteData(context: any): Promise<any> {
|
|
|
282
242
|
if (!facts.ok) {
|
|
283
243
|
return {
|
|
284
244
|
earlyReturn: facts.error.retryable
|
|
285
|
-
? blockedResult(CHECK_TYPE, providerError(facts.error, "PLATFORM_PROVIDER_OPERATION_FAILED").message, "network_error")
|
|
286
|
-
: failResult(CHECK_TYPE, providerError(facts.error, "PLATFORM_PROVIDER_OPERATION_FAILED").message, "check_failed")
|
|
245
|
+
? shared.blockedResult(CHECK_TYPE, providerError(facts.error, "PLATFORM_PROVIDER_OPERATION_FAILED").message, "network_error")
|
|
246
|
+
: shared.failResult(CHECK_TYPE, providerError(facts.error, "PLATFORM_PROVIDER_OPERATION_FAILED").message, "check_failed")
|
|
287
247
|
};
|
|
288
248
|
}
|
|
289
249
|
const issueSnapshot = facts.value.issue;
|
|
@@ -308,12 +268,33 @@ async function fetchRemoteData(context: any): Promise<any> {
|
|
|
308
268
|
const listed = await provider.comments.list({ context: operationContext, parent: context.prIdentity });
|
|
309
269
|
if (!listed.ok) return {
|
|
310
270
|
earlyReturn: listed.error.retryable
|
|
311
|
-
? blockedResult(CHECK_TYPE, listed.error.message, "network_error")
|
|
312
|
-
: failResult(CHECK_TYPE, listed.error.message, "check_failed")
|
|
271
|
+
? shared.blockedResult(CHECK_TYPE, listed.error.message, "network_error")
|
|
272
|
+
: shared.failResult(CHECK_TYPE, listed.error.message, "check_failed")
|
|
313
273
|
};
|
|
314
274
|
prComments = listed.value.map((comment: { id: string; body: string }) => ({ id: comment.id, body: comment.body }));
|
|
315
275
|
}
|
|
316
276
|
const changeRequest = facts.value.changeRequest;
|
|
277
|
+
let inLabelMapping: Record<string, string[]> = {};
|
|
278
|
+
let repositoryLabels: string[] = [];
|
|
279
|
+
if (context.config.verify_in_labels_computed && context.hasTriage) {
|
|
280
|
+
const mapping = loadInLabelMapping(shared);
|
|
281
|
+
if (!mapping.ok) return { earlyReturn: shared.failResult(CHECK_TYPE, mapping.message, "check_failed") };
|
|
282
|
+
inLabelMapping = mapping.value;
|
|
283
|
+
if (Object.keys(inLabelMapping).length > 0) {
|
|
284
|
+
const labels = provider?.issues?.listLabels
|
|
285
|
+
? await provider.issues.listLabels({ context: operationContext })
|
|
286
|
+
: unsupportedProviderOperation(provider, "issues.listLabels");
|
|
287
|
+
if (!labels.ok) {
|
|
288
|
+
const error = providerError(labels.error, "PLATFORM_PROVIDER_OPERATION_FAILED");
|
|
289
|
+
return {
|
|
290
|
+
earlyReturn: error.retryable
|
|
291
|
+
? shared.blockedResult(CHECK_TYPE, `${error.code}: ${error.message}`, "network_error")
|
|
292
|
+
: shared.failResult(CHECK_TYPE, `${error.code}: ${error.message}`, "check_failed")
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
repositoryLabels = labels.value;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
317
298
|
return {
|
|
318
299
|
issue,
|
|
319
300
|
comments: facts.value.comments.map((comment: { id: string; body: string }) => ({ id: comment.id, body: comment.body })),
|
|
@@ -327,7 +308,9 @@ async function fetchRemoteData(context: any): Promise<any> {
|
|
|
327
308
|
? (changeRequest.milestone ? { title: changeRequest.milestone } : null)
|
|
328
309
|
: undefined,
|
|
329
310
|
prAssignees: changeRequest?.assignees,
|
|
330
|
-
prHeadSha: changeRequest?.headSha
|
|
311
|
+
prHeadSha: changeRequest?.headSha,
|
|
312
|
+
inLabelMapping,
|
|
313
|
+
repositoryLabels
|
|
331
314
|
};
|
|
332
315
|
}
|
|
333
316
|
|
|
@@ -347,7 +330,7 @@ function shouldFetchComments(config: any): any {
|
|
|
347
330
|
);
|
|
348
331
|
}
|
|
349
332
|
|
|
350
|
-
function checkStatusLabel(context: any, remoteData: any): any {
|
|
333
|
+
function checkStatusLabel(context: any, remoteData: any, shared: VerificationShared): any {
|
|
351
334
|
if (!context.expectedStatusLabel || !context.hasTriage) {
|
|
352
335
|
return null;
|
|
353
336
|
}
|
|
@@ -361,13 +344,13 @@ function checkStatusLabel(context: any, remoteData: any): any {
|
|
|
361
344
|
return null;
|
|
362
345
|
}
|
|
363
346
|
|
|
364
|
-
return failResult(CHECK_TYPE,
|
|
347
|
+
return shared.failResult(CHECK_TYPE,
|
|
365
348
|
`Expected label '${context.expectedStatusLabel}' not found on Issue #${context.issueNumber}`,
|
|
366
349
|
"check_failed"
|
|
367
350
|
);
|
|
368
351
|
}
|
|
369
352
|
|
|
370
|
-
function checkClosedIssueStatusLabels(context: any, remoteData: any): any {
|
|
353
|
+
function checkClosedIssueStatusLabels(context: any, remoteData: any, shared: VerificationShared): any {
|
|
371
354
|
if (!context.config.verify_closed_issue_has_no_status_labels) {
|
|
372
355
|
return null;
|
|
373
356
|
}
|
|
@@ -382,13 +365,13 @@ function checkClosedIssueStatusLabels(context: any, remoteData: any): any {
|
|
|
382
365
|
return null;
|
|
383
366
|
}
|
|
384
367
|
|
|
385
|
-
return failResult(CHECK_TYPE,
|
|
368
|
+
return shared.failResult(CHECK_TYPE,
|
|
386
369
|
`Closed Issue #${context.issueNumber} retains status labels: ${statusLabels.join(", ")}`,
|
|
387
370
|
"check_failed"
|
|
388
371
|
);
|
|
389
372
|
}
|
|
390
373
|
|
|
391
|
-
function checkCommentMarker(context: any, remoteData: any): any {
|
|
374
|
+
function checkCommentMarker(context: any, remoteData: any, shared: VerificationShared): any {
|
|
392
375
|
if (!context.marker) {
|
|
393
376
|
return null;
|
|
394
377
|
}
|
|
@@ -398,13 +381,13 @@ function checkCommentMarker(context: any, remoteData: any): any {
|
|
|
398
381
|
return null;
|
|
399
382
|
}
|
|
400
383
|
|
|
401
|
-
return failResult(CHECK_TYPE,
|
|
384
|
+
return shared.failResult(CHECK_TYPE,
|
|
402
385
|
`Expected comment marker '${context.marker}' not found on Issue #${context.issueNumber}`,
|
|
403
386
|
"check_failed"
|
|
404
387
|
);
|
|
405
388
|
}
|
|
406
389
|
|
|
407
|
-
function checkPrCommentMarker(context: any, remoteData: any): any {
|
|
390
|
+
function checkPrCommentMarker(context: any, remoteData: any, shared: VerificationShared): any {
|
|
408
391
|
if (!context.prMarker) {
|
|
409
392
|
return null;
|
|
410
393
|
}
|
|
@@ -414,19 +397,19 @@ function checkPrCommentMarker(context: any, remoteData: any): any {
|
|
|
414
397
|
return null;
|
|
415
398
|
}
|
|
416
399
|
|
|
417
|
-
return failResult(CHECK_TYPE,
|
|
400
|
+
return shared.failResult(CHECK_TYPE,
|
|
418
401
|
`Expected PR comment marker '${context.prMarker}' not found on PR #${context.prNumber}`,
|
|
419
402
|
"check_failed"
|
|
420
403
|
);
|
|
421
404
|
}
|
|
422
405
|
|
|
423
|
-
function checkPrCommentLastCommit(context: any, remoteData: any): any {
|
|
406
|
+
function checkPrCommentLastCommit(context: any, remoteData: any, shared: VerificationShared): any {
|
|
424
407
|
if (!context.config.verify_pr_comment_last_commit_matches_head) {
|
|
425
408
|
return null;
|
|
426
409
|
}
|
|
427
410
|
|
|
428
411
|
if (!context.prMarker) {
|
|
429
|
-
return failResult(CHECK_TYPE,
|
|
412
|
+
return shared.failResult(CHECK_TYPE,
|
|
430
413
|
"verify_pr_comment_last_commit_matches_head requires expected_pr_comment_marker",
|
|
431
414
|
"check_failed"
|
|
432
415
|
);
|
|
@@ -434,7 +417,7 @@ function checkPrCommentLastCommit(context: any, remoteData: any): any {
|
|
|
434
417
|
|
|
435
418
|
const comment = findCommentByMarker(remoteData.prComments, context.prMarker);
|
|
436
419
|
if (!comment) {
|
|
437
|
-
return failResult(CHECK_TYPE,
|
|
420
|
+
return shared.failResult(CHECK_TYPE,
|
|
438
421
|
`Expected PR comment marker '${context.prMarker}' not found on PR #${context.prNumber}`,
|
|
439
422
|
"check_failed"
|
|
440
423
|
);
|
|
@@ -442,33 +425,33 @@ function checkPrCommentLastCommit(context: any, remoteData: any): any {
|
|
|
442
425
|
|
|
443
426
|
const match = String(comment.body || "").match(/<!--\s*last-commit:\s*([0-9a-f]{7,40})\s*-->/i);
|
|
444
427
|
if (!match) {
|
|
445
|
-
return failResult(CHECK_TYPE,
|
|
428
|
+
return shared.failResult(CHECK_TYPE,
|
|
446
429
|
`PR #${context.prNumber} summary comment is missing '<!-- last-commit: <sha> -->' metadata`,
|
|
447
430
|
"check_failed"
|
|
448
431
|
);
|
|
449
432
|
}
|
|
450
433
|
|
|
451
434
|
const expectedHead = String(remoteData.prHeadSha || "").trim();
|
|
452
|
-
if (!expectedHead) return blockedResult(CHECK_TYPE, "Unable to resolve the PR head SHA", "network_error");
|
|
435
|
+
if (!expectedHead) return shared.blockedResult(CHECK_TYPE, "Unable to resolve the PR head SHA", "network_error");
|
|
453
436
|
const actualHead = match[1]!.trim();
|
|
454
437
|
if (expectedHead === actualHead) {
|
|
455
438
|
return null;
|
|
456
439
|
}
|
|
457
440
|
|
|
458
|
-
return failResult(CHECK_TYPE,
|
|
441
|
+
return shared.failResult(CHECK_TYPE,
|
|
459
442
|
`PR #${context.prNumber} summary comment last-commit metadata mismatch: expected ${expectedHead}, got ${actualHead}`,
|
|
460
443
|
"check_failed"
|
|
461
444
|
);
|
|
462
445
|
}
|
|
463
446
|
|
|
464
|
-
function checkPrCommentRequiredPatterns(context: any, remoteData: any): any {
|
|
447
|
+
function checkPrCommentRequiredPatterns(context: any, remoteData: any, shared: VerificationShared): any {
|
|
465
448
|
const patterns = context.config.expected_pr_comment_required_patterns || [];
|
|
466
449
|
if (!Array.isArray(patterns) || patterns.length === 0) {
|
|
467
450
|
return null;
|
|
468
451
|
}
|
|
469
452
|
|
|
470
453
|
if (!context.prMarker) {
|
|
471
|
-
return failResult(CHECK_TYPE,
|
|
454
|
+
return shared.failResult(CHECK_TYPE,
|
|
472
455
|
"expected_pr_comment_required_patterns requires expected_pr_comment_marker",
|
|
473
456
|
"check_failed"
|
|
474
457
|
);
|
|
@@ -476,7 +459,7 @@ function checkPrCommentRequiredPatterns(context: any, remoteData: any): any {
|
|
|
476
459
|
|
|
477
460
|
const comment = findCommentByMarker(remoteData.prComments, context.prMarker);
|
|
478
461
|
if (!comment) {
|
|
479
|
-
return failResult(CHECK_TYPE,
|
|
462
|
+
return shared.failResult(CHECK_TYPE,
|
|
480
463
|
`Expected PR comment marker '${context.prMarker}' not found on PR #${context.prNumber}`,
|
|
481
464
|
"check_failed"
|
|
482
465
|
);
|
|
@@ -486,7 +469,7 @@ function checkPrCommentRequiredPatterns(context: any, remoteData: any): any {
|
|
|
486
469
|
for (const pattern of patterns) {
|
|
487
470
|
const regex = new RegExp(pattern, "m");
|
|
488
471
|
if (!regex.test(body)) {
|
|
489
|
-
return failResult(CHECK_TYPE,
|
|
472
|
+
return shared.failResult(CHECK_TYPE,
|
|
490
473
|
`PR #${context.prNumber} summary comment is missing required pattern: ${pattern}`,
|
|
491
474
|
"check_failed"
|
|
492
475
|
);
|
|
@@ -496,31 +479,54 @@ function checkPrCommentRequiredPatterns(context: any, remoteData: any): any {
|
|
|
496
479
|
return null;
|
|
497
480
|
}
|
|
498
481
|
|
|
499
|
-
function checkCommentContent(context: any, remoteData: any): any {
|
|
482
|
+
function checkCommentContent(context: any, remoteData: any, shared: VerificationShared): any {
|
|
500
483
|
if (!context.config.verify_comment_content) {
|
|
501
484
|
return null;
|
|
502
485
|
}
|
|
503
486
|
|
|
504
487
|
if (!context.marker) {
|
|
505
|
-
return failResult(CHECK_TYPE, "verify_comment_content requires expected_comment_marker", "check_failed");
|
|
488
|
+
return shared.failResult(CHECK_TYPE, "verify_comment_content requires expected_comment_marker", "check_failed");
|
|
506
489
|
}
|
|
507
490
|
|
|
508
|
-
if (!context.artifactPath || !safeStat(context.artifactPath)) {
|
|
509
|
-
return failResult(CHECK_TYPE,
|
|
491
|
+
if (!context.artifactPath || !shared.safeStat(context.artifactPath)) {
|
|
492
|
+
return shared.failResult(CHECK_TYPE,
|
|
510
493
|
`Artifact not found for comment verification: ${context.artifactFile || "(missing artifactFile)"}`,
|
|
511
494
|
"check_failed"
|
|
512
495
|
);
|
|
513
496
|
}
|
|
514
497
|
|
|
515
498
|
const comment = findCommentByMarker(remoteData.comments, context.marker);
|
|
516
|
-
|
|
517
|
-
|
|
499
|
+
let localContent: string;
|
|
500
|
+
let commentContent: string;
|
|
501
|
+
try {
|
|
502
|
+
const localCanonical = canonicalizeCommentBody(fs.readFileSync(context.artifactPath, "utf8"));
|
|
503
|
+
const commentCanonical = canonicalizeCommentBody(extractCommentBody(comment?.body || ""));
|
|
504
|
+
if (!localCanonical.ok) {
|
|
505
|
+
return shared.failResult(CHECK_TYPE,
|
|
506
|
+
`Comment content cannot be canonicalized for '${path.basename(context.artifactPath, path.extname(context.artifactPath))}': ${localCanonical.error.message}`,
|
|
507
|
+
"check_failed"
|
|
508
|
+
);
|
|
509
|
+
}
|
|
510
|
+
if (!commentCanonical.ok) {
|
|
511
|
+
return shared.failResult(CHECK_TYPE,
|
|
512
|
+
`Comment content cannot be canonicalized for '${path.basename(context.artifactPath, path.extname(context.artifactPath))}': ${commentCanonical.error.message}`,
|
|
513
|
+
"check_failed"
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
localContent = shared.normalizeContent(localCanonical.value);
|
|
517
|
+
commentContent = shared.normalizeContent(commentCanonical.value);
|
|
518
|
+
} catch (error) {
|
|
519
|
+
return shared.failResult(CHECK_TYPE,
|
|
520
|
+
`Comment content cannot be read for '${path.basename(context.artifactPath, path.extname(context.artifactPath))}': ${error instanceof Error ? error.message : String(error)}`,
|
|
521
|
+
"check_failed"
|
|
522
|
+
);
|
|
523
|
+
}
|
|
518
524
|
|
|
519
525
|
if (localContent === commentContent) {
|
|
520
526
|
return null;
|
|
521
527
|
}
|
|
522
528
|
|
|
523
|
-
return failResult(CHECK_TYPE,
|
|
529
|
+
return shared.failResult(CHECK_TYPE,
|
|
524
530
|
buildCommentContentMismatchMessage(
|
|
525
531
|
path.basename(context.artifactPath, path.extname(context.artifactPath)),
|
|
526
532
|
context.issueNumber,
|
|
@@ -531,7 +537,7 @@ function checkCommentContent(context: any, remoteData: any): any {
|
|
|
531
537
|
);
|
|
532
538
|
}
|
|
533
539
|
|
|
534
|
-
function checkTaskCommentContent(context: any, remoteData: any): any {
|
|
540
|
+
function checkTaskCommentContent(context: any, remoteData: any, shared: VerificationShared): any {
|
|
535
541
|
if (!context.config.verify_task_comment_content) {
|
|
536
542
|
return null;
|
|
537
543
|
}
|
|
@@ -539,26 +545,33 @@ function checkTaskCommentContent(context: any, remoteData: any): any {
|
|
|
539
545
|
const taskMarker = `<!-- sync-issue:${context.task.metadata.id}:task -->`;
|
|
540
546
|
const comment = findCommentByMarker(remoteData.comments, taskMarker);
|
|
541
547
|
if (!comment) {
|
|
542
|
-
return failResult(CHECK_TYPE,
|
|
548
|
+
return shared.failResult(CHECK_TYPE,
|
|
543
549
|
`Expected comment marker '${taskMarker}' not found on Issue #${context.issueNumber}`,
|
|
544
550
|
"check_failed"
|
|
545
551
|
);
|
|
546
552
|
}
|
|
547
553
|
|
|
548
|
-
const
|
|
549
|
-
|
|
554
|
+
const expectedTaskBody = buildExpectedTaskBody(context.task.content, shared);
|
|
555
|
+
if (expectedTaskBody === null) {
|
|
556
|
+
return shared.failResult(CHECK_TYPE,
|
|
557
|
+
"Task content cannot be rendered safely for comment verification",
|
|
558
|
+
"check_failed"
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
const expectedBody = shared.normalizeContent(expectedTaskBody);
|
|
562
|
+
const commentBody = shared.normalizeContent(extractCommentBody(comment.body || ""));
|
|
550
563
|
|
|
551
564
|
if (expectedBody === commentBody) {
|
|
552
565
|
return null;
|
|
553
566
|
}
|
|
554
567
|
|
|
555
|
-
return failResult(CHECK_TYPE,
|
|
568
|
+
return shared.failResult(CHECK_TYPE,
|
|
556
569
|
buildCommentContentMismatchMessage("task", context.issueNumber, expectedBody, commentBody),
|
|
557
570
|
"check_failed"
|
|
558
571
|
);
|
|
559
572
|
}
|
|
560
573
|
|
|
561
|
-
function checkPrTypeLabel(context: any, remoteData: any): any {
|
|
574
|
+
function checkPrTypeLabel(context: any, remoteData: any, shared: VerificationShared): any {
|
|
562
575
|
if (!context.config.verify_pr_type_label || !context.hasTriage || !context.prNumber || !remoteData.prLabels) {
|
|
563
576
|
return null;
|
|
564
577
|
}
|
|
@@ -572,13 +585,13 @@ function checkPrTypeLabel(context: any, remoteData: any): any {
|
|
|
572
585
|
return null;
|
|
573
586
|
}
|
|
574
587
|
|
|
575
|
-
return failResult(CHECK_TYPE,
|
|
588
|
+
return shared.failResult(CHECK_TYPE,
|
|
576
589
|
`Expected type label '${expectedLabel}' not found on PR #${context.prNumber}`,
|
|
577
590
|
"check_failed"
|
|
578
591
|
);
|
|
579
592
|
}
|
|
580
593
|
|
|
581
|
-
function checkInLabelsMatchPr(context: any, remoteData: any): any {
|
|
594
|
+
function checkInLabelsMatchPr(context: any, remoteData: any, shared: VerificationShared): any {
|
|
582
595
|
if (!context.config.verify_in_labels_match_pr || !context.hasTriage || !context.prNumber || !remoteData.prLabels) {
|
|
583
596
|
return null;
|
|
584
597
|
}
|
|
@@ -594,22 +607,22 @@ function checkInLabelsMatchPr(context: any, remoteData: any): any {
|
|
|
594
607
|
return null;
|
|
595
608
|
}
|
|
596
609
|
|
|
597
|
-
return failResult(CHECK_TYPE,
|
|
610
|
+
return shared.failResult(CHECK_TYPE,
|
|
598
611
|
`in: labels mismatch — PR #${context.prNumber} has [${formatLabelList(prInLabels)}], Issue #${context.issueNumber} has [${formatLabelList(issueInLabels)}]`,
|
|
599
612
|
"check_failed"
|
|
600
613
|
);
|
|
601
614
|
}
|
|
602
615
|
|
|
603
|
-
function checkInLabelsComputed(context: any, remoteData: any): any {
|
|
616
|
+
function checkInLabelsComputed(context: any, remoteData: any, shared: VerificationShared): any {
|
|
604
617
|
if (!context.config.verify_in_labels_computed || !context.hasTriage) {
|
|
605
618
|
return null;
|
|
606
619
|
}
|
|
607
620
|
|
|
608
|
-
const expectedInLabels = computeExpectedInLabels(context.taskDir,
|
|
621
|
+
const expectedInLabels = computeExpectedInLabels(context.taskDir, remoteData.repositoryLabels, remoteData.inLabelMapping, shared);
|
|
609
622
|
if (!expectedInLabels.ok) {
|
|
610
623
|
return expectedInLabels.type === "check_failed"
|
|
611
|
-
? failResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type)
|
|
612
|
-
: blockedResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type);
|
|
624
|
+
? shared.failResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type)
|
|
625
|
+
: shared.blockedResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type);
|
|
613
626
|
}
|
|
614
627
|
|
|
615
628
|
if (expectedInLabels.mode === "skipped") {
|
|
@@ -624,19 +637,19 @@ function checkInLabelsComputed(context: any, remoteData: any): any {
|
|
|
624
637
|
return null;
|
|
625
638
|
}
|
|
626
639
|
|
|
627
|
-
return failResult(
|
|
640
|
+
return shared.failResult(
|
|
628
641
|
CHECK_TYPE,
|
|
629
642
|
`Issue #${context.issueNumber} in: labels do not match committed changes: expected [${formatLabelList(expectedInLabels.labels)}], got [${formatLabelList(actualInLabels)}]`,
|
|
630
643
|
"check_failed"
|
|
631
644
|
);
|
|
632
645
|
}
|
|
633
646
|
|
|
634
|
-
function checkSyncedRequirements(context: any, remoteData: any): any {
|
|
647
|
+
function checkSyncedRequirements(context: any, remoteData: any, shared: VerificationShared): any {
|
|
635
648
|
if (!context.config.sync_checked_requirements || !context.hasTriage) {
|
|
636
649
|
return null;
|
|
637
650
|
}
|
|
638
651
|
|
|
639
|
-
const checkedRequirements = getCheckedRequirements(context.task.content);
|
|
652
|
+
const checkedRequirements = shared.getCheckedRequirements(context.task.content);
|
|
640
653
|
if (checkedRequirements.length === 0) {
|
|
641
654
|
return null;
|
|
642
655
|
}
|
|
@@ -644,13 +657,13 @@ function checkSyncedRequirements(context: any, remoteData: any): any {
|
|
|
644
657
|
const issueBody = remoteData.issue.body || "";
|
|
645
658
|
const resolution = resolveRequirementSection(
|
|
646
659
|
issueBody,
|
|
647
|
-
requirementSectionAnchors(repoRoot, context.task.metadata.type || "task")
|
|
660
|
+
requirementSectionAnchors(shared.repoRoot, context.task.metadata.type || "task")
|
|
648
661
|
);
|
|
649
662
|
if (resolution.status === "missing") {
|
|
650
663
|
return null;
|
|
651
664
|
}
|
|
652
665
|
if (resolution.status === "ambiguous") {
|
|
653
|
-
return failResult(CHECK_TYPE,
|
|
666
|
+
return shared.failResult(CHECK_TYPE,
|
|
654
667
|
`Issue #${context.issueNumber} requirements section is ambiguous`,
|
|
655
668
|
"check_failed"
|
|
656
669
|
);
|
|
@@ -663,13 +676,13 @@ function checkSyncedRequirements(context: any, remoteData: any): any {
|
|
|
663
676
|
return null;
|
|
664
677
|
}
|
|
665
678
|
|
|
666
|
-
return failResult(CHECK_TYPE,
|
|
679
|
+
return shared.failResult(CHECK_TYPE,
|
|
667
680
|
`Issue body is missing checked requirements: ${missingRequirements.join(", ")}`,
|
|
668
681
|
"check_failed"
|
|
669
682
|
);
|
|
670
683
|
}
|
|
671
684
|
|
|
672
|
-
function checkIssueType(context: any, remoteData: any): any {
|
|
685
|
+
function checkIssueType(context: any, remoteData: any, shared: VerificationShared): any {
|
|
673
686
|
if (!context.config.verify_issue_type || !context.hasPush) {
|
|
674
687
|
return null;
|
|
675
688
|
}
|
|
@@ -683,7 +696,7 @@ function checkIssueType(context: any, remoteData: any): any {
|
|
|
683
696
|
return null;
|
|
684
697
|
}
|
|
685
698
|
|
|
686
|
-
return failResult(CHECK_TYPE,
|
|
699
|
+
return shared.failResult(CHECK_TYPE,
|
|
687
700
|
`Issue #${context.issueNumber} has no Issue Type set`,
|
|
688
701
|
"check_failed"
|
|
689
702
|
);
|
|
@@ -691,7 +704,7 @@ function checkIssueType(context: any, remoteData: any): any {
|
|
|
691
704
|
|
|
692
705
|
const expectedType = mapTaskTypeToIssueType(context.task.metadata.type);
|
|
693
706
|
if (expectedType && remoteData.issueType !== expectedType) {
|
|
694
|
-
return failResult(CHECK_TYPE,
|
|
707
|
+
return shared.failResult(CHECK_TYPE,
|
|
695
708
|
`Issue #${context.issueNumber} has type '${remoteData.issueType}', expected '${expectedType}' (from task type '${context.task.metadata.type}')`,
|
|
696
709
|
"check_failed"
|
|
697
710
|
);
|
|
@@ -700,7 +713,7 @@ function checkIssueType(context: any, remoteData: any): any {
|
|
|
700
713
|
return null;
|
|
701
714
|
}
|
|
702
715
|
|
|
703
|
-
function checkIssueFields(context: any, remoteData: any): any {
|
|
716
|
+
function checkIssueFields(context: any, remoteData: any, shared: VerificationShared): any {
|
|
704
717
|
if (!context.config.verify_issue_fields || !context.hasPush) {
|
|
705
718
|
return null;
|
|
706
719
|
}
|
|
@@ -711,7 +724,7 @@ function checkIssueFields(context: any, remoteData: any): any {
|
|
|
711
724
|
|
|
712
725
|
for (const [metadataKey, fieldName] of Object.entries(FRONTMATTER_FIELD_MAP)) {
|
|
713
726
|
const expectedRaw = context.task.metadata[metadataKey];
|
|
714
|
-
if (isBlank(expectedRaw) || !remoteData.issueFields.pinnedNames.has(fieldName)) {
|
|
727
|
+
if (shared.isBlank(expectedRaw) || !remoteData.issueFields.pinnedNames.has(fieldName)) {
|
|
715
728
|
continue;
|
|
716
729
|
}
|
|
717
730
|
|
|
@@ -722,14 +735,14 @@ function checkIssueFields(context: any, remoteData: any): any {
|
|
|
722
735
|
}
|
|
723
736
|
|
|
724
737
|
if (!actual) {
|
|
725
|
-
return failResult(CHECK_TYPE,
|
|
738
|
+
return shared.failResult(CHECK_TYPE,
|
|
726
739
|
`Issue #${context.issueNumber} field '${fieldName}' is missing, expected '${expected.value}'`,
|
|
727
740
|
"check_failed"
|
|
728
741
|
);
|
|
729
742
|
}
|
|
730
743
|
|
|
731
744
|
if (actual.kind !== expected.kind || actual.value !== expected.value) {
|
|
732
|
-
return failResult(CHECK_TYPE,
|
|
745
|
+
return shared.failResult(CHECK_TYPE,
|
|
733
746
|
`Issue #${context.issueNumber} field '${fieldName}' is '${actual.value}', expected '${expected.value}'`,
|
|
734
747
|
"check_failed"
|
|
735
748
|
);
|
|
@@ -739,13 +752,13 @@ function checkIssueFields(context: any, remoteData: any): any {
|
|
|
739
752
|
return null;
|
|
740
753
|
}
|
|
741
754
|
|
|
742
|
-
function checkPrAssignee(context: any, remoteData: any): any {
|
|
755
|
+
function checkPrAssignee(context: any, remoteData: any, shared: VerificationShared): any {
|
|
743
756
|
if (!context.config.verify_pr_assignee || !context.hasPush || !context.prNumber) {
|
|
744
757
|
return null;
|
|
745
758
|
}
|
|
746
759
|
|
|
747
760
|
if (!remoteData.prAssignees || remoteData.prAssignees.length === 0) {
|
|
748
|
-
return failResult(CHECK_TYPE,
|
|
761
|
+
return shared.failResult(CHECK_TYPE,
|
|
749
762
|
`PR #${context.prNumber} has no assignee`,
|
|
750
763
|
"check_failed"
|
|
751
764
|
);
|
|
@@ -754,20 +767,20 @@ function checkPrAssignee(context: any, remoteData: any): any {
|
|
|
754
767
|
return null;
|
|
755
768
|
}
|
|
756
769
|
|
|
757
|
-
function checkMilestone(context: any, remoteData: any): any {
|
|
770
|
+
function checkMilestone(context: any, remoteData: any, shared: VerificationShared): any {
|
|
758
771
|
if (!context.config.verify_milestone || !context.hasTriage) {
|
|
759
772
|
return null;
|
|
760
773
|
}
|
|
761
774
|
|
|
762
775
|
if (!remoteData.issue?.milestone?.title) {
|
|
763
|
-
return failResult(CHECK_TYPE,
|
|
776
|
+
return shared.failResult(CHECK_TYPE,
|
|
764
777
|
`Issue #${context.issueNumber} has no milestone set`,
|
|
765
778
|
"check_failed"
|
|
766
779
|
);
|
|
767
780
|
}
|
|
768
781
|
|
|
769
782
|
if (context.prNumber && remoteData.prMilestone !== undefined && !remoteData.prMilestone?.title) {
|
|
770
|
-
return failResult(CHECK_TYPE,
|
|
783
|
+
return shared.failResult(CHECK_TYPE,
|
|
771
784
|
`PR #${context.prNumber} has no milestone set`,
|
|
772
785
|
"check_failed"
|
|
773
786
|
);
|
|
@@ -776,13 +789,13 @@ function checkMilestone(context: any, remoteData: any): any {
|
|
|
776
789
|
if (context.config.verify_milestone_specific) {
|
|
777
790
|
const issueTitle = remoteData.issue.milestone.title;
|
|
778
791
|
if (VERSION_LINE_REGEX.test(issueTitle)) {
|
|
779
|
-
return failResult(CHECK_TYPE,
|
|
792
|
+
return shared.failResult(CHECK_TYPE,
|
|
780
793
|
`Issue #${context.issueNumber} milestone '${issueTitle}' is a release line; narrow to a specific version (e.g. ${issueTitle.replace(/\.x$/, ".N")}) before continuing`,
|
|
781
794
|
"check_failed"
|
|
782
795
|
);
|
|
783
796
|
}
|
|
784
797
|
if (context.prNumber && remoteData.prMilestone?.title && VERSION_LINE_REGEX.test(remoteData.prMilestone.title)) {
|
|
785
|
-
return failResult(CHECK_TYPE,
|
|
798
|
+
return shared.failResult(CHECK_TYPE,
|
|
786
799
|
`PR #${context.prNumber} milestone '${remoteData.prMilestone.title}' is a release line; narrow to a specific version before continuing`,
|
|
787
800
|
"check_failed"
|
|
788
801
|
);
|
|
@@ -843,19 +856,20 @@ function extractCommentBody(commentBody: any): any {
|
|
|
843
856
|
return lines.slice(start, end).join("\n");
|
|
844
857
|
}
|
|
845
858
|
|
|
846
|
-
function buildExpectedTaskBody(taskContent: any): any {
|
|
859
|
+
function buildExpectedTaskBody(taskContent: any, shared: VerificationShared): any {
|
|
847
860
|
const frontmatterMatch = taskContent.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
|
848
861
|
if (!frontmatterMatch) {
|
|
849
|
-
return taskContent.trim();
|
|
862
|
+
return sanitizeCommentContent(taskContent.trim());
|
|
850
863
|
}
|
|
851
864
|
|
|
852
|
-
const body = taskContent.slice(frontmatterMatch[0].length).trim();
|
|
865
|
+
const body = sanitizeCommentContent(taskContent.slice(frontmatterMatch[0].length).trim());
|
|
866
|
+
if (body === null) {
|
|
867
|
+
return null;
|
|
868
|
+
}
|
|
853
869
|
return [
|
|
854
|
-
buildTaskFrontmatterSummary(),
|
|
870
|
+
buildTaskFrontmatterSummary(shared),
|
|
855
871
|
"",
|
|
856
|
-
"
|
|
857
|
-
frontmatterMatch[0].trim(),
|
|
858
|
-
"```",
|
|
872
|
+
renderSafeCodeFence(frontmatterMatch[0].trim(), "yaml"),
|
|
859
873
|
"",
|
|
860
874
|
"</details>",
|
|
861
875
|
"",
|
|
@@ -863,8 +877,8 @@ function buildExpectedTaskBody(taskContent: any): any {
|
|
|
863
877
|
].join("\n").trim();
|
|
864
878
|
}
|
|
865
879
|
|
|
866
|
-
function buildTaskFrontmatterSummary(): any {
|
|
867
|
-
const language = loadProjectLanguage();
|
|
880
|
+
function buildTaskFrontmatterSummary(shared: VerificationShared): any {
|
|
881
|
+
const language = loadProjectLanguage(shared);
|
|
868
882
|
if (language === "en" || language === "en-US") {
|
|
869
883
|
return "<details><summary>Metadata (frontmatter)</summary>";
|
|
870
884
|
}
|
|
@@ -872,13 +886,13 @@ function buildTaskFrontmatterSummary(): any {
|
|
|
872
886
|
return "<details><summary>元数据 (frontmatter)</summary>";
|
|
873
887
|
}
|
|
874
888
|
|
|
875
|
-
function loadProjectLanguage(): any {
|
|
889
|
+
function loadProjectLanguage(shared: VerificationShared): any {
|
|
876
890
|
const override = process.env.VALIDATE_ARTIFACT_LANGUAGE;
|
|
877
|
-
if (!isBlank(override)) {
|
|
891
|
+
if (!shared.isBlank(override)) {
|
|
878
892
|
return String(override).trim();
|
|
879
893
|
}
|
|
880
894
|
|
|
881
|
-
const configPath = path.join(repoRoot, ".agents", ".airc.json");
|
|
895
|
+
const configPath = path.join(shared.repoRoot, ".agents", ".airc.json");
|
|
882
896
|
if (!fs.existsSync(configPath)) {
|
|
883
897
|
return "";
|
|
884
898
|
}
|
|
@@ -1015,8 +1029,8 @@ function formatLabelList(labels: any): any {
|
|
|
1015
1029
|
return labels.length > 0 ? labels.join(", ") : "none";
|
|
1016
1030
|
}
|
|
1017
1031
|
|
|
1018
|
-
function computeExpectedInLabels(taskDir: any,
|
|
1019
|
-
const task = loadTask(taskDir);
|
|
1032
|
+
function computeExpectedInLabels(taskDir: any, repositoryLabels: string[], mappingOverride: Record<string, string[]> | undefined, shared: VerificationShared): any {
|
|
1033
|
+
const task = shared.loadTask(taskDir);
|
|
1020
1034
|
if (!task.ok) {
|
|
1021
1035
|
return task;
|
|
1022
1036
|
}
|
|
@@ -1034,32 +1048,16 @@ function computeExpectedInLabels(taskDir: any, repository: any): any {
|
|
|
1034
1048
|
.map((value) => value.trim())
|
|
1035
1049
|
.filter(Boolean);
|
|
1036
1050
|
|
|
1037
|
-
const mapping =
|
|
1038
|
-
if (
|
|
1039
|
-
return mapping;
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
if (Object.keys(mapping.value ?? {}).length === 0) {
|
|
1051
|
+
const mapping = mappingOverride ?? {};
|
|
1052
|
+
if (Object.keys(mapping).length === 0) {
|
|
1043
1053
|
return { ok: true, labels: [], mode: "mapped" };
|
|
1044
1054
|
}
|
|
1045
1055
|
|
|
1046
|
-
const client = createGitHubClient();
|
|
1047
|
-
const repoLabelsResult = withRetry(() => client.json([
|
|
1048
|
-
"api", "--paginate", "--slurp", `repos/${repository}/labels?per_page=100`
|
|
1049
|
-
], { cwd: taskDir }));
|
|
1050
|
-
if (!repoLabelsResult.ok) {
|
|
1051
|
-
return repoLabelsResult;
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
const repositoryLabels = validateRepositoryLabelPayload(repoLabelsResult.value);
|
|
1055
|
-
if (!repositoryLabels.ok) {
|
|
1056
|
-
return { ok: false, type: "check_failed", message: repositoryLabels.error.message };
|
|
1057
|
-
}
|
|
1058
1056
|
const planned = planInLabelUpdate({
|
|
1059
1057
|
changedFiles,
|
|
1060
1058
|
currentLabels: [],
|
|
1061
|
-
mapping
|
|
1062
|
-
repositoryLabels: new Set(repositoryLabels
|
|
1059
|
+
mapping,
|
|
1060
|
+
repositoryLabels: new Set(repositoryLabels)
|
|
1063
1061
|
});
|
|
1064
1062
|
if (planned.error) {
|
|
1065
1063
|
return { ok: false, type: "check_failed", message: planned.error.message };
|
|
@@ -1067,8 +1065,8 @@ function computeExpectedInLabels(taskDir: any, repository: any): any {
|
|
|
1067
1065
|
return { ok: true, labels: planned.target, mode: "mapped" };
|
|
1068
1066
|
}
|
|
1069
1067
|
|
|
1070
|
-
function loadInLabelMapping(): any {
|
|
1071
|
-
const configPath = path.join(repoRoot, ".agents", ".airc.json");
|
|
1068
|
+
function loadInLabelMapping(shared: VerificationShared): any {
|
|
1069
|
+
const configPath = path.join(shared.repoRoot, ".agents", ".airc.json");
|
|
1072
1070
|
if (!fs.existsSync(configPath)) {
|
|
1073
1071
|
return { ok: true, value: {} };
|
|
1074
1072
|
}
|
|
@@ -1084,7 +1082,7 @@ function loadInLabelMapping(): any {
|
|
|
1084
1082
|
}
|
|
1085
1083
|
}
|
|
1086
1084
|
|
|
1087
|
-
// ===
|
|
1085
|
+
// === Git working tree ===
|
|
1088
1086
|
|
|
1089
1087
|
function gitText(args: any, cwd: any): any {
|
|
1090
1088
|
try {
|
|
@@ -1101,13 +1099,13 @@ function gitText(args: any, cwd: any): any {
|
|
|
1101
1099
|
}
|
|
1102
1100
|
|
|
1103
1101
|
function resolvePrHeadSha(context: any): any {
|
|
1104
|
-
const fallback = () =>
|
|
1102
|
+
const fallback = () => gitText(["rev-parse", "HEAD"], context.taskDir);
|
|
1105
1103
|
const branch = String(context.task?.metadata?.branch || "").trim();
|
|
1106
1104
|
if (!branch) {
|
|
1107
1105
|
return fallback();
|
|
1108
1106
|
}
|
|
1109
1107
|
|
|
1110
|
-
const worktreeList =
|
|
1108
|
+
const worktreeList = gitText(["worktree", "list", "--porcelain"], context.taskDir);
|
|
1111
1109
|
if (!worktreeList.ok) {
|
|
1112
1110
|
return fallback();
|
|
1113
1111
|
}
|
|
@@ -1117,7 +1115,7 @@ function resolvePrHeadSha(context: any): any {
|
|
|
1117
1115
|
return fallback();
|
|
1118
1116
|
}
|
|
1119
1117
|
|
|
1120
|
-
const headInWorktree =
|
|
1118
|
+
const headInWorktree = gitText(["rev-parse", "HEAD"], matchedWorktree);
|
|
1121
1119
|
if (!headInWorktree.ok) {
|
|
1122
1120
|
return fallback();
|
|
1123
1121
|
}
|
|
@@ -1145,10 +1143,6 @@ function findWorktreeForBranch(porcelainOutput: any, branch: any): any {
|
|
|
1145
1143
|
return null;
|
|
1146
1144
|
}
|
|
1147
1145
|
|
|
1148
|
-
function withRetry(operation: any): any {
|
|
1149
|
-
return operation();
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
1146
|
function interpolate(template: any, taskDir: any, artifactFile: any): any {
|
|
1153
1147
|
const artifactStem = artifactFile ? path.basename(artifactFile, path.extname(artifactFile)) : "";
|
|
1154
1148
|
return template
|