patchrelay 0.35.6 → 0.35.7
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/run-orchestrator.js +2 -0
- package/dist/webhook-handler.js +92 -57
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
package/dist/run-orchestrator.js
CHANGED
|
@@ -461,6 +461,7 @@ export class RunOrchestrator {
|
|
|
461
461
|
projectId: run.projectId,
|
|
462
462
|
linearIssueId: run.linearIssueId,
|
|
463
463
|
activeRunId: null,
|
|
464
|
+
...(postRunState === "awaiting_queue" ? { queueLabelApplied: false } : {}),
|
|
464
465
|
...(postRunState ? { factoryState: postRunState } : {}),
|
|
465
466
|
...(postRunState === "awaiting_queue" || postRunState === "done"
|
|
466
467
|
? {
|
|
@@ -1073,6 +1074,7 @@ export class RunOrchestrator {
|
|
|
1073
1074
|
projectId: run.projectId,
|
|
1074
1075
|
linearIssueId: run.linearIssueId,
|
|
1075
1076
|
activeRunId: null,
|
|
1077
|
+
...(postRunState === "awaiting_queue" ? { queueLabelApplied: false } : {}),
|
|
1076
1078
|
...(postRunState ? { factoryState: postRunState } : {}),
|
|
1077
1079
|
...(postRunState === "awaiting_queue" || postRunState === "done"
|
|
1078
1080
|
? {
|
package/dist/webhook-handler.js
CHANGED
|
@@ -185,74 +185,74 @@ export class WebhookHandler {
|
|
|
185
185
|
if (!normalizedIssue) {
|
|
186
186
|
return { issue: undefined, desiredStage: undefined, delegated: false };
|
|
187
187
|
}
|
|
188
|
+
// ── 1. Fetch data ────────────────────────────────────────────
|
|
188
189
|
const existingIssue = this.db.getIssue(project.id, normalizedIssue.id);
|
|
189
190
|
const activeRun = existingIssue?.activeRunId ? this.db.getRun(existingIssue.activeRunId) : undefined;
|
|
190
191
|
const delegated = this.isDelegatedToPatchRelay(project, normalized);
|
|
191
192
|
const triggerAllowed = triggerEventAllowed(project, normalized.triggerEvent);
|
|
192
|
-
|
|
193
|
-
if (!shouldTrack) {
|
|
193
|
+
if (!existingIssue && !delegated) {
|
|
194
194
|
return { issue: undefined, desiredStage: undefined, delegated };
|
|
195
195
|
}
|
|
196
196
|
const hydratedIssue = await this.syncIssueDependencies(project.id, normalizedIssue);
|
|
197
197
|
const unresolvedBlockers = this.db.countUnresolvedBlockers(project.id, normalizedIssue.id);
|
|
198
198
|
const pendingRunContextJson = mergePendingImplementationContext(existingIssue?.pendingRunContextJson, normalized);
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
199
|
+
const terminal = isTerminalDelegationState(existingIssue, hydratedIssue);
|
|
200
|
+
// ── 2. Pure decisions ────────────────────────────────────────
|
|
201
|
+
const pendingRunType = decideRunIntent({
|
|
202
|
+
delegated, triggerAllowed, unresolvedBlockers,
|
|
203
|
+
hasActiveRun: Boolean(activeRun),
|
|
204
|
+
hasPendingRun: Boolean(existingIssue?.pendingRunType),
|
|
205
|
+
terminal,
|
|
206
|
+
});
|
|
207
|
+
const runRelease = decideActiveRunRelease({
|
|
208
|
+
hasActiveRun: Boolean(activeRun),
|
|
209
|
+
terminal,
|
|
210
|
+
triggerEvent: normalized.triggerEvent,
|
|
211
|
+
delegated,
|
|
212
|
+
});
|
|
213
|
+
const undelegation = decideUnDelegation({
|
|
214
|
+
triggerEvent: normalized.triggerEvent,
|
|
215
|
+
delegated,
|
|
216
|
+
currentState: existingIssue?.factoryState,
|
|
217
|
+
});
|
|
218
|
+
const clearPending = (unresolvedBlockers > 0 && existingIssue?.pendingRunType === "implementation" && !activeRun)
|
|
219
|
+
|| undelegation.clearPending;
|
|
220
|
+
const agentSessionId = decideAgentSession({
|
|
221
|
+
sessionId: normalized.agentSession?.id,
|
|
222
|
+
hasActiveRun: Boolean(activeRun),
|
|
223
|
+
hasPendingRun: Boolean(pendingRunType),
|
|
224
|
+
triggerEvent: normalized.triggerEvent,
|
|
225
|
+
delegated,
|
|
226
|
+
});
|
|
227
|
+
// ── 3. Transactional commit ──────────────────────────────────
|
|
228
|
+
const issue = this.db.transaction(() => {
|
|
229
|
+
const record = this.db.upsertIssue({
|
|
230
|
+
projectId: project.id,
|
|
231
|
+
linearIssueId: normalizedIssue.id,
|
|
232
|
+
...(hydratedIssue.identifier ? { issueKey: hydratedIssue.identifier } : {}),
|
|
233
|
+
...(hydratedIssue.title ? { title: hydratedIssue.title } : {}),
|
|
234
|
+
...(hydratedIssue.description ? { description: hydratedIssue.description } : {}),
|
|
235
|
+
...(hydratedIssue.url ? { url: hydratedIssue.url } : {}),
|
|
236
|
+
...(hydratedIssue.priority != null ? { priority: hydratedIssue.priority } : {}),
|
|
237
|
+
...(hydratedIssue.estimate != null ? { estimate: hydratedIssue.estimate } : {}),
|
|
238
|
+
...(hydratedIssue.stateName ? { currentLinearState: hydratedIssue.stateName } : {}),
|
|
239
|
+
...(hydratedIssue.stateType ? { currentLinearStateType: hydratedIssue.stateType } : {}),
|
|
240
|
+
...(pendingRunType ? { pendingRunType, factoryState: "delegated" } : {}),
|
|
241
|
+
...(clearPending ? { pendingRunType: null } : {}),
|
|
242
|
+
...((pendingRunType || existingIssue?.pendingRunType === "implementation") && pendingRunContextJson
|
|
243
|
+
? { pendingRunContextJson }
|
|
244
|
+
: {}),
|
|
245
|
+
...(agentSessionId !== undefined ? { agentSessionId } : {}),
|
|
246
|
+
...(runRelease.release ? { activeRunId: null } : {}),
|
|
247
|
+
...(undelegation.factoryState ? { factoryState: undelegation.factoryState } : {}),
|
|
248
|
+
});
|
|
249
|
+
if (runRelease.release && activeRun && runRelease.reason) {
|
|
250
|
+
this.db.finishRun(activeRun.id, { status: "released", failureReason: runRelease.reason });
|
|
225
251
|
}
|
|
226
|
-
|
|
227
|
-
// Resolve agent session
|
|
228
|
-
const agentSessionId = normalized.agentSession?.id ??
|
|
229
|
-
(!activeRun && (pendingRunType || (normalized.triggerEvent === "delegateChanged" && !delegated)) ? null : undefined);
|
|
230
|
-
// Upsert the issue
|
|
231
|
-
const issue = this.db.upsertIssue({
|
|
232
|
-
projectId: project.id,
|
|
233
|
-
linearIssueId: normalizedIssue.id,
|
|
234
|
-
...(hydratedIssue.identifier ? { issueKey: hydratedIssue.identifier } : {}),
|
|
235
|
-
...(hydratedIssue.title ? { title: hydratedIssue.title } : {}),
|
|
236
|
-
...(hydratedIssue.description ? { description: hydratedIssue.description } : {}),
|
|
237
|
-
...(hydratedIssue.url ? { url: hydratedIssue.url } : {}),
|
|
238
|
-
...(hydratedIssue.priority != null ? { priority: hydratedIssue.priority } : {}),
|
|
239
|
-
...(hydratedIssue.estimate != null ? { estimate: hydratedIssue.estimate } : {}),
|
|
240
|
-
...(hydratedIssue.stateName ? { currentLinearState: hydratedIssue.stateName } : {}),
|
|
241
|
-
...(hydratedIssue.stateType ? { currentLinearStateType: hydratedIssue.stateType } : {}),
|
|
242
|
-
...(pendingRunType ? { pendingRunType, factoryState: "delegated" } : {}),
|
|
243
|
-
...(clearPendingImplementation ? { pendingRunType: null } : {}),
|
|
244
|
-
...((pendingRunType || existingIssue?.pendingRunType === "implementation") && pendingRunContextJson
|
|
245
|
-
? { pendingRunContextJson }
|
|
246
|
-
: {}),
|
|
247
|
-
...(agentSessionId !== undefined ? { agentSessionId } : {}),
|
|
248
|
-
...(clearActiveRun ? { activeRunId: null } : {}),
|
|
249
|
-
...(undelegatedFactoryState ? { factoryState: undelegatedFactoryState } : {}),
|
|
252
|
+
return record;
|
|
250
253
|
});
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
this.db.finishRun(activeRun.id, { status: "released", failureReason: reason });
|
|
254
|
-
}
|
|
255
|
-
if (undelegatedFactoryState) {
|
|
254
|
+
// ── 4. Side effects (after transaction) ──────────────────────
|
|
255
|
+
if (undelegation.factoryState) {
|
|
256
256
|
this.feed?.publish({
|
|
257
257
|
level: "warn",
|
|
258
258
|
kind: "stage",
|
|
@@ -612,6 +612,41 @@ export class WebhookHandler {
|
|
|
612
612
|
return undefined;
|
|
613
613
|
}
|
|
614
614
|
}
|
|
615
|
+
// ─── Pure decision functions for recordDesiredStage ──────────────
|
|
616
|
+
function decideRunIntent(p) {
|
|
617
|
+
if (p.delegated && p.triggerAllowed && p.unresolvedBlockers === 0
|
|
618
|
+
&& !p.hasActiveRun && !p.hasPendingRun && !p.terminal) {
|
|
619
|
+
return "implementation";
|
|
620
|
+
}
|
|
621
|
+
return undefined;
|
|
622
|
+
}
|
|
623
|
+
function decideActiveRunRelease(p) {
|
|
624
|
+
if (!p.hasActiveRun)
|
|
625
|
+
return { release: false };
|
|
626
|
+
if (p.terminal)
|
|
627
|
+
return { release: true, reason: "Issue reached terminal state during active run" };
|
|
628
|
+
if (p.triggerEvent === "delegateChanged" && !p.delegated)
|
|
629
|
+
return { release: true, reason: "Un-delegated from PatchRelay" };
|
|
630
|
+
return { release: false };
|
|
631
|
+
}
|
|
632
|
+
function decideUnDelegation(p) {
|
|
633
|
+
if (p.triggerEvent !== "delegateChanged" || p.delegated)
|
|
634
|
+
return { clearPending: false };
|
|
635
|
+
if (!p.currentState)
|
|
636
|
+
return { clearPending: false };
|
|
637
|
+
const pastNoReturn = p.currentState === "awaiting_queue" || TERMINAL_STATES.has(p.currentState);
|
|
638
|
+
if (pastNoReturn)
|
|
639
|
+
return { clearPending: false };
|
|
640
|
+
return { factoryState: "awaiting_input", clearPending: true };
|
|
641
|
+
}
|
|
642
|
+
function decideAgentSession(p) {
|
|
643
|
+
if (p.sessionId)
|
|
644
|
+
return p.sessionId;
|
|
645
|
+
if (!p.hasActiveRun && (p.hasPendingRun || (p.triggerEvent === "delegateChanged" && !p.delegated)))
|
|
646
|
+
return null;
|
|
647
|
+
return undefined;
|
|
648
|
+
}
|
|
649
|
+
// ─── Helper predicates ──────────────────────────────────────────
|
|
615
650
|
function isResolvedLinearState(stateType, stateName) {
|
|
616
651
|
return stateType === "completed" || stateName?.trim().toLowerCase() === "done";
|
|
617
652
|
}
|