diff options
| author | soryu <soryu@soryu.co> | 2026-01-26 03:09:36 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-01-26 03:09:36 +0000 |
| commit | 34d80fdead09e7deca364e8fad11b901abe8fbec (patch) | |
| tree | 3d23e7975f94233e6406b855b16f080ef92afa60 | |
| parent | cb4f2fc40dbabb40de948512eee74c7e46264665 (diff) | |
| download | soryu-makima/task-task-fee9930d-fee9930d.tar.gz soryu-makima/task-task-fee9930d-fee9930d.zip | |
[WIP] Heartbeat checkpoint - 2026-01-26 03:09:36 UTCmakima/task-task-fee9930d-fee9930d
| -rw-r--r-- | makima/frontend/src/routes/mesh.tsx | 82 |
1 files changed, 80 insertions, 2 deletions
diff --git a/makima/frontend/src/routes/mesh.tsx b/makima/frontend/src/routes/mesh.tsx index fb366a2..dfc6123 100644 --- a/makima/frontend/src/routes/mesh.tsx +++ b/makima/frontend/src/routes/mesh.tsx @@ -8,8 +8,8 @@ import { UnifiedMeshChatInput } from "../components/mesh/UnifiedMeshChatInput"; import { ContractCompleteQuestion } from "../components/mesh/ContractCompleteQuestion"; import { useTasks } from "../hooks/useTasks"; import { useTaskSubscription, type TaskUpdateEvent, type TaskOutputEvent } from "../hooks/useTaskSubscription"; -import type { TaskWithSubtasks, MeshChatContext, ContractSummary, ContractWithRelations, DaemonDirectory, TaskSummary, RepositoryHistoryEntry } from "../lib/api"; -import { startTask as startTaskApi, stopTask as stopTaskApi, getTaskOutput, listContracts, getContract, getDaemonDirectories, continueTask as continueTaskApi, resumeSupervisor, branchTask, getRepositorySuggestions } from "../lib/api"; +import type { TaskWithSubtasks, MeshChatContext, ContractSummary, ContractWithRelations, DaemonDirectory, TaskSummary, RepositoryHistoryEntry, ContractTypeTemplate } from "../lib/api"; +import { startTask as startTaskApi, stopTask as stopTaskApi, getTaskOutput, listContracts, getContract, getDaemonDirectories, continueTask as continueTaskApi, resumeSupervisor, branchTask, getRepositorySuggestions, listContractTypes } from "../lib/api"; import { DirectoryInput } from "../components/mesh/DirectoryInput"; import { useAuth } from "../contexts/AuthContext"; import { useSupervisorQuestions } from "../contexts/SupervisorQuestionsContext"; @@ -131,6 +131,10 @@ export default function MeshPage() { const [standaloneRepoPath, setStandaloneRepoPath] = useState(""); const [repoSuggestions, setRepoSuggestions] = useState<RepositoryHistoryEntry[]>([]); const [showRepoSuggestions, setShowRepoSuggestions] = useState(false); + // Contract type selection for standalone tasks + const [standaloneContractTypes, setStandaloneContractTypes] = useState<ContractTypeTemplate[]>([]); + const [standaloneContractType, setStandaloneContractType] = useState<string>("simple"); + const [contractTypesLoading, setContractTypesLoading] = useState(false); // Track which subtask's output we're viewing (null = parent task) const [viewingSubtaskId, setViewingSubtaskId] = useState<string | null>(null); const [viewingSubtaskName, setViewingSubtaskName] = useState<string | null>(null); @@ -364,6 +368,41 @@ export default function MeshPage() { } }, [showContractModal, modalStep, selectedContract, standaloneRepoType]); + // Fetch contract types when standalone task modal is open + useEffect(() => { + if (showContractModal && modalStep === 2 && !selectedContract) { + setContractTypesLoading(true); + listContractTypes() + .then((res) => { + setStandaloneContractTypes(res.types); + setContractTypesLoading(false); + }) + .catch((err) => { + console.error("Failed to fetch contract types:", err); + // Fall back to built-in types + setStandaloneContractTypes([ + { + id: "simple", + name: "Simple", + description: "Plan → Execute: Simple workflow with a plan document", + phases: ["plan", "execute"], + defaultPhase: "plan", + isBuiltin: true, + }, + { + id: "specification", + name: "Specification", + description: "Research → Specify → Plan → Execute → Review: Full specification-driven development with TDD", + phases: ["research", "specify", "plan", "execute", "review"], + defaultPhase: "research", + isBuiltin: true, + }, + ]); + setContractTypesLoading(false); + }); + } + }, [showContractModal, modalStep, selectedContract]); + // Apply a repository suggestion const applyRepoSuggestion = useCallback((suggestion: RepositoryHistoryEntry) => { if (suggestion.repositoryUrl) { @@ -576,6 +615,7 @@ export default function MeshPage() { setStandaloneRepoType("remote"); setStandaloneRepoUrl(""); setStandaloneRepoPath(""); + setStandaloneContractType("simple"); setModalStep(2); }, []); @@ -625,6 +665,7 @@ export default function MeshPage() { setStandaloneRepoType("remote"); setStandaloneRepoUrl(""); setStandaloneRepoPath(""); + setStandaloneContractType("simple"); setRepoSuggestions([]); setShowRepoSuggestions(false); }, []); @@ -1006,6 +1047,43 @@ export default function MeshPage() { )} </div> + {/* Contract type selector - for standalone tasks */} + {!selectedContract && ( + <div className="space-y-1"> + <label className="block text-[10px] font-mono uppercase tracking-wide text-[#7788aa]"> + Contract Type + </label> + {contractTypesLoading ? ( + <div className="flex items-center justify-center py-4"> + <span className="font-mono text-xs text-[#8b949e]">Loading contract types...</span> + </div> + ) : ( + <> + <div className="flex gap-2"> + {standaloneContractTypes.map((type) => ( + <button + key={type.id} + type="button" + onClick={() => setStandaloneContractType(type.id)} + className={`flex-1 px-3 py-2 font-mono text-xs uppercase transition-colors ${ + standaloneContractType === type.id + ? "bg-[#0f3c78] text-[#dbe7ff] border border-[#75aafc]" + : "bg-[#0d1b2d] text-[#8b949e] border border-[#3f6fb3] hover:border-[#75aafc]" + }`} + > + {type.name} + </button> + ))} + </div> + <p className="mt-1 font-mono text-[10px] text-[#556677]"> + {standaloneContractTypes.find((t) => t.id === standaloneContractType)?.description || + "Select a contract type"} + </p> + </> + )} + </div> + )} + {/* Task name */} <div className="space-y-1"> <label className="block text-[10px] font-mono uppercase tracking-wide text-[#7788aa]">Task Name</label> |
