patchrelay 0.36.14 → 0.36.16
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
CHANGED
|
@@ -103,6 +103,10 @@ export class InterruptedRunRecovery {
|
|
|
103
103
|
await this.handleInterruptedRequestedChangesRun(run, issue);
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
|
+
if (run.runType === "implementation" && !issue.prNumber) {
|
|
107
|
+
await this.handleInterruptedImplementationRun(run, issue);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
106
110
|
const recoveredState = resolveRecoverablePostRunState(this.db.issues.getIssue(run.projectId, run.linearIssueId) ?? issue);
|
|
107
111
|
this.failRunAndClear(run, "Codex turn was interrupted", recoveredState);
|
|
108
112
|
await this.restoreIdleWorktree(issue);
|
|
@@ -124,6 +128,47 @@ export class InterruptedRunRecovery {
|
|
|
124
128
|
void this.linearSync.syncSession(failedIssue, { activeRunType: run.runType });
|
|
125
129
|
this.releaseLease(run.projectId, run.linearIssueId);
|
|
126
130
|
}
|
|
131
|
+
async handleInterruptedImplementationRun(run, issue) {
|
|
132
|
+
const interruptedMessage = "Implementation run was interrupted before PatchRelay could publish a PR";
|
|
133
|
+
this.failRunAndClear(run, "Codex turn was interrupted", "delegated");
|
|
134
|
+
await this.restoreIdleWorktree(issue);
|
|
135
|
+
const refreshedIssue = this.db.issues.getIssue(run.projectId, run.linearIssueId) ?? issue;
|
|
136
|
+
this.db.issueSessions.appendIssueSessionEventRespectingActiveLease(run.projectId, run.linearIssueId, {
|
|
137
|
+
projectId: run.projectId,
|
|
138
|
+
linearIssueId: run.linearIssueId,
|
|
139
|
+
eventType: "delegated",
|
|
140
|
+
dedupeKey: `interrupted_implementation:implementation:${run.linearIssueId}`,
|
|
141
|
+
});
|
|
142
|
+
if (!this.db.issueSessions.peekIssueSessionWake(run.projectId, run.linearIssueId)) {
|
|
143
|
+
const failedIssue = this.db.issues.getIssue(run.projectId, run.linearIssueId) ?? refreshedIssue;
|
|
144
|
+
this.feed?.publish({
|
|
145
|
+
level: "error",
|
|
146
|
+
kind: "workflow",
|
|
147
|
+
issueKey: issue.issueKey,
|
|
148
|
+
projectId: run.projectId,
|
|
149
|
+
stage: run.runType,
|
|
150
|
+
status: "escalated",
|
|
151
|
+
summary: interruptedMessage,
|
|
152
|
+
});
|
|
153
|
+
void this.linearSync.emitActivity(failedIssue, buildRunFailureActivity(run.runType, interruptedMessage));
|
|
154
|
+
void this.linearSync.syncSession(failedIssue, { activeRunType: run.runType });
|
|
155
|
+
this.releaseLease(run.projectId, run.linearIssueId);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
this.feed?.publish({
|
|
159
|
+
level: "warn",
|
|
160
|
+
kind: "workflow",
|
|
161
|
+
issueKey: issue.issueKey,
|
|
162
|
+
projectId: run.projectId,
|
|
163
|
+
stage: run.runType,
|
|
164
|
+
status: "retry_queued",
|
|
165
|
+
summary: "Implementation run was interrupted; PatchRelay will retry automatically",
|
|
166
|
+
});
|
|
167
|
+
const recoveredIssue = this.db.issues.getIssue(run.projectId, run.linearIssueId) ?? refreshedIssue;
|
|
168
|
+
void this.linearSync.syncSession(recoveredIssue, { activeRunType: run.runType });
|
|
169
|
+
this.enqueueIssue(run.projectId, run.linearIssueId);
|
|
170
|
+
this.releaseLease(run.projectId, run.linearIssueId);
|
|
171
|
+
}
|
|
127
172
|
async handleInterruptedRequestedChangesRun(run, issue) {
|
|
128
173
|
const freshIssue = this.db.issues.getIssue(run.projectId, run.linearIssueId) ?? issue;
|
|
129
174
|
const refreshedIssue = await this.completionPolicy.refreshIssueAfterReactivePublish(run, freshIssue);
|
|
@@ -254,7 +254,7 @@ export class LinearSessionSync {
|
|
|
254
254
|
const previous = this.agentMessageBuffers.get(messageKey) ?? "";
|
|
255
255
|
const next = `${previous}${delta}`;
|
|
256
256
|
this.agentMessageBuffers.set(messageKey, next);
|
|
257
|
-
const sentence =
|
|
257
|
+
const sentence = extractFirstCompletedSentence(next);
|
|
258
258
|
if (!sentence)
|
|
259
259
|
return undefined;
|
|
260
260
|
this.agentMessageProgressPublished.add(messageKey);
|
|
@@ -522,6 +522,13 @@ function extractFirstSentence(text) {
|
|
|
522
522
|
const match = sanitized.match(/^(.+?[.!?])(?:\s|$)/);
|
|
523
523
|
return truncateProgressText((match?.[1] ?? sanitized).trim(), MAX_PROGRESS_TEXT_LENGTH);
|
|
524
524
|
}
|
|
525
|
+
function extractFirstCompletedSentence(text) {
|
|
526
|
+
const sanitized = sanitizeOperatorFacingText(text)?.replace(/\s+/g, " ").trim();
|
|
527
|
+
if (!sanitized)
|
|
528
|
+
return undefined;
|
|
529
|
+
const match = sanitized.match(/^(.+?[.!?])(?:\s|$)/);
|
|
530
|
+
return match?.[1] ? truncateProgressText(match[1].trim(), MAX_PROGRESS_TEXT_LENGTH) : undefined;
|
|
531
|
+
}
|
|
525
532
|
function summarizeProgressSentence(text) {
|
|
526
533
|
const summary = extractFirstSentence(text);
|
|
527
534
|
if (!summary)
|