From 8b17a175c3e7e27b789812eba4e3cd760beadb10 Mon Sep 17 00:00:00 2001
From: soryu <soryu@soryu.co>
Date: Tue, 6 Jan 2026 04:08:11 +0000
Subject: Initial Control system

---
 makima/frontend/src/components/files/CliInput.tsx | 58 +++++++++++++++++++++--
 1 file changed, 53 insertions(+), 5 deletions(-)

(limited to 'makima/frontend/src/components/files/CliInput.tsx')

diff --git a/makima/frontend/src/components/files/CliInput.tsx b/makima/frontend/src/components/files/CliInput.tsx
index ff2b0a4..47e7616 100644
--- a/makima/frontend/src/components/files/CliInput.tsx
+++ b/makima/frontend/src/components/files/CliInput.tsx
@@ -8,10 +8,15 @@ import {
   type UserAnswer,
 } from "../../lib/api";
 import { SimpleMarkdown } from "../SimpleMarkdown";
+import type { FocusedElement } from "./FileDetail";
 
 interface CliInputProps {
   fileId: string;
   onUpdate: (body: BodyElement[], summary: string | null) => void;
+  focusedElement?: FocusedElement | null;
+  onClearFocus?: () => void;
+  suggestedPrompt?: string | null;
+  onClearSuggestedPrompt?: () => void;
 }
 
 interface Message {
@@ -28,7 +33,7 @@ const MODEL_OPTIONS: { value: LlmModel; label: string }[] = [
   { value: "groq", label: "Groq Kimi" },
 ];
 
-export function CliInput({ fileId, onUpdate }: CliInputProps) {
+export function CliInput({ fileId, onUpdate, focusedElement, onClearFocus, suggestedPrompt, onClearSuggestedPrompt }: CliInputProps) {
   const [input, setInput] = useState("");
   const [loading, setLoading] = useState(false);
   const [messages, setMessages] = useState<Message[]>([]);
@@ -53,6 +58,21 @@ export function CliInput({ fileId, onUpdate }: CliInputProps) {
     }
   }, [messages]);
 
+  // Auto-focus input when an element is focused
+  useEffect(() => {
+    if (focusedElement && inputRef.current) {
+      inputRef.current.focus();
+    }
+  }, [focusedElement]);
+
+  // Handle suggested prompt from generate actions
+  useEffect(() => {
+    if (suggestedPrompt) {
+      setInput(suggestedPrompt);
+      onClearSuggestedPrompt?.();
+    }
+  }, [suggestedPrompt, onClearSuggestedPrompt]);
+
   const handleSubmit = useCallback(
     async (e: React.FormEvent) => {
       e.preventDefault();
@@ -73,7 +93,13 @@ export function CliInput({ fileId, onUpdate }: CliInputProps) {
 
       try {
         // Send request with conversation history for context
-        const response = await chatWithFile(fileId, userMessage, model, conversationHistory);
+        const response = await chatWithFile(
+          fileId,
+          userMessage,
+          model,
+          conversationHistory,
+          focusedElement?.index
+        );
 
         // Add assistant response
         const assistantMsgId = (Date.now() + 1).toString();
@@ -128,7 +154,7 @@ export function CliInput({ fileId, onUpdate }: CliInputProps) {
         inputRef.current?.focus();
       }
     },
-    [input, loading, fileId, model, onUpdate, conversationHistory]
+    [input, loading, fileId, model, onUpdate, conversationHistory, focusedElement]
   );
 
   // Handle option selection for a question
@@ -206,7 +232,13 @@ export function CliInput({ fileId, onUpdate }: CliInputProps) {
 
     try {
       // Send answers as the next message
-      const response = await chatWithFile(fileId, answerText, model, conversationHistory);
+      const response = await chatWithFile(
+        fileId,
+        answerText,
+        model,
+        conversationHistory,
+        focusedElement?.index
+      );
 
       // Add assistant response
       const assistantMsgId = (Date.now() + 1).toString();
@@ -258,7 +290,7 @@ export function CliInput({ fileId, onUpdate }: CliInputProps) {
     } finally {
       setLoading(false);
     }
-  }, [pendingQuestions, userAnswers, customInputs, loading, fileId, model, conversationHistory, onUpdate]);
+  }, [pendingQuestions, userAnswers, customInputs, loading, fileId, model, conversationHistory, onUpdate, focusedElement]);
 
   // Cancel answering questions
   const handleCancelQuestions = useCallback(() => {
@@ -397,6 +429,22 @@ export function CliInput({ fileId, onUpdate }: CliInputProps) {
             </option>
           ))}
         </select>
+
+        {/* Focus Badge */}
+        {focusedElement && (
+          <button
+            type="button"
+            onClick={onClearFocus}
+            className="flex items-center gap-1 px-2 py-0.5 font-mono text-[10px] bg-[rgba(117,170,252,0.1)] border border-[rgba(117,170,252,0.3)] text-[#9bc3ff] hover:border-[#75aafc] transition-colors group"
+            title="Click to clear focus"
+          >
+            <span className="text-[#75aafc]">{focusedElement.type}</span>
+            <span className="text-[#555]">:</span>
+            <span>{focusedElement.index}</span>
+            <span className="text-[#555] group-hover:text-red-400 ml-1">&times;</span>
+          </button>
+        )}
+
         <span className="text-[#9bc3ff] font-mono text-sm">&gt;</span>
         <input
           ref={inputRef}
-- 
cgit v1.2.3

