From c618174e60e4632d36d7352d83399508c72b2f42 Mon Sep 17 00:00:00 2001
From: soryu <soryu@soryu.co>
Date: Tue, 27 Jan 2026 11:04:20 +0000
Subject: Add Red Team CLI command and frontend UI (#39)

* Add Red Team CLI command and frontend UI

Backend additions:
- Add `makima red-team notify` CLI command for red team tasks
- Add RedTeamCommand enum with Notify subcommand
- Add red_team API client module for notify endpoint
- Add RedTeamNotifyArgs with severity, task, file, context options

Frontend additions:
- Add ContractCreateModal with red team toggle and prompt input
- Update ContractDetail with red-team tab for notifications
- Update ContractList with red team enabled badge
- Add TypeScript types for RedTeamNotification and related interfaces

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add CSS styles for Red Team frontend components

Add comprehensive styling for:
- Contract list and detail containers
- Red team badge styling with gradient backgrounds
- Tab navigation with red team specific styling
- Red team notifications panel with severity indicators
- Contract creation modal form elements
- Task badges for supervisor and red team roles

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix missing local_only field in TUI CreateContractRequest

Add the missing local_only field to the CreateContractRequest struct
initialization in the TUI contract creation handler.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* [WIP] Heartbeat checkpoint - 2026-01-27 03:07:28 UTC

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
---
 frontend/src/components/ContractCreateModal.tsx | 185 ++++++++++++++++++++++++
 1 file changed, 185 insertions(+)
 create mode 100644 frontend/src/components/ContractCreateModal.tsx

(limited to 'frontend/src/components/ContractCreateModal.tsx')

diff --git a/frontend/src/components/ContractCreateModal.tsx b/frontend/src/components/ContractCreateModal.tsx
new file mode 100644
index 0000000..e1d9732
--- /dev/null
+++ b/frontend/src/components/ContractCreateModal.tsx
@@ -0,0 +1,185 @@
+import React, { useState } from 'react'
+
+interface ContractCreateModalProps {
+  isOpen: boolean
+  onClose: () => void
+  onCreated: () => void
+}
+
+interface CreateContractForm {
+  name: string
+  description: string
+  contractType: string
+  redTeamEnabled: boolean
+  redTeamPrompt: string
+}
+
+export function ContractCreateModal({ isOpen, onClose, onCreated }: ContractCreateModalProps) {
+  const [form, setForm] = useState<CreateContractForm>({
+    name: '',
+    description: '',
+    contractType: 'simple',
+    redTeamEnabled: false,
+    redTeamPrompt: '',
+  })
+  const [loading, setLoading] = useState(false)
+  const [error, setError] = useState<string | null>(null)
+
+  if (!isOpen) return null
+
+  const handleSubmit = async (e: React.FormEvent) => {
+    e.preventDefault()
+    setLoading(true)
+    setError(null)
+
+    try {
+      const response = await fetch('/api/v1/contracts', {
+        method: 'POST',
+        headers: {
+          'Content-Type': 'application/json',
+        },
+        body: JSON.stringify({
+          name: form.name,
+          description: form.description || undefined,
+          contract_type: form.contractType,
+          red_team_enabled: form.redTeamEnabled,
+          red_team_prompt: form.redTeamEnabled && form.redTeamPrompt ? form.redTeamPrompt : undefined,
+        }),
+      })
+
+      if (!response.ok) {
+        const errorData = await response.json().catch(() => ({}))
+        throw new Error(errorData.message || `Failed to create contract: ${response.statusText}`)
+      }
+
+      // Reset form and close modal
+      setForm({
+        name: '',
+        description: '',
+        contractType: 'simple',
+        redTeamEnabled: false,
+        redTeamPrompt: '',
+      })
+      onCreated()
+      onClose()
+    } catch (err) {
+      setError(err instanceof Error ? err.message : 'Unknown error')
+    } finally {
+      setLoading(false)
+    }
+  }
+
+  return (
+    <div className="modal-overlay" onClick={onClose}>
+      <div className="settings-modal contract-create-modal" onClick={(e) => e.stopPropagation()}>
+        <div className="modal-header">
+          <h2 className="modal-title">Create Contract</h2>
+          <button className="modal-close-btn" onClick={onClose}>
+            ×
+          </button>
+        </div>
+
+        <form onSubmit={handleSubmit}>
+          <div className="modal-content">
+            {error && (
+              <div className="form-error">
+                {error}
+              </div>
+            )}
+
+            <div className="settings-section">
+              <h3>Contract Details</h3>
+
+              <div className="setting-item">
+                <label>
+                  Name
+                  <input
+                    type="text"
+                    value={form.name}
+                    onChange={(e) => setForm({ ...form, name: e.target.value })}
+                    placeholder="Enter contract name"
+                    required
+                    className="form-input"
+                  />
+                </label>
+              </div>
+
+              <div className="setting-item">
+                <label>
+                  Description
+                  <textarea
+                    value={form.description}
+                    onChange={(e) => setForm({ ...form, description: e.target.value })}
+                    placeholder="Enter contract description (optional)"
+                    className="form-textarea"
+                    rows={3}
+                  />
+                </label>
+              </div>
+
+              <div className="setting-item">
+                <label>
+                  Contract Type
+                  <select
+                    value={form.contractType}
+                    onChange={(e) => setForm({ ...form, contractType: e.target.value })}
+                    className="form-select"
+                  >
+                    <option value="simple">Simple</option>
+                    <option value="specification">Specification</option>
+                    <option value="execute">Execute</option>
+                  </select>
+                </label>
+              </div>
+            </div>
+
+            <div className="settings-section">
+              <h3>Red Team Monitoring</h3>
+
+              <div className="setting-item">
+                <label className="checkbox-label">
+                  <input
+                    type="checkbox"
+                    checked={form.redTeamEnabled}
+                    onChange={(e) => setForm({ ...form, redTeamEnabled: e.target.checked })}
+                  />
+                  <span>Enable Red Team monitoring</span>
+                </label>
+                <div className="setting-description">
+                  Spawns a parallel task that monitors work output for quality and compliance
+                </div>
+              </div>
+
+              {form.redTeamEnabled && (
+                <div className="setting-item red-team-prompt-container">
+                  <label>
+                    Custom review criteria (optional)
+                    <textarea
+                      value={form.redTeamPrompt}
+                      onChange={(e) => setForm({ ...form, redTeamPrompt: e.target.value })}
+                      placeholder="Enter custom criteria for the red team to evaluate against... (e.g., 'Ensure all functions have proper error handling', 'Verify security best practices are followed')"
+                      className="form-textarea"
+                      rows={4}
+                    />
+                  </label>
+                  <div className="setting-description">
+                    Provide specific criteria for the red team to focus on during reviews
+                  </div>
+                </div>
+              )}
+            </div>
+          </div>
+
+          <div className="modal-footer">
+            <button type="button" className="modal-btn secondary" onClick={onClose} disabled={loading}>
+              Cancel
+            </button>
+            <button type="submit" className="modal-btn primary" disabled={loading || !form.name.trim()}>
+              {loading ? 'Creating...' : 'Create Contract'}
+            </button>
+          </div>
+        </form>
+      </div>
+    </div>
+  )
+}
-- 
cgit v1.2.3

