@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
|
@@ -6,12 +6,11 @@ import { resolvePlatformProviderContext } from "./context.js";
|
|
|
6
6
|
import { hasCheckedRequirement, resolveRequirementSection } from "./issue-metadata.js";
|
|
7
7
|
import { requirementSectionAnchors } from "./issues.js";
|
|
8
8
|
import { taskTypeLabel } from "./metadata-labels.js";
|
|
9
|
-
import { planInLabelUpdate, validateInLabelMapping
|
|
10
|
-
import { inspectGitHubPullRequest } from "./pull-requests.js";
|
|
11
|
-
import { createGitHubClient } from "./github-client.js";
|
|
9
|
+
import { planInLabelUpdate, validateInLabelMapping } from "./in-label-sync.js";
|
|
12
10
|
import { readPrDeliveryFact } from "../task/pr-delivery-fact.js";
|
|
13
11
|
import { providerError, providerOperationContext, resourceIdentityNumber, unsupportedProviderOperation } from "./provider-bridge.js";
|
|
14
12
|
import { taskIssueIdentity } from "./task-identities.js";
|
|
13
|
+
import { CONTROL_MARKER_PATTERN, canonicalizeCommentBody, renderSafeCodeFence, sanitizeMarkdownDocument } from "./comment-safety.js";
|
|
15
14
|
const CHECK_TYPE = "platform-sync";
|
|
16
15
|
const VERSION_LINE_REGEX = /^[0-9]+\.[0-9]+\.x$/;
|
|
17
16
|
const FRONTMATTER_FIELD_MAP = {
|
|
@@ -26,8 +25,6 @@ const OPTION_LOCALIZATION = {
|
|
|
26
25
|
"中": "Medium",
|
|
27
26
|
"低": "Low"
|
|
28
27
|
};
|
|
29
|
-
let activeShared = null;
|
|
30
|
-
let repoRoot = "";
|
|
31
28
|
export function getDefaults() {
|
|
32
29
|
return {
|
|
33
30
|
statusLabels: {
|
|
@@ -47,47 +44,16 @@ export function getDefaults() {
|
|
|
47
44
|
}
|
|
48
45
|
};
|
|
49
46
|
}
|
|
50
|
-
function
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
return activeShared;
|
|
55
|
-
}
|
|
56
|
-
function loadTask(...args) {
|
|
57
|
-
return getShared().loadTask(...args);
|
|
58
|
-
}
|
|
59
|
-
function getCheckedRequirements(...args) {
|
|
60
|
-
return getShared().getCheckedRequirements(...args);
|
|
61
|
-
}
|
|
62
|
-
function normalizeContent(...args) {
|
|
63
|
-
return getShared().normalizeContent(...args);
|
|
64
|
-
}
|
|
65
|
-
function isBlank(...args) {
|
|
66
|
-
return getShared().isBlank(...args);
|
|
67
|
-
}
|
|
68
|
-
function escapeRegExp(...args) {
|
|
69
|
-
return getShared().escapeRegExp(...args);
|
|
70
|
-
}
|
|
71
|
-
function passResult(...args) {
|
|
72
|
-
return getShared().passResult(...args);
|
|
73
|
-
}
|
|
74
|
-
function failResult(...args) {
|
|
75
|
-
return getShared().failResult(...args);
|
|
76
|
-
}
|
|
77
|
-
function blockedResult(...args) {
|
|
78
|
-
return getShared().blockedResult(...args);
|
|
79
|
-
}
|
|
80
|
-
function safeStat(...args) {
|
|
81
|
-
return getShared().safeStat(...args);
|
|
47
|
+
function sanitizeCommentContent(content) {
|
|
48
|
+
const result = sanitizeMarkdownDocument(content, { reservedMarkers: [CONTROL_MARKER_PATTERN] });
|
|
49
|
+
return result.ok ? result.value : null;
|
|
82
50
|
}
|
|
83
51
|
export async function check({ taskDir, config, artifactFile }, shared) {
|
|
84
|
-
|
|
85
|
-
repoRoot = shared.repoRoot;
|
|
86
|
-
const context = await buildSyncContext({ taskDir, config, artifactFile });
|
|
52
|
+
const context = await buildSyncContext({ taskDir, config, artifactFile }, shared);
|
|
87
53
|
if (context.earlyReturn) {
|
|
88
54
|
return context.earlyReturn;
|
|
89
55
|
}
|
|
90
|
-
const remoteData = await fetchRemoteData(context);
|
|
56
|
+
const remoteData = await fetchRemoteData(context, shared);
|
|
91
57
|
if (remoteData.earlyReturn) {
|
|
92
58
|
return remoteData.earlyReturn;
|
|
93
59
|
}
|
|
@@ -110,52 +76,52 @@ export async function check({ taskDir, config, artifactFile }, shared) {
|
|
|
110
76
|
checkMilestone
|
|
111
77
|
];
|
|
112
78
|
for (const subCheck of subChecks) {
|
|
113
|
-
const result = subCheck(context, remoteData);
|
|
79
|
+
const result = subCheck(context, remoteData, shared);
|
|
114
80
|
if (result) {
|
|
115
81
|
return result;
|
|
116
82
|
}
|
|
117
83
|
}
|
|
118
|
-
return passResult(CHECK_TYPE, `Platform sync checks passed for Issue ${context.issueNumber || "identity"}`);
|
|
84
|
+
return shared.passResult(CHECK_TYPE, `Platform sync checks passed for Issue ${context.issueNumber || "identity"}`);
|
|
119
85
|
}
|
|
120
|
-
async function buildSyncContext({ taskDir, config, artifactFile }) {
|
|
121
|
-
const task = loadTask(taskDir);
|
|
86
|
+
async function buildSyncContext({ taskDir, config, artifactFile }, shared) {
|
|
87
|
+
const task = shared.loadTask(taskDir);
|
|
122
88
|
if (!task.ok) {
|
|
123
|
-
return { earlyReturn: failResult(CHECK_TYPE, task.message) };
|
|
89
|
+
return { earlyReturn: shared.failResult(CHECK_TYPE, task.message) };
|
|
124
90
|
}
|
|
125
91
|
const issueIdentity = taskIssueIdentity(task.metadata);
|
|
126
92
|
const issueNumber = resourceIdentityNumber(issueIdentity);
|
|
127
93
|
const fact = readPrDeliveryFact(task.metadata);
|
|
128
94
|
if (fact.status === "invalid") {
|
|
129
|
-
return { earlyReturn: failResult(CHECK_TYPE, fact.error.message, "check_failed") };
|
|
95
|
+
return { earlyReturn: shared.failResult(CHECK_TYPE, fact.error.message, "check_failed") };
|
|
130
96
|
}
|
|
131
97
|
const prIdentity = fact.status === "valid" && fact.fact.state === "bound" ? fact.fact.identity.resource : null;
|
|
132
98
|
const prNumber = resourceIdentityNumber(prIdentity);
|
|
133
99
|
if (config.when === "issue_number_exists" && !issueIdentity) {
|
|
134
|
-
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no issue_number") };
|
|
100
|
+
return { earlyReturn: shared.passResult(CHECK_TYPE, "Skipped: task has no issue_number") };
|
|
135
101
|
}
|
|
136
102
|
if (config.when === "pr_fact_bound" && !prIdentity) {
|
|
137
|
-
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no verified bound pull request") };
|
|
103
|
+
return { earlyReturn: shared.passResult(CHECK_TYPE, "Skipped: task has no verified bound pull request") };
|
|
138
104
|
}
|
|
139
105
|
if (!issueIdentity) {
|
|
140
|
-
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: platform-sync not required for this task") };
|
|
106
|
+
return { earlyReturn: shared.passResult(CHECK_TYPE, "Skipped: platform-sync not required for this task") };
|
|
141
107
|
}
|
|
142
|
-
const loaded = await resolvePlatformProviderContext({ cwd: repoRoot });
|
|
108
|
+
const loaded = await resolvePlatformProviderContext({ cwd: shared.repoRoot });
|
|
143
109
|
const platformContext = loaded.ok ? loaded.value.context : loaded.context;
|
|
144
110
|
if (platformContext.status === "failed") {
|
|
145
|
-
return { earlyReturn: failResult(CHECK_TYPE, platformContext.error?.message || "Platform context failed", "check_failed") };
|
|
111
|
+
return { earlyReturn: shared.failResult(CHECK_TYPE, platformContext.error?.message || "Platform context failed", "check_failed") };
|
|
146
112
|
}
|
|
147
113
|
if (platformContext.status === "blocked") {
|
|
148
|
-
return { earlyReturn: blockedResult(CHECK_TYPE, platformContext.error?.message || "Platform context blocked", "network_error") };
|
|
114
|
+
return { earlyReturn: shared.blockedResult(CHECK_TYPE, platformContext.error?.message || "Platform context blocked", "network_error") };
|
|
149
115
|
}
|
|
150
116
|
if (!platformContext.platform.repository) {
|
|
151
117
|
if (platformContext.error?.code === "REMOTE_MISSING" || platformContext.error?.code === "REMOTE_INVALID") {
|
|
152
|
-
return { earlyReturn: blockedResult(CHECK_TYPE, platformContext.error.message, "network_error") };
|
|
118
|
+
return { earlyReturn: shared.blockedResult(CHECK_TYPE, platformContext.error.message, "network_error") };
|
|
153
119
|
}
|
|
154
|
-
return { earlyReturn: passResult(CHECK_TYPE, `Skipped: ${platformContext.error?.message || "platform unavailable"}`) };
|
|
120
|
+
return { earlyReturn: shared.passResult(CHECK_TYPE, `Skipped: ${platformContext.error?.message || "platform unavailable"}`) };
|
|
155
121
|
}
|
|
156
122
|
const expectedValues = resolveExpectedValues(config);
|
|
157
123
|
if (!expectedValues.ok) {
|
|
158
|
-
return { earlyReturn: failResult(CHECK_TYPE, expectedValues.message, "check_failed") };
|
|
124
|
+
return { earlyReturn: shared.failResult(CHECK_TYPE, expectedValues.message, "check_failed") };
|
|
159
125
|
}
|
|
160
126
|
const marker = expectedValues.commentMarker
|
|
161
127
|
? interpolate(expectedValues.commentMarker, taskDir, artifactFile)
|
|
@@ -174,7 +140,6 @@ async function buildSyncContext({ taskDir, config, artifactFile }) {
|
|
|
174
140
|
prIdentity,
|
|
175
141
|
issueNumber,
|
|
176
142
|
prNumber,
|
|
177
|
-
upstreamRepo: platformContext.platform.repository,
|
|
178
143
|
repoOwnerType: String(loaded.ok ? loaded.value.snapshot.metadata?.ownerType || "unknown" : "unknown"),
|
|
179
144
|
hasTriage: platformContext.capabilities.triage,
|
|
180
145
|
hasPush: platformContext.capabilities.push,
|
|
@@ -232,7 +197,7 @@ function resolveDefaultValue({ collection, key, value, configKey }) {
|
|
|
232
197
|
}
|
|
233
198
|
return { ok: true, value: resolvedValue };
|
|
234
199
|
}
|
|
235
|
-
async function fetchRemoteData(context) {
|
|
200
|
+
async function fetchRemoteData(context, shared) {
|
|
236
201
|
const provider = context.provider;
|
|
237
202
|
const operationContext = providerOperationContext(context.loadedContext, context.taskDir);
|
|
238
203
|
const facts = provider?.verification?.fetchRemoteFacts
|
|
@@ -248,8 +213,8 @@ async function fetchRemoteData(context) {
|
|
|
248
213
|
if (!facts.ok) {
|
|
249
214
|
return {
|
|
250
215
|
earlyReturn: facts.error.retryable
|
|
251
|
-
? blockedResult(CHECK_TYPE, providerError(facts.error, "PLATFORM_PROVIDER_OPERATION_FAILED").message, "network_error")
|
|
252
|
-
: failResult(CHECK_TYPE, providerError(facts.error, "PLATFORM_PROVIDER_OPERATION_FAILED").message, "check_failed")
|
|
216
|
+
? shared.blockedResult(CHECK_TYPE, providerError(facts.error, "PLATFORM_PROVIDER_OPERATION_FAILED").message, "network_error")
|
|
217
|
+
: shared.failResult(CHECK_TYPE, providerError(facts.error, "PLATFORM_PROVIDER_OPERATION_FAILED").message, "check_failed")
|
|
253
218
|
};
|
|
254
219
|
}
|
|
255
220
|
const issueSnapshot = facts.value.issue;
|
|
@@ -275,12 +240,34 @@ async function fetchRemoteData(context) {
|
|
|
275
240
|
if (!listed.ok)
|
|
276
241
|
return {
|
|
277
242
|
earlyReturn: listed.error.retryable
|
|
278
|
-
? blockedResult(CHECK_TYPE, listed.error.message, "network_error")
|
|
279
|
-
: failResult(CHECK_TYPE, listed.error.message, "check_failed")
|
|
243
|
+
? shared.blockedResult(CHECK_TYPE, listed.error.message, "network_error")
|
|
244
|
+
: shared.failResult(CHECK_TYPE, listed.error.message, "check_failed")
|
|
280
245
|
};
|
|
281
246
|
prComments = listed.value.map((comment) => ({ id: comment.id, body: comment.body }));
|
|
282
247
|
}
|
|
283
248
|
const changeRequest = facts.value.changeRequest;
|
|
249
|
+
let inLabelMapping = {};
|
|
250
|
+
let repositoryLabels = [];
|
|
251
|
+
if (context.config.verify_in_labels_computed && context.hasTriage) {
|
|
252
|
+
const mapping = loadInLabelMapping(shared);
|
|
253
|
+
if (!mapping.ok)
|
|
254
|
+
return { earlyReturn: shared.failResult(CHECK_TYPE, mapping.message, "check_failed") };
|
|
255
|
+
inLabelMapping = mapping.value;
|
|
256
|
+
if (Object.keys(inLabelMapping).length > 0) {
|
|
257
|
+
const labels = provider?.issues?.listLabels
|
|
258
|
+
? await provider.issues.listLabels({ context: operationContext })
|
|
259
|
+
: unsupportedProviderOperation(provider, "issues.listLabels");
|
|
260
|
+
if (!labels.ok) {
|
|
261
|
+
const error = providerError(labels.error, "PLATFORM_PROVIDER_OPERATION_FAILED");
|
|
262
|
+
return {
|
|
263
|
+
earlyReturn: error.retryable
|
|
264
|
+
? shared.blockedResult(CHECK_TYPE, `${error.code}: ${error.message}`, "network_error")
|
|
265
|
+
: shared.failResult(CHECK_TYPE, `${error.code}: ${error.message}`, "check_failed")
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
repositoryLabels = labels.value;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
284
271
|
return {
|
|
285
272
|
issue,
|
|
286
273
|
comments: facts.value.comments.map((comment) => ({ id: comment.id, body: comment.body })),
|
|
@@ -294,7 +281,9 @@ async function fetchRemoteData(context) {
|
|
|
294
281
|
? (changeRequest.milestone ? { title: changeRequest.milestone } : null)
|
|
295
282
|
: undefined,
|
|
296
283
|
prAssignees: changeRequest?.assignees,
|
|
297
|
-
prHeadSha: changeRequest?.headSha
|
|
284
|
+
prHeadSha: changeRequest?.headSha,
|
|
285
|
+
inLabelMapping,
|
|
286
|
+
repositoryLabels
|
|
298
287
|
};
|
|
299
288
|
}
|
|
300
289
|
function mapTaskTypeToLabel(taskType) {
|
|
@@ -309,7 +298,7 @@ function shouldFetchComments(config) {
|
|
|
309
298
|
|| config.verify_comment_content
|
|
310
299
|
|| config.verify_task_comment_content);
|
|
311
300
|
}
|
|
312
|
-
function checkStatusLabel(context, remoteData) {
|
|
301
|
+
function checkStatusLabel(context, remoteData, shared) {
|
|
313
302
|
if (!context.expectedStatusLabel || !context.hasTriage) {
|
|
314
303
|
return null;
|
|
315
304
|
}
|
|
@@ -320,9 +309,9 @@ function checkStatusLabel(context, remoteData) {
|
|
|
320
309
|
if (labels.includes(context.expectedStatusLabel)) {
|
|
321
310
|
return null;
|
|
322
311
|
}
|
|
323
|
-
return failResult(CHECK_TYPE, `Expected label '${context.expectedStatusLabel}' not found on Issue #${context.issueNumber}`, "check_failed");
|
|
312
|
+
return shared.failResult(CHECK_TYPE, `Expected label '${context.expectedStatusLabel}' not found on Issue #${context.issueNumber}`, "check_failed");
|
|
324
313
|
}
|
|
325
|
-
function checkClosedIssueStatusLabels(context, remoteData) {
|
|
314
|
+
function checkClosedIssueStatusLabels(context, remoteData, shared) {
|
|
326
315
|
if (!context.config.verify_closed_issue_has_no_status_labels) {
|
|
327
316
|
return null;
|
|
328
317
|
}
|
|
@@ -334,9 +323,9 @@ function checkClosedIssueStatusLabels(context, remoteData) {
|
|
|
334
323
|
if (statusLabels.length === 0) {
|
|
335
324
|
return null;
|
|
336
325
|
}
|
|
337
|
-
return failResult(CHECK_TYPE, `Closed Issue #${context.issueNumber} retains status labels: ${statusLabels.join(", ")}`, "check_failed");
|
|
326
|
+
return shared.failResult(CHECK_TYPE, `Closed Issue #${context.issueNumber} retains status labels: ${statusLabels.join(", ")}`, "check_failed");
|
|
338
327
|
}
|
|
339
|
-
function checkCommentMarker(context, remoteData) {
|
|
328
|
+
function checkCommentMarker(context, remoteData, shared) {
|
|
340
329
|
if (!context.marker) {
|
|
341
330
|
return null;
|
|
342
331
|
}
|
|
@@ -344,9 +333,9 @@ function checkCommentMarker(context, remoteData) {
|
|
|
344
333
|
if (comment) {
|
|
345
334
|
return null;
|
|
346
335
|
}
|
|
347
|
-
return failResult(CHECK_TYPE, `Expected comment marker '${context.marker}' not found on Issue #${context.issueNumber}`, "check_failed");
|
|
336
|
+
return shared.failResult(CHECK_TYPE, `Expected comment marker '${context.marker}' not found on Issue #${context.issueNumber}`, "check_failed");
|
|
348
337
|
}
|
|
349
|
-
function checkPrCommentMarker(context, remoteData) {
|
|
338
|
+
function checkPrCommentMarker(context, remoteData, shared) {
|
|
350
339
|
if (!context.prMarker) {
|
|
351
340
|
return null;
|
|
352
341
|
}
|
|
@@ -354,88 +343,107 @@ function checkPrCommentMarker(context, remoteData) {
|
|
|
354
343
|
if (comment) {
|
|
355
344
|
return null;
|
|
356
345
|
}
|
|
357
|
-
return failResult(CHECK_TYPE, `Expected PR comment marker '${context.prMarker}' not found on PR #${context.prNumber}`, "check_failed");
|
|
346
|
+
return shared.failResult(CHECK_TYPE, `Expected PR comment marker '${context.prMarker}' not found on PR #${context.prNumber}`, "check_failed");
|
|
358
347
|
}
|
|
359
|
-
function checkPrCommentLastCommit(context, remoteData) {
|
|
348
|
+
function checkPrCommentLastCommit(context, remoteData, shared) {
|
|
360
349
|
if (!context.config.verify_pr_comment_last_commit_matches_head) {
|
|
361
350
|
return null;
|
|
362
351
|
}
|
|
363
352
|
if (!context.prMarker) {
|
|
364
|
-
return failResult(CHECK_TYPE, "verify_pr_comment_last_commit_matches_head requires expected_pr_comment_marker", "check_failed");
|
|
353
|
+
return shared.failResult(CHECK_TYPE, "verify_pr_comment_last_commit_matches_head requires expected_pr_comment_marker", "check_failed");
|
|
365
354
|
}
|
|
366
355
|
const comment = findCommentByMarker(remoteData.prComments, context.prMarker);
|
|
367
356
|
if (!comment) {
|
|
368
|
-
return failResult(CHECK_TYPE, `Expected PR comment marker '${context.prMarker}' not found on PR #${context.prNumber}`, "check_failed");
|
|
357
|
+
return shared.failResult(CHECK_TYPE, `Expected PR comment marker '${context.prMarker}' not found on PR #${context.prNumber}`, "check_failed");
|
|
369
358
|
}
|
|
370
359
|
const match = String(comment.body || "").match(/<!--\s*last-commit:\s*([0-9a-f]{7,40})\s*-->/i);
|
|
371
360
|
if (!match) {
|
|
372
|
-
return failResult(CHECK_TYPE, `PR #${context.prNumber} summary comment is missing '<!-- last-commit: <sha> -->' metadata`, "check_failed");
|
|
361
|
+
return shared.failResult(CHECK_TYPE, `PR #${context.prNumber} summary comment is missing '<!-- last-commit: <sha> -->' metadata`, "check_failed");
|
|
373
362
|
}
|
|
374
363
|
const expectedHead = String(remoteData.prHeadSha || "").trim();
|
|
375
364
|
if (!expectedHead)
|
|
376
|
-
return blockedResult(CHECK_TYPE, "Unable to resolve the PR head SHA", "network_error");
|
|
365
|
+
return shared.blockedResult(CHECK_TYPE, "Unable to resolve the PR head SHA", "network_error");
|
|
377
366
|
const actualHead = match[1].trim();
|
|
378
367
|
if (expectedHead === actualHead) {
|
|
379
368
|
return null;
|
|
380
369
|
}
|
|
381
|
-
return failResult(CHECK_TYPE, `PR #${context.prNumber} summary comment last-commit metadata mismatch: expected ${expectedHead}, got ${actualHead}`, "check_failed");
|
|
370
|
+
return shared.failResult(CHECK_TYPE, `PR #${context.prNumber} summary comment last-commit metadata mismatch: expected ${expectedHead}, got ${actualHead}`, "check_failed");
|
|
382
371
|
}
|
|
383
|
-
function checkPrCommentRequiredPatterns(context, remoteData) {
|
|
372
|
+
function checkPrCommentRequiredPatterns(context, remoteData, shared) {
|
|
384
373
|
const patterns = context.config.expected_pr_comment_required_patterns || [];
|
|
385
374
|
if (!Array.isArray(patterns) || patterns.length === 0) {
|
|
386
375
|
return null;
|
|
387
376
|
}
|
|
388
377
|
if (!context.prMarker) {
|
|
389
|
-
return failResult(CHECK_TYPE, "expected_pr_comment_required_patterns requires expected_pr_comment_marker", "check_failed");
|
|
378
|
+
return shared.failResult(CHECK_TYPE, "expected_pr_comment_required_patterns requires expected_pr_comment_marker", "check_failed");
|
|
390
379
|
}
|
|
391
380
|
const comment = findCommentByMarker(remoteData.prComments, context.prMarker);
|
|
392
381
|
if (!comment) {
|
|
393
|
-
return failResult(CHECK_TYPE, `Expected PR comment marker '${context.prMarker}' not found on PR #${context.prNumber}`, "check_failed");
|
|
382
|
+
return shared.failResult(CHECK_TYPE, `Expected PR comment marker '${context.prMarker}' not found on PR #${context.prNumber}`, "check_failed");
|
|
394
383
|
}
|
|
395
384
|
const body = String(comment.body || "");
|
|
396
385
|
for (const pattern of patterns) {
|
|
397
386
|
const regex = new RegExp(pattern, "m");
|
|
398
387
|
if (!regex.test(body)) {
|
|
399
|
-
return failResult(CHECK_TYPE, `PR #${context.prNumber} summary comment is missing required pattern: ${pattern}`, "check_failed");
|
|
388
|
+
return shared.failResult(CHECK_TYPE, `PR #${context.prNumber} summary comment is missing required pattern: ${pattern}`, "check_failed");
|
|
400
389
|
}
|
|
401
390
|
}
|
|
402
391
|
return null;
|
|
403
392
|
}
|
|
404
|
-
function checkCommentContent(context, remoteData) {
|
|
393
|
+
function checkCommentContent(context, remoteData, shared) {
|
|
405
394
|
if (!context.config.verify_comment_content) {
|
|
406
395
|
return null;
|
|
407
396
|
}
|
|
408
397
|
if (!context.marker) {
|
|
409
|
-
return failResult(CHECK_TYPE, "verify_comment_content requires expected_comment_marker", "check_failed");
|
|
398
|
+
return shared.failResult(CHECK_TYPE, "verify_comment_content requires expected_comment_marker", "check_failed");
|
|
410
399
|
}
|
|
411
|
-
if (!context.artifactPath || !safeStat(context.artifactPath)) {
|
|
412
|
-
return failResult(CHECK_TYPE, `Artifact not found for comment verification: ${context.artifactFile || "(missing artifactFile)"}`, "check_failed");
|
|
400
|
+
if (!context.artifactPath || !shared.safeStat(context.artifactPath)) {
|
|
401
|
+
return shared.failResult(CHECK_TYPE, `Artifact not found for comment verification: ${context.artifactFile || "(missing artifactFile)"}`, "check_failed");
|
|
413
402
|
}
|
|
414
403
|
const comment = findCommentByMarker(remoteData.comments, context.marker);
|
|
415
|
-
|
|
416
|
-
|
|
404
|
+
let localContent;
|
|
405
|
+
let commentContent;
|
|
406
|
+
try {
|
|
407
|
+
const localCanonical = canonicalizeCommentBody(fs.readFileSync(context.artifactPath, "utf8"));
|
|
408
|
+
const commentCanonical = canonicalizeCommentBody(extractCommentBody(comment?.body || ""));
|
|
409
|
+
if (!localCanonical.ok) {
|
|
410
|
+
return shared.failResult(CHECK_TYPE, `Comment content cannot be canonicalized for '${path.basename(context.artifactPath, path.extname(context.artifactPath))}': ${localCanonical.error.message}`, "check_failed");
|
|
411
|
+
}
|
|
412
|
+
if (!commentCanonical.ok) {
|
|
413
|
+
return shared.failResult(CHECK_TYPE, `Comment content cannot be canonicalized for '${path.basename(context.artifactPath, path.extname(context.artifactPath))}': ${commentCanonical.error.message}`, "check_failed");
|
|
414
|
+
}
|
|
415
|
+
localContent = shared.normalizeContent(localCanonical.value);
|
|
416
|
+
commentContent = shared.normalizeContent(commentCanonical.value);
|
|
417
|
+
}
|
|
418
|
+
catch (error) {
|
|
419
|
+
return shared.failResult(CHECK_TYPE, `Comment content cannot be read for '${path.basename(context.artifactPath, path.extname(context.artifactPath))}': ${error instanceof Error ? error.message : String(error)}`, "check_failed");
|
|
420
|
+
}
|
|
417
421
|
if (localContent === commentContent) {
|
|
418
422
|
return null;
|
|
419
423
|
}
|
|
420
|
-
return failResult(CHECK_TYPE, buildCommentContentMismatchMessage(path.basename(context.artifactPath, path.extname(context.artifactPath)), context.issueNumber, localContent, commentContent), "check_failed");
|
|
424
|
+
return shared.failResult(CHECK_TYPE, buildCommentContentMismatchMessage(path.basename(context.artifactPath, path.extname(context.artifactPath)), context.issueNumber, localContent, commentContent), "check_failed");
|
|
421
425
|
}
|
|
422
|
-
function checkTaskCommentContent(context, remoteData) {
|
|
426
|
+
function checkTaskCommentContent(context, remoteData, shared) {
|
|
423
427
|
if (!context.config.verify_task_comment_content) {
|
|
424
428
|
return null;
|
|
425
429
|
}
|
|
426
430
|
const taskMarker = `<!-- sync-issue:${context.task.metadata.id}:task -->`;
|
|
427
431
|
const comment = findCommentByMarker(remoteData.comments, taskMarker);
|
|
428
432
|
if (!comment) {
|
|
429
|
-
return failResult(CHECK_TYPE, `Expected comment marker '${taskMarker}' not found on Issue #${context.issueNumber}`, "check_failed");
|
|
433
|
+
return shared.failResult(CHECK_TYPE, `Expected comment marker '${taskMarker}' not found on Issue #${context.issueNumber}`, "check_failed");
|
|
434
|
+
}
|
|
435
|
+
const expectedTaskBody = buildExpectedTaskBody(context.task.content, shared);
|
|
436
|
+
if (expectedTaskBody === null) {
|
|
437
|
+
return shared.failResult(CHECK_TYPE, "Task content cannot be rendered safely for comment verification", "check_failed");
|
|
430
438
|
}
|
|
431
|
-
const expectedBody = normalizeContent(
|
|
432
|
-
const commentBody = normalizeContent(extractCommentBody(comment.body || ""));
|
|
439
|
+
const expectedBody = shared.normalizeContent(expectedTaskBody);
|
|
440
|
+
const commentBody = shared.normalizeContent(extractCommentBody(comment.body || ""));
|
|
433
441
|
if (expectedBody === commentBody) {
|
|
434
442
|
return null;
|
|
435
443
|
}
|
|
436
|
-
return failResult(CHECK_TYPE, buildCommentContentMismatchMessage("task", context.issueNumber, expectedBody, commentBody), "check_failed");
|
|
444
|
+
return shared.failResult(CHECK_TYPE, buildCommentContentMismatchMessage("task", context.issueNumber, expectedBody, commentBody), "check_failed");
|
|
437
445
|
}
|
|
438
|
-
function checkPrTypeLabel(context, remoteData) {
|
|
446
|
+
function checkPrTypeLabel(context, remoteData, shared) {
|
|
439
447
|
if (!context.config.verify_pr_type_label || !context.hasTriage || !context.prNumber || !remoteData.prLabels) {
|
|
440
448
|
return null;
|
|
441
449
|
}
|
|
@@ -446,9 +454,9 @@ function checkPrTypeLabel(context, remoteData) {
|
|
|
446
454
|
if (remoteData.prLabels.includes(expectedLabel)) {
|
|
447
455
|
return null;
|
|
448
456
|
}
|
|
449
|
-
return failResult(CHECK_TYPE, `Expected type label '${expectedLabel}' not found on PR #${context.prNumber}`, "check_failed");
|
|
457
|
+
return shared.failResult(CHECK_TYPE, `Expected type label '${expectedLabel}' not found on PR #${context.prNumber}`, "check_failed");
|
|
450
458
|
}
|
|
451
|
-
function checkInLabelsMatchPr(context, remoteData) {
|
|
459
|
+
function checkInLabelsMatchPr(context, remoteData, shared) {
|
|
452
460
|
if (!context.config.verify_in_labels_match_pr || !context.hasTriage || !context.prNumber || !remoteData.prLabels) {
|
|
453
461
|
return null;
|
|
454
462
|
}
|
|
@@ -461,17 +469,17 @@ function checkInLabelsMatchPr(context, remoteData) {
|
|
|
461
469
|
if (arraysEqual(issueInLabels, prInLabels)) {
|
|
462
470
|
return null;
|
|
463
471
|
}
|
|
464
|
-
return failResult(CHECK_TYPE, `in: labels mismatch — PR #${context.prNumber} has [${formatLabelList(prInLabels)}], Issue #${context.issueNumber} has [${formatLabelList(issueInLabels)}]`, "check_failed");
|
|
472
|
+
return shared.failResult(CHECK_TYPE, `in: labels mismatch — PR #${context.prNumber} has [${formatLabelList(prInLabels)}], Issue #${context.issueNumber} has [${formatLabelList(issueInLabels)}]`, "check_failed");
|
|
465
473
|
}
|
|
466
|
-
function checkInLabelsComputed(context, remoteData) {
|
|
474
|
+
function checkInLabelsComputed(context, remoteData, shared) {
|
|
467
475
|
if (!context.config.verify_in_labels_computed || !context.hasTriage) {
|
|
468
476
|
return null;
|
|
469
477
|
}
|
|
470
|
-
const expectedInLabels = computeExpectedInLabels(context.taskDir,
|
|
478
|
+
const expectedInLabels = computeExpectedInLabels(context.taskDir, remoteData.repositoryLabels, remoteData.inLabelMapping, shared);
|
|
471
479
|
if (!expectedInLabels.ok) {
|
|
472
480
|
return expectedInLabels.type === "check_failed"
|
|
473
|
-
? failResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type)
|
|
474
|
-
: blockedResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type);
|
|
481
|
+
? shared.failResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type)
|
|
482
|
+
: shared.blockedResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type);
|
|
475
483
|
}
|
|
476
484
|
if (expectedInLabels.mode === "skipped") {
|
|
477
485
|
return null;
|
|
@@ -482,32 +490,32 @@ function checkInLabelsComputed(context, remoteData) {
|
|
|
482
490
|
if (arraysEqual(expectedInLabels.labels, actualInLabels)) {
|
|
483
491
|
return null;
|
|
484
492
|
}
|
|
485
|
-
return failResult(CHECK_TYPE, `Issue #${context.issueNumber} in: labels do not match committed changes: expected [${formatLabelList(expectedInLabels.labels)}], got [${formatLabelList(actualInLabels)}]`, "check_failed");
|
|
493
|
+
return shared.failResult(CHECK_TYPE, `Issue #${context.issueNumber} in: labels do not match committed changes: expected [${formatLabelList(expectedInLabels.labels)}], got [${formatLabelList(actualInLabels)}]`, "check_failed");
|
|
486
494
|
}
|
|
487
|
-
function checkSyncedRequirements(context, remoteData) {
|
|
495
|
+
function checkSyncedRequirements(context, remoteData, shared) {
|
|
488
496
|
if (!context.config.sync_checked_requirements || !context.hasTriage) {
|
|
489
497
|
return null;
|
|
490
498
|
}
|
|
491
|
-
const checkedRequirements = getCheckedRequirements(context.task.content);
|
|
499
|
+
const checkedRequirements = shared.getCheckedRequirements(context.task.content);
|
|
492
500
|
if (checkedRequirements.length === 0) {
|
|
493
501
|
return null;
|
|
494
502
|
}
|
|
495
503
|
const issueBody = remoteData.issue.body || "";
|
|
496
|
-
const resolution = resolveRequirementSection(issueBody, requirementSectionAnchors(repoRoot, context.task.metadata.type || "task"));
|
|
504
|
+
const resolution = resolveRequirementSection(issueBody, requirementSectionAnchors(shared.repoRoot, context.task.metadata.type || "task"));
|
|
497
505
|
if (resolution.status === "missing") {
|
|
498
506
|
return null;
|
|
499
507
|
}
|
|
500
508
|
if (resolution.status === "ambiguous") {
|
|
501
|
-
return failResult(CHECK_TYPE, `Issue #${context.issueNumber} requirements section is ambiguous`, "check_failed");
|
|
509
|
+
return shared.failResult(CHECK_TYPE, `Issue #${context.issueNumber} requirements section is ambiguous`, "check_failed");
|
|
502
510
|
}
|
|
503
511
|
const requirementBody = issueBody.slice(resolution.bodyStart, resolution.bodyEnd);
|
|
504
512
|
const missingRequirements = checkedRequirements.filter((item) => !hasCheckedRequirement(requirementBody, item));
|
|
505
513
|
if (missingRequirements.length === 0) {
|
|
506
514
|
return null;
|
|
507
515
|
}
|
|
508
|
-
return failResult(CHECK_TYPE, `Issue body is missing checked requirements: ${missingRequirements.join(", ")}`, "check_failed");
|
|
516
|
+
return shared.failResult(CHECK_TYPE, `Issue body is missing checked requirements: ${missingRequirements.join(", ")}`, "check_failed");
|
|
509
517
|
}
|
|
510
|
-
function checkIssueType(context, remoteData) {
|
|
518
|
+
function checkIssueType(context, remoteData, shared) {
|
|
511
519
|
if (!context.config.verify_issue_type || !context.hasPush) {
|
|
512
520
|
return null;
|
|
513
521
|
}
|
|
@@ -518,15 +526,15 @@ function checkIssueType(context, remoteData) {
|
|
|
518
526
|
if (context.repoOwnerType === "User") {
|
|
519
527
|
return null;
|
|
520
528
|
}
|
|
521
|
-
return failResult(CHECK_TYPE, `Issue #${context.issueNumber} has no Issue Type set`, "check_failed");
|
|
529
|
+
return shared.failResult(CHECK_TYPE, `Issue #${context.issueNumber} has no Issue Type set`, "check_failed");
|
|
522
530
|
}
|
|
523
531
|
const expectedType = mapTaskTypeToIssueType(context.task.metadata.type);
|
|
524
532
|
if (expectedType && remoteData.issueType !== expectedType) {
|
|
525
|
-
return failResult(CHECK_TYPE, `Issue #${context.issueNumber} has type '${remoteData.issueType}', expected '${expectedType}' (from task type '${context.task.metadata.type}')`, "check_failed");
|
|
533
|
+
return shared.failResult(CHECK_TYPE, `Issue #${context.issueNumber} has type '${remoteData.issueType}', expected '${expectedType}' (from task type '${context.task.metadata.type}')`, "check_failed");
|
|
526
534
|
}
|
|
527
535
|
return null;
|
|
528
536
|
}
|
|
529
|
-
function checkIssueFields(context, remoteData) {
|
|
537
|
+
function checkIssueFields(context, remoteData, shared) {
|
|
530
538
|
if (!context.config.verify_issue_fields || !context.hasPush) {
|
|
531
539
|
return null;
|
|
532
540
|
}
|
|
@@ -535,7 +543,7 @@ function checkIssueFields(context, remoteData) {
|
|
|
535
543
|
}
|
|
536
544
|
for (const [metadataKey, fieldName] of Object.entries(FRONTMATTER_FIELD_MAP)) {
|
|
537
545
|
const expectedRaw = context.task.metadata[metadataKey];
|
|
538
|
-
if (isBlank(expectedRaw) || !remoteData.issueFields.pinnedNames.has(fieldName)) {
|
|
546
|
+
if (shared.isBlank(expectedRaw) || !remoteData.issueFields.pinnedNames.has(fieldName)) {
|
|
539
547
|
continue;
|
|
540
548
|
}
|
|
541
549
|
const actual = remoteData.issueFields.values.get(fieldName);
|
|
@@ -544,40 +552,40 @@ function checkIssueFields(context, remoteData) {
|
|
|
544
552
|
continue;
|
|
545
553
|
}
|
|
546
554
|
if (!actual) {
|
|
547
|
-
return failResult(CHECK_TYPE, `Issue #${context.issueNumber} field '${fieldName}' is missing, expected '${expected.value}'`, "check_failed");
|
|
555
|
+
return shared.failResult(CHECK_TYPE, `Issue #${context.issueNumber} field '${fieldName}' is missing, expected '${expected.value}'`, "check_failed");
|
|
548
556
|
}
|
|
549
557
|
if (actual.kind !== expected.kind || actual.value !== expected.value) {
|
|
550
|
-
return failResult(CHECK_TYPE, `Issue #${context.issueNumber} field '${fieldName}' is '${actual.value}', expected '${expected.value}'`, "check_failed");
|
|
558
|
+
return shared.failResult(CHECK_TYPE, `Issue #${context.issueNumber} field '${fieldName}' is '${actual.value}', expected '${expected.value}'`, "check_failed");
|
|
551
559
|
}
|
|
552
560
|
}
|
|
553
561
|
return null;
|
|
554
562
|
}
|
|
555
|
-
function checkPrAssignee(context, remoteData) {
|
|
563
|
+
function checkPrAssignee(context, remoteData, shared) {
|
|
556
564
|
if (!context.config.verify_pr_assignee || !context.hasPush || !context.prNumber) {
|
|
557
565
|
return null;
|
|
558
566
|
}
|
|
559
567
|
if (!remoteData.prAssignees || remoteData.prAssignees.length === 0) {
|
|
560
|
-
return failResult(CHECK_TYPE, `PR #${context.prNumber} has no assignee`, "check_failed");
|
|
568
|
+
return shared.failResult(CHECK_TYPE, `PR #${context.prNumber} has no assignee`, "check_failed");
|
|
561
569
|
}
|
|
562
570
|
return null;
|
|
563
571
|
}
|
|
564
|
-
function checkMilestone(context, remoteData) {
|
|
572
|
+
function checkMilestone(context, remoteData, shared) {
|
|
565
573
|
if (!context.config.verify_milestone || !context.hasTriage) {
|
|
566
574
|
return null;
|
|
567
575
|
}
|
|
568
576
|
if (!remoteData.issue?.milestone?.title) {
|
|
569
|
-
return failResult(CHECK_TYPE, `Issue #${context.issueNumber} has no milestone set`, "check_failed");
|
|
577
|
+
return shared.failResult(CHECK_TYPE, `Issue #${context.issueNumber} has no milestone set`, "check_failed");
|
|
570
578
|
}
|
|
571
579
|
if (context.prNumber && remoteData.prMilestone !== undefined && !remoteData.prMilestone?.title) {
|
|
572
|
-
return failResult(CHECK_TYPE, `PR #${context.prNumber} has no milestone set`, "check_failed");
|
|
580
|
+
return shared.failResult(CHECK_TYPE, `PR #${context.prNumber} has no milestone set`, "check_failed");
|
|
573
581
|
}
|
|
574
582
|
if (context.config.verify_milestone_specific) {
|
|
575
583
|
const issueTitle = remoteData.issue.milestone.title;
|
|
576
584
|
if (VERSION_LINE_REGEX.test(issueTitle)) {
|
|
577
|
-
return failResult(CHECK_TYPE, `Issue #${context.issueNumber} milestone '${issueTitle}' is a release line; narrow to a specific version (e.g. ${issueTitle.replace(/\.x$/, ".N")}) before continuing`, "check_failed");
|
|
585
|
+
return shared.failResult(CHECK_TYPE, `Issue #${context.issueNumber} milestone '${issueTitle}' is a release line; narrow to a specific version (e.g. ${issueTitle.replace(/\.x$/, ".N")}) before continuing`, "check_failed");
|
|
578
586
|
}
|
|
579
587
|
if (context.prNumber && remoteData.prMilestone?.title && VERSION_LINE_REGEX.test(remoteData.prMilestone.title)) {
|
|
580
|
-
return failResult(CHECK_TYPE, `PR #${context.prNumber} milestone '${remoteData.prMilestone.title}' is a release line; narrow to a specific version before continuing`, "check_failed");
|
|
588
|
+
return shared.failResult(CHECK_TYPE, `PR #${context.prNumber} milestone '${remoteData.prMilestone.title}' is a release line; narrow to a specific version before continuing`, "check_failed");
|
|
581
589
|
}
|
|
582
590
|
}
|
|
583
591
|
return null;
|
|
@@ -622,37 +630,38 @@ function extractCommentBody(commentBody) {
|
|
|
622
630
|
}
|
|
623
631
|
return lines.slice(start, end).join("\n");
|
|
624
632
|
}
|
|
625
|
-
function buildExpectedTaskBody(taskContent) {
|
|
633
|
+
function buildExpectedTaskBody(taskContent, shared) {
|
|
626
634
|
const frontmatterMatch = taskContent.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
|
627
635
|
if (!frontmatterMatch) {
|
|
628
|
-
return taskContent.trim();
|
|
636
|
+
return sanitizeCommentContent(taskContent.trim());
|
|
637
|
+
}
|
|
638
|
+
const body = sanitizeCommentContent(taskContent.slice(frontmatterMatch[0].length).trim());
|
|
639
|
+
if (body === null) {
|
|
640
|
+
return null;
|
|
629
641
|
}
|
|
630
|
-
const body = taskContent.slice(frontmatterMatch[0].length).trim();
|
|
631
642
|
return [
|
|
632
|
-
buildTaskFrontmatterSummary(),
|
|
643
|
+
buildTaskFrontmatterSummary(shared),
|
|
633
644
|
"",
|
|
634
|
-
"
|
|
635
|
-
frontmatterMatch[0].trim(),
|
|
636
|
-
"```",
|
|
645
|
+
renderSafeCodeFence(frontmatterMatch[0].trim(), "yaml"),
|
|
637
646
|
"",
|
|
638
647
|
"</details>",
|
|
639
648
|
"",
|
|
640
649
|
body
|
|
641
650
|
].join("\n").trim();
|
|
642
651
|
}
|
|
643
|
-
function buildTaskFrontmatterSummary() {
|
|
644
|
-
const language = loadProjectLanguage();
|
|
652
|
+
function buildTaskFrontmatterSummary(shared) {
|
|
653
|
+
const language = loadProjectLanguage(shared);
|
|
645
654
|
if (language === "en" || language === "en-US") {
|
|
646
655
|
return "<details><summary>Metadata (frontmatter)</summary>";
|
|
647
656
|
}
|
|
648
657
|
return "<details><summary>元数据 (frontmatter)</summary>";
|
|
649
658
|
}
|
|
650
|
-
function loadProjectLanguage() {
|
|
659
|
+
function loadProjectLanguage(shared) {
|
|
651
660
|
const override = process.env.VALIDATE_ARTIFACT_LANGUAGE;
|
|
652
|
-
if (!isBlank(override)) {
|
|
661
|
+
if (!shared.isBlank(override)) {
|
|
653
662
|
return String(override).trim();
|
|
654
663
|
}
|
|
655
|
-
const configPath = path.join(repoRoot, ".agents", ".airc.json");
|
|
664
|
+
const configPath = path.join(shared.repoRoot, ".agents", ".airc.json");
|
|
656
665
|
if (!fs.existsSync(configPath)) {
|
|
657
666
|
return "";
|
|
658
667
|
}
|
|
@@ -767,8 +776,8 @@ function arraysEqual(left, right) {
|
|
|
767
776
|
function formatLabelList(labels) {
|
|
768
777
|
return labels.length > 0 ? labels.join(", ") : "none";
|
|
769
778
|
}
|
|
770
|
-
function computeExpectedInLabels(taskDir,
|
|
771
|
-
const task = loadTask(taskDir);
|
|
779
|
+
function computeExpectedInLabels(taskDir, repositoryLabels, mappingOverride, shared) {
|
|
780
|
+
const task = shared.loadTask(taskDir);
|
|
772
781
|
if (!task.ok) {
|
|
773
782
|
return task;
|
|
774
783
|
}
|
|
@@ -784,37 +793,23 @@ function computeExpectedInLabels(taskDir, repository) {
|
|
|
784
793
|
.split(/\r?\n/)
|
|
785
794
|
.map((value) => value.trim())
|
|
786
795
|
.filter(Boolean);
|
|
787
|
-
const mapping =
|
|
788
|
-
if (
|
|
789
|
-
return mapping;
|
|
790
|
-
}
|
|
791
|
-
if (Object.keys(mapping.value ?? {}).length === 0) {
|
|
796
|
+
const mapping = mappingOverride ?? {};
|
|
797
|
+
if (Object.keys(mapping).length === 0) {
|
|
792
798
|
return { ok: true, labels: [], mode: "mapped" };
|
|
793
799
|
}
|
|
794
|
-
const client = createGitHubClient();
|
|
795
|
-
const repoLabelsResult = withRetry(() => client.json([
|
|
796
|
-
"api", "--paginate", "--slurp", `repos/${repository}/labels?per_page=100`
|
|
797
|
-
], { cwd: taskDir }));
|
|
798
|
-
if (!repoLabelsResult.ok) {
|
|
799
|
-
return repoLabelsResult;
|
|
800
|
-
}
|
|
801
|
-
const repositoryLabels = validateRepositoryLabelPayload(repoLabelsResult.value);
|
|
802
|
-
if (!repositoryLabels.ok) {
|
|
803
|
-
return { ok: false, type: "check_failed", message: repositoryLabels.error.message };
|
|
804
|
-
}
|
|
805
800
|
const planned = planInLabelUpdate({
|
|
806
801
|
changedFiles,
|
|
807
802
|
currentLabels: [],
|
|
808
|
-
mapping
|
|
809
|
-
repositoryLabels: new Set(repositoryLabels
|
|
803
|
+
mapping,
|
|
804
|
+
repositoryLabels: new Set(repositoryLabels)
|
|
810
805
|
});
|
|
811
806
|
if (planned.error) {
|
|
812
807
|
return { ok: false, type: "check_failed", message: planned.error.message };
|
|
813
808
|
}
|
|
814
809
|
return { ok: true, labels: planned.target, mode: "mapped" };
|
|
815
810
|
}
|
|
816
|
-
function loadInLabelMapping() {
|
|
817
|
-
const configPath = path.join(repoRoot, ".agents", ".airc.json");
|
|
811
|
+
function loadInLabelMapping(shared) {
|
|
812
|
+
const configPath = path.join(shared.repoRoot, ".agents", ".airc.json");
|
|
818
813
|
if (!fs.existsSync(configPath)) {
|
|
819
814
|
return { ok: true, value: {} };
|
|
820
815
|
}
|
|
@@ -829,7 +824,7 @@ function loadInLabelMapping() {
|
|
|
829
824
|
return { ok: false, type: "check_failed", message: `Unable to parse .agents/.airc.json: ${error.message}` };
|
|
830
825
|
}
|
|
831
826
|
}
|
|
832
|
-
// ===
|
|
827
|
+
// === Git working tree ===
|
|
833
828
|
function gitText(args, cwd) {
|
|
834
829
|
try {
|
|
835
830
|
const value = execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
@@ -845,12 +840,12 @@ function gitText(args, cwd) {
|
|
|
845
840
|
}
|
|
846
841
|
}
|
|
847
842
|
function resolvePrHeadSha(context) {
|
|
848
|
-
const fallback = () =>
|
|
843
|
+
const fallback = () => gitText(["rev-parse", "HEAD"], context.taskDir);
|
|
849
844
|
const branch = String(context.task?.metadata?.branch || "").trim();
|
|
850
845
|
if (!branch) {
|
|
851
846
|
return fallback();
|
|
852
847
|
}
|
|
853
|
-
const worktreeList =
|
|
848
|
+
const worktreeList = gitText(["worktree", "list", "--porcelain"], context.taskDir);
|
|
854
849
|
if (!worktreeList.ok) {
|
|
855
850
|
return fallback();
|
|
856
851
|
}
|
|
@@ -858,7 +853,7 @@ function resolvePrHeadSha(context) {
|
|
|
858
853
|
if (!matchedWorktree) {
|
|
859
854
|
return fallback();
|
|
860
855
|
}
|
|
861
|
-
const headInWorktree =
|
|
856
|
+
const headInWorktree = gitText(["rev-parse", "HEAD"], matchedWorktree);
|
|
862
857
|
if (!headInWorktree.ok) {
|
|
863
858
|
return fallback();
|
|
864
859
|
}
|
|
@@ -881,9 +876,6 @@ function findWorktreeForBranch(porcelainOutput, branch) {
|
|
|
881
876
|
}
|
|
882
877
|
return null;
|
|
883
878
|
}
|
|
884
|
-
function withRetry(operation) {
|
|
885
|
-
return operation();
|
|
886
|
-
}
|
|
887
879
|
function interpolate(template, taskDir, artifactFile) {
|
|
888
880
|
const artifactStem = artifactFile ? path.basename(artifactFile, path.extname(artifactFile)) : "";
|
|
889
881
|
return template
|