patchrelay 0.35.1 → 0.35.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/db.js +14 -0
- package/dist/run-orchestrator.js +16 -0
- package/dist/service.js +4 -0
- package/dist/webhook-handler.js +17 -1
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
package/dist/db.js
CHANGED
|
@@ -484,6 +484,20 @@ export class PatchRelayDatabase {
|
|
|
484
484
|
.all();
|
|
485
485
|
return rows.map(mapIssueRow);
|
|
486
486
|
}
|
|
487
|
+
/**
|
|
488
|
+
* Issues in delegated state with dependencies but no pending/active run.
|
|
489
|
+
* Candidates for unblocking when their blockers complete.
|
|
490
|
+
*/
|
|
491
|
+
listBlockedDelegatedIssues() {
|
|
492
|
+
const rows = this.connection
|
|
493
|
+
.prepare(`SELECT DISTINCT i.* FROM issues i
|
|
494
|
+
JOIN issue_dependencies d ON d.project_id = i.project_id AND d.linear_issue_id = i.linear_issue_id
|
|
495
|
+
WHERE i.factory_state = 'delegated'
|
|
496
|
+
AND i.active_run_id IS NULL
|
|
497
|
+
AND i.pending_run_type IS NULL`)
|
|
498
|
+
.all();
|
|
499
|
+
return rows.map(mapIssueRow);
|
|
500
|
+
}
|
|
487
501
|
/**
|
|
488
502
|
* Issues waiting in the merge queue with no active or pending run.
|
|
489
503
|
* Used by the queue health monitor to probe GitHub for stuck PRs.
|
package/dist/run-orchestrator.js
CHANGED
|
@@ -126,6 +126,10 @@ export class RunOrchestrator {
|
|
|
126
126
|
const issue = this.db.getIssue(item.projectId, item.issueId);
|
|
127
127
|
if (!issue?.pendingRunType || issue.activeRunId !== undefined)
|
|
128
128
|
return;
|
|
129
|
+
if (issue.prState === "merged") {
|
|
130
|
+
this.db.upsertIssue({ projectId: issue.projectId, linearIssueId: issue.linearIssueId, pendingRunType: null, factoryState: "done" });
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
129
133
|
const runType = issue.pendingRunType;
|
|
130
134
|
const contextJson = issue.pendingRunContextJson;
|
|
131
135
|
const context = contextJson ? JSON.parse(contextJson) : undefined;
|
|
@@ -759,6 +763,18 @@ export class RunOrchestrator {
|
|
|
759
763
|
await this.reconcileFromGitHub(issue);
|
|
760
764
|
}
|
|
761
765
|
}
|
|
766
|
+
// Unblock delegated issues whose blockers have been resolved.
|
|
767
|
+
for (const issue of this.db.listBlockedDelegatedIssues()) {
|
|
768
|
+
const unresolved = this.db.countUnresolvedBlockers(issue.projectId, issue.linearIssueId);
|
|
769
|
+
if (unresolved === 0) {
|
|
770
|
+
this.db.upsertIssue({
|
|
771
|
+
projectId: issue.projectId,
|
|
772
|
+
linearIssueId: issue.linearIssueId,
|
|
773
|
+
pendingRunType: "implementation",
|
|
774
|
+
});
|
|
775
|
+
this.enqueueIssue(issue.projectId, issue.linearIssueId);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
762
778
|
}
|
|
763
779
|
async reconcileFromGitHub(issue) {
|
|
764
780
|
const project = this.config.projects.find((p) => p.id === issue.projectId);
|
package/dist/service.js
CHANGED
|
@@ -487,6 +487,10 @@ export class PatchRelayService {
|
|
|
487
487
|
return undefined;
|
|
488
488
|
if (issue.activeRunId)
|
|
489
489
|
return { error: "Issue already has an active run" };
|
|
490
|
+
if (issue.prState === "merged") {
|
|
491
|
+
this.db.upsertIssue({ projectId: issue.projectId, linearIssueId: issue.linearIssueId, factoryState: "done" });
|
|
492
|
+
return { issueKey, runType: "none" };
|
|
493
|
+
}
|
|
490
494
|
// Infer run type from current state instead of always resetting to implementation
|
|
491
495
|
let runType = "implementation";
|
|
492
496
|
let factoryState = "delegated";
|
package/dist/webhook-handler.js
CHANGED
|
@@ -167,7 +167,18 @@ export class WebhookHandler {
|
|
|
167
167
|
if (delegated && triggerAllowed && unresolvedBlockers === 0 && !activeRun && !existingIssue?.pendingRunType && !terminalForAutomation) {
|
|
168
168
|
pendingRunType = "implementation";
|
|
169
169
|
}
|
|
170
|
-
|
|
170
|
+
let clearPendingImplementation = unresolvedBlockers > 0 && existingIssue?.pendingRunType === "implementation" && !activeRun;
|
|
171
|
+
// Release active run when issue reaches a terminal state or is un-delegated.
|
|
172
|
+
let clearActiveRun = false;
|
|
173
|
+
if (activeRun && existingIssue) {
|
|
174
|
+
if (terminalForAutomation) {
|
|
175
|
+
clearActiveRun = true;
|
|
176
|
+
}
|
|
177
|
+
if (normalized.triggerEvent === "delegateChanged" && !delegated) {
|
|
178
|
+
clearActiveRun = true;
|
|
179
|
+
clearPendingImplementation = Boolean(existingIssue.pendingRunType);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
171
182
|
// Resolve agent session
|
|
172
183
|
const agentSessionId = normalized.agentSession?.id ??
|
|
173
184
|
(!activeRun && (pendingRunType || (normalized.triggerEvent === "delegateChanged" && !delegated)) ? null : undefined);
|
|
@@ -189,7 +200,12 @@ export class WebhookHandler {
|
|
|
189
200
|
? { pendingRunContextJson }
|
|
190
201
|
: {}),
|
|
191
202
|
...(agentSessionId !== undefined ? { agentSessionId } : {}),
|
|
203
|
+
...(clearActiveRun ? { activeRunId: null } : {}),
|
|
192
204
|
});
|
|
205
|
+
if (clearActiveRun && activeRun) {
|
|
206
|
+
const reason = terminalForAutomation ? "Issue reached terminal state during active run" : "Un-delegated from PatchRelay";
|
|
207
|
+
this.db.finishRun(activeRun.id, { status: "released", failureReason: reason });
|
|
208
|
+
}
|
|
193
209
|
return {
|
|
194
210
|
issue: this.db.issueToTrackedIssue(issue),
|
|
195
211
|
desiredStage: pendingRunType,
|