patchrelay 0.52.1 → 0.52.3
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/dist/build-info.json +3 -3
- package/dist/cli/data.js +2 -52
- package/dist/implementation-outcome-policy.js +39 -13
- package/dist/no-pr-completion-check.js +45 -0
- package/dist/operator-retry-event.js +3 -3
- package/dist/reactive-run-policy.js +46 -4
- package/dist/remote-pr-review.js +60 -0
- package/dist/run-launcher.js +14 -1
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
package/dist/cli/data.js
CHANGED
|
@@ -6,6 +6,7 @@ import { extractCompletionCheck } from "../completion-check.js";
|
|
|
6
6
|
import { getThreadTurns } from "../codex-thread-utils.js";
|
|
7
7
|
import { PatchRelayDatabase } from "../db.js";
|
|
8
8
|
import { buildManualRetryAttemptReset, resolveRetryTarget } from "../manual-issue-actions.js";
|
|
9
|
+
import { buildOperatorRetryEvent } from "../operator-retry-event.js";
|
|
9
10
|
import { WorktreeManager } from "../worktree-manager.js";
|
|
10
11
|
import { parseDelegationObservedPayload, parseRunReleasedAuthorityPayload } from "../delegation-audit.js";
|
|
11
12
|
import { CliOperatorApiClient } from "./operator-client.js";
|
|
@@ -386,61 +387,10 @@ export class CliDataAccess extends CliOperatorApiClient {
|
|
|
386
387
|
};
|
|
387
388
|
}
|
|
388
389
|
appendRetryWake(issue, runType) {
|
|
389
|
-
if (runType === "queue_repair") {
|
|
390
|
-
const queueIncident = parseObjectJson(issue.lastQueueIncidentJson);
|
|
391
|
-
const failureContext = parseObjectJson(issue.lastGitHubFailureContextJson);
|
|
392
|
-
this.db.issueSessions.appendIssueSessionEventRespectingActiveLease(issue.projectId, issue.linearIssueId, {
|
|
393
|
-
projectId: issue.projectId,
|
|
394
|
-
linearIssueId: issue.linearIssueId,
|
|
395
|
-
eventType: "merge_steward_incident",
|
|
396
|
-
eventJson: JSON.stringify({
|
|
397
|
-
...(queueIncident ?? {}),
|
|
398
|
-
...(failureContext ?? {}),
|
|
399
|
-
source: "operator_retry",
|
|
400
|
-
}),
|
|
401
|
-
dedupeKey: `operator_retry:queue_repair:${issue.linearIssueId}:${issue.prHeadSha ?? issue.lastGitHubFailureHeadSha ?? "unknown-sha"}`,
|
|
402
|
-
});
|
|
403
|
-
return;
|
|
404
|
-
}
|
|
405
|
-
if (runType === "ci_repair") {
|
|
406
|
-
const failureContext = parseObjectJson(issue.lastGitHubFailureContextJson);
|
|
407
|
-
this.db.issueSessions.appendIssueSessionEventRespectingActiveLease(issue.projectId, issue.linearIssueId, {
|
|
408
|
-
projectId: issue.projectId,
|
|
409
|
-
linearIssueId: issue.linearIssueId,
|
|
410
|
-
eventType: "settled_red_ci",
|
|
411
|
-
eventJson: JSON.stringify({
|
|
412
|
-
...(failureContext ?? {}),
|
|
413
|
-
source: "operator_retry",
|
|
414
|
-
}),
|
|
415
|
-
dedupeKey: `operator_retry:ci_repair:${issue.linearIssueId}:${issue.lastGitHubFailureSignature ?? issue.prHeadSha ?? "unknown-sha"}`,
|
|
416
|
-
});
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
if (runType === "review_fix" || runType === "branch_upkeep") {
|
|
420
|
-
this.db.issueSessions.appendIssueSessionEventRespectingActiveLease(issue.projectId, issue.linearIssueId, {
|
|
421
|
-
projectId: issue.projectId,
|
|
422
|
-
linearIssueId: issue.linearIssueId,
|
|
423
|
-
eventType: "review_changes_requested",
|
|
424
|
-
eventJson: JSON.stringify({
|
|
425
|
-
reviewBody: runType === "branch_upkeep"
|
|
426
|
-
? "Operator requested retry of branch upkeep after requested changes."
|
|
427
|
-
: "Operator requested retry of review-fix work.",
|
|
428
|
-
...(runType === "branch_upkeep" ? { branchUpkeepRequired: true, wakeReason: "branch_upkeep" } : {}),
|
|
429
|
-
source: "operator_retry",
|
|
430
|
-
}),
|
|
431
|
-
dedupeKey: `operator_retry:${runType}:${issue.linearIssueId}:${issue.prHeadSha ?? "unknown-sha"}`,
|
|
432
|
-
});
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
390
|
this.db.issueSessions.appendIssueSessionEventRespectingActiveLease(issue.projectId, issue.linearIssueId, {
|
|
436
391
|
projectId: issue.projectId,
|
|
437
392
|
linearIssueId: issue.linearIssueId,
|
|
438
|
-
|
|
439
|
-
eventJson: JSON.stringify({
|
|
440
|
-
promptContext: "Operator requested retry of PatchRelay work.",
|
|
441
|
-
source: "operator_retry",
|
|
442
|
-
}),
|
|
443
|
-
dedupeKey: `operator_retry:implementation:${issue.linearIssueId}`,
|
|
393
|
+
...buildOperatorRetryEvent(issue, runType),
|
|
444
394
|
});
|
|
445
395
|
}
|
|
446
396
|
list(options) {
|
|
@@ -38,7 +38,7 @@ export class ImplementationOutcomePolicy {
|
|
|
38
38
|
return await this.describeLocalImplementationOutcome(issue, baseBranch);
|
|
39
39
|
}
|
|
40
40
|
async detectPublishedPrState(run, issue, repoFullName) {
|
|
41
|
-
if (issue.prNumber && issue.prState
|
|
41
|
+
if (issue.prNumber && isOpenPrState(issue.prState)) {
|
|
42
42
|
return "open";
|
|
43
43
|
}
|
|
44
44
|
if (!repoFullName || !issue.branchName) {
|
|
@@ -61,24 +61,30 @@ export class ImplementationOutcomePolicy {
|
|
|
61
61
|
return "unknown";
|
|
62
62
|
}
|
|
63
63
|
const matches = JSON.parse(stdout);
|
|
64
|
-
const pr = matches[0];
|
|
64
|
+
const pr = matches.find((candidate) => isOpenPrState(candidate.state)) ?? matches[0];
|
|
65
65
|
if (!pr?.number) {
|
|
66
|
+
this.clearObservedPrIfLeaseHeld(issue, "published PR verification found no PRs for branch");
|
|
66
67
|
return "none";
|
|
67
68
|
}
|
|
68
69
|
const state = pr.state?.toLowerCase();
|
|
69
|
-
|
|
70
|
-
projectId
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
if (isOpenPrState(state)) {
|
|
71
|
+
this.upsertIssueIfLeaseHeld(issue.projectId, issue.linearIssueId, {
|
|
72
|
+
projectId: issue.projectId,
|
|
73
|
+
linearIssueId: issue.linearIssueId,
|
|
74
|
+
prNumber: pr.number,
|
|
75
|
+
...(pr.url ? { prUrl: pr.url } : {}),
|
|
76
|
+
...(state ? { prState: state } : {}),
|
|
77
|
+
...(pr.headRefOid ? { prHeadSha: pr.headRefOid } : {}),
|
|
78
|
+
...(pr.author?.login ? { prAuthorLogin: pr.author.login } : {}),
|
|
79
|
+
}, "published PR verification refresh");
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
this.clearObservedPrIfLeaseHeld(issue, "published PR verification found only historical PRs for branch");
|
|
83
|
+
}
|
|
84
|
+
if (isOpenPrState(state) && isMainRepairIssue(issue)) {
|
|
79
85
|
await this.ensurePriorityQueueLabel(run.projectId, pr.number, repoFullName);
|
|
80
86
|
}
|
|
81
|
-
return state
|
|
87
|
+
return isOpenPrState(state) ? "open" : "closed";
|
|
82
88
|
}
|
|
83
89
|
catch (error) {
|
|
84
90
|
this.logger.debug({
|
|
@@ -97,6 +103,20 @@ export class ImplementationOutcomePolicy {
|
|
|
97
103
|
}
|
|
98
104
|
return updated;
|
|
99
105
|
}
|
|
106
|
+
clearObservedPrIfLeaseHeld(issue, context) {
|
|
107
|
+
this.upsertIssueIfLeaseHeld(issue.projectId, issue.linearIssueId, {
|
|
108
|
+
projectId: issue.projectId,
|
|
109
|
+
linearIssueId: issue.linearIssueId,
|
|
110
|
+
prNumber: null,
|
|
111
|
+
prUrl: null,
|
|
112
|
+
prState: null,
|
|
113
|
+
prIsDraft: null,
|
|
114
|
+
prHeadSha: null,
|
|
115
|
+
prAuthorLogin: null,
|
|
116
|
+
prReviewState: null,
|
|
117
|
+
prCheckStatus: null,
|
|
118
|
+
}, context);
|
|
119
|
+
}
|
|
100
120
|
async describeLocalImplementationOutcome(issue, baseBranch) {
|
|
101
121
|
if (!issue.worktreePath) {
|
|
102
122
|
return undefined;
|
|
@@ -177,3 +197,9 @@ export class ImplementationOutcomePolicy {
|
|
|
177
197
|
}
|
|
178
198
|
}
|
|
179
199
|
}
|
|
200
|
+
function isOpenPrState(state) {
|
|
201
|
+
if (!state)
|
|
202
|
+
return false;
|
|
203
|
+
const normalized = state.trim().toLowerCase();
|
|
204
|
+
return normalized !== "closed" && normalized !== "merged";
|
|
205
|
+
}
|
|
@@ -170,6 +170,51 @@ export async function handleNoPrCompletionCheck(params) {
|
|
|
170
170
|
});
|
|
171
171
|
return;
|
|
172
172
|
}
|
|
173
|
+
if (params.run.runType === "main_repair") {
|
|
174
|
+
const continued = params.withHeldLease(params.run.projectId, params.run.linearIssueId, (lease) => {
|
|
175
|
+
params.db.runs.finishRun(params.run.id, runUpdate);
|
|
176
|
+
params.db.runs.saveCompletionCheck(params.run.id, {
|
|
177
|
+
...completionCheck,
|
|
178
|
+
outcome: "continue",
|
|
179
|
+
summary: "Main repair cannot finish without a published repair PR; continuing automatically until the fix is published or main recovers externally.",
|
|
180
|
+
why: completionCheck.summary,
|
|
181
|
+
});
|
|
182
|
+
params.db.issues.upsertIssue({
|
|
183
|
+
projectId: params.run.projectId,
|
|
184
|
+
linearIssueId: params.run.linearIssueId,
|
|
185
|
+
activeRunId: null,
|
|
186
|
+
factoryState: "delegated",
|
|
187
|
+
pendingRunType: null,
|
|
188
|
+
pendingRunContextJson: null,
|
|
189
|
+
});
|
|
190
|
+
return Boolean(params.db.issueSessions.appendIssueSessionEventWithLease(lease, {
|
|
191
|
+
projectId: params.run.projectId,
|
|
192
|
+
linearIssueId: params.run.linearIssueId,
|
|
193
|
+
eventType: "completion_check_continue",
|
|
194
|
+
eventJson: JSON.stringify({
|
|
195
|
+
runType: params.run.runType,
|
|
196
|
+
summary: params.publishedOutcomeError,
|
|
197
|
+
}),
|
|
198
|
+
dedupeKey: `completion_check_continue:${params.run.id}`,
|
|
199
|
+
}));
|
|
200
|
+
});
|
|
201
|
+
if (!continued) {
|
|
202
|
+
params.logger.warn({ runId: params.run.id, issueId: params.run.linearIssueId }, "Skipping main-repair completion-check continue writes after losing issue-session lease");
|
|
203
|
+
params.clearProgressAndRelease(params.run);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
params.syncCompletionCheckOutcome({
|
|
207
|
+
run: params.run,
|
|
208
|
+
fallbackIssue: params.issue,
|
|
209
|
+
level: "info",
|
|
210
|
+
status: "completion_check_continue",
|
|
211
|
+
summary: "No repair PR found; continuing automatically",
|
|
212
|
+
detail: "Main repair cannot close until PatchRelay publishes a repair PR or main recovers externally.",
|
|
213
|
+
activity: buildCompletionCheckActivity("continue"),
|
|
214
|
+
enqueue: true,
|
|
215
|
+
});
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
173
218
|
const orchestrationOpenChildren = params.issue.issueClass === "orchestration"
|
|
174
219
|
? params.db.issues.countOpenChildIssues(params.run.projectId, params.run.linearIssueId)
|
|
175
220
|
: 0;
|
|
@@ -38,9 +38,9 @@ export function buildOperatorRetryEvent(issue, runType, source = "operator_retry
|
|
|
38
38
|
return {
|
|
39
39
|
eventType: "review_changes_requested",
|
|
40
40
|
eventJson: JSON.stringify({
|
|
41
|
-
|
|
42
|
-
? `${humanizeSource(source)} requested retry of branch upkeep after requested changes.`
|
|
43
|
-
: `${humanizeSource(source)} requested retry of review-fix work
|
|
41
|
+
...(runType === "branch_upkeep"
|
|
42
|
+
? { reviewBody: `${humanizeSource(source)} requested retry of branch upkeep after requested changes.` }
|
|
43
|
+
: { promptContext: `${humanizeSource(source)} requested retry of review-fix work.` }),
|
|
44
44
|
...(runType === "branch_upkeep" ? { branchUpkeepRequired: true, wakeReason: "branch_upkeep" } : {}),
|
|
45
45
|
source,
|
|
46
46
|
}),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { buildReviewFixBranchUpkeepContext, isDirtyMergeStateStatus, isRequestedChangesRunType, readReactivePrSnapshot, } from "./reactive-pr-state.js";
|
|
2
|
+
import { readLatestRequestedChangesReviewContext } from "./remote-pr-review.js";
|
|
2
3
|
export class ReactiveRunPolicy {
|
|
3
4
|
config;
|
|
4
5
|
db;
|
|
@@ -136,6 +137,7 @@ export class ReactiveRunPolicy {
|
|
|
136
137
|
const snapshot = await readReactivePrSnapshot(this.config, issue.projectId, issue.prNumber);
|
|
137
138
|
if (!snapshot)
|
|
138
139
|
return context;
|
|
140
|
+
const refreshedContext = await this.hydrateRequestedChangesContext(issue.projectId, issue.prNumber, snapshot.repoFullName, snapshot.headSha, context);
|
|
139
141
|
this.upsertIssueIfLeaseHeld(issue.projectId, issue.linearIssueId, {
|
|
140
142
|
projectId: issue.projectId,
|
|
141
143
|
linearIssueId: issue.linearIssueId,
|
|
@@ -144,12 +146,12 @@ export class ReactiveRunPolicy {
|
|
|
144
146
|
...(snapshot.reviewState ? { prReviewState: snapshot.reviewState } : {}),
|
|
145
147
|
}, "review-fix wake refresh");
|
|
146
148
|
if (snapshot.prState !== "open")
|
|
147
|
-
return
|
|
149
|
+
return refreshedContext;
|
|
148
150
|
if (snapshot.reviewState && snapshot.reviewState !== "changes_requested")
|
|
149
|
-
return
|
|
151
|
+
return refreshedContext;
|
|
150
152
|
if (!isDirtyMergeStateStatus(snapshot.pr.mergeStateStatus))
|
|
151
|
-
return
|
|
152
|
-
return buildReviewFixBranchUpkeepContext(issue.prNumber, snapshot.baseBranch, snapshot.pr,
|
|
153
|
+
return refreshedContext;
|
|
154
|
+
return buildReviewFixBranchUpkeepContext(issue.prNumber, snapshot.baseBranch, snapshot.pr, refreshedContext);
|
|
153
155
|
}
|
|
154
156
|
catch (error) {
|
|
155
157
|
this.logger.debug({
|
|
@@ -210,4 +212,44 @@ export class ReactiveRunPolicy {
|
|
|
210
212
|
}
|
|
211
213
|
return updated;
|
|
212
214
|
}
|
|
215
|
+
async hydrateRequestedChangesContext(projectId, prNumber, repoFullName, headSha, context) {
|
|
216
|
+
const merged = {
|
|
217
|
+
...(context ?? {}),
|
|
218
|
+
...(headSha ? { headSha } : {}),
|
|
219
|
+
};
|
|
220
|
+
if (hasStructuredReviewContext(merged)) {
|
|
221
|
+
return merged;
|
|
222
|
+
}
|
|
223
|
+
const liveReview = await readLatestRequestedChangesReviewContext(repoFullName, prNumber);
|
|
224
|
+
if (!liveReview) {
|
|
225
|
+
return Object.keys(merged).length > 0 ? merged : context;
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
...merged,
|
|
229
|
+
...(liveReview.reviewId !== undefined ? { reviewId: liveReview.reviewId } : {}),
|
|
230
|
+
...(liveReview.reviewCommitId ? { reviewCommitId: liveReview.reviewCommitId } : {}),
|
|
231
|
+
...(liveReview.reviewUrl ? { reviewUrl: liveReview.reviewUrl } : {}),
|
|
232
|
+
...(liveReview.reviewerName ? { reviewerName: liveReview.reviewerName } : {}),
|
|
233
|
+
...(liveReview.reviewBody ? { reviewBody: liveReview.reviewBody } : {}),
|
|
234
|
+
...(liveReview.reviewComments ? { reviewComments: liveReview.reviewComments } : {}),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function hasStructuredReviewContext(context) {
|
|
239
|
+
if (!context)
|
|
240
|
+
return false;
|
|
241
|
+
const reviewBody = typeof context.reviewBody === "string" ? context.reviewBody.trim() : "";
|
|
242
|
+
const isOperatorRetryPlaceholder = typeof context.source === "string"
|
|
243
|
+
&& context.source === "operator_retry"
|
|
244
|
+
&& /^operator requested retry of review-fix work\.?$/i.test(reviewBody);
|
|
245
|
+
if (isOperatorRetryPlaceholder) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
if (reviewBody)
|
|
249
|
+
return true;
|
|
250
|
+
if (typeof context.reviewUrl === "string" && context.reviewUrl.trim())
|
|
251
|
+
return true;
|
|
252
|
+
if (typeof context.reviewerName === "string" && context.reviewerName.trim())
|
|
253
|
+
return true;
|
|
254
|
+
return Array.isArray(context.reviewComments) && context.reviewComments.length > 0;
|
|
213
255
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { execCommand, safeJsonParse } from "./utils.js";
|
|
2
|
+
export async function readLatestRequestedChangesReviewContext(repoFullName, prNumber) {
|
|
3
|
+
const [owner, repo] = repoFullName.split("/", 2);
|
|
4
|
+
if (!owner || !repo) {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
const reviewsResult = await execCommand("gh", [
|
|
8
|
+
"api",
|
|
9
|
+
`repos/${owner}/${repo}/pulls/${prNumber}/reviews?per_page=100`,
|
|
10
|
+
], { timeoutMs: 10_000 });
|
|
11
|
+
if (reviewsResult.exitCode !== 0) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
const reviews = safeJsonParse(reviewsResult.stdout);
|
|
15
|
+
if (!Array.isArray(reviews)) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
const review = [...reviews].reverse().find((entry) => entry?.state?.trim().toUpperCase() === "CHANGES_REQUESTED");
|
|
19
|
+
if (!review?.id) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
const comments = await readReviewComments(owner, repo, prNumber, review.id);
|
|
23
|
+
return {
|
|
24
|
+
reviewId: review.id,
|
|
25
|
+
...(typeof review.commit_id === "string" && review.commit_id.trim() ? { reviewCommitId: review.commit_id.trim() } : {}),
|
|
26
|
+
...(typeof review.html_url === "string" && review.html_url.trim() ? { reviewUrl: review.html_url.trim() } : {}),
|
|
27
|
+
...(typeof review.body === "string" && review.body.trim() ? { reviewBody: review.body.trim() } : {}),
|
|
28
|
+
...(typeof review.user?.login === "string" && review.user.login.trim() ? { reviewerName: review.user.login.trim() } : {}),
|
|
29
|
+
...(comments.length > 0 ? { reviewComments: comments } : {}),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async function readReviewComments(owner, repo, prNumber, reviewId) {
|
|
33
|
+
const commentsResult = await execCommand("gh", [
|
|
34
|
+
"api",
|
|
35
|
+
`repos/${owner}/${repo}/pulls/${prNumber}/reviews/${reviewId}/comments?per_page=100`,
|
|
36
|
+
], { timeoutMs: 10_000 });
|
|
37
|
+
if (commentsResult.exitCode !== 0) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const comments = safeJsonParse(commentsResult.stdout);
|
|
41
|
+
if (!Array.isArray(comments)) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
return comments.flatMap((entry) => {
|
|
45
|
+
const body = typeof entry.body === "string" ? entry.body.trim() : "";
|
|
46
|
+
if (!body) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
return [{
|
|
50
|
+
body,
|
|
51
|
+
...(typeof entry.path === "string" ? { path: entry.path } : {}),
|
|
52
|
+
...(typeof entry.line === "number" ? { line: entry.line } : {}),
|
|
53
|
+
...(typeof entry.side === "string" ? { side: entry.side } : {}),
|
|
54
|
+
...(typeof entry.start_line === "number" ? { startLine: entry.start_line } : {}),
|
|
55
|
+
...(typeof entry.start_side === "string" ? { startSide: entry.start_side } : {}),
|
|
56
|
+
...(typeof entry.html_url === "string" ? { url: entry.html_url } : {}),
|
|
57
|
+
...(typeof entry.user?.login === "string" ? { authorLogin: entry.user.login } : {}),
|
|
58
|
+
}];
|
|
59
|
+
});
|
|
60
|
+
}
|
package/dist/run-launcher.js
CHANGED
|
@@ -18,6 +18,16 @@ function shouldCompactThread(issue, threadGeneration, context) {
|
|
|
18
18
|
export function shouldReuseIssueThread(params) {
|
|
19
19
|
return Boolean(params.existingThreadId) && !params.compactThread && params.resumeThread;
|
|
20
20
|
}
|
|
21
|
+
export function shouldFreshenWorktreeBeforeLaunch(params) {
|
|
22
|
+
if (params.runType === "queue_repair") {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
if (params.runType === "review_fix") {
|
|
26
|
+
return params.effectiveContext?.branchUpkeepRequired === true
|
|
27
|
+
|| params.effectiveContext?.reviewFixMode === "branch_upkeep";
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
21
31
|
export class RunLauncher {
|
|
22
32
|
config;
|
|
23
33
|
db;
|
|
@@ -125,7 +135,10 @@ export class RunLauncher {
|
|
|
125
135
|
});
|
|
126
136
|
}
|
|
127
137
|
await this.worktreeManager.resetWorktreeToTrackedBranch(params.worktreePath, params.branchName, params.issue, this.logger);
|
|
128
|
-
if (
|
|
138
|
+
if (shouldFreshenWorktreeBeforeLaunch({
|
|
139
|
+
runType: params.runType,
|
|
140
|
+
...(params.effectiveContext ? { effectiveContext: params.effectiveContext } : {}),
|
|
141
|
+
})) {
|
|
129
142
|
await this.worktreeManager.freshenWorktree(params.worktreePath, params.project, params.issue, this.logger);
|
|
130
143
|
}
|
|
131
144
|
const hookEnv = buildHookEnv(params.issue.issueKey ?? params.issue.linearIssueId, params.branchName, params.runType, params.worktreePath);
|