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/build-info.json
CHANGED
|
@@ -20,7 +20,7 @@ export async function collectClusterHealth(config, db, runCommand) {
|
|
|
20
20
|
});
|
|
21
21
|
const snapshots = openIssues.map((issue) => {
|
|
22
22
|
const tracked = db.getTrackedIssue(issue.projectId, issue.linearIssueId);
|
|
23
|
-
const deps = db.listIssueDependencies(issue.projectId, issue.linearIssueId);
|
|
23
|
+
const deps = db.issues.listIssueDependencies(issue.projectId, issue.linearIssueId);
|
|
24
24
|
const blockedBy = deps.filter((dep) => !isResolvedDependency(dep));
|
|
25
25
|
const missingTrackedBlockers = blockedBy.filter((dep) => {
|
|
26
26
|
if (trackedByLinearId.has(dep.blockerLinearIssueId))
|
package/dist/cli/data.js
CHANGED
|
@@ -94,7 +94,7 @@ export class CliDataAccess extends CliOperatorApiClient {
|
|
|
94
94
|
const issue = this.db.getTrackedIssueByKey(issueKey);
|
|
95
95
|
if (!issue)
|
|
96
96
|
return undefined;
|
|
97
|
-
const dbIssue = this.db.getIssueByKey(issueKey);
|
|
97
|
+
const dbIssue = this.db.issues.getIssueByKey(issueKey);
|
|
98
98
|
const activeRun = dbIssue.activeRunId ? this.db.runs.getRunById(dbIssue.activeRunId) : undefined;
|
|
99
99
|
const latestRun = this.db.runs.getLatestRunForIssue(issue.projectId, issue.linearIssueId);
|
|
100
100
|
const latestReport = normalizeStageReport(latestRun?.reportJson, latestRun?.status);
|
|
@@ -120,7 +120,7 @@ export class CliDataAccess extends CliOperatorApiClient {
|
|
|
120
120
|
const issue = this.db.getTrackedIssueByKey(issueKey);
|
|
121
121
|
if (!issue)
|
|
122
122
|
return undefined;
|
|
123
|
-
const dbIssue = this.db.getIssueByKey(issueKey);
|
|
123
|
+
const dbIssue = this.db.issues.getIssueByKey(issueKey);
|
|
124
124
|
const run = dbIssue.activeRunId ? this.db.runs.getRunById(dbIssue.activeRunId) : undefined;
|
|
125
125
|
if (!run)
|
|
126
126
|
return undefined;
|
|
@@ -132,7 +132,7 @@ export class CliDataAccess extends CliOperatorApiClient {
|
|
|
132
132
|
const issue = this.db.getTrackedIssueByKey(issueKey);
|
|
133
133
|
if (!issue)
|
|
134
134
|
return undefined;
|
|
135
|
-
const dbIssue = this.db.getIssueByKey(issueKey);
|
|
135
|
+
const dbIssue = this.db.issues.getIssueByKey(issueKey);
|
|
136
136
|
if (!dbIssue.branchName || !dbIssue.worktreePath)
|
|
137
137
|
return undefined;
|
|
138
138
|
return { issue, branchName: dbIssue.branchName, worktreePath: dbIssue.worktreePath, repoId: issue.projectId };
|
|
@@ -141,7 +141,7 @@ export class CliDataAccess extends CliOperatorApiClient {
|
|
|
141
141
|
const worktree = this.worktree(issueKey);
|
|
142
142
|
if (!worktree)
|
|
143
143
|
return undefined;
|
|
144
|
-
const dbIssue = this.db.getIssueByKey(issueKey);
|
|
144
|
+
const dbIssue = this.db.issues.getIssueByKey(issueKey);
|
|
145
145
|
const resumeThreadId = dbIssue.threadId ?? undefined;
|
|
146
146
|
return {
|
|
147
147
|
...worktree,
|
|
@@ -155,7 +155,7 @@ export class CliDataAccess extends CliOperatorApiClient {
|
|
|
155
155
|
if (options?.ensureWorktree) {
|
|
156
156
|
await this.ensureOpenWorktree(worktree);
|
|
157
157
|
}
|
|
158
|
-
const dbIssue = this.db.getIssueByKey(issueKey);
|
|
158
|
+
const dbIssue = this.db.issues.getIssueByKey(issueKey);
|
|
159
159
|
const existingThreadId = dbIssue.threadId;
|
|
160
160
|
if (existingThreadId && (await this.canReadThread(existingThreadId))) {
|
|
161
161
|
return { ...worktree, resumeThreadId: existingThreadId };
|
|
@@ -165,7 +165,7 @@ export class CliDataAccess extends CliOperatorApiClient {
|
|
|
165
165
|
}
|
|
166
166
|
const codex = await this.getCodex();
|
|
167
167
|
const thread = await codex.startThread({ cwd: worktree.worktreePath });
|
|
168
|
-
this.db.upsertIssue({
|
|
168
|
+
this.db.issues.upsertIssue({
|
|
169
169
|
projectId: worktree.issue.projectId,
|
|
170
170
|
linearIssueId: worktree.issue.linearIssueId,
|
|
171
171
|
threadId: thread.id,
|
|
@@ -179,7 +179,7 @@ export class CliDataAccess extends CliOperatorApiClient {
|
|
|
179
179
|
const issue = this.db.getTrackedIssueByKey(issueKey);
|
|
180
180
|
if (!issue)
|
|
181
181
|
return undefined;
|
|
182
|
-
const dbIssue = this.db.getIssueByKey(issueKey);
|
|
182
|
+
const dbIssue = this.db.issues.getIssueByKey(issueKey);
|
|
183
183
|
const issueSession = this.db.issueSessions.getIssueSession(issue.projectId, issue.linearIssueId);
|
|
184
184
|
if (dbIssue.activeRunId !== undefined) {
|
|
185
185
|
throw new Error(`Issue ${issueKey} already has an active run.`);
|
|
@@ -200,7 +200,7 @@ export class CliDataAccess extends CliOperatorApiClient {
|
|
|
200
200
|
? "changes_requested"
|
|
201
201
|
: "delegated";
|
|
202
202
|
this.appendRetryWake(dbIssue, runType);
|
|
203
|
-
this.db.upsertIssue({
|
|
203
|
+
this.db.issues.upsertIssue({
|
|
204
204
|
projectId: issue.projectId,
|
|
205
205
|
linearIssueId: issue.linearIssueId,
|
|
206
206
|
pendingRunType: null,
|
|
@@ -214,13 +214,14 @@ export class CliDataAccess extends CliOperatorApiClient {
|
|
|
214
214
|
const issue = this.db.getTrackedIssueByKey(issueKey);
|
|
215
215
|
if (!issue)
|
|
216
216
|
return undefined;
|
|
217
|
-
const dbIssue = this.db.getIssueByKey(issueKey);
|
|
217
|
+
const dbIssue = this.db.issues.getIssueByKey(issueKey);
|
|
218
218
|
const runs = this.db.runs.listRunsForIssue(issue.projectId, issue.linearIssueId);
|
|
219
219
|
const sessions = runs
|
|
220
220
|
.slice()
|
|
221
221
|
.reverse()
|
|
222
222
|
.map((run) => {
|
|
223
223
|
const summary = summarizeRun(run);
|
|
224
|
+
const eventCount = this.db.runs.listThreadEvents(run.id).length;
|
|
224
225
|
return {
|
|
225
226
|
runId: run.id,
|
|
226
227
|
runType: run.runType,
|
|
@@ -230,7 +231,8 @@ export class CliDataAccess extends CliOperatorApiClient {
|
|
|
230
231
|
...(run.parentThreadId ? { parentThreadId: run.parentThreadId } : {}),
|
|
231
232
|
...(summary ? { summary } : {}),
|
|
232
233
|
...(run.failureReason ? { failureReason: run.failureReason } : {}),
|
|
233
|
-
eventCount
|
|
234
|
+
eventCount,
|
|
235
|
+
eventCountAvailable: this.config.runner.codex.persistExtendedHistory || eventCount > 0,
|
|
234
236
|
startedAt: run.startedAt,
|
|
235
237
|
...(run.endedAt ? { endedAt: run.endedAt } : {}),
|
|
236
238
|
isCurrentThread: run.threadId !== undefined && run.threadId === dbIssue.threadId,
|
|
@@ -106,7 +106,9 @@ export function formatSessionHistory(result, buildOpenForThread) {
|
|
|
106
106
|
if (session.turnId) {
|
|
107
107
|
lines.push(value("Turn", session.turnId));
|
|
108
108
|
}
|
|
109
|
-
lines.push(value("Events", session.
|
|
109
|
+
lines.push(value("Events", session.eventCountAvailable
|
|
110
|
+
? session.eventCount
|
|
111
|
+
: "not persisted (persistExtendedHistory=false)"));
|
|
110
112
|
if (session.summary) {
|
|
111
113
|
lines.push(value("Summary", truncateLine(session.summary)));
|
|
112
114
|
}
|
|
@@ -4,24 +4,16 @@ export class IssueSessionStore {
|
|
|
4
4
|
connection;
|
|
5
5
|
mapIssueSessionRow;
|
|
6
6
|
mapIssueSessionEventRow;
|
|
7
|
-
|
|
7
|
+
issues;
|
|
8
|
+
runs;
|
|
8
9
|
deriveImplicitReactiveWake;
|
|
9
|
-
|
|
10
|
-
upsertIssue;
|
|
11
|
-
finishRun;
|
|
12
|
-
updateRunThread;
|
|
13
|
-
setBranchOwner;
|
|
14
|
-
constructor(connection, mapIssueSessionRow, mapIssueSessionEventRow, getIssue, deriveImplicitReactiveWake, transaction, upsertIssue, finishRun, updateRunThread, setBranchOwner) {
|
|
10
|
+
constructor(connection, mapIssueSessionRow, mapIssueSessionEventRow, issues, runs, deriveImplicitReactiveWake) {
|
|
15
11
|
this.connection = connection;
|
|
16
12
|
this.mapIssueSessionRow = mapIssueSessionRow;
|
|
17
13
|
this.mapIssueSessionEventRow = mapIssueSessionEventRow;
|
|
18
|
-
this.
|
|
14
|
+
this.issues = issues;
|
|
15
|
+
this.runs = runs;
|
|
19
16
|
this.deriveImplicitReactiveWake = deriveImplicitReactiveWake;
|
|
20
|
-
this.transaction = transaction;
|
|
21
|
-
this.upsertIssue = upsertIssue;
|
|
22
|
-
this.finishRun = finishRun;
|
|
23
|
-
this.updateRunThread = updateRunThread;
|
|
24
|
-
this.setBranchOwner = setBranchOwner;
|
|
25
17
|
}
|
|
26
18
|
getIssueSession(projectId, linearIssueId) {
|
|
27
19
|
const row = this.connection
|
|
@@ -107,7 +99,7 @@ export class IssueSessionStore {
|
|
|
107
99
|
return row !== undefined;
|
|
108
100
|
}
|
|
109
101
|
peekIssueSessionWake(projectId, linearIssueId) {
|
|
110
|
-
const issue = this.getIssue(projectId, linearIssueId);
|
|
102
|
+
const issue = this.issues.getIssue(projectId, linearIssueId);
|
|
111
103
|
if (!issue)
|
|
112
104
|
return undefined;
|
|
113
105
|
const events = this.listIssueSessionEvents(projectId, linearIssueId, { pendingOnly: true });
|
|
@@ -201,40 +193,40 @@ export class IssueSessionStore {
|
|
|
201
193
|
return { projectId, linearIssueId, leaseId };
|
|
202
194
|
}
|
|
203
195
|
withIssueSessionLease(projectId, linearIssueId, leaseId, fn) {
|
|
204
|
-
return this.transaction(() => {
|
|
196
|
+
return this.connection.transaction(() => {
|
|
205
197
|
if (!this.hasActiveIssueSessionLease(projectId, linearIssueId, leaseId)) {
|
|
206
198
|
return undefined;
|
|
207
199
|
}
|
|
208
200
|
return fn();
|
|
209
|
-
});
|
|
201
|
+
})();
|
|
210
202
|
}
|
|
211
203
|
upsertIssueWithLease(lease, params) {
|
|
212
|
-
return this.withIssueSessionLease(lease.projectId, lease.linearIssueId, lease.leaseId, () => this.upsertIssue(params));
|
|
204
|
+
return this.withIssueSessionLease(lease.projectId, lease.linearIssueId, lease.leaseId, () => this.issues.upsertIssue(params));
|
|
213
205
|
}
|
|
214
206
|
upsertIssueRespectingActiveLease(projectId, linearIssueId, params) {
|
|
215
207
|
const lease = this.getActiveIssueSessionLease(projectId, linearIssueId);
|
|
216
208
|
if (!lease) {
|
|
217
|
-
return this.upsertIssue(params);
|
|
209
|
+
return this.issues.upsertIssue(params);
|
|
218
210
|
}
|
|
219
211
|
return this.upsertIssueWithLease(lease, params);
|
|
220
212
|
}
|
|
221
213
|
finishRunWithLease(lease, runId, params) {
|
|
222
214
|
return this.withIssueSessionLease(lease.projectId, lease.linearIssueId, lease.leaseId, () => {
|
|
223
|
-
this.finishRun(runId, params);
|
|
215
|
+
this.runs.finishRun(runId, params);
|
|
224
216
|
return true;
|
|
225
217
|
}) ?? false;
|
|
226
218
|
}
|
|
227
219
|
finishRunRespectingActiveLease(projectId, linearIssueId, runId, params) {
|
|
228
220
|
const lease = this.getActiveIssueSessionLease(projectId, linearIssueId);
|
|
229
221
|
if (!lease) {
|
|
230
|
-
this.finishRun(runId, params);
|
|
222
|
+
this.runs.finishRun(runId, params);
|
|
231
223
|
return true;
|
|
232
224
|
}
|
|
233
225
|
return this.finishRunWithLease(lease, runId, params);
|
|
234
226
|
}
|
|
235
227
|
updateRunThreadWithLease(lease, runId, params) {
|
|
236
228
|
return this.withIssueSessionLease(lease.projectId, lease.linearIssueId, lease.leaseId, () => {
|
|
237
|
-
this.updateRunThread(runId, params);
|
|
229
|
+
this.runs.updateRunThread(runId, params);
|
|
238
230
|
return true;
|
|
239
231
|
}) ?? false;
|
|
240
232
|
}
|
|
@@ -273,14 +265,14 @@ export class IssueSessionStore {
|
|
|
273
265
|
}
|
|
274
266
|
setBranchOwnerWithLease(lease, owner) {
|
|
275
267
|
return this.withIssueSessionLease(lease.projectId, lease.linearIssueId, lease.leaseId, () => {
|
|
276
|
-
this.setBranchOwner(lease.projectId, lease.linearIssueId, owner);
|
|
268
|
+
this.issues.setBranchOwner(lease.projectId, lease.linearIssueId, owner);
|
|
277
269
|
return true;
|
|
278
270
|
}) ?? false;
|
|
279
271
|
}
|
|
280
272
|
setBranchOwnerRespectingActiveLease(projectId, linearIssueId, owner) {
|
|
281
273
|
const lease = this.getActiveIssueSessionLease(projectId, linearIssueId);
|
|
282
274
|
if (!lease) {
|
|
283
|
-
this.setBranchOwner(projectId, linearIssueId, owner);
|
|
275
|
+
this.issues.setBranchOwner(projectId, linearIssueId, owner);
|
|
284
276
|
return true;
|
|
285
277
|
}
|
|
286
278
|
return this.setBranchOwnerWithLease(lease, owner);
|