@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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { VerificationShared } from "../task/verification-types.ts";
|
|
1
2
|
import fs from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import process from "node:process";
|
|
@@ -11,6 +12,13 @@ import { planInLabelUpdate, validateInLabelMapping } from "./in-label-sync.ts";
|
|
|
11
12
|
import { readPrDeliveryFact } from "../task/pr-delivery-fact.ts";
|
|
12
13
|
import { providerError, providerOperationContext, resourceIdentityNumber, unsupportedProviderOperation } from "./provider-bridge.ts";
|
|
13
14
|
import { taskIssueIdentity } from "./task-identities.ts";
|
|
15
|
+
import { isTaskCommentTooLarge } from "./issue-comments.ts";
|
|
16
|
+
import {
|
|
17
|
+
CONTROL_MARKER_PATTERN,
|
|
18
|
+
canonicalizeCommentBody,
|
|
19
|
+
renderSafeCodeFence,
|
|
20
|
+
sanitizeMarkdownDocument
|
|
21
|
+
} from "./comment-safety.ts";
|
|
14
22
|
|
|
15
23
|
const CHECK_TYPE = "platform-sync";
|
|
16
24
|
const VERSION_LINE_REGEX = /^[0-9]+\.[0-9]+\.x$/;
|
|
@@ -27,9 +35,6 @@ const OPTION_LOCALIZATION: Record<string, string> = {
|
|
|
27
35
|
"低": "Low"
|
|
28
36
|
};
|
|
29
37
|
|
|
30
|
-
let activeShared: any = null;
|
|
31
|
-
let repoRoot = "";
|
|
32
|
-
|
|
33
38
|
export function getDefaults(): any {
|
|
34
39
|
return {
|
|
35
40
|
statusLabels: {
|
|
@@ -50,59 +55,18 @@ export function getDefaults(): any {
|
|
|
50
55
|
};
|
|
51
56
|
}
|
|
52
57
|
|
|
53
|
-
function
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return activeShared;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function loadTask(...args: any[]): any {
|
|
62
|
-
return getShared().loadTask(...args);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function getCheckedRequirements(...args: any[]): any {
|
|
66
|
-
return getShared().getCheckedRequirements(...args);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function normalizeContent(...args: any[]): any {
|
|
70
|
-
return getShared().normalizeContent(...args);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function isBlank(...args: any[]): any {
|
|
74
|
-
return getShared().isBlank(...args);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function escapeRegExp(...args: any[]): any {
|
|
78
|
-
return getShared().escapeRegExp(...args);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function passResult(...args: any[]): any {
|
|
82
|
-
return getShared().passResult(...args);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function failResult(...args: any[]): any {
|
|
86
|
-
return getShared().failResult(...args);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function blockedResult(...args: any[]): any {
|
|
90
|
-
return getShared().blockedResult(...args);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function safeStat(...args: any[]): any {
|
|
94
|
-
return getShared().safeStat(...args);
|
|
58
|
+
function sanitizeCommentContent(content: string): string | null {
|
|
59
|
+
const result = sanitizeMarkdownDocument(content, { reservedMarkers: [CONTROL_MARKER_PATTERN] });
|
|
60
|
+
return result.ok ? result.value : null;
|
|
95
61
|
}
|
|
96
62
|
|
|
97
|
-
export async function check({ taskDir, config, artifactFile }: any, shared:
|
|
98
|
-
|
|
99
|
-
repoRoot = shared.repoRoot;
|
|
100
|
-
const context = await buildSyncContext({ taskDir, config, artifactFile });
|
|
63
|
+
export async function check({ taskDir, config, artifactFile }: any, shared: VerificationShared): Promise<any> {
|
|
64
|
+
const context = await buildSyncContext({ taskDir, config, artifactFile }, shared);
|
|
101
65
|
if (context.earlyReturn) {
|
|
102
66
|
return context.earlyReturn;
|
|
103
67
|
}
|
|
104
68
|
|
|
105
|
-
const remoteData = await fetchRemoteData(context);
|
|
69
|
+
const remoteData = await fetchRemoteData(context, shared);
|
|
106
70
|
if (remoteData.earlyReturn) {
|
|
107
71
|
return remoteData.earlyReturn;
|
|
108
72
|
}
|
|
@@ -127,57 +91,57 @@ export async function check({ taskDir, config, artifactFile }: any, shared: any)
|
|
|
127
91
|
];
|
|
128
92
|
|
|
129
93
|
for (const subCheck of subChecks) {
|
|
130
|
-
const result = subCheck(context, remoteData);
|
|
94
|
+
const result = subCheck(context, remoteData, shared);
|
|
131
95
|
if (result) {
|
|
132
96
|
return result;
|
|
133
97
|
}
|
|
134
98
|
}
|
|
135
99
|
|
|
136
|
-
return passResult(CHECK_TYPE, `Platform sync checks passed for Issue ${context.issueNumber || "identity"}`);
|
|
100
|
+
return shared.passResult(CHECK_TYPE, `Platform sync checks passed for Issue ${context.issueNumber || "identity"}`);
|
|
137
101
|
}
|
|
138
102
|
|
|
139
|
-
async function buildSyncContext({ taskDir, config, artifactFile }: any): Promise<any> {
|
|
140
|
-
const task = loadTask(taskDir);
|
|
103
|
+
async function buildSyncContext({ taskDir, config, artifactFile }: any, shared: VerificationShared): Promise<any> {
|
|
104
|
+
const task = shared.loadTask(taskDir);
|
|
141
105
|
if (!task.ok) {
|
|
142
|
-
return { earlyReturn: failResult(CHECK_TYPE, task.message) };
|
|
106
|
+
return { earlyReturn: shared.failResult(CHECK_TYPE, task.message) };
|
|
143
107
|
}
|
|
144
108
|
|
|
145
109
|
const issueIdentity = taskIssueIdentity(task.metadata);
|
|
146
110
|
const issueNumber = resourceIdentityNumber(issueIdentity);
|
|
147
111
|
const fact = readPrDeliveryFact(task.metadata);
|
|
148
112
|
if (fact.status === "invalid") {
|
|
149
|
-
return { earlyReturn: failResult(CHECK_TYPE, fact.error.message, "check_failed") };
|
|
113
|
+
return { earlyReturn: shared.failResult(CHECK_TYPE, fact.error.message, "check_failed") };
|
|
150
114
|
}
|
|
151
115
|
const prIdentity = fact.status === "valid" && fact.fact.state === "bound" ? fact.fact.identity.resource : null;
|
|
152
116
|
const prNumber = resourceIdentityNumber(prIdentity);
|
|
153
|
-
if (config.when === "
|
|
154
|
-
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no
|
|
117
|
+
if (config.when === "platform_issue_identity_exists" && !issueIdentity) {
|
|
118
|
+
return { earlyReturn: shared.passResult(CHECK_TYPE, "Skipped: task has no platform_issue_identity") };
|
|
155
119
|
}
|
|
156
120
|
if (config.when === "pr_fact_bound" && !prIdentity) {
|
|
157
|
-
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no verified bound pull request") };
|
|
121
|
+
return { earlyReturn: shared.passResult(CHECK_TYPE, "Skipped: task has no verified bound pull request") };
|
|
158
122
|
}
|
|
159
123
|
|
|
160
124
|
if (!issueIdentity) {
|
|
161
|
-
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: platform-sync not required for this task") };
|
|
125
|
+
return { earlyReturn: shared.passResult(CHECK_TYPE, "Skipped: platform-sync not required for this task") };
|
|
162
126
|
}
|
|
163
127
|
|
|
164
|
-
const loaded = await resolvePlatformProviderContext({ cwd: repoRoot });
|
|
128
|
+
const loaded = await resolvePlatformProviderContext({ cwd: shared.repoRoot });
|
|
165
129
|
const platformContext = loaded.ok ? loaded.value.context : loaded.context;
|
|
166
130
|
if (platformContext.status === "failed") {
|
|
167
|
-
return { earlyReturn: failResult(CHECK_TYPE, platformContext.error?.message || "Platform context failed", "check_failed") };
|
|
131
|
+
return { earlyReturn: shared.failResult(CHECK_TYPE, platformContext.error?.message || "Platform context failed", "check_failed") };
|
|
168
132
|
}
|
|
169
133
|
if (platformContext.status === "blocked") {
|
|
170
|
-
return { earlyReturn: blockedResult(CHECK_TYPE, platformContext.error?.message || "Platform context blocked", "network_error") };
|
|
134
|
+
return { earlyReturn: shared.blockedResult(CHECK_TYPE, platformContext.error?.message || "Platform context blocked", "network_error") };
|
|
171
135
|
}
|
|
172
136
|
if (!platformContext.platform.repository) {
|
|
173
137
|
if (platformContext.error?.code === "REMOTE_MISSING" || platformContext.error?.code === "REMOTE_INVALID") {
|
|
174
|
-
return { earlyReturn: blockedResult(CHECK_TYPE, platformContext.error.message, "network_error") };
|
|
138
|
+
return { earlyReturn: shared.blockedResult(CHECK_TYPE, platformContext.error.message, "network_error") };
|
|
175
139
|
}
|
|
176
|
-
return { earlyReturn: passResult(CHECK_TYPE, `Skipped: ${platformContext.error?.message || "platform unavailable"}`) };
|
|
140
|
+
return { earlyReturn: shared.passResult(CHECK_TYPE, `Skipped: ${platformContext.error?.message || "platform unavailable"}`) };
|
|
177
141
|
}
|
|
178
142
|
const expectedValues = resolveExpectedValues(config);
|
|
179
143
|
if (!expectedValues.ok) {
|
|
180
|
-
return { earlyReturn: failResult(CHECK_TYPE, expectedValues.message, "check_failed") };
|
|
144
|
+
return { earlyReturn: shared.failResult(CHECK_TYPE, expectedValues.message, "check_failed") };
|
|
181
145
|
}
|
|
182
146
|
|
|
183
147
|
const marker = expectedValues.commentMarker
|
|
@@ -263,7 +227,7 @@ function resolveDefaultValue({ collection, key, value, configKey }: any): any {
|
|
|
263
227
|
return { ok: true, value: resolvedValue };
|
|
264
228
|
}
|
|
265
229
|
|
|
266
|
-
async function fetchRemoteData(context: any): Promise<any> {
|
|
230
|
+
async function fetchRemoteData(context: any, shared: VerificationShared): Promise<any> {
|
|
267
231
|
const provider = context.provider;
|
|
268
232
|
const operationContext = providerOperationContext(context.loadedContext, context.taskDir);
|
|
269
233
|
const facts = provider?.verification?.fetchRemoteFacts
|
|
@@ -279,8 +243,8 @@ async function fetchRemoteData(context: any): Promise<any> {
|
|
|
279
243
|
if (!facts.ok) {
|
|
280
244
|
return {
|
|
281
245
|
earlyReturn: facts.error.retryable
|
|
282
|
-
? blockedResult(CHECK_TYPE, providerError(facts.error, "PLATFORM_PROVIDER_OPERATION_FAILED").message, "network_error")
|
|
283
|
-
: failResult(CHECK_TYPE, providerError(facts.error, "PLATFORM_PROVIDER_OPERATION_FAILED").message, "check_failed")
|
|
246
|
+
? shared.blockedResult(CHECK_TYPE, providerError(facts.error, "PLATFORM_PROVIDER_OPERATION_FAILED").message, "network_error")
|
|
247
|
+
: shared.failResult(CHECK_TYPE, providerError(facts.error, "PLATFORM_PROVIDER_OPERATION_FAILED").message, "check_failed")
|
|
284
248
|
};
|
|
285
249
|
}
|
|
286
250
|
const issueSnapshot = facts.value.issue;
|
|
@@ -305,8 +269,8 @@ async function fetchRemoteData(context: any): Promise<any> {
|
|
|
305
269
|
const listed = await provider.comments.list({ context: operationContext, parent: context.prIdentity });
|
|
306
270
|
if (!listed.ok) return {
|
|
307
271
|
earlyReturn: listed.error.retryable
|
|
308
|
-
? blockedResult(CHECK_TYPE, listed.error.message, "network_error")
|
|
309
|
-
: failResult(CHECK_TYPE, listed.error.message, "check_failed")
|
|
272
|
+
? shared.blockedResult(CHECK_TYPE, listed.error.message, "network_error")
|
|
273
|
+
: shared.failResult(CHECK_TYPE, listed.error.message, "check_failed")
|
|
310
274
|
};
|
|
311
275
|
prComments = listed.value.map((comment: { id: string; body: string }) => ({ id: comment.id, body: comment.body }));
|
|
312
276
|
}
|
|
@@ -314,8 +278,8 @@ async function fetchRemoteData(context: any): Promise<any> {
|
|
|
314
278
|
let inLabelMapping: Record<string, string[]> = {};
|
|
315
279
|
let repositoryLabels: string[] = [];
|
|
316
280
|
if (context.config.verify_in_labels_computed && context.hasTriage) {
|
|
317
|
-
const mapping = loadInLabelMapping();
|
|
318
|
-
if (!mapping.ok) return { earlyReturn: failResult(CHECK_TYPE, mapping.message, "check_failed") };
|
|
281
|
+
const mapping = loadInLabelMapping(shared);
|
|
282
|
+
if (!mapping.ok) return { earlyReturn: shared.failResult(CHECK_TYPE, mapping.message, "check_failed") };
|
|
319
283
|
inLabelMapping = mapping.value;
|
|
320
284
|
if (Object.keys(inLabelMapping).length > 0) {
|
|
321
285
|
const labels = provider?.issues?.listLabels
|
|
@@ -325,8 +289,8 @@ async function fetchRemoteData(context: any): Promise<any> {
|
|
|
325
289
|
const error = providerError(labels.error, "PLATFORM_PROVIDER_OPERATION_FAILED");
|
|
326
290
|
return {
|
|
327
291
|
earlyReturn: error.retryable
|
|
328
|
-
? blockedResult(CHECK_TYPE, `${error.code}: ${error.message}`, "network_error")
|
|
329
|
-
: failResult(CHECK_TYPE, `${error.code}: ${error.message}`, "check_failed")
|
|
292
|
+
? shared.blockedResult(CHECK_TYPE, `${error.code}: ${error.message}`, "network_error")
|
|
293
|
+
: shared.failResult(CHECK_TYPE, `${error.code}: ${error.message}`, "check_failed")
|
|
330
294
|
};
|
|
331
295
|
}
|
|
332
296
|
repositoryLabels = labels.value;
|
|
@@ -367,7 +331,7 @@ function shouldFetchComments(config: any): any {
|
|
|
367
331
|
);
|
|
368
332
|
}
|
|
369
333
|
|
|
370
|
-
function checkStatusLabel(context: any, remoteData: any): any {
|
|
334
|
+
function checkStatusLabel(context: any, remoteData: any, shared: VerificationShared): any {
|
|
371
335
|
if (!context.expectedStatusLabel || !context.hasTriage) {
|
|
372
336
|
return null;
|
|
373
337
|
}
|
|
@@ -381,13 +345,13 @@ function checkStatusLabel(context: any, remoteData: any): any {
|
|
|
381
345
|
return null;
|
|
382
346
|
}
|
|
383
347
|
|
|
384
|
-
return failResult(CHECK_TYPE,
|
|
348
|
+
return shared.failResult(CHECK_TYPE,
|
|
385
349
|
`Expected label '${context.expectedStatusLabel}' not found on Issue #${context.issueNumber}`,
|
|
386
350
|
"check_failed"
|
|
387
351
|
);
|
|
388
352
|
}
|
|
389
353
|
|
|
390
|
-
function checkClosedIssueStatusLabels(context: any, remoteData: any): any {
|
|
354
|
+
function checkClosedIssueStatusLabels(context: any, remoteData: any, shared: VerificationShared): any {
|
|
391
355
|
if (!context.config.verify_closed_issue_has_no_status_labels) {
|
|
392
356
|
return null;
|
|
393
357
|
}
|
|
@@ -402,13 +366,13 @@ function checkClosedIssueStatusLabels(context: any, remoteData: any): any {
|
|
|
402
366
|
return null;
|
|
403
367
|
}
|
|
404
368
|
|
|
405
|
-
return failResult(CHECK_TYPE,
|
|
369
|
+
return shared.failResult(CHECK_TYPE,
|
|
406
370
|
`Closed Issue #${context.issueNumber} retains status labels: ${statusLabels.join(", ")}`,
|
|
407
371
|
"check_failed"
|
|
408
372
|
);
|
|
409
373
|
}
|
|
410
374
|
|
|
411
|
-
function checkCommentMarker(context: any, remoteData: any): any {
|
|
375
|
+
function checkCommentMarker(context: any, remoteData: any, shared: VerificationShared): any {
|
|
412
376
|
if (!context.marker) {
|
|
413
377
|
return null;
|
|
414
378
|
}
|
|
@@ -418,13 +382,13 @@ function checkCommentMarker(context: any, remoteData: any): any {
|
|
|
418
382
|
return null;
|
|
419
383
|
}
|
|
420
384
|
|
|
421
|
-
return failResult(CHECK_TYPE,
|
|
385
|
+
return shared.failResult(CHECK_TYPE,
|
|
422
386
|
`Expected comment marker '${context.marker}' not found on Issue #${context.issueNumber}`,
|
|
423
387
|
"check_failed"
|
|
424
388
|
);
|
|
425
389
|
}
|
|
426
390
|
|
|
427
|
-
function checkPrCommentMarker(context: any, remoteData: any): any {
|
|
391
|
+
function checkPrCommentMarker(context: any, remoteData: any, shared: VerificationShared): any {
|
|
428
392
|
if (!context.prMarker) {
|
|
429
393
|
return null;
|
|
430
394
|
}
|
|
@@ -434,19 +398,19 @@ function checkPrCommentMarker(context: any, remoteData: any): any {
|
|
|
434
398
|
return null;
|
|
435
399
|
}
|
|
436
400
|
|
|
437
|
-
return failResult(CHECK_TYPE,
|
|
401
|
+
return shared.failResult(CHECK_TYPE,
|
|
438
402
|
`Expected PR comment marker '${context.prMarker}' not found on PR #${context.prNumber}`,
|
|
439
403
|
"check_failed"
|
|
440
404
|
);
|
|
441
405
|
}
|
|
442
406
|
|
|
443
|
-
function checkPrCommentLastCommit(context: any, remoteData: any): any {
|
|
407
|
+
function checkPrCommentLastCommit(context: any, remoteData: any, shared: VerificationShared): any {
|
|
444
408
|
if (!context.config.verify_pr_comment_last_commit_matches_head) {
|
|
445
409
|
return null;
|
|
446
410
|
}
|
|
447
411
|
|
|
448
412
|
if (!context.prMarker) {
|
|
449
|
-
return failResult(CHECK_TYPE,
|
|
413
|
+
return shared.failResult(CHECK_TYPE,
|
|
450
414
|
"verify_pr_comment_last_commit_matches_head requires expected_pr_comment_marker",
|
|
451
415
|
"check_failed"
|
|
452
416
|
);
|
|
@@ -454,7 +418,7 @@ function checkPrCommentLastCommit(context: any, remoteData: any): any {
|
|
|
454
418
|
|
|
455
419
|
const comment = findCommentByMarker(remoteData.prComments, context.prMarker);
|
|
456
420
|
if (!comment) {
|
|
457
|
-
return failResult(CHECK_TYPE,
|
|
421
|
+
return shared.failResult(CHECK_TYPE,
|
|
458
422
|
`Expected PR comment marker '${context.prMarker}' not found on PR #${context.prNumber}`,
|
|
459
423
|
"check_failed"
|
|
460
424
|
);
|
|
@@ -462,33 +426,33 @@ function checkPrCommentLastCommit(context: any, remoteData: any): any {
|
|
|
462
426
|
|
|
463
427
|
const match = String(comment.body || "").match(/<!--\s*last-commit:\s*([0-9a-f]{7,40})\s*-->/i);
|
|
464
428
|
if (!match) {
|
|
465
|
-
return failResult(CHECK_TYPE,
|
|
429
|
+
return shared.failResult(CHECK_TYPE,
|
|
466
430
|
`PR #${context.prNumber} summary comment is missing '<!-- last-commit: <sha> -->' metadata`,
|
|
467
431
|
"check_failed"
|
|
468
432
|
);
|
|
469
433
|
}
|
|
470
434
|
|
|
471
435
|
const expectedHead = String(remoteData.prHeadSha || "").trim();
|
|
472
|
-
if (!expectedHead) return blockedResult(CHECK_TYPE, "Unable to resolve the PR head SHA", "network_error");
|
|
436
|
+
if (!expectedHead) return shared.blockedResult(CHECK_TYPE, "Unable to resolve the PR head SHA", "network_error");
|
|
473
437
|
const actualHead = match[1]!.trim();
|
|
474
438
|
if (expectedHead === actualHead) {
|
|
475
439
|
return null;
|
|
476
440
|
}
|
|
477
441
|
|
|
478
|
-
return failResult(CHECK_TYPE,
|
|
442
|
+
return shared.failResult(CHECK_TYPE,
|
|
479
443
|
`PR #${context.prNumber} summary comment last-commit metadata mismatch: expected ${expectedHead}, got ${actualHead}`,
|
|
480
444
|
"check_failed"
|
|
481
445
|
);
|
|
482
446
|
}
|
|
483
447
|
|
|
484
|
-
function checkPrCommentRequiredPatterns(context: any, remoteData: any): any {
|
|
448
|
+
function checkPrCommentRequiredPatterns(context: any, remoteData: any, shared: VerificationShared): any {
|
|
485
449
|
const patterns = context.config.expected_pr_comment_required_patterns || [];
|
|
486
450
|
if (!Array.isArray(patterns) || patterns.length === 0) {
|
|
487
451
|
return null;
|
|
488
452
|
}
|
|
489
453
|
|
|
490
454
|
if (!context.prMarker) {
|
|
491
|
-
return failResult(CHECK_TYPE,
|
|
455
|
+
return shared.failResult(CHECK_TYPE,
|
|
492
456
|
"expected_pr_comment_required_patterns requires expected_pr_comment_marker",
|
|
493
457
|
"check_failed"
|
|
494
458
|
);
|
|
@@ -496,7 +460,7 @@ function checkPrCommentRequiredPatterns(context: any, remoteData: any): any {
|
|
|
496
460
|
|
|
497
461
|
const comment = findCommentByMarker(remoteData.prComments, context.prMarker);
|
|
498
462
|
if (!comment) {
|
|
499
|
-
return failResult(CHECK_TYPE,
|
|
463
|
+
return shared.failResult(CHECK_TYPE,
|
|
500
464
|
`Expected PR comment marker '${context.prMarker}' not found on PR #${context.prNumber}`,
|
|
501
465
|
"check_failed"
|
|
502
466
|
);
|
|
@@ -506,7 +470,7 @@ function checkPrCommentRequiredPatterns(context: any, remoteData: any): any {
|
|
|
506
470
|
for (const pattern of patterns) {
|
|
507
471
|
const regex = new RegExp(pattern, "m");
|
|
508
472
|
if (!regex.test(body)) {
|
|
509
|
-
return failResult(CHECK_TYPE,
|
|
473
|
+
return shared.failResult(CHECK_TYPE,
|
|
510
474
|
`PR #${context.prNumber} summary comment is missing required pattern: ${pattern}`,
|
|
511
475
|
"check_failed"
|
|
512
476
|
);
|
|
@@ -516,31 +480,54 @@ function checkPrCommentRequiredPatterns(context: any, remoteData: any): any {
|
|
|
516
480
|
return null;
|
|
517
481
|
}
|
|
518
482
|
|
|
519
|
-
function checkCommentContent(context: any, remoteData: any): any {
|
|
483
|
+
function checkCommentContent(context: any, remoteData: any, shared: VerificationShared): any {
|
|
520
484
|
if (!context.config.verify_comment_content) {
|
|
521
485
|
return null;
|
|
522
486
|
}
|
|
523
487
|
|
|
524
488
|
if (!context.marker) {
|
|
525
|
-
return failResult(CHECK_TYPE, "verify_comment_content requires expected_comment_marker", "check_failed");
|
|
489
|
+
return shared.failResult(CHECK_TYPE, "verify_comment_content requires expected_comment_marker", "check_failed");
|
|
526
490
|
}
|
|
527
491
|
|
|
528
|
-
if (!context.artifactPath || !safeStat(context.artifactPath)) {
|
|
529
|
-
return failResult(CHECK_TYPE,
|
|
492
|
+
if (!context.artifactPath || !shared.safeStat(context.artifactPath)) {
|
|
493
|
+
return shared.failResult(CHECK_TYPE,
|
|
530
494
|
`Artifact not found for comment verification: ${context.artifactFile || "(missing artifactFile)"}`,
|
|
531
495
|
"check_failed"
|
|
532
496
|
);
|
|
533
497
|
}
|
|
534
498
|
|
|
535
499
|
const comment = findCommentByMarker(remoteData.comments, context.marker);
|
|
536
|
-
|
|
537
|
-
|
|
500
|
+
let localContent: string;
|
|
501
|
+
let commentContent: string;
|
|
502
|
+
try {
|
|
503
|
+
const localCanonical = canonicalizeCommentBody(fs.readFileSync(context.artifactPath, "utf8"));
|
|
504
|
+
const commentCanonical = canonicalizeCommentBody(extractCommentBody(comment?.body || ""));
|
|
505
|
+
if (!localCanonical.ok) {
|
|
506
|
+
return shared.failResult(CHECK_TYPE,
|
|
507
|
+
`Comment content cannot be canonicalized for '${path.basename(context.artifactPath, path.extname(context.artifactPath))}': ${localCanonical.error.message}`,
|
|
508
|
+
"check_failed"
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
if (!commentCanonical.ok) {
|
|
512
|
+
return shared.failResult(CHECK_TYPE,
|
|
513
|
+
`Comment content cannot be canonicalized for '${path.basename(context.artifactPath, path.extname(context.artifactPath))}': ${commentCanonical.error.message}`,
|
|
514
|
+
"check_failed"
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
localContent = shared.normalizeContent(localCanonical.value);
|
|
518
|
+
commentContent = shared.normalizeContent(commentCanonical.value);
|
|
519
|
+
} catch (error) {
|
|
520
|
+
return shared.failResult(CHECK_TYPE,
|
|
521
|
+
`Comment content cannot be read for '${path.basename(context.artifactPath, path.extname(context.artifactPath))}': ${error instanceof Error ? error.message : String(error)}`,
|
|
522
|
+
"check_failed"
|
|
523
|
+
);
|
|
524
|
+
}
|
|
538
525
|
|
|
539
526
|
if (localContent === commentContent) {
|
|
540
527
|
return null;
|
|
541
528
|
}
|
|
542
529
|
|
|
543
|
-
return failResult(CHECK_TYPE,
|
|
530
|
+
return shared.failResult(CHECK_TYPE,
|
|
544
531
|
buildCommentContentMismatchMessage(
|
|
545
532
|
path.basename(context.artifactPath, path.extname(context.artifactPath)),
|
|
546
533
|
context.issueNumber,
|
|
@@ -551,34 +538,44 @@ function checkCommentContent(context: any, remoteData: any): any {
|
|
|
551
538
|
);
|
|
552
539
|
}
|
|
553
540
|
|
|
554
|
-
function checkTaskCommentContent(context: any, remoteData: any): any {
|
|
541
|
+
function checkTaskCommentContent(context: any, remoteData: any, shared: VerificationShared): any {
|
|
555
542
|
if (!context.config.verify_task_comment_content) {
|
|
556
543
|
return null;
|
|
557
544
|
}
|
|
545
|
+
if (isTaskCommentTooLarge(context.task.content)) {
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
558
548
|
|
|
559
549
|
const taskMarker = `<!-- sync-issue:${context.task.metadata.id}:task -->`;
|
|
560
550
|
const comment = findCommentByMarker(remoteData.comments, taskMarker);
|
|
561
551
|
if (!comment) {
|
|
562
|
-
return failResult(CHECK_TYPE,
|
|
552
|
+
return shared.failResult(CHECK_TYPE,
|
|
563
553
|
`Expected comment marker '${taskMarker}' not found on Issue #${context.issueNumber}`,
|
|
564
554
|
"check_failed"
|
|
565
555
|
);
|
|
566
556
|
}
|
|
567
557
|
|
|
568
|
-
const
|
|
569
|
-
|
|
558
|
+
const expectedTaskBody = buildExpectedTaskBody(context.task.content, shared);
|
|
559
|
+
if (expectedTaskBody === null) {
|
|
560
|
+
return shared.failResult(CHECK_TYPE,
|
|
561
|
+
"Task content cannot be rendered safely for comment verification",
|
|
562
|
+
"check_failed"
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
const expectedBody = shared.normalizeContent(expectedTaskBody);
|
|
566
|
+
const commentBody = shared.normalizeContent(extractCommentBody(comment.body || ""));
|
|
570
567
|
|
|
571
568
|
if (expectedBody === commentBody) {
|
|
572
569
|
return null;
|
|
573
570
|
}
|
|
574
571
|
|
|
575
|
-
return failResult(CHECK_TYPE,
|
|
572
|
+
return shared.failResult(CHECK_TYPE,
|
|
576
573
|
buildCommentContentMismatchMessage("task", context.issueNumber, expectedBody, commentBody),
|
|
577
574
|
"check_failed"
|
|
578
575
|
);
|
|
579
576
|
}
|
|
580
577
|
|
|
581
|
-
function checkPrTypeLabel(context: any, remoteData: any): any {
|
|
578
|
+
function checkPrTypeLabel(context: any, remoteData: any, shared: VerificationShared): any {
|
|
582
579
|
if (!context.config.verify_pr_type_label || !context.hasTriage || !context.prNumber || !remoteData.prLabels) {
|
|
583
580
|
return null;
|
|
584
581
|
}
|
|
@@ -592,13 +589,13 @@ function checkPrTypeLabel(context: any, remoteData: any): any {
|
|
|
592
589
|
return null;
|
|
593
590
|
}
|
|
594
591
|
|
|
595
|
-
return failResult(CHECK_TYPE,
|
|
592
|
+
return shared.failResult(CHECK_TYPE,
|
|
596
593
|
`Expected type label '${expectedLabel}' not found on PR #${context.prNumber}`,
|
|
597
594
|
"check_failed"
|
|
598
595
|
);
|
|
599
596
|
}
|
|
600
597
|
|
|
601
|
-
function checkInLabelsMatchPr(context: any, remoteData: any): any {
|
|
598
|
+
function checkInLabelsMatchPr(context: any, remoteData: any, shared: VerificationShared): any {
|
|
602
599
|
if (!context.config.verify_in_labels_match_pr || !context.hasTriage || !context.prNumber || !remoteData.prLabels) {
|
|
603
600
|
return null;
|
|
604
601
|
}
|
|
@@ -614,22 +611,22 @@ function checkInLabelsMatchPr(context: any, remoteData: any): any {
|
|
|
614
611
|
return null;
|
|
615
612
|
}
|
|
616
613
|
|
|
617
|
-
return failResult(CHECK_TYPE,
|
|
614
|
+
return shared.failResult(CHECK_TYPE,
|
|
618
615
|
`in: labels mismatch — PR #${context.prNumber} has [${formatLabelList(prInLabels)}], Issue #${context.issueNumber} has [${formatLabelList(issueInLabels)}]`,
|
|
619
616
|
"check_failed"
|
|
620
617
|
);
|
|
621
618
|
}
|
|
622
619
|
|
|
623
|
-
function checkInLabelsComputed(context: any, remoteData: any): any {
|
|
620
|
+
function checkInLabelsComputed(context: any, remoteData: any, shared: VerificationShared): any {
|
|
624
621
|
if (!context.config.verify_in_labels_computed || !context.hasTriage) {
|
|
625
622
|
return null;
|
|
626
623
|
}
|
|
627
624
|
|
|
628
|
-
const expectedInLabels = computeExpectedInLabels(context.taskDir, remoteData.repositoryLabels, remoteData.inLabelMapping);
|
|
625
|
+
const expectedInLabels = computeExpectedInLabels(context.taskDir, remoteData.repositoryLabels, remoteData.inLabelMapping, shared);
|
|
629
626
|
if (!expectedInLabels.ok) {
|
|
630
627
|
return expectedInLabels.type === "check_failed"
|
|
631
|
-
? failResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type)
|
|
632
|
-
: blockedResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type);
|
|
628
|
+
? shared.failResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type)
|
|
629
|
+
: shared.blockedResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type);
|
|
633
630
|
}
|
|
634
631
|
|
|
635
632
|
if (expectedInLabels.mode === "skipped") {
|
|
@@ -644,19 +641,19 @@ function checkInLabelsComputed(context: any, remoteData: any): any {
|
|
|
644
641
|
return null;
|
|
645
642
|
}
|
|
646
643
|
|
|
647
|
-
return failResult(
|
|
644
|
+
return shared.failResult(
|
|
648
645
|
CHECK_TYPE,
|
|
649
646
|
`Issue #${context.issueNumber} in: labels do not match committed changes: expected [${formatLabelList(expectedInLabels.labels)}], got [${formatLabelList(actualInLabels)}]`,
|
|
650
647
|
"check_failed"
|
|
651
648
|
);
|
|
652
649
|
}
|
|
653
650
|
|
|
654
|
-
function checkSyncedRequirements(context: any, remoteData: any): any {
|
|
651
|
+
function checkSyncedRequirements(context: any, remoteData: any, shared: VerificationShared): any {
|
|
655
652
|
if (!context.config.sync_checked_requirements || !context.hasTriage) {
|
|
656
653
|
return null;
|
|
657
654
|
}
|
|
658
655
|
|
|
659
|
-
const checkedRequirements = getCheckedRequirements(context.task.content);
|
|
656
|
+
const checkedRequirements = shared.getCheckedRequirements(context.task.content);
|
|
660
657
|
if (checkedRequirements.length === 0) {
|
|
661
658
|
return null;
|
|
662
659
|
}
|
|
@@ -664,13 +661,13 @@ function checkSyncedRequirements(context: any, remoteData: any): any {
|
|
|
664
661
|
const issueBody = remoteData.issue.body || "";
|
|
665
662
|
const resolution = resolveRequirementSection(
|
|
666
663
|
issueBody,
|
|
667
|
-
requirementSectionAnchors(repoRoot, context.task.metadata.type || "task")
|
|
664
|
+
requirementSectionAnchors(shared.repoRoot, context.task.metadata.type || "task")
|
|
668
665
|
);
|
|
669
666
|
if (resolution.status === "missing") {
|
|
670
667
|
return null;
|
|
671
668
|
}
|
|
672
669
|
if (resolution.status === "ambiguous") {
|
|
673
|
-
return failResult(CHECK_TYPE,
|
|
670
|
+
return shared.failResult(CHECK_TYPE,
|
|
674
671
|
`Issue #${context.issueNumber} requirements section is ambiguous`,
|
|
675
672
|
"check_failed"
|
|
676
673
|
);
|
|
@@ -683,13 +680,13 @@ function checkSyncedRequirements(context: any, remoteData: any): any {
|
|
|
683
680
|
return null;
|
|
684
681
|
}
|
|
685
682
|
|
|
686
|
-
return failResult(CHECK_TYPE,
|
|
683
|
+
return shared.failResult(CHECK_TYPE,
|
|
687
684
|
`Issue body is missing checked requirements: ${missingRequirements.join(", ")}`,
|
|
688
685
|
"check_failed"
|
|
689
686
|
);
|
|
690
687
|
}
|
|
691
688
|
|
|
692
|
-
function checkIssueType(context: any, remoteData: any): any {
|
|
689
|
+
function checkIssueType(context: any, remoteData: any, shared: VerificationShared): any {
|
|
693
690
|
if (!context.config.verify_issue_type || !context.hasPush) {
|
|
694
691
|
return null;
|
|
695
692
|
}
|
|
@@ -703,7 +700,7 @@ function checkIssueType(context: any, remoteData: any): any {
|
|
|
703
700
|
return null;
|
|
704
701
|
}
|
|
705
702
|
|
|
706
|
-
return failResult(CHECK_TYPE,
|
|
703
|
+
return shared.failResult(CHECK_TYPE,
|
|
707
704
|
`Issue #${context.issueNumber} has no Issue Type set`,
|
|
708
705
|
"check_failed"
|
|
709
706
|
);
|
|
@@ -711,7 +708,7 @@ function checkIssueType(context: any, remoteData: any): any {
|
|
|
711
708
|
|
|
712
709
|
const expectedType = mapTaskTypeToIssueType(context.task.metadata.type);
|
|
713
710
|
if (expectedType && remoteData.issueType !== expectedType) {
|
|
714
|
-
return failResult(CHECK_TYPE,
|
|
711
|
+
return shared.failResult(CHECK_TYPE,
|
|
715
712
|
`Issue #${context.issueNumber} has type '${remoteData.issueType}', expected '${expectedType}' (from task type '${context.task.metadata.type}')`,
|
|
716
713
|
"check_failed"
|
|
717
714
|
);
|
|
@@ -720,7 +717,7 @@ function checkIssueType(context: any, remoteData: any): any {
|
|
|
720
717
|
return null;
|
|
721
718
|
}
|
|
722
719
|
|
|
723
|
-
function checkIssueFields(context: any, remoteData: any): any {
|
|
720
|
+
function checkIssueFields(context: any, remoteData: any, shared: VerificationShared): any {
|
|
724
721
|
if (!context.config.verify_issue_fields || !context.hasPush) {
|
|
725
722
|
return null;
|
|
726
723
|
}
|
|
@@ -731,7 +728,7 @@ function checkIssueFields(context: any, remoteData: any): any {
|
|
|
731
728
|
|
|
732
729
|
for (const [metadataKey, fieldName] of Object.entries(FRONTMATTER_FIELD_MAP)) {
|
|
733
730
|
const expectedRaw = context.task.metadata[metadataKey];
|
|
734
|
-
if (isBlank(expectedRaw) || !remoteData.issueFields.pinnedNames.has(fieldName)) {
|
|
731
|
+
if (shared.isBlank(expectedRaw) || !remoteData.issueFields.pinnedNames.has(fieldName)) {
|
|
735
732
|
continue;
|
|
736
733
|
}
|
|
737
734
|
|
|
@@ -742,14 +739,14 @@ function checkIssueFields(context: any, remoteData: any): any {
|
|
|
742
739
|
}
|
|
743
740
|
|
|
744
741
|
if (!actual) {
|
|
745
|
-
return failResult(CHECK_TYPE,
|
|
742
|
+
return shared.failResult(CHECK_TYPE,
|
|
746
743
|
`Issue #${context.issueNumber} field '${fieldName}' is missing, expected '${expected.value}'`,
|
|
747
744
|
"check_failed"
|
|
748
745
|
);
|
|
749
746
|
}
|
|
750
747
|
|
|
751
748
|
if (actual.kind !== expected.kind || actual.value !== expected.value) {
|
|
752
|
-
return failResult(CHECK_TYPE,
|
|
749
|
+
return shared.failResult(CHECK_TYPE,
|
|
753
750
|
`Issue #${context.issueNumber} field '${fieldName}' is '${actual.value}', expected '${expected.value}'`,
|
|
754
751
|
"check_failed"
|
|
755
752
|
);
|
|
@@ -759,13 +756,13 @@ function checkIssueFields(context: any, remoteData: any): any {
|
|
|
759
756
|
return null;
|
|
760
757
|
}
|
|
761
758
|
|
|
762
|
-
function checkPrAssignee(context: any, remoteData: any): any {
|
|
759
|
+
function checkPrAssignee(context: any, remoteData: any, shared: VerificationShared): any {
|
|
763
760
|
if (!context.config.verify_pr_assignee || !context.hasPush || !context.prNumber) {
|
|
764
761
|
return null;
|
|
765
762
|
}
|
|
766
763
|
|
|
767
764
|
if (!remoteData.prAssignees || remoteData.prAssignees.length === 0) {
|
|
768
|
-
return failResult(CHECK_TYPE,
|
|
765
|
+
return shared.failResult(CHECK_TYPE,
|
|
769
766
|
`PR #${context.prNumber} has no assignee`,
|
|
770
767
|
"check_failed"
|
|
771
768
|
);
|
|
@@ -774,20 +771,20 @@ function checkPrAssignee(context: any, remoteData: any): any {
|
|
|
774
771
|
return null;
|
|
775
772
|
}
|
|
776
773
|
|
|
777
|
-
function checkMilestone(context: any, remoteData: any): any {
|
|
774
|
+
function checkMilestone(context: any, remoteData: any, shared: VerificationShared): any {
|
|
778
775
|
if (!context.config.verify_milestone || !context.hasTriage) {
|
|
779
776
|
return null;
|
|
780
777
|
}
|
|
781
778
|
|
|
782
779
|
if (!remoteData.issue?.milestone?.title) {
|
|
783
|
-
return failResult(CHECK_TYPE,
|
|
780
|
+
return shared.failResult(CHECK_TYPE,
|
|
784
781
|
`Issue #${context.issueNumber} has no milestone set`,
|
|
785
782
|
"check_failed"
|
|
786
783
|
);
|
|
787
784
|
}
|
|
788
785
|
|
|
789
786
|
if (context.prNumber && remoteData.prMilestone !== undefined && !remoteData.prMilestone?.title) {
|
|
790
|
-
return failResult(CHECK_TYPE,
|
|
787
|
+
return shared.failResult(CHECK_TYPE,
|
|
791
788
|
`PR #${context.prNumber} has no milestone set`,
|
|
792
789
|
"check_failed"
|
|
793
790
|
);
|
|
@@ -796,13 +793,13 @@ function checkMilestone(context: any, remoteData: any): any {
|
|
|
796
793
|
if (context.config.verify_milestone_specific) {
|
|
797
794
|
const issueTitle = remoteData.issue.milestone.title;
|
|
798
795
|
if (VERSION_LINE_REGEX.test(issueTitle)) {
|
|
799
|
-
return failResult(CHECK_TYPE,
|
|
796
|
+
return shared.failResult(CHECK_TYPE,
|
|
800
797
|
`Issue #${context.issueNumber} milestone '${issueTitle}' is a release line; narrow to a specific version (e.g. ${issueTitle.replace(/\.x$/, ".N")}) before continuing`,
|
|
801
798
|
"check_failed"
|
|
802
799
|
);
|
|
803
800
|
}
|
|
804
801
|
if (context.prNumber && remoteData.prMilestone?.title && VERSION_LINE_REGEX.test(remoteData.prMilestone.title)) {
|
|
805
|
-
return failResult(CHECK_TYPE,
|
|
802
|
+
return shared.failResult(CHECK_TYPE,
|
|
806
803
|
`PR #${context.prNumber} milestone '${remoteData.prMilestone.title}' is a release line; narrow to a specific version before continuing`,
|
|
807
804
|
"check_failed"
|
|
808
805
|
);
|
|
@@ -863,19 +860,20 @@ function extractCommentBody(commentBody: any): any {
|
|
|
863
860
|
return lines.slice(start, end).join("\n");
|
|
864
861
|
}
|
|
865
862
|
|
|
866
|
-
function buildExpectedTaskBody(taskContent: any): any {
|
|
863
|
+
function buildExpectedTaskBody(taskContent: any, shared: VerificationShared): any {
|
|
867
864
|
const frontmatterMatch = taskContent.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
|
868
865
|
if (!frontmatterMatch) {
|
|
869
|
-
return taskContent.trim();
|
|
866
|
+
return sanitizeCommentContent(taskContent.trim());
|
|
870
867
|
}
|
|
871
868
|
|
|
872
|
-
const body = taskContent.slice(frontmatterMatch[0].length).trim();
|
|
869
|
+
const body = sanitizeCommentContent(taskContent.slice(frontmatterMatch[0].length).trim());
|
|
870
|
+
if (body === null) {
|
|
871
|
+
return null;
|
|
872
|
+
}
|
|
873
873
|
return [
|
|
874
|
-
buildTaskFrontmatterSummary(),
|
|
874
|
+
buildTaskFrontmatterSummary(shared),
|
|
875
875
|
"",
|
|
876
|
-
"
|
|
877
|
-
frontmatterMatch[0].trim(),
|
|
878
|
-
"```",
|
|
876
|
+
renderSafeCodeFence(frontmatterMatch[0].trim(), "yaml"),
|
|
879
877
|
"",
|
|
880
878
|
"</details>",
|
|
881
879
|
"",
|
|
@@ -883,8 +881,8 @@ function buildExpectedTaskBody(taskContent: any): any {
|
|
|
883
881
|
].join("\n").trim();
|
|
884
882
|
}
|
|
885
883
|
|
|
886
|
-
function buildTaskFrontmatterSummary(): any {
|
|
887
|
-
const language = loadProjectLanguage();
|
|
884
|
+
function buildTaskFrontmatterSummary(shared: VerificationShared): any {
|
|
885
|
+
const language = loadProjectLanguage(shared);
|
|
888
886
|
if (language === "en" || language === "en-US") {
|
|
889
887
|
return "<details><summary>Metadata (frontmatter)</summary>";
|
|
890
888
|
}
|
|
@@ -892,13 +890,13 @@ function buildTaskFrontmatterSummary(): any {
|
|
|
892
890
|
return "<details><summary>元数据 (frontmatter)</summary>";
|
|
893
891
|
}
|
|
894
892
|
|
|
895
|
-
function loadProjectLanguage(): any {
|
|
893
|
+
function loadProjectLanguage(shared: VerificationShared): any {
|
|
896
894
|
const override = process.env.VALIDATE_ARTIFACT_LANGUAGE;
|
|
897
|
-
if (!isBlank(override)) {
|
|
895
|
+
if (!shared.isBlank(override)) {
|
|
898
896
|
return String(override).trim();
|
|
899
897
|
}
|
|
900
898
|
|
|
901
|
-
const configPath = path.join(repoRoot, ".agents", ".airc.json");
|
|
899
|
+
const configPath = path.join(shared.repoRoot, ".agents", ".airc.json");
|
|
902
900
|
if (!fs.existsSync(configPath)) {
|
|
903
901
|
return "";
|
|
904
902
|
}
|
|
@@ -1035,8 +1033,8 @@ function formatLabelList(labels: any): any {
|
|
|
1035
1033
|
return labels.length > 0 ? labels.join(", ") : "none";
|
|
1036
1034
|
}
|
|
1037
1035
|
|
|
1038
|
-
function computeExpectedInLabels(taskDir: any, repositoryLabels: string[]
|
|
1039
|
-
const task = loadTask(taskDir);
|
|
1036
|
+
function computeExpectedInLabels(taskDir: any, repositoryLabels: string[], mappingOverride: Record<string, string[]> | undefined, shared: VerificationShared): any {
|
|
1037
|
+
const task = shared.loadTask(taskDir);
|
|
1040
1038
|
if (!task.ok) {
|
|
1041
1039
|
return task;
|
|
1042
1040
|
}
|
|
@@ -1071,8 +1069,8 @@ function computeExpectedInLabels(taskDir: any, repositoryLabels: string[] = [],
|
|
|
1071
1069
|
return { ok: true, labels: planned.target, mode: "mapped" };
|
|
1072
1070
|
}
|
|
1073
1071
|
|
|
1074
|
-
function loadInLabelMapping(): any {
|
|
1075
|
-
const configPath = path.join(repoRoot, ".agents", ".airc.json");
|
|
1072
|
+
function loadInLabelMapping(shared: VerificationShared): any {
|
|
1073
|
+
const configPath = path.join(shared.repoRoot, ".agents", ".airc.json");
|
|
1076
1074
|
if (!fs.existsSync(configPath)) {
|
|
1077
1075
|
return { ok: true, value: {} };
|
|
1078
1076
|
}
|
|
@@ -1105,13 +1103,13 @@ function gitText(args: any, cwd: any): any {
|
|
|
1105
1103
|
}
|
|
1106
1104
|
|
|
1107
1105
|
function resolvePrHeadSha(context: any): any {
|
|
1108
|
-
const fallback = () =>
|
|
1106
|
+
const fallback = () => gitText(["rev-parse", "HEAD"], context.taskDir);
|
|
1109
1107
|
const branch = String(context.task?.metadata?.branch || "").trim();
|
|
1110
1108
|
if (!branch) {
|
|
1111
1109
|
return fallback();
|
|
1112
1110
|
}
|
|
1113
1111
|
|
|
1114
|
-
const worktreeList =
|
|
1112
|
+
const worktreeList = gitText(["worktree", "list", "--porcelain"], context.taskDir);
|
|
1115
1113
|
if (!worktreeList.ok) {
|
|
1116
1114
|
return fallback();
|
|
1117
1115
|
}
|
|
@@ -1121,7 +1119,7 @@ function resolvePrHeadSha(context: any): any {
|
|
|
1121
1119
|
return fallback();
|
|
1122
1120
|
}
|
|
1123
1121
|
|
|
1124
|
-
const headInWorktree =
|
|
1122
|
+
const headInWorktree = gitText(["rev-parse", "HEAD"], matchedWorktree);
|
|
1125
1123
|
if (!headInWorktree.ok) {
|
|
1126
1124
|
return fallback();
|
|
1127
1125
|
}
|
|
@@ -1149,10 +1147,6 @@ function findWorktreeForBranch(porcelainOutput: any, branch: any): any {
|
|
|
1149
1147
|
return null;
|
|
1150
1148
|
}
|
|
1151
1149
|
|
|
1152
|
-
function withRetry(operation: any): any {
|
|
1153
|
-
return operation();
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
1150
|
function interpolate(template: any, taskDir: any, artifactFile: any): any {
|
|
1157
1151
|
const artifactStem = artifactFile ? path.basename(artifactFile, path.extname(artifactFile)) : "";
|
|
1158
1152
|
return template
|