summaryrefslogtreecommitdiff
path: root/makima/frontend/src/routes/contracts.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'makima/frontend/src/routes/contracts.tsx')
-rw-r--r--makima/frontend/src/routes/contracts.tsx78
1 files changed, 72 insertions, 6 deletions
diff --git a/makima/frontend/src/routes/contracts.tsx b/makima/frontend/src/routes/contracts.tsx
index aa62bd9..bb66215 100644
--- a/makima/frontend/src/routes/contracts.tsx
+++ b/makima/frontend/src/routes/contracts.tsx
@@ -93,6 +93,8 @@ function ContractsPageContent() {
const [contractTypes, setContractTypes] = useState<ContractTypeTemplate[]>([]);
const [contractTypesLoading, setContractTypesLoading] = useState(false);
const [localOnly, setLocalOnly] = useState(false);
+ const [redTeamEnabled, setRedTeamEnabled] = useState(false);
+ const [redTeamPrompt, setRedTeamPrompt] = useState("");
// Fetch contract types when modal opens - merges built-in types with user templates
useEffect(() => {
@@ -108,11 +110,12 @@ function ContractsPageContent() {
// Convert user templates to ContractTypeTemplate format, excluding built-ins
return templates
.filter((t: { isBuiltIn?: boolean }) => !t.isBuiltIn)
- .map((t: { id: string; name: string; description: string; phases: { id: string }[] }) => ({
+ .map((t: { id: string; name: string; description: string; phases: { id: string; name: string }[] }) => ({
id: t.id,
name: t.name,
description: t.description,
phases: t.phases.map((p: { id: string }) => p.id) as ContractPhase[],
+ phaseNames: Object.fromEntries(t.phases.map((p: { id: string; name: string }) => [p.id, p.name])),
defaultPhase: (t.phases[0]?.id || "execute") as ContractPhase,
isBuiltin: false,
}));
@@ -265,6 +268,8 @@ function ContractsPageContent() {
contractType: contractType,
initialPhase: initialPhase !== defaultPhaseForType ? initialPhase : undefined,
localOnly: localOnly || undefined,
+ redTeamEnabled: redTeamEnabled || undefined,
+ redTeamPrompt: redTeamEnabled && redTeamPrompt.trim() ? redTeamPrompt.trim() : undefined,
};
try {
@@ -340,6 +345,8 @@ function ContractsPageContent() {
setRepoUrl("");
setRepoPath("");
setLocalOnly(false);
+ setRedTeamEnabled(false);
+ setRedTeamPrompt("");
setCreateError(null);
}, []);
@@ -652,11 +659,17 @@ function ContractsPageContent() {
onChange={(e) => setInitialPhase(e.target.value as ContractPhase)}
className="w-full px-3 py-2 bg-[#0d1b2d] border border-[#3f6fb3] text-[#dbe7ff] font-mono text-sm focus:outline-none focus:border-[#75aafc]"
>
- {(contractTypes.find((t) => t.id === contractType)?.phases || []).map((phase) => (
- <option key={phase} value={phase}>
- {phase.charAt(0).toUpperCase() + phase.slice(1)}
- </option>
- ))}
+ {(() => {
+ const template = contractTypes.find((t) => t.id === contractType);
+ return (template?.phases || []).map((phase) => {
+ const displayName = template?.phaseNames?.[phase] || (phase.charAt(0).toUpperCase() + phase.slice(1));
+ return (
+ <option key={phase} value={phase}>
+ {displayName}
+ </option>
+ );
+ });
+ })()}
</select>
<p className="mt-1 font-mono text-xs text-[#8b949e]">
{contractType === "simple"
@@ -705,6 +718,59 @@ function ContractsPageContent() {
</p>
</div>
+ {/* Red Team Monitoring */}
+ <div className="border-t border-[rgba(117,170,252,0.2)] pt-4">
+ <div className="flex items-center gap-3">
+ <button
+ type="button"
+ onClick={() => setRedTeamEnabled(!redTeamEnabled)}
+ className={`w-5 h-5 flex items-center justify-center border transition-colors ${
+ redTeamEnabled
+ ? "bg-[#0f3c78] border-[#75aafc] text-[#dbe7ff]"
+ : "bg-[#0d1b2d] border-[#3f6fb3] text-transparent"
+ }`}
+ >
+ {redTeamEnabled && (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ width="12"
+ height="12"
+ viewBox="0 0 24 24"
+ fill="none"
+ stroke="currentColor"
+ strokeWidth="3"
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ >
+ <polyline points="20 6 9 17 4 12" />
+ </svg>
+ )}
+ </button>
+ <label
+ className="font-mono text-sm text-[#dbe7ff] cursor-pointer select-none"
+ onClick={() => setRedTeamEnabled(!redTeamEnabled)}
+ >
+ Enable Red Team Monitoring
+ </label>
+ </div>
+ <p className="font-mono text-xs text-[#8b949e] pl-8">
+ Spawns a parallel task to monitor work output for quality and compliance.
+ </p>
+ {redTeamEnabled && (
+ <div className="mt-3 pl-8">
+ <label className="block font-mono text-xs text-[#75aafc] uppercase mb-2">
+ Custom Review Criteria (Optional)
+ </label>
+ <textarea
+ value={redTeamPrompt}
+ onChange={(e) => setRedTeamPrompt(e.target.value)}
+ placeholder="e.g., 'Focus on security best practices' or 'Ensure all functions have tests'"
+ className="w-full px-3 py-2 bg-[#0d1b2d] border border-[#3f6fb3] text-[#dbe7ff] text-sm font-mono h-20 resize-none focus:border-[#75aafc] focus:outline-none"
+ />
+ </div>
+ )}
+ </div>
+
{/* Repository Configuration */}
<div className="border-t border-[rgba(117,170,252,0.2)] pt-4">
<label className="block font-mono text-xs text-[#75aafc] uppercase mb-3">