Add opt-in local screenshot attachments and scrubbed activity traces to reports. - Capture, preview, confirm, and locally retain report screenshots without GitHub egress. - Include bounded activity traces in draft and filing context with server-side validation. - Add report pipeline coverage, documentation, and release metadata. Files changed: .changeset/fn-8309-report-capture.md | 7 ++ docs/dashboard-guide.md | 2 + packages/dashboard/app/App.tsx | 10 ++ packages/dashboard/app/api/report.ts | 16 ++- packages/dashboard/app/components/ReportModal.css | 3 + packages/dashboard/app/components/ReportModal.tsx | 45 ++++++- .../app/utils/__tests__/activity-trace.test.ts | 19 +++ packages/dashboard/app/utils/activity-trace.ts | 37 ++++++ packages/dashboard/app/utils/capture-screenshot.ts | 22 ++++ packages/dashboard/package.json | 5 +- .../src/__tests__/report-pipeline.test.ts | 13 +++ packages/dashboard/src/report-pipeline.ts | 29 ++++- packages/dashboard/src/routes.ts | 2 +- .../dashboard/src/routes/register-report-routes.ts | 85 +++++++++++++- packages/dashboard/src/routes/types.ts | 4 +- pnpm-lock.yaml | 129 ++++++++++----------- 16 files changed, 341 insertions(+), 87 deletions(-) Fusion-Task-Id: FN-8309 Fusion-Task-Lineage: db9c14a6-1721-4e81-8891-cfd301473cd0 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
24 lines
1.7 KiB
TypeScript
24 lines
1.7 KiB
TypeScript
import type { ReportActionType } from "@fusion/core";
|
|
|
|
async function post(path: string, body: unknown) {
|
|
const response = await fetch(path, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) });
|
|
if (!response.ok) throw new Error((await response.json().catch(() => ({ error: response.statusText }))).error ?? response.statusText);
|
|
return response.json();
|
|
}
|
|
|
|
export interface ReportActivityTraceEntry { ts: string; kind: string; label: string; }
|
|
export interface ReportContextInput { actionType: ReportActionType; userPrompt: string; contextRefs?: { taskId?: string; agentId?: string }; activityTrace?: ReportActivityTraceEntry[]; screenshotArtifactId?: string; }
|
|
|
|
export async function uploadReportScreenshot(blob: Blob, contextRefs?: { taskId?: string; agentId?: string }): Promise<{ artifactId: string; uri?: string }> {
|
|
const form = new FormData();
|
|
form.append("screenshot", blob, "report-screenshot.jpg");
|
|
if (contextRefs) form.append("contextRefs", JSON.stringify(contextRefs));
|
|
const response = await fetch("/api/report/attachment", { method: "POST", body: form });
|
|
if (!response.ok) throw new Error((await response.json().catch(() => ({ error: response.statusText }))).error ?? response.statusText);
|
|
return response.json();
|
|
}
|
|
|
|
export function reportDraft(input: ReportContextInput) { return post("/api/report/draft", input); }
|
|
export function reportFile(input: { actionType: ReportActionType; report: unknown; endorseIssueNumber?: number; endorseDiscussionId?: string; activityTrace?: ReportActivityTraceEntry[]; screenshotArtifactId?: string }) { return post("/api/report/file", input); }
|
|
export function reportHelp(question: string) { return post("/api/report/help", { question }); }
|