patchrelay 0.36.8 → 0.36.10
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/cluster-health.js +1 -1
- package/dist/cli/data.js +12 -10
- package/dist/cli/formatters/text.js +3 -1
- package/dist/db/issue-session-store.js +15 -23
- package/dist/db/issue-store.js +559 -0
- package/dist/db/run-store.js +10 -12
- package/dist/db.js +37 -625
- package/dist/github-webhook-handler.js +36 -20
- package/dist/idle-reconciliation.js +26 -15
- package/dist/interrupted-run-recovery.js +176 -0
- package/dist/issue-query-service.js +4 -4
- package/dist/issue-session-projector.js +114 -0
- package/dist/linear-session-sync.js +6 -6
- package/dist/queue-health-monitor.js +3 -3
- package/dist/run-completion-policy.js +412 -0
- package/dist/run-finalizer.js +34 -23
- package/dist/run-launcher.js +5 -5
- package/dist/run-orchestrator.js +46 -684
- package/dist/run-recovery-service.js +26 -18
- package/dist/run-wake-planner.js +1 -1
- package/dist/service.js +9 -9
- package/dist/webhook-handler.js +5 -5
- package/dist/webhooks/agent-session-handler.js +7 -7
- package/dist/webhooks/comment-wake-handler.js +1 -1
- package/dist/webhooks/desired-stage-recorder.js +5 -5
- package/dist/webhooks/issue-removal-handler.js +3 -3
- package/dist/worktree-manager.js +69 -0
- package/dist/zombie-recovery.js +13 -0
- package/package.json +1 -1
package/dist/db.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { isIssueSessionReadyForExecution, deriveIssueSessionState, deriveIssueSessionReactiveIntent,
|
|
2
|
-
import {
|
|
1
|
+
import { isIssueSessionReadyForExecution, deriveIssueSessionState, deriveIssueSessionReactiveIntent, } from "./issue-session.js";
|
|
2
|
+
import {} from "./issue-session-events.js";
|
|
3
|
+
import { IssueStore } from "./db/issue-store.js";
|
|
3
4
|
import { IssueSessionStore } from "./db/issue-session-store.js";
|
|
4
5
|
import { LinearInstallationStore } from "./db/linear-installation-store.js";
|
|
5
6
|
import { OperatorFeedStore } from "./db/operator-feed-store.js";
|
|
@@ -7,7 +8,8 @@ import { RepositoryLinkStore } from "./db/repository-link-store.js";
|
|
|
7
8
|
import { RunStore } from "./db/run-store.js";
|
|
8
9
|
import { WebhookEventStore } from "./db/webhook-event-store.js";
|
|
9
10
|
import { runPatchRelayMigrations } from "./db/migrations.js";
|
|
10
|
-
import { SqliteConnection
|
|
11
|
+
import { SqliteConnection } from "./db/shared.js";
|
|
12
|
+
import { syncIssueSessionFromIssue } from "./issue-session-projector.js";
|
|
11
13
|
import { buildTrackedIssueRecord } from "./tracked-issue-projector.js";
|
|
12
14
|
function parseObjectJson(raw) {
|
|
13
15
|
if (!raw)
|
|
@@ -92,6 +94,7 @@ export class PatchRelayDatabase {
|
|
|
92
94
|
operatorFeed;
|
|
93
95
|
repositories;
|
|
94
96
|
webhookEvents;
|
|
97
|
+
issues;
|
|
95
98
|
issueSessions;
|
|
96
99
|
runs;
|
|
97
100
|
constructor(databasePath, wal) {
|
|
@@ -104,8 +107,16 @@ export class PatchRelayDatabase {
|
|
|
104
107
|
this.operatorFeed = new OperatorFeedStore(this.connection);
|
|
105
108
|
this.repositories = new RepositoryLinkStore(this.connection);
|
|
106
109
|
this.webhookEvents = new WebhookEventStore(this.connection);
|
|
107
|
-
this.
|
|
108
|
-
this.runs = new RunStore(this.connection, mapRunRow,
|
|
110
|
+
this.issues = new IssueStore(this.connection, (issue) => syncIssueSessionFromIssue({ connection: this.connection, issues: this.issues, issueSessions: this.issueSessions, runs: this.runs, issue }));
|
|
111
|
+
this.runs = new RunStore(this.connection, mapRunRow, this.issues, (issue, options) => syncIssueSessionFromIssue({
|
|
112
|
+
connection: this.connection,
|
|
113
|
+
issues: this.issues,
|
|
114
|
+
issueSessions: this.issueSessions,
|
|
115
|
+
runs: this.runs,
|
|
116
|
+
issue,
|
|
117
|
+
...(options ? { options } : {}),
|
|
118
|
+
}));
|
|
119
|
+
this.issueSessions = new IssueSessionStore(this.connection, mapIssueSessionRow, mapIssueSessionEventRow, this.issues, this.runs, deriveImplicitReactiveWake);
|
|
109
120
|
}
|
|
110
121
|
runMigrations() {
|
|
111
122
|
runPatchRelayMigrations(this.connection);
|
|
@@ -113,415 +124,44 @@ export class PatchRelayDatabase {
|
|
|
113
124
|
transaction(fn) {
|
|
114
125
|
return this.connection.transaction(fn)();
|
|
115
126
|
}
|
|
116
|
-
// ─── Issues ───────────────────────────────────────────────────────
|
|
117
127
|
upsertIssue(params) {
|
|
118
|
-
|
|
119
|
-
const existing = this.getIssue(params.projectId, params.linearIssueId);
|
|
120
|
-
if (existing) {
|
|
121
|
-
// Build dynamic SET clauses for nullable fields
|
|
122
|
-
const sets = ["updated_at = @now"];
|
|
123
|
-
const values = {
|
|
124
|
-
now,
|
|
125
|
-
projectId: params.projectId,
|
|
126
|
-
linearIssueId: params.linearIssueId,
|
|
127
|
-
};
|
|
128
|
-
if (params.issueKey !== undefined) {
|
|
129
|
-
sets.push("issue_key = COALESCE(@issueKey, issue_key)");
|
|
130
|
-
values.issueKey = params.issueKey;
|
|
131
|
-
}
|
|
132
|
-
if (params.title !== undefined) {
|
|
133
|
-
sets.push("title = COALESCE(@title, title)");
|
|
134
|
-
values.title = params.title;
|
|
135
|
-
}
|
|
136
|
-
if (params.description !== undefined) {
|
|
137
|
-
sets.push("description = COALESCE(@description, description)");
|
|
138
|
-
values.description = params.description;
|
|
139
|
-
}
|
|
140
|
-
if (params.url !== undefined) {
|
|
141
|
-
sets.push("url = COALESCE(@url, url)");
|
|
142
|
-
values.url = params.url;
|
|
143
|
-
}
|
|
144
|
-
if (params.priority !== undefined) {
|
|
145
|
-
sets.push("priority = @priority");
|
|
146
|
-
values.priority = params.priority;
|
|
147
|
-
}
|
|
148
|
-
if (params.estimate !== undefined) {
|
|
149
|
-
sets.push("estimate = @estimate");
|
|
150
|
-
values.estimate = params.estimate;
|
|
151
|
-
}
|
|
152
|
-
if (params.currentLinearState !== undefined) {
|
|
153
|
-
sets.push("current_linear_state = COALESCE(@currentLinearState, current_linear_state)");
|
|
154
|
-
values.currentLinearState = params.currentLinearState;
|
|
155
|
-
}
|
|
156
|
-
if (params.currentLinearStateType !== undefined) {
|
|
157
|
-
sets.push("current_linear_state_type = COALESCE(@currentLinearStateType, current_linear_state_type)");
|
|
158
|
-
values.currentLinearStateType = params.currentLinearStateType;
|
|
159
|
-
}
|
|
160
|
-
if (params.factoryState !== undefined) {
|
|
161
|
-
sets.push("factory_state = @factoryState");
|
|
162
|
-
values.factoryState = params.factoryState;
|
|
163
|
-
}
|
|
164
|
-
if (params.pendingRunType !== undefined) {
|
|
165
|
-
sets.push("pending_run_type = @pendingRunType");
|
|
166
|
-
values.pendingRunType = params.pendingRunType;
|
|
167
|
-
}
|
|
168
|
-
if (params.pendingRunContextJson !== undefined) {
|
|
169
|
-
sets.push("pending_run_context_json = @pendingRunContextJson");
|
|
170
|
-
values.pendingRunContextJson = params.pendingRunContextJson;
|
|
171
|
-
}
|
|
172
|
-
if (params.branchName !== undefined) {
|
|
173
|
-
sets.push("branch_name = COALESCE(@branchName, branch_name)");
|
|
174
|
-
values.branchName = params.branchName;
|
|
175
|
-
}
|
|
176
|
-
if (params.worktreePath !== undefined) {
|
|
177
|
-
sets.push("worktree_path = COALESCE(@worktreePath, worktree_path)");
|
|
178
|
-
values.worktreePath = params.worktreePath;
|
|
179
|
-
}
|
|
180
|
-
if (params.threadId !== undefined) {
|
|
181
|
-
sets.push("thread_id = @threadId");
|
|
182
|
-
values.threadId = params.threadId;
|
|
183
|
-
}
|
|
184
|
-
if (params.activeRunId !== undefined) {
|
|
185
|
-
sets.push("active_run_id = @activeRunId");
|
|
186
|
-
values.activeRunId = params.activeRunId;
|
|
187
|
-
}
|
|
188
|
-
if (params.statusCommentId !== undefined) {
|
|
189
|
-
sets.push("status_comment_id = @statusCommentId");
|
|
190
|
-
values.statusCommentId = params.statusCommentId;
|
|
191
|
-
}
|
|
192
|
-
if (params.agentSessionId !== undefined) {
|
|
193
|
-
sets.push("agent_session_id = @agentSessionId");
|
|
194
|
-
values.agentSessionId = params.agentSessionId;
|
|
195
|
-
}
|
|
196
|
-
if (params.prNumber !== undefined) {
|
|
197
|
-
sets.push("pr_number = @prNumber");
|
|
198
|
-
values.prNumber = params.prNumber;
|
|
199
|
-
}
|
|
200
|
-
if (params.prUrl !== undefined) {
|
|
201
|
-
sets.push("pr_url = @prUrl");
|
|
202
|
-
values.prUrl = params.prUrl;
|
|
203
|
-
}
|
|
204
|
-
if (params.prState !== undefined) {
|
|
205
|
-
sets.push("pr_state = @prState");
|
|
206
|
-
values.prState = params.prState;
|
|
207
|
-
}
|
|
208
|
-
if (params.prHeadSha !== undefined) {
|
|
209
|
-
sets.push("pr_head_sha = @prHeadSha");
|
|
210
|
-
values.prHeadSha = params.prHeadSha;
|
|
211
|
-
}
|
|
212
|
-
if (params.prAuthorLogin !== undefined) {
|
|
213
|
-
sets.push("pr_author_login = @prAuthorLogin");
|
|
214
|
-
values.prAuthorLogin = params.prAuthorLogin;
|
|
215
|
-
}
|
|
216
|
-
if (params.prReviewState !== undefined) {
|
|
217
|
-
sets.push("pr_review_state = @prReviewState");
|
|
218
|
-
values.prReviewState = params.prReviewState;
|
|
219
|
-
}
|
|
220
|
-
if (params.prCheckStatus !== undefined) {
|
|
221
|
-
sets.push("pr_check_status = @prCheckStatus");
|
|
222
|
-
values.prCheckStatus = params.prCheckStatus;
|
|
223
|
-
}
|
|
224
|
-
if (params.lastBlockingReviewHeadSha !== undefined) {
|
|
225
|
-
sets.push("last_blocking_review_head_sha = @lastBlockingReviewHeadSha");
|
|
226
|
-
values.lastBlockingReviewHeadSha = params.lastBlockingReviewHeadSha;
|
|
227
|
-
}
|
|
228
|
-
if (params.lastGitHubFailureSource !== undefined) {
|
|
229
|
-
sets.push("last_github_failure_source = @lastGitHubFailureSource");
|
|
230
|
-
values.lastGitHubFailureSource = params.lastGitHubFailureSource;
|
|
231
|
-
}
|
|
232
|
-
if (params.lastGitHubFailureHeadSha !== undefined) {
|
|
233
|
-
sets.push("last_github_failure_head_sha = @lastGitHubFailureHeadSha");
|
|
234
|
-
values.lastGitHubFailureHeadSha = params.lastGitHubFailureHeadSha;
|
|
235
|
-
}
|
|
236
|
-
if (params.lastGitHubFailureSignature !== undefined) {
|
|
237
|
-
sets.push("last_github_failure_signature = @lastGitHubFailureSignature");
|
|
238
|
-
values.lastGitHubFailureSignature = params.lastGitHubFailureSignature;
|
|
239
|
-
}
|
|
240
|
-
if (params.lastGitHubFailureCheckName !== undefined) {
|
|
241
|
-
sets.push("last_github_failure_check_name = @lastGitHubFailureCheckName");
|
|
242
|
-
values.lastGitHubFailureCheckName = params.lastGitHubFailureCheckName;
|
|
243
|
-
}
|
|
244
|
-
if (params.lastGitHubFailureCheckUrl !== undefined) {
|
|
245
|
-
sets.push("last_github_failure_check_url = @lastGitHubFailureCheckUrl");
|
|
246
|
-
values.lastGitHubFailureCheckUrl = params.lastGitHubFailureCheckUrl;
|
|
247
|
-
}
|
|
248
|
-
if (params.lastGitHubFailureContextJson !== undefined) {
|
|
249
|
-
sets.push("last_github_failure_context_json = @lastGitHubFailureContextJson");
|
|
250
|
-
values.lastGitHubFailureContextJson = params.lastGitHubFailureContextJson;
|
|
251
|
-
}
|
|
252
|
-
if (params.lastGitHubFailureAt !== undefined) {
|
|
253
|
-
sets.push("last_github_failure_at = @lastGitHubFailureAt");
|
|
254
|
-
values.lastGitHubFailureAt = params.lastGitHubFailureAt;
|
|
255
|
-
}
|
|
256
|
-
if (params.lastGitHubCiSnapshotHeadSha !== undefined) {
|
|
257
|
-
sets.push("last_github_ci_snapshot_head_sha = @lastGitHubCiSnapshotHeadSha");
|
|
258
|
-
values.lastGitHubCiSnapshotHeadSha = params.lastGitHubCiSnapshotHeadSha;
|
|
259
|
-
}
|
|
260
|
-
if (params.lastGitHubCiSnapshotGateCheckName !== undefined) {
|
|
261
|
-
sets.push("last_github_ci_snapshot_gate_check_name = @lastGitHubCiSnapshotGateCheckName");
|
|
262
|
-
values.lastGitHubCiSnapshotGateCheckName = params.lastGitHubCiSnapshotGateCheckName;
|
|
263
|
-
}
|
|
264
|
-
if (params.lastGitHubCiSnapshotGateCheckStatus !== undefined) {
|
|
265
|
-
sets.push("last_github_ci_snapshot_gate_check_status = @lastGitHubCiSnapshotGateCheckStatus");
|
|
266
|
-
values.lastGitHubCiSnapshotGateCheckStatus = params.lastGitHubCiSnapshotGateCheckStatus;
|
|
267
|
-
}
|
|
268
|
-
if (params.lastGitHubCiSnapshotJson !== undefined) {
|
|
269
|
-
sets.push("last_github_ci_snapshot_json = @lastGitHubCiSnapshotJson");
|
|
270
|
-
values.lastGitHubCiSnapshotJson = params.lastGitHubCiSnapshotJson;
|
|
271
|
-
}
|
|
272
|
-
if (params.lastGitHubCiSnapshotSettledAt !== undefined) {
|
|
273
|
-
sets.push("last_github_ci_snapshot_settled_at = @lastGitHubCiSnapshotSettledAt");
|
|
274
|
-
values.lastGitHubCiSnapshotSettledAt = params.lastGitHubCiSnapshotSettledAt;
|
|
275
|
-
}
|
|
276
|
-
if (params.lastQueueSignalAt !== undefined) {
|
|
277
|
-
sets.push("last_queue_signal_at = @lastQueueSignalAt");
|
|
278
|
-
values.lastQueueSignalAt = params.lastQueueSignalAt;
|
|
279
|
-
}
|
|
280
|
-
if (params.lastQueueIncidentJson !== undefined) {
|
|
281
|
-
sets.push("last_queue_incident_json = @lastQueueIncidentJson");
|
|
282
|
-
values.lastQueueIncidentJson = params.lastQueueIncidentJson;
|
|
283
|
-
}
|
|
284
|
-
if (params.lastAttemptedFailureHeadSha !== undefined) {
|
|
285
|
-
sets.push("last_attempted_failure_head_sha = @lastAttemptedFailureHeadSha");
|
|
286
|
-
values.lastAttemptedFailureHeadSha = params.lastAttemptedFailureHeadSha;
|
|
287
|
-
}
|
|
288
|
-
if (params.lastAttemptedFailureSignature !== undefined) {
|
|
289
|
-
sets.push("last_attempted_failure_signature = @lastAttemptedFailureSignature");
|
|
290
|
-
values.lastAttemptedFailureSignature = params.lastAttemptedFailureSignature;
|
|
291
|
-
}
|
|
292
|
-
if (params.ciRepairAttempts !== undefined) {
|
|
293
|
-
sets.push("ci_repair_attempts = @ciRepairAttempts");
|
|
294
|
-
values.ciRepairAttempts = params.ciRepairAttempts;
|
|
295
|
-
}
|
|
296
|
-
if (params.queueRepairAttempts !== undefined) {
|
|
297
|
-
sets.push("queue_repair_attempts = @queueRepairAttempts");
|
|
298
|
-
values.queueRepairAttempts = params.queueRepairAttempts;
|
|
299
|
-
}
|
|
300
|
-
if (params.reviewFixAttempts !== undefined) {
|
|
301
|
-
sets.push("review_fix_attempts = @reviewFixAttempts");
|
|
302
|
-
values.reviewFixAttempts = params.reviewFixAttempts;
|
|
303
|
-
}
|
|
304
|
-
if (params.zombieRecoveryAttempts !== undefined) {
|
|
305
|
-
sets.push("zombie_recovery_attempts = @zombieRecoveryAttempts");
|
|
306
|
-
values.zombieRecoveryAttempts = params.zombieRecoveryAttempts;
|
|
307
|
-
}
|
|
308
|
-
if (params.lastZombieRecoveryAt !== undefined) {
|
|
309
|
-
sets.push("last_zombie_recovery_at = @lastZombieRecoveryAt");
|
|
310
|
-
values.lastZombieRecoveryAt = params.lastZombieRecoveryAt;
|
|
311
|
-
}
|
|
312
|
-
this.connection.prepare(`UPDATE issues SET ${sets.join(", ")} WHERE project_id = @projectId AND linear_issue_id = @linearIssueId`).run(values);
|
|
313
|
-
}
|
|
314
|
-
else {
|
|
315
|
-
this.connection.prepare(`
|
|
316
|
-
INSERT INTO issues (
|
|
317
|
-
project_id, linear_issue_id, issue_key, title, description, url,
|
|
318
|
-
priority, estimate,
|
|
319
|
-
current_linear_state, current_linear_state_type, factory_state, pending_run_type, pending_run_context_json,
|
|
320
|
-
branch_name, worktree_path, thread_id, active_run_id, status_comment_id,
|
|
321
|
-
agent_session_id,
|
|
322
|
-
pr_number, pr_url, pr_state, pr_head_sha, pr_author_login, pr_review_state, pr_check_status, last_blocking_review_head_sha,
|
|
323
|
-
last_github_failure_source, last_github_failure_head_sha, last_github_failure_signature, last_github_failure_check_name, last_github_failure_check_url, last_github_failure_context_json, last_github_failure_at,
|
|
324
|
-
last_github_ci_snapshot_head_sha, last_github_ci_snapshot_gate_check_name, last_github_ci_snapshot_gate_check_status, last_github_ci_snapshot_json, last_github_ci_snapshot_settled_at,
|
|
325
|
-
last_queue_signal_at, last_queue_incident_json,
|
|
326
|
-
last_attempted_failure_head_sha, last_attempted_failure_signature,
|
|
327
|
-
ci_repair_attempts, queue_repair_attempts, review_fix_attempts, zombie_recovery_attempts, last_zombie_recovery_at,
|
|
328
|
-
updated_at
|
|
329
|
-
) VALUES (
|
|
330
|
-
@projectId, @linearIssueId, @issueKey, @title, @description, @url,
|
|
331
|
-
@priority, @estimate,
|
|
332
|
-
@currentLinearState, @currentLinearStateType, @factoryState, @pendingRunType, @pendingRunContextJson,
|
|
333
|
-
@branchName, @worktreePath, @threadId, @activeRunId, @statusCommentId,
|
|
334
|
-
@agentSessionId,
|
|
335
|
-
@prNumber, @prUrl, @prState, @prHeadSha, @prAuthorLogin, @prReviewState, @prCheckStatus, @lastBlockingReviewHeadSha,
|
|
336
|
-
@lastGitHubFailureSource, @lastGitHubFailureHeadSha, @lastGitHubFailureSignature, @lastGitHubFailureCheckName, @lastGitHubFailureCheckUrl, @lastGitHubFailureContextJson, @lastGitHubFailureAt,
|
|
337
|
-
@lastGitHubCiSnapshotHeadSha, @lastGitHubCiSnapshotGateCheckName, @lastGitHubCiSnapshotGateCheckStatus, @lastGitHubCiSnapshotJson, @lastGitHubCiSnapshotSettledAt,
|
|
338
|
-
@lastQueueSignalAt, @lastQueueIncidentJson,
|
|
339
|
-
@lastAttemptedFailureHeadSha, @lastAttemptedFailureSignature,
|
|
340
|
-
@ciRepairAttempts, @queueRepairAttempts, @reviewFixAttempts, @zombieRecoveryAttempts, @lastZombieRecoveryAt,
|
|
341
|
-
@now
|
|
342
|
-
)
|
|
343
|
-
`).run({
|
|
344
|
-
projectId: params.projectId,
|
|
345
|
-
linearIssueId: params.linearIssueId,
|
|
346
|
-
issueKey: params.issueKey ?? null,
|
|
347
|
-
title: params.title ?? null,
|
|
348
|
-
description: params.description ?? null,
|
|
349
|
-
url: params.url ?? null,
|
|
350
|
-
priority: params.priority ?? null,
|
|
351
|
-
estimate: params.estimate ?? null,
|
|
352
|
-
currentLinearState: params.currentLinearState ?? null,
|
|
353
|
-
currentLinearStateType: params.currentLinearStateType ?? null,
|
|
354
|
-
factoryState: params.factoryState ?? "delegated",
|
|
355
|
-
pendingRunType: params.pendingRunType ?? null,
|
|
356
|
-
pendingRunContextJson: params.pendingRunContextJson ?? null,
|
|
357
|
-
branchName: params.branchName ?? null,
|
|
358
|
-
worktreePath: params.worktreePath ?? null,
|
|
359
|
-
threadId: params.threadId ?? null,
|
|
360
|
-
activeRunId: params.activeRunId ?? null,
|
|
361
|
-
statusCommentId: params.statusCommentId ?? null,
|
|
362
|
-
agentSessionId: params.agentSessionId ?? null,
|
|
363
|
-
prNumber: params.prNumber ?? null,
|
|
364
|
-
prUrl: params.prUrl ?? null,
|
|
365
|
-
prState: params.prState ?? null,
|
|
366
|
-
prHeadSha: params.prHeadSha ?? null,
|
|
367
|
-
prAuthorLogin: params.prAuthorLogin ?? null,
|
|
368
|
-
prReviewState: params.prReviewState ?? null,
|
|
369
|
-
prCheckStatus: params.prCheckStatus ?? null,
|
|
370
|
-
lastBlockingReviewHeadSha: params.lastBlockingReviewHeadSha ?? null,
|
|
371
|
-
lastGitHubFailureSource: params.lastGitHubFailureSource ?? null,
|
|
372
|
-
lastGitHubFailureHeadSha: params.lastGitHubFailureHeadSha ?? null,
|
|
373
|
-
lastGitHubFailureSignature: params.lastGitHubFailureSignature ?? null,
|
|
374
|
-
lastGitHubFailureCheckName: params.lastGitHubFailureCheckName ?? null,
|
|
375
|
-
lastGitHubFailureCheckUrl: params.lastGitHubFailureCheckUrl ?? null,
|
|
376
|
-
lastGitHubFailureContextJson: params.lastGitHubFailureContextJson ?? null,
|
|
377
|
-
lastGitHubFailureAt: params.lastGitHubFailureAt ?? null,
|
|
378
|
-
lastGitHubCiSnapshotHeadSha: params.lastGitHubCiSnapshotHeadSha ?? null,
|
|
379
|
-
lastGitHubCiSnapshotGateCheckName: params.lastGitHubCiSnapshotGateCheckName ?? null,
|
|
380
|
-
lastGitHubCiSnapshotGateCheckStatus: params.lastGitHubCiSnapshotGateCheckStatus ?? null,
|
|
381
|
-
lastGitHubCiSnapshotJson: params.lastGitHubCiSnapshotJson ?? null,
|
|
382
|
-
lastGitHubCiSnapshotSettledAt: params.lastGitHubCiSnapshotSettledAt ?? null,
|
|
383
|
-
lastQueueSignalAt: params.lastQueueSignalAt ?? null,
|
|
384
|
-
lastQueueIncidentJson: params.lastQueueIncidentJson ?? null,
|
|
385
|
-
lastAttemptedFailureHeadSha: params.lastAttemptedFailureHeadSha ?? null,
|
|
386
|
-
lastAttemptedFailureSignature: params.lastAttemptedFailureSignature ?? null,
|
|
387
|
-
ciRepairAttempts: params.ciRepairAttempts ?? 0,
|
|
388
|
-
queueRepairAttempts: params.queueRepairAttempts ?? 0,
|
|
389
|
-
reviewFixAttempts: params.reviewFixAttempts ?? 0,
|
|
390
|
-
zombieRecoveryAttempts: params.zombieRecoveryAttempts ?? 0,
|
|
391
|
-
lastZombieRecoveryAt: params.lastZombieRecoveryAt ?? null,
|
|
392
|
-
now,
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
const updated = this.getIssue(params.projectId, params.linearIssueId);
|
|
396
|
-
this.syncIssueSessionFromIssue(updated);
|
|
397
|
-
return updated;
|
|
128
|
+
return this.issues.upsertIssue(params);
|
|
398
129
|
}
|
|
399
130
|
getIssue(projectId, linearIssueId) {
|
|
400
|
-
|
|
401
|
-
.prepare("SELECT * FROM issues WHERE project_id = ? AND linear_issue_id = ?")
|
|
402
|
-
.get(projectId, linearIssueId);
|
|
403
|
-
return row ? mapIssueRow(row) : undefined;
|
|
131
|
+
return this.issues.getIssue(projectId, linearIssueId);
|
|
404
132
|
}
|
|
405
133
|
getIssueById(id) {
|
|
406
|
-
|
|
407
|
-
return row ? mapIssueRow(row) : undefined;
|
|
134
|
+
return this.issues.getIssueById(id);
|
|
408
135
|
}
|
|
409
136
|
getIssueByKey(issueKey) {
|
|
410
|
-
|
|
411
|
-
return row ? mapIssueRow(row) : undefined;
|
|
137
|
+
return this.issues.getIssueByKey(issueKey);
|
|
412
138
|
}
|
|
413
139
|
getIssueByBranch(branchName) {
|
|
414
|
-
|
|
415
|
-
return row ? mapIssueRow(row) : undefined;
|
|
140
|
+
return this.issues.getIssueByBranch(branchName);
|
|
416
141
|
}
|
|
417
142
|
getIssueByPrNumber(prNumber) {
|
|
418
|
-
|
|
419
|
-
return row ? mapIssueRow(row) : undefined;
|
|
143
|
+
return this.issues.getIssueByPrNumber(prNumber);
|
|
420
144
|
}
|
|
421
145
|
setBranchOwner(projectId, linearIssueId, owner) {
|
|
422
|
-
this.
|
|
423
|
-
UPDATE issues
|
|
424
|
-
SET branch_owner = ?, branch_ownership_changed_at = ?, updated_at = ?
|
|
425
|
-
WHERE project_id = ? AND linear_issue_id = ?
|
|
426
|
-
`).run(owner, isoNow(), isoNow(), projectId, linearIssueId);
|
|
146
|
+
this.issues.setBranchOwner(projectId, linearIssueId, owner);
|
|
427
147
|
}
|
|
428
148
|
replaceIssueDependencies(params) {
|
|
429
|
-
|
|
430
|
-
this.connection
|
|
431
|
-
.prepare("DELETE FROM issue_dependencies WHERE project_id = ? AND linear_issue_id = ?")
|
|
432
|
-
.run(params.projectId, params.linearIssueId);
|
|
433
|
-
if (params.blockers.length === 0) {
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
const insert = this.connection.prepare(`
|
|
437
|
-
INSERT INTO issue_dependencies (
|
|
438
|
-
project_id,
|
|
439
|
-
linear_issue_id,
|
|
440
|
-
blocker_linear_issue_id,
|
|
441
|
-
blocker_issue_key,
|
|
442
|
-
blocker_title,
|
|
443
|
-
blocker_current_linear_state,
|
|
444
|
-
blocker_current_linear_state_type,
|
|
445
|
-
updated_at
|
|
446
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
447
|
-
`);
|
|
448
|
-
for (const blocker of params.blockers) {
|
|
449
|
-
insert.run(params.projectId, params.linearIssueId, blocker.blockerLinearIssueId, blocker.blockerIssueKey ?? null, blocker.blockerTitle ?? null, blocker.blockerCurrentLinearState ?? null, blocker.blockerCurrentLinearStateType ?? null, now);
|
|
450
|
-
}
|
|
149
|
+
this.issues.replaceIssueDependencies(params);
|
|
451
150
|
}
|
|
452
151
|
listIssueDependencies(projectId, linearIssueId) {
|
|
453
|
-
|
|
454
|
-
SELECT
|
|
455
|
-
d.project_id,
|
|
456
|
-
d.linear_issue_id,
|
|
457
|
-
d.blocker_linear_issue_id,
|
|
458
|
-
COALESCE(blockers.issue_key, d.blocker_issue_key) AS blocker_issue_key,
|
|
459
|
-
COALESCE(blockers.title, d.blocker_title) AS blocker_title,
|
|
460
|
-
COALESCE(blockers.current_linear_state, d.blocker_current_linear_state) AS blocker_current_linear_state,
|
|
461
|
-
COALESCE(blockers.current_linear_state_type, d.blocker_current_linear_state_type) AS blocker_current_linear_state_type,
|
|
462
|
-
d.updated_at
|
|
463
|
-
FROM issue_dependencies d
|
|
464
|
-
LEFT JOIN issues blockers
|
|
465
|
-
ON blockers.project_id = d.project_id
|
|
466
|
-
AND blockers.linear_issue_id = d.blocker_linear_issue_id
|
|
467
|
-
WHERE d.project_id = ? AND d.linear_issue_id = ?
|
|
468
|
-
ORDER BY COALESCE(blockers.issue_key, d.blocker_issue_key, d.blocker_linear_issue_id) ASC
|
|
469
|
-
`).all(projectId, linearIssueId);
|
|
470
|
-
return rows.map((row) => ({
|
|
471
|
-
projectId: String(row.project_id),
|
|
472
|
-
linearIssueId: String(row.linear_issue_id),
|
|
473
|
-
blockerLinearIssueId: String(row.blocker_linear_issue_id),
|
|
474
|
-
...(row.blocker_issue_key !== null && row.blocker_issue_key !== undefined ? { blockerIssueKey: String(row.blocker_issue_key) } : {}),
|
|
475
|
-
...(row.blocker_title !== null && row.blocker_title !== undefined ? { blockerTitle: String(row.blocker_title) } : {}),
|
|
476
|
-
...(row.blocker_current_linear_state !== null && row.blocker_current_linear_state !== undefined
|
|
477
|
-
? { blockerCurrentLinearState: String(row.blocker_current_linear_state) }
|
|
478
|
-
: {}),
|
|
479
|
-
...(row.blocker_current_linear_state_type !== null && row.blocker_current_linear_state_type !== undefined
|
|
480
|
-
? { blockerCurrentLinearStateType: String(row.blocker_current_linear_state_type) }
|
|
481
|
-
: {}),
|
|
482
|
-
updatedAt: String(row.updated_at),
|
|
483
|
-
}));
|
|
152
|
+
return this.issues.listIssueDependencies(projectId, linearIssueId);
|
|
484
153
|
}
|
|
485
154
|
listDependents(projectId, blockerLinearIssueId) {
|
|
486
|
-
|
|
487
|
-
SELECT project_id, linear_issue_id
|
|
488
|
-
FROM issue_dependencies
|
|
489
|
-
WHERE project_id = ? AND blocker_linear_issue_id = ?
|
|
490
|
-
ORDER BY linear_issue_id ASC
|
|
491
|
-
`).all(projectId, blockerLinearIssueId);
|
|
492
|
-
return rows.map((row) => ({
|
|
493
|
-
projectId: String(row.project_id),
|
|
494
|
-
linearIssueId: String(row.linear_issue_id),
|
|
495
|
-
}));
|
|
155
|
+
return this.issues.listDependents(projectId, blockerLinearIssueId);
|
|
496
156
|
}
|
|
497
157
|
getLatestGitHubCiSnapshot(projectId, linearIssueId) {
|
|
498
|
-
|
|
499
|
-
if (!issue?.lastGitHubCiSnapshotJson)
|
|
500
|
-
return undefined;
|
|
501
|
-
try {
|
|
502
|
-
return JSON.parse(issue.lastGitHubCiSnapshotJson);
|
|
503
|
-
}
|
|
504
|
-
catch {
|
|
505
|
-
return undefined;
|
|
506
|
-
}
|
|
158
|
+
return this.issues.getLatestGitHubCiSnapshot(projectId, linearIssueId);
|
|
507
159
|
}
|
|
508
160
|
countUnresolvedBlockers(projectId, linearIssueId) {
|
|
509
|
-
|
|
510
|
-
SELECT COUNT(*) AS count
|
|
511
|
-
FROM issue_dependencies d
|
|
512
|
-
LEFT JOIN issues blockers
|
|
513
|
-
ON blockers.project_id = d.project_id
|
|
514
|
-
AND blockers.linear_issue_id = d.blocker_linear_issue_id
|
|
515
|
-
WHERE d.project_id = ? AND d.linear_issue_id = ?
|
|
516
|
-
AND (
|
|
517
|
-
COALESCE(blockers.current_linear_state_type, d.blocker_current_linear_state_type, '') != 'completed'
|
|
518
|
-
AND LOWER(TRIM(COALESCE(blockers.current_linear_state, d.blocker_current_linear_state, ''))) != 'done'
|
|
519
|
-
)
|
|
520
|
-
`).get(projectId, linearIssueId);
|
|
521
|
-
return Number(row?.count ?? 0);
|
|
161
|
+
return this.issues.countUnresolvedBlockers(projectId, linearIssueId);
|
|
522
162
|
}
|
|
523
163
|
listIssuesReadyForExecution() {
|
|
524
|
-
return this.listIssues()
|
|
164
|
+
return this.issues.listIssues()
|
|
525
165
|
.filter((issue) => isIssueSessionReadyForExecution({
|
|
526
166
|
factoryState: issue.factoryState,
|
|
527
167
|
sessionState: deriveIssueSessionState({
|
|
@@ -529,7 +169,7 @@ export class PatchRelayDatabase {
|
|
|
529
169
|
factoryState: issue.factoryState,
|
|
530
170
|
}),
|
|
531
171
|
activeRunId: issue.activeRunId,
|
|
532
|
-
blockedByCount: this.countUnresolvedBlockers(issue.projectId, issue.linearIssueId),
|
|
172
|
+
blockedByCount: this.issues.countUnresolvedBlockers(issue.projectId, issue.linearIssueId),
|
|
533
173
|
hasPendingWake: this.issueSessions.peekIssueSessionWake(issue.projectId, issue.linearIssueId) !== undefined,
|
|
534
174
|
hasLegacyPendingRun: issue.pendingRunType !== undefined,
|
|
535
175
|
prNumber: issue.prNumber,
|
|
@@ -548,55 +188,31 @@ export class PatchRelayDatabase {
|
|
|
548
188
|
* advancement based on stored PR metadata (missed GitHub webhooks).
|
|
549
189
|
*/
|
|
550
190
|
listIdleNonTerminalIssues() {
|
|
551
|
-
|
|
552
|
-
.prepare(`SELECT * FROM issues
|
|
553
|
-
WHERE factory_state NOT IN ('done', 'escalated', 'failed', 'awaiting_input')
|
|
554
|
-
AND active_run_id IS NULL
|
|
555
|
-
AND pending_run_type IS NULL
|
|
556
|
-
AND pr_number IS NOT NULL`)
|
|
557
|
-
.all();
|
|
558
|
-
return rows.map(mapIssueRow);
|
|
191
|
+
return this.issues.listIdleNonTerminalIssues();
|
|
559
192
|
}
|
|
560
193
|
/**
|
|
561
194
|
* Issues in delegated state with dependencies but no pending/active run.
|
|
562
195
|
* Candidates for unblocking when their blockers complete.
|
|
563
196
|
*/
|
|
564
197
|
listBlockedDelegatedIssues() {
|
|
565
|
-
|
|
566
|
-
.prepare(`SELECT DISTINCT i.* FROM issues i
|
|
567
|
-
JOIN issue_dependencies d ON d.project_id = i.project_id AND d.linear_issue_id = i.linear_issue_id
|
|
568
|
-
WHERE i.factory_state = 'delegated'
|
|
569
|
-
AND i.active_run_id IS NULL
|
|
570
|
-
AND i.pending_run_type IS NULL`)
|
|
571
|
-
.all();
|
|
572
|
-
return rows.map(mapIssueRow);
|
|
198
|
+
return this.issues.listBlockedDelegatedIssues();
|
|
573
199
|
}
|
|
574
200
|
/**
|
|
575
201
|
* Issues waiting in the merge queue with no active or pending run.
|
|
576
202
|
* Used by the queue health monitor to probe GitHub for stuck PRs.
|
|
577
203
|
*/
|
|
578
204
|
listAwaitingQueueIssues() {
|
|
579
|
-
|
|
580
|
-
.prepare(`SELECT * FROM issues
|
|
581
|
-
WHERE factory_state = 'awaiting_queue'
|
|
582
|
-
AND active_run_id IS NULL
|
|
583
|
-
AND pending_run_type IS NULL
|
|
584
|
-
AND pr_number IS NOT NULL`)
|
|
585
|
-
.all();
|
|
586
|
-
return rows.map(mapIssueRow);
|
|
205
|
+
return this.issues.listAwaitingQueueIssues();
|
|
587
206
|
}
|
|
588
207
|
listIssuesByState(projectId, state) {
|
|
589
|
-
|
|
590
|
-
.prepare("SELECT * FROM issues WHERE project_id = ? AND factory_state = ? ORDER BY pr_number ASC")
|
|
591
|
-
.all(projectId, state);
|
|
592
|
-
return rows.map(mapIssueRow);
|
|
208
|
+
return this.issues.listIssuesByState(projectId, state);
|
|
593
209
|
}
|
|
594
210
|
// ─── View builders ──────────────────────────────────────────────
|
|
595
211
|
issueToTrackedIssue(issue) {
|
|
596
212
|
return buildTrackedIssueRecord({
|
|
597
213
|
issue,
|
|
598
214
|
session: this.issueSessions.getIssueSession(issue.projectId, issue.linearIssueId),
|
|
599
|
-
blockedBy: this.listIssueDependencies(issue.projectId, issue.linearIssueId),
|
|
215
|
+
blockedBy: this.issues.listIssueDependencies(issue.projectId, issue.linearIssueId),
|
|
600
216
|
hasPendingWake: this.issueSessions.peekIssueSessionWake(issue.projectId, issue.linearIssueId) !== undefined,
|
|
601
217
|
latestRun: this.runs.getLatestRunForIssue(issue.projectId, issue.linearIssueId),
|
|
602
218
|
latestEvent: this.issueSessions.listIssueSessionEvents(issue.projectId, issue.linearIssueId, { limit: 1 }).at(-1),
|
|
@@ -611,16 +227,10 @@ export class PatchRelayDatabase {
|
|
|
611
227
|
return issue ? this.issueToTrackedIssue(issue) : undefined;
|
|
612
228
|
}
|
|
613
229
|
listIssues() {
|
|
614
|
-
|
|
615
|
-
.prepare("SELECT * FROM issues ORDER BY updated_at DESC")
|
|
616
|
-
.all();
|
|
617
|
-
return rows.map(mapIssueRow);
|
|
230
|
+
return this.issues.listIssues();
|
|
618
231
|
}
|
|
619
232
|
listIssuesWithAgentSessions() {
|
|
620
|
-
|
|
621
|
-
.prepare("SELECT * FROM issues WHERE agent_session_id IS NOT NULL ORDER BY updated_at DESC")
|
|
622
|
-
.all();
|
|
623
|
-
return rows.map(mapIssueRow);
|
|
233
|
+
return this.issues.listIssuesWithAgentSessions();
|
|
624
234
|
}
|
|
625
235
|
// ─── Issue overview for query service ─────────────────────────────
|
|
626
236
|
getIssueOverview(issueKey) {
|
|
@@ -634,206 +244,8 @@ export class PatchRelayDatabase {
|
|
|
634
244
|
...(activeRun ? { activeRun } : {}),
|
|
635
245
|
};
|
|
636
246
|
}
|
|
637
|
-
syncIssueSessionFromIssue(issue, options) {
|
|
638
|
-
const tracked = this.issueToTrackedIssue(issue);
|
|
639
|
-
const existing = this.issueSessions.getIssueSession(issue.projectId, issue.linearIssueId);
|
|
640
|
-
const latestRun = this.runs.getLatestRunForIssue(issue.projectId, issue.linearIssueId);
|
|
641
|
-
const latestRunType = options?.lastRunType ?? latestRun?.runType ?? existing?.lastRunType;
|
|
642
|
-
const summaryText = this.resolveIssueSessionSummary(issue, latestRun, existing?.summaryText, options?.summaryText);
|
|
643
|
-
const activeThreadId = issue.threadId ?? existing?.activeThreadId;
|
|
644
|
-
const threadGeneration = activeThreadId && activeThreadId !== existing?.activeThreadId
|
|
645
|
-
? (existing?.threadGeneration ?? 0) + 1
|
|
646
|
-
: (existing?.threadGeneration ?? (activeThreadId ? 1 : 0));
|
|
647
|
-
const sessionState = deriveIssueSessionState({
|
|
648
|
-
...(issue.activeRunId !== undefined ? { activeRunId: issue.activeRunId } : {}),
|
|
649
|
-
factoryState: issue.factoryState,
|
|
650
|
-
});
|
|
651
|
-
const lastWakeReason = options?.lastWakeReason
|
|
652
|
-
?? deriveIssueSessionWakeReason({
|
|
653
|
-
pendingRunType: issue.pendingRunType,
|
|
654
|
-
factoryState: issue.factoryState,
|
|
655
|
-
prNumber: issue.prNumber,
|
|
656
|
-
prState: issue.prState,
|
|
657
|
-
prReviewState: issue.prReviewState,
|
|
658
|
-
prCheckStatus: issue.prCheckStatus,
|
|
659
|
-
latestFailureSource: issue.lastGitHubFailureSource,
|
|
660
|
-
})
|
|
661
|
-
?? existing?.lastWakeReason;
|
|
662
|
-
const now = isoNow();
|
|
663
|
-
if (existing) {
|
|
664
|
-
this.connection.prepare(`
|
|
665
|
-
UPDATE issue_sessions SET
|
|
666
|
-
issue_key = ?,
|
|
667
|
-
repo_id = ?,
|
|
668
|
-
branch_name = ?,
|
|
669
|
-
worktree_path = ?,
|
|
670
|
-
pr_number = ?,
|
|
671
|
-
pr_head_sha = ?,
|
|
672
|
-
pr_author_login = ?,
|
|
673
|
-
session_state = ?,
|
|
674
|
-
waiting_reason = ?,
|
|
675
|
-
summary_text = ?,
|
|
676
|
-
active_thread_id = ?,
|
|
677
|
-
thread_generation = ?,
|
|
678
|
-
active_run_id = ?,
|
|
679
|
-
last_run_type = ?,
|
|
680
|
-
last_wake_reason = ?,
|
|
681
|
-
ci_repair_attempts = ?,
|
|
682
|
-
queue_repair_attempts = ?,
|
|
683
|
-
review_fix_attempts = ?,
|
|
684
|
-
updated_at = ?
|
|
685
|
-
WHERE project_id = ? AND linear_issue_id = ?
|
|
686
|
-
`).run(issue.issueKey ?? null, issue.projectId, issue.branchName ?? null, issue.worktreePath ?? null, issue.prNumber ?? null, issue.prHeadSha ?? null, issue.prAuthorLogin ?? null, sessionState, tracked.waitingReason ?? null, summaryText ?? null, activeThreadId ?? null, threadGeneration, issue.activeRunId ?? null, latestRunType ?? null, lastWakeReason ?? null, issue.ciRepairAttempts, issue.queueRepairAttempts, issue.reviewFixAttempts, now, issue.projectId, issue.linearIssueId);
|
|
687
|
-
return;
|
|
688
|
-
}
|
|
689
|
-
this.connection.prepare(`
|
|
690
|
-
INSERT INTO issue_sessions (
|
|
691
|
-
project_id, linear_issue_id, issue_key, repo_id, branch_name, worktree_path,
|
|
692
|
-
pr_number, pr_head_sha, pr_author_login, session_state, waiting_reason, summary_text,
|
|
693
|
-
active_thread_id, thread_generation, active_run_id, last_run_type, last_wake_reason,
|
|
694
|
-
ci_repair_attempts, queue_repair_attempts, review_fix_attempts,
|
|
695
|
-
created_at, updated_at
|
|
696
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
697
|
-
`).run(issue.projectId, issue.linearIssueId, issue.issueKey ?? null, issue.projectId, issue.branchName ?? null, issue.worktreePath ?? null, issue.prNumber ?? null, issue.prHeadSha ?? null, issue.prAuthorLogin ?? null, sessionState, tracked.waitingReason ?? null, summaryText ?? null, activeThreadId ?? null, threadGeneration, issue.activeRunId ?? null, latestRunType ?? null, lastWakeReason ?? null, issue.ciRepairAttempts, issue.queueRepairAttempts, issue.reviewFixAttempts, now, now);
|
|
698
|
-
}
|
|
699
|
-
resolveIssueSessionSummary(issue, latestRun, existingSummaryText, explicitSummaryText) {
|
|
700
|
-
if (explicitSummaryText?.trim()) {
|
|
701
|
-
return explicitSummaryText;
|
|
702
|
-
}
|
|
703
|
-
const latestSummary = extractLatestAssistantSummary(latestRun);
|
|
704
|
-
if (latestRun && (latestRun.status === "queued" || latestRun.status === "running")) {
|
|
705
|
-
return latestSummary;
|
|
706
|
-
}
|
|
707
|
-
if (this.shouldKeepPreviousIssueSummary(issue, latestRun)) {
|
|
708
|
-
return this.findLatestCompletedRunSummary(issue.projectId, issue.linearIssueId)
|
|
709
|
-
?? existingSummaryText
|
|
710
|
-
?? latestSummary;
|
|
711
|
-
}
|
|
712
|
-
return latestSummary ?? existingSummaryText;
|
|
713
|
-
}
|
|
714
|
-
shouldKeepPreviousIssueSummary(issue, latestRun) {
|
|
715
|
-
if (!latestRun || latestRun.status !== "failed") {
|
|
716
|
-
return false;
|
|
717
|
-
}
|
|
718
|
-
if (latestRun.summaryJson || latestRun.reportJson) {
|
|
719
|
-
return false;
|
|
720
|
-
}
|
|
721
|
-
return issue.factoryState === "pr_open"
|
|
722
|
-
|| issue.factoryState === "awaiting_queue"
|
|
723
|
-
|| issue.factoryState === "done";
|
|
724
|
-
}
|
|
725
|
-
findLatestCompletedRunSummary(projectId, linearIssueId) {
|
|
726
|
-
const runs = this.runs.listRunsForIssue(projectId, linearIssueId);
|
|
727
|
-
for (let index = runs.length - 1; index >= 0; index -= 1) {
|
|
728
|
-
const run = runs[index];
|
|
729
|
-
if (!run || run.status !== "completed") {
|
|
730
|
-
continue;
|
|
731
|
-
}
|
|
732
|
-
const summary = extractLatestAssistantSummary(run);
|
|
733
|
-
if (summary?.trim()) {
|
|
734
|
-
return summary;
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
return undefined;
|
|
738
|
-
}
|
|
739
247
|
}
|
|
740
248
|
// ─── Row mappers ──────────────────────────────────────────────────
|
|
741
|
-
function mapIssueRow(row) {
|
|
742
|
-
return {
|
|
743
|
-
id: Number(row.id),
|
|
744
|
-
projectId: String(row.project_id),
|
|
745
|
-
linearIssueId: String(row.linear_issue_id),
|
|
746
|
-
...(row.issue_key !== null ? { issueKey: String(row.issue_key) } : {}),
|
|
747
|
-
...(row.title !== null ? { title: String(row.title) } : {}),
|
|
748
|
-
...(row.description !== null && row.description !== undefined ? { description: String(row.description) } : {}),
|
|
749
|
-
...(row.url !== null ? { url: String(row.url) } : {}),
|
|
750
|
-
...(row.priority !== null && row.priority !== undefined ? { priority: Number(row.priority) } : {}),
|
|
751
|
-
...(row.estimate !== null && row.estimate !== undefined ? { estimate: Number(row.estimate) } : {}),
|
|
752
|
-
...(row.current_linear_state !== null ? { currentLinearState: String(row.current_linear_state) } : {}),
|
|
753
|
-
...(row.current_linear_state_type !== null && row.current_linear_state_type !== undefined
|
|
754
|
-
? { currentLinearStateType: String(row.current_linear_state_type) }
|
|
755
|
-
: {}),
|
|
756
|
-
factoryState: String(row.factory_state ?? "delegated"),
|
|
757
|
-
...(row.pending_run_type !== null && row.pending_run_type !== undefined ? { pendingRunType: String(row.pending_run_type) } : {}),
|
|
758
|
-
...(row.pending_run_context_json !== null && row.pending_run_context_json !== undefined ? { pendingRunContextJson: String(row.pending_run_context_json) } : {}),
|
|
759
|
-
...(row.branch_name !== null ? { branchName: String(row.branch_name) } : {}),
|
|
760
|
-
...(row.branch_owner !== null && row.branch_owner !== undefined && String(row.branch_owner) === "patchrelay"
|
|
761
|
-
? { branchOwner: "patchrelay" }
|
|
762
|
-
: { branchOwner: "patchrelay" }),
|
|
763
|
-
...(row.branch_ownership_changed_at !== null && row.branch_ownership_changed_at !== undefined
|
|
764
|
-
? { branchOwnershipChangedAt: String(row.branch_ownership_changed_at) }
|
|
765
|
-
: {}),
|
|
766
|
-
...(row.worktree_path !== null ? { worktreePath: String(row.worktree_path) } : {}),
|
|
767
|
-
...(row.thread_id !== null ? { threadId: String(row.thread_id) } : {}),
|
|
768
|
-
...(row.active_run_id !== null ? { activeRunId: Number(row.active_run_id) } : {}),
|
|
769
|
-
...(row.status_comment_id !== null && row.status_comment_id !== undefined ? { statusCommentId: String(row.status_comment_id) } : {}),
|
|
770
|
-
...(row.agent_session_id !== null ? { agentSessionId: String(row.agent_session_id) } : {}),
|
|
771
|
-
updatedAt: String(row.updated_at),
|
|
772
|
-
...(row.pr_number !== null && row.pr_number !== undefined ? { prNumber: Number(row.pr_number) } : {}),
|
|
773
|
-
...(row.pr_url !== null && row.pr_url !== undefined ? { prUrl: String(row.pr_url) } : {}),
|
|
774
|
-
...(row.pr_state !== null && row.pr_state !== undefined ? { prState: String(row.pr_state) } : {}),
|
|
775
|
-
...(row.pr_head_sha !== null && row.pr_head_sha !== undefined ? { prHeadSha: String(row.pr_head_sha) } : {}),
|
|
776
|
-
...(row.pr_author_login !== null && row.pr_author_login !== undefined ? { prAuthorLogin: String(row.pr_author_login) } : {}),
|
|
777
|
-
...(row.pr_review_state !== null && row.pr_review_state !== undefined ? { prReviewState: String(row.pr_review_state) } : {}),
|
|
778
|
-
...(row.pr_check_status !== null && row.pr_check_status !== undefined ? { prCheckStatus: String(row.pr_check_status) } : {}),
|
|
779
|
-
...(row.last_blocking_review_head_sha !== null && row.last_blocking_review_head_sha !== undefined
|
|
780
|
-
? { lastBlockingReviewHeadSha: String(row.last_blocking_review_head_sha) }
|
|
781
|
-
: {}),
|
|
782
|
-
...(row.last_github_failure_source !== null && row.last_github_failure_source !== undefined
|
|
783
|
-
? { lastGitHubFailureSource: String(row.last_github_failure_source) }
|
|
784
|
-
: {}),
|
|
785
|
-
...(row.last_github_failure_head_sha !== null && row.last_github_failure_head_sha !== undefined
|
|
786
|
-
? { lastGitHubFailureHeadSha: String(row.last_github_failure_head_sha) }
|
|
787
|
-
: {}),
|
|
788
|
-
...(row.last_github_failure_signature !== null && row.last_github_failure_signature !== undefined
|
|
789
|
-
? { lastGitHubFailureSignature: String(row.last_github_failure_signature) }
|
|
790
|
-
: {}),
|
|
791
|
-
...(row.last_github_failure_check_name !== null && row.last_github_failure_check_name !== undefined
|
|
792
|
-
? { lastGitHubFailureCheckName: String(row.last_github_failure_check_name) }
|
|
793
|
-
: {}),
|
|
794
|
-
...(row.last_github_failure_check_url !== null && row.last_github_failure_check_url !== undefined
|
|
795
|
-
? { lastGitHubFailureCheckUrl: String(row.last_github_failure_check_url) }
|
|
796
|
-
: {}),
|
|
797
|
-
...(row.last_github_failure_context_json !== null && row.last_github_failure_context_json !== undefined
|
|
798
|
-
? { lastGitHubFailureContextJson: String(row.last_github_failure_context_json) }
|
|
799
|
-
: {}),
|
|
800
|
-
...(row.last_github_failure_at !== null && row.last_github_failure_at !== undefined
|
|
801
|
-
? { lastGitHubFailureAt: String(row.last_github_failure_at) }
|
|
802
|
-
: {}),
|
|
803
|
-
...(row.last_github_ci_snapshot_head_sha !== null && row.last_github_ci_snapshot_head_sha !== undefined
|
|
804
|
-
? { lastGitHubCiSnapshotHeadSha: String(row.last_github_ci_snapshot_head_sha) }
|
|
805
|
-
: {}),
|
|
806
|
-
...(row.last_github_ci_snapshot_gate_check_name !== null && row.last_github_ci_snapshot_gate_check_name !== undefined
|
|
807
|
-
? { lastGitHubCiSnapshotGateCheckName: String(row.last_github_ci_snapshot_gate_check_name) }
|
|
808
|
-
: {}),
|
|
809
|
-
...(row.last_github_ci_snapshot_gate_check_status !== null && row.last_github_ci_snapshot_gate_check_status !== undefined
|
|
810
|
-
? { lastGitHubCiSnapshotGateCheckStatus: String(row.last_github_ci_snapshot_gate_check_status) }
|
|
811
|
-
: {}),
|
|
812
|
-
...(row.last_github_ci_snapshot_json !== null && row.last_github_ci_snapshot_json !== undefined
|
|
813
|
-
? { lastGitHubCiSnapshotJson: String(row.last_github_ci_snapshot_json) }
|
|
814
|
-
: {}),
|
|
815
|
-
...(row.last_github_ci_snapshot_settled_at !== null && row.last_github_ci_snapshot_settled_at !== undefined
|
|
816
|
-
? { lastGitHubCiSnapshotSettledAt: String(row.last_github_ci_snapshot_settled_at) }
|
|
817
|
-
: {}),
|
|
818
|
-
...(row.last_queue_signal_at !== null && row.last_queue_signal_at !== undefined
|
|
819
|
-
? { lastQueueSignalAt: String(row.last_queue_signal_at) }
|
|
820
|
-
: {}),
|
|
821
|
-
...(row.last_queue_incident_json !== null && row.last_queue_incident_json !== undefined
|
|
822
|
-
? { lastQueueIncidentJson: String(row.last_queue_incident_json) }
|
|
823
|
-
: {}),
|
|
824
|
-
...(row.last_attempted_failure_head_sha !== null && row.last_attempted_failure_head_sha !== undefined
|
|
825
|
-
? { lastAttemptedFailureHeadSha: String(row.last_attempted_failure_head_sha) }
|
|
826
|
-
: {}),
|
|
827
|
-
...(row.last_attempted_failure_signature !== null && row.last_attempted_failure_signature !== undefined
|
|
828
|
-
? { lastAttemptedFailureSignature: String(row.last_attempted_failure_signature) }
|
|
829
|
-
: {}),
|
|
830
|
-
ciRepairAttempts: Number(row.ci_repair_attempts ?? 0),
|
|
831
|
-
queueRepairAttempts: Number(row.queue_repair_attempts ?? 0),
|
|
832
|
-
reviewFixAttempts: Number(row.review_fix_attempts ?? 0),
|
|
833
|
-
zombieRecoveryAttempts: Number(row.zombie_recovery_attempts ?? 0),
|
|
834
|
-
...(row.last_zombie_recovery_at !== null && row.last_zombie_recovery_at !== undefined ? { lastZombieRecoveryAt: String(row.last_zombie_recovery_at) } : {}),
|
|
835
|
-
};
|
|
836
|
-
}
|
|
837
249
|
function mapIssueSessionRow(row) {
|
|
838
250
|
return {
|
|
839
251
|
id: Number(row.id),
|