Files
fusion/packages/dashboard/app/components/TaskVerificationStatus.tsx
gsxdsm 38891bfd81 FN-8296: add chat-requested task verification
Enable chat agents to queue and monitor executor-owned verification runs.

- Persist task verification requests through a new PostgreSQL migration.
- Expose action-gated chat request and status tools with executor processing.
- Show verification status in task and Command Center views.
- Advance the schema baseline to migration 0024 and keep chat mocks complete.

Files changed:
 .changeset/fn-8296-feature.md                      |  7 ++
 docs/agent-tool-surface-full-loop.md               | 10 +--
 docs/dashboard-guide.md                            |  4 +
 packages/core/src/index.ts                         |  2 +
 .../core/src/postgres/migrations/0000_initial.sql  | 20 +++++
 .../migrations/0024_task_verification_request.sql  | 20 +++++
 packages/core/src/postgres/schema-applier.ts       | 13 ++-
 packages/core/src/postgres/schema/project.ts       | 25 ++++++
 packages/core/src/store.ts                         | 16 +++-
 packages/core/src/task-store/reads.ts              | 14 +++-
 packages/core/src/task-store/remaining-ops-6.ts    | 49 ++++++++++-
 packages/core/src/types.ts                         | 30 +++++++
 packages/dashboard/app/api/legacy.ts               |  1 +
 packages/dashboard/app/api/task-content.ts         | 10 +++
 .../dashboard/app/components/TaskDetailModal.tsx   | 17 +++-
 .../app/components/TaskVerificationStatus.css      | 94 ++++++++++++++++++++++
 .../app/components/TaskVerificationStatus.tsx      | 39 +++++++++
 .../__tests__/TaskVerificationStatus.test.tsx      | 28 +++++++
 .../components/command-center/CommandCenter.css    | 33 ++++++++
 .../components/command-center/CommandCenter.tsx    | 37 ++++++++-
 packages/dashboard/src/__tests__/chat.test.ts      |  1 +
 packages/dashboard/src/chat.ts                     | 55 +++++++++++++
 .../src/routes/register-command-center-routes.ts   | 20 +++++
 .../src/routes/register-task-workflow-routes.ts    | 17 ++++
 packages/engine/src/executor.ts                    | 51 +++++++++++-
 packages/engine/src/gating-classifications.ts      |  5 ++
 packages/engine/src/index.ts                       |  2 +-
 27 files changed, 605 insertions(+), 15 deletions(-)

Fusion-Task-Id: FN-8296

Fusion-Task-Lineage: f94647cf-c89f-4f0e-b25f-cbf5b56683bc

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-18 18:38:47 -07:00

40 lines
2.2 KiB
TypeScript

import type { TaskVerificationRequest } from "@fusion/core";
import { AlertCircle, CheckCircle2, Loader2 } from "lucide-react";
import "./TaskVerificationStatus.css";
function formatDuration(durationMs: number | undefined): string | null {
if (typeof durationMs !== "number") return null;
return `${(durationMs / 1000).toFixed(1)}s`;
}
/**
* FNXC:TaskVerificationStatus 2026-07-30-00:00:
* FN-8296 exposes executor-owned verification as persisted state in every human
* surface. This component deliberately renders a record only; it never offers a
* command control or reimplements the chat/executor permission boundary.
*/
export function TaskVerificationStatus({ request, compact = false }: { request: TaskVerificationRequest | null; compact?: boolean }) {
if (!request) return compact ? null : <p className="task-verification-status task-verification-status--empty">No chat verification requested.</p>;
const running = request.status === "requested" || request.status === "running";
const failed = request.status === "failed" || request.status === "rejected";
const Icon = running ? Loader2 : failed ? AlertCircle : CheckCircle2;
const summary = request.status === "rejected"
? request.rejectionReason ?? "Request rejected"
: request.result
? `${request.result.success ? "Passed" : "Failed"}${formatDuration(request.result.durationMs) ? ` · ${formatDuration(request.result.durationMs)}` : ""}`
: request.status === "requested" ? "Queued for the task executor" : "Running in the task worktree";
return (
<section className={`task-verification-status task-verification-status--${request.status}${compact ? " task-verification-status--compact" : ""}`} aria-live="polite" data-testid="task-verification-status">
<div className="task-verification-status__heading">
<Icon aria-hidden="true" className={running ? "task-verification-status__spinner" : undefined} />
<strong>Verification · {request.profile}</strong>
<span className="task-verification-status__state">{request.status}</span>
</div>
<p>{summary}</p>
{!compact && request.result?.stderrTail ? <pre className="task-verification-status__output">{request.result.stderrTail}</pre> : null}
</section>
);
}