@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
package/lib/platform/issues.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { PlatformIssueSnapshot as IssueSnapshot } from './snapshots.ts';
|
|
2
|
+
import type { IssueFieldSchema } from './github-data.ts';
|
|
1
3
|
import fs from 'node:fs';
|
|
2
4
|
import path from 'node:path';
|
|
3
5
|
import { execFileSync } from 'node:child_process';
|
|
@@ -38,26 +40,7 @@ import {
|
|
|
38
40
|
import { resourceIdentityEquals, resourceIdentityNumber, resourceIdentityString, serializeResourceIdentity } from './resource-identity.ts';
|
|
39
41
|
import { taskIssueIdentity, taskIssueIdentityError } from './task-identities.ts';
|
|
40
42
|
import type { ResourceIdentity } from './resource-identity.ts';
|
|
41
|
-
|
|
42
|
-
type GitHubClient = PlatformClient;
|
|
43
43
|
import type { IssueSnapshot as ProviderIssueSnapshot, RepositoryMetadataSnapshot } from './provider-contract.ts';
|
|
44
|
-
|
|
45
|
-
type IssueSnapshot = {
|
|
46
|
-
repository: string;
|
|
47
|
-
number: number;
|
|
48
|
-
identity?: ResourceIdentity;
|
|
49
|
-
databaseId: number | null;
|
|
50
|
-
nodeId: string;
|
|
51
|
-
url: string;
|
|
52
|
-
state: 'open' | 'closed';
|
|
53
|
-
title: string;
|
|
54
|
-
body: string;
|
|
55
|
-
labels: string[];
|
|
56
|
-
assignees: string[];
|
|
57
|
-
milestone: string | null;
|
|
58
|
-
issueType: string | null;
|
|
59
|
-
fields: Record<string, string | number | null>;
|
|
60
|
-
};
|
|
61
44
|
type IssueResult = PlatformResult & {
|
|
62
45
|
task: { id: string | null; issueNumber: number | null };
|
|
63
46
|
issue: IssueSnapshot | null;
|
|
@@ -80,33 +63,6 @@ type SyncOptions = SharedOptions & {
|
|
|
80
63
|
dryRun?: boolean;
|
|
81
64
|
};
|
|
82
65
|
|
|
83
|
-
type RemoteIssue = {
|
|
84
|
-
number?: number;
|
|
85
|
-
id?: number;
|
|
86
|
-
node_id?: string;
|
|
87
|
-
html_url?: string;
|
|
88
|
-
state?: string;
|
|
89
|
-
title?: string;
|
|
90
|
-
body?: string | null;
|
|
91
|
-
labels?: Array<string | { name?: string }>;
|
|
92
|
-
assignees?: Array<{ login?: string }>;
|
|
93
|
-
milestone?: { title?: string } | null;
|
|
94
|
-
type?: { name?: string } | null;
|
|
95
|
-
pull_request?: unknown;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
type IssueFieldSchema = {
|
|
99
|
-
id: string;
|
|
100
|
-
name: string;
|
|
101
|
-
kind: 'single-select' | 'date' | 'text' | 'number';
|
|
102
|
-
options: Array<{ id: string; name: string }>;
|
|
103
|
-
};
|
|
104
|
-
type IssueTypeSchema = { id: string; name: string; fields: IssueFieldSchema[] };
|
|
105
|
-
type CurrentField = { id: string; name: string; kind: IssueFieldSchema['kind']; value: string | number | null };
|
|
106
|
-
|
|
107
|
-
const ISSUE_TYPES_QUERY = `query($owner:String!){organization(login:$owner){issueTypes(first:20){nodes{id name pinnedFields{__typename ... on IssueFieldSingleSelect{id name options{id name}} ... on IssueFieldDate{id name} ... on IssueFieldText{id name} ... on IssueFieldNumber{id name}}}}}}`;
|
|
108
|
-
const ISSUE_FIELDS_QUERY = `query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){issue(number:$number){id issueType{id name pinnedFields{__typename ... on IssueFieldSingleSelect{id name options{id name}} ... on IssueFieldDate{id name} ... on IssueFieldText{id name} ... on IssueFieldNumber{id name}}} issueFieldValues(first:50){nodes{__typename ... on IssueFieldSingleSelectValue{name optionId field{... on IssueFieldSingleSelect{id name}}} ... on IssueFieldDateValue{value field{... on IssueFieldDate{id name}}} ... on IssueFieldTextValue{value field{... on IssueFieldText{id name}}} ... on IssueFieldNumberValue{value field{... on IssueFieldNumber{id name}}}}}}}}`;
|
|
109
|
-
|
|
110
66
|
function result(
|
|
111
67
|
status: PlatformResult['status'],
|
|
112
68
|
taskId: string | null,
|
|
@@ -129,7 +85,7 @@ async function resolvedContext(taskRef: string, options: SharedOptions) {
|
|
|
129
85
|
const content = fs.readFileSync(resolved.taskMdPath, 'utf8');
|
|
130
86
|
const frontmatter = parseTaskFrontmatter(content);
|
|
131
87
|
let issueIdentity: ResourceIdentity | null;
|
|
132
|
-
try { issueIdentity = taskIssueIdentity(frontmatter
|
|
88
|
+
try { issueIdentity = taskIssueIdentity(frontmatter); }
|
|
133
89
|
catch (error) {
|
|
134
90
|
return { ok: false as const, output: result('failed', resolved.taskId, null, { error: { ...taskIssueIdentityError(error), retryable: false } }) };
|
|
135
91
|
}
|
|
@@ -235,118 +191,6 @@ async function inspectExternalIssue(
|
|
|
235
191
|
});
|
|
236
192
|
}
|
|
237
193
|
|
|
238
|
-
function normalizeIssue(remote: RemoteIssue, repository: string, fallbackNumber?: number): IssueSnapshot | null {
|
|
239
|
-
const number = Number.isInteger(remote.number) && Number(remote.number) > 0
|
|
240
|
-
? Number(remote.number)
|
|
241
|
-
: fallbackNumber;
|
|
242
|
-
if (!number || !Number.isSafeInteger(number) || remote.pull_request) return null;
|
|
243
|
-
return {
|
|
244
|
-
repository,
|
|
245
|
-
number,
|
|
246
|
-
databaseId: Number.isInteger(remote.id) ? Number(remote.id) : null,
|
|
247
|
-
nodeId: remote.node_id || `issue-${number}`,
|
|
248
|
-
url: remote.html_url || `https://github.com/${repository}/issues/${number}`,
|
|
249
|
-
state: String(remote.state || '').toLowerCase() === 'closed' ? 'closed' : 'open',
|
|
250
|
-
title: remote.title || '',
|
|
251
|
-
body: remote.body || '',
|
|
252
|
-
labels: (remote.labels || []).map((label) => typeof label === 'string' ? label : label.name || '').filter(Boolean).sort(),
|
|
253
|
-
assignees: (remote.assignees || []).map((assignee) => assignee.login || '').filter(Boolean).sort(),
|
|
254
|
-
milestone: remote.milestone?.title || null,
|
|
255
|
-
issueType: remote.type?.name || null,
|
|
256
|
-
fields: {}
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
function fieldKind(value: { __typename?: string }): IssueFieldSchema['kind'] | null {
|
|
261
|
-
if (value.__typename === 'IssueFieldSingleSelect' || value.__typename === 'IssueFieldSingleSelectValue') return 'single-select';
|
|
262
|
-
if (value.__typename === 'IssueFieldDate' || value.__typename === 'IssueFieldDateValue') return 'date';
|
|
263
|
-
if (value.__typename === 'IssueFieldText' || value.__typename === 'IssueFieldTextValue') return 'text';
|
|
264
|
-
if (value.__typename === 'IssueFieldNumber' || value.__typename === 'IssueFieldNumberValue') return 'number';
|
|
265
|
-
return null;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function normalizeFieldSchemas(value: unknown): IssueFieldSchema[] {
|
|
269
|
-
if (!Array.isArray(value)) return [];
|
|
270
|
-
return value.flatMap((raw) => {
|
|
271
|
-
const item = raw as { id?: string; name?: string; __typename?: string; options?: Array<{ id?: string; name?: string }> };
|
|
272
|
-
const kind = fieldKind(item);
|
|
273
|
-
return item.id && item.name && kind ? [{
|
|
274
|
-
id: item.id,
|
|
275
|
-
name: item.name,
|
|
276
|
-
kind,
|
|
277
|
-
options: (item.options || []).flatMap((option) => option.id && option.name ? [{ id: option.id, name: option.name }] : [])
|
|
278
|
-
}] : [];
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function normalizeIssueTypes(value: unknown): IssueTypeSchema[] {
|
|
283
|
-
const nodes = (value as { data?: { organization?: { issueTypes?: { nodes?: unknown[] } } } })?.data?.organization?.issueTypes?.nodes;
|
|
284
|
-
return (nodes || []).flatMap((raw) => {
|
|
285
|
-
const item = raw as { id?: string; name?: string; pinnedFields?: unknown[] };
|
|
286
|
-
return item.id && item.name ? [{ id: item.id, name: item.name, fields: normalizeFieldSchemas(item.pinnedFields) }] : [];
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function normalizeCurrentFields(value: unknown): { issueId: string | null; type: IssueTypeSchema | null; values: CurrentField[] } {
|
|
291
|
-
const issue = (value as { data?: { repository?: { issue?: {
|
|
292
|
-
id?: string;
|
|
293
|
-
issueType?: { id?: string; name?: string; pinnedFields?: unknown[] } | null;
|
|
294
|
-
issueFieldValues?: { nodes?: unknown[] };
|
|
295
|
-
} } } })?.data?.repository?.issue;
|
|
296
|
-
const type = issue?.issueType?.name ? {
|
|
297
|
-
id: issue.issueType.id || issue.issueType.name,
|
|
298
|
-
name: issue.issueType.name,
|
|
299
|
-
fields: normalizeFieldSchemas(issue.issueType.pinnedFields)
|
|
300
|
-
} : null;
|
|
301
|
-
const values = (issue?.issueFieldValues?.nodes || []).flatMap((raw) => {
|
|
302
|
-
const item = raw as { __typename?: string; name?: string; value?: string | number; field?: { id?: string; name?: string } };
|
|
303
|
-
const kind = fieldKind(item);
|
|
304
|
-
const value = kind === 'single-select' ? item.name : item.value;
|
|
305
|
-
return item.field?.name && kind && value !== undefined
|
|
306
|
-
? [{ id: item.field.id || item.field.name, name: item.field.name, kind, value: value ?? null }]
|
|
307
|
-
: [];
|
|
308
|
-
});
|
|
309
|
-
return { issueId: issue?.id || null, type, values };
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
function graphState(client: GitHubClient, repository: string, issue: number, cwd: string) {
|
|
313
|
-
const [owner, name] = repository.split('/');
|
|
314
|
-
if (!owner || !name) return null;
|
|
315
|
-
const current = client.json<unknown>([
|
|
316
|
-
'api', 'graphql', '-f', `query=${ISSUE_FIELDS_QUERY}`, '-F', `owner=${owner}`, '-F', `name=${name}`, '-F', `number=${issue}`
|
|
317
|
-
], { cwd });
|
|
318
|
-
if (!current.ok) return null;
|
|
319
|
-
return normalizeCurrentFields(current.value);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
function fetchIssue(client: GitHubClient, repository: string, issue: number, cwd: string) {
|
|
323
|
-
return client.json<RemoteIssue>(['api', `repos/${repository}/issues/${issue}`], { cwd });
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
function inspectGitHubIssue(client: GitHubClient, repository: string, issue: number, cwd: string) {
|
|
327
|
-
const fetched = fetchIssue(client, repository, issue, cwd);
|
|
328
|
-
if (!fetched.ok) return fetched;
|
|
329
|
-
const snapshot = normalizeIssue(fetched.value, repository, issue);
|
|
330
|
-
return snapshot
|
|
331
|
-
? { ok: true as const, value: snapshot }
|
|
332
|
-
: { ok: false as const, error: { code: 'ISSUE_IDENTITY_INVALID', message: 'Remote resource is not a valid Issue', retryable: false } };
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
function inspectGitHubIssueMetadata(client: GitHubClient, repository: string, issue: number, cwd: string) {
|
|
336
|
-
const fetched = fetchIssue(client, repository, issue, cwd);
|
|
337
|
-
if (!fetched.ok) return fetched;
|
|
338
|
-
const remote = fetched.value;
|
|
339
|
-
return {
|
|
340
|
-
ok: true as const,
|
|
341
|
-
value: {
|
|
342
|
-
state: String(remote.state || '').toLowerCase() === 'closed' ? 'closed' as const : 'open' as const,
|
|
343
|
-
labels: (remote.labels || []).map((label: string | { name?: string }) => typeof label === 'string' ? label : label.name || '').filter(Boolean).sort(),
|
|
344
|
-
body: remote.body || '',
|
|
345
|
-
milestone: remote.milestone?.title || null
|
|
346
|
-
}
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
|
|
350
194
|
async function inspectPlatformIssue(taskRef: string, options: SharedOptions = {}): Promise<IssueResult> {
|
|
351
195
|
const base = await resolvedContext(taskRef, options);
|
|
352
196
|
if (!base.ok) return base.output;
|
|
@@ -543,14 +387,6 @@ function requirementsFromTask(content: string): Requirement[] {
|
|
|
543
387
|
}));
|
|
544
388
|
}
|
|
545
389
|
|
|
546
|
-
function flattenPages(value: unknown): unknown[] {
|
|
547
|
-
return Array.isArray(value) ? value.flatMap((item) => Array.isArray(item) ? item : [item]) : [];
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
function listNames(value: unknown): string[] {
|
|
551
|
-
return flattenPages(value).map((item) => typeof item === 'string' ? item : String((item as { name?: string }).name || '')).filter(Boolean);
|
|
552
|
-
}
|
|
553
|
-
|
|
554
390
|
function milestoneBasis(repoRoot: string, current: string | null): string | null {
|
|
555
391
|
if (!current || !/^\d+\.\d+\.x$/.test(current)) return current;
|
|
556
392
|
try {
|
|
@@ -642,73 +478,6 @@ function desiredFieldValues(frontmatter: Record<string, string>, fields: IssueFi
|
|
|
642
478
|
return desired;
|
|
643
479
|
}
|
|
644
480
|
|
|
645
|
-
function planGraphMetadata(
|
|
646
|
-
client: GitHubClient,
|
|
647
|
-
repository: string,
|
|
648
|
-
issue: number,
|
|
649
|
-
cwd: string,
|
|
650
|
-
frontmatter: Record<string, string>,
|
|
651
|
-
options: Pick<SyncOptions, 'issueType' | 'fields'>,
|
|
652
|
-
capabilities: PlatformResult['capabilities']
|
|
653
|
-
): { operations: PlannedOperation[]; issueId: string | null } {
|
|
654
|
-
if (!options.issueType && !options.fields) return { operations: [], issueId: null };
|
|
655
|
-
if (!capabilities.push) return {
|
|
656
|
-
operations: [
|
|
657
|
-
...(options.issueType ? [{ name: 'issue-type', status: 'skipped' as const, reasonCode: 'PUSH_REQUIRED' }] : []),
|
|
658
|
-
...(options.fields ? [{ name: 'fields', status: 'skipped' as const, reasonCode: 'PUSH_REQUIRED' }] : [])
|
|
659
|
-
], issueId: null
|
|
660
|
-
};
|
|
661
|
-
const [owner] = repository.split('/');
|
|
662
|
-
const typesResult = client.json<unknown>(['api', 'graphql', '-f', `query=${ISSUE_TYPES_QUERY}`, '-F', `owner=${owner}`], { cwd });
|
|
663
|
-
if (!typesResult.ok) return { operations: [{ name: 'issue-schema', status: 'failed', reasonCode: typesResult.error.code }], issueId: null };
|
|
664
|
-
const types = normalizeIssueTypes(typesResult.value);
|
|
665
|
-
if (types.length === 0) return {
|
|
666
|
-
operations: [
|
|
667
|
-
...(options.issueType ? [{ name: 'issue-type', status: 'skipped' as const, reasonCode: 'ISSUE_TYPES_UNSUPPORTED' }] : []),
|
|
668
|
-
...(options.fields ? [{ name: 'fields', status: 'skipped' as const, reasonCode: 'ISSUE_TYPES_UNSUPPORTED' }] : [])
|
|
669
|
-
], issueId: null
|
|
670
|
-
};
|
|
671
|
-
const current = graphState(client, repository, issue, cwd);
|
|
672
|
-
if (!current?.issueId) return { operations: [{ name: 'issue-schema', status: 'failed', reasonCode: 'ISSUE_GRAPH_IDENTITY_INVALID' }], issueId: null };
|
|
673
|
-
const target = types.find((type) => type.name === desiredIssueType(frontmatter.type || ''));
|
|
674
|
-
if (!target) return { operations: [{ name: 'issue-type', status: 'failed', reasonCode: 'ISSUE_TYPE_NOT_FOUND' }], issueId: current.issueId };
|
|
675
|
-
const operations: PlannedOperation[] = [];
|
|
676
|
-
if (options.issueType) operations.push(current.type?.id === target.id
|
|
677
|
-
? { name: 'issue-type', status: 'no-op', reasonCode: null }
|
|
678
|
-
: { name: 'issue-type', status: 'planned', reasonCode: null, value: { issueTypeId: target.id } });
|
|
679
|
-
if (options.fields) {
|
|
680
|
-
const desired = desiredFieldValues(frontmatter, target.fields);
|
|
681
|
-
const inputs = desired.filter((field) => current.values.find((value) => value.name === field.name)?.value !== field.value).map((field) => field.input);
|
|
682
|
-
if (current.type?.id !== target.id) {
|
|
683
|
-
const targetNames = new Set(target.fields.map((field) => field.name));
|
|
684
|
-
for (const old of current.values) if (!targetNames.has(old.name)) inputs.push({ fieldId: old.id, delete: true });
|
|
685
|
-
}
|
|
686
|
-
operations.push(inputs.length === 0
|
|
687
|
-
? { name: 'fields', status: 'no-op', reasonCode: null }
|
|
688
|
-
: { name: 'fields', status: 'planned', reasonCode: null, value: inputs });
|
|
689
|
-
}
|
|
690
|
-
return { operations, issueId: current.issueId };
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
function executeGraphOperation(
|
|
694
|
-
client: GitHubClient,
|
|
695
|
-
cwd: string,
|
|
696
|
-
issueId: string,
|
|
697
|
-
operation: PlannedOperation
|
|
698
|
-
) {
|
|
699
|
-
if (operation.name === 'issue-type') {
|
|
700
|
-
const query = 'mutation($issueId:ID!,$issueTypeId:ID){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$issueTypeId}){issue{id}}}';
|
|
701
|
-
const typeId = (operation.value as { issueTypeId: string }).issueTypeId;
|
|
702
|
-
return client.json(['api', 'graphql', '--input', '-'], {
|
|
703
|
-
cwd, method: 'POST', input: JSON.stringify({ query, variables: { issueId, issueTypeId: typeId } })
|
|
704
|
-
});
|
|
705
|
-
}
|
|
706
|
-
const query = 'mutation($issueId:ID!,$issueFields:[IssueFieldCreateOrUpdateInput!]!){setIssueFieldValue(input:{issueId:$issueId,issueFields:$issueFields}){issue{id}}}';
|
|
707
|
-
return client.json(['api', 'graphql', '--input', '-'], {
|
|
708
|
-
cwd, method: 'POST', input: JSON.stringify({ query, variables: { issueId, issueFields: operation.value } })
|
|
709
|
-
});
|
|
710
|
-
}
|
|
711
|
-
|
|
712
481
|
async function syncPlatformIssue(taskRef: string, options: SyncOptions): Promise<IssueResult> {
|
|
713
482
|
const base = await resolvedContext(taskRef, options);
|
|
714
483
|
if (!base.ok) return base.output;
|
|
@@ -849,15 +618,5 @@ async function syncPlatformIssue(taskRef: string, options: SyncOptions): Promise
|
|
|
849
618
|
});
|
|
850
619
|
}
|
|
851
620
|
|
|
852
|
-
export {
|
|
853
|
-
|
|
854
|
-
createPlatformIssue,
|
|
855
|
-
graphState,
|
|
856
|
-
inspectGitHubIssue,
|
|
857
|
-
inspectGitHubIssueMetadata,
|
|
858
|
-
inspectPlatformIssue,
|
|
859
|
-
normalizeIssue,
|
|
860
|
-
requirementSectionAnchors,
|
|
861
|
-
syncPlatformIssue
|
|
862
|
-
};
|
|
863
|
-
export type { BindOptions, CreateOptions, IssueResult, IssueSnapshot, SyncOptions };
|
|
621
|
+
export { bindPlatformIssue, createPlatformIssue, inspectPlatformIssue, requirementSectionAnchors, syncPlatformIssue };
|
|
622
|
+
export type { BindOptions, CreateOptions, IssueResult, SyncOptions };
|
|
@@ -3,9 +3,11 @@ 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.ts';
|
|
6
|
+
import { isResourceIdentity } from './resource-identity.ts';
|
|
7
|
+
import type { ResourceIdentity } from './resource-identity.ts';
|
|
6
8
|
|
|
7
9
|
const REPORT_FILE_NAME = 'pr-change-report.json';
|
|
8
|
-
const REPORT_VERSION =
|
|
10
|
+
const REPORT_VERSION = 2 as const;
|
|
9
11
|
const CANONICAL_REPORT_PLACEHOLDER = '<!-- canonical-pr-change-report -->';
|
|
10
12
|
const CANONICAL_REPORT_HEADING = '### PR 代码增减';
|
|
11
13
|
const PRECHECK_IDS = [
|
|
@@ -83,7 +85,7 @@ type PrecheckCandidate = {
|
|
|
83
85
|
|
|
84
86
|
type PullRequestIdentity = {
|
|
85
87
|
repository: string;
|
|
86
|
-
|
|
88
|
+
resource: ResourceIdentity;
|
|
87
89
|
base: { repository: string; ref: string; sha: string };
|
|
88
90
|
head: { repository: string; ref: string; sha: string };
|
|
89
91
|
};
|
|
@@ -279,8 +281,8 @@ function validatePrChangeReport(value: unknown): ValidationResult<PrChangeReport
|
|
|
279
281
|
}
|
|
280
282
|
const identity = value.identity;
|
|
281
283
|
const identityRepository = identity.repository;
|
|
282
|
-
const
|
|
283
|
-
if (!isNonEmptyString(identityRepository) ||
|
|
284
|
+
const identityResource = identity.resource;
|
|
285
|
+
if (!isNonEmptyString(identityRepository) || !isResourceIdentity(identityResource)) return invalid('change report identity is invalid');
|
|
284
286
|
const parseIdentityPart = (part: unknown, name: string): ValidationResult<{ repository: string; ref: string; sha: string }> => {
|
|
285
287
|
if (!isRecord(part) || !isNonEmptyString(part.repository) || !isNonEmptyString(part.ref) || !isSha(part.sha)) return invalid(`change report identity.${name} is invalid`);
|
|
286
288
|
return { ok: true, value: { repository: part.repository, ref: part.ref, sha: part.sha } };
|
|
@@ -315,7 +317,7 @@ function validatePrChangeReport(value: unknown): ValidationResult<PrChangeReport
|
|
|
315
317
|
version: REPORT_VERSION,
|
|
316
318
|
identity: {
|
|
317
319
|
repository: identityRepository,
|
|
318
|
-
|
|
320
|
+
resource: identityResource,
|
|
319
321
|
base: base.value,
|
|
320
322
|
head: head.value
|
|
321
323
|
},
|
|
@@ -2,7 +2,8 @@ import fs from 'node:fs';
|
|
|
2
2
|
|
|
3
3
|
import { parseTypedTaskFrontmatter } from '../task/frontmatter.ts';
|
|
4
4
|
import { resolveTaskRef } from '../task/resolve-ref.ts';
|
|
5
|
-
import type { PlatformCheckSnapshot } from './
|
|
5
|
+
import type { PlatformCheckSnapshot } from './snapshots.ts';
|
|
6
|
+
import { checkStatusBucket } from './check-status.ts';
|
|
6
7
|
import { resolvePlatformProviderContext } from './context.ts';
|
|
7
8
|
import type { PlatformClient } from './context.ts';
|
|
8
9
|
import { inspectPlatformPullRequest } from './pull-requests.ts';
|
|
@@ -33,7 +34,6 @@ type ChecksResult = PlatformResult & {
|
|
|
33
34
|
resolution?: { status: 'resolved' | 'missing' | 'ambiguous'; runId: number | null; jobId: number | null };
|
|
34
35
|
logs?: { runId: number; jobId?: number; text: string };
|
|
35
36
|
};
|
|
36
|
-
type GitHubClient = PlatformClient;
|
|
37
37
|
type InspectionOptions = { cwd?: string; client?: PlatformClient; runtimeVersion?: string };
|
|
38
38
|
type SharedOptions = { cwd?: string; client?: PlatformClient };
|
|
39
39
|
|
|
@@ -56,18 +56,6 @@ function classifyPullRequestReadiness(input: {
|
|
|
56
56
|
return { state: 'ready', headSha: input.headSha };
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
function parseRunJobIdentity(detailsUrl: string): { runId: number; jobId: number | null } | null {
|
|
60
|
-
try {
|
|
61
|
-
const url = new URL(detailsUrl);
|
|
62
|
-
if (url.hostname !== 'github.com') return null;
|
|
63
|
-
const match = url.pathname.match(/\/actions\/runs\/(\d+)(?:\/job\/(\d+))?/);
|
|
64
|
-
if (!match) return null;
|
|
65
|
-
return { runId: Number(match[1]), jobId: match[2] ? Number(match[2]) : null };
|
|
66
|
-
} catch {
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
59
|
function resolveRunCandidate(candidates: RunCandidate[], headSha: string, checkName: string):
|
|
72
60
|
| { status: 'resolved'; runId: number; jobId: number | null }
|
|
73
61
|
| { status: 'missing' | 'ambiguous'; runId: null; jobId: null } {
|
|
@@ -85,41 +73,6 @@ function checksResult(status: PlatformResult['status'], overrides: Partial<Check
|
|
|
85
73
|
};
|
|
86
74
|
}
|
|
87
75
|
|
|
88
|
-
function normalizeBucket(value: { bucket?: string; status?: string; state?: string; conclusion?: string }): CheckBucket {
|
|
89
|
-
const raw = String(value.bucket || value.status || value.conclusion || value.state || '').toLowerCase();
|
|
90
|
-
if (['pass', 'success', 'successful', 'neutral'].includes(raw)) return 'pass';
|
|
91
|
-
if (['fail', 'failure', 'failed', 'error', 'timed_out', 'action_required'].includes(raw)) return 'fail';
|
|
92
|
-
if (['cancel', 'cancelled', 'canceled', 'skipped', 'stale'].includes(raw)) return 'cancel';
|
|
93
|
-
return 'pending';
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function normalizeChecks(value: unknown): CheckSnapshot[] {
|
|
97
|
-
if (!Array.isArray(value)) return [];
|
|
98
|
-
return value.flatMap((raw) => {
|
|
99
|
-
const item = raw as Record<string, unknown>;
|
|
100
|
-
const name = String(item.name || item.context || '');
|
|
101
|
-
return name ? [{
|
|
102
|
-
name,
|
|
103
|
-
bucket: normalizeBucket(item as { bucket?: string; state?: string; conclusion?: string }),
|
|
104
|
-
workflow: item.workflow ? String(item.workflow) : null,
|
|
105
|
-
conclusion: item.conclusion ? String(item.conclusion) : item.state ? String(item.state) : null,
|
|
106
|
-
detailsUrl: item.link ? String(item.link) : item.detailsUrl ? String(item.detailsUrl) : null,
|
|
107
|
-
startedAt: item.startedAt ? String(item.startedAt) : null,
|
|
108
|
-
completedAt: item.completedAt ? String(item.completedAt) : null
|
|
109
|
-
}] : [];
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function inspectGitHubRequiredChecks(client: GitHubClient, repository: string, number: number, cwd: string) {
|
|
114
|
-
const inspected = client.json<unknown>([
|
|
115
|
-
'pr', 'checks', String(number), '--repo', repository,
|
|
116
|
-
'--json', 'name,state,bucket,link,workflow,startedAt,completedAt'
|
|
117
|
-
], { cwd });
|
|
118
|
-
return inspected.ok
|
|
119
|
-
? { ok: true as const, value: normalizeChecks(inspected.value) }
|
|
120
|
-
: { ok: false as const, error: inspected.error };
|
|
121
|
-
}
|
|
122
|
-
|
|
123
76
|
async function resolvedTask(taskRef: string, options: InspectionOptions) {
|
|
124
77
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
125
78
|
if (!resolved.ok) return { ok: false as const, output: checksResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } }) };
|
|
@@ -141,14 +94,12 @@ async function resolvedTask(taskRef: string, options: InspectionOptions) {
|
|
|
141
94
|
async function inspectRequiredChecks(taskRef: string, options: InspectionOptions = {}): Promise<ChecksResult> {
|
|
142
95
|
const base = await resolvedTask(taskRef, options);
|
|
143
96
|
if (!base.ok) return base.output;
|
|
144
|
-
return inspectChecksForResolvedTask(base
|
|
97
|
+
return inspectChecksForResolvedTask(base);
|
|
145
98
|
}
|
|
146
99
|
|
|
147
100
|
async function inspectChecksForResolvedTask(
|
|
148
|
-
base: Extract<Awaited<ReturnType<typeof resolvedTask>>, { ok: true }
|
|
149
|
-
options: InspectionOptions
|
|
101
|
+
base: Extract<Awaited<ReturnType<typeof resolvedTask>>, { ok: true }>
|
|
150
102
|
): Promise<ChecksResult> {
|
|
151
|
-
const repository = base.context.platform.repository!;
|
|
152
103
|
{
|
|
153
104
|
const inspected = base.provider.checks?.inspectRequired
|
|
154
105
|
? await base.provider.checks.inspectRequired({
|
|
@@ -164,7 +115,13 @@ async function inspectChecksForResolvedTask(
|
|
|
164
115
|
pullRequest: base.pullRequest,
|
|
165
116
|
error: providerError(inspected.error, 'PLATFORM_PROVIDER_OPERATION_FAILED')
|
|
166
117
|
});
|
|
167
|
-
const required =
|
|
118
|
+
const required = inspected.value.map((check): CheckSnapshot => ({
|
|
119
|
+
name: check.name,
|
|
120
|
+
bucket: checkStatusBucket(check.status),
|
|
121
|
+
conclusion: check.conclusion || null,
|
|
122
|
+
detailsUrl: check.detailsUrl || null,
|
|
123
|
+
workflow: null, startedAt: null, completedAt: null
|
|
124
|
+
}));
|
|
168
125
|
const classified = classifyRequiredChecks(required);
|
|
169
126
|
const status = classified.state === 'passed' || classified.state === 'no-required'
|
|
170
127
|
? 'no-op'
|
|
@@ -184,7 +141,7 @@ async function inspectChecksForResolvedTask(
|
|
|
184
141
|
async function inspectPullRequestReadiness(taskRef: string, options: InspectionOptions = {}): Promise<ChecksResult> {
|
|
185
142
|
const base = await resolvedTask(taskRef, options);
|
|
186
143
|
if (!base.ok) return base.output;
|
|
187
|
-
const checked = await inspectChecksForResolvedTask(base
|
|
144
|
+
const checked = await inspectChecksForResolvedTask(base);
|
|
188
145
|
const classifiedCodes = new Set(['REQUIRED_CHECKS_PENDING', 'REQUIRED_CHECKS_FAILED', 'REQUIRED_CHECKS_CANCELLED']);
|
|
189
146
|
if (checked.error && !classifiedCodes.has(checked.error.code)) return checked;
|
|
190
147
|
const readiness = classifyPullRequestReadiness({
|
|
@@ -271,15 +228,6 @@ async function resolvePlatformCheckRun(taskRef: string, options: SharedOptions &
|
|
|
271
228
|
}
|
|
272
229
|
}
|
|
273
230
|
|
|
274
|
-
function fetchCheckLogText(client: GitHubClient, args: string[], cwd: string) {
|
|
275
|
-
if (!client.text) return { ok: false as const, error: { code: 'PLATFORM_CLIENT_TEXT_UNAVAILABLE', message: 'Platform client does not support text responses', retryable: false } };
|
|
276
|
-
const fetched = client.text(args, { cwd });
|
|
277
|
-
if (fetched.ok || args[0] !== 'api' || !/response contains terminal escape sequences/i.test(fetched.error.message)) {
|
|
278
|
-
return fetched;
|
|
279
|
-
}
|
|
280
|
-
return client.text([...args, '--allow-escape-sequences'], { cwd });
|
|
281
|
-
}
|
|
282
|
-
|
|
283
231
|
async function fetchPlatformCheckLogs(taskRef: string, options: SharedOptions & { run: number; job?: number }): Promise<ChecksResult> {
|
|
284
232
|
const base = await resolvedTask(taskRef, options);
|
|
285
233
|
if (!base.ok) return base.output;
|
|
@@ -308,17 +256,5 @@ async function fetchPlatformCheckLogs(taskRef: string, options: SharedOptions &
|
|
|
308
256
|
}
|
|
309
257
|
}
|
|
310
258
|
|
|
311
|
-
export {
|
|
312
|
-
classifyPullRequestReadiness,
|
|
313
|
-
classifyRequiredChecks,
|
|
314
|
-
fetchCheckLogText,
|
|
315
|
-
fetchPlatformCheckLogs,
|
|
316
|
-
inspectGitHubRequiredChecks,
|
|
317
|
-
inspectRequiredChecks,
|
|
318
|
-
inspectPullRequestReadiness,
|
|
319
|
-
parseRunJobIdentity,
|
|
320
|
-
resolvePlatformCheckRun,
|
|
321
|
-
resolveRunCandidate,
|
|
322
|
-
watchPullRequestReadiness
|
|
323
|
-
};
|
|
259
|
+
export { classifyPullRequestReadiness, classifyRequiredChecks, fetchPlatformCheckLogs, inspectRequiredChecks, inspectPullRequestReadiness, resolvePlatformCheckRun, resolveRunCandidate, watchPullRequestReadiness };
|
|
324
260
|
export type { CheckBucket, CheckSnapshot, ChecksResult, ChecksSnapshot, CheckState, ReadinessSnapshot, ReadinessState, RunCandidate };
|