Intelligence

Artifacts

Browse the repository, read documents, and manage the governance folders. Source, runtime, and infrastructure are read-only.

Repository
.gitignoreDockerfilenext-env.d.tsnext.config.mjspackage-lock.jsonpackage.jsonpostcss.config.mjsREADME.mdtailwind.config.tstsconfig.jsontsconfig.tsbuildinfo
README.md
CONSTITUTION_COMPLIANCE_AUDIT_V1.mdREADME.md
repositories/aaf-holdings/hq01/components/executives/instruct-hq01.tsx
15.5 KB
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import Link from "next/link";
import {
  Send,
  Loader2,
  ArrowRight,
  Building2,
  FileText,
  AlertTriangle,
  CheckCircle2,
  Play,
  ClipboardCheck,
  X,
  CornerUpRight,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Card } from "@/components/ui/card";
import { cn } from "@/lib/utils";
import type {
  Briefing,
  Confidence,
  ExecutiveProposal,
  RoutingResult,
} from "@/lib/executives/types";

const CONFIDENCE_STYLE: Record<Confidence, string> = {
  high: "bg-emerald-50 text-emerald-700",
  medium: "bg-amber-50 text-amber-700",
  low: "bg-red-50 text-red-700",
};

/**
 * "Instruct HQ01" — the CEO types an instruction, HQ01 routes it to the right
 * executive office, and offers dispatch (existing office) or an approval-gated
 * proposal (unstaffed office).
 */
export function InstructHQ01() {
  const router = useRouter();
  const [instruction, setInstruction] = useState("");
  const [repository, setRepository] = useState("");
  const [busy, setBusy] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [routing, setRouting] = useState<RoutingResult | null>(null);
  const [briefing, setBriefing] = useState<Briefing | null>(null);
  const [proposal, setProposal] = useState<ExecutiveProposal | null>(null);
  const [approved, setApproved] = useState(false);

  async function call(url: string, init?: RequestInit): Promise<any> {
    const res = await fetch(url, init);
    const data = await res.json().catch(() => ({}));
    if (!res.ok || data.ok === false) {
      throw new Error(data.error ?? `Request failed (HTTP ${res.status}).`);
    }
    return data;
  }

  function resetDownstream() {
    setBriefing(null);
    setProposal(null);
    setApproved(false);
    setError(null);
  }

  async function routeInstruction(preferredExecutiveId?: string) {
    if (!instruction.trim()) return;
    setBusy("route");
    resetDownstream();
    try {
      const data = await call("/api/router/route", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          instruction,
          repository: repository || undefined,
          preferredExecutiveId,
        }),
      });
      setRouting(data.result as RoutingResult);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Routing failed.");
    } finally {
      setBusy(null);
    }
  }

  async function previewBriefing() {
    if (!routing) return;
    setBusy("briefing");
    setError(null);
    try {
      const data = await call("/api/router/briefing", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          executiveId: routing.recommendedExecutiveId,
          instruction,
          routingReason: routing.routingReason,
        }),
      });
      setBriefing(data.briefing as Briefing);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Could not load briefing.");
    } finally {
      setBusy(null);
    }
  }

  // Dispatch now happens from a Mission (PASS M0): a dispatch must belong to a
  // mission, so this routing surface previews and hands off to Mission Control.

  async function createProposal() {
    if (!routing) return;
    setBusy("proposal");
    setError(null);
    try {
      const data = await call("/api/executives/proposals", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          proposedExecutiveId: routing.recommendedExecutiveId,
          reason: routing.routingReason,
          originatingInstruction: instruction,
        }),
      });
      setProposal(data.proposal as ExecutiveProposal);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Could not create proposal.");
    } finally {
      setBusy(null);
    }
  }

  async function decideProposal(decision: "approve" | "reject") {
    if (!proposal) return;
    setBusy(decision);
    setError(null);
    try {
      const data = await call(
        `/api/executives/proposals/${encodeURIComponent(proposal.id)}/${decision}`,
        { method: "POST" },
      );
      setProposal(data.proposal as ExecutiveProposal);
      if (decision === "approve") {
        setApproved(true);
        // Re-route so dispatch becomes available now the office is active.
        await routeInstruction();
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : "Action failed.");
    } finally {
      setBusy(null);
    }
  }

  const triageHold =
    routing && !routing.dispatchAllowed && !routing.requiresNewExecutiveProposal;

  return (
    <div className="space-y-6">
      {/* Instruction input */}
      <Card className="p-5">
        <label className="mb-1.5 block text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">
          Instruction
        </label>
        <textarea
          value={instruction}
          onChange={(e) => setInstruction(e.target.value)}
          placeholder="e.g. Fix the billing deploy script before we break live"
          rows={3}
          className="flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1"
        />
        <div className="mt-3 flex flex-wrap items-end gap-3">
          <div className="min-w-[16rem] flex-1">
            <label className="mb-1.5 block text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">
              Repository (optional)
            </label>
            <Input
              value={repository}
              onChange={(e) => setRepository(e.target.value)}
              placeholder="defaults to aaf-holdings"
              className="h-9 font-mono text-xs"
            />
          </div>
          <Button
            type="button"
            onClick={() => routeInstruction()}
            disabled={busy !== null || !instruction.trim()}
          >
            {busy === "route" ? (
              <Loader2 className="h-4 w-4 animate-spin" />
            ) : (
              <Send className="h-4 w-4" />
            )}
            Route Instruction
          </Button>
        </div>
      </Card>

      {error && (
        <div className="flex items-center gap-2 rounded-md bg-destructive/10 px-4 py-2.5 text-[13px] text-destructive">
          <AlertTriangle className="h-4 w-4 shrink-0" />
          {error}
        </div>
      )}

      {/* Routing result */}
      {routing && (
        <Card className="overflow-hidden">
          <div className="flex items-center justify-between gap-3 border-b border-border bg-secondary/40 px-5 py-3">
            <div className="flex items-center gap-2">
              <Building2 className="h-4 w-4 text-muted-foreground" />
              <span className="text-sm font-semibold">Routing result</span>
            </div>
            <span
              className={cn(
                "rounded-full px-2.5 py-0.5 text-xs font-medium",
                CONFIDENCE_STYLE[routing.confidence],
              )}
            >
              {routing.confidence} confidence
            </span>
          </div>

          <div className="space-y-4 p-5">
            <div className="flex flex-wrap items-baseline gap-x-3 gap-y-1">
              <span className="text-lg font-semibold tracking-tight">
                {routing.recommendedOffice}
              </span>
              <span className="font-mono text-xs text-muted-foreground">
                {routing.recommendedExecutiveId} · {routing.department}
              </span>
            </div>

            <p className="text-[14px] leading-relaxed text-foreground/90">
              {routing.routingReason}
            </p>

            {routing.secondaryExecutives.length > 0 && (
              <div className="flex flex-wrap items-center gap-2 text-[12px] text-muted-foreground">
                <span>Also considered:</span>
                {routing.secondaryExecutives.map((s) => (
                  <span
                    key={s.id}
                    className="rounded-full bg-secondary px-2 py-0.5 font-medium text-foreground/70"
                  >
                    {s.office}
                  </span>
                ))}
              </div>
            )}

            {routing.warnings.length > 0 && (
              <ul className="space-y-1">
                {routing.warnings.map((w, i) => (
                  <li
                    key={i}
                    className="flex items-start gap-2 text-[12px] text-amber-700"
                  >
                    <AlertTriangle className="mt-0.5 h-3.5 w-3.5 shrink-0" />
                    {w}
                  </li>
                ))}
              </ul>
            )}

            {/* Actions */}
            <div className="flex flex-wrap items-center gap-2 border-t border-border pt-4">
              {routing.dispatchAllowed ? (
                <>
                  <span className="mr-1 inline-flex items-center gap-1.5 text-[12px] font-medium text-emerald-700">
                    <CheckCircle2 className="h-4 w-4" /> Office active
                  </span>
                  <Button
                    type="button"
                    variant="outline"
                    size="sm"
                    onClick={previewBriefing}
                    disabled={busy !== null}
                  >
                    {busy === "briefing" ? (
                      <Loader2 className="h-3.5 w-3.5 animate-spin" />
                    ) : (
                      <FileText className="h-3.5 w-3.5" />
                    )}
                    Preview Briefing
                  </Button>
                  <Link
                    href="/mission-control"
                    className="inline-flex items-center gap-2 rounded-md bg-primary px-3 py-2 text-xs font-medium text-primary-foreground transition-colors hover:bg-primary/90"
                  >
                    Dispatch from a Mission <ArrowRight className="h-3.5 w-3.5" />
                  </Link>
                </>
              ) : routing.requiresNewExecutiveProposal ? (
                <ProposalFlow
                  routing={routing}
                  proposal={proposal}
                  approved={approved}
                  busy={busy}
                  onCreate={createProposal}
                  onApprove={() => decideProposal("approve")}
                  onReject={() => decideProposal("reject")}
                  onRouteToIvan={() => routeInstruction("ivan")}
                />
              ) : (
                <span className="inline-flex items-center gap-1.5 text-[12px] text-muted-foreground">
                  <CornerUpRight className="h-4 w-4" />
                  Held for IVAN triage — IVAN is not yet executable, so this needs
                  CEO/COO review.
                </span>
              )}
            </div>
          </div>

          {/* Briefing preview */}
          {briefing && <BriefingPreview briefing={briefing} onClose={() => setBriefing(null)} />}
        </Card>
      )}
    </div>
  );
}

function ProposalFlow({
  routing,
  proposal,
  approved,
  busy,
  onCreate,
  onApprove,
  onReject,
  onRouteToIvan,
}: {
  routing: RoutingResult;
  proposal: ExecutiveProposal | null;
  approved: boolean;
  busy: string | null;
  onCreate: () => void;
  onApprove: () => void;
  onReject: () => void;
  onRouteToIvan: () => void;
}) {
  if (approved) {
    return (
      <span className="inline-flex items-center gap-1.5 text-[12px] font-medium text-emerald-700">
        <CheckCircle2 className="h-4 w-4" /> Office approved and activated — re-routed
        for dispatch above.
      </span>
    );
  }

  return (
    <div className="w-full space-y-3">
      <div className="flex items-center gap-2 rounded-md bg-amber-50 px-3 py-2 text-[13px] text-amber-800">
        <AlertTriangle className="h-4 w-4 shrink-0" />
        This requires a new executive office proposal — {routing.recommendedOffice}{" "}
        is not staffed yet.
      </div>

      {!proposal ? (
        <div className="flex flex-wrap gap-2">
          <Button type="button" size="sm" onClick={onCreate} disabled={busy !== null}>
            {busy === "proposal" ? (
              <Loader2 className="h-3.5 w-3.5 animate-spin" />
            ) : (
              <ClipboardCheck className="h-3.5 w-3.5" />
            )}
            Create Proposal
          </Button>
          <Button
            type="button"
            variant="outline"
            size="sm"
            onClick={onRouteToIvan}
            disabled={busy !== null}
          >
            <CornerUpRight className="h-3.5 w-3.5" /> Route to IVAN instead
          </Button>
        </div>
      ) : proposal.status === "rejected" ? (
        <div className="flex items-center gap-2 text-[12px] text-muted-foreground">
          <X className="h-4 w-4" /> Proposal rejected. The office stays unstaffed.
        </div>
      ) : (
        <div className="rounded-md border border-border p-3">
          <div className="mb-2 font-mono text-[11px] text-muted-foreground">
            proposal · {proposal.id} · {proposal.status}
          </div>
          <div className="mb-3 text-[12px] text-muted-foreground">
            Approving creates the {proposal.office} office (status active) and its
            constitution folder. It does not write the constitution.
          </div>
          <div className="flex flex-wrap gap-2">
            <Button type="button" size="sm" onClick={onApprove} disabled={busy !== null}>
              {busy === "approve" ? (
                <Loader2 className="h-3.5 w-3.5 animate-spin" />
              ) : (
                <CheckCircle2 className="h-3.5 w-3.5" />
              )}
              Approve Office
            </Button>
            <Button
              type="button"
              variant="outline"
              size="sm"
              onClick={onReject}
              disabled={busy !== null}
            >
              <X className="h-3.5 w-3.5" /> Reject Proposal
            </Button>
          </div>
        </div>
      )}
    </div>
  );
}

function BriefingPreview({
  briefing,
  onClose,
}: {
  briefing: Briefing;
  onClose: () => void;
}) {
  return (
    <div className="border-t border-border">
      <div className="flex items-center justify-between gap-3 bg-secondary/30 px-5 py-2.5">
        <span className="text-[12px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">
          Briefing manifest
        </span>
        <button
          type="button"
          onClick={onClose}
          className="rounded-md p-1 text-muted-foreground hover:bg-secondary"
        >
          <X className="h-4 w-4" />
        </button>
      </div>
      <div className="space-y-3 px-5 py-4">
        <div className="text-[12px] text-muted-foreground">
          Constitution:{" "}
          {briefing.constitutionLoaded ? (
            <span className="text-foreground">
              {briefing.constitutionFiles.map((f) => f.path).join(", ")}
            </span>
          ) : (
            <span className="text-amber-700">none filed yet</span>
          )}
        </div>
        {briefing.warnings.map((w, i) => (
          <div key={i} className="flex items-start gap-2 text-[12px] text-amber-700">
            <AlertTriangle className="mt-0.5 h-3.5 w-3.5 shrink-0" />
            {w}
          </div>
        ))}
        <pre className="max-h-80 overflow-auto rounded-md bg-[#0d1117] px-4 py-3 text-[12px] leading-relaxed text-[#c9d1d9]">
          {briefing.systemPrompt}
        </pre>
      </div>
    </div>
  );
}

root · /srv/aaf