@fitlab-ai/agent-infra 0.9.11 → 0.9.13
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 +13 -13
- package/README.zh-CN.md +13 -13
- package/dist/bin/internal-cli.js +29 -19
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +71 -10
- package/dist/lib/agent-clients/next-steps.js +6 -1
- package/dist/lib/decide.js +3 -3
- package/dist/lib/defaults.json +4 -0
- package/dist/lib/git/workflow.js +43 -1
- package/dist/lib/init.js +1 -0
- package/dist/lib/internal/git-workflow.js +8 -1
- package/dist/lib/internal/platform-checks.js +3 -3
- package/dist/lib/internal/platform-comment.js +9 -9
- package/dist/lib/internal/platform-context.js +2 -2
- package/dist/lib/internal/platform-issue.js +8 -9
- package/dist/lib/internal/platform-pr-review.js +10 -10
- package/dist/lib/internal/platform-pr.js +68 -23
- package/dist/lib/internal/platform-release-notes.js +3 -3
- package/dist/lib/internal/pr-review-grade.js +11 -9
- package/dist/lib/internal/release-workflow.js +4 -4
- package/dist/lib/internal/sandbox-control.js +30 -4
- package/dist/lib/internal/task-activity.js +3 -3
- package/dist/lib/internal/task-artifact.js +76 -24
- package/dist/lib/internal/task-create.js +2 -2
- package/dist/lib/internal/task-delivery.js +59 -0
- package/dist/lib/internal/task-event.js +6 -3
- package/dist/lib/internal/task-finalization.js +2 -2
- package/dist/lib/internal/task-invalidation.js +60 -0
- package/dist/lib/internal/task-ledger.js +9 -6
- package/dist/lib/internal/task-lifecycle.js +2 -2
- package/dist/lib/internal/task-override.js +4 -4
- package/dist/lib/internal/task-review.js +3 -3
- package/dist/lib/internal/task-verify.js +6 -6
- package/dist/lib/internal/task-warning.js +3 -3
- package/dist/lib/platform/adapters.js +1 -3
- package/dist/lib/platform/change-request-git-evidence.js +27 -7
- package/dist/lib/platform/completion-backfill.js +6 -5
- package/dist/lib/platform/context.js +70 -130
- package/dist/lib/platform/github-client.js +8 -2
- package/dist/lib/platform/github-provider.js +903 -0
- package/dist/lib/platform/in-label-sync.js +143 -0
- package/dist/lib/platform/issue-comments.js +94 -41
- package/dist/lib/platform/issues.js +335 -189
- package/dist/lib/platform/metadata-labels.js +6 -2
- package/dist/lib/platform/none-provider.js +28 -0
- package/dist/lib/platform/pr-change-report.js +551 -0
- package/dist/lib/platform/pr-checks.js +124 -106
- package/dist/lib/platform/pr-review.js +88 -72
- package/dist/lib/platform/pr-summary.js +523 -49
- package/dist/lib/platform/provider-bridge.js +45 -0
- package/dist/lib/platform/provider-contract.d.ts +487 -0
- package/dist/lib/platform/provider-contract.js +95 -0
- package/dist/lib/platform/provider-loader.js +251 -0
- package/dist/lib/platform/provider-validation.js +504 -0
- package/dist/lib/platform/pull-request-metadata.js +8 -6
- package/dist/lib/platform/pull-requests.js +1050 -502
- package/dist/lib/platform/release-notes.js +78 -55
- package/dist/lib/platform/releases.js +79 -50
- package/dist/lib/platform/resource-identity.d.ts +26 -0
- package/dist/lib/platform/resource-identity.js +92 -0
- package/dist/lib/platform/task-identities.js +31 -0
- package/dist/lib/platform/verification-required.js +22 -12
- package/dist/lib/platform/verification-sync.js +118 -239
- package/dist/lib/pr-review/evidence-grading.js +30 -9
- package/dist/lib/run/index.js +63 -23
- package/dist/lib/sandbox/config.js +5 -0
- package/dist/lib/sandbox/control/client.js +96 -15
- package/dist/lib/sandbox/control/executor.js +3 -3
- package/dist/lib/sandbox/control/lifecycle.js +29 -7
- package/dist/lib/sandbox/control/protocol.js +77 -0
- package/dist/lib/sandbox/control/server.js +398 -25
- package/dist/lib/sandbox/control/state.js +204 -1
- package/dist/lib/server/process-state.js +2 -2
- package/dist/lib/server/protocol.js +38 -1
- package/dist/lib/task/activity-log.js +8 -1
- package/dist/lib/task/artifact-lifecycle.js +35 -7
- package/dist/lib/task/capabilities.js +239 -0
- package/dist/lib/task/commands/status.js +32 -0
- package/dist/lib/task/commit-intent.js +100 -0
- package/dist/lib/task/commit-operation.js +207 -102
- package/dist/lib/task/control-authority.js +8 -5
- package/dist/lib/task/create-service.js +8 -8
- package/dist/lib/task/create.js +33 -7
- package/dist/lib/task/current-contract.js +5 -1
- package/dist/lib/task/decision-details.js +3 -48
- package/dist/lib/task/delivery-target.js +97 -0
- package/dist/lib/task/delivery.js +153 -0
- package/dist/lib/task/events.js +297 -17
- package/dist/lib/task/finalization.js +37 -13
- package/dist/lib/task/human-override.js +61 -36
- package/dist/lib/task/invalidation-command.js +86 -0
- package/dist/lib/task/invalidation.js +260 -0
- package/dist/lib/task/ledger-intents.js +37 -0
- package/dist/lib/task/lifecycle.js +106 -9
- package/dist/lib/task/local-artifact-finalization.js +374 -0
- package/dist/lib/task/orchestration.js +100 -151
- package/dist/lib/task/pr-delivery-fact.js +183 -0
- package/dist/lib/task/review-finalization.js +4 -8
- package/dist/lib/task/review-fingerprint.js +32 -2
- package/dist/lib/task/rework-intent.js +138 -0
- package/dist/lib/task/skill-scope.js +23 -0
- package/dist/lib/task/task-execution-lock.js +27 -17
- package/dist/lib/task/verification-engine.js +89 -38
- package/dist/lib/task/verification-review.js +1 -1
- package/dist/lib/task/verification.js +3 -3
- package/dist/lib/task/workflow-warning-intents.js +1 -1
- package/dist/lib/task/write.js +11 -0
- package/dist/lib/update.js +9 -0
- package/dist/lib/version.js +11 -1
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +105 -10
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +12 -1
- package/lib/agent-clients/next-steps.ts +6 -1
- package/lib/decide.ts +3 -3
- package/lib/defaults.json +4 -0
- package/lib/git/workflow.ts +38 -1
- package/lib/init.ts +4 -1
- package/lib/internal/git-workflow.ts +7 -1
- package/lib/internal/platform-checks.ts +3 -3
- package/lib/internal/platform-comment.ts +8 -8
- package/lib/internal/platform-context.ts +2 -2
- package/lib/internal/platform-issue.ts +7 -8
- package/lib/internal/platform-pr-review.ts +9 -9
- package/lib/internal/platform-pr.ts +53 -21
- package/lib/internal/platform-release-notes.ts +3 -3
- package/lib/internal/pr-review-grade.ts +10 -8
- package/lib/internal/release-workflow.ts +4 -4
- package/lib/internal/sandbox-control.ts +27 -3
- package/lib/internal/task-activity.ts +3 -3
- package/lib/internal/task-artifact.ts +65 -22
- package/lib/internal/task-create.ts +2 -2
- package/lib/internal/task-delivery.ts +53 -0
- package/lib/internal/task-event.ts +6 -3
- package/lib/internal/task-finalization.ts +3 -3
- package/lib/internal/task-invalidation.ts +39 -0
- package/lib/internal/task-ledger.ts +11 -8
- package/lib/internal/task-lifecycle.ts +2 -2
- package/lib/internal/task-override.ts +6 -6
- package/lib/internal/task-review.ts +3 -3
- package/lib/internal/task-verify.ts +6 -6
- package/lib/internal/task-warning.ts +3 -3
- package/lib/platform/adapters.ts +3 -2
- package/lib/platform/change-request-git-evidence.ts +36 -9
- package/lib/platform/completion-backfill.ts +9 -8
- package/lib/platform/context.ts +97 -134
- package/lib/platform/github-client.ts +10 -3
- package/lib/platform/github-provider.ts +910 -0
- package/lib/platform/in-label-sync.ts +208 -0
- package/lib/platform/issue-comments.ts +97 -47
- package/lib/platform/issues.ts +344 -174
- package/lib/platform/metadata-labels.ts +5 -2
- package/lib/platform/none-provider.ts +35 -0
- package/lib/platform/pr-change-report.ts +645 -0
- package/lib/platform/pr-checks.ts +129 -107
- package/lib/platform/pr-review.ts +88 -85
- package/lib/platform/pr-summary.ts +562 -52
- package/lib/platform/provider-bridge.ts +82 -0
- package/lib/platform/provider-contract.ts +536 -0
- package/lib/platform/provider-loader.ts +307 -0
- package/lib/platform/provider-validation.ts +529 -0
- package/lib/platform/pull-request-metadata.ts +10 -7
- package/lib/platform/pull-requests.ts +1126 -505
- package/lib/platform/release-notes.ts +76 -59
- package/lib/platform/releases.ts +77 -43
- package/lib/platform/resource-identity.ts +121 -0
- package/lib/platform/task-identities.ts +40 -0
- package/lib/platform/types.ts +4 -2
- package/lib/platform/verification-required.ts +21 -13
- package/lib/platform/verification-sync.ts +118 -293
- package/lib/pr-review/evidence-grading.ts +31 -11
- package/lib/run/index.ts +57 -22
- package/lib/sandbox/config.ts +7 -0
- package/lib/sandbox/control/client.ts +105 -15
- package/lib/sandbox/control/executor.ts +4 -4
- package/lib/sandbox/control/lifecycle.ts +30 -8
- package/lib/sandbox/control/protocol.ts +113 -0
- package/lib/sandbox/control/server.ts +431 -23
- package/lib/sandbox/control/state.ts +251 -1
- package/lib/server/process-state.ts +2 -2
- package/lib/server/protocol.ts +36 -1
- package/lib/task/activity-log.ts +8 -0
- package/lib/task/artifact-lifecycle.ts +34 -8
- package/lib/task/capabilities.ts +262 -0
- package/lib/task/commands/status.ts +38 -0
- package/lib/task/commit-intent.ts +137 -0
- package/lib/task/commit-operation.ts +186 -88
- package/lib/task/control-authority.ts +11 -8
- package/lib/task/create-service.ts +8 -8
- package/lib/task/create.ts +34 -9
- package/lib/task/current-contract.ts +6 -1
- package/lib/task/decision-details.ts +8 -64
- package/lib/task/delivery-target.ts +130 -0
- package/lib/task/delivery.ts +160 -0
- package/lib/task/events.ts +296 -16
- package/lib/task/finalization.ts +50 -14
- package/lib/task/human-override.ts +73 -46
- package/lib/task/invalidation-command.ts +86 -0
- package/lib/task/invalidation.ts +332 -0
- package/lib/task/ledger-intents.ts +35 -1
- package/lib/task/lifecycle.ts +93 -4
- package/lib/task/local-artifact-finalization.ts +563 -0
- package/lib/task/orchestration.ts +110 -146
- package/lib/task/pr-delivery-fact.ts +237 -0
- package/lib/task/review-finalization.ts +4 -14
- package/lib/task/review-fingerprint.ts +33 -2
- package/lib/task/rework-intent.ts +165 -0
- package/lib/task/skill-scope.ts +24 -0
- package/lib/task/task-execution-lock.ts +23 -14
- package/lib/task/verification-engine.ts +95 -43
- package/lib/task/verification-review.ts +2 -0
- package/lib/task/verification.ts +4 -4
- package/lib/task/workflow-warning-intents.ts +1 -1
- package/lib/task/write.ts +19 -0
- package/lib/update.ts +11 -1
- package/lib/version.ts +15 -1
- package/package.json +7 -1
- package/templates/.agents/rules/README.en.md +4 -2
- package/templates/.agents/rules/README.zh-CN.md +4 -2
- package/templates/.agents/rules/create-issue.en.md +11 -2
- package/templates/.agents/rules/create-issue.zh-CN.md +24 -2
- package/templates/.agents/rules/issue-pr-commands.en.md +4 -17
- package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
- package/templates/.agents/rules/issue-sync.en.md +28 -5
- package/templates/.agents/rules/issue-sync.zh-CN.md +64 -5
- package/templates/.agents/rules/label-milestone-setup.en.md +15 -2
- package/templates/.agents/rules/label-milestone-setup.zh-CN.md +15 -2
- package/templates/.agents/rules/local-artifact-repair.en.md +53 -0
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +53 -0
- package/templates/.agents/rules/milestone-inference.en.md +12 -2
- package/templates/.agents/rules/milestone-inference.zh-CN.md +25 -3
- package/templates/.agents/rules/pr-sync.en.md +28 -13
- package/templates/.agents/rules/pr-sync.zh-CN.md +39 -5
- package/templates/.agents/rules/release-commands.en.md +42 -3
- package/templates/.agents/rules/release-commands.zh-CN.md +42 -3
- package/templates/.agents/rules/security-alerts.en.md +17 -2
- package/templates/.agents/rules/security-alerts.zh-CN.md +17 -2
- package/templates/.agents/rules/sync-content-generation.en.md +8 -0
- package/templates/.agents/rules/sync-content-generation.zh-CN.md +8 -0
- package/templates/.agents/rules/task-management.en.md +1 -1
- package/templates/.agents/rules/task-management.zh-CN.md +1 -1
- package/templates/.agents/rules/task-short-id.en.md +1 -4
- package/templates/.agents/rules/task-short-id.zh-CN.md +1 -3
- package/templates/.agents/scripts/security-alerts.github.sh +151 -0
- package/templates/.agents/scripts/security-alerts.sh +31 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +14 -3
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +11 -3
- package/templates/.agents/skills/check-task/SKILL.en.md +16 -37
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -37
- 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 +32 -10
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +35 -13
- package/templates/.agents/skills/code-task/config/verify.en.json +1 -0
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +1 -0
- package/templates/.agents/skills/commit/SKILL.en.md +3 -3
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/commit/config/verify.json +1 -1
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +3 -3
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +3 -3
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +2 -0
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +2 -0
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +4 -4
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +4 -4
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +2 -2
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +2 -2
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +7 -4
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +7 -4
- 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/summary-update.en.md +5 -4
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +5 -4
- package/templates/.agents/skills/complete-task/SKILL.en.md +31 -13
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +30 -13
- package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +2 -2
- package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +2 -2
- package/templates/.agents/skills/create-pr/SKILL.en.md +11 -10
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +11 -11
- package/templates/.agents/skills/create-pr/config/verify.json +1 -0
- package/templates/.agents/skills/create-pr/reference/change-report.en.md +16 -4
- package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +16 -4
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +5 -3
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +5 -3
- package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
- package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
- package/templates/.agents/skills/create-pr/scripts/change-report.mjs +3 -0
- package/templates/.agents/skills/create-task/SKILL.en.md +1 -0
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +1 -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 +9 -10
- package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +9 -10
- package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +57 -1
- package/templates/.agents/skills/init-labels/scripts/init-labels.sh +27 -1
- package/templates/.agents/skills/init-milestones/SKILL.en.md +3 -5
- package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +3 -5
- package/templates/.agents/skills/plan-task/SKILL.en.md +14 -3
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +11 -3
- package/templates/.agents/skills/review-analysis/SKILL.en.md +6 -5
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +6 -5
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +18 -0
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +18 -0
- package/templates/.agents/skills/review-code/SKILL.en.md +10 -9
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +10 -9
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +19 -1
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +19 -1
- package/templates/.agents/skills/review-code/reference/report-template.en.md +4 -2
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +4 -2
- package/templates/.agents/skills/review-plan/SKILL.en.md +6 -5
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +6 -5
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +18 -0
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +18 -0
- package/templates/.agents/skills/review-pr/SKILL.en.md +1 -0
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +1 -0
- package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +2 -2
- package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +2 -2
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +5 -2
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +5 -2
- 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/update-agent-infra/scripts/sync-templates.js +4 -0
- package/templates/.agents/skills/watch-pr/SKILL.en.md +6 -6
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +6 -6
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +6 -0
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +6 -0
- package/templates/.agents/templates/task.en.md +23 -2
- package/templates/.agents/templates/task.zh-CN.md +23 -2
- package/templates/.agents/workflows/bug-fix.en.yaml +9 -8
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +9 -8
- package/templates/.agents/workflows/feature-development.en.yaml +9 -8
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +9 -8
- package/templates/.agents/workflows/refactoring.en.yaml +9 -8
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +9 -8
- package/templates/.github/workflows/pr-label.yml +7 -26
- package/templates/.agents/rules/create-issue.github.en.md +0 -14
- package/templates/.agents/rules/create-issue.github.zh-CN.md +0 -27
- package/templates/.agents/rules/issue-pr-commands.github.en.md +0 -34
- package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +0 -49
- package/templates/.agents/rules/issue-sync.github.en.md +0 -40
- package/templates/.agents/rules/issue-sync.github.zh-CN.md +0 -76
- package/templates/.agents/rules/label-milestone-setup.github.en.md +0 -60
- package/templates/.agents/rules/label-milestone-setup.github.zh-CN.md +0 -60
- package/templates/.agents/rules/milestone-inference.github.en.md +0 -15
- package/templates/.agents/rules/milestone-inference.github.zh-CN.md +0 -27
- package/templates/.agents/rules/pr-checks-commands.github.en.md +0 -18
- package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +0 -34
- package/templates/.agents/rules/pr-sync.github.en.md +0 -43
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +0 -69
- package/templates/.agents/rules/release-commands.github.en.md +0 -44
- package/templates/.agents/rules/release-commands.github.zh-CN.md +0 -44
- package/templates/.agents/rules/security-alerts.github.en.md +0 -43
- package/templates/.agents/rules/security-alerts.github.zh-CN.md +0 -43
- /package/templates/.agents/rules/{issue-fields.github.en.md → issue-fields.en.md} +0 -0
- /package/templates/.agents/rules/{issue-fields.github.zh-CN.md → issue-fields.zh-CN.md} +0 -0
|
@@ -3,13 +3,16 @@ import path from "node:path";
|
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
import { execFileSync } from "node:child_process";
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import { resolvePlatformContext } from "./context.ts";
|
|
6
|
+
import { resolvePlatformProviderContext } from "./context.ts";
|
|
8
7
|
import { hasCheckedRequirement, resolveRequirementSection } from "./issue-metadata.ts";
|
|
9
|
-
import {
|
|
10
|
-
import { listRemoteComments } from "./issue-comments.ts";
|
|
8
|
+
import { requirementSectionAnchors } from "./issues.ts";
|
|
11
9
|
import { taskTypeLabel } from "./metadata-labels.ts";
|
|
10
|
+
import { planInLabelUpdate, validateInLabelMapping, validateRepositoryLabelPayload } from "./in-label-sync.ts";
|
|
12
11
|
import { inspectGitHubPullRequest } from "./pull-requests.ts";
|
|
12
|
+
import { createGitHubClient } from "./github-client.ts";
|
|
13
|
+
import { readPrDeliveryFact } from "../task/pr-delivery-fact.ts";
|
|
14
|
+
import { providerError, providerOperationContext, resourceIdentityNumber, unsupportedProviderOperation } from "./provider-bridge.ts";
|
|
15
|
+
import { taskIssueIdentity } from "./task-identities.ts";
|
|
13
16
|
|
|
14
17
|
const CHECK_TYPE = "platform-sync";
|
|
15
18
|
const VERSION_LINE_REGEX = /^[0-9]+\.[0-9]+\.x$/;
|
|
@@ -28,7 +31,6 @@ const OPTION_LOCALIZATION: Record<string, string> = {
|
|
|
28
31
|
|
|
29
32
|
let activeShared: any = null;
|
|
30
33
|
let repoRoot = "";
|
|
31
|
-
const githubClient = createGitHubClient();
|
|
32
34
|
|
|
33
35
|
export function getDefaults(): any {
|
|
34
36
|
return {
|
|
@@ -94,23 +96,15 @@ function safeStat(...args: any[]): any {
|
|
|
94
96
|
return getShared().safeStat(...args);
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
function
|
|
98
|
-
return getShared().parseIssueNumber(...args);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function parsePrNumber(...args: any[]): any {
|
|
102
|
-
return getShared().parsePrNumber(...args);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export function check({ taskDir, config, artifactFile }: any, shared: any): any {
|
|
99
|
+
export async function check({ taskDir, config, artifactFile }: any, shared: any): Promise<any> {
|
|
106
100
|
activeShared = shared;
|
|
107
101
|
repoRoot = shared.repoRoot;
|
|
108
|
-
const context = buildSyncContext({ taskDir, config, artifactFile });
|
|
102
|
+
const context = await buildSyncContext({ taskDir, config, artifactFile });
|
|
109
103
|
if (context.earlyReturn) {
|
|
110
104
|
return context.earlyReturn;
|
|
111
105
|
}
|
|
112
106
|
|
|
113
|
-
const remoteData = fetchRemoteData(context);
|
|
107
|
+
const remoteData = await fetchRemoteData(context);
|
|
114
108
|
if (remoteData.earlyReturn) {
|
|
115
109
|
return remoteData.earlyReturn;
|
|
116
110
|
}
|
|
@@ -141,29 +135,36 @@ export function check({ taskDir, config, artifactFile }: any, shared: any): any
|
|
|
141
135
|
}
|
|
142
136
|
}
|
|
143
137
|
|
|
144
|
-
return passResult(CHECK_TYPE, `
|
|
138
|
+
return passResult(CHECK_TYPE, `Platform sync checks passed for Issue ${context.issueNumber || "identity"}`);
|
|
145
139
|
}
|
|
146
140
|
|
|
147
|
-
function buildSyncContext({ taskDir, config, artifactFile }: any): any {
|
|
141
|
+
async function buildSyncContext({ taskDir, config, artifactFile }: any): Promise<any> {
|
|
148
142
|
const task = loadTask(taskDir);
|
|
149
143
|
if (!task.ok) {
|
|
150
144
|
return { earlyReturn: failResult(CHECK_TYPE, task.message) };
|
|
151
145
|
}
|
|
152
146
|
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
|
|
147
|
+
const issueIdentity = taskIssueIdentity(task.metadata);
|
|
148
|
+
const issueNumber = resourceIdentityNumber(issueIdentity);
|
|
149
|
+
const fact = readPrDeliveryFact(task.metadata);
|
|
150
|
+
if (fact.status === "invalid") {
|
|
151
|
+
return { earlyReturn: failResult(CHECK_TYPE, fact.error.message, "check_failed") };
|
|
152
|
+
}
|
|
153
|
+
const prIdentity = fact.status === "valid" && fact.fact.state === "bound" ? fact.fact.identity.resource : null;
|
|
154
|
+
const prNumber = resourceIdentityNumber(prIdentity);
|
|
155
|
+
if (config.when === "issue_number_exists" && !issueIdentity) {
|
|
156
156
|
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no issue_number") };
|
|
157
157
|
}
|
|
158
|
-
if (config.when === "
|
|
159
|
-
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no
|
|
158
|
+
if (config.when === "pr_fact_bound" && !prIdentity) {
|
|
159
|
+
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no verified bound pull request") };
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
if (!
|
|
162
|
+
if (!issueIdentity) {
|
|
163
163
|
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: platform-sync not required for this task") };
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
const
|
|
166
|
+
const loaded = await resolvePlatformProviderContext({ cwd: repoRoot });
|
|
167
|
+
const platformContext = loaded.ok ? loaded.value.context : loaded.context;
|
|
167
168
|
if (platformContext.status === "failed") {
|
|
168
169
|
return { earlyReturn: failResult(CHECK_TYPE, platformContext.error?.message || "Platform context failed", "check_failed") };
|
|
169
170
|
}
|
|
@@ -176,7 +177,6 @@ function buildSyncContext({ taskDir, config, artifactFile }: any): any {
|
|
|
176
177
|
}
|
|
177
178
|
return { earlyReturn: passResult(CHECK_TYPE, `Skipped: ${platformContext.error?.message || "platform unavailable"}`) };
|
|
178
179
|
}
|
|
179
|
-
const repoOwnerType = detectRepoOwnerType(platformContext.platform.repository, taskDir);
|
|
180
180
|
const expectedValues = resolveExpectedValues(config);
|
|
181
181
|
if (!expectedValues.ok) {
|
|
182
182
|
return { earlyReturn: failResult(CHECK_TYPE, expectedValues.message, "check_failed") };
|
|
@@ -196,15 +196,20 @@ function buildSyncContext({ taskDir, config, artifactFile }: any): any {
|
|
|
196
196
|
config,
|
|
197
197
|
artifactFile,
|
|
198
198
|
artifactPath,
|
|
199
|
+
issueIdentity,
|
|
200
|
+
prIdentity,
|
|
199
201
|
issueNumber,
|
|
200
202
|
prNumber,
|
|
201
203
|
upstreamRepo: platformContext.platform.repository,
|
|
202
|
-
repoOwnerType,
|
|
204
|
+
repoOwnerType: String(loaded.ok ? loaded.value.snapshot.metadata?.ownerType || "unknown" : "unknown"),
|
|
203
205
|
hasTriage: platformContext.capabilities.triage,
|
|
204
206
|
hasPush: platformContext.capabilities.push,
|
|
205
207
|
expectedStatusLabel: expectedValues.statusLabel,
|
|
206
208
|
marker,
|
|
207
|
-
prMarker
|
|
209
|
+
prMarker,
|
|
210
|
+
provider: loaded.ok ? loaded.value.provider : null,
|
|
211
|
+
providerType: loaded.ok ? loaded.value.providerType : null,
|
|
212
|
+
loadedContext: loaded.ok ? loaded.value : null
|
|
208
213
|
};
|
|
209
214
|
}
|
|
210
215
|
|
|
@@ -261,170 +266,68 @@ function resolveDefaultValue({ collection, key, value, configKey }: any): any {
|
|
|
261
266
|
return { ok: true, value: resolvedValue };
|
|
262
267
|
}
|
|
263
268
|
|
|
264
|
-
function fetchRemoteData(context: any): any {
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
milestone: sharedIssue.value.milestone ? { title: sharedIssue.value.milestone } : null
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
: {
|
|
282
|
-
ok: false,
|
|
283
|
-
type: sharedIssue.error.retryable ? "network_error" : "check_failed",
|
|
284
|
-
message: sharedIssue.error.message
|
|
285
|
-
};
|
|
286
|
-
if (!issueResult.ok) {
|
|
287
|
-
return {
|
|
288
|
-
earlyReturn: issueResult.type === "check_failed"
|
|
289
|
-
? failResult(CHECK_TYPE, issueResult.message, issueResult.type)
|
|
290
|
-
: blockedResult(CHECK_TYPE, issueResult.message, issueResult.type)
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
const issue = issueResult.value;
|
|
295
|
-
if (context.config.issue_must_exist !== false && !issue) {
|
|
269
|
+
async function fetchRemoteData(context: any): Promise<any> {
|
|
270
|
+
const provider = context.provider;
|
|
271
|
+
const operationContext = providerOperationContext(context.loadedContext, context.taskDir);
|
|
272
|
+
const facts = provider?.verification?.fetchRemoteFacts
|
|
273
|
+
? await provider.verification.fetchRemoteFacts({
|
|
274
|
+
context: operationContext,
|
|
275
|
+
taskId: context.task?.metadata?.id || context.task?.id || "",
|
|
276
|
+
...(context.issueIdentity ? { issue: context.issueIdentity } : {}),
|
|
277
|
+
...(context.prIdentity ? { changeRequest: context.prIdentity } : {}),
|
|
278
|
+
includeComments: shouldFetchComments(context.config),
|
|
279
|
+
includeFields: Boolean(context.config.verify_issue_fields)
|
|
280
|
+
})
|
|
281
|
+
: unsupportedProviderOperation(provider, "verification.fetchRemoteFacts");
|
|
282
|
+
if (!facts.ok) {
|
|
296
283
|
return {
|
|
297
|
-
earlyReturn:
|
|
284
|
+
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")
|
|
298
287
|
};
|
|
299
288
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
`repos/${context.upstreamRepo}/issues/${context.issueNumber}/comments?per_page=100`
|
|
308
|
-
], context.taskDir));
|
|
309
|
-
|
|
310
|
-
if (!commentsResult.ok) {
|
|
311
|
-
return {
|
|
312
|
-
earlyReturn: commentsResult.type === "check_failed"
|
|
313
|
-
? failResult(CHECK_TYPE, commentsResult.message, commentsResult.type)
|
|
314
|
-
: blockedResult(CHECK_TYPE, commentsResult.message, commentsResult.type)
|
|
315
|
-
};
|
|
289
|
+
const issueSnapshot = facts.value.issue;
|
|
290
|
+
const issue = issueSnapshot
|
|
291
|
+
? {
|
|
292
|
+
state: issueSnapshot.state.toUpperCase(),
|
|
293
|
+
labels: issueSnapshot.labels.map((name: string) => ({ name })),
|
|
294
|
+
body: issueSnapshot.body,
|
|
295
|
+
milestone: issueSnapshot.milestone ? { title: issueSnapshot.milestone } : null
|
|
316
296
|
}
|
|
317
|
-
|
|
318
|
-
|
|
297
|
+
: null;
|
|
298
|
+
let issueFields: any;
|
|
299
|
+
if (context.config.verify_issue_fields && issueSnapshot?.issueType) {
|
|
300
|
+
const fieldKinds = new Map(issueSnapshot.issueType.fields.map((field: { name: string; kind: string }) => [field.name, field.kind]));
|
|
301
|
+
issueFields = {
|
|
302
|
+
pinnedNames: new Set(issueSnapshot.issueType.fields.map((field: { name: string }) => field.name)),
|
|
303
|
+
values: new Map(Object.entries(issueSnapshot.fields).map(([name, value]) => [name, { kind: fieldKinds.get(name) || (typeof value === "number" ? "number" : "single-select"), value }]))
|
|
304
|
+
};
|
|
319
305
|
}
|
|
320
|
-
|
|
321
306
|
let prComments = null;
|
|
322
|
-
if (context.prMarker) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
githubClient,
|
|
331
|
-
context.upstreamRepo,
|
|
332
|
-
context.prNumber,
|
|
333
|
-
context.taskDir
|
|
334
|
-
);
|
|
335
|
-
|
|
336
|
-
if (!prCommentsResult.ok) {
|
|
337
|
-
return {
|
|
338
|
-
earlyReturn: prCommentsResult.error.retryable
|
|
339
|
-
? blockedResult(CHECK_TYPE, prCommentsResult.error.message, "network_error")
|
|
340
|
-
: failResult(CHECK_TYPE, prCommentsResult.error.message, "check_failed")
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
prComments = prCommentsResult.value;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
let issueType;
|
|
348
|
-
if (context.config.verify_issue_type && context.hasPush) {
|
|
349
|
-
const issueTypeResult = withRetry(() => ghText([
|
|
350
|
-
"api",
|
|
351
|
-
`repos/${context.upstreamRepo}/issues/${context.issueNumber}`,
|
|
352
|
-
"--jq",
|
|
353
|
-
".type.name // empty"
|
|
354
|
-
], context.taskDir));
|
|
355
|
-
|
|
356
|
-
if (issueTypeResult.ok) {
|
|
357
|
-
issueType = issueTypeResult.value || null;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
let issueFields;
|
|
362
|
-
if (context.config.verify_issue_fields && context.hasPush) {
|
|
363
|
-
const [owner, name] = context.upstreamRepo.split("/");
|
|
364
|
-
const issueFieldsResult = withRetry(() => ghJson([
|
|
365
|
-
"api",
|
|
366
|
-
"graphql",
|
|
367
|
-
"-f",
|
|
368
|
-
`query=${ISSUE_FIELDS_QUERY}`,
|
|
369
|
-
"-F",
|
|
370
|
-
`owner=${owner}`,
|
|
371
|
-
"-F",
|
|
372
|
-
`name=${name}`,
|
|
373
|
-
"-F",
|
|
374
|
-
`number=${context.issueNumber}`
|
|
375
|
-
], context.taskDir));
|
|
376
|
-
|
|
377
|
-
if (issueFieldsResult.ok) {
|
|
378
|
-
issueFields = normalizeIssueFields(issueFieldsResult.value);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
let prLabels = null;
|
|
383
|
-
let prMilestone;
|
|
384
|
-
let prAssignees;
|
|
385
|
-
let prHeadSha;
|
|
386
|
-
if (((context.config.verify_in_labels_match_pr && context.hasTriage)
|
|
387
|
-
|| (context.config.verify_pr_type_label && context.hasTriage)
|
|
388
|
-
|| (context.config.verify_milestone && context.hasTriage)
|
|
389
|
-
|| (context.config.verify_pr_assignee && context.hasPush)
|
|
390
|
-
|| context.config.verify_pr_comment_last_commit_matches_head) && context.prNumber) {
|
|
391
|
-
const prResult = inspectGitHubPullRequest(
|
|
392
|
-
githubClient,
|
|
393
|
-
context.upstreamRepo,
|
|
394
|
-
context.prNumber,
|
|
395
|
-
context.taskDir
|
|
396
|
-
);
|
|
397
|
-
|
|
398
|
-
if (!prResult.ok) {
|
|
399
|
-
return {
|
|
400
|
-
earlyReturn: prResult.error.retryable
|
|
401
|
-
? blockedResult(CHECK_TYPE, prResult.error.message, "network_error")
|
|
402
|
-
: failResult(CHECK_TYPE, prResult.error.message, "check_failed")
|
|
403
|
-
};
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
prLabels = (context.config.verify_in_labels_match_pr || context.config.verify_pr_type_label)
|
|
407
|
-
? prResult.value.labels
|
|
408
|
-
: null;
|
|
409
|
-
prMilestone = context.config.verify_milestone
|
|
410
|
-
? prResult.value.milestone ? { title: prResult.value.milestone } : null
|
|
411
|
-
: undefined;
|
|
412
|
-
prAssignees = context.config.verify_pr_assignee
|
|
413
|
-
? prResult.value.assignees
|
|
414
|
-
: undefined;
|
|
415
|
-
prHeadSha = prResult.value.head.sha;
|
|
307
|
+
if (context.prMarker && context.prIdentity && shouldFetchComments(context.config) && provider?.comments?.list) {
|
|
308
|
+
const listed = await provider.comments.list({ context: operationContext, parent: context.prIdentity });
|
|
309
|
+
if (!listed.ok) return {
|
|
310
|
+
earlyReturn: listed.error.retryable
|
|
311
|
+
? blockedResult(CHECK_TYPE, listed.error.message, "network_error")
|
|
312
|
+
: failResult(CHECK_TYPE, listed.error.message, "check_failed")
|
|
313
|
+
};
|
|
314
|
+
prComments = listed.value.map((comment: { id: string; body: string }) => ({ id: comment.id, body: comment.body }));
|
|
416
315
|
}
|
|
417
|
-
|
|
316
|
+
const changeRequest = facts.value.changeRequest;
|
|
418
317
|
return {
|
|
419
318
|
issue,
|
|
420
|
-
comments,
|
|
319
|
+
comments: facts.value.comments.map((comment: { id: string; body: string }) => ({ id: comment.id, body: comment.body })),
|
|
421
320
|
prComments,
|
|
422
|
-
prLabels,
|
|
423
|
-
issueType
|
|
321
|
+
prLabels: changeRequest?.labels || null,
|
|
322
|
+
issueType: issueSnapshot
|
|
323
|
+
? (issueSnapshot.issueType ? issueSnapshot.issueType.name : null)
|
|
324
|
+
: undefined,
|
|
424
325
|
issueFields,
|
|
425
|
-
prMilestone
|
|
426
|
-
|
|
427
|
-
|
|
326
|
+
prMilestone: changeRequest
|
|
327
|
+
? (changeRequest.milestone ? { title: changeRequest.milestone } : null)
|
|
328
|
+
: undefined,
|
|
329
|
+
prAssignees: changeRequest?.assignees,
|
|
330
|
+
prHeadSha: changeRequest?.headSha
|
|
428
331
|
};
|
|
429
332
|
}
|
|
430
333
|
|
|
@@ -444,14 +347,6 @@ function shouldFetchComments(config: any): any {
|
|
|
444
347
|
);
|
|
445
348
|
}
|
|
446
349
|
|
|
447
|
-
function flattenComments(value: any): any {
|
|
448
|
-
if (!Array.isArray(value)) {
|
|
449
|
-
return [];
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
return value.flatMap((page) => Array.isArray(page) ? page : []);
|
|
453
|
-
}
|
|
454
|
-
|
|
455
350
|
function checkStatusLabel(context: any, remoteData: any): any {
|
|
456
351
|
if (!context.expectedStatusLabel || !context.hasTriage) {
|
|
457
352
|
return null;
|
|
@@ -710,7 +605,7 @@ function checkInLabelsComputed(context: any, remoteData: any): any {
|
|
|
710
605
|
return null;
|
|
711
606
|
}
|
|
712
607
|
|
|
713
|
-
const expectedInLabels = computeExpectedInLabels(context.taskDir);
|
|
608
|
+
const expectedInLabels = computeExpectedInLabels(context.taskDir, context.upstreamRepo);
|
|
714
609
|
if (!expectedInLabels.ok) {
|
|
715
610
|
return expectedInLabels.type === "check_failed"
|
|
716
611
|
? failResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type)
|
|
@@ -1047,8 +942,6 @@ function mapTaskTypeToIssueType(taskType: any): any {
|
|
|
1047
942
|
return mapping[taskType] || "Task";
|
|
1048
943
|
}
|
|
1049
944
|
|
|
1050
|
-
const ISSUE_FIELDS_QUERY = `query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){issue(number:$number){issueType{name pinnedFields{__typename ... on IssueFieldSingleSelect{id name} ... on IssueFieldDate{id name} ... on IssueFieldText{id name} ... on IssueFieldNumber{id name}}} issueFieldValues(first:50){nodes{__typename ... on IssueFieldSingleSelectValue{name optionId field{... on IssueFieldSingleSelect{name}}} ... on IssueFieldDateValue{value field{... on IssueFieldDate{name}}} ... on IssueFieldTextValue{value field{... on IssueFieldText{name}}} ... on IssueFieldNumberValue{value field{... on IssueFieldNumber{name}}}}}}}}`;
|
|
1051
|
-
|
|
1052
945
|
function normalizeIssueFields(payload: any): any {
|
|
1053
946
|
const issue = payload?.data?.repository?.issue;
|
|
1054
947
|
const pinnedFields = Array.isArray(issue?.issueType?.pinnedFields)
|
|
@@ -1122,10 +1015,18 @@ function formatLabelList(labels: any): any {
|
|
|
1122
1015
|
return labels.length > 0 ? labels.join(", ") : "none";
|
|
1123
1016
|
}
|
|
1124
1017
|
|
|
1125
|
-
function computeExpectedInLabels(taskDir: any): any {
|
|
1126
|
-
const
|
|
1018
|
+
function computeExpectedInLabels(taskDir: any, repository: any): any {
|
|
1019
|
+
const task = loadTask(taskDir);
|
|
1020
|
+
if (!task.ok) {
|
|
1021
|
+
return task;
|
|
1022
|
+
}
|
|
1023
|
+
const baseRef = String(task.metadata?.delivery_base_ref || "").trim();
|
|
1024
|
+
if (!baseRef) {
|
|
1025
|
+
return { ok: false, type: "check_failed", message: "Task has no delivery_base_ref for in-label evidence" };
|
|
1026
|
+
}
|
|
1027
|
+
const changedFilesResult = gitText(["diff", `${baseRef}...HEAD`, "--name-only"], taskDir);
|
|
1127
1028
|
if (!changedFilesResult.ok) {
|
|
1128
|
-
return changedFilesResult;
|
|
1029
|
+
return { ...changedFilesResult, type: "network_error" };
|
|
1129
1030
|
}
|
|
1130
1031
|
|
|
1131
1032
|
const changedFiles = String(changedFilesResult.value || "")
|
|
@@ -1138,55 +1039,32 @@ function computeExpectedInLabels(taskDir: any): any {
|
|
|
1138
1039
|
return mapping;
|
|
1139
1040
|
}
|
|
1140
1041
|
|
|
1141
|
-
if (Object.keys(mapping.value ?? {}).length
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
for (const file of changedFiles) {
|
|
1145
|
-
for (const [label, prefixes] of Object.entries(mapping.value ?? {}) as Array<[string, string[]]>) {
|
|
1146
|
-
if (prefixes.some((prefix: any) => file.startsWith(prefix))) {
|
|
1147
|
-
labels.add(`in: ${label}`);
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
return { ok: true, labels: Array.from(labels).sort(), mode: "mapped" };
|
|
1042
|
+
if (Object.keys(mapping.value ?? {}).length === 0) {
|
|
1043
|
+
return { ok: true, labels: [], mode: "mapped" };
|
|
1153
1044
|
}
|
|
1154
1045
|
|
|
1155
|
-
const
|
|
1156
|
-
|
|
1157
|
-
"
|
|
1158
|
-
|
|
1159
|
-
"200",
|
|
1160
|
-
"--json",
|
|
1161
|
-
"name"
|
|
1162
|
-
], taskDir));
|
|
1046
|
+
const client = createGitHubClient();
|
|
1047
|
+
const repoLabelsResult = withRetry(() => client.json([
|
|
1048
|
+
"api", "--paginate", "--slurp", `repos/${repository}/labels?per_page=100`
|
|
1049
|
+
], { cwd: taskDir }));
|
|
1163
1050
|
if (!repoLabelsResult.ok) {
|
|
1164
1051
|
return repoLabelsResult;
|
|
1165
1052
|
}
|
|
1166
1053
|
|
|
1167
|
-
const
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
);
|
|
1171
|
-
|
|
1172
|
-
if (repoInLabels.size === 0) {
|
|
1173
|
-
return { ok: true, labels: [], mode: "fallback" };
|
|
1054
|
+
const repositoryLabels = validateRepositoryLabelPayload(repoLabelsResult.value);
|
|
1055
|
+
if (!repositoryLabels.ok) {
|
|
1056
|
+
return { ok: false, type: "check_failed", message: repositoryLabels.error.message };
|
|
1174
1057
|
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
const candidate = `in: ${topLevel}`;
|
|
1184
|
-
if (repoInLabels.has(candidate)) {
|
|
1185
|
-
labels.add(candidate);
|
|
1186
|
-
}
|
|
1058
|
+
const planned = planInLabelUpdate({
|
|
1059
|
+
changedFiles,
|
|
1060
|
+
currentLabels: [],
|
|
1061
|
+
mapping: mapping.value ?? {},
|
|
1062
|
+
repositoryLabels: new Set(repositoryLabels.value)
|
|
1063
|
+
});
|
|
1064
|
+
if (planned.error) {
|
|
1065
|
+
return { ok: false, type: "check_failed", message: planned.error.message };
|
|
1187
1066
|
}
|
|
1188
|
-
|
|
1189
|
-
return { ok: true, labels: Array.from(labels).sort(), mode: "fallback" };
|
|
1067
|
+
return { ok: true, labels: planned.target, mode: "mapped" };
|
|
1190
1068
|
}
|
|
1191
1069
|
|
|
1192
1070
|
function loadInLabelMapping(): any {
|
|
@@ -1197,26 +1075,10 @@ function loadInLabelMapping(): any {
|
|
|
1197
1075
|
|
|
1198
1076
|
try {
|
|
1199
1077
|
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
1200
|
-
const mapping = config?.labels?.in;
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
const normalized: Record<string, string[]> = {};
|
|
1206
|
-
for (const [label, prefixes] of Object.entries(mapping)) {
|
|
1207
|
-
if (!Array.isArray(prefixes)) {
|
|
1208
|
-
continue;
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
const cleaned = prefixes
|
|
1212
|
-
.map((value) => String(value || "").trim())
|
|
1213
|
-
.filter(Boolean);
|
|
1214
|
-
if (cleaned.length > 0) {
|
|
1215
|
-
normalized[label] = cleaned;
|
|
1216
|
-
}
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
return { ok: true, value: normalized };
|
|
1078
|
+
const mapping = validateInLabelMapping(config?.labels?.in);
|
|
1079
|
+
return mapping.ok
|
|
1080
|
+
? { ok: true, value: mapping.value }
|
|
1081
|
+
: { ok: false, type: "check_failed", message: mapping.error.message };
|
|
1220
1082
|
} catch (error: any) {
|
|
1221
1083
|
return { ok: false, type: "check_failed", message: `Unable to parse .agents/.airc.json: ${error.message}` };
|
|
1222
1084
|
}
|
|
@@ -1224,43 +1086,6 @@ function loadInLabelMapping(): any {
|
|
|
1224
1086
|
|
|
1225
1087
|
// === GitHub API ===
|
|
1226
1088
|
|
|
1227
|
-
function detectRepoOwnerType(upstreamRepo: any, taskDir: any): any {
|
|
1228
|
-
const ownerTypeResult = withRetry(() => ghText([
|
|
1229
|
-
"api",
|
|
1230
|
-
`repos/${upstreamRepo}`,
|
|
1231
|
-
"--jq",
|
|
1232
|
-
".owner.type // empty"
|
|
1233
|
-
], taskDir));
|
|
1234
|
-
|
|
1235
|
-
if (!ownerTypeResult.ok) {
|
|
1236
|
-
return "unknown";
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
return ownerTypeResult.value || "unknown";
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
function ghJson(args: any, cwd: any): any {
|
|
1243
|
-
return mapClientResult(githubClient.json(args, { cwd }));
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
function ghText(args: any, cwd: any): any {
|
|
1247
|
-
return mapClientResult(githubClient.text(args, { cwd }));
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
function ghPaginatedJson(args: any, cwd: any): any {
|
|
1251
|
-
return ghJson(args, cwd);
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1254
|
-
function mapClientResult(result: any): any {
|
|
1255
|
-
if (result.ok) return result;
|
|
1256
|
-
const checkFailed = ["RESOURCE_NOT_FOUND", "PERMISSION_DENIED", "PLATFORM_REQUEST_INVALID"].includes(result.error.code);
|
|
1257
|
-
return {
|
|
1258
|
-
ok: false,
|
|
1259
|
-
type: checkFailed ? "check_failed" : "network_error",
|
|
1260
|
-
message: result.error.message
|
|
1261
|
-
};
|
|
1262
|
-
}
|
|
1263
|
-
|
|
1264
1089
|
function gitText(args: any, cwd: any): any {
|
|
1265
1090
|
try {
|
|
1266
1091
|
const value = execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { parseTypedTaskFrontmatter } from '../task/frontmatter.ts';
|
|
5
|
+
import { readPrDeliveryFact } from '../task/pr-delivery-fact.ts';
|
|
6
|
+
import { resourceIdentityEquals, resourceIdentityNumber } from '../platform/resource-identity.ts';
|
|
7
|
+
import type { ResourceIdentity } from '../platform/resource-identity.ts';
|
|
8
|
+
import { taskIssueIdentity } from '../platform/task-identities.ts';
|
|
5
9
|
|
|
6
10
|
// ---------------------------------------------------------------------------
|
|
7
11
|
// Host resolution (PL-4): PR -> unique / ambiguous / none.
|
|
@@ -12,10 +16,12 @@ export type HostCandidate = {
|
|
|
12
16
|
taskDir: string;
|
|
13
17
|
issueNumber: number | null;
|
|
14
18
|
prNumber: number | null;
|
|
19
|
+
issueIdentity?: ResourceIdentity;
|
|
20
|
+
prIdentity?: ResourceIdentity;
|
|
15
21
|
};
|
|
16
22
|
|
|
17
23
|
export type HostResolution =
|
|
18
|
-
| { kind: 'unique'; taskId: string; taskDir: string; issueNumber: number; prNumber: number }
|
|
24
|
+
| { kind: 'unique'; taskId: string; taskDir: string; issueNumber: number; prNumber: number; issueIdentity?: ResourceIdentity; prIdentity?: ResourceIdentity }
|
|
19
25
|
| { kind: 'ambiguous'; candidates: Array<{ taskId: string; issueNumber: number }> }
|
|
20
26
|
| { kind: 'none' };
|
|
21
27
|
|
|
@@ -62,10 +68,11 @@ export function extractClosingIssueNumbers(body: string): number[] {
|
|
|
62
68
|
/**
|
|
63
69
|
* Scan `.agents/workspace/active/{task-id}/task.md` files for tasks bound to the
|
|
64
70
|
* PR number or to one of the PR's closing issues. A task is emitted at most once;
|
|
65
|
-
* a
|
|
71
|
+
* a verified fact identity hit takes priority over the issue-number reverse lookup.
|
|
66
72
|
*/
|
|
67
73
|
export function collectHostCandidates(input: {
|
|
68
|
-
prNumber
|
|
74
|
+
prNumber?: number;
|
|
75
|
+
prIdentity?: ResourceIdentity;
|
|
69
76
|
closingIssues: number[];
|
|
70
77
|
workspaceRoot: string;
|
|
71
78
|
}): HostCandidate[] {
|
|
@@ -87,13 +94,24 @@ export function collectHostCandidates(input: {
|
|
|
87
94
|
} catch {
|
|
88
95
|
continue;
|
|
89
96
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
97
|
+
let frontmatter: ReturnType<typeof parseTypedTaskFrontmatter>;
|
|
98
|
+
try { frontmatter = parseTypedTaskFrontmatter(content); } catch { continue; }
|
|
99
|
+
const issueIdentity = taskIssueIdentity(frontmatter);
|
|
100
|
+
const issueNumber = resourceIdentityNumber(issueIdentity) ?? toPositiveNumber(frontmatter.issue_number);
|
|
101
|
+
const fact = readPrDeliveryFact(frontmatter);
|
|
102
|
+
const prIdentity = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.resource : null;
|
|
103
|
+
const prNumber = resourceIdentityNumber(prIdentity);
|
|
104
|
+
const matchesPr = input.prIdentity
|
|
105
|
+
? Boolean(prIdentity && resourceIdentityEquals(prIdentity, input.prIdentity))
|
|
106
|
+
: input.prNumber !== undefined && prNumber === input.prNumber;
|
|
107
|
+
const identityDetails = {
|
|
108
|
+
...(issueIdentity && issueIdentity.kind !== 'number' ? { issueIdentity } : {}),
|
|
109
|
+
...(prIdentity && prIdentity.kind !== 'number' ? { prIdentity } : {})
|
|
110
|
+
};
|
|
111
|
+
if (matchesPr) {
|
|
112
|
+
candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber, ...identityDetails });
|
|
95
113
|
} else if (issueNumber !== null && input.closingIssues.includes(issueNumber)) {
|
|
96
|
-
candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber });
|
|
114
|
+
candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber, ...identityDetails });
|
|
97
115
|
}
|
|
98
116
|
}
|
|
99
117
|
return candidates;
|
|
@@ -113,7 +131,9 @@ export function resolveHostFromCandidates(candidates: HostCandidate[]): HostReso
|
|
|
113
131
|
taskId: candidate.taskId,
|
|
114
132
|
taskDir: candidate.taskDir,
|
|
115
133
|
issueNumber: candidate.issueNumber ?? 0,
|
|
116
|
-
prNumber: candidate.prNumber ?? 0
|
|
134
|
+
prNumber: candidate.prNumber ?? 0,
|
|
135
|
+
...(candidate.issueIdentity ? { issueIdentity: candidate.issueIdentity } : {}),
|
|
136
|
+
...(candidate.prIdentity ? { prIdentity: candidate.prIdentity } : {})
|
|
117
137
|
};
|
|
118
138
|
}
|
|
119
139
|
return {
|