@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
|
@@ -2,13 +2,16 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
import { execFileSync } from "node:child_process";
|
|
5
|
-
import {
|
|
6
|
-
import { resolvePlatformContext } from "./context.js";
|
|
5
|
+
import { resolvePlatformProviderContext } from "./context.js";
|
|
7
6
|
import { hasCheckedRequirement, resolveRequirementSection } from "./issue-metadata.js";
|
|
8
|
-
import {
|
|
9
|
-
import { listRemoteComments } from "./issue-comments.js";
|
|
7
|
+
import { requirementSectionAnchors } from "./issues.js";
|
|
10
8
|
import { taskTypeLabel } from "./metadata-labels.js";
|
|
9
|
+
import { planInLabelUpdate, validateInLabelMapping, validateRepositoryLabelPayload } from "./in-label-sync.js";
|
|
11
10
|
import { inspectGitHubPullRequest } from "./pull-requests.js";
|
|
11
|
+
import { createGitHubClient } from "./github-client.js";
|
|
12
|
+
import { readPrDeliveryFact } from "../task/pr-delivery-fact.js";
|
|
13
|
+
import { providerError, providerOperationContext, resourceIdentityNumber, unsupportedProviderOperation } from "./provider-bridge.js";
|
|
14
|
+
import { taskIssueIdentity } from "./task-identities.js";
|
|
12
15
|
const CHECK_TYPE = "platform-sync";
|
|
13
16
|
const VERSION_LINE_REGEX = /^[0-9]+\.[0-9]+\.x$/;
|
|
14
17
|
const FRONTMATTER_FIELD_MAP = {
|
|
@@ -25,7 +28,6 @@ const OPTION_LOCALIZATION = {
|
|
|
25
28
|
};
|
|
26
29
|
let activeShared = null;
|
|
27
30
|
let repoRoot = "";
|
|
28
|
-
const githubClient = createGitHubClient();
|
|
29
31
|
export function getDefaults() {
|
|
30
32
|
return {
|
|
31
33
|
statusLabels: {
|
|
@@ -78,20 +80,14 @@ function blockedResult(...args) {
|
|
|
78
80
|
function safeStat(...args) {
|
|
79
81
|
return getShared().safeStat(...args);
|
|
80
82
|
}
|
|
81
|
-
function
|
|
82
|
-
return getShared().parseIssueNumber(...args);
|
|
83
|
-
}
|
|
84
|
-
function parsePrNumber(...args) {
|
|
85
|
-
return getShared().parsePrNumber(...args);
|
|
86
|
-
}
|
|
87
|
-
export function check({ taskDir, config, artifactFile }, shared) {
|
|
83
|
+
export async function check({ taskDir, config, artifactFile }, shared) {
|
|
88
84
|
activeShared = shared;
|
|
89
85
|
repoRoot = shared.repoRoot;
|
|
90
|
-
const context = buildSyncContext({ taskDir, config, artifactFile });
|
|
86
|
+
const context = await buildSyncContext({ taskDir, config, artifactFile });
|
|
91
87
|
if (context.earlyReturn) {
|
|
92
88
|
return context.earlyReturn;
|
|
93
89
|
}
|
|
94
|
-
const remoteData = fetchRemoteData(context);
|
|
90
|
+
const remoteData = await fetchRemoteData(context);
|
|
95
91
|
if (remoteData.earlyReturn) {
|
|
96
92
|
return remoteData.earlyReturn;
|
|
97
93
|
}
|
|
@@ -119,25 +115,32 @@ export function check({ taskDir, config, artifactFile }, shared) {
|
|
|
119
115
|
return result;
|
|
120
116
|
}
|
|
121
117
|
}
|
|
122
|
-
return passResult(CHECK_TYPE, `
|
|
118
|
+
return passResult(CHECK_TYPE, `Platform sync checks passed for Issue ${context.issueNumber || "identity"}`);
|
|
123
119
|
}
|
|
124
|
-
function buildSyncContext({ taskDir, config, artifactFile }) {
|
|
120
|
+
async function buildSyncContext({ taskDir, config, artifactFile }) {
|
|
125
121
|
const task = loadTask(taskDir);
|
|
126
122
|
if (!task.ok) {
|
|
127
123
|
return { earlyReturn: failResult(CHECK_TYPE, task.message) };
|
|
128
124
|
}
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
|
|
125
|
+
const issueIdentity = taskIssueIdentity(task.metadata);
|
|
126
|
+
const issueNumber = resourceIdentityNumber(issueIdentity);
|
|
127
|
+
const fact = readPrDeliveryFact(task.metadata);
|
|
128
|
+
if (fact.status === "invalid") {
|
|
129
|
+
return { earlyReturn: failResult(CHECK_TYPE, fact.error.message, "check_failed") };
|
|
130
|
+
}
|
|
131
|
+
const prIdentity = fact.status === "valid" && fact.fact.state === "bound" ? fact.fact.identity.resource : null;
|
|
132
|
+
const prNumber = resourceIdentityNumber(prIdentity);
|
|
133
|
+
if (config.when === "issue_number_exists" && !issueIdentity) {
|
|
132
134
|
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no issue_number") };
|
|
133
135
|
}
|
|
134
|
-
if (config.when === "
|
|
135
|
-
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no
|
|
136
|
+
if (config.when === "pr_fact_bound" && !prIdentity) {
|
|
137
|
+
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no verified bound pull request") };
|
|
136
138
|
}
|
|
137
|
-
if (!
|
|
139
|
+
if (!issueIdentity) {
|
|
138
140
|
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: platform-sync not required for this task") };
|
|
139
141
|
}
|
|
140
|
-
const
|
|
142
|
+
const loaded = await resolvePlatformProviderContext({ cwd: repoRoot });
|
|
143
|
+
const platformContext = loaded.ok ? loaded.value.context : loaded.context;
|
|
141
144
|
if (platformContext.status === "failed") {
|
|
142
145
|
return { earlyReturn: failResult(CHECK_TYPE, platformContext.error?.message || "Platform context failed", "check_failed") };
|
|
143
146
|
}
|
|
@@ -150,7 +153,6 @@ function buildSyncContext({ taskDir, config, artifactFile }) {
|
|
|
150
153
|
}
|
|
151
154
|
return { earlyReturn: passResult(CHECK_TYPE, `Skipped: ${platformContext.error?.message || "platform unavailable"}`) };
|
|
152
155
|
}
|
|
153
|
-
const repoOwnerType = detectRepoOwnerType(platformContext.platform.repository, taskDir);
|
|
154
156
|
const expectedValues = resolveExpectedValues(config);
|
|
155
157
|
if (!expectedValues.ok) {
|
|
156
158
|
return { earlyReturn: failResult(CHECK_TYPE, expectedValues.message, "check_failed") };
|
|
@@ -168,15 +170,20 @@ function buildSyncContext({ taskDir, config, artifactFile }) {
|
|
|
168
170
|
config,
|
|
169
171
|
artifactFile,
|
|
170
172
|
artifactPath,
|
|
173
|
+
issueIdentity,
|
|
174
|
+
prIdentity,
|
|
171
175
|
issueNumber,
|
|
172
176
|
prNumber,
|
|
173
177
|
upstreamRepo: platformContext.platform.repository,
|
|
174
|
-
repoOwnerType,
|
|
178
|
+
repoOwnerType: String(loaded.ok ? loaded.value.snapshot.metadata?.ownerType || "unknown" : "unknown"),
|
|
175
179
|
hasTriage: platformContext.capabilities.triage,
|
|
176
180
|
hasPush: platformContext.capabilities.push,
|
|
177
181
|
expectedStatusLabel: expectedValues.statusLabel,
|
|
178
182
|
marker,
|
|
179
|
-
prMarker
|
|
183
|
+
prMarker,
|
|
184
|
+
provider: loaded.ok ? loaded.value.provider : null,
|
|
185
|
+
providerType: loaded.ok ? loaded.value.providerType : null,
|
|
186
|
+
loadedContext: loaded.ok ? loaded.value : null
|
|
180
187
|
};
|
|
181
188
|
}
|
|
182
189
|
function resolveExpectedValues(config) {
|
|
@@ -225,139 +232,69 @@ function resolveDefaultValue({ collection, key, value, configKey }) {
|
|
|
225
232
|
}
|
|
226
233
|
return { ok: true, value: resolvedValue };
|
|
227
234
|
}
|
|
228
|
-
function fetchRemoteData(context) {
|
|
229
|
-
const
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
:
|
|
241
|
-
|
|
242
|
-
type: sharedIssue.error.retryable ? "network_error" : "check_failed",
|
|
243
|
-
message: sharedIssue.error.message
|
|
244
|
-
};
|
|
245
|
-
if (!issueResult.ok) {
|
|
246
|
-
return {
|
|
247
|
-
earlyReturn: issueResult.type === "check_failed"
|
|
248
|
-
? failResult(CHECK_TYPE, issueResult.message, issueResult.type)
|
|
249
|
-
: blockedResult(CHECK_TYPE, issueResult.message, issueResult.type)
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
const issue = issueResult.value;
|
|
253
|
-
if (context.config.issue_must_exist !== false && !issue) {
|
|
235
|
+
async function fetchRemoteData(context) {
|
|
236
|
+
const provider = context.provider;
|
|
237
|
+
const operationContext = providerOperationContext(context.loadedContext, context.taskDir);
|
|
238
|
+
const facts = provider?.verification?.fetchRemoteFacts
|
|
239
|
+
? await provider.verification.fetchRemoteFacts({
|
|
240
|
+
context: operationContext,
|
|
241
|
+
taskId: context.task?.metadata?.id || context.task?.id || "",
|
|
242
|
+
...(context.issueIdentity ? { issue: context.issueIdentity } : {}),
|
|
243
|
+
...(context.prIdentity ? { changeRequest: context.prIdentity } : {}),
|
|
244
|
+
includeComments: shouldFetchComments(context.config),
|
|
245
|
+
includeFields: Boolean(context.config.verify_issue_fields)
|
|
246
|
+
})
|
|
247
|
+
: unsupportedProviderOperation(provider, "verification.fetchRemoteFacts");
|
|
248
|
+
if (!facts.ok) {
|
|
254
249
|
return {
|
|
255
|
-
earlyReturn:
|
|
250
|
+
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")
|
|
256
253
|
};
|
|
257
254
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
], context.taskDir));
|
|
266
|
-
if (!commentsResult.ok) {
|
|
267
|
-
return {
|
|
268
|
-
earlyReturn: commentsResult.type === "check_failed"
|
|
269
|
-
? failResult(CHECK_TYPE, commentsResult.message, commentsResult.type)
|
|
270
|
-
: blockedResult(CHECK_TYPE, commentsResult.message, commentsResult.type)
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
comments = flattenComments(commentsResult.value);
|
|
274
|
-
}
|
|
275
|
-
let prComments = null;
|
|
276
|
-
if (context.prMarker) {
|
|
277
|
-
if (!context.prNumber) {
|
|
278
|
-
return {
|
|
279
|
-
earlyReturn: failResult(CHECK_TYPE, "Expected a valid pr_number for PR comment verification", "check_failed")
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
const prCommentsResult = listRemoteComments(githubClient, context.upstreamRepo, context.prNumber, context.taskDir);
|
|
283
|
-
if (!prCommentsResult.ok) {
|
|
284
|
-
return {
|
|
285
|
-
earlyReturn: prCommentsResult.error.retryable
|
|
286
|
-
? blockedResult(CHECK_TYPE, prCommentsResult.error.message, "network_error")
|
|
287
|
-
: failResult(CHECK_TYPE, prCommentsResult.error.message, "check_failed")
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
prComments = prCommentsResult.value;
|
|
291
|
-
}
|
|
292
|
-
let issueType;
|
|
293
|
-
if (context.config.verify_issue_type && context.hasPush) {
|
|
294
|
-
const issueTypeResult = withRetry(() => ghText([
|
|
295
|
-
"api",
|
|
296
|
-
`repos/${context.upstreamRepo}/issues/${context.issueNumber}`,
|
|
297
|
-
"--jq",
|
|
298
|
-
".type.name // empty"
|
|
299
|
-
], context.taskDir));
|
|
300
|
-
if (issueTypeResult.ok) {
|
|
301
|
-
issueType = issueTypeResult.value || null;
|
|
255
|
+
const issueSnapshot = facts.value.issue;
|
|
256
|
+
const issue = issueSnapshot
|
|
257
|
+
? {
|
|
258
|
+
state: issueSnapshot.state.toUpperCase(),
|
|
259
|
+
labels: issueSnapshot.labels.map((name) => ({ name })),
|
|
260
|
+
body: issueSnapshot.body,
|
|
261
|
+
milestone: issueSnapshot.milestone ? { title: issueSnapshot.milestone } : null
|
|
302
262
|
}
|
|
303
|
-
|
|
263
|
+
: null;
|
|
304
264
|
let issueFields;
|
|
305
|
-
if (context.config.verify_issue_fields &&
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
"
|
|
310
|
-
|
|
311
|
-
`query=${ISSUE_FIELDS_QUERY}`,
|
|
312
|
-
"-F",
|
|
313
|
-
`owner=${owner}`,
|
|
314
|
-
"-F",
|
|
315
|
-
`name=${name}`,
|
|
316
|
-
"-F",
|
|
317
|
-
`number=${context.issueNumber}`
|
|
318
|
-
], context.taskDir));
|
|
319
|
-
if (issueFieldsResult.ok) {
|
|
320
|
-
issueFields = normalizeIssueFields(issueFieldsResult.value);
|
|
321
|
-
}
|
|
265
|
+
if (context.config.verify_issue_fields && issueSnapshot?.issueType) {
|
|
266
|
+
const fieldKinds = new Map(issueSnapshot.issueType.fields.map((field) => [field.name, field.kind]));
|
|
267
|
+
issueFields = {
|
|
268
|
+
pinnedNames: new Set(issueSnapshot.issueType.fields.map((field) => field.name)),
|
|
269
|
+
values: new Map(Object.entries(issueSnapshot.fields).map(([name, value]) => [name, { kind: fieldKinds.get(name) || (typeof value === "number" ? "number" : "single-select"), value }]))
|
|
270
|
+
};
|
|
322
271
|
}
|
|
323
|
-
let
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
if (((context.config.verify_in_labels_match_pr && context.hasTriage)
|
|
328
|
-
|| (context.config.verify_pr_type_label && context.hasTriage)
|
|
329
|
-
|| (context.config.verify_milestone && context.hasTriage)
|
|
330
|
-
|| (context.config.verify_pr_assignee && context.hasPush)
|
|
331
|
-
|| context.config.verify_pr_comment_last_commit_matches_head) && context.prNumber) {
|
|
332
|
-
const prResult = inspectGitHubPullRequest(githubClient, context.upstreamRepo, context.prNumber, context.taskDir);
|
|
333
|
-
if (!prResult.ok) {
|
|
272
|
+
let prComments = null;
|
|
273
|
+
if (context.prMarker && context.prIdentity && shouldFetchComments(context.config) && provider?.comments?.list) {
|
|
274
|
+
const listed = await provider.comments.list({ context: operationContext, parent: context.prIdentity });
|
|
275
|
+
if (!listed.ok)
|
|
334
276
|
return {
|
|
335
|
-
earlyReturn:
|
|
336
|
-
? blockedResult(CHECK_TYPE,
|
|
337
|
-
: failResult(CHECK_TYPE,
|
|
277
|
+
earlyReturn: listed.error.retryable
|
|
278
|
+
? blockedResult(CHECK_TYPE, listed.error.message, "network_error")
|
|
279
|
+
: failResult(CHECK_TYPE, listed.error.message, "check_failed")
|
|
338
280
|
};
|
|
339
|
-
}
|
|
340
|
-
prLabels = (context.config.verify_in_labels_match_pr || context.config.verify_pr_type_label)
|
|
341
|
-
? prResult.value.labels
|
|
342
|
-
: null;
|
|
343
|
-
prMilestone = context.config.verify_milestone
|
|
344
|
-
? prResult.value.milestone ? { title: prResult.value.milestone } : null
|
|
345
|
-
: undefined;
|
|
346
|
-
prAssignees = context.config.verify_pr_assignee
|
|
347
|
-
? prResult.value.assignees
|
|
348
|
-
: undefined;
|
|
349
|
-
prHeadSha = prResult.value.head.sha;
|
|
281
|
+
prComments = listed.value.map((comment) => ({ id: comment.id, body: comment.body }));
|
|
350
282
|
}
|
|
283
|
+
const changeRequest = facts.value.changeRequest;
|
|
351
284
|
return {
|
|
352
285
|
issue,
|
|
353
|
-
comments,
|
|
286
|
+
comments: facts.value.comments.map((comment) => ({ id: comment.id, body: comment.body })),
|
|
354
287
|
prComments,
|
|
355
|
-
prLabels,
|
|
356
|
-
issueType
|
|
288
|
+
prLabels: changeRequest?.labels || null,
|
|
289
|
+
issueType: issueSnapshot
|
|
290
|
+
? (issueSnapshot.issueType ? issueSnapshot.issueType.name : null)
|
|
291
|
+
: undefined,
|
|
357
292
|
issueFields,
|
|
358
|
-
prMilestone
|
|
359
|
-
|
|
360
|
-
|
|
293
|
+
prMilestone: changeRequest
|
|
294
|
+
? (changeRequest.milestone ? { title: changeRequest.milestone } : null)
|
|
295
|
+
: undefined,
|
|
296
|
+
prAssignees: changeRequest?.assignees,
|
|
297
|
+
prHeadSha: changeRequest?.headSha
|
|
361
298
|
};
|
|
362
299
|
}
|
|
363
300
|
function mapTaskTypeToLabel(taskType) {
|
|
@@ -372,12 +309,6 @@ function shouldFetchComments(config) {
|
|
|
372
309
|
|| config.verify_comment_content
|
|
373
310
|
|| config.verify_task_comment_content);
|
|
374
311
|
}
|
|
375
|
-
function flattenComments(value) {
|
|
376
|
-
if (!Array.isArray(value)) {
|
|
377
|
-
return [];
|
|
378
|
-
}
|
|
379
|
-
return value.flatMap((page) => Array.isArray(page) ? page : []);
|
|
380
|
-
}
|
|
381
312
|
function checkStatusLabel(context, remoteData) {
|
|
382
313
|
if (!context.expectedStatusLabel || !context.hasTriage) {
|
|
383
314
|
return null;
|
|
@@ -536,7 +467,7 @@ function checkInLabelsComputed(context, remoteData) {
|
|
|
536
467
|
if (!context.config.verify_in_labels_computed || !context.hasTriage) {
|
|
537
468
|
return null;
|
|
538
469
|
}
|
|
539
|
-
const expectedInLabels = computeExpectedInLabels(context.taskDir);
|
|
470
|
+
const expectedInLabels = computeExpectedInLabels(context.taskDir, context.upstreamRepo);
|
|
540
471
|
if (!expectedInLabels.ok) {
|
|
541
472
|
return expectedInLabels.type === "check_failed"
|
|
542
473
|
? failResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type)
|
|
@@ -776,7 +707,6 @@ function mapTaskTypeToIssueType(taskType) {
|
|
|
776
707
|
};
|
|
777
708
|
return mapping[taskType] || "Task";
|
|
778
709
|
}
|
|
779
|
-
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}}}}}}}}`;
|
|
780
710
|
function normalizeIssueFields(payload) {
|
|
781
711
|
const issue = payload?.data?.repository?.issue;
|
|
782
712
|
const pinnedFields = Array.isArray(issue?.issueType?.pinnedFields)
|
|
@@ -837,10 +767,18 @@ function arraysEqual(left, right) {
|
|
|
837
767
|
function formatLabelList(labels) {
|
|
838
768
|
return labels.length > 0 ? labels.join(", ") : "none";
|
|
839
769
|
}
|
|
840
|
-
function computeExpectedInLabels(taskDir) {
|
|
841
|
-
const
|
|
770
|
+
function computeExpectedInLabels(taskDir, repository) {
|
|
771
|
+
const task = loadTask(taskDir);
|
|
772
|
+
if (!task.ok) {
|
|
773
|
+
return task;
|
|
774
|
+
}
|
|
775
|
+
const baseRef = String(task.metadata?.delivery_base_ref || "").trim();
|
|
776
|
+
if (!baseRef) {
|
|
777
|
+
return { ok: false, type: "check_failed", message: "Task has no delivery_base_ref for in-label evidence" };
|
|
778
|
+
}
|
|
779
|
+
const changedFilesResult = gitText(["diff", `${baseRef}...HEAD`, "--name-only"], taskDir);
|
|
842
780
|
if (!changedFilesResult.ok) {
|
|
843
|
-
return changedFilesResult;
|
|
781
|
+
return { ...changedFilesResult, type: "network_error" };
|
|
844
782
|
}
|
|
845
783
|
const changedFiles = String(changedFilesResult.value || "")
|
|
846
784
|
.split(/\r?\n/)
|
|
@@ -850,45 +788,30 @@ function computeExpectedInLabels(taskDir) {
|
|
|
850
788
|
if (!mapping.ok) {
|
|
851
789
|
return mapping;
|
|
852
790
|
}
|
|
853
|
-
if (Object.keys(mapping.value ?? {}).length
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
return { ok: true, labels: Array.from(labels).sort(), mode: "mapped" };
|
|
863
|
-
}
|
|
864
|
-
const repoLabelsResult = withRetry(() => ghJson([
|
|
865
|
-
"label",
|
|
866
|
-
"list",
|
|
867
|
-
"--limit",
|
|
868
|
-
"200",
|
|
869
|
-
"--json",
|
|
870
|
-
"name"
|
|
871
|
-
], taskDir));
|
|
791
|
+
if (Object.keys(mapping.value ?? {}).length === 0) {
|
|
792
|
+
return { ok: true, labels: [], mode: "mapped" };
|
|
793
|
+
}
|
|
794
|
+
const client = createGitHubClient();
|
|
795
|
+
const repoLabelsResult = withRetry(() => client.json([
|
|
796
|
+
"api", "--paginate", "--slurp", `repos/${repository}/labels?per_page=100`
|
|
797
|
+
], { cwd: taskDir }));
|
|
872
798
|
if (!repoLabelsResult.ok) {
|
|
873
799
|
return repoLabelsResult;
|
|
874
800
|
}
|
|
875
|
-
const
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
return { ok: true, labels: [], mode: "fallback" };
|
|
801
|
+
const repositoryLabels = validateRepositoryLabelPayload(repoLabelsResult.value);
|
|
802
|
+
if (!repositoryLabels.ok) {
|
|
803
|
+
return { ok: false, type: "check_failed", message: repositoryLabels.error.message };
|
|
879
804
|
}
|
|
880
|
-
const
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
labels.add(candidate);
|
|
889
|
-
}
|
|
805
|
+
const planned = planInLabelUpdate({
|
|
806
|
+
changedFiles,
|
|
807
|
+
currentLabels: [],
|
|
808
|
+
mapping: mapping.value ?? {},
|
|
809
|
+
repositoryLabels: new Set(repositoryLabels.value)
|
|
810
|
+
});
|
|
811
|
+
if (planned.error) {
|
|
812
|
+
return { ok: false, type: "check_failed", message: planned.error.message };
|
|
890
813
|
}
|
|
891
|
-
return { ok: true, labels:
|
|
814
|
+
return { ok: true, labels: planned.target, mode: "mapped" };
|
|
892
815
|
}
|
|
893
816
|
function loadInLabelMapping() {
|
|
894
817
|
const configPath = path.join(repoRoot, ".agents", ".airc.json");
|
|
@@ -897,60 +820,16 @@ function loadInLabelMapping() {
|
|
|
897
820
|
}
|
|
898
821
|
try {
|
|
899
822
|
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
900
|
-
const mapping = config?.labels?.in;
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
const normalized = {};
|
|
905
|
-
for (const [label, prefixes] of Object.entries(mapping)) {
|
|
906
|
-
if (!Array.isArray(prefixes)) {
|
|
907
|
-
continue;
|
|
908
|
-
}
|
|
909
|
-
const cleaned = prefixes
|
|
910
|
-
.map((value) => String(value || "").trim())
|
|
911
|
-
.filter(Boolean);
|
|
912
|
-
if (cleaned.length > 0) {
|
|
913
|
-
normalized[label] = cleaned;
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
return { ok: true, value: normalized };
|
|
823
|
+
const mapping = validateInLabelMapping(config?.labels?.in);
|
|
824
|
+
return mapping.ok
|
|
825
|
+
? { ok: true, value: mapping.value }
|
|
826
|
+
: { ok: false, type: "check_failed", message: mapping.error.message };
|
|
917
827
|
}
|
|
918
828
|
catch (error) {
|
|
919
829
|
return { ok: false, type: "check_failed", message: `Unable to parse .agents/.airc.json: ${error.message}` };
|
|
920
830
|
}
|
|
921
831
|
}
|
|
922
832
|
// === GitHub API ===
|
|
923
|
-
function detectRepoOwnerType(upstreamRepo, taskDir) {
|
|
924
|
-
const ownerTypeResult = withRetry(() => ghText([
|
|
925
|
-
"api",
|
|
926
|
-
`repos/${upstreamRepo}`,
|
|
927
|
-
"--jq",
|
|
928
|
-
".owner.type // empty"
|
|
929
|
-
], taskDir));
|
|
930
|
-
if (!ownerTypeResult.ok) {
|
|
931
|
-
return "unknown";
|
|
932
|
-
}
|
|
933
|
-
return ownerTypeResult.value || "unknown";
|
|
934
|
-
}
|
|
935
|
-
function ghJson(args, cwd) {
|
|
936
|
-
return mapClientResult(githubClient.json(args, { cwd }));
|
|
937
|
-
}
|
|
938
|
-
function ghText(args, cwd) {
|
|
939
|
-
return mapClientResult(githubClient.text(args, { cwd }));
|
|
940
|
-
}
|
|
941
|
-
function ghPaginatedJson(args, cwd) {
|
|
942
|
-
return ghJson(args, cwd);
|
|
943
|
-
}
|
|
944
|
-
function mapClientResult(result) {
|
|
945
|
-
if (result.ok)
|
|
946
|
-
return result;
|
|
947
|
-
const checkFailed = ["RESOURCE_NOT_FOUND", "PERMISSION_DENIED", "PLATFORM_REQUEST_INVALID"].includes(result.error.code);
|
|
948
|
-
return {
|
|
949
|
-
ok: false,
|
|
950
|
-
type: checkFailed ? "check_failed" : "network_error",
|
|
951
|
-
message: result.error.message
|
|
952
|
-
};
|
|
953
|
-
}
|
|
954
833
|
function gitText(args, cwd) {
|
|
955
834
|
try {
|
|
956
835
|
const value = execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { parseTypedTaskFrontmatter } from '../task/frontmatter.js';
|
|
4
|
+
import { readPrDeliveryFact } from '../task/pr-delivery-fact.js';
|
|
5
|
+
import { resourceIdentityEquals, resourceIdentityNumber } from '../platform/resource-identity.js';
|
|
6
|
+
import { taskIssueIdentity } from '../platform/task-identities.js';
|
|
4
7
|
export class HostResolutionError extends Error {
|
|
5
8
|
code;
|
|
6
9
|
constructor(code, message) {
|
|
@@ -38,7 +41,7 @@ export function extractClosingIssueNumbers(body) {
|
|
|
38
41
|
/**
|
|
39
42
|
* Scan `.agents/workspace/active/{task-id}/task.md` files for tasks bound to the
|
|
40
43
|
* PR number or to one of the PR's closing issues. A task is emitted at most once;
|
|
41
|
-
* a
|
|
44
|
+
* a verified fact identity hit takes priority over the issue-number reverse lookup.
|
|
42
45
|
*/
|
|
43
46
|
export function collectHostCandidates(input) {
|
|
44
47
|
const activeRoot = path.join(input.workspaceRoot, '.agents', 'workspace', 'active');
|
|
@@ -62,14 +65,30 @@ export function collectHostCandidates(input) {
|
|
|
62
65
|
catch {
|
|
63
66
|
continue;
|
|
64
67
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
let frontmatter;
|
|
69
|
+
try {
|
|
70
|
+
frontmatter = parseTypedTaskFrontmatter(content);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const issueIdentity = taskIssueIdentity(frontmatter);
|
|
76
|
+
const issueNumber = resourceIdentityNumber(issueIdentity) ?? toPositiveNumber(frontmatter.issue_number);
|
|
77
|
+
const fact = readPrDeliveryFact(frontmatter);
|
|
78
|
+
const prIdentity = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.resource : null;
|
|
79
|
+
const prNumber = resourceIdentityNumber(prIdentity);
|
|
80
|
+
const matchesPr = input.prIdentity
|
|
81
|
+
? Boolean(prIdentity && resourceIdentityEquals(prIdentity, input.prIdentity))
|
|
82
|
+
: input.prNumber !== undefined && prNumber === input.prNumber;
|
|
83
|
+
const identityDetails = {
|
|
84
|
+
...(issueIdentity && issueIdentity.kind !== 'number' ? { issueIdentity } : {}),
|
|
85
|
+
...(prIdentity && prIdentity.kind !== 'number' ? { prIdentity } : {})
|
|
86
|
+
};
|
|
87
|
+
if (matchesPr) {
|
|
88
|
+
candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber, ...identityDetails });
|
|
70
89
|
}
|
|
71
90
|
else if (issueNumber !== null && input.closingIssues.includes(issueNumber)) {
|
|
72
|
-
candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber });
|
|
91
|
+
candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber, ...identityDetails });
|
|
73
92
|
}
|
|
74
93
|
}
|
|
75
94
|
return candidates;
|
|
@@ -89,7 +108,9 @@ export function resolveHostFromCandidates(candidates) {
|
|
|
89
108
|
taskId: candidate.taskId,
|
|
90
109
|
taskDir: candidate.taskDir,
|
|
91
110
|
issueNumber: candidate.issueNumber ?? 0,
|
|
92
|
-
prNumber: candidate.prNumber ?? 0
|
|
111
|
+
prNumber: candidate.prNumber ?? 0,
|
|
112
|
+
...(candidate.issueIdentity ? { issueIdentity: candidate.issueIdentity } : {}),
|
|
113
|
+
...(candidate.prIdentity ? { prIdentity: candidate.prIdentity } : {})
|
|
93
114
|
};
|
|
94
115
|
}
|
|
95
116
|
return {
|