@fitlab-ai/agent-infra 0.9.14 → 0.9.15
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 +3 -2
- package/dist/lib/defaults.json +103 -103
- package/dist/lib/fs/durable-write.js +37 -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 +3 -1
- 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 +322 -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 +15 -262
- package/dist/lib/internal/task-create.js +6 -5
- package/dist/lib/internal/task-event.js +37 -37
- package/dist/lib/internal/task-operation-registry.js +101 -3
- package/dist/lib/internal/task-review.js +8 -53
- 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 +2 -2
- package/dist/lib/platform/issues.js +1 -179
- package/dist/lib/platform/pr-checks.js +12 -65
- package/dist/lib/platform/pr-summary.js +55 -3
- package/dist/lib/platform/pull-requests.js +2 -105
- package/dist/lib/platform/snapshots.js +2 -0
- package/dist/lib/platform/verification-sync.js +127 -142
- package/dist/lib/release/workflow.js +1 -1
- package/dist/lib/sandbox/commands/create.js +7 -2
- package/dist/lib/sandbox/commands/rm.js +3 -1514
- 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 +491 -120
- package/dist/lib/sandbox/control/state.js +58 -0
- package/dist/lib/sandbox/control/task-workflow.js +74 -0
- package/dist/lib/sandbox/control/workflow-executor.js +99 -0
- package/dist/lib/sandbox/index.js +2 -2
- package/dist/lib/sandbox/recovery.js +28 -4
- package/dist/lib/sandbox/removal.js +1717 -0
- package/dist/lib/sandbox/task-cleanup.js +217 -0
- 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 +101 -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 +23 -69
- package/dist/lib/task/artifact-receipts.js +3 -15
- package/dist/lib/task/artifact-repair-intent.js +87 -16
- 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 +2 -16
- package/dist/lib/task/control-authority.js +371 -5
- package/dist/lib/task/control-recovery.js +128 -0
- package/dist/lib/task/create.js +62 -9
- package/dist/lib/task/decision-details.js +2 -46
- package/dist/lib/task/events.js +120 -9
- package/dist/lib/task/finalization-state.js +9 -0
- package/dist/lib/task/human-override.js +3 -6
- package/dist/lib/task/implementation-inputs.js +3 -3
- package/dist/lib/task/intermediate-cleanup.js +383 -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.js +19 -1
- package/dist/lib/task/local-artifact-finalization.js +132 -157
- 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 +101 -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 +14 -17
- package/dist/lib/task/qualification-audit.js +20 -34
- package/dist/lib/task/review-artifacts.js +2 -18
- package/dist/lib/task/review-command.js +25 -0
- package/dist/lib/task/review-finalization.js +125 -193
- package/dist/lib/task/review-fingerprint.js +2 -2
- package/dist/lib/task/sections.js +34 -56
- package/dist/lib/task/verification-engine.js +116 -323
- package/dist/lib/task/verification.js +1 -1
- package/dist/lib/task/workflow-command.js +17 -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/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 +3 -2
- package/lib/fs/durable-write.ts +29 -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 +3 -1
- 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 +306 -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 +13 -216
- package/lib/internal/task-create.ts +5 -5
- package/lib/internal/task-event.ts +20 -11
- package/lib/internal/task-operation-registry.ts +111 -3
- package/lib/internal/task-review.ts +6 -51
- 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 +3 -4
- package/lib/platform/issues.ts +4 -245
- package/lib/platform/pr-checks.ts +13 -77
- package/lib/platform/pr-summary.ts +61 -5
- package/lib/platform/pull-requests.ts +3 -170
- package/lib/platform/snapshots.ts +53 -0
- package/lib/platform/verification-sync.ts +145 -155
- package/lib/release/workflow.ts +3 -3
- package/lib/sandbox/commands/create.ts +7 -6
- package/lib/sandbox/commands/rm.ts +3 -1909
- 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 +75 -6
- package/lib/sandbox/control/server.ts +538 -123
- package/lib/sandbox/control/state.ts +78 -0
- package/lib/sandbox/control/task-workflow.ts +95 -0
- package/lib/sandbox/control/workflow-executor.ts +102 -0
- package/lib/sandbox/index.ts +2 -2
- package/lib/sandbox/recovery.ts +28 -5
- package/lib/sandbox/removal.ts +2144 -0
- package/lib/sandbox/task-cleanup.ts +209 -0
- 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 +104 -0
- package/lib/task/artifact-lifecycle.ts +31 -26
- package/lib/task/artifact-name.ts +55 -0
- package/lib/task/artifact-operations.ts +22 -68
- package/lib/task/artifact-receipts.ts +3 -14
- package/lib/task/artifact-repair-intent.ts +99 -18
- 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 +2 -16
- package/lib/task/control-authority.ts +502 -5
- package/lib/task/control-recovery.ts +174 -0
- package/lib/task/create.ts +63 -8
- package/lib/task/decision-details.ts +3 -71
- package/lib/task/events.ts +131 -10
- package/lib/task/finalization-state.ts +11 -0
- package/lib/task/human-override.ts +3 -8
- package/lib/task/implementation-inputs.ts +3 -3
- package/lib/task/intermediate-cleanup.ts +455 -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.ts +17 -1
- package/lib/task/local-artifact-finalization.ts +148 -182
- 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 +152 -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 +19 -19
- package/lib/task/qualification-audit.ts +22 -33
- package/lib/task/review-artifacts.ts +1 -20
- package/lib/task/review-command.ts +23 -0
- package/lib/task/review-finalization.ts +131 -259
- package/lib/task/review-fingerprint.ts +2 -2
- package/lib/task/sections.ts +33 -54
- package/lib/task/verification-engine.ts +110 -366
- package/lib/task/verification-types.ts +17 -0
- package/lib/task/verification.ts +1 -1
- package/lib/task/workflow-command.ts +18 -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/package.json +6 -6
- package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
- 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/complete-manual-validation/SKILL.en.md +32 -20
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +32 -20
- 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 +1 -1
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +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/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/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/.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 { ISSUE_FIELDS_QUERY, graphState, inspectGitHubIssue, inspectGitHubPullRequest, inspectGitHubIssueClosingChangeRequests, inspectGitHubRequiredChecks, parseRunJobIdentity, fetchCheckLogText } from './github-data.js';
|
|
1
2
|
import { execFileSync } from 'node:child_process';
|
|
2
3
|
import fs from 'node:fs';
|
|
3
4
|
import os from 'node:os';
|
|
@@ -8,7 +9,6 @@ import { resourceIdentityNumber, resourceIdentityString } from './resource-ident
|
|
|
8
9
|
import { extractPullRequestFileNames, syncLabelDelta } from './in-label-sync.js';
|
|
9
10
|
const CURRENT_USER_QUERY = 'query { viewer { login } }';
|
|
10
11
|
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}}}}}}`;
|
|
11
|
-
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}}}}}}}}`;
|
|
12
12
|
const CLOSING_ISSUES_QUERY = 'query($owner:String!,$name:String!,$number:Int!,$cursor:String){repository(owner:$owner,name:$name){pullRequest(number:$number){closingIssuesReferences(first:100,after:$cursor){nodes{number} pageInfo{hasNextPage endCursor}}}}}';
|
|
13
13
|
function parseGitHubRemote(remote) {
|
|
14
14
|
const trimmed = remote.trim().replace(/\.git$/, '');
|
|
@@ -399,11 +399,10 @@ function createGitHubOperations(client) {
|
|
|
399
399
|
const number = resourceIdentityNumber(target);
|
|
400
400
|
if (!number)
|
|
401
401
|
return invalid('ISSUE_NUMBER_INVALID', 'Issue number must be positive');
|
|
402
|
-
const
|
|
403
|
-
const fetched = module.inspectGitHubIssue(client, repository(context), number, context.workingDirectory);
|
|
402
|
+
const fetched = inspectGitHubIssue(client, repository(context), number, context.workingDirectory);
|
|
404
403
|
if (!fetched.ok)
|
|
405
404
|
return fetched;
|
|
406
|
-
const graph =
|
|
405
|
+
const graph = graphState(client, repository(context), number, context.workingDirectory);
|
|
407
406
|
return { ok: true, value: issueSnapshot(fetched.value, graph || undefined) };
|
|
408
407
|
},
|
|
409
408
|
async create({ context, desired }) {
|
|
@@ -606,8 +605,7 @@ function createGitHubOperations(client) {
|
|
|
606
605
|
const number = resourceIdentityNumber(target);
|
|
607
606
|
if (!number)
|
|
608
607
|
return invalid('PR_NUMBER_INVALID', 'Pull request number must be positive');
|
|
609
|
-
const
|
|
610
|
-
const fetched = module.inspectGitHubPullRequest(client, repository(context), number, context.workingDirectory);
|
|
608
|
+
const fetched = inspectGitHubPullRequest(client, repository(context), number, context.workingDirectory);
|
|
611
609
|
if (!fetched.ok)
|
|
612
610
|
return fetched;
|
|
613
611
|
return { ok: true, value: changeRequestSnapshot(fetched.value) };
|
|
@@ -671,8 +669,7 @@ function createGitHubOperations(client) {
|
|
|
671
669
|
const number = resourceIdentityNumber(issue);
|
|
672
670
|
if (!number)
|
|
673
671
|
return invalid('ISSUE_NUMBER_INVALID', 'Issue number must be positive');
|
|
674
|
-
const
|
|
675
|
-
const fetched = module.inspectGitHubIssueClosingChangeRequests(client, repository(context), number, context.workingDirectory);
|
|
672
|
+
const fetched = inspectGitHubIssueClosingChangeRequests(client, repository(context), number, context.workingDirectory);
|
|
676
673
|
if (!fetched.ok)
|
|
677
674
|
return fetched;
|
|
678
675
|
return { ok: true, value: fetched.value.map(changeRequestSnapshot) };
|
|
@@ -756,8 +753,7 @@ function createGitHubOperations(client) {
|
|
|
756
753
|
const number = resourceIdentityNumber(target);
|
|
757
754
|
if (!number)
|
|
758
755
|
return invalid('PR_NUMBER_INVALID', 'Pull request number must be positive');
|
|
759
|
-
|
|
760
|
-
return module.resolveGitHubChangeRequestGitEvidence({
|
|
756
|
+
return resolveGitHubChangeRequestGitEvidence({
|
|
761
757
|
cwd: context.workingDirectory,
|
|
762
758
|
repository: repository(context),
|
|
763
759
|
number,
|
|
@@ -771,18 +767,13 @@ function createGitHubOperations(client) {
|
|
|
771
767
|
const number = resourceIdentityNumber(changeRequest);
|
|
772
768
|
if (!number)
|
|
773
769
|
return invalid('PR_NUMBER_INVALID', 'Pull request number must be positive');
|
|
774
|
-
|
|
775
|
-
const fetched = module.inspectGitHubRequiredChecks(client, repository(context), number, context.workingDirectory);
|
|
776
|
-
if (!fetched.ok)
|
|
777
|
-
return fetched;
|
|
778
|
-
return { ok: true, value: fetched.value.map((check) => ({ name: check.name, status: check.bucket, conclusion: check.conclusion, detailsUrl: check.detailsUrl })) };
|
|
770
|
+
return inspectGitHubRequiredChecks(client, repository(context), number, context.workingDirectory);
|
|
779
771
|
},
|
|
780
772
|
async resolveRun({ context, changeRequest, checkName, detailsUrl }) {
|
|
781
773
|
const number = resourceIdentityNumber(changeRequest);
|
|
782
774
|
if (!number)
|
|
783
775
|
return invalid('PR_NUMBER_INVALID', 'Pull request number must be positive');
|
|
784
|
-
const
|
|
785
|
-
const direct = detailsUrl ? module.parseRunJobIdentity(detailsUrl) : null;
|
|
776
|
+
const direct = detailsUrl ? parseRunJobIdentity(detailsUrl) : null;
|
|
786
777
|
if (direct) {
|
|
787
778
|
const run = client.json(['api', `repos/${repository(context)}/actions/runs/${direct.runId}`], { cwd: context.workingDirectory });
|
|
788
779
|
if (!run.ok)
|
|
@@ -798,11 +789,10 @@ function createGitHubOperations(client) {
|
|
|
798
789
|
: invalid('CHECK_RUN_NOT_FOUND', 'Check run was not found');
|
|
799
790
|
},
|
|
800
791
|
async fetchLogs({ context, runId, jobId }) {
|
|
801
|
-
const module = await import('./pr-checks.js');
|
|
802
792
|
const args = jobId
|
|
803
793
|
? ['api', `repos/${repository(context)}/actions/jobs/${jobId}/logs`]
|
|
804
794
|
: ['run', 'view', runId, '--repo', repository(context), '--log-failed'];
|
|
805
|
-
const fetched =
|
|
795
|
+
const fetched = fetchCheckLogText(client, args, context.workingDirectory);
|
|
806
796
|
if (!fetched.ok)
|
|
807
797
|
return fetched;
|
|
808
798
|
return { ok: true, value: { runId, jobId, text: fetched.value || '' } };
|
|
@@ -883,7 +873,12 @@ function createGitHubOperations(client) {
|
|
|
883
873
|
}
|
|
884
874
|
continue;
|
|
885
875
|
}
|
|
886
|
-
const response = client.json([
|
|
876
|
+
const response = client.json([
|
|
877
|
+
'api', '--method', 'POST', `repos/${repository(context)}/milestones`,
|
|
878
|
+
'-f', `title=${item.title}`,
|
|
879
|
+
'-f', `description=${item.description}`,
|
|
880
|
+
'-f', `state=${item.state}`
|
|
881
|
+
], { cwd: context.workingDirectory });
|
|
887
882
|
if (!response.ok)
|
|
888
883
|
return response;
|
|
889
884
|
created.push(item.title);
|
|
@@ -7,7 +7,7 @@ import { platformResult } from './types.js';
|
|
|
7
7
|
import { providerError, providerOperationContext, providerStatus, providerResourceToken, unsupportedProviderOperation } from './provider-bridge.js';
|
|
8
8
|
import { resourceIdentityNumber } from './resource-identity.js';
|
|
9
9
|
import { taskIssueIdentity, taskIssueIdentityError } from './task-identities.js';
|
|
10
|
-
import {
|
|
10
|
+
import { canonicalizeCommentBody, escapeHtmlText, fenceRanges, renderSafeCodeFence } from './comment-safety.js';
|
|
11
11
|
function providerCommentId(id, provider) {
|
|
12
12
|
return provider.identity?.comment === 'number' && /^\d+$/.test(id) ? Number(id) : id;
|
|
13
13
|
}
|
|
@@ -39,7 +39,7 @@ function splitFrontmatter(content) {
|
|
|
39
39
|
return { frontmatter: match[1], body: content.slice(match[0].length).replace(/^\r?\n/, '') };
|
|
40
40
|
}
|
|
41
41
|
function sanitizeCommentBody(value, label) {
|
|
42
|
-
const result =
|
|
42
|
+
const result = canonicalizeCommentBody(value);
|
|
43
43
|
if (!result.ok)
|
|
44
44
|
throw new Error(`${result.error.code}: ${label}: ${result.error.message} at offset ${result.error.offset}`);
|
|
45
45
|
return result.value;
|
|
@@ -14,8 +14,6 @@ import { labelDelta, planInLabelUpdate, syncLabelDelta, validateInLabelMapping,
|
|
|
14
14
|
import { providerError, providerOperationContext, providerStatus, providerResourceIdentity, providerResourceToken, unsupportedProviderOperation } from './provider-bridge.js';
|
|
15
15
|
import { resourceIdentityEquals, resourceIdentityNumber, resourceIdentityString, serializeResourceIdentity } from './resource-identity.js';
|
|
16
16
|
import { taskIssueIdentity, taskIssueIdentityError } from './task-identities.js';
|
|
17
|
-
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}}}}}}`;
|
|
18
|
-
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}}}}}}}}`;
|
|
19
17
|
function result(status, taskId, issueNumber, overrides = {}) {
|
|
20
18
|
return {
|
|
21
19
|
...platformResult(status),
|
|
@@ -133,115 +131,6 @@ async function inspectExternalIssue(base, issueIdentity) {
|
|
|
133
131
|
error: null
|
|
134
132
|
});
|
|
135
133
|
}
|
|
136
|
-
function normalizeIssue(remote, repository, fallbackNumber) {
|
|
137
|
-
const number = Number.isInteger(remote.number) && Number(remote.number) > 0
|
|
138
|
-
? Number(remote.number)
|
|
139
|
-
: fallbackNumber;
|
|
140
|
-
if (!number || !Number.isSafeInteger(number) || remote.pull_request)
|
|
141
|
-
return null;
|
|
142
|
-
return {
|
|
143
|
-
repository,
|
|
144
|
-
number,
|
|
145
|
-
databaseId: Number.isInteger(remote.id) ? Number(remote.id) : null,
|
|
146
|
-
nodeId: remote.node_id || `issue-${number}`,
|
|
147
|
-
url: remote.html_url || `https://github.com/${repository}/issues/${number}`,
|
|
148
|
-
state: String(remote.state || '').toLowerCase() === 'closed' ? 'closed' : 'open',
|
|
149
|
-
title: remote.title || '',
|
|
150
|
-
body: remote.body || '',
|
|
151
|
-
labels: (remote.labels || []).map((label) => typeof label === 'string' ? label : label.name || '').filter(Boolean).sort(),
|
|
152
|
-
assignees: (remote.assignees || []).map((assignee) => assignee.login || '').filter(Boolean).sort(),
|
|
153
|
-
milestone: remote.milestone?.title || null,
|
|
154
|
-
issueType: remote.type?.name || null,
|
|
155
|
-
fields: {}
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
function fieldKind(value) {
|
|
159
|
-
if (value.__typename === 'IssueFieldSingleSelect' || value.__typename === 'IssueFieldSingleSelectValue')
|
|
160
|
-
return 'single-select';
|
|
161
|
-
if (value.__typename === 'IssueFieldDate' || value.__typename === 'IssueFieldDateValue')
|
|
162
|
-
return 'date';
|
|
163
|
-
if (value.__typename === 'IssueFieldText' || value.__typename === 'IssueFieldTextValue')
|
|
164
|
-
return 'text';
|
|
165
|
-
if (value.__typename === 'IssueFieldNumber' || value.__typename === 'IssueFieldNumberValue')
|
|
166
|
-
return 'number';
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
function normalizeFieldSchemas(value) {
|
|
170
|
-
if (!Array.isArray(value))
|
|
171
|
-
return [];
|
|
172
|
-
return value.flatMap((raw) => {
|
|
173
|
-
const item = raw;
|
|
174
|
-
const kind = fieldKind(item);
|
|
175
|
-
return item.id && item.name && kind ? [{
|
|
176
|
-
id: item.id,
|
|
177
|
-
name: item.name,
|
|
178
|
-
kind,
|
|
179
|
-
options: (item.options || []).flatMap((option) => option.id && option.name ? [{ id: option.id, name: option.name }] : [])
|
|
180
|
-
}] : [];
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
function normalizeIssueTypes(value) {
|
|
184
|
-
const nodes = value?.data?.organization?.issueTypes?.nodes;
|
|
185
|
-
return (nodes || []).flatMap((raw) => {
|
|
186
|
-
const item = raw;
|
|
187
|
-
return item.id && item.name ? [{ id: item.id, name: item.name, fields: normalizeFieldSchemas(item.pinnedFields) }] : [];
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
function normalizeCurrentFields(value) {
|
|
191
|
-
const issue = value?.data?.repository?.issue;
|
|
192
|
-
const type = issue?.issueType?.name ? {
|
|
193
|
-
id: issue.issueType.id || issue.issueType.name,
|
|
194
|
-
name: issue.issueType.name,
|
|
195
|
-
fields: normalizeFieldSchemas(issue.issueType.pinnedFields)
|
|
196
|
-
} : null;
|
|
197
|
-
const values = (issue?.issueFieldValues?.nodes || []).flatMap((raw) => {
|
|
198
|
-
const item = raw;
|
|
199
|
-
const kind = fieldKind(item);
|
|
200
|
-
const value = kind === 'single-select' ? item.name : item.value;
|
|
201
|
-
return item.field?.name && kind && value !== undefined
|
|
202
|
-
? [{ id: item.field.id || item.field.name, name: item.field.name, kind, value: value ?? null }]
|
|
203
|
-
: [];
|
|
204
|
-
});
|
|
205
|
-
return { issueId: issue?.id || null, type, values };
|
|
206
|
-
}
|
|
207
|
-
function graphState(client, repository, issue, cwd) {
|
|
208
|
-
const [owner, name] = repository.split('/');
|
|
209
|
-
if (!owner || !name)
|
|
210
|
-
return null;
|
|
211
|
-
const current = client.json([
|
|
212
|
-
'api', 'graphql', '-f', `query=${ISSUE_FIELDS_QUERY}`, '-F', `owner=${owner}`, '-F', `name=${name}`, '-F', `number=${issue}`
|
|
213
|
-
], { cwd });
|
|
214
|
-
if (!current.ok)
|
|
215
|
-
return null;
|
|
216
|
-
return normalizeCurrentFields(current.value);
|
|
217
|
-
}
|
|
218
|
-
function fetchIssue(client, repository, issue, cwd) {
|
|
219
|
-
return client.json(['api', `repos/${repository}/issues/${issue}`], { cwd });
|
|
220
|
-
}
|
|
221
|
-
function inspectGitHubIssue(client, repository, issue, cwd) {
|
|
222
|
-
const fetched = fetchIssue(client, repository, issue, cwd);
|
|
223
|
-
if (!fetched.ok)
|
|
224
|
-
return fetched;
|
|
225
|
-
const snapshot = normalizeIssue(fetched.value, repository, issue);
|
|
226
|
-
return snapshot
|
|
227
|
-
? { ok: true, value: snapshot }
|
|
228
|
-
: { ok: false, error: { code: 'ISSUE_IDENTITY_INVALID', message: 'Remote resource is not a valid Issue', retryable: false } };
|
|
229
|
-
}
|
|
230
|
-
function inspectGitHubIssueMetadata(client, repository, issue, cwd) {
|
|
231
|
-
const fetched = fetchIssue(client, repository, issue, cwd);
|
|
232
|
-
if (!fetched.ok)
|
|
233
|
-
return fetched;
|
|
234
|
-
const remote = fetched.value;
|
|
235
|
-
return {
|
|
236
|
-
ok: true,
|
|
237
|
-
value: {
|
|
238
|
-
state: String(remote.state || '').toLowerCase() === 'closed' ? 'closed' : 'open',
|
|
239
|
-
labels: (remote.labels || []).map((label) => typeof label === 'string' ? label : label.name || '').filter(Boolean).sort(),
|
|
240
|
-
body: remote.body || '',
|
|
241
|
-
milestone: remote.milestone?.title || null
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
134
|
async function inspectPlatformIssue(taskRef, options = {}) {
|
|
246
135
|
const base = await resolvedContext(taskRef, options);
|
|
247
136
|
if (!base.ok)
|
|
@@ -450,12 +339,6 @@ function requirementsFromTask(content) {
|
|
|
450
339
|
checked: match[1].toLowerCase() === 'x', text: match[2]
|
|
451
340
|
}));
|
|
452
341
|
}
|
|
453
|
-
function flattenPages(value) {
|
|
454
|
-
return Array.isArray(value) ? value.flatMap((item) => Array.isArray(item) ? item : [item]) : [];
|
|
455
|
-
}
|
|
456
|
-
function listNames(value) {
|
|
457
|
-
return flattenPages(value).map((item) => typeof item === 'string' ? item : String(item.name || '')).filter(Boolean);
|
|
458
|
-
}
|
|
459
342
|
function milestoneBasis(repoRoot, current) {
|
|
460
343
|
if (!current || !/^\d+\.\d+\.x$/.test(current))
|
|
461
344
|
return current;
|
|
@@ -552,67 +435,6 @@ function desiredFieldValues(frontmatter, fields) {
|
|
|
552
435
|
}
|
|
553
436
|
return desired;
|
|
554
437
|
}
|
|
555
|
-
function planGraphMetadata(client, repository, issue, cwd, frontmatter, options, capabilities) {
|
|
556
|
-
if (!options.issueType && !options.fields)
|
|
557
|
-
return { operations: [], issueId: null };
|
|
558
|
-
if (!capabilities.push)
|
|
559
|
-
return {
|
|
560
|
-
operations: [
|
|
561
|
-
...(options.issueType ? [{ name: 'issue-type', status: 'skipped', reasonCode: 'PUSH_REQUIRED' }] : []),
|
|
562
|
-
...(options.fields ? [{ name: 'fields', status: 'skipped', reasonCode: 'PUSH_REQUIRED' }] : [])
|
|
563
|
-
], issueId: null
|
|
564
|
-
};
|
|
565
|
-
const [owner] = repository.split('/');
|
|
566
|
-
const typesResult = client.json(['api', 'graphql', '-f', `query=${ISSUE_TYPES_QUERY}`, '-F', `owner=${owner}`], { cwd });
|
|
567
|
-
if (!typesResult.ok)
|
|
568
|
-
return { operations: [{ name: 'issue-schema', status: 'failed', reasonCode: typesResult.error.code }], issueId: null };
|
|
569
|
-
const types = normalizeIssueTypes(typesResult.value);
|
|
570
|
-
if (types.length === 0)
|
|
571
|
-
return {
|
|
572
|
-
operations: [
|
|
573
|
-
...(options.issueType ? [{ name: 'issue-type', status: 'skipped', reasonCode: 'ISSUE_TYPES_UNSUPPORTED' }] : []),
|
|
574
|
-
...(options.fields ? [{ name: 'fields', status: 'skipped', reasonCode: 'ISSUE_TYPES_UNSUPPORTED' }] : [])
|
|
575
|
-
], issueId: null
|
|
576
|
-
};
|
|
577
|
-
const current = graphState(client, repository, issue, cwd);
|
|
578
|
-
if (!current?.issueId)
|
|
579
|
-
return { operations: [{ name: 'issue-schema', status: 'failed', reasonCode: 'ISSUE_GRAPH_IDENTITY_INVALID' }], issueId: null };
|
|
580
|
-
const target = types.find((type) => type.name === desiredIssueType(frontmatter.type || ''));
|
|
581
|
-
if (!target)
|
|
582
|
-
return { operations: [{ name: 'issue-type', status: 'failed', reasonCode: 'ISSUE_TYPE_NOT_FOUND' }], issueId: current.issueId };
|
|
583
|
-
const operations = [];
|
|
584
|
-
if (options.issueType)
|
|
585
|
-
operations.push(current.type?.id === target.id
|
|
586
|
-
? { name: 'issue-type', status: 'no-op', reasonCode: null }
|
|
587
|
-
: { name: 'issue-type', status: 'planned', reasonCode: null, value: { issueTypeId: target.id } });
|
|
588
|
-
if (options.fields) {
|
|
589
|
-
const desired = desiredFieldValues(frontmatter, target.fields);
|
|
590
|
-
const inputs = desired.filter((field) => current.values.find((value) => value.name === field.name)?.value !== field.value).map((field) => field.input);
|
|
591
|
-
if (current.type?.id !== target.id) {
|
|
592
|
-
const targetNames = new Set(target.fields.map((field) => field.name));
|
|
593
|
-
for (const old of current.values)
|
|
594
|
-
if (!targetNames.has(old.name))
|
|
595
|
-
inputs.push({ fieldId: old.id, delete: true });
|
|
596
|
-
}
|
|
597
|
-
operations.push(inputs.length === 0
|
|
598
|
-
? { name: 'fields', status: 'no-op', reasonCode: null }
|
|
599
|
-
: { name: 'fields', status: 'planned', reasonCode: null, value: inputs });
|
|
600
|
-
}
|
|
601
|
-
return { operations, issueId: current.issueId };
|
|
602
|
-
}
|
|
603
|
-
function executeGraphOperation(client, cwd, issueId, operation) {
|
|
604
|
-
if (operation.name === 'issue-type') {
|
|
605
|
-
const query = 'mutation($issueId:ID!,$issueTypeId:ID){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$issueTypeId}){issue{id}}}';
|
|
606
|
-
const typeId = operation.value.issueTypeId;
|
|
607
|
-
return client.json(['api', 'graphql', '--input', '-'], {
|
|
608
|
-
cwd, method: 'POST', input: JSON.stringify({ query, variables: { issueId, issueTypeId: typeId } })
|
|
609
|
-
});
|
|
610
|
-
}
|
|
611
|
-
const query = 'mutation($issueId:ID!,$issueFields:[IssueFieldCreateOrUpdateInput!]!){setIssueFieldValue(input:{issueId:$issueId,issueFields:$issueFields}){issue{id}}}';
|
|
612
|
-
return client.json(['api', 'graphql', '--input', '-'], {
|
|
613
|
-
cwd, method: 'POST', input: JSON.stringify({ query, variables: { issueId, issueFields: operation.value } })
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
438
|
async function syncPlatformIssue(taskRef, options) {
|
|
617
439
|
const base = await resolvedContext(taskRef, options);
|
|
618
440
|
if (!base.ok)
|
|
@@ -761,5 +583,5 @@ async function syncPlatformIssue(taskRef, options) {
|
|
|
761
583
|
operations: plan.operations.map((operation) => operation.status === 'planned' ? { ...operation, status: 'applied' } : operation), error: null
|
|
762
584
|
});
|
|
763
585
|
}
|
|
764
|
-
export { bindPlatformIssue, createPlatformIssue,
|
|
586
|
+
export { bindPlatformIssue, createPlatformIssue, inspectPlatformIssue, requirementSectionAnchors, syncPlatformIssue };
|
|
765
587
|
//# sourceMappingURL=issues.js.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { parseTypedTaskFrontmatter } from '../task/frontmatter.js';
|
|
3
3
|
import { resolveTaskRef } from '../task/resolve-ref.js';
|
|
4
|
+
import { checkStatusBucket } from './check-status.js';
|
|
4
5
|
import { resolvePlatformProviderContext } from './context.js';
|
|
5
6
|
import { inspectPlatformPullRequest } from './pull-requests.js';
|
|
6
7
|
import { platformResult } from './types.js';
|
|
@@ -26,20 +27,6 @@ function classifyPullRequestReadiness(input) {
|
|
|
26
27
|
return { state: 'pending', headSha: input.headSha };
|
|
27
28
|
return { state: 'ready', headSha: input.headSha };
|
|
28
29
|
}
|
|
29
|
-
function parseRunJobIdentity(detailsUrl) {
|
|
30
|
-
try {
|
|
31
|
-
const url = new URL(detailsUrl);
|
|
32
|
-
if (url.hostname !== 'github.com')
|
|
33
|
-
return null;
|
|
34
|
-
const match = url.pathname.match(/\/actions\/runs\/(\d+)(?:\/job\/(\d+))?/);
|
|
35
|
-
if (!match)
|
|
36
|
-
return null;
|
|
37
|
-
return { runId: Number(match[1]), jobId: match[2] ? Number(match[2]) : null };
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
30
|
function resolveRunCandidate(candidates, headSha, checkName) {
|
|
44
31
|
const matches = candidates.filter((candidate) => candidate.headSha === headSha && candidate.name === checkName);
|
|
45
32
|
if (matches.length === 1)
|
|
@@ -54,42 +41,6 @@ function checksResult(status, overrides = {}) {
|
|
|
54
41
|
...overrides
|
|
55
42
|
};
|
|
56
43
|
}
|
|
57
|
-
function normalizeBucket(value) {
|
|
58
|
-
const raw = String(value.bucket || value.status || value.conclusion || value.state || '').toLowerCase();
|
|
59
|
-
if (['pass', 'success', 'successful', 'neutral'].includes(raw))
|
|
60
|
-
return 'pass';
|
|
61
|
-
if (['fail', 'failure', 'failed', 'error', 'timed_out', 'action_required'].includes(raw))
|
|
62
|
-
return 'fail';
|
|
63
|
-
if (['cancel', 'cancelled', 'canceled', 'skipped', 'stale'].includes(raw))
|
|
64
|
-
return 'cancel';
|
|
65
|
-
return 'pending';
|
|
66
|
-
}
|
|
67
|
-
function normalizeChecks(value) {
|
|
68
|
-
if (!Array.isArray(value))
|
|
69
|
-
return [];
|
|
70
|
-
return value.flatMap((raw) => {
|
|
71
|
-
const item = raw;
|
|
72
|
-
const name = String(item.name || item.context || '');
|
|
73
|
-
return name ? [{
|
|
74
|
-
name,
|
|
75
|
-
bucket: normalizeBucket(item),
|
|
76
|
-
workflow: item.workflow ? String(item.workflow) : null,
|
|
77
|
-
conclusion: item.conclusion ? String(item.conclusion) : item.state ? String(item.state) : null,
|
|
78
|
-
detailsUrl: item.link ? String(item.link) : item.detailsUrl ? String(item.detailsUrl) : null,
|
|
79
|
-
startedAt: item.startedAt ? String(item.startedAt) : null,
|
|
80
|
-
completedAt: item.completedAt ? String(item.completedAt) : null
|
|
81
|
-
}] : [];
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
function inspectGitHubRequiredChecks(client, repository, number, cwd) {
|
|
85
|
-
const inspected = client.json([
|
|
86
|
-
'pr', 'checks', String(number), '--repo', repository,
|
|
87
|
-
'--json', 'name,state,bucket,link,workflow,startedAt,completedAt'
|
|
88
|
-
], { cwd });
|
|
89
|
-
return inspected.ok
|
|
90
|
-
? { ok: true, value: normalizeChecks(inspected.value) }
|
|
91
|
-
: { ok: false, error: inspected.error };
|
|
92
|
-
}
|
|
93
44
|
async function resolvedTask(taskRef, options) {
|
|
94
45
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
95
46
|
if (!resolved.ok)
|
|
@@ -117,10 +68,9 @@ async function inspectRequiredChecks(taskRef, options = {}) {
|
|
|
117
68
|
const base = await resolvedTask(taskRef, options);
|
|
118
69
|
if (!base.ok)
|
|
119
70
|
return base.output;
|
|
120
|
-
return inspectChecksForResolvedTask(base
|
|
71
|
+
return inspectChecksForResolvedTask(base);
|
|
121
72
|
}
|
|
122
|
-
async function inspectChecksForResolvedTask(base
|
|
123
|
-
const repository = base.context.platform.repository;
|
|
73
|
+
async function inspectChecksForResolvedTask(base) {
|
|
124
74
|
{
|
|
125
75
|
const inspected = base.provider.checks?.inspectRequired
|
|
126
76
|
? await base.provider.checks.inspectRequired({
|
|
@@ -137,7 +87,13 @@ async function inspectChecksForResolvedTask(base, options) {
|
|
|
137
87
|
pullRequest: base.pullRequest,
|
|
138
88
|
error: providerError(inspected.error, 'PLATFORM_PROVIDER_OPERATION_FAILED')
|
|
139
89
|
});
|
|
140
|
-
const required =
|
|
90
|
+
const required = inspected.value.map((check) => ({
|
|
91
|
+
name: check.name,
|
|
92
|
+
bucket: checkStatusBucket(check.status),
|
|
93
|
+
conclusion: check.conclusion || null,
|
|
94
|
+
detailsUrl: check.detailsUrl || null,
|
|
95
|
+
workflow: null, startedAt: null, completedAt: null
|
|
96
|
+
}));
|
|
141
97
|
const classified = classifyRequiredChecks(required);
|
|
142
98
|
const status = classified.state === 'passed' || classified.state === 'no-required'
|
|
143
99
|
? 'no-op'
|
|
@@ -157,7 +113,7 @@ async function inspectPullRequestReadiness(taskRef, options = {}) {
|
|
|
157
113
|
const base = await resolvedTask(taskRef, options);
|
|
158
114
|
if (!base.ok)
|
|
159
115
|
return base.output;
|
|
160
|
-
const checked = await inspectChecksForResolvedTask(base
|
|
116
|
+
const checked = await inspectChecksForResolvedTask(base);
|
|
161
117
|
const classifiedCodes = new Set(['REQUIRED_CHECKS_PENDING', 'REQUIRED_CHECKS_FAILED', 'REQUIRED_CHECKS_CANCELLED']);
|
|
162
118
|
if (checked.error && !classifiedCodes.has(checked.error.code))
|
|
163
119
|
return checked;
|
|
@@ -242,15 +198,6 @@ async function resolvePlatformCheckRun(taskRef, options) {
|
|
|
242
198
|
});
|
|
243
199
|
}
|
|
244
200
|
}
|
|
245
|
-
function fetchCheckLogText(client, args, cwd) {
|
|
246
|
-
if (!client.text)
|
|
247
|
-
return { ok: false, error: { code: 'PLATFORM_CLIENT_TEXT_UNAVAILABLE', message: 'Platform client does not support text responses', retryable: false } };
|
|
248
|
-
const fetched = client.text(args, { cwd });
|
|
249
|
-
if (fetched.ok || args[0] !== 'api' || !/response contains terminal escape sequences/i.test(fetched.error.message)) {
|
|
250
|
-
return fetched;
|
|
251
|
-
}
|
|
252
|
-
return client.text([...args, '--allow-escape-sequences'], { cwd });
|
|
253
|
-
}
|
|
254
201
|
async function fetchPlatformCheckLogs(taskRef, options) {
|
|
255
202
|
const base = await resolvedTask(taskRef, options);
|
|
256
203
|
if (!base.ok)
|
|
@@ -281,5 +228,5 @@ async function fetchPlatformCheckLogs(taskRef, options) {
|
|
|
281
228
|
});
|
|
282
229
|
}
|
|
283
230
|
}
|
|
284
|
-
export { classifyPullRequestReadiness, classifyRequiredChecks,
|
|
231
|
+
export { classifyPullRequestReadiness, classifyRequiredChecks, fetchPlatformCheckLogs, inspectRequiredChecks, inspectPullRequestReadiness, resolvePlatformCheckRun, resolveRunCandidate, watchPullRequestReadiness };
|
|
285
232
|
//# sourceMappingURL=pr-checks.js.map
|
|
@@ -12,6 +12,8 @@ import { CONTROL_MARKER_PATTERN, escapeHtmlText, sanitizeMarkdownDocument, split
|
|
|
12
12
|
import { platformResult } from './types.js';
|
|
13
13
|
import { providerError, providerOperationContext, providerStatus, providerResourceToken, resourceIdentityNumber, unsupportedProviderOperation } from './provider-bridge.js';
|
|
14
14
|
import { buildPrChangeReport, CANONICAL_REPORT_PLACEHOLDER, readPrChangeReport, replaceCanonicalReportPlaceholder, runMechanicalChangeReport, taskIntentDigest, validateMechanicalReport, validatePrecheckCandidate, writePrChangeReportAtomic } from './pr-change-report.js';
|
|
15
|
+
import { manualValidationFinalSummaryProjectionMatches } from '../task/manual-validation-receipt.js';
|
|
16
|
+
import { readManualValidationCompletion } from '../task/manual-validation-completion.js';
|
|
15
17
|
function summaryMarker(taskId) {
|
|
16
18
|
return `<!-- sync-pr:${taskId}:summary -->`;
|
|
17
19
|
}
|
|
@@ -286,6 +288,25 @@ async function summaryContext(taskRef, options = {}) {
|
|
|
286
288
|
artifacts: canonicalArtifacts(resolved.taskDir)
|
|
287
289
|
};
|
|
288
290
|
}
|
|
291
|
+
async function summaryCommentState(taskRef, options = {}) {
|
|
292
|
+
const context = await summaryContext(taskRef, options);
|
|
293
|
+
if (!context.task.prNumber || !context.pullRequest)
|
|
294
|
+
return { ...context, comment: null };
|
|
295
|
+
const loaded = await resolvePlatformProviderContext({ cwd: options.cwd, client: options.client });
|
|
296
|
+
if (!loaded.ok || !loaded.value.provider.comments?.list)
|
|
297
|
+
return { ...context, comment: null };
|
|
298
|
+
const listed = await loaded.value.provider.comments.list({
|
|
299
|
+
context: providerOperationContext(loaded.value),
|
|
300
|
+
parent: providerResourceToken(loaded.value.provider, 'pull-request', String(context.task.prNumber))
|
|
301
|
+
});
|
|
302
|
+
if (!listed.ok)
|
|
303
|
+
return { ...context, comment: null };
|
|
304
|
+
const matches = listed.value.filter((comment) => comment.body.includes(summaryMarker(context.task.id)));
|
|
305
|
+
return {
|
|
306
|
+
...context,
|
|
307
|
+
comment: matches.length === 1 ? { id: /^\d+$/u.test(matches[0].id) ? Number(matches[0].id) : matches[0].id, body: matches[0].body } : null
|
|
308
|
+
};
|
|
309
|
+
}
|
|
289
310
|
async function reportWrite(taskRef, options) {
|
|
290
311
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
291
312
|
if (!resolved.ok)
|
|
@@ -444,7 +465,7 @@ async function syncPullRequestSummary(taskRef, options) {
|
|
|
444
465
|
return preserveFailure(context);
|
|
445
466
|
}
|
|
446
467
|
try {
|
|
447
|
-
|
|
468
|
+
const execute = async () => {
|
|
448
469
|
const { taskContent, boundFact } = readBoundTaskSnapshot(resolved.taskMdPath);
|
|
449
470
|
if (!boundFact)
|
|
450
471
|
return {
|
|
@@ -463,6 +484,34 @@ async function syncPullRequestSummary(taskRef, options) {
|
|
|
463
484
|
const initial = await inspectBoundPullRequest(context, resolved.repoRoot, boundPrNumber, loaded.value);
|
|
464
485
|
if (!initial.ok)
|
|
465
486
|
return fail(initial.status, context, initial.error);
|
|
487
|
+
const manual = options.manualValidation;
|
|
488
|
+
const hasFinalManualValidation = /###\s+✅\s+(?:Manual Validation Passed|人工验证已通过)/u.test(options.body);
|
|
489
|
+
if (hasFinalManualValidation && (!manual || manual.phase !== 'final'))
|
|
490
|
+
return fail('failed', context, { code: 'MANUAL_VALIDATION_TRANSACTION_REQUIRED', message: 'final manual-validation summary requires the transaction coordinator', retryable: false }, prNumber);
|
|
491
|
+
if (manual && (manual.phase === 'pending' ? hasFinalManualValidation : !hasFinalManualValidation))
|
|
492
|
+
return fail('failed', context, { code: 'MANUAL_VALIDATION_SUMMARY_PHASE_INVALID', message: 'manual-validation summary phase does not match the requested writer phase', retryable: false }, prNumber);
|
|
493
|
+
if (manual) {
|
|
494
|
+
if (manual.phase === 'final' && (!manual.transactionId || !manual.receiptDigest || !manual.prHeadSha || manual.prHeadSha !== initial.value.head.sha))
|
|
495
|
+
return fail('failed', context, { code: 'MANUAL_VALIDATION_TRANSACTION_REQUIRED', message: 'final manual-validation summary requires transaction, receipt, and current head identity', retryable: false }, prNumber);
|
|
496
|
+
if (manual.phase === 'final') {
|
|
497
|
+
if (manual.authority !== 'coordinator')
|
|
498
|
+
return fail('failed', context, { code: 'MANUAL_VALIDATION_TRANSACTION_REQUIRED', message: 'final manual-validation summary requires coordinator authority', retryable: false }, prNumber);
|
|
499
|
+
const completion = readManualValidationCompletion(resolved.taskDir, {
|
|
500
|
+
transactionId: manual.transactionId,
|
|
501
|
+
taskId: resolved.taskId,
|
|
502
|
+
prNumber,
|
|
503
|
+
prHeadSha: initial.value.head.sha,
|
|
504
|
+
receiptDigest: manual.receiptDigest
|
|
505
|
+
});
|
|
506
|
+
if (!completion.ok)
|
|
507
|
+
return fail('failed', context, platformError(completion.error), prNumber);
|
|
508
|
+
const { receipt, transaction } = completion.value;
|
|
509
|
+
if (transaction.phase !== 'final-promotion-in-progress' || !transaction.eventAppended)
|
|
510
|
+
return fail('failed', context, { code: 'MANUAL_VALIDATION_TRANSACTION_PHASE_INVALID', message: 'final summary requires a receipt-backed promotion intent', retryable: false }, prNumber);
|
|
511
|
+
if (!manualValidationFinalSummaryProjectionMatches(options.body, receipt))
|
|
512
|
+
return fail('failed', context, { code: 'MANUAL_VALIDATION_SUMMARY_PROJECTION_INVALID', message: 'final summary body does not match the canonical receipt projection', retryable: false }, prNumber);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
466
515
|
const expectedReportPath = taskReportPath(resolved.taskDir);
|
|
467
516
|
const suppliedReportPath = path.resolve(resolved.repoRoot, options.changeReportFile);
|
|
468
517
|
if (suppliedReportPath !== expectedReportPath)
|
|
@@ -610,7 +659,10 @@ async function syncPullRequestSummary(taskRef, options) {
|
|
|
610
659
|
operations: [{ name: `summary:${reconciliation.action}`, status: 'applied', reasonCode: null }],
|
|
611
660
|
result: null, warnings: [], ...info
|
|
612
661
|
};
|
|
613
|
-
}
|
|
662
|
+
};
|
|
663
|
+
return await (options.lockAlreadyHeld
|
|
664
|
+
? execute()
|
|
665
|
+
: withTaskExecutionLock(resolved.repoRoot, resolved.taskId, options.agent, execute));
|
|
614
666
|
}
|
|
615
667
|
catch (error) {
|
|
616
668
|
const lockError = error instanceof TaskExecutionLockError
|
|
@@ -619,5 +671,5 @@ async function syncPullRequestSummary(taskRef, options) {
|
|
|
619
671
|
return fail(lockError.retryable ? 'blocked' : 'failed', context, lockError);
|
|
620
672
|
}
|
|
621
673
|
}
|
|
622
|
-
export { buildPullRequestSummary, reconcileSummaryComment, reportWrite, summaryContext, summaryMarker, syncPullRequestSummary, warningResultForPrimary };
|
|
674
|
+
export { buildPullRequestSummary, reconcileSummaryComment, reportWrite, summaryCommentState, summaryContext, summaryMarker, syncPullRequestSummary, warningResultForPrimary };
|
|
623
675
|
//# sourceMappingURL=pr-summary.js.map
|