@fitlab-ai/agent-infra 0.9.14 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/README.zh-CN.md +10 -0
- package/bin/internal-cli.sh +45 -0
- package/dist/bin/internal-cli.js +93 -30
- package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +165 -27
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +9 -4
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +43 -3
- package/dist/lib/defaults.json +103 -103
- package/dist/lib/fs/durable-write.js +39 -0
- package/dist/lib/fs/file-lock.js +111 -0
- package/dist/lib/host-control/audit.js +19 -0
- package/dist/lib/host-control/client.js +142 -0
- package/dist/lib/host-control/command.js +49 -0
- package/dist/lib/host-control/path.js +160 -0
- package/dist/lib/host-control/secure-fs.js +140 -0
- package/dist/lib/host-control/server.js +159 -0
- package/dist/lib/host-control/service.js +112 -0
- package/dist/lib/init.js +11 -2
- package/dist/lib/internal/cli-route-inventory.js +4 -2
- package/dist/lib/internal/codex-lifecycle.js +6 -6
- package/dist/lib/internal/demo-promotion.js +322 -0
- package/dist/lib/internal/demo-transcript.js +454 -0
- package/dist/lib/internal/host-control.js +28 -0
- package/dist/lib/internal/manual-validation.js +331 -0
- package/dist/lib/internal/platform-pr.js +18 -4
- package/dist/lib/internal/release-workflow.js +63 -84
- package/dist/lib/internal/sandbox-control.js +149 -2
- package/dist/lib/internal/task-artifact.js +16 -263
- package/dist/lib/internal/task-create.js +6 -5
- package/dist/lib/internal/task-event.js +37 -37
- package/dist/lib/internal/task-lifecycle.js +2 -2
- package/dist/lib/internal/task-operation-registry.js +101 -4
- package/dist/lib/internal/task-review.js +11 -56
- package/dist/lib/internal/task-validate.js +30 -10
- package/dist/lib/owned-path.js +33 -0
- package/dist/lib/platform/check-status.js +11 -0
- package/dist/lib/platform/comment-safety.js +4 -1
- package/dist/lib/platform/completion-backfill.js +1 -1
- package/dist/lib/platform/github-data.js +241 -0
- package/dist/lib/platform/github-provider.js +15 -20
- package/dist/lib/platform/issue-comments.js +18 -12
- package/dist/lib/platform/issues.js +2 -180
- package/dist/lib/platform/pr-change-report.js +5 -4
- package/dist/lib/platform/pr-checks.js +12 -65
- package/dist/lib/platform/pr-summary.js +117 -33
- package/dist/lib/platform/pull-requests.js +5 -108
- package/dist/lib/platform/snapshots.js +2 -0
- package/dist/lib/platform/task-identities.js +2 -9
- package/dist/lib/platform/verification-sync.js +132 -143
- package/dist/lib/pr-review/evidence-grading.js +4 -8
- package/dist/lib/release/workflow.js +1 -1
- package/dist/lib/sandbox/commands/create.js +7 -2
- package/dist/lib/sandbox/commands/rm.js +19 -1511
- package/dist/lib/sandbox/control/audit.js +203 -0
- package/dist/lib/sandbox/control/client.js +93 -54
- package/dist/lib/sandbox/control/executor.js +129 -65
- package/dist/lib/sandbox/control/finalization-response.js +27 -0
- package/dist/lib/sandbox/control/identity-sentinel.js +107 -0
- package/dist/lib/sandbox/control/lifecycle.js +36 -2
- package/dist/lib/sandbox/control/native-file-lock.js +6 -98
- package/dist/lib/sandbox/control/protocol.js +55 -4
- package/dist/lib/sandbox/control/server.js +518 -127
- package/dist/lib/sandbox/control/state.js +64 -0
- package/dist/lib/sandbox/control/task-workflow.js +74 -0
- package/dist/lib/sandbox/control/workflow-executor.js +89 -0
- package/dist/lib/sandbox/index.js +1 -2
- package/dist/lib/sandbox/recovery.js +28 -4
- package/dist/lib/sandbox/removal.js +822 -0
- package/dist/lib/sandbox/task-cleanup.js +217 -0
- package/dist/lib/sandbox/workspace-identity.js +17 -1
- package/dist/lib/sandbox/workspace-view.js +13 -14
- package/dist/lib/task/activity-intent.js +2 -1
- package/dist/lib/task/activity-log.js +30 -24
- package/dist/lib/task/artifact-command.js +79 -0
- package/dist/lib/task/artifact-lifecycle.js +30 -28
- package/dist/lib/task/artifact-name.js +36 -0
- package/dist/lib/task/artifact-operations.js +29 -289
- package/dist/lib/task/artifact-receipts.js +3 -15
- package/dist/lib/task/artifact-recovery.js +430 -0
- package/dist/lib/task/artifact-repair-intent.js +134 -29
- package/dist/lib/task/artifact-schema.js +6 -14
- package/dist/lib/task/capabilities.js +12 -19
- package/dist/lib/task/codex-orchestration.js +71 -25
- package/dist/lib/task/commit-identity.js +28 -0
- package/dist/lib/task/commit-operation.js +33 -20
- package/dist/lib/task/control-authority.js +403 -6
- package/dist/lib/task/control-recovery.js +140 -0
- package/dist/lib/task/create-service.js +1 -8
- package/dist/lib/task/create.js +62 -9
- package/dist/lib/task/decision-details.js +2 -46
- package/dist/lib/task/delegation-receipts.js +64 -3
- package/dist/lib/task/events.js +275 -22
- package/dist/lib/task/finalization-state.js +9 -0
- package/dist/lib/task/human-override.js +8 -14
- package/dist/lib/task/implementation-inputs.js +3 -3
- package/dist/lib/task/intermediate-cleanup.js +441 -0
- package/dist/lib/task/invalidation.js +18 -65
- package/dist/lib/task/ledger-intents.js +7 -22
- package/dist/lib/task/ledger.js +1 -3
- package/dist/lib/task/lifecycle-recovery.js +549 -0
- package/dist/lib/task/lifecycle.js +31 -4
- package/dist/lib/task/local-artifact-finalization.js +197 -197
- package/dist/lib/task/manual-validation-completion.js +26 -0
- package/dist/lib/task/manual-validation-evidence.js +130 -0
- package/dist/lib/task/manual-validation-receipt.js +105 -0
- package/dist/lib/task/manual-validation-shared.js +40 -0
- package/dist/lib/task/manual-validation-transaction.js +243 -0
- package/dist/lib/task/markdown.js +47 -0
- package/dist/lib/task/orchestration.js +66 -19
- package/dist/lib/task/pr-delivery-fact.js +12 -56
- package/dist/lib/task/qualification-audit.js +20 -34
- package/dist/lib/task/recovery-warning.js +19 -0
- package/dist/lib/task/review-artifacts.js +2 -18
- package/dist/lib/task/review-command.js +26 -0
- package/dist/lib/task/review-finalization.js +175 -216
- package/dist/lib/task/review-fingerprint.js +2 -2
- package/dist/lib/task/sections.js +34 -56
- package/dist/lib/task/short-id.js +15 -7
- package/dist/lib/task/task-execution-lock.js +1 -1
- package/dist/lib/task/verification-engine.js +119 -337
- package/dist/lib/task/verification.js +1 -1
- package/dist/lib/task/workflow-command.js +16 -0
- package/dist/lib/task/workflow-warning-intents.js +0 -16
- package/dist/lib/task/workflow-warnings.js +28 -2
- package/dist/lib/update.js +2 -0
- package/dist/lib/version.js +1 -11
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +223 -33
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +10 -4
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +55 -3
- package/lib/fs/durable-write.ts +30 -0
- package/lib/fs/file-lock.ts +113 -0
- package/lib/host-control/audit.ts +22 -0
- package/lib/host-control/client.ts +172 -0
- package/lib/host-control/command.ts +60 -0
- package/lib/host-control/path.ts +167 -0
- package/lib/host-control/secure-fs.ts +135 -0
- package/lib/host-control/server.ts +180 -0
- package/lib/host-control/service.ts +133 -0
- package/lib/init.ts +15 -2
- package/lib/internal/cli-route-inventory.ts +4 -2
- package/lib/internal/codex-lifecycle.ts +6 -6
- package/lib/internal/demo-promotion.ts +354 -0
- package/lib/internal/demo-transcript.ts +419 -0
- package/lib/internal/host-control.ts +28 -0
- package/lib/internal/manual-validation.ts +315 -0
- package/lib/internal/platform-pr.ts +15 -4
- package/lib/internal/release-workflow.ts +74 -82
- package/lib/internal/sandbox-control.ts +162 -1
- package/lib/internal/task-artifact.ts +14 -217
- package/lib/internal/task-create.ts +5 -5
- package/lib/internal/task-event.ts +20 -11
- package/lib/internal/task-lifecycle.ts +4 -3
- package/lib/internal/task-operation-registry.ts +111 -4
- package/lib/internal/task-review.ts +9 -54
- package/lib/internal/task-validate.ts +26 -10
- package/lib/owned-path.ts +26 -0
- package/lib/platform/check-status.ts +9 -0
- package/lib/platform/comment-safety.ts +5 -0
- package/lib/platform/completion-backfill.ts +1 -1
- package/lib/platform/github-data.ts +322 -0
- package/lib/platform/github-provider.ts +15 -20
- package/lib/platform/issue-comments.ts +21 -14
- package/lib/platform/issues.ts +5 -246
- package/lib/platform/pr-change-report.ts +7 -5
- package/lib/platform/pr-checks.ts +13 -77
- package/lib/platform/pr-summary.ts +123 -35
- package/lib/platform/pull-requests.ts +6 -173
- package/lib/platform/snapshots.ts +53 -0
- package/lib/platform/task-identities.ts +3 -14
- package/lib/platform/verification-sync.ts +150 -156
- package/lib/pr-review/evidence-grading.ts +4 -9
- package/lib/release/workflow.ts +3 -3
- package/lib/sandbox/commands/create.ts +7 -6
- package/lib/sandbox/commands/rm.ts +21 -1895
- package/lib/sandbox/control/audit.ts +253 -0
- package/lib/sandbox/control/client.ts +109 -66
- package/lib/sandbox/control/executor.ts +134 -74
- package/lib/sandbox/control/finalization-response.ts +29 -0
- package/lib/sandbox/control/identity-sentinel.ts +137 -0
- package/lib/sandbox/control/lifecycle.ts +45 -3
- package/lib/sandbox/control/native-file-lock.ts +6 -107
- package/lib/sandbox/control/protocol.ts +80 -6
- package/lib/sandbox/control/server.ts +567 -132
- package/lib/sandbox/control/state.ts +86 -0
- package/lib/sandbox/control/task-workflow.ts +95 -0
- package/lib/sandbox/control/workflow-executor.ts +92 -0
- package/lib/sandbox/index.ts +1 -2
- package/lib/sandbox/recovery.ts +28 -5
- package/lib/sandbox/removal.ts +1142 -0
- package/lib/sandbox/task-cleanup.ts +209 -0
- package/lib/sandbox/workspace-identity.ts +19 -3
- package/lib/sandbox/workspace-view.ts +17 -15
- package/lib/task/activity-intent.ts +2 -2
- package/lib/task/activity-log.ts +27 -19
- package/lib/task/artifact-command.ts +85 -0
- package/lib/task/artifact-lifecycle.ts +31 -26
- package/lib/task/artifact-name.ts +55 -0
- package/lib/task/artifact-operations.ts +34 -310
- package/lib/task/artifact-receipts.ts +3 -14
- package/lib/task/artifact-recovery.ts +519 -0
- package/lib/task/artifact-repair-intent.ts +162 -33
- package/lib/task/artifact-schema.ts +5 -34
- package/lib/task/capabilities.ts +13 -22
- package/lib/task/codex-orchestration.ts +85 -24
- package/lib/task/commit-identity.ts +31 -0
- package/lib/task/commit-operation.ts +37 -20
- package/lib/task/control-authority.ts +540 -10
- package/lib/task/control-recovery.ts +186 -0
- package/lib/task/create-service.ts +1 -10
- package/lib/task/create.ts +63 -8
- package/lib/task/decision-details.ts +3 -71
- package/lib/task/delegation-receipts.ts +73 -2
- package/lib/task/events.ts +309 -24
- package/lib/task/finalization-state.ts +11 -0
- package/lib/task/human-override.ts +8 -16
- package/lib/task/implementation-inputs.ts +3 -3
- package/lib/task/intermediate-cleanup.ts +493 -0
- package/lib/task/invalidation.ts +18 -62
- package/lib/task/ledger-intents.ts +7 -24
- package/lib/task/ledger.ts +1 -3
- package/lib/task/lifecycle-recovery.ts +691 -0
- package/lib/task/lifecycle.ts +30 -5
- package/lib/task/local-artifact-finalization.ts +244 -234
- package/lib/task/manual-validation-completion.ts +40 -0
- package/lib/task/manual-validation-evidence.ts +209 -0
- package/lib/task/manual-validation-receipt.ts +156 -0
- package/lib/task/manual-validation-shared.ts +50 -0
- package/lib/task/manual-validation-transaction.ts +304 -0
- package/lib/task/markdown.ts +70 -0
- package/lib/task/orchestration.ts +84 -19
- package/lib/task/pr-delivery-fact.ts +15 -62
- package/lib/task/qualification-audit.ts +22 -33
- package/lib/task/recovery-warning.ts +21 -0
- package/lib/task/review-artifacts.ts +1 -20
- package/lib/task/review-command.ts +24 -0
- package/lib/task/review-finalization.ts +183 -292
- package/lib/task/review-fingerprint.ts +2 -2
- package/lib/task/sections.ts +33 -54
- package/lib/task/short-id.ts +27 -5
- package/lib/task/task-execution-lock.ts +1 -1
- package/lib/task/verification-engine.ts +113 -383
- package/lib/task/verification-types.ts +15 -0
- package/lib/task/verification.ts +1 -1
- package/lib/task/workflow-command.ts +17 -0
- package/lib/task/workflow-warning-intents.ts +0 -13
- package/lib/task/workflow-warnings.ts +21 -2
- package/lib/update.ts +6 -0
- package/lib/version.ts +1 -15
- package/package.json +6 -6
- package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
- package/templates/.agents/rules/create-issue.en.md +1 -1
- package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
- package/templates/.agents/rules/issue-sync.en.md +4 -2
- package/templates/.agents/rules/issue-sync.zh-CN.md +4 -3
- package/templates/.agents/rules/local-artifact-repair.en.md +46 -39
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +43 -36
- package/templates/.agents/rules/testing-discipline.en.md +2 -0
- package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -0
- package/templates/.agents/scripts/package.json +3 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +6 -6
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +6 -6
- package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/block-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/block-task/config/verify.json +1 -1
- package/templates/.agents/skills/cancel-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/cancel-task/config/verify.json +1 -1
- package/templates/.agents/skills/code-task/SKILL.en.md +7 -7
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +7 -7
- package/templates/.agents/skills/code-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +33 -21
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +33 -21
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +16 -7
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +16 -7
- package/templates/.agents/skills/complete-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/complete-task/config/verify.en.json +2 -2
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +2 -2
- package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +1 -1
- package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +1 -1
- package/templates/.agents/skills/create-pr/SKILL.en.md +2 -2
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/create-pr/config/verify.json +1 -1
- package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +2 -2
- package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +2 -2
- package/templates/.agents/skills/create-task/SKILL.en.md +5 -5
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/create-task/config/verify.json +1 -1
- package/templates/.agents/skills/import-issue/SKILL.en.md +8 -8
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/import-issue/config/verify.json +2 -2
- package/templates/.agents/skills/plan-task/SKILL.en.md +4 -4
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/plan-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/release/SKILL.en.md +7 -3
- package/templates/.agents/skills/release/SKILL.zh-CN.md +7 -3
- package/templates/.agents/skills/restore-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/restore-task/config/verify.json +1 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -1
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +7 -7
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +6 -6
- package/templates/.agents/skills/review-code/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-code/config/verify.en.json +1 -1
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/review-code/reference/report-template.en.md +12 -12
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +12 -12
- package/templates/.agents/skills/review-plan/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-plan/config/verify.en.json +1 -1
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +7 -7
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +7 -7
- package/templates/.agents/skills/review-pr/config/verify.en.json +1 -1
- package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +3 -3
- package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +3 -3
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +20 -3
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +20 -3
- package/templates/.agents/skills/run-manual-validation/config/verify.en.json +1 -1
- package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +4 -1
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +4 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +2 -0
- package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +2 -0
- package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/test/SKILL.en.md +17 -6
- package/templates/.agents/skills/test/SKILL.zh-CN.md +17 -6
- package/templates/.agents/templates/task.en.md +1 -1
- package/templates/.agents/templates/task.zh-CN.md +1 -1
- package/templates/.claude/commands/import-issue.en.md +1 -1
- package/templates/.claude/commands/import-issue.zh-CN.md +1 -1
- package/templates/.claude/commands/restore-task.en.md +1 -1
- package/templates/.claude/commands/restore-task.zh-CN.md +1 -1
- package/templates/.claude/commands/run-manual-validation.en.md +1 -1
- package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
- package/dist/lib/platform/adapters.js +0 -56
- package/lib/platform/adapters.ts +0 -197
|
@@ -3,8 +3,9 @@ import path from 'node:path';
|
|
|
3
3
|
import { createHash, randomUUID } from 'node:crypto';
|
|
4
4
|
import { execFileSync } from 'node:child_process';
|
|
5
5
|
import { escapeHtmlText } from './comment-safety.js';
|
|
6
|
+
import { isResourceIdentity } from './resource-identity.js';
|
|
6
7
|
const REPORT_FILE_NAME = 'pr-change-report.json';
|
|
7
|
-
const REPORT_VERSION =
|
|
8
|
+
const REPORT_VERSION = 2;
|
|
8
9
|
const CANONICAL_REPORT_PLACEHOLDER = '<!-- canonical-pr-change-report -->';
|
|
9
10
|
const CANONICAL_REPORT_HEADING = '### PR 代码增减';
|
|
10
11
|
const PRECHECK_IDS = [
|
|
@@ -211,8 +212,8 @@ function validatePrChangeReport(value) {
|
|
|
211
212
|
}
|
|
212
213
|
const identity = value.identity;
|
|
213
214
|
const identityRepository = identity.repository;
|
|
214
|
-
const
|
|
215
|
-
if (!isNonEmptyString(identityRepository) ||
|
|
215
|
+
const identityResource = identity.resource;
|
|
216
|
+
if (!isNonEmptyString(identityRepository) || !isResourceIdentity(identityResource))
|
|
216
217
|
return invalid('change report identity is invalid');
|
|
217
218
|
const parseIdentityPart = (part, name) => {
|
|
218
219
|
if (!isRecord(part) || !isNonEmptyString(part.repository) || !isNonEmptyString(part.ref) || !isSha(part.sha))
|
|
@@ -259,7 +260,7 @@ function validatePrChangeReport(value) {
|
|
|
259
260
|
version: REPORT_VERSION,
|
|
260
261
|
identity: {
|
|
261
262
|
repository: identityRepository,
|
|
262
|
-
|
|
263
|
+
resource: identityResource,
|
|
263
264
|
base: base.value,
|
|
264
265
|
head: head.value
|
|
265
266
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { parseTypedTaskFrontmatter } from '../task/frontmatter.js';
|
|
3
3
|
import { resolveTaskRef } from '../task/resolve-ref.js';
|
|
4
|
+
import { checkStatusBucket } from './check-status.js';
|
|
4
5
|
import { resolvePlatformProviderContext } from './context.js';
|
|
5
6
|
import { inspectPlatformPullRequest } from './pull-requests.js';
|
|
6
7
|
import { platformResult } from './types.js';
|
|
@@ -26,20 +27,6 @@ function classifyPullRequestReadiness(input) {
|
|
|
26
27
|
return { state: 'pending', headSha: input.headSha };
|
|
27
28
|
return { state: 'ready', headSha: input.headSha };
|
|
28
29
|
}
|
|
29
|
-
function parseRunJobIdentity(detailsUrl) {
|
|
30
|
-
try {
|
|
31
|
-
const url = new URL(detailsUrl);
|
|
32
|
-
if (url.hostname !== 'github.com')
|
|
33
|
-
return null;
|
|
34
|
-
const match = url.pathname.match(/\/actions\/runs\/(\d+)(?:\/job\/(\d+))?/);
|
|
35
|
-
if (!match)
|
|
36
|
-
return null;
|
|
37
|
-
return { runId: Number(match[1]), jobId: match[2] ? Number(match[2]) : null };
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
30
|
function resolveRunCandidate(candidates, headSha, checkName) {
|
|
44
31
|
const matches = candidates.filter((candidate) => candidate.headSha === headSha && candidate.name === checkName);
|
|
45
32
|
if (matches.length === 1)
|
|
@@ -54,42 +41,6 @@ function checksResult(status, overrides = {}) {
|
|
|
54
41
|
...overrides
|
|
55
42
|
};
|
|
56
43
|
}
|
|
57
|
-
function normalizeBucket(value) {
|
|
58
|
-
const raw = String(value.bucket || value.status || value.conclusion || value.state || '').toLowerCase();
|
|
59
|
-
if (['pass', 'success', 'successful', 'neutral'].includes(raw))
|
|
60
|
-
return 'pass';
|
|
61
|
-
if (['fail', 'failure', 'failed', 'error', 'timed_out', 'action_required'].includes(raw))
|
|
62
|
-
return 'fail';
|
|
63
|
-
if (['cancel', 'cancelled', 'canceled', 'skipped', 'stale'].includes(raw))
|
|
64
|
-
return 'cancel';
|
|
65
|
-
return 'pending';
|
|
66
|
-
}
|
|
67
|
-
function normalizeChecks(value) {
|
|
68
|
-
if (!Array.isArray(value))
|
|
69
|
-
return [];
|
|
70
|
-
return value.flatMap((raw) => {
|
|
71
|
-
const item = raw;
|
|
72
|
-
const name = String(item.name || item.context || '');
|
|
73
|
-
return name ? [{
|
|
74
|
-
name,
|
|
75
|
-
bucket: normalizeBucket(item),
|
|
76
|
-
workflow: item.workflow ? String(item.workflow) : null,
|
|
77
|
-
conclusion: item.conclusion ? String(item.conclusion) : item.state ? String(item.state) : null,
|
|
78
|
-
detailsUrl: item.link ? String(item.link) : item.detailsUrl ? String(item.detailsUrl) : null,
|
|
79
|
-
startedAt: item.startedAt ? String(item.startedAt) : null,
|
|
80
|
-
completedAt: item.completedAt ? String(item.completedAt) : null
|
|
81
|
-
}] : [];
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
function inspectGitHubRequiredChecks(client, repository, number, cwd) {
|
|
85
|
-
const inspected = client.json([
|
|
86
|
-
'pr', 'checks', String(number), '--repo', repository,
|
|
87
|
-
'--json', 'name,state,bucket,link,workflow,startedAt,completedAt'
|
|
88
|
-
], { cwd });
|
|
89
|
-
return inspected.ok
|
|
90
|
-
? { ok: true, value: normalizeChecks(inspected.value) }
|
|
91
|
-
: { ok: false, error: inspected.error };
|
|
92
|
-
}
|
|
93
44
|
async function resolvedTask(taskRef, options) {
|
|
94
45
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
95
46
|
if (!resolved.ok)
|
|
@@ -117,10 +68,9 @@ async function inspectRequiredChecks(taskRef, options = {}) {
|
|
|
117
68
|
const base = await resolvedTask(taskRef, options);
|
|
118
69
|
if (!base.ok)
|
|
119
70
|
return base.output;
|
|
120
|
-
return inspectChecksForResolvedTask(base
|
|
71
|
+
return inspectChecksForResolvedTask(base);
|
|
121
72
|
}
|
|
122
|
-
async function inspectChecksForResolvedTask(base
|
|
123
|
-
const repository = base.context.platform.repository;
|
|
73
|
+
async function inspectChecksForResolvedTask(base) {
|
|
124
74
|
{
|
|
125
75
|
const inspected = base.provider.checks?.inspectRequired
|
|
126
76
|
? await base.provider.checks.inspectRequired({
|
|
@@ -137,7 +87,13 @@ async function inspectChecksForResolvedTask(base, options) {
|
|
|
137
87
|
pullRequest: base.pullRequest,
|
|
138
88
|
error: providerError(inspected.error, 'PLATFORM_PROVIDER_OPERATION_FAILED')
|
|
139
89
|
});
|
|
140
|
-
const required =
|
|
90
|
+
const required = inspected.value.map((check) => ({
|
|
91
|
+
name: check.name,
|
|
92
|
+
bucket: checkStatusBucket(check.status),
|
|
93
|
+
conclusion: check.conclusion || null,
|
|
94
|
+
detailsUrl: check.detailsUrl || null,
|
|
95
|
+
workflow: null, startedAt: null, completedAt: null
|
|
96
|
+
}));
|
|
141
97
|
const classified = classifyRequiredChecks(required);
|
|
142
98
|
const status = classified.state === 'passed' || classified.state === 'no-required'
|
|
143
99
|
? 'no-op'
|
|
@@ -157,7 +113,7 @@ async function inspectPullRequestReadiness(taskRef, options = {}) {
|
|
|
157
113
|
const base = await resolvedTask(taskRef, options);
|
|
158
114
|
if (!base.ok)
|
|
159
115
|
return base.output;
|
|
160
|
-
const checked = await inspectChecksForResolvedTask(base
|
|
116
|
+
const checked = await inspectChecksForResolvedTask(base);
|
|
161
117
|
const classifiedCodes = new Set(['REQUIRED_CHECKS_PENDING', 'REQUIRED_CHECKS_FAILED', 'REQUIRED_CHECKS_CANCELLED']);
|
|
162
118
|
if (checked.error && !classifiedCodes.has(checked.error.code))
|
|
163
119
|
return checked;
|
|
@@ -242,15 +198,6 @@ async function resolvePlatformCheckRun(taskRef, options) {
|
|
|
242
198
|
});
|
|
243
199
|
}
|
|
244
200
|
}
|
|
245
|
-
function fetchCheckLogText(client, args, cwd) {
|
|
246
|
-
if (!client.text)
|
|
247
|
-
return { ok: false, error: { code: 'PLATFORM_CLIENT_TEXT_UNAVAILABLE', message: 'Platform client does not support text responses', retryable: false } };
|
|
248
|
-
const fetched = client.text(args, { cwd });
|
|
249
|
-
if (fetched.ok || args[0] !== 'api' || !/response contains terminal escape sequences/i.test(fetched.error.message)) {
|
|
250
|
-
return fetched;
|
|
251
|
-
}
|
|
252
|
-
return client.text([...args, '--allow-escape-sequences'], { cwd });
|
|
253
|
-
}
|
|
254
201
|
async function fetchPlatformCheckLogs(taskRef, options) {
|
|
255
202
|
const base = await resolvedTask(taskRef, options);
|
|
256
203
|
if (!base.ok)
|
|
@@ -281,5 +228,5 @@ async function fetchPlatformCheckLogs(taskRef, options) {
|
|
|
281
228
|
});
|
|
282
229
|
}
|
|
283
230
|
}
|
|
284
|
-
export { classifyPullRequestReadiness, classifyRequiredChecks,
|
|
231
|
+
export { classifyPullRequestReadiness, classifyRequiredChecks, fetchPlatformCheckLogs, inspectRequiredChecks, inspectPullRequestReadiness, resolvePlatformCheckRun, resolveRunCandidate, watchPullRequestReadiness };
|
|
285
232
|
//# sourceMappingURL=pr-checks.js.map
|
|
@@ -11,7 +11,10 @@ import { normalizeCommentContent } from './issue-comments.js';
|
|
|
11
11
|
import { CONTROL_MARKER_PATTERN, escapeHtmlText, sanitizeMarkdownDocument, splitDocumentPlaceholder } from './comment-safety.js';
|
|
12
12
|
import { platformResult } from './types.js';
|
|
13
13
|
import { providerError, providerOperationContext, providerStatus, providerResourceToken, resourceIdentityNumber, unsupportedProviderOperation } from './provider-bridge.js';
|
|
14
|
+
import { resourceIdentityEquals } from './resource-identity.js';
|
|
14
15
|
import { buildPrChangeReport, CANONICAL_REPORT_PLACEHOLDER, readPrChangeReport, replaceCanonicalReportPlaceholder, runMechanicalChangeReport, taskIntentDigest, validateMechanicalReport, validatePrecheckCandidate, writePrChangeReportAtomic } from './pr-change-report.js';
|
|
16
|
+
import { manualValidationFinalSummaryProjectionMatches } from '../task/manual-validation-receipt.js';
|
|
17
|
+
import { readManualValidationCompletion } from '../task/manual-validation-completion.js';
|
|
15
18
|
function summaryMarker(taskId) {
|
|
16
19
|
return `<!-- sync-pr:${taskId}:summary -->`;
|
|
17
20
|
}
|
|
@@ -46,7 +49,8 @@ function readBoundTaskSnapshot(taskMdPath) {
|
|
|
46
49
|
const frontmatter = parseTypedTaskFrontmatter(taskContent);
|
|
47
50
|
const fact = readPrDeliveryFact(frontmatter);
|
|
48
51
|
const boundFact = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact : null;
|
|
49
|
-
|
|
52
|
+
const factError = fact.status === 'invalid' ? { code: fact.error.code, message: fact.error.message } : null;
|
|
53
|
+
return { taskContent, boundFact, factError };
|
|
50
54
|
}
|
|
51
55
|
function boundPrNumberForWarning(taskMdPath) {
|
|
52
56
|
try {
|
|
@@ -115,7 +119,7 @@ function isHardSummaryFailure(error) {
|
|
|
115
119
|
function inspectionError(error) {
|
|
116
120
|
return error.retryable ? 'blocked' : 'failed';
|
|
117
121
|
}
|
|
118
|
-
async function inspectBoundPullRequest(context, repoRoot,
|
|
122
|
+
async function inspectBoundPullRequest(context, repoRoot, prIdentity, loadedContext) {
|
|
119
123
|
if (!context.platform.repository) {
|
|
120
124
|
return { ok: false, status: context.status, error: context.error };
|
|
121
125
|
}
|
|
@@ -124,16 +128,15 @@ async function inspectBoundPullRequest(context, repoRoot, prNumber, loadedContex
|
|
|
124
128
|
: await resolvePlatformProviderContext({ cwd: repoRoot });
|
|
125
129
|
if (!loaded.ok)
|
|
126
130
|
return { ok: false, status: loaded.context.status, error: loaded.context.error };
|
|
127
|
-
const target = providerResourceToken(loaded.value.provider, 'pull-request', String(prNumber));
|
|
128
131
|
const inspected = loaded.value.provider.changeRequests?.inspect
|
|
129
|
-
? await loaded.value.provider.changeRequests.inspect({ context: providerOperationContext(loaded.value), target })
|
|
132
|
+
? await loaded.value.provider.changeRequests.inspect({ context: providerOperationContext(loaded.value), target: prIdentity })
|
|
130
133
|
: unsupportedProviderOperation(loaded.value.provider, 'changeRequests.inspect');
|
|
131
134
|
if (!inspected.ok) {
|
|
132
135
|
const error = providerError(inspected.error, 'PLATFORM_PROVIDER_OPERATION_FAILED');
|
|
133
136
|
return { ok: false, status: inspectionError(error), error };
|
|
134
137
|
}
|
|
135
138
|
const remote = inspected.value;
|
|
136
|
-
const number = remote.number ?? resourceIdentityNumber(remote.identity) ??
|
|
139
|
+
const number = remote.number ?? resourceIdentityNumber(remote.identity) ?? resourceIdentityNumber(prIdentity) ?? 0;
|
|
137
140
|
const head = remote.head || { repository: context.platform.repository, ref: '', sha: remote.headSha || '' };
|
|
138
141
|
const base = remote.base || { repository: context.platform.repository, ref: '', sha: remote.baseSha || '' };
|
|
139
142
|
return {
|
|
@@ -141,6 +144,7 @@ async function inspectBoundPullRequest(context, repoRoot, prNumber, loadedContex
|
|
|
141
144
|
value: {
|
|
142
145
|
repository: context.platform.repository,
|
|
143
146
|
number,
|
|
147
|
+
identity: remote.identity ?? prIdentity,
|
|
144
148
|
nodeId: remote.id,
|
|
145
149
|
url: remote.displayUrl || '',
|
|
146
150
|
state: remote.state === 'closed' ? 'closed' : 'open',
|
|
@@ -161,20 +165,22 @@ async function inspectBoundPullRequest(context, repoRoot, prNumber, loadedContex
|
|
|
161
165
|
function sameIdentity(left, right) {
|
|
162
166
|
return JSON.stringify({
|
|
163
167
|
repository: left.repository,
|
|
164
|
-
|
|
168
|
+
identity: left.identity ?? null,
|
|
165
169
|
base: left.base,
|
|
166
170
|
head: left.head
|
|
167
171
|
}) === JSON.stringify({
|
|
168
172
|
repository: right.repository,
|
|
169
|
-
|
|
173
|
+
identity: right.identity ?? null,
|
|
170
174
|
base: right.base,
|
|
171
175
|
head: right.head
|
|
172
176
|
});
|
|
173
177
|
}
|
|
174
178
|
function identityFromSnapshot(snapshot) {
|
|
179
|
+
if (!snapshot.identity)
|
|
180
|
+
throw new Error('pull-request snapshot has no canonical identity');
|
|
175
181
|
return {
|
|
176
182
|
repository: snapshot.repository,
|
|
177
|
-
|
|
183
|
+
resource: snapshot.identity,
|
|
178
184
|
base: { ...snapshot.base },
|
|
179
185
|
head: { ...snapshot.head }
|
|
180
186
|
};
|
|
@@ -203,7 +209,7 @@ function currentReportCheck(report, snapshot, taskContent, repoRoot) {
|
|
|
203
209
|
if (!digest.ok)
|
|
204
210
|
return { ok: false, error: platformError(digest.error) };
|
|
205
211
|
const reportIdentity = report.identity;
|
|
206
|
-
if (reportIdentity.repository !== snapshot.repository || reportIdentity.
|
|
212
|
+
if (reportIdentity.repository !== snapshot.repository || !resourceIdentityEquals(reportIdentity.resource, snapshot.identity) ||
|
|
207
213
|
JSON.stringify(reportIdentity.base) !== JSON.stringify(snapshot.base) || JSON.stringify(reportIdentity.head) !== JSON.stringify(snapshot.head))
|
|
208
214
|
return {
|
|
209
215
|
ok: false,
|
|
@@ -261,14 +267,23 @@ async function summaryContext(taskRef, options = {}) {
|
|
|
261
267
|
};
|
|
262
268
|
const taskContent = fs.readFileSync(resolved.taskMdPath, 'utf8');
|
|
263
269
|
const frontmatter = parseTypedTaskFrontmatter(taskContent);
|
|
264
|
-
const fact = readPrDeliveryFact(frontmatter, options.runtimeVersion);
|
|
265
|
-
const prNumber = fact.status === 'valid' && fact.fact.state === 'bound' ? resourceIdentityNumber(fact.fact.identity.resource) : null;
|
|
266
270
|
const reportPath = taskReportPath(resolved.taskDir);
|
|
271
|
+
const fact = readPrDeliveryFact(frontmatter, options.runtimeVersion);
|
|
272
|
+
if (fact.status === 'invalid')
|
|
273
|
+
return {
|
|
274
|
+
...platformResult('failed', { error: { code: fact.error.code, message: fact.error.message, retryable: false } }),
|
|
275
|
+
task: { id: resolved.taskId, prNumber: null },
|
|
276
|
+
pullRequest: null,
|
|
277
|
+
changeReport: { status: 'invalid', path: reportPath, taskIntentSha256: null, reason: fact.error.message },
|
|
278
|
+
artifacts: []
|
|
279
|
+
};
|
|
280
|
+
const prIdentity = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.resource : null;
|
|
281
|
+
const prNumber = resourceIdentityNumber(prIdentity);
|
|
267
282
|
const loaded = await resolvePlatformProviderContext({ cwd: resolved.repoRoot, client: options.client });
|
|
268
283
|
const context = loaded.ok ? loaded.value.context : loaded.context;
|
|
269
284
|
let pullRequest = null;
|
|
270
|
-
if (loaded.ok &&
|
|
271
|
-
const inspected = await inspectBoundPullRequest(context, resolved.repoRoot,
|
|
285
|
+
if (loaded.ok && prIdentity && context.platform.repository && ['no-op', 'degraded'].includes(context.status)) {
|
|
286
|
+
const inspected = await inspectBoundPullRequest(context, resolved.repoRoot, prIdentity, loaded.value);
|
|
272
287
|
if (inspected.ok)
|
|
273
288
|
pullRequest = inspected.value;
|
|
274
289
|
}
|
|
@@ -286,10 +301,45 @@ async function summaryContext(taskRef, options = {}) {
|
|
|
286
301
|
artifacts: canonicalArtifacts(resolved.taskDir)
|
|
287
302
|
};
|
|
288
303
|
}
|
|
304
|
+
async function summaryCommentState(taskRef, options = {}) {
|
|
305
|
+
const context = await summaryContext(taskRef, options);
|
|
306
|
+
const prIdentity = context.pullRequest?.identity;
|
|
307
|
+
if (!prIdentity)
|
|
308
|
+
return { ...context, comment: null };
|
|
309
|
+
const loaded = await resolvePlatformProviderContext({ cwd: options.cwd, client: options.client });
|
|
310
|
+
if (!loaded.ok || !loaded.value.provider.comments?.list)
|
|
311
|
+
return { ...context, comment: null };
|
|
312
|
+
const listed = await loaded.value.provider.comments.list({
|
|
313
|
+
context: providerOperationContext(loaded.value),
|
|
314
|
+
parent: prIdentity
|
|
315
|
+
});
|
|
316
|
+
if (!listed.ok)
|
|
317
|
+
return { ...context, comment: null };
|
|
318
|
+
const matches = listed.value.filter((comment) => comment.body.includes(summaryMarker(context.task.id)));
|
|
319
|
+
return {
|
|
320
|
+
...context,
|
|
321
|
+
comment: matches.length === 1 ? { id: /^\d+$/u.test(matches[0].id) ? Number(matches[0].id) : matches[0].id, body: matches[0].body } : null
|
|
322
|
+
};
|
|
323
|
+
}
|
|
289
324
|
async function reportWrite(taskRef, options) {
|
|
290
325
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
291
326
|
if (!resolved.ok)
|
|
292
327
|
return { ...platformResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } }), report: null };
|
|
328
|
+
let preflight;
|
|
329
|
+
try {
|
|
330
|
+
preflight = readBoundTaskSnapshot(resolved.taskMdPath);
|
|
331
|
+
}
|
|
332
|
+
catch (error) {
|
|
333
|
+
return {
|
|
334
|
+
...platformResult('failed', { error: { code: 'PR_CHANGE_REPORT_FAILED', message: error instanceof Error ? error.message : String(error), retryable: false } }),
|
|
335
|
+
report: null
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
if (preflight.factError)
|
|
339
|
+
return {
|
|
340
|
+
...platformResult('failed', { error: { code: preflight.factError.code, message: preflight.factError.message, retryable: false } }),
|
|
341
|
+
report: null
|
|
342
|
+
};
|
|
293
343
|
const loaded = await resolvePlatformProviderContext({ cwd: resolved.repoRoot, client: options.client });
|
|
294
344
|
const context = loaded.ok ? loaded.value.context : loaded.context;
|
|
295
345
|
if (!loaded.ok || !context.platform.repository || !['no-op', 'degraded'].includes(context.status))
|
|
@@ -297,20 +347,21 @@ async function reportWrite(taskRef, options) {
|
|
|
297
347
|
let knownPrNumber = null;
|
|
298
348
|
try {
|
|
299
349
|
return await withTaskExecutionLock(resolved.repoRoot, resolved.taskId, options.agent, async () => {
|
|
300
|
-
const { taskContent, boundFact } = readBoundTaskSnapshot(resolved.taskMdPath);
|
|
301
|
-
if (
|
|
350
|
+
const { taskContent, boundFact, factError } = readBoundTaskSnapshot(resolved.taskMdPath);
|
|
351
|
+
if (factError)
|
|
302
352
|
return {
|
|
303
|
-
...basePlatformResult('failed', context, resolved.taskId, null, { code:
|
|
353
|
+
...basePlatformResult('failed', context, resolved.taskId, null, { code: factError.code, message: factError.message, retryable: false }),
|
|
304
354
|
report: null
|
|
305
355
|
};
|
|
306
|
-
|
|
307
|
-
if (!boundPrNumber)
|
|
356
|
+
if (!boundFact)
|
|
308
357
|
return {
|
|
309
|
-
...basePlatformResult('failed', context, resolved.taskId, null, { code: '
|
|
358
|
+
...basePlatformResult('failed', context, resolved.taskId, null, { code: 'PR_NOT_LINKED', message: 'Task has no verified bound pull request', retryable: false }),
|
|
310
359
|
report: null
|
|
311
360
|
};
|
|
361
|
+
const boundPrIdentity = boundFact.identity.resource;
|
|
362
|
+
const boundPrNumber = resourceIdentityNumber(boundPrIdentity);
|
|
312
363
|
knownPrNumber = boundPrNumber;
|
|
313
|
-
const initial = await inspectBoundPullRequest(context, resolved.repoRoot,
|
|
364
|
+
const initial = await inspectBoundPullRequest(context, resolved.repoRoot, boundPrIdentity, loaded.value);
|
|
314
365
|
if (!initial.ok)
|
|
315
366
|
return { ...basePlatformResult(initial.status, context, resolved.taskId, boundPrNumber, initial.error), report: null };
|
|
316
367
|
const digest = taskIntentDigest(taskContent);
|
|
@@ -343,7 +394,7 @@ async function reportWrite(taskRef, options) {
|
|
|
343
394
|
const built = buildPrChangeReport(identityFromSnapshot(initial.value), digest.value.sha256, mechanical.value, candidate.value);
|
|
344
395
|
if (!built.ok)
|
|
345
396
|
return { ...basePlatformResult('failed', context, resolved.taskId, boundPrNumber, platformError(built.error)), report: null };
|
|
346
|
-
const final = await inspectBoundPullRequest(context, resolved.repoRoot,
|
|
397
|
+
const final = await inspectBoundPullRequest(context, resolved.repoRoot, boundPrIdentity, loaded.value);
|
|
347
398
|
if (!final.ok)
|
|
348
399
|
return { ...basePlatformResult(final.status, context, resolved.taskId, boundPrNumber, final.error), report: null };
|
|
349
400
|
if (!sameIdentity(initial.value, final.value))
|
|
@@ -444,8 +495,13 @@ async function syncPullRequestSummary(taskRef, options) {
|
|
|
444
495
|
return preserveFailure(context);
|
|
445
496
|
}
|
|
446
497
|
try {
|
|
447
|
-
|
|
448
|
-
const { taskContent, boundFact } = readBoundTaskSnapshot(resolved.taskMdPath);
|
|
498
|
+
const execute = async () => {
|
|
499
|
+
const { taskContent, boundFact, factError } = readBoundTaskSnapshot(resolved.taskMdPath);
|
|
500
|
+
if (factError)
|
|
501
|
+
return {
|
|
502
|
+
...platformResult('failed', { resource: { kind: 'pull-request', number: null }, error: { code: factError.code, message: factError.message, retryable: false } }),
|
|
503
|
+
result: null, warnings: []
|
|
504
|
+
};
|
|
449
505
|
if (!boundFact)
|
|
450
506
|
return {
|
|
451
507
|
...platformResult('failed', { resource: { kind: 'pull-request', number: null }, error: { code: 'PR_NOT_LINKED', message: 'Task has no verified bound pull request', retryable: false } }),
|
|
@@ -453,16 +509,41 @@ async function syncPullRequestSummary(taskRef, options) {
|
|
|
453
509
|
};
|
|
454
510
|
const prIdentity = boundFact.identity.resource;
|
|
455
511
|
const boundPrNumber = resourceIdentityNumber(prIdentity);
|
|
456
|
-
if (!boundPrNumber)
|
|
457
|
-
return {
|
|
458
|
-
...platformResult('failed', { resource: { kind: 'pull-request', number: null }, error: { code: 'PR_NUMBER_INVALID', message: 'Bound pull request has no numeric identifier', retryable: false } }),
|
|
459
|
-
result: null, warnings: []
|
|
460
|
-
};
|
|
461
512
|
knownPrNumber = boundPrNumber;
|
|
462
513
|
const prNumber = boundPrNumber;
|
|
463
|
-
const initial = await inspectBoundPullRequest(context, resolved.repoRoot,
|
|
514
|
+
const initial = await inspectBoundPullRequest(context, resolved.repoRoot, prIdentity, loaded.value);
|
|
464
515
|
if (!initial.ok)
|
|
465
516
|
return fail(initial.status, context, initial.error);
|
|
517
|
+
const manual = options.manualValidation;
|
|
518
|
+
const hasFinalManualValidation = /###\s+✅\s+(?:Manual Validation Passed|人工验证已通过)/u.test(options.body);
|
|
519
|
+
if (hasFinalManualValidation && (!manual || manual.phase !== 'final'))
|
|
520
|
+
return fail('failed', context, { code: 'MANUAL_VALIDATION_TRANSACTION_REQUIRED', message: 'final manual-validation summary requires the transaction coordinator', retryable: false }, prNumber);
|
|
521
|
+
if (manual && (manual.phase === 'pending' ? hasFinalManualValidation : !hasFinalManualValidation))
|
|
522
|
+
return fail('failed', context, { code: 'MANUAL_VALIDATION_SUMMARY_PHASE_INVALID', message: 'manual-validation summary phase does not match the requested writer phase', retryable: false }, prNumber);
|
|
523
|
+
if (manual) {
|
|
524
|
+
if (prNumber === null)
|
|
525
|
+
return fail('failed', context, { code: 'MANUAL_VALIDATION_PR_NUMBER_REQUIRED', message: 'manual-validation summary requires a numeric pull-request identity', retryable: false }, prNumber);
|
|
526
|
+
if (manual.phase === 'final' && (!manual.transactionId || !manual.receiptDigest || !manual.prHeadSha || manual.prHeadSha !== initial.value.head.sha))
|
|
527
|
+
return fail('failed', context, { code: 'MANUAL_VALIDATION_TRANSACTION_REQUIRED', message: 'final manual-validation summary requires transaction, receipt, and current head identity', retryable: false }, prNumber);
|
|
528
|
+
if (manual.phase === 'final') {
|
|
529
|
+
if (manual.authority !== 'coordinator')
|
|
530
|
+
return fail('failed', context, { code: 'MANUAL_VALIDATION_TRANSACTION_REQUIRED', message: 'final manual-validation summary requires coordinator authority', retryable: false }, prNumber);
|
|
531
|
+
const completion = readManualValidationCompletion(resolved.taskDir, {
|
|
532
|
+
transactionId: manual.transactionId,
|
|
533
|
+
taskId: resolved.taskId,
|
|
534
|
+
prNumber,
|
|
535
|
+
prHeadSha: initial.value.head.sha,
|
|
536
|
+
receiptDigest: manual.receiptDigest
|
|
537
|
+
});
|
|
538
|
+
if (!completion.ok)
|
|
539
|
+
return fail('failed', context, platformError(completion.error), prNumber);
|
|
540
|
+
const { receipt, transaction } = completion.value;
|
|
541
|
+
if (transaction.phase !== 'final-promotion-in-progress' || !transaction.eventAppended)
|
|
542
|
+
return fail('failed', context, { code: 'MANUAL_VALIDATION_TRANSACTION_PHASE_INVALID', message: 'final summary requires a receipt-backed promotion intent', retryable: false }, prNumber);
|
|
543
|
+
if (!manualValidationFinalSummaryProjectionMatches(options.body, receipt))
|
|
544
|
+
return fail('failed', context, { code: 'MANUAL_VALIDATION_SUMMARY_PROJECTION_INVALID', message: 'final summary body does not match the canonical receipt projection', retryable: false }, prNumber);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
466
547
|
const expectedReportPath = taskReportPath(resolved.taskDir);
|
|
467
548
|
const suppliedReportPath = path.resolve(resolved.repoRoot, options.changeReportFile);
|
|
468
549
|
if (suppliedReportPath !== expectedReportPath)
|
|
@@ -521,7 +602,7 @@ async function syncPullRequestSummary(taskRef, options) {
|
|
|
521
602
|
? listed.value.find((comment) => comment.id === reconciliation.commentId)?.body ?? null
|
|
522
603
|
: null;
|
|
523
604
|
const info = { precheckVerdict: report.value.precheck.verdict, nextAction: report.value.precheck.route };
|
|
524
|
-
const beforeWrite = await inspectBoundPullRequest(context, resolved.repoRoot,
|
|
605
|
+
const beforeWrite = await inspectBoundPullRequest(context, resolved.repoRoot, prIdentity, loaded.value);
|
|
525
606
|
if (!beforeWrite.ok)
|
|
526
607
|
return fail(beforeWrite.status, context, beforeWrite.error, prNumber);
|
|
527
608
|
if (!sameIdentity(initial.value, beforeWrite.value))
|
|
@@ -556,7 +637,7 @@ async function syncPullRequestSummary(taskRef, options) {
|
|
|
556
637
|
: unsupportedProviderOperation(loaded.value.provider, 'comments.write');
|
|
557
638
|
if (!written.ok)
|
|
558
639
|
return fail(providerStatus(written.error) === 'blocked' ? 'blocked' : 'failed', context, providerError(written.error, 'PLATFORM_PROVIDER_OPERATION_FAILED'), prNumber);
|
|
559
|
-
const after = await inspectBoundPullRequest(context, resolved.repoRoot,
|
|
640
|
+
const after = await inspectBoundPullRequest(context, resolved.repoRoot, prIdentity, loaded.value);
|
|
560
641
|
const id = /^\d+$/.test(written.value.remoteId) ? Number(written.value.remoteId) : written.value.remoteId;
|
|
561
642
|
const compensateWrittenSummary = async () => reconciliation.action === 'create'
|
|
562
643
|
? written.value.remoteId && loaded.value.provider.comments?.delete
|
|
@@ -610,7 +691,10 @@ async function syncPullRequestSummary(taskRef, options) {
|
|
|
610
691
|
operations: [{ name: `summary:${reconciliation.action}`, status: 'applied', reasonCode: null }],
|
|
611
692
|
result: null, warnings: [], ...info
|
|
612
693
|
};
|
|
613
|
-
}
|
|
694
|
+
};
|
|
695
|
+
return await (options.lockAlreadyHeld
|
|
696
|
+
? execute()
|
|
697
|
+
: withTaskExecutionLock(resolved.repoRoot, resolved.taskId, options.agent, execute));
|
|
614
698
|
}
|
|
615
699
|
catch (error) {
|
|
616
700
|
const lockError = error instanceof TaskExecutionLockError
|
|
@@ -619,5 +703,5 @@ async function syncPullRequestSummary(taskRef, options) {
|
|
|
619
703
|
return fail(lockError.retryable ? 'blocked' : 'failed', context, lockError);
|
|
620
704
|
}
|
|
621
705
|
}
|
|
622
|
-
export { buildPullRequestSummary, reconcileSummaryComment, reportWrite, summaryContext, summaryMarker, syncPullRequestSummary, warningResultForPrimary };
|
|
706
|
+
export { buildPullRequestSummary, reconcileSummaryComment, reportWrite, summaryCommentState, summaryContext, summaryMarker, syncPullRequestSummary, warningResultForPrimary };
|
|
623
707
|
//# sourceMappingURL=pr-summary.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizePullRequest } from './github-data.js';
|
|
1
2
|
import fs from 'node:fs';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { execFileSync } from 'node:child_process';
|
|
@@ -54,56 +55,6 @@ function withCreation(output, creation) {
|
|
|
54
55
|
const PRECONDITION_NOT_CREATED = {
|
|
55
56
|
kind: 'not-created', reason: 'precondition-failed', createdByCurrentOperation: false
|
|
56
57
|
};
|
|
57
|
-
function normalizePullRequest(remote, repository) {
|
|
58
|
-
const number = Number(remote.number);
|
|
59
|
-
const headRepository = remote.head?.repo?.full_name;
|
|
60
|
-
const baseRepository = remote.base?.repo?.full_name;
|
|
61
|
-
if (!Number.isInteger(number) || number <= 0 || !remote.node_id || !remote.html_url ||
|
|
62
|
-
!remote.head?.ref || !remote.head.sha || !headRepository || !remote.base?.ref || !baseRepository)
|
|
63
|
-
return null;
|
|
64
|
-
const mergeabilityDetail = remote.mergeable_state?.trim().toLowerCase() || null;
|
|
65
|
-
const mergeability = remote.mergeable === false
|
|
66
|
-
? { state: 'conflicting', detail: mergeabilityDetail }
|
|
67
|
-
: remote.mergeable === true && mergeabilityDetail !== 'dirty'
|
|
68
|
-
? { state: 'mergeable', detail: mergeabilityDetail }
|
|
69
|
-
: { state: 'unknown', detail: mergeabilityDetail };
|
|
70
|
-
return {
|
|
71
|
-
repository,
|
|
72
|
-
number,
|
|
73
|
-
nodeId: remote.node_id,
|
|
74
|
-
url: remote.html_url,
|
|
75
|
-
state: remote.state === 'closed' ? 'closed' : 'open',
|
|
76
|
-
title: remote.title || '',
|
|
77
|
-
body: remote.body || '',
|
|
78
|
-
draft: Boolean(remote.draft),
|
|
79
|
-
head: { repository: headRepository, ref: remote.head.ref, sha: remote.head.sha },
|
|
80
|
-
base: { repository: baseRepository, ref: remote.base.ref, sha: remote.base.sha || '' },
|
|
81
|
-
mergedAt: remote.merged_at || null,
|
|
82
|
-
mergeCommitSha: remote.merge_commit_sha || null,
|
|
83
|
-
labels: (remote.labels || []).map((label) => typeof label === 'string' ? label : label.name || '').filter(Boolean).sort(),
|
|
84
|
-
assignees: (remote.assignees || []).map((assignee) => assignee.login || '').filter(Boolean).sort(),
|
|
85
|
-
milestone: remote.milestone?.title || null,
|
|
86
|
-
mergeability
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
function normalizeClosingPullRequest(node, repository) {
|
|
90
|
-
return normalizePullRequest({
|
|
91
|
-
number: node.number,
|
|
92
|
-
node_id: node.id,
|
|
93
|
-
html_url: node.url,
|
|
94
|
-
state: node.state === 'OPEN' ? 'open' : 'closed',
|
|
95
|
-
title: node.title,
|
|
96
|
-
body: node.body,
|
|
97
|
-
draft: node.isDraft,
|
|
98
|
-
head: { ref: node.headRefName, sha: node.headRefOid, repo: node.headRepository ? { full_name: node.headRepository.nameWithOwner } : null },
|
|
99
|
-
base: { ref: node.baseRefName, sha: node.baseRefOid, repo: node.baseRepository ? { full_name: node.baseRepository.nameWithOwner } : null },
|
|
100
|
-
merged_at: node.mergedAt,
|
|
101
|
-
merge_commit_sha: node.mergeCommit?.oid,
|
|
102
|
-
labels: node.labels?.nodes,
|
|
103
|
-
assignees: node.assignees?.nodes,
|
|
104
|
-
milestone: node.milestone
|
|
105
|
-
}, repository);
|
|
106
|
-
}
|
|
107
58
|
function repositoryKey(repository) {
|
|
108
59
|
return repository.trim().toLowerCase();
|
|
109
60
|
}
|
|
@@ -183,51 +134,6 @@ function selectExternalPullRequest(candidates, repository, existingPrIdentity, e
|
|
|
183
134
|
};
|
|
184
135
|
return { status: 'selected', source: 'unique', selected: eligible[0], candidates, eligible };
|
|
185
136
|
}
|
|
186
|
-
const CLOSING_PULL_REQUESTS_QUERY = `query($owner:String!,$name:String!,$issue:Int!,$cursor:String){repository(owner:$owner,name:$name){issue(number:$issue){closedByPullRequestsReferences(first:100,after:$cursor){nodes{number id url state title body isDraft headRefName headRefOid headRepository{nameWithOwner} baseRefName baseRefOid baseRepository{nameWithOwner} mergedAt mergeCommit{oid} labels(first:100){nodes{name}} assignees(first:100){nodes{login}} milestone{title}} pageInfo{hasNextPage endCursor}}}}}`;
|
|
187
|
-
function inspectGitHubIssueClosingChangeRequests(client, repository, issueNumber, cwd) {
|
|
188
|
-
const [owner, name] = repository.split('/');
|
|
189
|
-
if (!owner || !name || !Number.isInteger(issueNumber) || issueNumber <= 0)
|
|
190
|
-
return {
|
|
191
|
-
ok: false,
|
|
192
|
-
error: { code: 'PR_IDENTITY_INVALID', message: 'Repository or Issue identity is invalid', retryable: false }
|
|
193
|
-
};
|
|
194
|
-
const candidates = [];
|
|
195
|
-
let cursor = null;
|
|
196
|
-
for (;;) {
|
|
197
|
-
const args = [
|
|
198
|
-
'api', 'graphql', '-f', `query=${CLOSING_PULL_REQUESTS_QUERY}`,
|
|
199
|
-
'-F', `owner=${owner}`, '-F', `name=${name}`, '-F', `issue=${issueNumber}`
|
|
200
|
-
];
|
|
201
|
-
if (cursor)
|
|
202
|
-
args.push('-F', `cursor=${cursor}`);
|
|
203
|
-
const response = client.json(args, { cwd });
|
|
204
|
-
if (!response.ok)
|
|
205
|
-
return response;
|
|
206
|
-
const connection = response.value?.data?.repository?.issue?.closedByPullRequestsReferences;
|
|
207
|
-
if (!connection || !Array.isArray(connection.nodes) || !connection.pageInfo)
|
|
208
|
-
return {
|
|
209
|
-
ok: false,
|
|
210
|
-
error: { code: 'PR_IDENTITY_INVALID', message: 'Closing pull request response is incomplete', retryable: false }
|
|
211
|
-
};
|
|
212
|
-
for (const node of connection.nodes) {
|
|
213
|
-
const normalized = normalizeClosingPullRequest(node, repository);
|
|
214
|
-
if (!normalized)
|
|
215
|
-
return {
|
|
216
|
-
ok: false,
|
|
217
|
-
error: { code: 'PR_IDENTITY_INVALID', message: 'Closing pull request identity is incomplete', retryable: false }
|
|
218
|
-
};
|
|
219
|
-
candidates.push(normalized);
|
|
220
|
-
}
|
|
221
|
-
if (!connection.pageInfo.hasNextPage)
|
|
222
|
-
return { ok: true, value: candidates };
|
|
223
|
-
if (!connection.pageInfo.endCursor || connection.pageInfo.endCursor === cursor)
|
|
224
|
-
return {
|
|
225
|
-
ok: false,
|
|
226
|
-
error: { code: 'PR_IDENTITY_INVALID', message: 'Closing pull request pagination cursor is invalid', retryable: false }
|
|
227
|
-
};
|
|
228
|
-
cursor = connection.pageInfo.endCursor;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
137
|
function expectedHead(repository, head) {
|
|
232
138
|
const colon = head.indexOf(':');
|
|
233
139
|
if (colon === -1)
|
|
@@ -346,7 +252,7 @@ async function resolvedContext(taskRef, options) {
|
|
|
346
252
|
const fact = factRead.status === 'valid' ? factRead.fact : null;
|
|
347
253
|
let issueIdentity;
|
|
348
254
|
try {
|
|
349
|
-
issueIdentity = taskIssueIdentity(frontmatter
|
|
255
|
+
issueIdentity = taskIssueIdentity(frontmatter);
|
|
350
256
|
}
|
|
351
257
|
catch (error) {
|
|
352
258
|
return { ok: false, output: result('failed', resolved.taskId, null, null, { error: { ...taskIssueIdentityError(error), retryable: false } }) };
|
|
@@ -420,15 +326,6 @@ async function inspectExternalPullRequest(base, prIdentity) {
|
|
|
420
326
|
error: null
|
|
421
327
|
});
|
|
422
328
|
}
|
|
423
|
-
function inspectGitHubPullRequest(client, repository, number, cwd) {
|
|
424
|
-
const fetched = client.json(['api', `repos/${repository}/pulls/${number}`], { cwd });
|
|
425
|
-
if (!fetched.ok)
|
|
426
|
-
return fetched;
|
|
427
|
-
const pullRequest = normalizePullRequest(fetched.value, repository);
|
|
428
|
-
return pullRequest
|
|
429
|
-
? { ok: true, value: pullRequest }
|
|
430
|
-
: { ok: false, error: { code: 'PR_IDENTITY_INVALID', message: 'Remote resource is not a valid pull request', retryable: false } };
|
|
431
|
-
}
|
|
432
329
|
async function inspectPlatformPullRequest(taskRef, options = {}) {
|
|
433
330
|
const base = await resolvedContext(taskRef, options);
|
|
434
331
|
if (!base.ok)
|
|
@@ -879,7 +776,7 @@ async function resolveExternalPullRequest(taskRef, options) {
|
|
|
879
776
|
return externalResult(result('failed', base.resolved.taskId, null, base.prNumber, {
|
|
880
777
|
platform: base.context.platform,
|
|
881
778
|
capabilities: base.context.capabilities,
|
|
882
|
-
error: { code: 'EXTERNAL_DELIVERY_ISSUE_REQUIRED', message: 'External delivery requires a valid
|
|
779
|
+
error: { code: 'EXTERNAL_DELIVERY_ISSUE_REQUIRED', message: 'External delivery requires a valid platform issue identity', retryable: false }
|
|
883
780
|
}));
|
|
884
781
|
const inspected = base.provider.changeRequests?.listClosing
|
|
885
782
|
? await base.provider.changeRequests.listClosing({
|
|
@@ -1388,7 +1285,7 @@ function skipPlatformPullRequestFactUnlocked(resolved, options) {
|
|
|
1388
1285
|
}
|
|
1389
1286
|
let issueIdentity;
|
|
1390
1287
|
try {
|
|
1391
|
-
issueIdentity = taskIssueIdentity(frontmatter
|
|
1288
|
+
issueIdentity = taskIssueIdentity(frontmatter);
|
|
1392
1289
|
}
|
|
1393
1290
|
catch (error) {
|
|
1394
1291
|
return result('failed', resolved.taskId, null, null, { error: { ...taskIssueIdentityError(error), retryable: false } });
|
|
@@ -1463,6 +1360,6 @@ async function skipPlatformPullRequestFact(taskRef, options) {
|
|
|
1463
1360
|
});
|
|
1464
1361
|
}
|
|
1465
1362
|
}
|
|
1466
|
-
export { bindPlatformPullRequest, createPlatformPullRequest,
|
|
1363
|
+
export { bindPlatformPullRequest, createPlatformPullRequest, inspectPlatformPullRequest, inspectPlatformPullRequestByNumber, resolveExternalPullRequest, skipPlatformPullRequestFact, selectExternalPullRequest, selectPullRequest, syncPlatformPullRequest, syncPlatformPullRequestInLabels };
|
|
1467
1364
|
export { warningResultForPrimary };
|
|
1468
1365
|
//# sourceMappingURL=pull-requests.js.map
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { parseResourceIdentity } from './resource-identity.js';
|
|
2
|
-
import { isLegacyCompatibilityEnabled, legacyCompatibilityError, VERSION } from '../version.js';
|
|
3
2
|
import { parse as parseYaml } from 'yaml';
|
|
4
|
-
function taskIssueIdentity(frontmatter
|
|
3
|
+
function taskIssueIdentity(frontmatter) {
|
|
5
4
|
const serialized = frontmatter.platform_issue_identity;
|
|
6
5
|
if (typeof serialized === 'string' && serialized.trim()) {
|
|
7
6
|
try {
|
|
@@ -12,13 +11,7 @@ function taskIssueIdentity(frontmatter, _declaration, runtimeVersion = VERSION)
|
|
|
12
11
|
return null;
|
|
13
12
|
}
|
|
14
13
|
}
|
|
15
|
-
|
|
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;
|
|
14
|
+
return null;
|
|
22
15
|
}
|
|
23
16
|
function taskIssueIdentityError(error) {
|
|
24
17
|
const value = error && typeof error === 'object' ? error : {};
|