patchrelay 0.2.0 → 0.3.0
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/args.js +73 -0
- package/dist/cli/command-types.js +1 -0
- package/dist/cli/commands/connect.js +28 -0
- package/dist/cli/commands/issues.js +147 -0
- package/dist/cli/commands/project.js +140 -0
- package/dist/cli/commands/setup.js +140 -0
- package/dist/cli/connect-flow.js +52 -0
- package/dist/cli/data.js +17 -63
- package/dist/cli/index.js +59 -615
- package/dist/cli/interactive.js +48 -0
- package/dist/cli/output.js +13 -0
- package/dist/cli/service-commands.js +31 -0
- package/dist/db/issue-projection-store.js +54 -0
- package/dist/db/issue-workflow-coordinator.js +280 -0
- package/dist/db/issue-workflow-store.js +53 -550
- package/dist/db/run-report-store.js +33 -0
- package/dist/db.js +20 -1
- package/dist/index.js +13 -4
- package/dist/install.js +4 -3
- package/dist/linear-oauth.js +8 -7
- package/dist/service-stage-finalizer.js +2 -2
- package/dist/service-stage-runner.js +4 -4
- package/dist/service.js +1 -0
- package/dist/stage-failure.js +3 -17
- package/dist/stage-lifecycle-publisher.js +5 -28
- package/dist/webhook-desired-stage-recorder.js +4 -35
- package/infra/patchrelay.path +2 -0
- package/infra/patchrelay.service +2 -0
- package/package.json +1 -1
|
@@ -1,346 +1,90 @@
|
|
|
1
1
|
import { isoNow } from "./shared.js";
|
|
2
2
|
export class IssueWorkflowStore {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
this.
|
|
9
|
-
|
|
10
|
-
linearIssueId: params.linearIssueId,
|
|
11
|
-
...(params.issueKey ? { issueKey: params.issueKey } : {}),
|
|
12
|
-
...(params.title ? { title: params.title } : {}),
|
|
13
|
-
...(params.issueUrl ? { issueUrl: params.issueUrl } : {}),
|
|
14
|
-
...(params.currentLinearState ? { currentLinearState: params.currentLinearState } : {}),
|
|
15
|
-
...(params.lastWebhookAt ? { lastWebhookAt: params.lastWebhookAt } : {}),
|
|
16
|
-
});
|
|
17
|
-
const desiredReceiptId = params.desiredWebhookId === undefined
|
|
18
|
-
? undefined
|
|
19
|
-
: params.desiredWebhookId === null
|
|
20
|
-
? null
|
|
21
|
-
: this.ensureDesiredReceipt(params.projectId, params.linearIssueId, params.desiredWebhookId);
|
|
22
|
-
this.upsertIssueControl({
|
|
23
|
-
projectId: params.projectId,
|
|
24
|
-
linearIssueId: params.linearIssueId,
|
|
25
|
-
...(params.desiredStage !== undefined ? { desiredStage: params.desiredStage } : {}),
|
|
26
|
-
...(desiredReceiptId !== undefined ? { desiredReceiptId } : {}),
|
|
27
|
-
...(params.activeWorkspaceId !== undefined ? { activeWorkspaceOwnershipId: params.activeWorkspaceId } : {}),
|
|
28
|
-
...(params.activeStageRunId !== undefined ? { activeRunLeaseId: params.activeStageRunId } : {}),
|
|
29
|
-
...(params.statusCommentId !== undefined ? { serviceOwnedCommentId: params.statusCommentId } : {}),
|
|
30
|
-
...(params.activeAgentSessionId !== undefined ? { activeAgentSessionId: params.activeAgentSessionId } : {}),
|
|
31
|
-
lifecycleStatus: params.lifecycleStatus,
|
|
32
|
-
});
|
|
33
|
-
return this.getTrackedIssue(params.projectId, params.linearIssueId);
|
|
3
|
+
authoritativeLedger;
|
|
4
|
+
issueProjections;
|
|
5
|
+
runReports;
|
|
6
|
+
constructor(dependencies) {
|
|
7
|
+
this.authoritativeLedger = dependencies.authoritativeLedger;
|
|
8
|
+
this.issueProjections = dependencies.issueProjections;
|
|
9
|
+
this.runReports = dependencies.runReports;
|
|
34
10
|
}
|
|
35
11
|
getTrackedIssue(projectId, linearIssueId) {
|
|
36
|
-
const issueControl = this.
|
|
37
|
-
const projection = this.
|
|
12
|
+
const issueControl = this.authoritativeLedger.getIssueControl(projectId, linearIssueId);
|
|
13
|
+
const projection = this.issueProjections.getIssueProjection(projectId, linearIssueId);
|
|
38
14
|
if (!issueControl && !projection) {
|
|
39
15
|
return undefined;
|
|
40
16
|
}
|
|
41
17
|
return this.buildTrackedIssue(issueControl, projection);
|
|
42
18
|
}
|
|
43
19
|
getTrackedIssueByKey(issueKey) {
|
|
44
|
-
const projection = this.
|
|
45
|
-
.prepare("SELECT * FROM issue_projection WHERE issue_key = ? ORDER BY updated_at DESC LIMIT 1")
|
|
46
|
-
.get(issueKey);
|
|
20
|
+
const projection = this.issueProjections.getIssueProjectionByKey(issueKey);
|
|
47
21
|
if (!projection) {
|
|
48
22
|
return undefined;
|
|
49
23
|
}
|
|
50
|
-
return this.getTrackedIssue(
|
|
24
|
+
return this.getTrackedIssue(projection.projectId, projection.linearIssueId);
|
|
51
25
|
}
|
|
52
26
|
getTrackedIssueByLinearIssueId(linearIssueId) {
|
|
53
|
-
const projection = this.
|
|
54
|
-
.prepare("SELECT * FROM issue_projection WHERE linear_issue_id = ? ORDER BY updated_at DESC LIMIT 1")
|
|
55
|
-
.get(linearIssueId);
|
|
27
|
+
const projection = this.issueProjections.getIssueProjectionByLinearIssueId(linearIssueId);
|
|
56
28
|
if (!projection) {
|
|
57
29
|
return undefined;
|
|
58
30
|
}
|
|
59
|
-
return this.getTrackedIssue(
|
|
60
|
-
}
|
|
61
|
-
recordDesiredStage(params) {
|
|
62
|
-
const existing = this.getTrackedIssue(params.projectId, params.linearIssueId);
|
|
63
|
-
this.upsertIssueProjection({
|
|
64
|
-
projectId: params.projectId,
|
|
65
|
-
linearIssueId: params.linearIssueId,
|
|
66
|
-
...(params.issueKey ? { issueKey: params.issueKey } : existing?.issueKey ? { issueKey: existing.issueKey } : {}),
|
|
67
|
-
...(params.title ? { title: params.title } : existing?.title ? { title: existing.title } : {}),
|
|
68
|
-
...(params.issueUrl ? { issueUrl: params.issueUrl } : existing?.issueUrl ? { issueUrl: existing.issueUrl } : {}),
|
|
69
|
-
...(params.currentLinearState
|
|
70
|
-
? { currentLinearState: params.currentLinearState }
|
|
71
|
-
: existing?.currentLinearState
|
|
72
|
-
? { currentLinearState: existing.currentLinearState }
|
|
73
|
-
: {}),
|
|
74
|
-
lastWebhookAt: params.lastWebhookAt,
|
|
75
|
-
});
|
|
76
|
-
const existingIssueControl = this.getIssueControlRow(params.projectId, params.linearIssueId);
|
|
77
|
-
const lifecycleStatus = existingIssueControl?.active_run_lease_id || params.desiredStage
|
|
78
|
-
? existing?.lifecycleStatus ?? "queued"
|
|
79
|
-
: existing?.lifecycleStatus ?? "idle";
|
|
80
|
-
const desiredReceiptId = params.desiredWebhookId === undefined ? undefined : this.ensureDesiredReceipt(params.projectId, params.linearIssueId, params.desiredWebhookId);
|
|
81
|
-
this.upsertIssueControl({
|
|
82
|
-
projectId: params.projectId,
|
|
83
|
-
linearIssueId: params.linearIssueId,
|
|
84
|
-
...(params.desiredStage !== undefined ? { desiredStage: params.desiredStage } : {}),
|
|
85
|
-
...(desiredReceiptId !== undefined ? { desiredReceiptId } : {}),
|
|
86
|
-
lifecycleStatus,
|
|
87
|
-
...(existing?.statusCommentId ? { serviceOwnedCommentId: existing.statusCommentId } : {}),
|
|
88
|
-
...(existing?.activeAgentSessionId ? { activeAgentSessionId: existing.activeAgentSessionId } : {}),
|
|
89
|
-
...(existing?.activeWorkspaceId !== undefined ? { activeWorkspaceOwnershipId: existing.activeWorkspaceId } : {}),
|
|
90
|
-
...(existingIssueControl?.active_run_lease_id !== undefined && existingIssueControl.active_run_lease_id !== null
|
|
91
|
-
? { activeRunLeaseId: Number(existingIssueControl.active_run_lease_id) }
|
|
92
|
-
: {}),
|
|
93
|
-
});
|
|
94
|
-
return this.getTrackedIssue(params.projectId, params.linearIssueId);
|
|
95
|
-
}
|
|
96
|
-
listIssuesReadyForExecution() {
|
|
97
|
-
const rows = this.connection
|
|
98
|
-
.prepare("SELECT project_id, linear_issue_id FROM issue_control WHERE desired_stage IS NOT NULL AND active_run_lease_id IS NULL ORDER BY id")
|
|
99
|
-
.all();
|
|
100
|
-
return rows.map((row) => ({
|
|
101
|
-
projectId: String(row.project_id),
|
|
102
|
-
linearIssueId: String(row.linear_issue_id),
|
|
103
|
-
}));
|
|
31
|
+
return this.getTrackedIssue(projection.projectId, linearIssueId);
|
|
104
32
|
}
|
|
105
33
|
listActiveStageRuns() {
|
|
106
|
-
return this.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const issue = this.getTrackedIssue(params.projectId, params.linearIssueId);
|
|
111
|
-
const issueControlRow = this.getIssueControlRow(params.projectId, params.linearIssueId);
|
|
112
|
-
const issueControl = issueControlRow ? mapIssueControl(issueControlRow) : undefined;
|
|
113
|
-
if (!issue || !issueControl || issueControl.activeRunLeaseId !== undefined || issue.desiredStage !== params.stage || issue.desiredWebhookId !== params.triggerWebhookId) {
|
|
114
|
-
return undefined;
|
|
115
|
-
}
|
|
116
|
-
const workspaceOwnership = this.upsertWorkspaceOwnership({
|
|
117
|
-
projectId: params.projectId,
|
|
118
|
-
linearIssueId: params.linearIssueId,
|
|
119
|
-
branchName: params.branchName,
|
|
120
|
-
worktreePath: params.worktreePath,
|
|
121
|
-
status: "active",
|
|
122
|
-
});
|
|
123
|
-
const runLease = this.insertRunLease({
|
|
124
|
-
issueControlId: issueControl.id,
|
|
125
|
-
projectId: params.projectId,
|
|
126
|
-
linearIssueId: params.linearIssueId,
|
|
127
|
-
workspaceOwnershipId: workspaceOwnership.id,
|
|
128
|
-
stage: params.stage,
|
|
129
|
-
status: "running",
|
|
130
|
-
workflowFile: params.workflowFile,
|
|
131
|
-
promptText: params.promptText,
|
|
132
|
-
triggerReceiptId: issueControl.desiredReceiptId ?? null,
|
|
133
|
-
});
|
|
134
|
-
this.upsertWorkspaceOwnership({
|
|
135
|
-
projectId: params.projectId,
|
|
136
|
-
linearIssueId: params.linearIssueId,
|
|
137
|
-
branchName: params.branchName,
|
|
138
|
-
worktreePath: params.worktreePath,
|
|
139
|
-
status: "active",
|
|
140
|
-
currentRunLeaseId: runLease.id,
|
|
141
|
-
});
|
|
142
|
-
this.upsertIssueControl({
|
|
143
|
-
projectId: params.projectId,
|
|
144
|
-
linearIssueId: params.linearIssueId,
|
|
145
|
-
desiredStage: null,
|
|
146
|
-
desiredReceiptId: null,
|
|
147
|
-
activeWorkspaceOwnershipId: workspaceOwnership.id,
|
|
148
|
-
activeRunLeaseId: runLease.id,
|
|
149
|
-
lifecycleStatus: "running",
|
|
150
|
-
...(issue.statusCommentId ? { serviceOwnedCommentId: issue.statusCommentId } : {}),
|
|
151
|
-
...(issue.activeAgentSessionId ? { activeAgentSessionId: issue.activeAgentSessionId } : {}),
|
|
152
|
-
});
|
|
153
|
-
const refreshedIssue = this.getTrackedIssue(params.projectId, params.linearIssueId);
|
|
154
|
-
const workspace = this.getWorkspace(workspaceOwnership.id);
|
|
155
|
-
const stageRun = this.getStageRun(runLease.id);
|
|
156
|
-
const pipeline = this.getPipelineRun(runLease.id);
|
|
157
|
-
return { issue: refreshedIssue, workspace, pipeline, stageRun };
|
|
158
|
-
});
|
|
159
|
-
return transaction();
|
|
34
|
+
return this.authoritativeLedger
|
|
35
|
+
.listActiveRunLeases()
|
|
36
|
+
.filter((runLease) => runLease.status === "running")
|
|
37
|
+
.map((runLease) => this.buildStageRun(runLease));
|
|
160
38
|
}
|
|
161
39
|
getWorkspace(id) {
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
return undefined;
|
|
165
|
-
}
|
|
166
|
-
return this.buildWorkspace(mapWorkspaceOwnership(row));
|
|
40
|
+
const workspaceOwnership = this.authoritativeLedger.getWorkspaceOwnership(id);
|
|
41
|
+
return workspaceOwnership ? this.buildWorkspace(workspaceOwnership) : undefined;
|
|
167
42
|
}
|
|
168
43
|
getActiveWorkspaceForIssue(projectId, linearIssueId) {
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
.get(projectId, linearIssueId);
|
|
172
|
-
return row ? this.buildWorkspace(mapWorkspaceOwnership(row)) : undefined;
|
|
44
|
+
const workspaceOwnership = this.authoritativeLedger.getWorkspaceOwnershipForIssue(projectId, linearIssueId);
|
|
45
|
+
return workspaceOwnership ? this.buildWorkspace(workspaceOwnership) : undefined;
|
|
173
46
|
}
|
|
174
47
|
getPipelineRun(id) {
|
|
175
|
-
const runLease = this.
|
|
48
|
+
const runLease = this.authoritativeLedger.getRunLease(id);
|
|
176
49
|
if (!runLease) {
|
|
177
50
|
return undefined;
|
|
178
51
|
}
|
|
179
|
-
const issueControl = this.
|
|
180
|
-
const status = resolvePipelineStatus(runLease.status, issueControl?.
|
|
52
|
+
const issueControl = this.authoritativeLedger.getIssueControl(runLease.projectId, runLease.linearIssueId);
|
|
53
|
+
const status = resolvePipelineStatus(runLease.status, issueControl?.lifecycleStatus);
|
|
181
54
|
return {
|
|
182
|
-
id:
|
|
183
|
-
projectId:
|
|
184
|
-
linearIssueId:
|
|
185
|
-
workspaceId:
|
|
55
|
+
id: runLease.id,
|
|
56
|
+
projectId: runLease.projectId,
|
|
57
|
+
linearIssueId: runLease.linearIssueId,
|
|
58
|
+
workspaceId: runLease.workspaceOwnershipId,
|
|
186
59
|
status,
|
|
187
60
|
currentStage: runLease.stage,
|
|
188
|
-
startedAt:
|
|
189
|
-
...(runLease.
|
|
61
|
+
startedAt: runLease.startedAt,
|
|
62
|
+
...(runLease.endedAt ? { endedAt: runLease.endedAt } : {}),
|
|
190
63
|
};
|
|
191
64
|
}
|
|
192
65
|
getStageRun(id) {
|
|
193
|
-
const
|
|
194
|
-
return
|
|
66
|
+
const runLease = this.authoritativeLedger.getRunLease(id);
|
|
67
|
+
return runLease ? this.buildStageRun(runLease) : undefined;
|
|
195
68
|
}
|
|
196
69
|
getStageRunByThreadId(threadId) {
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
.get(threadId);
|
|
200
|
-
return row ? this.buildStageRun(row) : undefined;
|
|
70
|
+
const runLease = this.authoritativeLedger.getRunLeaseByThreadId(threadId);
|
|
71
|
+
return runLease ? this.buildStageRun(runLease) : undefined;
|
|
201
72
|
}
|
|
202
73
|
listStageRunsForIssue(projectId, linearIssueId) {
|
|
203
|
-
return this.
|
|
204
|
-
}
|
|
205
|
-
updateStageRunThread(params) {
|
|
206
|
-
this.connection
|
|
207
|
-
.prepare(`
|
|
208
|
-
UPDATE run_leases
|
|
209
|
-
SET thread_id = ?,
|
|
210
|
-
parent_thread_id = COALESCE(?, parent_thread_id),
|
|
211
|
-
turn_id = COALESCE(?, turn_id)
|
|
212
|
-
WHERE id = ?
|
|
213
|
-
`)
|
|
214
|
-
.run(params.threadId, params.parentThreadId ?? null, params.turnId ?? null, params.stageRunId);
|
|
215
|
-
}
|
|
216
|
-
finishStageRun(params) {
|
|
217
|
-
const stageRun = this.getStageRun(params.stageRunId);
|
|
218
|
-
if (!stageRun) {
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
const now = isoNow();
|
|
222
|
-
this.connection
|
|
223
|
-
.prepare(`
|
|
224
|
-
INSERT INTO run_reports (run_lease_id, summary_json, report_json, created_at, updated_at)
|
|
225
|
-
VALUES (?, ?, ?, ?, ?)
|
|
226
|
-
ON CONFLICT(run_lease_id) DO UPDATE SET
|
|
227
|
-
summary_json = excluded.summary_json,
|
|
228
|
-
report_json = excluded.report_json,
|
|
229
|
-
updated_at = excluded.updated_at
|
|
230
|
-
`)
|
|
231
|
-
.run(params.stageRunId, params.summaryJson ?? null, params.reportJson ?? null, now, now);
|
|
232
|
-
this.connection
|
|
233
|
-
.prepare(`
|
|
234
|
-
UPDATE run_leases
|
|
235
|
-
SET status = ?,
|
|
236
|
-
thread_id = ?,
|
|
237
|
-
turn_id = COALESCE(?, turn_id),
|
|
238
|
-
ended_at = CASE WHEN ? IN ('completed', 'failed') THEN ? ELSE ended_at END
|
|
239
|
-
WHERE id = ?
|
|
240
|
-
`)
|
|
241
|
-
.run(params.status === "failed" ? "failed" : "completed", params.threadId, params.turnId ?? null, params.status === "failed" ? "failed" : "completed", now, params.stageRunId);
|
|
242
|
-
const workspace = this.getWorkspaceOwnershipRowById(stageRun.workspaceId);
|
|
243
|
-
if (workspace) {
|
|
244
|
-
this.upsertWorkspaceOwnership({
|
|
245
|
-
projectId: stageRun.projectId,
|
|
246
|
-
linearIssueId: stageRun.linearIssueId,
|
|
247
|
-
branchName: String(workspace.branch_name),
|
|
248
|
-
worktreePath: String(workspace.worktree_path),
|
|
249
|
-
status: params.status === "completed" ? "active" : "paused",
|
|
250
|
-
currentRunLeaseId: null,
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
setIssueDesiredStage(projectId, linearIssueId, desiredStage, desiredWebhookId) {
|
|
255
|
-
const existing = this.getTrackedIssue(projectId, linearIssueId);
|
|
256
|
-
const existingIssueControl = this.getIssueControlRow(projectId, linearIssueId);
|
|
257
|
-
this.upsertIssueControl({
|
|
258
|
-
projectId,
|
|
259
|
-
linearIssueId,
|
|
260
|
-
...(desiredStage !== undefined ? { desiredStage } : { desiredStage: null }),
|
|
261
|
-
...(desiredWebhookId !== undefined
|
|
262
|
-
? { desiredReceiptId: this.ensureDesiredReceipt(projectId, linearIssueId, desiredWebhookId) }
|
|
263
|
-
: desiredStage === undefined
|
|
264
|
-
? { desiredReceiptId: null }
|
|
265
|
-
: {}),
|
|
266
|
-
lifecycleStatus: desiredStage ? "queued" : existingIssueControl?.active_run_lease_id ? (existing?.lifecycleStatus ?? "idle") : "idle",
|
|
267
|
-
...(existing?.statusCommentId ? { serviceOwnedCommentId: existing.statusCommentId } : {}),
|
|
268
|
-
...(existing?.activeAgentSessionId ? { activeAgentSessionId: existing.activeAgentSessionId } : {}),
|
|
269
|
-
...(existing?.activeWorkspaceId !== undefined ? { activeWorkspaceOwnershipId: existing.activeWorkspaceId } : {}),
|
|
270
|
-
...(existingIssueControl?.active_run_lease_id !== undefined && existingIssueControl.active_run_lease_id !== null
|
|
271
|
-
? { activeRunLeaseId: Number(existingIssueControl.active_run_lease_id) }
|
|
272
|
-
: {}),
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
setIssueLifecycleStatus(projectId, linearIssueId, lifecycleStatus) {
|
|
276
|
-
const existing = this.getTrackedIssue(projectId, linearIssueId);
|
|
277
|
-
const existingIssueControl = this.getIssueControlRow(projectId, linearIssueId);
|
|
278
|
-
this.upsertIssueControl({
|
|
279
|
-
projectId,
|
|
280
|
-
linearIssueId,
|
|
281
|
-
lifecycleStatus,
|
|
282
|
-
...(existing?.desiredStage ? { desiredStage: existing.desiredStage } : {}),
|
|
283
|
-
...(existing?.desiredWebhookId ? { desiredReceiptId: this.ensureDesiredReceipt(projectId, linearIssueId, existing.desiredWebhookId) } : {}),
|
|
284
|
-
...(existing?.activeWorkspaceId !== undefined ? { activeWorkspaceOwnershipId: existing.activeWorkspaceId } : {}),
|
|
285
|
-
...(existingIssueControl?.active_run_lease_id !== undefined && existingIssueControl.active_run_lease_id !== null
|
|
286
|
-
? { activeRunLeaseId: Number(existingIssueControl.active_run_lease_id) }
|
|
287
|
-
: {}),
|
|
288
|
-
...(existing?.statusCommentId ? { serviceOwnedCommentId: existing.statusCommentId } : {}),
|
|
289
|
-
...(existing?.activeAgentSessionId ? { activeAgentSessionId: existing.activeAgentSessionId } : {}),
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
setIssueStatusComment(projectId, linearIssueId, statusCommentId) {
|
|
293
|
-
const existing = this.getTrackedIssue(projectId, linearIssueId);
|
|
294
|
-
const existingIssueControl = this.getIssueControlRow(projectId, linearIssueId);
|
|
295
|
-
this.upsertIssueControl({
|
|
296
|
-
projectId,
|
|
297
|
-
linearIssueId,
|
|
298
|
-
lifecycleStatus: existing?.lifecycleStatus ?? "idle",
|
|
299
|
-
...(existing?.desiredStage ? { desiredStage: existing.desiredStage } : {}),
|
|
300
|
-
...(existing?.desiredWebhookId ? { desiredReceiptId: this.ensureDesiredReceipt(projectId, linearIssueId, existing.desiredWebhookId) } : {}),
|
|
301
|
-
...(existing?.activeWorkspaceId !== undefined ? { activeWorkspaceOwnershipId: existing.activeWorkspaceId } : {}),
|
|
302
|
-
...(existingIssueControl?.active_run_lease_id !== undefined && existingIssueControl.active_run_lease_id !== null
|
|
303
|
-
? { activeRunLeaseId: Number(existingIssueControl.active_run_lease_id) }
|
|
304
|
-
: {}),
|
|
305
|
-
serviceOwnedCommentId: statusCommentId ?? null,
|
|
306
|
-
...(existing?.activeAgentSessionId ? { activeAgentSessionId: existing.activeAgentSessionId } : {}),
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
setIssueActiveAgentSession(projectId, linearIssueId, agentSessionId) {
|
|
310
|
-
const existing = this.getTrackedIssue(projectId, linearIssueId);
|
|
311
|
-
const existingIssueControl = this.getIssueControlRow(projectId, linearIssueId);
|
|
312
|
-
this.upsertIssueControl({
|
|
313
|
-
projectId,
|
|
314
|
-
linearIssueId,
|
|
315
|
-
lifecycleStatus: existing?.lifecycleStatus ?? "idle",
|
|
316
|
-
...(existing?.desiredStage ? { desiredStage: existing.desiredStage } : {}),
|
|
317
|
-
...(existing?.desiredWebhookId ? { desiredReceiptId: this.ensureDesiredReceipt(projectId, linearIssueId, existing.desiredWebhookId) } : {}),
|
|
318
|
-
...(existing?.activeWorkspaceId !== undefined ? { activeWorkspaceOwnershipId: existing.activeWorkspaceId } : {}),
|
|
319
|
-
...(existingIssueControl?.active_run_lease_id !== undefined && existingIssueControl.active_run_lease_id !== null
|
|
320
|
-
? { activeRunLeaseId: Number(existingIssueControl.active_run_lease_id) }
|
|
321
|
-
: {}),
|
|
322
|
-
...(existing?.statusCommentId ? { serviceOwnedCommentId: existing.statusCommentId } : {}),
|
|
323
|
-
activeAgentSessionId: agentSessionId ?? null,
|
|
324
|
-
});
|
|
74
|
+
return this.authoritativeLedger.listRunLeasesForIssue(projectId, linearIssueId).map((runLease) => this.buildStageRun(runLease));
|
|
325
75
|
}
|
|
326
76
|
getLatestStageRunForIssue(projectId, linearIssueId) {
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
.get(projectId, linearIssueId);
|
|
330
|
-
return row ? this.buildStageRun(row) : undefined;
|
|
77
|
+
const latestRunLease = this.getLatestRunLeaseForIssue(projectId, linearIssueId);
|
|
78
|
+
return latestRunLease ? this.buildStageRun(latestRunLease) : undefined;
|
|
331
79
|
}
|
|
332
80
|
getIssueOverview(issueKey) {
|
|
333
81
|
const issue = this.getTrackedIssueByKey(issueKey);
|
|
334
82
|
if (!issue) {
|
|
335
83
|
return undefined;
|
|
336
84
|
}
|
|
337
|
-
const issueControl = this.
|
|
338
|
-
const activeWorkspaceOwnershipId = issueControl?.
|
|
339
|
-
|
|
340
|
-
: Number(issueControl.active_workspace_ownership_id);
|
|
341
|
-
const activeRunLeaseId = issueControl?.active_run_lease_id === null || issueControl?.active_run_lease_id === undefined
|
|
342
|
-
? undefined
|
|
343
|
-
: Number(issueControl.active_run_lease_id);
|
|
85
|
+
const issueControl = this.authoritativeLedger.getIssueControl(issue.projectId, issue.linearIssueId);
|
|
86
|
+
const activeWorkspaceOwnershipId = issueControl?.activeWorkspaceOwnershipId;
|
|
87
|
+
const activeRunLeaseId = issueControl?.activeRunLeaseId;
|
|
344
88
|
const workspace = activeWorkspaceOwnershipId ? this.getWorkspace(activeWorkspaceOwnershipId) : this.getActiveWorkspaceForIssue(issue.projectId, issue.linearIssueId);
|
|
345
89
|
const pipeline = activeRunLeaseId ? this.getPipelineRun(activeRunLeaseId) : issue.activePipelineRunId ? this.getPipelineRun(issue.activePipelineRunId) : undefined;
|
|
346
90
|
const activeStageRun = activeRunLeaseId === undefined ? undefined : this.getStageRun(activeRunLeaseId);
|
|
@@ -351,107 +95,7 @@ export class IssueWorkflowStore {
|
|
|
351
95
|
...(activeStageRun ? { activeStageRun } : {}),
|
|
352
96
|
};
|
|
353
97
|
}
|
|
354
|
-
|
|
355
|
-
this.connection
|
|
356
|
-
.prepare(`
|
|
357
|
-
INSERT INTO issue_projection (
|
|
358
|
-
project_id, linear_issue_id, issue_key, title, issue_url, current_linear_state, last_webhook_at, updated_at
|
|
359
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
360
|
-
ON CONFLICT(project_id, linear_issue_id) DO UPDATE SET
|
|
361
|
-
issue_key = COALESCE(excluded.issue_key, issue_projection.issue_key),
|
|
362
|
-
title = COALESCE(excluded.title, issue_projection.title),
|
|
363
|
-
issue_url = COALESCE(excluded.issue_url, issue_projection.issue_url),
|
|
364
|
-
current_linear_state = COALESCE(excluded.current_linear_state, issue_projection.current_linear_state),
|
|
365
|
-
last_webhook_at = COALESCE(excluded.last_webhook_at, issue_projection.last_webhook_at),
|
|
366
|
-
updated_at = excluded.updated_at
|
|
367
|
-
`)
|
|
368
|
-
.run(params.projectId, params.linearIssueId, params.issueKey ?? null, params.title ?? null, params.issueUrl ?? null, params.currentLinearState ?? null, params.lastWebhookAt ?? null, isoNow());
|
|
369
|
-
}
|
|
370
|
-
upsertIssueControl(params) {
|
|
371
|
-
const now = isoNow();
|
|
372
|
-
this.connection
|
|
373
|
-
.prepare(`
|
|
374
|
-
INSERT INTO issue_control (
|
|
375
|
-
project_id, linear_issue_id, desired_stage, desired_receipt_id, active_workspace_ownership_id,
|
|
376
|
-
active_run_lease_id, service_owned_comment_id, active_agent_session_id, lifecycle_status, updated_at
|
|
377
|
-
) VALUES (
|
|
378
|
-
@projectId, @linearIssueId, @desiredStage, @desiredReceiptId, @activeWorkspaceOwnershipId,
|
|
379
|
-
@activeRunLeaseId, @serviceOwnedCommentId, @activeAgentSessionId, @lifecycleStatus, @updatedAt
|
|
380
|
-
)
|
|
381
|
-
ON CONFLICT(project_id, linear_issue_id) DO UPDATE SET
|
|
382
|
-
desired_stage = CASE WHEN @setDesiredStage = 1 THEN @desiredStage ELSE issue_control.desired_stage END,
|
|
383
|
-
desired_receipt_id = CASE WHEN @setDesiredReceiptId = 1 THEN @desiredReceiptId ELSE issue_control.desired_receipt_id END,
|
|
384
|
-
active_workspace_ownership_id = CASE WHEN @setActiveWorkspaceOwnershipId = 1 THEN @activeWorkspaceOwnershipId ELSE issue_control.active_workspace_ownership_id END,
|
|
385
|
-
active_run_lease_id = CASE WHEN @setActiveRunLeaseId = 1 THEN @activeRunLeaseId ELSE issue_control.active_run_lease_id END,
|
|
386
|
-
service_owned_comment_id = CASE WHEN @setServiceOwnedCommentId = 1 THEN @serviceOwnedCommentId ELSE issue_control.service_owned_comment_id END,
|
|
387
|
-
active_agent_session_id = CASE WHEN @setActiveAgentSessionId = 1 THEN @activeAgentSessionId ELSE issue_control.active_agent_session_id END,
|
|
388
|
-
lifecycle_status = @lifecycleStatus,
|
|
389
|
-
updated_at = @updatedAt
|
|
390
|
-
`)
|
|
391
|
-
.run({
|
|
392
|
-
projectId: params.projectId,
|
|
393
|
-
linearIssueId: params.linearIssueId,
|
|
394
|
-
desiredStage: params.desiredStage ?? null,
|
|
395
|
-
desiredReceiptId: params.desiredReceiptId ?? null,
|
|
396
|
-
activeWorkspaceOwnershipId: params.activeWorkspaceOwnershipId ?? null,
|
|
397
|
-
activeRunLeaseId: params.activeRunLeaseId ?? null,
|
|
398
|
-
serviceOwnedCommentId: params.serviceOwnedCommentId ?? null,
|
|
399
|
-
activeAgentSessionId: params.activeAgentSessionId ?? null,
|
|
400
|
-
lifecycleStatus: params.lifecycleStatus,
|
|
401
|
-
updatedAt: now,
|
|
402
|
-
setDesiredStage: Number("desiredStage" in params),
|
|
403
|
-
setDesiredReceiptId: Number("desiredReceiptId" in params),
|
|
404
|
-
setActiveWorkspaceOwnershipId: Number("activeWorkspaceOwnershipId" in params),
|
|
405
|
-
setActiveRunLeaseId: Number("activeRunLeaseId" in params),
|
|
406
|
-
setServiceOwnedCommentId: Number("serviceOwnedCommentId" in params),
|
|
407
|
-
setActiveAgentSessionId: Number("activeAgentSessionId" in params),
|
|
408
|
-
});
|
|
409
|
-
return mapIssueControl(this.connection
|
|
410
|
-
.prepare("SELECT * FROM issue_control WHERE project_id = ? AND linear_issue_id = ?")
|
|
411
|
-
.get(params.projectId, params.linearIssueId));
|
|
412
|
-
}
|
|
413
|
-
upsertWorkspaceOwnership(params) {
|
|
414
|
-
const now = isoNow();
|
|
415
|
-
this.connection
|
|
416
|
-
.prepare(`
|
|
417
|
-
INSERT INTO workspace_ownership (
|
|
418
|
-
project_id, linear_issue_id, branch_name, worktree_path, status, current_run_lease_id, created_at, updated_at
|
|
419
|
-
) VALUES (@projectId, @linearIssueId, @branchName, @worktreePath, @status, @currentRunLeaseId, @createdAt, @updatedAt)
|
|
420
|
-
ON CONFLICT(project_id, linear_issue_id) DO UPDATE SET
|
|
421
|
-
branch_name = @branchName,
|
|
422
|
-
worktree_path = @worktreePath,
|
|
423
|
-
status = @status,
|
|
424
|
-
current_run_lease_id = CASE WHEN @setCurrentRunLeaseId = 1 THEN @currentRunLeaseId ELSE workspace_ownership.current_run_lease_id END,
|
|
425
|
-
updated_at = @updatedAt
|
|
426
|
-
`)
|
|
427
|
-
.run({
|
|
428
|
-
projectId: params.projectId,
|
|
429
|
-
linearIssueId: params.linearIssueId,
|
|
430
|
-
branchName: params.branchName,
|
|
431
|
-
worktreePath: params.worktreePath,
|
|
432
|
-
status: params.status,
|
|
433
|
-
currentRunLeaseId: params.currentRunLeaseId ?? null,
|
|
434
|
-
createdAt: now,
|
|
435
|
-
updatedAt: now,
|
|
436
|
-
setCurrentRunLeaseId: Number("currentRunLeaseId" in params),
|
|
437
|
-
});
|
|
438
|
-
return mapWorkspaceOwnership(this.connection
|
|
439
|
-
.prepare("SELECT * FROM workspace_ownership WHERE project_id = ? AND linear_issue_id = ?")
|
|
440
|
-
.get(params.projectId, params.linearIssueId));
|
|
441
|
-
}
|
|
442
|
-
insertRunLease(params) {
|
|
443
|
-
const result = this.connection
|
|
444
|
-
.prepare(`
|
|
445
|
-
INSERT INTO run_leases (
|
|
446
|
-
issue_control_id, project_id, linear_issue_id, workspace_ownership_id, stage, status, trigger_receipt_id, workflow_file, prompt_text, started_at
|
|
447
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
448
|
-
`)
|
|
449
|
-
.run(params.issueControlId, params.projectId, params.linearIssueId, params.workspaceOwnershipId, params.stage, params.status, params.triggerReceiptId ?? null, params.workflowFile, params.promptText, isoNow());
|
|
450
|
-
return this.buildRunLease(this.connection.prepare("SELECT * FROM run_leases WHERE id = ?").get(Number(result.lastInsertRowid)));
|
|
451
|
-
}
|
|
452
|
-
buildTrackedIssue(issueControlRow, projectionRow) {
|
|
453
|
-
const issueControl = issueControlRow ? mapIssueControl(issueControlRow) : undefined;
|
|
454
|
-
const projection = projectionRow ? mapIssueProjection(projectionRow) : undefined;
|
|
98
|
+
buildTrackedIssue(issueControl, projection) {
|
|
455
99
|
const projectId = issueControl?.projectId ?? projection?.projectId;
|
|
456
100
|
const linearIssueId = issueControl?.linearIssueId ?? projection?.linearIssueId;
|
|
457
101
|
if (!projectId || !linearIssueId) {
|
|
@@ -472,7 +116,7 @@ export class IssueWorkflowStore {
|
|
|
472
116
|
if (!issueControl?.desiredReceiptId) {
|
|
473
117
|
return {};
|
|
474
118
|
}
|
|
475
|
-
const receipt = this.
|
|
119
|
+
const receipt = this.authoritativeLedger.getEventReceipt(issueControl.desiredReceiptId);
|
|
476
120
|
return receipt?.externalId ? { desiredWebhookId: receipt.externalId } : {};
|
|
477
121
|
})(),
|
|
478
122
|
...(issueControl?.activeWorkspaceOwnershipId !== undefined ? { activeWorkspaceId: issueControl.activeWorkspaceOwnershipId } : {}),
|
|
@@ -502,10 +146,11 @@ export class IssueWorkflowStore {
|
|
|
502
146
|
updatedAt: workspaceOwnership.updatedAt,
|
|
503
147
|
};
|
|
504
148
|
}
|
|
505
|
-
buildStageRun(
|
|
506
|
-
const
|
|
507
|
-
const
|
|
508
|
-
|
|
149
|
+
buildStageRun(runLease) {
|
|
150
|
+
const report = this.runReports.getRunReport(runLease.id);
|
|
151
|
+
const triggerWebhookId = runLease.triggerReceiptId
|
|
152
|
+
? this.authoritativeLedger.getEventReceipt(runLease.triggerReceiptId)?.externalId ?? `run-lease:${runLease.id}`
|
|
153
|
+
: `run-lease:${runLease.id}`;
|
|
509
154
|
return {
|
|
510
155
|
id: runLease.id,
|
|
511
156
|
pipelineRunId: runLease.id,
|
|
@@ -513,7 +158,11 @@ export class IssueWorkflowStore {
|
|
|
513
158
|
linearIssueId: runLease.linearIssueId,
|
|
514
159
|
workspaceId: runLease.workspaceOwnershipId,
|
|
515
160
|
stage: runLease.stage,
|
|
516
|
-
status: runLease.status === "failed"
|
|
161
|
+
status: runLease.status === "failed"
|
|
162
|
+
? "failed"
|
|
163
|
+
: runLease.status === "completed" || runLease.status === "released" || runLease.status === "paused"
|
|
164
|
+
? "completed"
|
|
165
|
+
: "running",
|
|
517
166
|
triggerWebhookId,
|
|
518
167
|
workflowFile: runLease.workflowFile,
|
|
519
168
|
promptText: runLease.promptText,
|
|
@@ -526,89 +175,8 @@ export class IssueWorkflowStore {
|
|
|
526
175
|
...(runLease.endedAt ? { endedAt: runLease.endedAt } : {}),
|
|
527
176
|
};
|
|
528
177
|
}
|
|
529
|
-
buildRunLease(row) {
|
|
530
|
-
return {
|
|
531
|
-
id: Number(row.id),
|
|
532
|
-
issueControlId: Number(row.issue_control_id),
|
|
533
|
-
projectId: String(row.project_id),
|
|
534
|
-
linearIssueId: String(row.linear_issue_id),
|
|
535
|
-
workspaceOwnershipId: Number(row.workspace_ownership_id),
|
|
536
|
-
stage: row.stage,
|
|
537
|
-
status: row.status,
|
|
538
|
-
...(row.trigger_receipt_id === null ? {} : { triggerReceiptId: Number(row.trigger_receipt_id) }),
|
|
539
|
-
workflowFile: String(row.workflow_file ?? ""),
|
|
540
|
-
promptText: String(row.prompt_text ?? ""),
|
|
541
|
-
...(row.thread_id === null ? {} : { threadId: String(row.thread_id) }),
|
|
542
|
-
...(row.parent_thread_id === null ? {} : { parentThreadId: String(row.parent_thread_id) }),
|
|
543
|
-
...(row.turn_id === null ? {} : { turnId: String(row.turn_id) }),
|
|
544
|
-
startedAt: String(row.started_at),
|
|
545
|
-
...(row.ended_at === null ? {} : { endedAt: String(row.ended_at) }),
|
|
546
|
-
...(row.failure_reason === null ? {} : { failureReason: String(row.failure_reason) }),
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
|
-
getIssueProjectionRow(projectId, linearIssueId) {
|
|
550
|
-
return this.connection
|
|
551
|
-
.prepare("SELECT * FROM issue_projection WHERE project_id = ? AND linear_issue_id = ?")
|
|
552
|
-
.get(projectId, linearIssueId);
|
|
553
|
-
}
|
|
554
|
-
getIssueControlRow(projectId, linearIssueId) {
|
|
555
|
-
return this.connection
|
|
556
|
-
.prepare("SELECT * FROM issue_control WHERE project_id = ? AND linear_issue_id = ?")
|
|
557
|
-
.get(projectId, linearIssueId);
|
|
558
|
-
}
|
|
559
|
-
getWorkspaceOwnershipRowById(id) {
|
|
560
|
-
return this.connection.prepare("SELECT * FROM workspace_ownership WHERE id = ?").get(id);
|
|
561
|
-
}
|
|
562
|
-
getRunLeaseRowById(id) {
|
|
563
|
-
return this.connection.prepare("SELECT * FROM run_leases WHERE id = ?").get(id);
|
|
564
|
-
}
|
|
565
|
-
listRunLeaseRows(params) {
|
|
566
|
-
const clauses = [];
|
|
567
|
-
const values = [];
|
|
568
|
-
if (params?.projectId) {
|
|
569
|
-
clauses.push("project_id = ?");
|
|
570
|
-
values.push(params.projectId);
|
|
571
|
-
}
|
|
572
|
-
if (params?.linearIssueId) {
|
|
573
|
-
clauses.push("linear_issue_id = ?");
|
|
574
|
-
values.push(params.linearIssueId);
|
|
575
|
-
}
|
|
576
|
-
if (params?.status) {
|
|
577
|
-
clauses.push("status = ?");
|
|
578
|
-
values.push(params.status);
|
|
579
|
-
}
|
|
580
|
-
const sql = `SELECT * FROM run_leases${clauses.length > 0 ? ` WHERE ${clauses.join(" AND ")}` : ""} ORDER BY id`;
|
|
581
|
-
return this.connection.prepare(sql).all(...values);
|
|
582
|
-
}
|
|
583
178
|
getLatestRunLeaseForIssue(projectId, linearIssueId) {
|
|
584
|
-
|
|
585
|
-
.prepare("SELECT * FROM run_leases WHERE project_id = ? AND linear_issue_id = ? ORDER BY id DESC LIMIT 1")
|
|
586
|
-
.get(projectId, linearIssueId);
|
|
587
|
-
return row ? this.buildRunLease(row) : undefined;
|
|
588
|
-
}
|
|
589
|
-
getRunReport(runLeaseId) {
|
|
590
|
-
const row = this.connection.prepare("SELECT * FROM run_reports WHERE run_lease_id = ?").get(runLeaseId);
|
|
591
|
-
return row ? mapRunReport(row) : undefined;
|
|
592
|
-
}
|
|
593
|
-
getEventReceiptById(id) {
|
|
594
|
-
const row = this.connection.prepare("SELECT * FROM event_receipts WHERE id = ?").get(id);
|
|
595
|
-
return row ? mapEventReceipt(row) : undefined;
|
|
596
|
-
}
|
|
597
|
-
ensureDesiredReceipt(projectId, linearIssueId, webhookId) {
|
|
598
|
-
const existing = this.connection
|
|
599
|
-
.prepare("SELECT * FROM event_receipts WHERE external_id = ? ORDER BY id DESC LIMIT 1")
|
|
600
|
-
.get(webhookId);
|
|
601
|
-
if (existing) {
|
|
602
|
-
return Number(existing.id);
|
|
603
|
-
}
|
|
604
|
-
const result = this.connection
|
|
605
|
-
.prepare(`
|
|
606
|
-
INSERT INTO event_receipts (
|
|
607
|
-
source, external_id, event_type, received_at, acceptance_status, processing_status, project_id, linear_issue_id
|
|
608
|
-
) VALUES (?, ?, ?, ?, 'accepted', 'processed', ?, ?)
|
|
609
|
-
`)
|
|
610
|
-
.run("patchrelay-desired-stage", webhookId, "desired_stage", isoNow(), projectId, linearIssueId);
|
|
611
|
-
return Number(result.lastInsertRowid);
|
|
179
|
+
return this.authoritativeLedger.listRunLeasesForIssue(projectId, linearIssueId).at(-1);
|
|
612
180
|
}
|
|
613
181
|
}
|
|
614
182
|
function resolvePipelineStatus(runStatus, lifecycleStatus) {
|
|
@@ -623,68 +191,3 @@ function resolvePipelineStatus(runStatus, lifecycleStatus) {
|
|
|
623
191
|
}
|
|
624
192
|
return "active";
|
|
625
193
|
}
|
|
626
|
-
function mapIssueProjection(row) {
|
|
627
|
-
return {
|
|
628
|
-
id: Number(row.id),
|
|
629
|
-
projectId: String(row.project_id),
|
|
630
|
-
linearIssueId: String(row.linear_issue_id),
|
|
631
|
-
...(row.issue_key === null ? {} : { issueKey: String(row.issue_key) }),
|
|
632
|
-
...(row.title === null ? {} : { title: String(row.title) }),
|
|
633
|
-
...(row.issue_url === null ? {} : { issueUrl: String(row.issue_url) }),
|
|
634
|
-
...(row.current_linear_state === null ? {} : { currentLinearState: String(row.current_linear_state) }),
|
|
635
|
-
...(row.last_webhook_at === null ? {} : { lastWebhookAt: String(row.last_webhook_at) }),
|
|
636
|
-
updatedAt: String(row.updated_at),
|
|
637
|
-
};
|
|
638
|
-
}
|
|
639
|
-
function mapIssueControl(row) {
|
|
640
|
-
return {
|
|
641
|
-
id: Number(row.id),
|
|
642
|
-
projectId: String(row.project_id),
|
|
643
|
-
linearIssueId: String(row.linear_issue_id),
|
|
644
|
-
...(row.desired_stage === null ? {} : { desiredStage: row.desired_stage }),
|
|
645
|
-
...(row.desired_receipt_id === null ? {} : { desiredReceiptId: Number(row.desired_receipt_id) }),
|
|
646
|
-
...(row.active_run_lease_id === null ? {} : { activeRunLeaseId: Number(row.active_run_lease_id) }),
|
|
647
|
-
...(row.active_workspace_ownership_id === null ? {} : { activeWorkspaceOwnershipId: Number(row.active_workspace_ownership_id) }),
|
|
648
|
-
...(row.service_owned_comment_id === null ? {} : { serviceOwnedCommentId: String(row.service_owned_comment_id) }),
|
|
649
|
-
...(row.active_agent_session_id === null ? {} : { activeAgentSessionId: String(row.active_agent_session_id) }),
|
|
650
|
-
lifecycleStatus: row.lifecycle_status,
|
|
651
|
-
updatedAt: String(row.updated_at),
|
|
652
|
-
};
|
|
653
|
-
}
|
|
654
|
-
function mapWorkspaceOwnership(row) {
|
|
655
|
-
return {
|
|
656
|
-
id: Number(row.id),
|
|
657
|
-
projectId: String(row.project_id),
|
|
658
|
-
linearIssueId: String(row.linear_issue_id),
|
|
659
|
-
branchName: String(row.branch_name),
|
|
660
|
-
worktreePath: String(row.worktree_path),
|
|
661
|
-
status: row.status,
|
|
662
|
-
...(row.current_run_lease_id === null ? {} : { currentRunLeaseId: Number(row.current_run_lease_id) }),
|
|
663
|
-
createdAt: String(row.created_at),
|
|
664
|
-
updatedAt: String(row.updated_at),
|
|
665
|
-
};
|
|
666
|
-
}
|
|
667
|
-
function mapRunReport(row) {
|
|
668
|
-
return {
|
|
669
|
-
runLeaseId: Number(row.run_lease_id),
|
|
670
|
-
...(row.summary_json === null ? {} : { summaryJson: String(row.summary_json) }),
|
|
671
|
-
...(row.report_json === null ? {} : { reportJson: String(row.report_json) }),
|
|
672
|
-
createdAt: String(row.created_at),
|
|
673
|
-
updatedAt: String(row.updated_at),
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
|
-
function mapEventReceipt(row) {
|
|
677
|
-
return {
|
|
678
|
-
id: Number(row.id),
|
|
679
|
-
source: String(row.source),
|
|
680
|
-
externalId: String(row.external_id),
|
|
681
|
-
eventType: String(row.event_type),
|
|
682
|
-
receivedAt: String(row.received_at),
|
|
683
|
-
acceptanceStatus: row.acceptance_status,
|
|
684
|
-
processingStatus: row.processing_status,
|
|
685
|
-
...(row.project_id === null ? {} : { projectId: String(row.project_id) }),
|
|
686
|
-
...(row.linear_issue_id === null ? {} : { linearIssueId: String(row.linear_issue_id) }),
|
|
687
|
-
...(row.headers_json === null ? {} : { headersJson: String(row.headers_json) }),
|
|
688
|
-
...(row.payload_json === null ? {} : { payloadJson: String(row.payload_json) }),
|
|
689
|
-
};
|
|
690
|
-
}
|