patchrelay 0.12.8 → 0.13.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/agent-session-plan.js +155 -11
- package/dist/agent-session-presentation.js +19 -14
- package/dist/build-info.json +3 -3
- package/dist/cli/args.js +1 -0
- package/dist/cli/commands/watch.js +30 -0
- package/dist/cli/help.js +1 -0
- package/dist/cli/index.js +8 -0
- package/dist/cli/watch/App.js +43 -0
- package/dist/cli/watch/HelpBar.js +7 -0
- package/dist/cli/watch/IssueDetailView.js +11 -0
- package/dist/cli/watch/IssueListView.js +9 -0
- package/dist/cli/watch/IssueRow.js +42 -0
- package/dist/cli/watch/ItemLine.js +72 -0
- package/dist/cli/watch/StatusBar.js +6 -0
- package/dist/cli/watch/ThreadView.js +20 -0
- package/dist/cli/watch/TurnSection.js +15 -0
- package/dist/cli/watch/use-detail-stream.js +160 -0
- package/dist/cli/watch/use-watch-stream.js +102 -0
- package/dist/cli/watch/watch-state.js +261 -0
- package/dist/codex-app-server.js +1 -4
- package/dist/config.js +2 -0
- package/dist/github-webhook-handler.js +44 -19
- package/dist/http.js +81 -0
- package/dist/issue-query-service.js +17 -2
- package/dist/linear-session-reporting.js +134 -0
- package/dist/run-orchestrator.js +65 -18
- package/dist/run-reporting.js +31 -0
- package/dist/service.js +60 -0
- package/dist/webhook-handler.js +49 -28
- package/package.json +4 -1
package/dist/webhook-handler.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildAgentSessionPlanForIssue, } from "./agent-session-plan.js";
|
|
2
2
|
import { buildAgentSessionExternalUrls } from "./agent-session-presentation.js";
|
|
3
|
+
import { buildAlreadyRunningThought, buildDelegationThought, buildPromptDeliveredThought, } from "./linear-session-reporting.js";
|
|
3
4
|
import { resolveProject, triggerEventAllowed, trustedActorAllowed } from "./project-resolution.js";
|
|
4
5
|
import { normalizeWebhook } from "./webhooks.js";
|
|
5
6
|
import { InstallationWebhookHandler } from "./webhook-installation-handler.js";
|
|
@@ -138,10 +139,10 @@ export class WebhookHandler {
|
|
|
138
139
|
const activeRun = existingIssue?.activeRunId ? this.db.getRun(existingIssue.activeRunId) : undefined;
|
|
139
140
|
const delegated = this.isDelegatedToPatchRelay(project, normalized);
|
|
140
141
|
const triggerAllowed = triggerEventAllowed(project, normalized.triggerEvent);
|
|
141
|
-
|
|
142
|
-
//
|
|
142
|
+
const pendingRunContextJson = mergePendingImplementationContext(existingIssue?.pendingRunContextJson, normalized);
|
|
143
|
+
// In the factory model, only a true delegation queues implementation work.
|
|
143
144
|
let pendingRunType;
|
|
144
|
-
const isDelegationSignal = delegated
|
|
145
|
+
const isDelegationSignal = delegated;
|
|
145
146
|
if (isDelegationSignal && triggerAllowed && !activeRun && !existingIssue?.pendingRunType) {
|
|
146
147
|
pendingRunType = "implementation";
|
|
147
148
|
}
|
|
@@ -157,6 +158,9 @@ export class WebhookHandler {
|
|
|
157
158
|
...(normalizedIssue.url ? { url: normalizedIssue.url } : {}),
|
|
158
159
|
...(normalizedIssue.stateName ? { currentLinearState: normalizedIssue.stateName } : {}),
|
|
159
160
|
...(pendingRunType ? { pendingRunType, factoryState: "delegated" } : {}),
|
|
161
|
+
...((pendingRunType || existingIssue?.pendingRunType === "implementation") && pendingRunContextJson
|
|
162
|
+
? { pendingRunContextJson }
|
|
163
|
+
: {}),
|
|
160
164
|
...(agentSessionId !== undefined ? { agentSessionId } : {}),
|
|
161
165
|
});
|
|
162
166
|
return {
|
|
@@ -189,19 +193,15 @@ export class WebhookHandler {
|
|
|
189
193
|
return;
|
|
190
194
|
}
|
|
191
195
|
if (desiredStage) {
|
|
192
|
-
|
|
193
|
-
await this.
|
|
194
|
-
|
|
195
|
-
body: `PatchRelay started working on the ${desiredStage} workflow.`,
|
|
196
|
-
});
|
|
196
|
+
const latestIssue = this.db.getIssue(project.id, normalized.issue.id);
|
|
197
|
+
await this.syncAgentSession(linear, normalized.agentSession.id, latestIssue ?? trackedIssue, { pendingRunType: desiredStage });
|
|
198
|
+
await this.publishAgentActivity(linear, normalized.agentSession.id, buildDelegationThought(desiredStage));
|
|
197
199
|
return;
|
|
198
200
|
}
|
|
199
201
|
if (activeRun) {
|
|
200
|
-
|
|
201
|
-
await this.
|
|
202
|
-
|
|
203
|
-
body: `PatchRelay is already running the ${activeRun.runType} workflow for this issue.`,
|
|
204
|
-
});
|
|
202
|
+
const latestIssue = this.db.getIssue(project.id, normalized.issue.id);
|
|
203
|
+
await this.syncAgentSession(linear, normalized.agentSession.id, latestIssue ?? trackedIssue, { activeRunType: activeRun.runType });
|
|
204
|
+
await this.publishAgentActivity(linear, normalized.agentSession.id, buildAlreadyRunningThought(activeRun.runType));
|
|
205
205
|
return;
|
|
206
206
|
}
|
|
207
207
|
await this.publishAgentActivity(linear, normalized.agentSession.id, {
|
|
@@ -242,18 +242,13 @@ export class WebhookHandler {
|
|
|
242
242
|
summary: `Could not deliver follow-up prompt to active ${activeRun.runType} workflow`,
|
|
243
243
|
});
|
|
244
244
|
}
|
|
245
|
-
await this.publishAgentActivity(linear, normalized.agentSession.id, {
|
|
246
|
-
type: "thought",
|
|
247
|
-
body: `PatchRelay routed your follow-up instructions into the active ${activeRun.runType} workflow.`,
|
|
248
|
-
});
|
|
245
|
+
await this.publishAgentActivity(linear, normalized.agentSession.id, buildPromptDeliveredThought(activeRun.runType), { ephemeral: true });
|
|
249
246
|
return;
|
|
250
247
|
}
|
|
251
248
|
if (desiredStage) {
|
|
252
|
-
|
|
253
|
-
await this.
|
|
254
|
-
|
|
255
|
-
body: `PatchRelay is preparing the ${desiredStage} workflow from your latest prompt.`,
|
|
256
|
-
});
|
|
249
|
+
const latestIssue = this.db.getIssue(project.id, normalized.issue.id);
|
|
250
|
+
await this.syncAgentSession(linear, normalized.agentSession.id, latestIssue ?? trackedIssue, { pendingRunType: desiredStage });
|
|
251
|
+
await this.publishAgentActivity(linear, normalized.agentSession.id, buildDelegationThought(desiredStage, "prompt"), { ephemeral: true });
|
|
257
252
|
}
|
|
258
253
|
}
|
|
259
254
|
// ─── Comment handling (inlined) ───────────────────────────────────
|
|
@@ -303,27 +298,40 @@ export class WebhookHandler {
|
|
|
303
298
|
}
|
|
304
299
|
}
|
|
305
300
|
// ─── Helpers ──────────────────────────────────────────────────────
|
|
306
|
-
async publishAgentActivity(linear, agentSessionId, content) {
|
|
301
|
+
async publishAgentActivity(linear, agentSessionId, content, options) {
|
|
307
302
|
try {
|
|
308
303
|
await linear.createAgentActivity({
|
|
309
304
|
agentSessionId,
|
|
310
305
|
content,
|
|
311
|
-
ephemeral: content.type === "thought",
|
|
306
|
+
ephemeral: options?.ephemeral ?? content.type === "thought",
|
|
312
307
|
});
|
|
313
308
|
}
|
|
314
309
|
catch (error) {
|
|
315
310
|
this.logger.warn({ agentSessionId, error: error instanceof Error ? error.message : String(error) }, "Failed to publish Linear agent activity");
|
|
316
311
|
}
|
|
317
312
|
}
|
|
318
|
-
async
|
|
313
|
+
async syncAgentSession(linear, agentSessionId, issue, options) {
|
|
319
314
|
if (!linear.updateAgentSession)
|
|
320
315
|
return;
|
|
321
316
|
try {
|
|
322
|
-
const
|
|
317
|
+
const prUrl = issue && "prUrl" in issue ? issue.prUrl : undefined;
|
|
318
|
+
const externalUrls = buildAgentSessionExternalUrls(this.config, {
|
|
319
|
+
...(issue?.issueKey ? { issueKey: issue.issueKey } : {}),
|
|
320
|
+
...(prUrl ? { prUrl } : {}),
|
|
321
|
+
});
|
|
323
322
|
await linear.updateAgentSession({
|
|
324
323
|
agentSessionId,
|
|
325
324
|
...(externalUrls ? { externalUrls } : {}),
|
|
326
|
-
|
|
325
|
+
...(issue
|
|
326
|
+
? {
|
|
327
|
+
plan: buildAgentSessionPlanForIssue({
|
|
328
|
+
factoryState: issue.factoryState,
|
|
329
|
+
pendingRunType: options?.pendingRunType ?? ("pendingRunType" in issue ? issue.pendingRunType : undefined),
|
|
330
|
+
ciRepairAttempts: "ciRepairAttempts" in issue ? issue.ciRepairAttempts : 0,
|
|
331
|
+
queueRepairAttempts: "queueRepairAttempts" in issue ? issue.queueRepairAttempts : 0,
|
|
332
|
+
}, options?.activeRunType ? { activeRunType: options.activeRunType } : undefined),
|
|
333
|
+
}
|
|
334
|
+
: {}),
|
|
327
335
|
});
|
|
328
336
|
}
|
|
329
337
|
catch (error) {
|
|
@@ -372,6 +380,19 @@ export class WebhookHandler {
|
|
|
372
380
|
function hasCompleteIssueContext(issue) {
|
|
373
381
|
return Boolean(issue.stateName && issue.delegateId && issue.teamId && issue.teamKey);
|
|
374
382
|
}
|
|
383
|
+
function mergePendingImplementationContext(existingJson, normalized) {
|
|
384
|
+
const existing = existingJson ? safeJsonParse(existingJson) ?? {} : {};
|
|
385
|
+
const next = { ...existing };
|
|
386
|
+
const promptContext = normalized.agentSession?.promptContext?.trim();
|
|
387
|
+
const promptBody = normalized.agentSession?.promptBody?.trim();
|
|
388
|
+
if (promptContext) {
|
|
389
|
+
next.promptContext = promptContext;
|
|
390
|
+
}
|
|
391
|
+
if (promptBody) {
|
|
392
|
+
next.promptBody = promptBody;
|
|
393
|
+
}
|
|
394
|
+
return Object.keys(next).length > 0 ? JSON.stringify(next) : undefined;
|
|
395
|
+
}
|
|
375
396
|
function mergeIssueMetadata(issue, liveIssue) {
|
|
376
397
|
return {
|
|
377
398
|
...issue,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patchrelay",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -43,13 +43,16 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"fastify": "^5.8.2",
|
|
45
45
|
"fastify-raw-body": "^5.0.0",
|
|
46
|
+
"ink": "^6.8.0",
|
|
46
47
|
"pino": "^10.3.1",
|
|
47
48
|
"pino-logfmt": "^1.1.3",
|
|
49
|
+
"react": "^19.2.4",
|
|
48
50
|
"zod": "^4.3.6"
|
|
49
51
|
},
|
|
50
52
|
"devDependencies": {
|
|
51
53
|
"@eslint/js": "^10.0.1",
|
|
52
54
|
"@types/node": "^24.12.0",
|
|
55
|
+
"@types/react": "^19.2.14",
|
|
53
56
|
"eslint": "^10.0.3",
|
|
54
57
|
"typescript": "^5.9.3",
|
|
55
58
|
"typescript-eslint": "^8.57.0"
|