@vypdev/copilot 3.8.0 → 3.9.1
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/build/api/index.js
CHANGED
|
@@ -5255,6 +5255,12 @@ exports.APPLICATION_ERROR_METADATA = {
|
|
|
5255
5255
|
action: 'Correct the input and retry.',
|
|
5256
5256
|
retainedState: UNCHANGED_STATE,
|
|
5257
5257
|
},
|
|
5258
|
+
'validation.evidence-unavailable': {
|
|
5259
|
+
kind: 'validation', retryable: false,
|
|
5260
|
+
impact: 'Progress was not assessed because GitHub omitted a required file patch.',
|
|
5261
|
+
action: 'Inspect the exact base/head comparison manually or split the work into smaller reviewed changes with complete patches before a new assessment. Retrying the same commits cannot restore omitted evidence.',
|
|
5262
|
+
retainedState: 'Existing progress labels and published assessments were preserved; no model assessment was made.',
|
|
5263
|
+
},
|
|
5258
5264
|
'validation.evidence-too-large': {
|
|
5259
5265
|
kind: 'validation', retryable: false,
|
|
5260
5266
|
impact: 'Progress could not be assessed within the fixed evidence limits.',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type BranchSyncValidationCode } from '../../domain/branch_sync_validation';
|
|
2
2
|
export type ApplicationErrorKind = 'configuration' | 'authorization' | 'provider' | 'agent' | 'validation' | 'workflow' | 'unknown';
|
|
3
|
-
export type ApplicationErrorCode = 'configuration.invalid' | 'configuration.unsupported' | 'authorization.denied' | 'authorization.credential-invalid' | 'provider.not-found' | 'provider.conflict' | 'provider.rate-limited' | 'provider.unavailable' | 'provider.contract-invalid' | 'agent.policy-rejected' | 'agent.failed' | 'locale.output-invalid' | 'locale.translation-failed' | 'validation.invalid-input' | 'validation.evidence-too-large' | 'workflow.invalid-event' | 'workflow.stale' | 'workflow.cancelled' | 'workflow.failed' | 'workflow.presentation-pending' | 'timeout' | 'unexpected';
|
|
3
|
+
export type ApplicationErrorCode = 'configuration.invalid' | 'configuration.unsupported' | 'authorization.denied' | 'authorization.credential-invalid' | 'provider.not-found' | 'provider.conflict' | 'provider.rate-limited' | 'provider.unavailable' | 'provider.contract-invalid' | 'agent.policy-rejected' | 'agent.failed' | 'locale.output-invalid' | 'locale.translation-failed' | 'validation.invalid-input' | 'validation.evidence-too-large' | 'validation.evidence-unavailable' | 'workflow.invalid-event' | 'workflow.stale' | 'workflow.cancelled' | 'workflow.failed' | 'workflow.presentation-pending' | 'timeout' | 'unexpected';
|
|
4
4
|
export declare const APPLICATION_ERROR_RECOVERY_IDS: readonly ["pull-request-link-restored", "pull-request-link-base-retained", "pull-request-link-reference-retained", "pull-request-link-base-and-reference-retained", "managed-branch-enrichment-failed", "inactivity-explanation-failed", "bugbot-review-blocks-pending", "branch-sync-agent-disabled", "branch-sync-fixer-unavailable", "branch-sync-resolution-invalid", "sdd-draft-size-exceeded", "sdd-draft-format-invalid", "workspace-changes-rejected"];
|
|
5
5
|
export type ApplicationErrorRecoveryId = typeof APPLICATION_ERROR_RECOVERY_IDS[number];
|
|
6
6
|
interface ApplicationErrorRecoveryVariables {
|
package/build/cli/index.js
CHANGED
|
@@ -39201,6 +39201,11 @@ const SPANISH_CONTENT = Object.freeze({
|
|
|
39201
39201
|
action: 'Corrige la entrada y reinténtalo.',
|
|
39202
39202
|
retainedState: UNCHANGED_STATE_ES,
|
|
39203
39203
|
}),
|
|
39204
|
+
'validation.evidence-unavailable': Object.freeze({
|
|
39205
|
+
impact: 'No se evaluó el progreso porque GitHub omitió un patch necesario.',
|
|
39206
|
+
action: 'Inspecciona manualmente la comparación entre los commits base y head exactos o divide el trabajo en cambios revisados más pequeños con patches completos antes de otra evaluación. Reintentar los mismos commits no recuperará la evidencia omitida.',
|
|
39207
|
+
retainedState: 'Se conservaron las etiquetas de progreso y las evaluaciones publicadas; no se realizó ninguna evaluación del modelo.',
|
|
39208
|
+
}),
|
|
39204
39209
|
'validation.evidence-too-large': Object.freeze({
|
|
39205
39210
|
impact: 'No se pudo evaluar el progreso dentro de los límites fijos de evidencia.',
|
|
39206
39211
|
action: 'Reduce el tamaño de la comparación o divide el trabajo en cambios revisados más pequeños antes de iniciar otra evaluación.',
|
|
@@ -58883,7 +58888,7 @@ async function runIssueWorkflow(context, taskId, ports) {
|
|
|
58883
58888
|
}
|
|
58884
58889
|
const agentAllowed = !context.membersOnly || Boolean(ports.actorAuthorizationPort
|
|
58885
58890
|
&& await ports.actorAuthorizationPort.isActorAllowedToUseMemberOnlyAutomation(context.actor));
|
|
58886
|
-
const recommendation = context.started && !sddWaiting && (!context.
|
|
58891
|
+
const recommendation = context.started && !sddWaiting && (!context.branchRequired || branchReady) && agentAllowed
|
|
58887
58892
|
? context.recommendation : undefined;
|
|
58888
58893
|
if (recommendation) {
|
|
58889
58894
|
const recommendationOutcome = recommendation === 'answer-help'
|
|
@@ -71916,13 +71921,13 @@ async function runLinkPullRequestIssue(param, taskId, port, delay) {
|
|
|
71916
71921
|
let retainedIssueReference = false;
|
|
71917
71922
|
let alreadyLinked = false;
|
|
71918
71923
|
if (!hasOwnedPendingOperation) {
|
|
71919
|
-
alreadyLinked = await port.isLinked(param.pullRequestNumber);
|
|
71924
|
+
alreadyLinked = await port.isLinked(param.pullRequestNumber, param.issueNumber);
|
|
71920
71925
|
if (alreadyLinked)
|
|
71921
71926
|
return [];
|
|
71922
71927
|
}
|
|
71923
71928
|
else {
|
|
71924
71929
|
try {
|
|
71925
|
-
alreadyLinked = await port.isLinked(param.pullRequestNumber);
|
|
71930
|
+
alreadyLinked = await port.isLinked(param.pullRequestNumber, param.issueNumber);
|
|
71926
71931
|
}
|
|
71927
71932
|
catch (error) {
|
|
71928
71933
|
primaryError = error;
|
|
@@ -78106,6 +78111,12 @@ exports.APPLICATION_ERROR_METADATA = {
|
|
|
78106
78111
|
action: 'Correct the input and retry.',
|
|
78107
78112
|
retainedState: UNCHANGED_STATE,
|
|
78108
78113
|
},
|
|
78114
|
+
'validation.evidence-unavailable': {
|
|
78115
|
+
kind: 'validation', retryable: false,
|
|
78116
|
+
impact: 'Progress was not assessed because GitHub omitted a required file patch.',
|
|
78117
|
+
action: 'Inspect the exact base/head comparison manually or split the work into smaller reviewed changes with complete patches before a new assessment. Retrying the same commits cannot restore omitted evidence.',
|
|
78118
|
+
retainedState: 'Existing progress labels and published assessments were preserved; no model assessment was made.',
|
|
78119
|
+
},
|
|
78109
78120
|
'validation.evidence-too-large': {
|
|
78110
78121
|
kind: 'validation', retryable: false,
|
|
78111
78122
|
impact: 'Progress could not be assessed within the fixed evidence limits.',
|
|
@@ -85414,8 +85425,10 @@ class ProgressDiffRepository {
|
|
|
85414
85425
|
throw unavailable();
|
|
85415
85426
|
paths.add(path);
|
|
85416
85427
|
const generated = path.startsWith('build/') || path === 'specs/CATALOG.md';
|
|
85417
|
-
|
|
85418
|
-
|
|
85428
|
+
const unchanged = file.status === 'unchanged' && file.additions === 0 && file.deletions === 0;
|
|
85429
|
+
if (!generated && !unchanged && (typeof file.patch !== 'string' || !file.patch)) {
|
|
85430
|
+
throw new application_error_1.ApplicationError('validation.evidence-unavailable', 'GitHub omitted a required file patch from the pinned comparison. Progress was not assessed and existing state was retained.');
|
|
85431
|
+
}
|
|
85419
85432
|
return { path, status: file.status, additions: file.additions, deletions: file.deletions,
|
|
85420
85433
|
...(generated ? { evidence: 'generated-metadata-only' } : { patch: file.patch ?? '' }) };
|
|
85421
85434
|
});
|
|
@@ -86701,6 +86714,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
|
86701
86714
|
exports.PullRequestLifecycleRepository = void 0;
|
|
86702
86715
|
const logger_1 = __nccwpck_require__(91151);
|
|
86703
86716
|
const application_error_1 = __nccwpck_require__(75999);
|
|
86717
|
+
const github_error_policy_1 = __nccwpck_require__(58791);
|
|
86704
86718
|
class PullRequestLifecycleRepository {
|
|
86705
86719
|
constructor(githubClient) {
|
|
86706
86720
|
this.githubClient = githubClient;
|
|
@@ -86762,26 +86776,69 @@ class PullRequestLifecycleRepository {
|
|
|
86762
86776
|
throw semanticError;
|
|
86763
86777
|
}
|
|
86764
86778
|
};
|
|
86765
|
-
|
|
86766
|
-
|
|
86767
|
-
const controller = new AbortController();
|
|
86768
|
-
const timeoutId = setTimeout(() => controller.abort(), PullRequestLifecycleRepository.IS_LINKED_FETCH_TIMEOUT_MS);
|
|
86779
|
+
/** Reads at most 200 closing references through the credential-bound API. */
|
|
86780
|
+
this.isLinked = async (owner, repository, pullRequestNumber, issueNumber, token) => {
|
|
86769
86781
|
try {
|
|
86770
|
-
|
|
86771
|
-
|
|
86772
|
-
|
|
86782
|
+
if (![pullRequestNumber, issueNumber].every(number => Number.isSafeInteger(number) && number > 0)) {
|
|
86783
|
+
throw new application_error_1.ApplicationError('validation.invalid-input', 'Linkage requires positive PR and issue numbers.');
|
|
86784
|
+
}
|
|
86785
|
+
const client = this.githubClient.getClient(token);
|
|
86786
|
+
if (!client.graphql)
|
|
86787
|
+
throw new application_error_1.ApplicationError('configuration.unsupported', 'Authenticated PR linkage queries are not supported by this installation.');
|
|
86788
|
+
const expectedRepository = `${owner}/${repository}`.toLowerCase();
|
|
86789
|
+
let cursor = null;
|
|
86790
|
+
for (let page = 0; page < 2; page += 1) {
|
|
86791
|
+
const result = await client.graphql(`
|
|
86792
|
+
query PullRequestIssueLinkage($owner: String!, $repo: String!, $number: Int!, $cursor: String) {
|
|
86793
|
+
repository(owner: $owner, name: $repo) {
|
|
86794
|
+
nameWithOwner
|
|
86795
|
+
pullRequest(number: $number) {
|
|
86796
|
+
number
|
|
86797
|
+
closingIssuesReferences(first: 100, after: $cursor) {
|
|
86798
|
+
nodes { number repository { nameWithOwner } }
|
|
86799
|
+
pageInfo { hasNextPage endCursor }
|
|
86800
|
+
}
|
|
86801
|
+
}
|
|
86802
|
+
}
|
|
86803
|
+
}`, { owner, repo: repository, number: pullRequestNumber, cursor });
|
|
86804
|
+
const resource = result?.repository;
|
|
86805
|
+
if (resource === null || resource?.pullRequest === null) {
|
|
86806
|
+
throw new application_error_1.ApplicationError('provider.not-found', 'The requested pull request is unavailable to the configured credential.');
|
|
86807
|
+
}
|
|
86808
|
+
const pr = resource?.pullRequest;
|
|
86809
|
+
const references = pr?.closingIssuesReferences;
|
|
86810
|
+
if (typeof resource?.nameWithOwner !== 'string' || resource.nameWithOwner.toLowerCase() !== expectedRepository || pr?.number !== pullRequestNumber
|
|
86811
|
+
|| !Array.isArray(references?.nodes) || references.nodes.length > 100
|
|
86812
|
+
|| typeof references.pageInfo?.hasNextPage !== 'boolean'
|
|
86813
|
+
|| references.nodes.some(node => !node || !Number.isSafeInteger(node.number) || node.number <= 0
|
|
86814
|
+
|| typeof node.repository?.nameWithOwner !== 'string' || !node.repository.nameWithOwner)) {
|
|
86815
|
+
throw new application_error_1.ApplicationError('provider.contract-invalid', 'GitHub did not return verifiable PR linkage evidence.');
|
|
86816
|
+
}
|
|
86817
|
+
if (references.nodes.some(node => node.number === issueNumber
|
|
86818
|
+
&& node.repository.nameWithOwner.toLowerCase() === expectedRepository))
|
|
86819
|
+
return true;
|
|
86820
|
+
if (!references.pageInfo.hasNextPage)
|
|
86821
|
+
return false;
|
|
86822
|
+
const nextCursor = references.pageInfo.endCursor;
|
|
86823
|
+
if (typeof nextCursor !== 'string' || !nextCursor || nextCursor === cursor) {
|
|
86824
|
+
throw new application_error_1.ApplicationError('provider.contract-invalid', 'GitHub returned incomplete linkage pagination.');
|
|
86825
|
+
}
|
|
86826
|
+
cursor = nextCursor;
|
|
86773
86827
|
}
|
|
86774
|
-
|
|
86775
|
-
return !htmlContent.includes('has_github_issues=false');
|
|
86828
|
+
throw new application_error_1.ApplicationError('provider.contract-invalid', 'PR linkage exceeds the fixed 200-reference inspection bound.');
|
|
86776
86829
|
}
|
|
86777
86830
|
catch (error) {
|
|
86778
|
-
const
|
|
86831
|
+
const status = (0, github_error_policy_1.getGithubErrorStatus)(error);
|
|
86832
|
+
const types = typeof error === 'object' && error !== null && 'errors' in error && Array.isArray(error.errors)
|
|
86833
|
+
? error.errors.map((entry) => entry?.type) : [];
|
|
86834
|
+
const code = (0, github_error_policy_1.isGithubRateLimited)(error) || types.includes('RATE_LIMITED') ? 'provider.rate-limited'
|
|
86835
|
+
: status === 401 ? 'authorization.credential-invalid'
|
|
86836
|
+
: status === 403 || types.includes('FORBIDDEN') || types.includes('UNAUTHORIZED') ? 'authorization.denied'
|
|
86837
|
+
: status === 404 || types.includes('NOT_FOUND') ? 'provider.not-found' : 'provider.unavailable';
|
|
86838
|
+
const semanticError = (0, application_error_1.toApplicationError)(error, code, `Unable to inspect issue linkage for pull request #${pullRequestNumber}.`);
|
|
86779
86839
|
(0, logger_1.logError)(semanticError);
|
|
86780
86840
|
throw semanticError;
|
|
86781
86841
|
}
|
|
86782
|
-
finally {
|
|
86783
|
-
clearTimeout(timeoutId);
|
|
86784
|
-
}
|
|
86785
86842
|
};
|
|
86786
86843
|
this.updateBaseBranch = async (owner, repository, pullRequestNumber, branch, token) => {
|
|
86787
86844
|
const octokit = this.githubClient.getClient(token);
|
|
@@ -86850,8 +86907,6 @@ class PullRequestLifecycleRepository {
|
|
|
86850
86907
|
}
|
|
86851
86908
|
}
|
|
86852
86909
|
exports.PullRequestLifecycleRepository = PullRequestLifecycleRepository;
|
|
86853
|
-
/** Default timeout (ms) for isLinked fetch. */
|
|
86854
|
-
PullRequestLifecycleRepository.IS_LINKED_FETCH_TIMEOUT_MS = 10000;
|
|
86855
86910
|
function toBugbotPullRequestIdentity(value) {
|
|
86856
86911
|
const number = value.number;
|
|
86857
86912
|
const state = value.state;
|
|
@@ -94843,7 +94898,7 @@ function createIssueUseCaseCompositionRoot(binding) {
|
|
|
94843
94898
|
const organizationMembers = (0, organization_members_composition_root_1.createOrganizationMembersCompositionRoot)();
|
|
94844
94899
|
const branchLifecycle = new branch_lifecycle_repository_1.BranchLifecycleRepository((0, github_branch_client_factory_1.createBranchClient)());
|
|
94845
94900
|
const branchName = new branch_name_repository_1.BranchNameRepository();
|
|
94846
|
-
const gitCli = new git_cli_repository_1.GitCliRepository();
|
|
94901
|
+
const gitCli = new git_cli_repository_1.GitCliRepository(binding.token);
|
|
94847
94902
|
const linkedBranch = new linked_branch_repository_1.LinkedBranchRepository((0, github_project_client_factory_1.createGraphqlTransportClient)());
|
|
94848
94903
|
const branchPropagationDelay = new timer_branch_propagation_delay_adapter_1.TimerBranchPropagationDelayAdapter();
|
|
94849
94904
|
const projectBoard = (0, project_board_composition_root_1.createProjectBoardCompositionRoot)();
|
|
@@ -94970,7 +95025,7 @@ function bindBranchWorkflow(port, binding) {
|
|
|
94970
95025
|
}
|
|
94971
95026
|
function bindPullRequestIssueLink(port, binding) {
|
|
94972
95027
|
return Object.freeze({
|
|
94973
|
-
isLinked: (pullRequestNumber) => port.isLinked(binding.owner, binding.repository, pullRequestNumber, binding.token),
|
|
95028
|
+
isLinked: (pullRequestNumber, issueNumber) => port.isLinked(binding.owner, binding.repository, pullRequestNumber, issueNumber, binding.token),
|
|
94974
95029
|
getDetails: (pullRequestNumber) => port.getDetails(binding.owner, binding.repository, pullRequestNumber, binding.token),
|
|
94975
95030
|
updateBaseBranch: (pullRequestNumber, baseBranch) => port.updateBaseBranch(binding.owner, binding.repository, pullRequestNumber, baseBranch, binding.token),
|
|
94976
95031
|
updateDescription: (pullRequestNumber, description) => port.updateDescription(binding.owner, binding.repository, pullRequestNumber, description, binding.token),
|
|
@@ -40545,6 +40545,11 @@ const SPANISH_CONTENT = Object.freeze({
|
|
|
40545
40545
|
action: 'Corrige la entrada y reinténtalo.',
|
|
40546
40546
|
retainedState: UNCHANGED_STATE_ES,
|
|
40547
40547
|
}),
|
|
40548
|
+
'validation.evidence-unavailable': Object.freeze({
|
|
40549
|
+
impact: 'No se evaluó el progreso porque GitHub omitió un patch necesario.',
|
|
40550
|
+
action: 'Inspecciona manualmente la comparación entre los commits base y head exactos o divide el trabajo en cambios revisados más pequeños con patches completos antes de otra evaluación. Reintentar los mismos commits no recuperará la evidencia omitida.',
|
|
40551
|
+
retainedState: 'Se conservaron las etiquetas de progreso y las evaluaciones publicadas; no se realizó ninguna evaluación del modelo.',
|
|
40552
|
+
}),
|
|
40548
40553
|
'validation.evidence-too-large': Object.freeze({
|
|
40549
40554
|
impact: 'No se pudo evaluar el progreso dentro de los límites fijos de evidencia.',
|
|
40550
40555
|
action: 'Reduce el tamaño de la comparación o divide el trabajo en cambios revisados más pequeños antes de iniciar otra evaluación.',
|
|
@@ -56715,7 +56720,7 @@ async function runIssueWorkflow(context, taskId, ports) {
|
|
|
56715
56720
|
}
|
|
56716
56721
|
const agentAllowed = !context.membersOnly || Boolean(ports.actorAuthorizationPort
|
|
56717
56722
|
&& await ports.actorAuthorizationPort.isActorAllowedToUseMemberOnlyAutomation(context.actor));
|
|
56718
|
-
const recommendation = context.started && !sddWaiting && (!context.
|
|
56723
|
+
const recommendation = context.started && !sddWaiting && (!context.branchRequired || branchReady) && agentAllowed
|
|
56719
56724
|
? context.recommendation : undefined;
|
|
56720
56725
|
if (recommendation) {
|
|
56721
56726
|
const recommendationOutcome = recommendation === 'answer-help'
|
|
@@ -67599,13 +67604,13 @@ async function runLinkPullRequestIssue(param, taskId, port, delay) {
|
|
|
67599
67604
|
let retainedIssueReference = false;
|
|
67600
67605
|
let alreadyLinked = false;
|
|
67601
67606
|
if (!hasOwnedPendingOperation) {
|
|
67602
|
-
alreadyLinked = await port.isLinked(param.pullRequestNumber);
|
|
67607
|
+
alreadyLinked = await port.isLinked(param.pullRequestNumber, param.issueNumber);
|
|
67603
67608
|
if (alreadyLinked)
|
|
67604
67609
|
return [];
|
|
67605
67610
|
}
|
|
67606
67611
|
else {
|
|
67607
67612
|
try {
|
|
67608
|
-
alreadyLinked = await port.isLinked(param.pullRequestNumber);
|
|
67613
|
+
alreadyLinked = await port.isLinked(param.pullRequestNumber, param.issueNumber);
|
|
67609
67614
|
}
|
|
67610
67615
|
catch (error) {
|
|
67611
67616
|
primaryError = error;
|
|
@@ -68461,6 +68466,12 @@ exports.APPLICATION_ERROR_METADATA = {
|
|
|
68461
68466
|
action: 'Correct the input and retry.',
|
|
68462
68467
|
retainedState: UNCHANGED_STATE,
|
|
68463
68468
|
},
|
|
68469
|
+
'validation.evidence-unavailable': {
|
|
68470
|
+
kind: 'validation', retryable: false,
|
|
68471
|
+
impact: 'Progress was not assessed because GitHub omitted a required file patch.',
|
|
68472
|
+
action: 'Inspect the exact base/head comparison manually or split the work into smaller reviewed changes with complete patches before a new assessment. Retrying the same commits cannot restore omitted evidence.',
|
|
68473
|
+
retainedState: 'Existing progress labels and published assessments were preserved; no model assessment was made.',
|
|
68474
|
+
},
|
|
68464
68475
|
'validation.evidence-too-large': {
|
|
68465
68476
|
kind: 'validation', retryable: false,
|
|
68466
68477
|
impact: 'Progress could not be assessed within the fixed evidence limits.',
|
|
@@ -75906,8 +75917,10 @@ class ProgressDiffRepository {
|
|
|
75906
75917
|
throw unavailable();
|
|
75907
75918
|
paths.add(path);
|
|
75908
75919
|
const generated = path.startsWith('build/') || path === 'specs/CATALOG.md';
|
|
75909
|
-
|
|
75910
|
-
|
|
75920
|
+
const unchanged = file.status === 'unchanged' && file.additions === 0 && file.deletions === 0;
|
|
75921
|
+
if (!generated && !unchanged && (typeof file.patch !== 'string' || !file.patch)) {
|
|
75922
|
+
throw new application_error_1.ApplicationError('validation.evidence-unavailable', 'GitHub omitted a required file patch from the pinned comparison. Progress was not assessed and existing state was retained.');
|
|
75923
|
+
}
|
|
75911
75924
|
return { path, status: file.status, additions: file.additions, deletions: file.deletions,
|
|
75912
75925
|
...(generated ? { evidence: 'generated-metadata-only' } : { patch: file.patch ?? '' }) };
|
|
75913
75926
|
});
|
|
@@ -77193,6 +77206,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
|
77193
77206
|
exports.PullRequestLifecycleRepository = void 0;
|
|
77194
77207
|
const logger_1 = __nccwpck_require__(91151);
|
|
77195
77208
|
const application_error_1 = __nccwpck_require__(75999);
|
|
77209
|
+
const github_error_policy_1 = __nccwpck_require__(58791);
|
|
77196
77210
|
class PullRequestLifecycleRepository {
|
|
77197
77211
|
constructor(githubClient) {
|
|
77198
77212
|
this.githubClient = githubClient;
|
|
@@ -77254,26 +77268,69 @@ class PullRequestLifecycleRepository {
|
|
|
77254
77268
|
throw semanticError;
|
|
77255
77269
|
}
|
|
77256
77270
|
};
|
|
77257
|
-
|
|
77258
|
-
|
|
77259
|
-
const controller = new AbortController();
|
|
77260
|
-
const timeoutId = setTimeout(() => controller.abort(), PullRequestLifecycleRepository.IS_LINKED_FETCH_TIMEOUT_MS);
|
|
77271
|
+
/** Reads at most 200 closing references through the credential-bound API. */
|
|
77272
|
+
this.isLinked = async (owner, repository, pullRequestNumber, issueNumber, token) => {
|
|
77261
77273
|
try {
|
|
77262
|
-
|
|
77263
|
-
|
|
77264
|
-
|
|
77274
|
+
if (![pullRequestNumber, issueNumber].every(number => Number.isSafeInteger(number) && number > 0)) {
|
|
77275
|
+
throw new application_error_1.ApplicationError('validation.invalid-input', 'Linkage requires positive PR and issue numbers.');
|
|
77276
|
+
}
|
|
77277
|
+
const client = this.githubClient.getClient(token);
|
|
77278
|
+
if (!client.graphql)
|
|
77279
|
+
throw new application_error_1.ApplicationError('configuration.unsupported', 'Authenticated PR linkage queries are not supported by this installation.');
|
|
77280
|
+
const expectedRepository = `${owner}/${repository}`.toLowerCase();
|
|
77281
|
+
let cursor = null;
|
|
77282
|
+
for (let page = 0; page < 2; page += 1) {
|
|
77283
|
+
const result = await client.graphql(`
|
|
77284
|
+
query PullRequestIssueLinkage($owner: String!, $repo: String!, $number: Int!, $cursor: String) {
|
|
77285
|
+
repository(owner: $owner, name: $repo) {
|
|
77286
|
+
nameWithOwner
|
|
77287
|
+
pullRequest(number: $number) {
|
|
77288
|
+
number
|
|
77289
|
+
closingIssuesReferences(first: 100, after: $cursor) {
|
|
77290
|
+
nodes { number repository { nameWithOwner } }
|
|
77291
|
+
pageInfo { hasNextPage endCursor }
|
|
77292
|
+
}
|
|
77293
|
+
}
|
|
77294
|
+
}
|
|
77295
|
+
}`, { owner, repo: repository, number: pullRequestNumber, cursor });
|
|
77296
|
+
const resource = result?.repository;
|
|
77297
|
+
if (resource === null || resource?.pullRequest === null) {
|
|
77298
|
+
throw new application_error_1.ApplicationError('provider.not-found', 'The requested pull request is unavailable to the configured credential.');
|
|
77299
|
+
}
|
|
77300
|
+
const pr = resource?.pullRequest;
|
|
77301
|
+
const references = pr?.closingIssuesReferences;
|
|
77302
|
+
if (typeof resource?.nameWithOwner !== 'string' || resource.nameWithOwner.toLowerCase() !== expectedRepository || pr?.number !== pullRequestNumber
|
|
77303
|
+
|| !Array.isArray(references?.nodes) || references.nodes.length > 100
|
|
77304
|
+
|| typeof references.pageInfo?.hasNextPage !== 'boolean'
|
|
77305
|
+
|| references.nodes.some(node => !node || !Number.isSafeInteger(node.number) || node.number <= 0
|
|
77306
|
+
|| typeof node.repository?.nameWithOwner !== 'string' || !node.repository.nameWithOwner)) {
|
|
77307
|
+
throw new application_error_1.ApplicationError('provider.contract-invalid', 'GitHub did not return verifiable PR linkage evidence.');
|
|
77308
|
+
}
|
|
77309
|
+
if (references.nodes.some(node => node.number === issueNumber
|
|
77310
|
+
&& node.repository.nameWithOwner.toLowerCase() === expectedRepository))
|
|
77311
|
+
return true;
|
|
77312
|
+
if (!references.pageInfo.hasNextPage)
|
|
77313
|
+
return false;
|
|
77314
|
+
const nextCursor = references.pageInfo.endCursor;
|
|
77315
|
+
if (typeof nextCursor !== 'string' || !nextCursor || nextCursor === cursor) {
|
|
77316
|
+
throw new application_error_1.ApplicationError('provider.contract-invalid', 'GitHub returned incomplete linkage pagination.');
|
|
77317
|
+
}
|
|
77318
|
+
cursor = nextCursor;
|
|
77265
77319
|
}
|
|
77266
|
-
|
|
77267
|
-
return !htmlContent.includes('has_github_issues=false');
|
|
77320
|
+
throw new application_error_1.ApplicationError('provider.contract-invalid', 'PR linkage exceeds the fixed 200-reference inspection bound.');
|
|
77268
77321
|
}
|
|
77269
77322
|
catch (error) {
|
|
77270
|
-
const
|
|
77323
|
+
const status = (0, github_error_policy_1.getGithubErrorStatus)(error);
|
|
77324
|
+
const types = typeof error === 'object' && error !== null && 'errors' in error && Array.isArray(error.errors)
|
|
77325
|
+
? error.errors.map((entry) => entry?.type) : [];
|
|
77326
|
+
const code = (0, github_error_policy_1.isGithubRateLimited)(error) || types.includes('RATE_LIMITED') ? 'provider.rate-limited'
|
|
77327
|
+
: status === 401 ? 'authorization.credential-invalid'
|
|
77328
|
+
: status === 403 || types.includes('FORBIDDEN') || types.includes('UNAUTHORIZED') ? 'authorization.denied'
|
|
77329
|
+
: status === 404 || types.includes('NOT_FOUND') ? 'provider.not-found' : 'provider.unavailable';
|
|
77330
|
+
const semanticError = (0, application_error_1.toApplicationError)(error, code, `Unable to inspect issue linkage for pull request #${pullRequestNumber}.`);
|
|
77271
77331
|
(0, logger_1.logError)(semanticError);
|
|
77272
77332
|
throw semanticError;
|
|
77273
77333
|
}
|
|
77274
|
-
finally {
|
|
77275
|
-
clearTimeout(timeoutId);
|
|
77276
|
-
}
|
|
77277
77334
|
};
|
|
77278
77335
|
this.updateBaseBranch = async (owner, repository, pullRequestNumber, branch, token) => {
|
|
77279
77336
|
const octokit = this.githubClient.getClient(token);
|
|
@@ -77342,8 +77399,6 @@ class PullRequestLifecycleRepository {
|
|
|
77342
77399
|
}
|
|
77343
77400
|
}
|
|
77344
77401
|
exports.PullRequestLifecycleRepository = PullRequestLifecycleRepository;
|
|
77345
|
-
/** Default timeout (ms) for isLinked fetch. */
|
|
77346
|
-
PullRequestLifecycleRepository.IS_LINKED_FETCH_TIMEOUT_MS = 10000;
|
|
77347
77402
|
function toBugbotPullRequestIdentity(value) {
|
|
77348
77403
|
const number = value.number;
|
|
77349
77404
|
const state = value.state;
|
|
@@ -85343,7 +85398,7 @@ function createIssueUseCaseCompositionRoot(binding) {
|
|
|
85343
85398
|
const organizationMembers = (0, organization_members_composition_root_1.createOrganizationMembersCompositionRoot)();
|
|
85344
85399
|
const branchLifecycle = new branch_lifecycle_repository_1.BranchLifecycleRepository((0, github_branch_client_factory_1.createBranchClient)());
|
|
85345
85400
|
const branchName = new branch_name_repository_1.BranchNameRepository();
|
|
85346
|
-
const gitCli = new git_cli_repository_1.GitCliRepository();
|
|
85401
|
+
const gitCli = new git_cli_repository_1.GitCliRepository(binding.token);
|
|
85347
85402
|
const linkedBranch = new linked_branch_repository_1.LinkedBranchRepository((0, github_project_client_factory_1.createGraphqlTransportClient)());
|
|
85348
85403
|
const branchPropagationDelay = new timer_branch_propagation_delay_adapter_1.TimerBranchPropagationDelayAdapter();
|
|
85349
85404
|
const projectBoard = (0, project_board_composition_root_1.createProjectBoardCompositionRoot)();
|
|
@@ -85470,7 +85525,7 @@ function bindBranchWorkflow(port, binding) {
|
|
|
85470
85525
|
}
|
|
85471
85526
|
function bindPullRequestIssueLink(port, binding) {
|
|
85472
85527
|
return Object.freeze({
|
|
85473
|
-
isLinked: (pullRequestNumber) => port.isLinked(binding.owner, binding.repository, pullRequestNumber, binding.token),
|
|
85528
|
+
isLinked: (pullRequestNumber, issueNumber) => port.isLinked(binding.owner, binding.repository, pullRequestNumber, issueNumber, binding.token),
|
|
85474
85529
|
getDetails: (pullRequestNumber) => port.getDetails(binding.owner, binding.repository, pullRequestNumber, binding.token),
|
|
85475
85530
|
updateBaseBranch: (pullRequestNumber, baseBranch) => port.updateBaseBranch(binding.owner, binding.repository, pullRequestNumber, baseBranch, binding.token),
|
|
85476
85531
|
updateDescription: (pullRequestNumber, description) => port.updateDescription(binding.owner, binding.repository, pullRequestNumber, description, binding.token),
|