From 45961186892bea48799973d8ca66362c996399c0 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 12:01:08 +0000 Subject: [PATCH 1/5] Work in progress --- bun.lockb | Bin 354162 -> 354163 bytes src/routeTree.gen.ts | 9 +++++++++ 2 files changed, 9 insertions(+) diff --git a/bun.lockb b/bun.lockb index a38daa633c1db4a6ee6cfc23a84c20706cf1624c..3deb9b8acbd1ed1e4b7ba1d2360d10bd73b64e06 100755 GIT binary patch delta 16140 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 delta 16154 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

a*T4xMg{-Euc&Hc>;v{(a7jYmc42 zE*pO1ly{hJvi_(sgw8gBk;Xm9-|qK4+q;%iGcbsw9&B(TcM+QQ2=$`20SKRe*AziK z0Dg4GXC`0l9r`-(s1hlHcQ=&_Nf+pmAaeOoV4zylzIYlKi^sU?_-eoTE2a+Ki8ph` z(i=gevC0e)bEzN@eqK(O1L393b)y9>| zjQf=}kMF(M`&~b=HtpIjP~9N4ZRL`-ch{AQrTX{5;JuYFi0TFZeN4uE(eg=WG735# z!g&o24i=l7loZw-pTg?GV|j&p_9WF0p5z#`aiz3s$5F$FHM-fx(IRc3lfeiD`?8c? zV6*7ukiTc8=Uk6fup$KR+e~L1tni$FD7NjZRq?qG*5uOrsIobf7pk_!Yt2)kY71ZE za%u3;{+;{g^jMFvh{x(kMY%}<&ERSI*3lx~W@V90Ad6@e$UnTBIDk)e;u)ii)(XB$ zRNM^V^E*)S(WV7G7N~q{X9+?|SV6&IKz34l5MSfkYRmmj4ZAoU*ob!>*n7pF-o>kK zi1LqbAN8D|vv^d|qx{+5`s*LOYzkJlEQJ?nNG#w@DtJFaCLz7 z8a@)b!Tjblq&Xr}qixO67*DsFqlcb|eW*bM){${9b;JuvrR9@85bu9QmPOW1pwtL3 z>#u>m*$`S5fy`rER}D%jnVaV|S}fz>Fg?LdAlFFv!?^F->A{|j+tt4FOl&4DlGcVP zTPOw$cu`o;Laj}yk!tg>e|i6j9nQFyd(tg(Xid-d?et*P{nVDuM&h__T==~fpD?QP z)P`g92nZGtP?vhYjvE;SLPWbSv z??FiWr>SWR2&qL0Ail=s-X)2)#%X#uW|Pn18vEZvU0eswzH2p)AAV{` z99i37uZf{XlC%SfJcp?f2mLc$M=kBXx}Nt{)P=Khy}G(R^=NkPPtEbp`P@{l5X0h=^ z^=--6l8#PPtI@8BYCj3+<8-6HCgR*OVv-vB4C=Jv?j)5x1GrK1Dah8k)9w9sOwnz^ zEEvFKh}Wh*=N~tkJ{fK-o~njD*E#x=|B^OjGKPHW6JyA_NGsi%p*qof)ATVJimY^E zntJ#-X&0ue?VbVb{f5j?-~4a%jpu-rnd6@X)}P=p6mYmY}K{! zKeJS)XFX*lz;1MeqxgpZmj!xLn@^1?v5!(mPkySl`ETiNGzBUsW%hH<(lvDZJMYZT z)E*LzqL)eCVEnE91LvvD4Pfs)M9AXL zRF$^QQ|*f9qfw8tbMw`=?7s_pEKnc17!4nPsm?Nf>j|aPO5K;b9lKYmLybl(KQT|b zv>#SE{2jeo#|__Cp`EK8IiSv0m7NM_ex+8^r(i8YvE*y%Eca<1=4qg1AHF84M zs-q2!yVvUWvjR1mdapyQc3h_maH#!moo*92W}}n45L{fKW*7pnf-4gte%GQZ>-B}9 zE6iN4<`|5xZg8y4*&B43I?tGm2y*jAhm`nPlX@w3|KNPC(*(DeD->jaif{HF{_%3yo@w?T2q}1NK9fLT! zTMb8}K61F%LQzGI96PT_6{|v*qW3g?t1l`Y$of_fH{GJU-{MW%vy7Ye=u#X#>+RL& z*8xn}t0#H@5w6K;O#_-Hrv-=)>XF2zsa{f81ZC_qw`!K*5{RVFT`gi;5*E@ESIaBUF*b3v aRHsxoOKXGUnwv#z0+q@N->Yu%>hXVuEN7hn diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 96bac3a..15af9f5 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -433,3 +433,12 @@ const rootRouteChildren: RootRouteChildren = { export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) ._addFileTypes() + +import type { getRouter } from './router.tsx' +import type { createStart } from '@tanstack/react-start' +declare module '@tanstack/react-start' { + interface Register { + ssr: true + router: Awaited> + } +} From ee5991a62b1da0ceeeab4d74e8a63d7cac3b3a0a Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 12:01:26 +0000 Subject: [PATCH 2/5] Changes Co-authored-by: domfelipe <53182096+domfelipe@users.noreply.github.com> --- src/routeTree.gen.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 15af9f5..96bac3a 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -433,12 +433,3 @@ const rootRouteChildren: RootRouteChildren = { export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) ._addFileTypes() - -import type { getRouter } from './router.tsx' -import type { createStart } from '@tanstack/react-start' -declare module '@tanstack/react-start' { - interface Register { - ssr: true - router: Awaited> - } -} From e0b7fa99420f0419b0956c9c8081247a36f03e8a Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 12:01:40 +0000 Subject: [PATCH 3/5] Changes Co-authored-by: domfelipe <53182096+domfelipe@users.noreply.github.com> --- src/routes/painel.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/routes/painel.tsx b/src/routes/painel.tsx index f2b6520..62c1cc9 100644 --- a/src/routes/painel.tsx +++ b/src/routes/painel.tsx @@ -4,6 +4,7 @@ import { createFileRoute, Outlet, redirect, Link, useNavigate, useLocation } fro import { useEffect, useState } from "react"; import { Bot, + CalendarClock, CreditCard, Home, LogOut, @@ -59,7 +60,7 @@ export const Route = createFileRoute("/painel")({ }); interface NavItem { - to: "/painel" | "/painel/agente" | "/painel/skills" | "/painel/integracoes" | "/painel/faturamento" | "/painel/configuracoes"; + to: "/painel" | "/painel/agente" | "/painel/skills" | "/painel/integracoes" | "/painel/cronjobs" | "/painel/faturamento" | "/painel/configuracoes"; label: string; icon: React.ComponentType<{ className?: string }>; disabled?: boolean; @@ -76,6 +77,7 @@ const NAV: (NavItem | DisabledNavItem)[] = [ { to: "/painel", label: "Dashboard", icon: Home }, { to: "/painel/agente", label: "Meu Agente", icon: Bot }, { to: "/painel/skills", label: "Skills", icon: Sparkles }, + { to: "/painel/cronjobs", label: "Automações", icon: CalendarClock }, { to: "/painel/integracoes", label: "Integrações", icon: Plug }, { to: "/painel/faturamento", label: "Faturamento", icon: CreditCard }, { to: "/painel/configuracoes", label: "Configurações", icon: Settings }, From 11d8c0c19a3c40cd04c6448be420464b77838718 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 12:03:53 +0000 Subject: [PATCH 4/5] Changes Co-authored-by: domfelipe <53182096+domfelipe@users.noreply.github.com> --- src/components/mika/cronjobs/CronjobCard.tsx | 189 +++++++++ .../mika/cronjobs/CronjobWizard.tsx | 379 ++++++++++++++++++ src/hooks/use-cronjobs.ts | 170 ++++++++ src/routeTree.gen.ts | 72 ++++ src/routes/painel.cronjobs.$id.tsx | 267 ++++++++++++ src/routes/painel.cronjobs.index.tsx | 124 ++++++ src/routes/painel.cronjobs.nova.tsx | 28 ++ 7 files changed, 1229 insertions(+) create mode 100644 src/components/mika/cronjobs/CronjobCard.tsx create mode 100644 src/components/mika/cronjobs/CronjobWizard.tsx create mode 100644 src/hooks/use-cronjobs.ts create mode 100644 src/routes/painel.cronjobs.$id.tsx create mode 100644 src/routes/painel.cronjobs.index.tsx create mode 100644 src/routes/painel.cronjobs.nova.tsx diff --git a/src/components/mika/cronjobs/CronjobCard.tsx b/src/components/mika/cronjobs/CronjobCard.tsx new file mode 100644 index 0000000..c59ba99 --- /dev/null +++ b/src/components/mika/cronjobs/CronjobCard.tsx @@ -0,0 +1,189 @@ +"use client"; + +import { Link } from "@tanstack/react-router"; +import { Pause, Play, Trash2, Clock, AlertTriangle } from "lucide-react"; +import { toast } from "sonner"; +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "@/components/ui/alert-dialog"; +import { + type ScheduledJob, + useDeleteCronjob, + useUpdateCronjobStatus, +} from "@/hooks/use-cronjobs"; +import { useAvailableMcps, useUserIntegrations } from "@/hooks/use-integrations"; + +interface Props { + job: ScheduledJob; +} + +export function CronjobCard({ job }: Props) { + const updateMut = useUpdateCronjobStatus(); + const deleteMut = useDeleteCronjob(); + const { data: mcps = [] } = useAvailableMcps(); + const { data: integrations = [] } = useUserIntegrations(); + const [confirmDelete, setConfirmDelete] = useState(false); + + const connectedMcpIds = new Set( + integrations.filter((i) => i.status === "active").map((i) => i.mcp_id), + ); + const requiredMcps = job.required_mcp_slugs + .map((slug) => mcps.find((m) => m.slug === slug)) + .filter((m): m is NonNullable => !!m); + const missingMcps = requiredMcps.filter((m) => !connectedMcpIds.has(m.id)); + + const isActive = job.status === "active"; + const isAutoPaused = job.status === "auto_paused"; + + async function toggle() { + try { + await updateMut.mutateAsync({ + id: job.id, + status: isActive ? "paused" : "active", + }); + toast.success(isActive ? "Automação pausada." : "Automação ativada."); + } catch (e) { + toast.error(e instanceof Error ? e.message : "Erro ao atualizar."); + } + } + + async function remove() { + try { + await deleteMut.mutateAsync(job.id); + toast.success("Automação excluída."); + setConfirmDelete(false); + } catch (e) { + toast.error(e instanceof Error ? e.message : "Erro ao excluir."); + } + } + + return ( +

+
+
+
+

{job.name}

+ {isActive && Ativa} + {job.status === "paused" && Pausada} + {isAutoPaused && ( + + Auto-pausada + + )} +
+

+ {job.human_readable} +

+
+
+ + {isAutoPaused && job.auto_paused_reason && ( +

{job.auto_paused_reason}

+ )} + + {missingMcps.length > 0 && isActive && ( +
+ + Integrações faltando:{" "} + + {missingMcps.map((m) => m.name).join(", ")} +
+ )} + + {requiredMcps.length > 0 && ( +
+ {requiredMcps.map((m) => { + const ok = connectedMcpIds.has(m.id); + return ( + + {m.name} + + ); + })} +
+ )} + +
+ {job.cron_expression} + {job.next_run_at && ( + + + {new Date(job.next_run_at).toLocaleString("pt-BR", { + timeZone: job.timezone, + dateStyle: "short", + timeStyle: "short", + })} + + )} +
+ +
+ +
+ + + + + + + + + Excluir automação? + + Esta ação remove permanentemente a automação “{job.name}”. + + + + + Cancelar + + { + e.preventDefault(); + remove(); + }} + disabled={deleteMut.isPending} + className="bg-destructive text-destructive-foreground hover:bg-destructive/90" + > + {deleteMut.isPending ? "Excluindo..." : "Excluir"} + + + + +
+
+
+ ); +} diff --git a/src/components/mika/cronjobs/CronjobWizard.tsx b/src/components/mika/cronjobs/CronjobWizard.tsx new file mode 100644 index 0000000..94f0f06 --- /dev/null +++ b/src/components/mika/cronjobs/CronjobWizard.tsx @@ -0,0 +1,379 @@ +"use client"; + +import { useMemo, useState } from "react"; +import { Loader2, Sparkles, AlertTriangle, ArrowLeft, CheckCircle2, Plug } from "lucide-react"; +import { Link } from "@tanstack/react-router"; +import { toast } from "sonner"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; +import { Badge } from "@/components/ui/badge"; +import { invokeFunction } from "@/lib/invoke-function"; +import { useCreateCronjob } from "@/hooks/use-cronjobs"; +import { useAvailableMcps, useUserIntegrations } from "@/hooks/use-integrations"; +import { useAgentInstance } from "@/hooks/use-agent-instance"; +import { useProfile } from "@/hooks/use-profile"; + +interface ParseResult { + cron_expression: string; + human_readable: string; + action_description: string; + required_mcp_slugs: string[]; + warnings: string[]; + confidence: "high" | "medium" | "low"; + next_run_at: string | null; +} + +type Step = "input" | "review" | "confirm"; + +interface Props { + onCreated?: (id: string) => void; + onCancel?: () => void; +} + +export function CronjobWizard({ onCreated, onCancel }: Props) { + const [step, setStep] = useState("input"); + const [naturalInput, setNaturalInput] = useState(""); + const [parsing, setParsing] = useState(false); + const [parsed, setParsed] = useState(null); + + // Form fields editáveis na revisão + const [name, setName] = useState(""); + const [description, setDescription] = useState(""); + const [cronExpression, setCronExpression] = useState(""); + const [humanReadable, setHumanReadable] = useState(""); + const [actionPrompt, setActionPrompt] = useState(""); + const [requiredMcps, setRequiredMcps] = useState([]); + const [reviewConfirmed, setReviewConfirmed] = useState(false); + + const { data: profile } = useProfile(); + const { data: agent } = useAgentInstance(); + const { data: mcps = [] } = useAvailableMcps(); + const { data: integrations = [] } = useUserIntegrations(); + const createMut = useCreateCronjob(); + + const tz = profile && "timezone" in profile && typeof (profile as { timezone?: string }).timezone === "string" + ? (profile as { timezone: string }).timezone + : "America/Sao_Paulo"; + + const mcpsBySlug = useMemo(() => { + const m = new Map(); + for (const x of mcps) m.set(x.slug, { id: x.id, name: x.name }); + return m; + }, [mcps]); + + const connectedSlugs = useMemo(() => { + const set = new Set(); + for (const it of integrations) { + if (it.status !== "active") continue; + const mcp = mcps.find((m) => m.id === it.mcp_id); + if (mcp) set.add(mcp.slug); + } + return set; + }, [integrations, mcps]); + + const missingMcps = requiredMcps.filter((s) => !connectedSlugs.has(s)); + + async function handleParse() { + const trimmed = naturalInput.trim(); + if (trimmed.length < 5) { + toast.error("Descreva a automação com mais detalhes."); + return; + } + setParsing(true); + const { data, error } = await invokeFunction( + "parse-cronjob-natural-language", + { natural_language_input: trimmed, user_timezone: tz }, + ); + setParsing(false); + if (error || !data) { + toast.error(error?.message ?? "Não conseguimos interpretar. Tente reescrever."); + return; + } + setParsed(data); + // Pré-preenche campos + const suggestedName = trimmed.length <= 60 ? trimmed : trimmed.slice(0, 57) + "..."; + setName(suggestedName); + setDescription(""); + setCronExpression(data.cron_expression); + setHumanReadable(data.human_readable); + setActionPrompt(data.action_description || trimmed); + setRequiredMcps(data.required_mcp_slugs); + setReviewConfirmed(false); + setStep("review"); + } + + async function handleCreate() { + if (!agent) { + toast.error("Agente ainda não está pronto."); + return; + } + if (!name.trim()) { + toast.error("Dê um nome à automação."); + return; + } + if (!cronExpression.trim() || !actionPrompt.trim()) { + toast.error("Preencha o cron e a ação."); + return; + } + try { + const job = await createMut.mutateAsync({ + agent_instance_id: agent.id, + name: name.trim(), + description: description.trim() || null, + natural_language_input: naturalInput.trim(), + cron_expression: cronExpression.trim(), + human_readable: humanReadable.trim() || cronExpression.trim(), + action_prompt: actionPrompt.trim(), + required_mcp_slugs: requiredMcps, + timezone: tz, + next_run_at: parsed?.next_run_at ?? null, + }); + toast.success("Automação criada!"); + onCreated?.(job.id); + } catch (e) { + const msg = e instanceof Error ? e.message : "Erro ao criar automação"; + toast.error(msg); + } + } + + // STEP 1 — Input + if (step === "input") { + return ( +
+
+ +

+ Diga o quê, quando e quais ferramentas usar. A IA traduz para um cronjob. +

+