a4c7c0fc15
* plan: issue 447 run artifact tracking and UI (supersedes stale pill notes) Made-with: Cursor * feat: workflow run artifact urls, chips, and safe PATCH validation Made-with: Cursor * chore(action): refresh latest-by-provider model snapshot Made-with: Cursor * refactor: resolve artifact urls via GraphQL nodes(ids), drop stored url columns Made-with: Cursor * docs: finalize issue 447 run-artifacts plan; remove demo backfill script Made-with: Cursor * refactor: DRY node-id constraint, replace margin with padding wrapper Made-with: Cursor * refactor: DRY audit — shared row info, derived types, unified Prisma select - extract WorkflowRunRowInfo component (description + issue link + time + pills) shared by ActiveWorkflowRunsSection and WorkflowRunHistory - derive API payload types via Omit + & instead of manual field lists; serialize with spread + override for bigint/date fields - extract workflowRunListSelect shared Prisma select base; history extends with completedAt - inline updateCommentNodeId → direct patchWorkflowRunFields calls - derive WorkflowRunArtifactSlice from canonical exported types - delete cancelling-out URL column migrations (no schema change vs main) Made-with: Cursor * refactor: artifact chips as inline CTAs with proper vertical alignment - chips now render as action links: "Open PR #N", "View summary", etc. - only render chips with resolved URLs; remove inert span fallback - inline chips in the row (right-justified) instead of a separate line - fix vertical alignment: remove ul/li wrappers that caused line-height mismatch, render chips as direct row siblings via flat flex layout - change row to items-center, remove compensating self-start/pt nudges - cancelled run X icon uses red-600 Made-with: Cursor * chore(action): refresh latest-by-provider model snapshot Made-with: Cursor --------- Co-authored-by: Colin McDonnell <colinmcd94@gmail.com>
63 lines
1.9 KiB
TypeScript
63 lines
1.9 KiB
TypeScript
import type { ToolContext } from "../mcp/server.ts";
|
|
import { apiFetch } from "./apiFetch.ts";
|
|
import { log } from "./cli.ts";
|
|
import { retry } from "./retry.ts";
|
|
|
|
/** Keys accepted by PATCH /api/workflow-run/[runId] — keep in sync with `ALLOWED_FIELDS` in `app/api/workflow-run/[runId]/route.ts`. */
|
|
export type WorkflowRunArtifactPatchKey =
|
|
| "prNodeId"
|
|
| "issueNodeId"
|
|
| "reviewNodeId"
|
|
| "planCommentNodeId"
|
|
| "summaryCommentNodeId";
|
|
|
|
export type WorkflowRunArtifactPatch = Partial<Record<WorkflowRunArtifactPatchKey, string>>;
|
|
|
|
const ARTIFACT_PATCH_KEYS: WorkflowRunArtifactPatchKey[] = [
|
|
"prNodeId",
|
|
"issueNodeId",
|
|
"reviewNodeId",
|
|
"planCommentNodeId",
|
|
"summaryCommentNodeId",
|
|
];
|
|
|
|
/** PATCH workflow-run artifact fields (Pullfrog JWT, not GitHub). */
|
|
export async function patchWorkflowRunFields(
|
|
ctx: ToolContext,
|
|
fields: WorkflowRunArtifactPatch
|
|
): Promise<void> {
|
|
if (ctx.runId === undefined || !ctx.apiToken) return;
|
|
const body: Record<string, string> = {};
|
|
for (const key of ARTIFACT_PATCH_KEYS) {
|
|
const value = fields[key];
|
|
if (typeof value === "string" && value.length > 0) {
|
|
body[key] = value;
|
|
}
|
|
}
|
|
if (Object.keys(body).length === 0) return;
|
|
try {
|
|
await retry(
|
|
async () => {
|
|
const response = await apiFetch({
|
|
path: `/api/workflow-run/${ctx.runId}`,
|
|
method: "PATCH",
|
|
headers: {
|
|
authorization: `Bearer ${ctx.apiToken}`,
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify(body),
|
|
signal: AbortSignal.timeout(10_000),
|
|
});
|
|
if (!response.ok) throw new Error(`PATCH workflow-run: ${response.status}`);
|
|
},
|
|
{
|
|
maxAttempts: 3,
|
|
delayMs: 2000,
|
|
label: "patchWorkflowRunFields",
|
|
}
|
|
);
|
|
} catch (error) {
|
|
log.warning(`patchWorkflowRunFields exhausted retries: ${error}`);
|
|
}
|
|
}
|