@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,8 +2,9 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { execFileSync } from 'node:child_process';
|
|
4
4
|
import { createHash } from 'node:crypto';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { resolvePlatformProviderContext } from './context.js';
|
|
6
|
+
import { providerError, providerOperationContext, providerStatus, unsupportedProviderOperation } from './provider-bridge.js';
|
|
7
|
+
import { resourceIdentityNumber } from './resource-identity.js';
|
|
7
8
|
const unsupportedError = {
|
|
8
9
|
code: 'PLATFORM_RELEASE_NOTES_UNSUPPORTED',
|
|
9
10
|
message: 'Release notes are not supported for the configured platform',
|
|
@@ -103,14 +104,21 @@ function configuredPlatform(cwd) {
|
|
|
103
104
|
return null;
|
|
104
105
|
}
|
|
105
106
|
}
|
|
106
|
-
function releaseNoteContext(input, options = {}) {
|
|
107
|
+
async function releaseNoteContext(input, options = {}) {
|
|
107
108
|
const historyLimit = input.historyLimit ?? 3;
|
|
108
109
|
if (!input.fromTag || !input.toTag || !input.branch || !Number.isInteger(historyLimit) || historyLimit < 1 || historyLimit > 20) {
|
|
109
110
|
return { ...baseResult('failed'), error: { code: 'RELEASE_NOTES_INPUT_INVALID', message: 'from-tag, to-tag, branch, and a history limit from 1 to 20 are required', retryable: false } };
|
|
110
111
|
}
|
|
111
112
|
const cwd = path.resolve(options.cwd || process.cwd());
|
|
112
113
|
const platformType = options.platformType ?? configuredPlatform(cwd);
|
|
113
|
-
|
|
114
|
+
const loaded = await resolvePlatformProviderContext({ cwd, platformType: platformType || undefined, client: options.client });
|
|
115
|
+
if (!loaded.ok) {
|
|
116
|
+
if (loaded.context.status === 'no-op')
|
|
117
|
+
return baseResult('no-op');
|
|
118
|
+
const status = loaded.context.status === 'blocked' ? 'blocked' : 'failed';
|
|
119
|
+
return { ...baseResult(status), error: loaded.context.error };
|
|
120
|
+
}
|
|
121
|
+
if (!loaded.value.context.platform.repository)
|
|
114
122
|
return baseResult('no-op');
|
|
115
123
|
let fromOid;
|
|
116
124
|
let toOid;
|
|
@@ -132,28 +140,24 @@ function releaseNoteContext(input, options = {}) {
|
|
|
132
140
|
catch {
|
|
133
141
|
return { ...baseResult('failed'), error: { code: 'RELEASE_NOTES_RANGE_INVALID', message: 'The release tag range is missing or is not ancestral', retryable: false } };
|
|
134
142
|
}
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
fromTime,
|
|
148
|
-
toTime
|
|
149
|
-
}, { cwd, client: options.client });
|
|
150
|
-
if (platform.status === 'blocked' || platform.status === 'failed' || !('authors' in platform)) {
|
|
151
|
-
return { ...baseResult(platform.status), error: platform.error };
|
|
152
|
-
}
|
|
143
|
+
const platform = loaded.value.provider.releases?.collectNotes
|
|
144
|
+
? await loaded.value.provider.releases.collectNotes({
|
|
145
|
+
context: providerOperationContext(loaded.value),
|
|
146
|
+
commitOids: commitFacts.map((item) => item.oid),
|
|
147
|
+
branch: input.branch,
|
|
148
|
+
historyLimit,
|
|
149
|
+
fromTime,
|
|
150
|
+
toTime
|
|
151
|
+
})
|
|
152
|
+
: unsupportedProviderOperation(loaded.value.provider, 'releases.collectNotes');
|
|
153
|
+
if (!platform.ok)
|
|
154
|
+
return { ...baseResult(platform.error.retryable ? 'blocked' : 'failed'), error: providerError(platform.error, 'PLATFORM_PROVIDER_OPERATION_FAILED') };
|
|
153
155
|
const commits = commitFacts.map((commit) => {
|
|
154
156
|
const seen = new Set();
|
|
155
|
-
const authors =
|
|
156
|
-
|
|
157
|
+
const authors = platform.value.history.filter((item) => item.sha === commit.oid).flatMap((item) => item.author ? [item.author] : [])
|
|
158
|
+
.concat(platform.value.actors)
|
|
159
|
+
.filter((actor) => {
|
|
160
|
+
const key = actor.id || actor.name || '';
|
|
157
161
|
if (seen.has(key))
|
|
158
162
|
return false;
|
|
159
163
|
seen.add(key);
|
|
@@ -161,43 +165,37 @@ function releaseNoteContext(input, options = {}) {
|
|
|
161
165
|
});
|
|
162
166
|
return { ...commit, authors };
|
|
163
167
|
});
|
|
164
|
-
const pullRequests = platform.
|
|
168
|
+
const pullRequests = platform.value.mergedPullRequests
|
|
165
169
|
.map((item) => ({
|
|
166
|
-
number:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
?
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
labels: Array.isArray(value.labels) ? value.labels.map((label) => String(label.name || label)) : [],
|
|
183
|
-
author: value.author && typeof value.author === 'object'
|
|
184
|
-
? { login: String(value.author.login || '').toLowerCase(), bot: String(value.author.login || '').endsWith('[bot]') }
|
|
185
|
-
: null
|
|
186
|
-
};
|
|
187
|
-
}) : []
|
|
170
|
+
number: item.number || resourceIdentityNumber(item.identity) || 0,
|
|
171
|
+
...(item.identity ? { identity: item.identity } : {}),
|
|
172
|
+
title: item.title,
|
|
173
|
+
body: item.body,
|
|
174
|
+
url: item.displayUrl || '',
|
|
175
|
+
mergedAt: item.mergedAt || '',
|
|
176
|
+
labels: item.labels || [],
|
|
177
|
+
author: item.author ? { login: item.author.name || item.author.id || '', bot: false } : null,
|
|
178
|
+
closingIssues: platform.value.closingIssues.filter((issue) => issue.id === item.id).map((issue) => ({
|
|
179
|
+
number: issue.number || resourceIdentityNumber(issue.identity) || 0,
|
|
180
|
+
...(issue.identity ? { identity: issue.identity } : {}),
|
|
181
|
+
title: issue.title,
|
|
182
|
+
url: issue.displayUrl || '',
|
|
183
|
+
labels: issue.labels || [],
|
|
184
|
+
author: issue.author ? { login: issue.author.name || issue.author.id || '', bot: false } : null
|
|
185
|
+
}))
|
|
188
186
|
}))
|
|
189
187
|
.sort((left, right) => left.number - right.number);
|
|
190
188
|
return {
|
|
191
189
|
status: 'no-op',
|
|
192
190
|
changed: false,
|
|
193
191
|
range: { fromTag: input.fromTag, toTag: input.toTag, fromOid, toOid },
|
|
194
|
-
history: platform.history,
|
|
192
|
+
history: platform.value.history,
|
|
195
193
|
pullRequests,
|
|
196
194
|
commits,
|
|
197
195
|
error: null
|
|
198
196
|
};
|
|
199
197
|
}
|
|
200
|
-
function publishReleaseNotes(input, options = {}) {
|
|
198
|
+
async function publishReleaseNotes(input, options = {}) {
|
|
201
199
|
if (!input.tag || !input.title || !input.notesFile || !SHA256_PATTERN.test(input.expectedSha256)) {
|
|
202
200
|
return releaseNoteFailure('RELEASE_NOTES_INPUT_INVALID', 'tag, title, notes-file, and expected-sha256 are required');
|
|
203
201
|
}
|
|
@@ -213,13 +211,38 @@ function publishReleaseNotes(input, options = {}) {
|
|
|
213
211
|
}
|
|
214
212
|
const cwd = path.resolve(options.cwd || process.cwd());
|
|
215
213
|
const platformType = options.platformType ?? configuredPlatform(cwd);
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
214
|
+
const loaded = await resolvePlatformProviderContext({ cwd, platformType: platformType || undefined, client: options.client });
|
|
215
|
+
if (!loaded.ok) {
|
|
216
|
+
const status = loaded.context.status === 'blocked'
|
|
217
|
+
? 'blocked'
|
|
218
|
+
: loaded.context.status === 'no-op' ? 'no-op' : 'failed';
|
|
219
|
+
return {
|
|
220
|
+
...baseResult(status),
|
|
221
|
+
error: loaded.context.error || { code: 'PLATFORM_PROVIDER_LOAD_FAILED', message: 'Selected provider failed to load', retryable: false }
|
|
222
|
+
};
|
|
221
223
|
}
|
|
222
|
-
|
|
224
|
+
if (loaded.ok) {
|
|
225
|
+
const context = loaded.value.context;
|
|
226
|
+
if (!context.platform.repository)
|
|
227
|
+
return { status: context.status === 'blocked' ? 'blocked' : 'failed', changed: false, operation: null, url: null, error: context.error };
|
|
228
|
+
const published = loaded.value.provider.releases?.publishNotes
|
|
229
|
+
? await loaded.value.provider.releases.publishNotes({
|
|
230
|
+
context: providerOperationContext(loaded.value),
|
|
231
|
+
release: { kind: 'key', value: input.tag },
|
|
232
|
+
title: input.title,
|
|
233
|
+
notes: {
|
|
234
|
+
text: fs.readFileSync(input.notesFile, 'utf8'),
|
|
235
|
+
sha256: actualSha256,
|
|
236
|
+
byteLength: fs.statSync(input.notesFile).size
|
|
237
|
+
},
|
|
238
|
+
mutation: { idempotencyKey: `release-notes:publish:${input.tag}` }
|
|
239
|
+
})
|
|
240
|
+
: unsupportedProviderOperation(loaded.value.provider, 'releases.publishNotes');
|
|
241
|
+
if (!published.ok)
|
|
242
|
+
return { status: providerStatus(published.error), changed: false, operation: null, url: null, error: providerError(published.error, 'PLATFORM_PROVIDER_OPERATION_FAILED') };
|
|
243
|
+
return { status: 'applied', changed: published.value.changed, operation: 'publish-notes', url: null, error: null };
|
|
244
|
+
}
|
|
245
|
+
return { status: 'failed', changed: false, operation: null, url: null, error: { code: 'PLATFORM_PROVIDER_LOAD_FAILED', message: 'Selected provider failed to load', retryable: false } };
|
|
223
246
|
}
|
|
224
247
|
export { normalizeReleaseNoteBytes, publishReleaseNotes, releaseNoteContext, releaseNoteSha256, stageReleaseNotes };
|
|
225
248
|
//# sourceMappingURL=release-notes.js.map
|
|
@@ -1,57 +1,80 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import crypto from 'node:crypto';
|
|
3
|
+
import { resolvePlatformProviderContext } from './context.js';
|
|
3
4
|
import { platformResult } from './types.js';
|
|
5
|
+
import { providerError, providerOperationContext, providerStatus, unsupportedProviderOperation } from './provider-bridge.js';
|
|
4
6
|
function flattenPages(value) {
|
|
5
7
|
if (!Array.isArray(value))
|
|
6
8
|
return [];
|
|
7
9
|
return value.flatMap((entry) => Array.isArray(entry) ? entry : [entry]).filter((entry) => Boolean(entry) && typeof entry === 'object');
|
|
8
10
|
}
|
|
9
|
-
function inspectPlatformRelease(tag, options = {}) {
|
|
10
|
-
const
|
|
11
|
-
const context =
|
|
11
|
+
async function inspectPlatformRelease(tag, options = {}) {
|
|
12
|
+
const loaded = await resolvePlatformProviderContext({ cwd: options.cwd, client: options.client });
|
|
13
|
+
const context = loaded.ok ? loaded.value.context : loaded.context;
|
|
12
14
|
if (!context.platform.repository)
|
|
13
15
|
return { ...platformResult(context.status), platform: context.platform, release: null, workflows: [], error: context.error };
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
if (loaded.ok) {
|
|
17
|
+
const inspected = loaded.value.provider.releases?.inspect
|
|
18
|
+
? await loaded.value.provider.releases.inspect({ context: providerOperationContext(loaded.value), tag })
|
|
19
|
+
: unsupportedProviderOperation(loaded.value.provider, 'releases.inspect');
|
|
20
|
+
if (!inspected.ok) {
|
|
21
|
+
if (inspected.error.code === 'RESOURCE_NOT_FOUND')
|
|
22
|
+
return { ...platformResult('no-op'), platform: context.platform, release: null, workflows: [], error: null };
|
|
23
|
+
return { ...platformResult(providerStatus(inspected.error)), platform: context.platform, release: null, workflows: [], error: providerError(inspected.error, 'PLATFORM_PROVIDER_OPERATION_FAILED') };
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
...platformResult('no-op'),
|
|
27
|
+
platform: context.platform,
|
|
28
|
+
release: { tag: inspected.value.tag, published: !inspected.value.draft, draft: inspected.value.draft, url: inspected.value.displayUrl || null },
|
|
29
|
+
workflows: inspected.value.workflows || [],
|
|
30
|
+
error: null
|
|
31
|
+
};
|
|
19
32
|
}
|
|
20
|
-
|
|
21
|
-
const runs = client.json(['run', 'list', '--repo', context.platform.repository, '--limit', '100', '--json', 'name,workflowName,displayTitle,event,headBranch,headSha,status,conclusion,createdAt,databaseId,attempt,url'], { cwd: options.cwd });
|
|
22
|
-
return { ...platformResult(runs.ok ? 'no-op' : runs.error.retryable ? 'blocked' : 'degraded'), platform: context.platform, release, workflows: runs.ok ? runs.value : [], error: runs.ok ? null : runs.error };
|
|
33
|
+
return { ...platformResult('failed'), platform: context.platform, release: null, workflows: [], error: context.error };
|
|
23
34
|
}
|
|
24
|
-
function upsertPlatformRelease(input, options = {}) {
|
|
25
|
-
const inspected = inspectPlatformRelease(input.tag, options);
|
|
35
|
+
async function upsertPlatformRelease(input, options = {}) {
|
|
36
|
+
const inspected = await inspectPlatformRelease(input.tag, options);
|
|
26
37
|
if (inspected.release?.published)
|
|
27
38
|
return { ...inspected, status: 'no-op', changed: false, operations: [] };
|
|
28
39
|
if (inspected.status === 'blocked' || inspected.status === 'failed')
|
|
29
40
|
return { ...inspected, changed: false, operations: [] };
|
|
30
41
|
if (!inspected.platform.repository)
|
|
31
42
|
return { ...inspected, status: 'no-op', changed: false, operations: [] };
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
const loaded = await resolvePlatformProviderContext({ cwd: options.cwd, client: options.client });
|
|
44
|
+
if (loaded.ok) {
|
|
45
|
+
let notes;
|
|
46
|
+
if (input.notesFile) {
|
|
47
|
+
try {
|
|
48
|
+
const bytes = fs.readFileSync(input.notesFile);
|
|
49
|
+
notes = { text: bytes.toString('utf8'), sha256: `sha256:${crypto.createHash('sha256').update(bytes).digest('hex')}`, byteLength: bytes.byteLength };
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return { ...inspected, status: 'failed', changed: false, operations: [{ name: 'create-release', status: 'failed' }], error: { code: 'RELEASE_NOTES_FILE_UNREADABLE', message: 'notes-file could not be read', retryable: false } };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const created = loaded.value.provider.releases?.create
|
|
56
|
+
? await loaded.value.provider.releases.create({
|
|
57
|
+
context: providerOperationContext(loaded.value),
|
|
58
|
+
tag: input.tag,
|
|
59
|
+
title: input.title ?? input.tag,
|
|
60
|
+
...(notes ? { notes } : {}),
|
|
61
|
+
mutation: { idempotencyKey: `release:create:${input.tag}` }
|
|
62
|
+
})
|
|
63
|
+
: unsupportedProviderOperation(loaded.value.provider, 'releases.create');
|
|
64
|
+
if (!created.ok)
|
|
65
|
+
return { ...inspected, status: providerStatus(created.error), changed: false, operations: [{ name: 'create-release', status: 'failed' }], error: providerError(created.error, 'PLATFORM_PROVIDER_OPERATION_FAILED') };
|
|
66
|
+
return { ...inspected, status: 'applied', changed: created.value.changed, operations: [{ name: 'create-release', status: 'applied' }], error: null };
|
|
67
|
+
}
|
|
68
|
+
return { ...inspected, status: 'failed', changed: false, operations: [{ name: 'create-release', status: 'failed' }], error: { code: 'PLATFORM_PROVIDER_LOAD_FAILED', message: 'Selected provider failed to load', retryable: false } };
|
|
42
69
|
}
|
|
43
|
-
function reconcileReleaseMilestones(version, options = {}) {
|
|
70
|
+
async function reconcileReleaseMilestones(version, options = {}) {
|
|
44
71
|
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
|
|
45
72
|
if (!match)
|
|
46
73
|
return { status: 'failed', changed: false, operations: [], error: { code: 'RELEASE_VERSION_INVALID', message: `Invalid version '${version}'` } };
|
|
47
|
-
const
|
|
48
|
-
const context =
|
|
74
|
+
const loaded = await resolvePlatformProviderContext({ cwd: options.cwd, client: options.client });
|
|
75
|
+
const context = loaded.ok ? loaded.value.context : loaded.context;
|
|
49
76
|
if (!context.platform.repository)
|
|
50
77
|
return { ...platformResult(context.status), changed: false, operations: [], error: context.error };
|
|
51
|
-
const listed = client.json(['api', '--paginate', '--slurp', `repos/${context.platform.repository}/milestones?state=all&per_page=100`], { cwd: options.cwd });
|
|
52
|
-
if (!listed.ok)
|
|
53
|
-
return { ...platformResult(listed.error.retryable ? 'blocked' : 'failed'), changed: false, operations: [], error: listed.error };
|
|
54
|
-
const milestones = flattenPages(listed.value).map((item) => ({ title: String(item.title || ''), number: Number(item.number), state: String(item.state || '') }));
|
|
55
78
|
const major = Number(match[1]);
|
|
56
79
|
const minor = Number(match[2]);
|
|
57
80
|
const patch = Number(match[3]);
|
|
@@ -66,25 +89,31 @@ function reconcileReleaseMilestones(version, options = {}) {
|
|
|
66
89
|
const nextLine = `${major}.${minor + 1}.x`;
|
|
67
90
|
ensure.push({ title: nextMinor, description: `Issues that we want to release in v${nextMinor}.` }, { title: nextLine, description: `Issues that we want to resolve in ${major}.${minor + 1} line.` });
|
|
68
91
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
92
|
+
if (loaded.ok) {
|
|
93
|
+
const reconciled = loaded.value.provider.releases?.reconcileMilestones
|
|
94
|
+
? await loaded.value.provider.releases.reconcileMilestones({
|
|
95
|
+
context: providerOperationContext(loaded.value),
|
|
96
|
+
version,
|
|
97
|
+
desired: [
|
|
98
|
+
{ key: version, title: version, description: `Issues that we want to resolve in v${version}.`, state: 'closed' },
|
|
99
|
+
...ensure.map((item) => ({ key: item.title, title: item.title, description: item.description, state: 'open' }))
|
|
100
|
+
],
|
|
101
|
+
mutation: { idempotencyKey: `milestones:reconcile:${version}` }
|
|
102
|
+
})
|
|
103
|
+
: unsupportedProviderOperation(loaded.value.provider, 'releases.reconcileMilestones');
|
|
104
|
+
if (!reconciled.ok)
|
|
105
|
+
return { status: providerStatus(reconciled.error), changed: false, operations: [], error: providerError(reconciled.error, 'PLATFORM_PROVIDER_OPERATION_FAILED') };
|
|
106
|
+
return {
|
|
107
|
+
status: reconciled.value.changed ? 'applied' : 'no-op',
|
|
108
|
+
changed: reconciled.value.changed,
|
|
109
|
+
operations: [
|
|
110
|
+
...reconciled.value.closed.map((title) => ({ name: 'close-milestone', title, status: 'applied' })),
|
|
111
|
+
...reconciled.value.created.map((title) => ({ name: 'ensure-milestone', title, status: 'applied' }))
|
|
112
|
+
],
|
|
113
|
+
error: null
|
|
114
|
+
};
|
|
84
115
|
}
|
|
85
|
-
|
|
86
|
-
const changed = operations.some((operation) => operation.status === 'applied');
|
|
87
|
-
return { status: failed ? 'failed' : changed ? 'applied' : 'no-op', changed, operations, error: failed ? { code: 'MILESTONE_RECONCILE_FAILED', message: 'One or more milestone operations failed' } : null };
|
|
116
|
+
return { status: 'failed', changed: false, operations: [], error: { code: 'PLATFORM_CAPABILITY_UNSUPPORTED', message: 'Release milestone reconciliation is unavailable', retryable: false } };
|
|
88
117
|
}
|
|
89
118
|
export { inspectPlatformRelease, reconcileReleaseMilestones, upsertPlatformRelease };
|
|
90
119
|
//# sourceMappingURL=releases.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
type ResourceIdentityKind = 'id' | 'number' | 'key';
|
|
2
|
+
type ResourceIdentity = {
|
|
3
|
+
kind: 'id';
|
|
4
|
+
value: string;
|
|
5
|
+
} | {
|
|
6
|
+
kind: 'number';
|
|
7
|
+
value: number;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'key';
|
|
10
|
+
value: string;
|
|
11
|
+
};
|
|
12
|
+
type CanonicalResourceIdentity = ResourceIdentity;
|
|
13
|
+
type PlatformResourceKind = 'issue' | 'pull-request' | 'comment' | 'release';
|
|
14
|
+
type ProviderIdentityDeclaration = Partial<Record<PlatformResourceKind, ResourceIdentityKind>>;
|
|
15
|
+
declare function isResourceIdentity(value: unknown): value is CanonicalResourceIdentity;
|
|
16
|
+
declare function parseResourceIdentity(value: unknown, label?: string): CanonicalResourceIdentity;
|
|
17
|
+
declare function serializeResourceIdentity(identity: ResourceIdentity): string;
|
|
18
|
+
declare function resourceIdentityEquals(left: unknown, right: unknown): boolean;
|
|
19
|
+
declare function primaryIdentityKind(declaration: ProviderIdentityDeclaration | undefined, resourceKind: PlatformResourceKind): ResourceIdentityKind;
|
|
20
|
+
declare function parseResourceToken(token: string, resourceKind: PlatformResourceKind, declaration: ProviderIdentityDeclaration | undefined): ResourceIdentity;
|
|
21
|
+
declare function identityFromRemoteValue(value: unknown, resourceKind: PlatformResourceKind, declaration: ProviderIdentityDeclaration | undefined): ResourceIdentity;
|
|
22
|
+
declare function resourceIdentityNumber(identity: ResourceIdentity | null | undefined): number | null;
|
|
23
|
+
declare function resourceIdentityString(identity: ResourceIdentity | null | undefined): string | null;
|
|
24
|
+
declare function reviewMarker(identity: ResourceIdentity): string;
|
|
25
|
+
export { identityFromRemoteValue, isResourceIdentity, parseResourceIdentity, parseResourceToken, primaryIdentityKind, resourceIdentityEquals, resourceIdentityNumber, resourceIdentityString, reviewMarker, serializeResourceIdentity };
|
|
26
|
+
export type { CanonicalResourceIdentity, PlatformResourceKind, ProviderIdentityDeclaration, ResourceIdentity, ResourceIdentityKind };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
function identityError(message) {
|
|
2
|
+
return Object.assign(new Error(`PLATFORM_IDENTITY_INVALID: ${message}`), {
|
|
3
|
+
code: 'PLATFORM_IDENTITY_INVALID'
|
|
4
|
+
});
|
|
5
|
+
}
|
|
6
|
+
function isResourceIdentity(value) {
|
|
7
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
8
|
+
return false;
|
|
9
|
+
const candidate = value;
|
|
10
|
+
if (Object.keys(candidate).length !== 2 || typeof candidate.kind !== 'string')
|
|
11
|
+
return false;
|
|
12
|
+
if (candidate.kind === 'number') {
|
|
13
|
+
return Number.isSafeInteger(candidate.value) && candidate.value > 0;
|
|
14
|
+
}
|
|
15
|
+
return (candidate.kind === 'id' || candidate.kind === 'key')
|
|
16
|
+
&& typeof candidate.value === 'string'
|
|
17
|
+
&& candidate.value.length > 0
|
|
18
|
+
&& candidate.value.trim() === candidate.value;
|
|
19
|
+
}
|
|
20
|
+
function parseResourceIdentity(value, label = 'identity') {
|
|
21
|
+
if (!isResourceIdentity(value))
|
|
22
|
+
throw identityError(`${label} must contain exactly one valid kind/value pair`);
|
|
23
|
+
if (value.kind === 'number')
|
|
24
|
+
return { kind: 'number', value: value.value };
|
|
25
|
+
if (value.kind === 'id')
|
|
26
|
+
return { kind: 'id', value: value.value };
|
|
27
|
+
return { kind: 'key', value: value.value };
|
|
28
|
+
}
|
|
29
|
+
function serializeResourceIdentity(identity) {
|
|
30
|
+
return JSON.stringify(parseResourceIdentity(identity));
|
|
31
|
+
}
|
|
32
|
+
function resourceIdentityEquals(left, right) {
|
|
33
|
+
return isResourceIdentity(left) && isResourceIdentity(right)
|
|
34
|
+
&& left.kind === right.kind && left.value === right.value;
|
|
35
|
+
}
|
|
36
|
+
function primaryIdentityKind(declaration, resourceKind) {
|
|
37
|
+
const kind = declaration?.[resourceKind];
|
|
38
|
+
if (kind !== 'id' && kind !== 'number' && kind !== 'key') {
|
|
39
|
+
throw identityError(`provider does not declare a primary identity for ${resourceKind}`);
|
|
40
|
+
}
|
|
41
|
+
return kind;
|
|
42
|
+
}
|
|
43
|
+
function parseResourceToken(token, resourceKind, declaration) {
|
|
44
|
+
if (typeof token !== 'string' || token.length === 0)
|
|
45
|
+
throw identityError('resource token must be a non-empty string');
|
|
46
|
+
const kind = primaryIdentityKind(declaration, resourceKind);
|
|
47
|
+
if (kind === 'number') {
|
|
48
|
+
if (!/^[1-9]\d*$/u.test(token))
|
|
49
|
+
throw identityError(`${resourceKind} token must be a positive safe integer`);
|
|
50
|
+
const value = Number(token);
|
|
51
|
+
if (!Number.isSafeInteger(value) || value <= 0)
|
|
52
|
+
throw identityError(`${resourceKind} token must be a positive safe integer`);
|
|
53
|
+
return { kind, value };
|
|
54
|
+
}
|
|
55
|
+
const value = token.trim();
|
|
56
|
+
if (!value)
|
|
57
|
+
throw identityError(`${resourceKind} token must not be empty`);
|
|
58
|
+
return { kind, value };
|
|
59
|
+
}
|
|
60
|
+
function identityFromRemoteValue(value, resourceKind, declaration) {
|
|
61
|
+
const kind = primaryIdentityKind(declaration, resourceKind);
|
|
62
|
+
if (isResourceIdentity(value)) {
|
|
63
|
+
if (value.kind !== kind)
|
|
64
|
+
throw identityError(`${resourceKind} response identity kind does not match provider declaration`);
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
if (kind === 'number') {
|
|
68
|
+
if (typeof value === 'number' && Number.isSafeInteger(value) && value > 0)
|
|
69
|
+
return { kind, value };
|
|
70
|
+
if (typeof value === 'string' && /^[1-9]\d*$/u.test(value))
|
|
71
|
+
return parseResourceToken(value, resourceKind, declaration);
|
|
72
|
+
throw identityError(`${resourceKind} response does not contain a valid number identity`);
|
|
73
|
+
}
|
|
74
|
+
if (typeof value !== 'string' || !value.trim())
|
|
75
|
+
throw identityError(`${resourceKind} response does not contain a valid string identity`);
|
|
76
|
+
return { kind, value: value.trim() };
|
|
77
|
+
}
|
|
78
|
+
function resourceIdentityNumber(identity) {
|
|
79
|
+
return identity?.kind === 'number' ? identity.value : null;
|
|
80
|
+
}
|
|
81
|
+
function resourceIdentityString(identity) {
|
|
82
|
+
return identity && (identity.kind === 'id' || identity.kind === 'key') ? identity.value : null;
|
|
83
|
+
}
|
|
84
|
+
function reviewMarker(identity) {
|
|
85
|
+
const parsed = parseResourceIdentity(identity);
|
|
86
|
+
if (parsed.kind === 'number')
|
|
87
|
+
return `pr${parsed.value}`;
|
|
88
|
+
const encoded = Buffer.from(serializeResourceIdentity(parsed), 'utf8').toString('base64url');
|
|
89
|
+
return `pr:${encoded}`;
|
|
90
|
+
}
|
|
91
|
+
export { identityFromRemoteValue, isResourceIdentity, parseResourceIdentity, parseResourceToken, primaryIdentityKind, resourceIdentityEquals, resourceIdentityNumber, resourceIdentityString, reviewMarker, serializeResourceIdentity };
|
|
92
|
+
//# sourceMappingURL=resource-identity.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { parseResourceIdentity } from './resource-identity.js';
|
|
2
|
+
import { isLegacyCompatibilityEnabled, legacyCompatibilityError, VERSION } from '../version.js';
|
|
3
|
+
import { parse as parseYaml } from 'yaml';
|
|
4
|
+
function taskIssueIdentity(frontmatter, _declaration, runtimeVersion = VERSION) {
|
|
5
|
+
const serialized = frontmatter.platform_issue_identity;
|
|
6
|
+
if (typeof serialized === 'string' && serialized.trim()) {
|
|
7
|
+
try {
|
|
8
|
+
const decoded = parseYaml(serialized);
|
|
9
|
+
return parseResourceIdentity(JSON.parse(typeof decoded === 'string' ? decoded : serialized), 'platform_issue_identity');
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const legacy = frontmatter.issue_number;
|
|
16
|
+
const number = typeof legacy === 'number' ? legacy : typeof legacy === 'string' && /^[1-9]\d*$/u.test(legacy) ? Number(legacy) : NaN;
|
|
17
|
+
// TODO(compat): Remove the numeric issue_number fallback before the first stable v1.0.0 release.
|
|
18
|
+
if (Number.isSafeInteger(number) && number > 0 && !isLegacyCompatibilityEnabled(runtimeVersion)) {
|
|
19
|
+
throw legacyCompatibilityError('issue_number', runtimeVersion);
|
|
20
|
+
}
|
|
21
|
+
return Number.isSafeInteger(number) && number > 0 ? { kind: 'number', value: number } : null;
|
|
22
|
+
}
|
|
23
|
+
function taskIssueIdentityError(error) {
|
|
24
|
+
const value = error && typeof error === 'object' ? error : {};
|
|
25
|
+
return {
|
|
26
|
+
code: typeof value.code === 'string' ? value.code : 'PLATFORM_IDENTITY_INVALID',
|
|
27
|
+
message: error instanceof Error ? error.message : String(error)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export { taskIssueIdentity, taskIssueIdentityError };
|
|
31
|
+
//# sourceMappingURL=task-identities.js.map
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { execFileSync } from "node:child_process";
|
|
4
|
-
import { hasPlatformCapability } from "./adapters.js";
|
|
5
4
|
import { inspectRequiredChecks } from "./pr-checks.js";
|
|
6
|
-
import {
|
|
5
|
+
import { resolvePlatformProviderContext } from "./context.js";
|
|
7
6
|
import { resolveReviewedHeadRelation } from "./merged-pr-equivalence.js";
|
|
7
|
+
import { readPrDeliveryFact } from "../task/pr-delivery-fact.js";
|
|
8
|
+
import { resourceIdentityNumber } from "./resource-identity.js";
|
|
8
9
|
const CHECK_TYPE = "required-checks";
|
|
9
10
|
const SHA_PATTERN = /^[0-9a-f]{7,40}$/i;
|
|
10
|
-
function validPrNumber(value) {
|
|
11
|
-
const parsed = Number(value);
|
|
12
|
-
return Number.isInteger(parsed) && parsed > 0;
|
|
13
|
-
}
|
|
14
11
|
function readPrFlow(repoRoot) {
|
|
15
12
|
try {
|
|
16
13
|
const config = JSON.parse(fs.readFileSync(path.join(repoRoot, ".agents", ".airc.json"), "utf8"));
|
|
@@ -30,7 +27,14 @@ function readHead(repoRoot) {
|
|
|
30
27
|
}
|
|
31
28
|
export function evaluateRequiredChecks(context, shared) {
|
|
32
29
|
const { metadata, localHead, inspection, prFlow } = context;
|
|
33
|
-
|
|
30
|
+
const factRead = readPrDeliveryFact(metadata);
|
|
31
|
+
if (factRead.status === "invalid") {
|
|
32
|
+
return shared.failResult(CHECK_TYPE, factRead.error.message, "check_failed");
|
|
33
|
+
}
|
|
34
|
+
const fact = factRead.status === "valid" ? factRead.fact : null;
|
|
35
|
+
const prIdentity = fact?.state === "bound" ? fact.identity.resource : null;
|
|
36
|
+
const prNumber = resourceIdentityNumber(prIdentity);
|
|
37
|
+
if (prFlow === "disabled" || fact?.state === "skipped" || !prIdentity) {
|
|
34
38
|
return shared.passResult(CHECK_TYPE, "Skipped: required checks are not applicable to this task");
|
|
35
39
|
}
|
|
36
40
|
const reviewedHead = String(metadata.last_reviewed_commit || "");
|
|
@@ -73,22 +77,28 @@ export function evaluateRequiredChecks(context, shared) {
|
|
|
73
77
|
}
|
|
74
78
|
return shared.failResult(CHECK_TYPE, inspection.error?.message || `Required checks are ${state || "unavailable"}`, "check_failed");
|
|
75
79
|
}
|
|
76
|
-
export function check({ taskDir }, shared) {
|
|
80
|
+
export async function check({ taskDir }, shared) {
|
|
77
81
|
const task = shared.loadTask(taskDir);
|
|
78
82
|
if (!task.ok)
|
|
79
83
|
return shared.failResult(CHECK_TYPE, task.message);
|
|
80
84
|
const prFlow = readPrFlow(shared.repoRoot);
|
|
81
|
-
|
|
85
|
+
const factRead = readPrDeliveryFact(task.metadata);
|
|
86
|
+
if (factRead.status === "invalid")
|
|
87
|
+
return shared.failResult(CHECK_TYPE, factRead.error.message, "check_failed");
|
|
88
|
+
const bound = factRead.status === "valid" && factRead.fact.state === "bound";
|
|
89
|
+
if (prFlow === "disabled" || (factRead.status === "valid" && factRead.fact.state === "skipped") || !bound) {
|
|
82
90
|
return evaluateRequiredChecks({ metadata: task.metadata, localHead: null, inspection: null, prFlow }, shared);
|
|
83
91
|
}
|
|
84
|
-
const
|
|
85
|
-
|
|
92
|
+
const loaded = await resolvePlatformProviderContext({ cwd: shared.repoRoot });
|
|
93
|
+
const platform = loaded.ok ? loaded.value.context : loaded.context;
|
|
94
|
+
const supportsChecks = loaded.ok && Boolean(loaded.value.provider.checks?.inspectRequired);
|
|
95
|
+
if (!supportsChecks) {
|
|
86
96
|
return shared.blockedResult(CHECK_TYPE, `Platform '${platform.platform.type || "none"}' does not provide required-checks inspection`, "dependency_error");
|
|
87
97
|
}
|
|
88
98
|
const localHead = readHead(shared.repoRoot);
|
|
89
99
|
if (!localHead)
|
|
90
100
|
return evaluateRequiredChecks({ metadata: task.metadata, localHead, inspection: null, prFlow }, shared);
|
|
91
|
-
const inspection = inspectRequiredChecks(task.metadata.id, { cwd: shared.repoRoot });
|
|
101
|
+
const inspection = await inspectRequiredChecks(task.metadata.id, { cwd: shared.repoRoot });
|
|
92
102
|
return evaluateRequiredChecks({
|
|
93
103
|
metadata: task.metadata,
|
|
94
104
|
localHead,
|