@danhachuel/leadmaster 0.1.26 → 0.1.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -19
- package/backend/__pycache__/main.cpython-311.pyc +0 -0
- package/backend/services/__pycache__/__init__.cpython-311.pyc +0 -0
- package/backend/services/__pycache__/agents.cpython-311.pyc +0 -0
- package/backend/services/__pycache__/crm_agent.cpython-311.pyc +0 -0
- package/backend/services/__pycache__/extractors.cpython-311.pyc +0 -0
- package/backend/services/__pycache__/flags.cpython-311.pyc +0 -0
- package/backend/services/__pycache__/llm.cpython-311.pyc +0 -0
- package/backend/services/__pycache__/storage.cpython-311.pyc +0 -0
- package/backend/tests/__pycache__/conftest.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/__pycache__/test_agents_routes.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/__pycache__/test_campaigns_routes.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/__pycache__/test_cnpj_extractor.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/__pycache__/test_config.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/__pycache__/test_crm_routes.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/__pycache__/test_extractors_real.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/__pycache__/test_funnel_routes.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/__pycache__/test_instagram_extractor.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/__pycache__/test_launcher_protections.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/__pycache__/test_lead_edit_routes.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/__pycache__/test_leads_export.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/__pycache__/test_maps_extractor.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/__pycache__/test_metrics.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/__pycache__/test_process_flags.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/__pycache__/test_webhook_routes.cpython-311-pytest-8.4.2.pyc +0 -0
- package/backend/tests/test_launcher_protections.py +12 -7
- package/frontend/dist/assets/{index-D5fh14uA.js → index-BUIOmUBy.js} +1 -1
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
- package/scripts/cli.mjs +10 -20
package/CHANGELOG.md
CHANGED
|
@@ -37,29 +37,63 @@ normaliza para a forma canônica (ex.: `0.1.0`).
|
|
|
37
37
|
falha se `process.stdin.resume();` desaparecer, se `.unref()` aparecer, se o
|
|
38
38
|
ciclo de vida vinculado for removido ou se os handlers globais sumirem.
|
|
39
39
|
|
|
40
|
+
## [0.1.28] — 2026-11-09
|
|
41
|
+
|
|
42
|
+
### Corrigido
|
|
43
|
+
|
|
44
|
+
- **Renumeração por colisão (E409):** a `0.1.27` já estava staged no registry
|
|
45
|
+
(sessão paralela), então esta versão republica o estado atual do `main` —
|
|
46
|
+
keep-alive do launcher com **Dummy Server** (`http.createServer` +
|
|
47
|
+
`listen(0, '127.0.0.1')` + `await new Promise(() => {})`, camada principal;
|
|
48
|
+
`stdin.resume`/`setInterval`/`beforeExit` secundárias) e os **gates de
|
|
49
|
+
regressão** correspondentes. Suíte: **83 passed**.
|
|
50
|
+
|
|
51
|
+
## [0.1.27] — 2026-11-09
|
|
52
|
+
|
|
53
|
+
### Corrigido (crítico)
|
|
54
|
+
|
|
55
|
+
- **Launcher — Dummy Server (keep-alive infalível):** as versões anteriores
|
|
56
|
+
dependiam de `stdin`/timers; quando o MobaXterm fecha a entrada padrão em EOF
|
|
57
|
+
(perda de foco/variação de PTY), o event loop do Node esvaziava e o prompt
|
|
58
|
+
voltava logo após "LeadMaster no ar", derrubando o uvicorn junto. Agora o
|
|
59
|
+
`cmdStart` cria, **logo após o spawn do Python**, um servidor HTTP inativo
|
|
60
|
+
(`http.createServer` + `keepAliveServer.listen(0, '127.0.0.1')`) — o socket
|
|
61
|
+
aberto no sistema operacional segura o processo **independentemente do
|
|
62
|
+
terminal**; o fluxo principal termina em `await new Promise(() => {})`
|
|
63
|
+
(congelado para sempre) e `stdin.resume`/`setInterval`/`beforeExit` seguem
|
|
64
|
+
como camadas secundárias. **Testado ao vivo com stdin em EOF (`< NUL`):**
|
|
65
|
+
node vivo 1min46s+, health 200, exportação CSV 200 no ar, encerramento
|
|
66
|
+
limpo, zero órfãos.
|
|
67
|
+
- **AGENTS.md:** regra 1 do launcher passa a ser o Dummy Server (camada
|
|
68
|
+
principal); regra 2 rebaixa stdin/timers a camadas secundárias.
|
|
69
|
+
- **Gates de regressão reforçados** (`test_launcher_protections.py`): falham se
|
|
70
|
+
`http.createServer`, `keepAliveServer.listen(0, '127.0.0.1')` ou
|
|
71
|
+
`await new Promise(() => {})` desaparecerem do corpo do `cmdStart`.
|
|
72
|
+
Suíte completa: **83 passed**.
|
|
73
|
+
|
|
40
74
|
## [0.1.26] — 2026-11-09
|
|
41
75
|
|
|
42
76
|
### Adicionado
|
|
43
77
|
|
|
44
|
-
- **Busca no CRM e exportação CSV
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
`
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"
|
|
55
|
-
|
|
56
|
-
'...'"* (Zeigarnik).
|
|
57
|
-
- **Corrigido
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
- **3 novos testes pytest** (`backend/tests/test_leads_export.py`): MIME +
|
|
61
|
-
|
|
62
|
-
|
|
78
|
+
- **Busca no CRM e exportação CSV** (registro retro-ativo — publicada sem
|
|
79
|
+
entrada anterior):
|
|
80
|
+
- `GET /api/crm/leads/export`: CSV de todos os leads com **BOM UTF-8**
|
|
81
|
+
(`\ufeff`, Excel em português não quebra acentos), delimitador `;`,
|
|
82
|
+
`text/csv; charset=utf-8` e
|
|
83
|
+
`Content-Disposition: attachment; filename="leads_leadmaster.csv"`; campos
|
|
84
|
+
de `extras` **achatados** como colunas `extras_<chave>` e listas (tags) em
|
|
85
|
+
células separadas por `; `.
|
|
86
|
+
- Frontend: **barra de busca larga** no CRM com filtragem local instantânea
|
|
87
|
+
por **Nome, Telefone ou Email** + botão de limpar (Lei de Fitts); botão
|
|
88
|
+
**"Exportar CSV"** em estilo **neutro/outline** — não compete com o
|
|
89
|
+
"Adicionar Lead" em gradiente (von Restorff); busca sem resultados mostra
|
|
90
|
+
*"Nenhum lead encontrado para '...'"* (Zeigarnik).
|
|
91
|
+
- **Corrigido:** o modelo `LeadIn` descartava o campo `extras` — leads
|
|
92
|
+
criados manualmente perdiam site/avaliação. Agora o POST preserva
|
|
93
|
+
`extras` (`LeadIn.extras: dict`).
|
|
94
|
+
- **3 novos testes pytest** (`backend/tests/test_leads_export.py`): MIME +
|
|
95
|
+
disposition + BOM + colunas, achatamento de `extras` e exportação de base
|
|
96
|
+
vazia (só cabeçalho).
|
|
63
97
|
|
|
64
98
|
## [0.1.25] — 2026-11-09
|
|
65
99
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -54,13 +54,18 @@ class TestLauncherProtections:
|
|
|
54
54
|
assert "já está rodando" not in c
|
|
55
55
|
|
|
56
56
|
def test_keepalive_no_fluxo_do_start(self):
|
|
57
|
-
# Gate de FLUXO (
|
|
58
|
-
# dentro do cmdStart — no install, em função morta ou em bloco
|
|
59
|
-
# não valem. A morte prematura do Node devolve o prompt do
|
|
57
|
+
# Gate de FLUXO (regressões da 0.1.21/0.1.24): as proteções precisam
|
|
58
|
+
# existir dentro do cmdStart — no install, em função morta ou em bloco
|
|
59
|
+
# errado não valem. A morte prematura do Node devolve o prompt do
|
|
60
|
+
# MobaXterm. A camada PRINCIPAL é o Dummy Server (socket do SO);
|
|
61
|
+
# setInterval/stdin/beforeExit são secundárias.
|
|
60
62
|
corpo = _corpo_cmd_start()
|
|
61
63
|
assert "spawn(" in corpo # worker Python é spawnado no start
|
|
62
|
-
assert "
|
|
63
|
-
assert "
|
|
64
|
+
assert "http.createServer" in corpo # Dummy Server: camada principal
|
|
65
|
+
assert "keepAliveServer.listen(0, '127.0.0.1')" in corpo
|
|
66
|
+
assert "await new Promise(() => {})" in corpo # fluxo principal congelado
|
|
67
|
+
assert "process.stdin.resume();" in corpo # camada secundária
|
|
68
|
+
assert "setInterval(() => {}, 1000)" in corpo # camada secundária
|
|
64
69
|
assert "beforeExit" in corpo # rede de segurança do event loop
|
|
65
70
|
assert "child.on('exit'" in corpo or 'child.on("exit"' in corpo
|
|
66
71
|
assert "child.on('close'" in corpo or 'child.on("close"' in corpo
|
|
@@ -69,10 +74,10 @@ class TestLauncherProtections:
|
|
|
69
74
|
def test_start_nunca_chama_exit_apos_terminal_preso(self):
|
|
70
75
|
# Após o terminal ser preso, nenhum caminho de sucesso chama
|
|
71
76
|
# process.exit — a saída só ocorre pelo ciclo de vida do filho
|
|
72
|
-
# (child exit/close) ou por sinais de parada legítima.
|
|
77
|
+
# (child exit/close) ou por sinais de parada legítima (SIGTERM/SIGBREAK).
|
|
73
78
|
corpo = _corpo_cmd_start()
|
|
74
79
|
pos = corpo.index("process.stdin.resume();")
|
|
75
|
-
fim_iife = corpo.
|
|
80
|
+
fim_iife = corpo.rindex("process.exit(1);") # catch de erro fatal, no fim
|
|
76
81
|
assert "process.exit(" not in corpo[pos:fim_iife]
|
|
77
82
|
|
|
78
83
|
def test_ciclo_de_vida_vinculado(self):
|
|
@@ -64,7 +64,7 @@ Error generating stack: `+i.message+`
|
|
|
64
64
|
* LICENSE.md file in the root directory of this source tree.
|
|
65
65
|
*
|
|
66
66
|
* @license MIT
|
|
67
|
-
*/function zl(){return zl=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var s in n)({}).hasOwnProperty.call(n,s)&&(t[s]=n[s])}return t},zl.apply(null,arguments)}function yy(t,e){if(t==null)return{};var n={};for(var s in t)if({}.hasOwnProperty.call(t,s)){if(e.indexOf(s)!==-1)continue;n[s]=t[s]}return n}function YS(t){return!!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)}function XS(t,e){return t.button===0&&(!e||e==="_self")&&!YS(t)}const qS=["onClick","relative","reloadDocument","replace","state","target","to","preventScrollReset","viewTransition"],GS=["aria-current","caseSensitive","className","end","style","to","viewTransition","children"],JS="6";try{window.__reactRouterVersion=JS}catch{}const ZS=w.createContext({isTransitioning:!1}),e_="startTransition",Xp=ub[e_];function t_(t){let{basename:e,children:n,future:s,window:r}=t,i=w.useRef();i.current==null&&(i.current=oS({window:r,v5Compat:!0}));let o=i.current,[a,l]=w.useState({action:o.action,location:o.location}),{v7_startTransition:c}=s||{},d=w.useCallback(f=>{c&&Xp?Xp(()=>l(f)):l(f)},[l,c]);return w.useLayoutEffect(()=>o.listen(d),[o,d]),w.useEffect(()=>VS(s),[s]),w.createElement(QS,{basename:e,children:n,location:a.location,navigationType:a.action,navigator:o,future:s})}const n_=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",s_=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,r_=w.forwardRef(function(e,n){let{onClick:s,relative:r,reloadDocument:i,replace:o,state:a,target:l,to:c,preventScrollReset:d,viewTransition:f}=e,h=yy(e,qS),{basename:p}=w.useContext(Os),v,x=!1;if(typeof c=="string"&&s_.test(c)&&(v=c,n_))try{let m=new URL(window.location.href),_=c.startsWith("//")?new URL(m.protocol+c):new URL(c),b=mi(_.pathname,p);_.origin===m.origin&&b!=null?c=b+_.search+_.hash:x=!0}catch{}let S=PS(c,{relative:r}),y=o_(c,{replace:o,state:a,target:l,preventScrollReset:d,relative:r,viewTransition:f});function g(m){s&&s(m),m.defaultPrevented||y(m)}return w.createElement("a",zl({},h,{href:v||S,onClick:x||i?s:g,ref:n,target:l}))}),vy=w.forwardRef(function(e,n){let{"aria-current":s="page",caseSensitive:r=!1,className:i="",end:o=!1,style:a,to:l,viewTransition:c,children:d}=e,f=yy(e,GS),h=wc(l,{relative:f.relative}),p=hr(),v=w.useContext(fy),{navigator:x,basename:S}=w.useContext(Os),y=v!=null&&a_(h)&&c===!0,g=x.encodeLocation?x.encodeLocation(h).pathname:h.pathname,m=p.pathname,_=v&&v.navigation&&v.navigation.location?v.navigation.location.pathname:null;r||(m=m.toLowerCase(),_=_?_.toLowerCase():null,g=g.toLowerCase()),_&&S&&(_=mi(_,S)||_);const b=g!=="/"&&g.endsWith("/")?g.length-1:g.length;let k=m===g||!o&&m.startsWith(g)&&m.charAt(b)==="/",C=_!=null&&(_===g||!o&&_.startsWith(g)&&_.charAt(g.length)==="/"),N={isActive:k,isPending:C,isTransitioning:y},R=k?s:void 0,M;typeof i=="function"?M=i(N):M=[i,k?"active":null,C?"pending":null,y?"transitioning":null].filter(Boolean).join(" ");let E=typeof a=="function"?a(N):a;return w.createElement(r_,zl({},f,{"aria-current":R,className:M,ref:n,style:E,to:l,viewTransition:c}),typeof d=="function"?d(N):d)});var Ld;(function(t){t.UseScrollRestoration="useScrollRestoration",t.UseSubmit="useSubmit",t.UseSubmitFetcher="useSubmitFetcher",t.UseFetcher="useFetcher",t.useViewTransitionState="useViewTransitionState"})(Ld||(Ld={}));var qp;(function(t){t.UseFetcher="useFetcher",t.UseFetchers="useFetchers",t.UseScrollRestoration="useScrollRestoration"})(qp||(qp={}));function i_(t){let e=w.useContext(vc);return e||Ne(!1),e}function o_(t,e){let{target:n,replace:s,state:r,preventScrollReset:i,relative:o,viewTransition:a}=e===void 0?{}:e,l=oa(),c=hr(),d=wc(t,{relative:o});return w.useCallback(f=>{if(XS(f,n)){f.preventDefault();let h=s!==void 0?s:Fl(c)===Fl(d);l(t,{replace:h,state:r,preventScrollReset:i,relative:o,viewTransition:a})}},[c,l,d,s,r,n,t,i,o,a])}function a_(t,e){e===void 0&&(e={});let n=w.useContext(ZS);n==null&&Ne(!1);let{basename:s}=i_(Ld.useViewTransitionState),r=wc(t,{relative:e.relative});if(!n.isTransitioning)return!1;let i=mi(n.currentLocation.pathname,s)||n.currentLocation.pathname,o=mi(n.nextLocation.pathname,s)||n.nextLocation.pathname;return Td(r.pathname,o)!=null||Td(r.pathname,i)!=null}const l_="/api";class by extends Error{constructor(n,s){super(s);U(this,"status");this.status=n,this.name="ApiError"}}async function V(t,e={}){const n=await fetch(l_+t,{...e,headers:e.body?{"Content-Type":"application/json",...e.headers||{}}:e.headers});if(!n.ok){let s=`Erro HTTP ${n.status}`;try{const r=await n.json();s=String(r.detail||r.mensagem||s)}catch{}throw new by(n.status,s)}if(n.status!==204)return n.json()}const Ce=t=>({method:"POST",body:JSON.stringify(t)}),Q={health:()=>V("/health"),doctor:()=>V("/doctor"),shutdown:()=>V("/shutdown",Ce({})),metricas:()=>V("/metrics"),leads:{listar:()=>V("/leads"),criar:t=>V("/leads",Ce(t)),atualizar:(t,e)=>V(`/leads/${t}`,{method:"PATCH",body:JSON.stringify(e)}),remover:t=>V(`/leads/${t}`,{method:"DELETE"}),importar:t=>V("/leads/import",Ce({leads:t})),enriquecer:t=>V(`/leads/${t}/enrich`,Ce({}))},crm:{leadsListar:()=>V("/crm/leads"),criarLead:t=>V("/crm/leads",Ce(t)),editarLead:(t,e)=>V(`/crm/leads/${t}`,{method:"PUT",body:JSON.stringify(e)}),exportarCsvUrl:()=>"/api/crm/leads/export",moverLead:(t,e)=>V(`/crm/leads/${t}/etapa`,{method:"PUT",body:JSON.stringify({etapa:e})}),sugestoes:()=>V("/crm/sugestoes"),aplicar:(t,e)=>V("/crm/sugestoes/aplicar",Ce({lead_id:t,para:e}))},campanhas:{listar:()=>V("/campaigns"),criar:t=>V("/campaigns",Ce(t)),status:(t,e)=>V(`/campaigns/${t}/status`,{method:"PUT",body:JSON.stringify({status:e})}),iniciar:t=>V(`/campaigns/${t}/start`,Ce({})),pausar:t=>V(`/campaigns/${t}/pause`,Ce({})),parar:t=>V(`/campaigns/${t}/stop`,Ce({})),remover:t=>V(`/campaigns/${t}`,{method:"DELETE"})},extrair:{maps:t=>V("/extractors/maps",Ce(t)),instagram:(t,e)=>V("/extractors/instagram",Ce({profile_url:t,limit:e})),cnpj:t=>V("/extract/cnpj",Ce({cnpj:t})),cnpjBusca:t=>V("/extract/cnpj/search",Ce(t)),cnpjExtract:t=>V("/extractors/cnpj",Ce(t))},config:{obter:()=>V("/config"),salvar:t=>V("/config",{method:"PUT",body:JSON.stringify(t)}),testarLlm:()=>V("/config/test/llm",Ce({})),testarIntegracao:t=>V("/config/test/integracao",Ce({url:t}))},integracoes:()=>V("/integrations/status"),agentes:{listar:()=>V("/agents"),status:(t,e)=>V(`/agents/${t}/status`,Ce({status:e})),salvarPrompt:(t,e)=>V(`/agents/${t}/prompt`,Ce({prompt:e})),templates:()=>V("/agents/templates"),salvarTemplates:t=>V("/agents/templates",{method:"PUT",body:JSON.stringify(t)}),testarTemplate:(t,e)=>V("/agents/templates/test",Ce({template:t,lead_id:e})),chat:t=>V("/agents/attendance/chat",Ce({mensagens:t}))},funil:()=>V("/funnel"),webhook:{obter:()=>V("/webhook"),salvar:t=>V("/webhook",{method:"PUT",body:JSON.stringify(t)}),testar:t=>V("/webhook/test",Ce({url:t}))}};function H(...t){return t.filter(Boolean).join(" ")}function c_(t){return(t||"?").trim().charAt(0).toUpperCase()||"?"}function $o(t){if(!t)return"—";try{return new Date(t).toLocaleString("pt-BR",{day:"2-digit",month:"2-digit",year:"2-digit",hour:"2-digit",minute:"2-digit"})}catch{return t}}function Sc(t){const e=(t||"").replace(/\D/g,"");return e?e.length===11?`(${e.slice(0,2)}) ${e.slice(2,7)}-${e.slice(7)}`:e.length===10?`(${e.slice(0,2)}) ${e.slice(2,6)}-${e.slice(6)}`:t||"—":"—"}function u_(t){const e=["nome","telefone","email","empresa","cidade","observacoes"],n=e.filter(s=>String(t[s]||"").trim().length>0);return Math.round(n.length/e.length*100)}function d_(t){const e={nome:"nome",telefone:"telefone",email:"e-mail",empresa:"empresa",cidade:"cidade",observacoes:"observações"};return["nome","telefone","email","empresa","cidade","observacoes"].filter(s=>String(t[s]||"").trim().length===0).map(s=>e[s])}function f_(t,e){if(t>=100)return"Lead 100% completo — excelente! 🎉";const n=e.slice(0,2).join(" e ");return`Faltam ${100-t}% (${n}${e.length>2?"...":""}) para o lead ficar completo`}function h_(t,e){const n=new Blob([JSON.stringify(t,null,2)],{type:"application/json"}),s=URL.createObjectURL(n),r=document.createElement("a");r.href=s,r.download=e,r.click(),URL.revokeObjectURL(s)}const p_={md:"max-w-lg",lg:"max-w-2xl",xl:"max-w-4xl"};function qt({aberto:t,onFechar:e,titulo:n,children:s,icone:r="fas fa-circle-info",largura:i="md"}){return w.useEffect(()=>{const o=a=>{a.key==="Escape"&&e()};return t&&window.addEventListener("keydown",o),()=>window.removeEventListener("keydown",o)},[t,e]),t?u.jsx("div",{className:"fixed inset-0 z-50 bg-black/40 flex items-center justify-center p-4",onMouseDown:o=>{o.target===o.currentTarget&&e()},children:u.jsxs("div",{className:H("bg-white rounded-2xl shadow-xl w-full",p_[i]),children:[u.jsxs("div",{className:"flex items-center justify-between px-6 py-4 border-b border-gray-100",children:[u.jsxs("h3",{className:"text-base font-semibold text-gray-800 flex items-center gap-2",children:[u.jsx("i",{className:H(r,"text-indigo-500")})," ",n]}),u.jsx("button",{onClick:e,className:"text-gray-400 hover:text-gray-600","aria-label":"Fechar",children:u.jsx("i",{className:"fas fa-times"})})]}),u.jsx("div",{className:"px-6 py-5 max-h-[70vh] overflow-y-auto",children:s})]})}):null}const m_=[{icone:"fas fa-users",texto:"Cadastre leads manualmente ou importe pelos Extratores (Maps, Instagram, CNPJ)."},{icone:"fas fa-columns",texto:"Arraste os cards no CRM conforme avança no funil (Leads → Em contato → Proposta → Fechado)."},{icone:"fas fa-bullhorn",texto:"Monte campanhas de disparo com seus templates e acompanhe as taxas no Painel."},{icone:"fas fa-robot",texto:"Use os Agentes (disparo e atendimento) e configure o LLM em Ferramentas para turbiná-los."}];function g_({titulo:t,nomeUsuario:e}){const[n,s]=w.useState(!1);return u.jsxs("header",{className:"bg-white shadow-sm px-8 py-4 flex items-center justify-between shrink-0",children:[u.jsx("div",{children:u.jsx("h2",{className:"text-lg font-semibold text-gray-800",children:t})}),u.jsxs("div",{className:"flex items-center space-x-4",children:[u.jsxs("button",{onClick:()=>s(!0),className:"text-sm text-indigo-600 hover:text-indigo-800 font-medium",children:[u.jsx("i",{className:"fas fa-play-circle mr-1"})," Ver tutorial"]}),u.jsx("div",{className:"w-8 h-8 rounded-full bg-indigo-100 flex items-center justify-center text-indigo-600 font-bold text-sm",children:c_(e)}),u.jsx("span",{className:"text-sm font-medium text-gray-700",children:e})]}),u.jsxs(qt,{aberto:n,onFechar:()=>s(!1),titulo:"Tutorial rápido",icone:"fas fa-graduation-cap",children:[u.jsx("ol",{className:"space-y-4",children:m_.map((r,i)=>u.jsxs("li",{className:"flex gap-3 items-start",children:[u.jsx("span",{className:"w-8 h-8 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center shrink-0",children:u.jsx("i",{className:r.icone})}),u.jsx("p",{className:"text-sm text-gray-600 pt-1.5",children:r.texto})]},i))}),u.jsx("p",{className:"text-xs text-gray-400 mt-5",children:"Dica: o LLM (para enriquecimento e agentes) é configurado em Ferramentas."})]})]})}const x_=[{itens:[{para:"/",icone:"fas fa-chart-pie text-indigo-300",rotulo:"Painel",fim:!0}]},{secao:"Conexões",itens:[{para:"/leads",icone:"fas fa-users",rotulo:"Leads"},{para:"/agentes",icone:"fas fa-robot",rotulo:"Agentes"},{para:"/ferramentas",icone:"fas fa-tools",rotulo:"Ferramentas"}]},{itens:[{para:"/extrator-maps",icone:"fas fa-map-marked-alt",rotulo:"Extrator Maps"},{para:"/extrator-instagram",icone:"fab fa-instagram",rotulo:"Extrator Instagram"},{para:"/extrator-cnpj",icone:"fas fa-building",rotulo:"Extrator CNPJ"}]},{secao:"Gestão",itens:[{para:"/disparos",icone:"fas fa-bullhorn",rotulo:"Disparos"},{para:"/crm",icone:"fas fa-columns",rotulo:"CRM"},{para:"/funil",icone:"fas fa-filter",rotulo:"Funil de Prospecção"}]},{secao:"Integrações",itens:[{para:"/webhook",icone:"fas fa-link",rotulo:"Webhook"},{para:"/suporte",icone:"fas fa-headset",rotulo:"Suporte"}]}];function y_({onSair:t}){const e=hr(),[n,s]=w.useState(!1);w.useEffect(()=>{e.pathname==="/agentes"&&s(!0)},[e.pathname]);const r=i=>{if(i.rotulo==="Agentes")return e.pathname==="/agentes";const[o,a]=i.para.split("?");return a?e.pathname===o&&e.search.includes(a):i.fim?e.pathname===o:e.pathname.startsWith(o)};return u.jsxs("aside",{className:"w-64 bg-[#1e1b4b] text-white flex flex-col shrink-0 h-screen sticky top-0",children:[u.jsx("div",{className:"p-6 border-b border-gray-700",children:u.jsxs("h1",{className:"text-2xl font-bold tracking-tight flex items-center gap-2",children:[u.jsx("span",{className:"text-2xl",children:"⚡"}),"LeadMaster",u.jsxs("span",{className:"text-[10px] font-medium text-indigo-300 border border-indigo-400/40 rounded-md px-1.5 py-0.5",children:["v","0.1.26"]})]})}),u.jsx("nav",{className:"flex-1 overflow-y-auto py-4",children:u.jsx("ul",{className:"space-y-1",children:x_.map((i,o)=>u.jsx("li",{children:u.jsxs("ul",{children:[i.secao&&u.jsx("li",{className:"px-6 py-2 text-xs font-semibold text-gray-400 uppercase tracking-wider list-none",children:i.secao}),i.itens.map(a=>a.rotulo==="Agentes"?u.jsxs("li",{children:[u.jsxs("button",{type:"button",onClick:()=>s(l=>!l),className:H("sidebar-link w-full flex items-center px-6 py-2.5 text-sm",r(a)&&"active"),children:[u.jsx("i",{className:H(a.icone,"w-5 text-gray-400")}),u.jsx("span",{className:"ml-3",children:a.rotulo}),u.jsx("i",{className:H("fas fa-chevron-down ml-auto text-xs text-gray-400 transition-transform",n&&"rotate-180")})]}),n&&u.jsxs("ul",{className:"pl-12 space-y-1 mt-1",children:[u.jsx("li",{children:u.jsx(Gp,{para:"/agentes?tab=disparo",rotulo:"Agente de Disparo",ativo:e.pathname==="/agentes"&&e.search.includes("disparo")})}),u.jsx("li",{children:u.jsx(Gp,{para:"/agentes?tab=atendimento",rotulo:"Agente de Atendimento",ativo:e.pathname==="/agentes"&&e.search.includes("atendimento")})})]})]},"agentes"):u.jsx("li",{children:u.jsxs(vy,{to:a.para,className:H("sidebar-link flex items-center px-6 py-2.5 text-sm",r(a)&&"active"),children:[u.jsx("i",{className:H(a.icone,"w-5 text-gray-400")}),u.jsx("span",{className:"ml-3",children:a.rotulo})]})},a.para))]})},o))})}),u.jsx("div",{className:"p-4 border-t border-gray-700",children:u.jsxs("button",{onClick:t,className:"w-full flex items-center justify-center px-4 py-2.5 bg-gradient-to-r from-indigo-500 to-purple-500 rounded-lg text-sm font-medium hover:opacity-90 transition",children:[u.jsx("i",{className:"fas fa-sign-out-alt mr-2"})," Sair"]})})]})}function Gp({para:t,rotulo:e,ativo:n}){return u.jsx(vy,{to:t,className:H("sidebar-link block px-4 py-2 text-xs text-gray-300 rounded",n&&"active"),children:e})}const wy=w.createContext({toast:()=>{}});function tn(){return w.useContext(wy)}const v_={sucesso:"bg-green-600",erro:"bg-red-600",info:"bg-indigo-600"},b_={sucesso:"fas fa-check-circle",erro:"fas fa-exclamation-circle",info:"fas fa-info-circle"};function w_({children:t}){const[e,n]=w.useState([]),s=w.useRef(0),r=w.useCallback((i,o)=>{const a=++s.current;n(l=>[...l,{id:a,tipo:i,mensagem:o}]),setTimeout(()=>n(l=>l.filter(c=>c.id!==a)),4500)},[]);return u.jsxs(wy.Provider,{value:{toast:r},children:[t,u.jsx("div",{className:"fixed top-4 right-4 z-[100] space-y-2 w-80",children:e.map(i=>u.jsxs("div",{className:H(v_[i.tipo],"text-white text-sm rounded-lg shadow-lg px-4 py-3 flex items-start gap-2 animate-pulse-once"),role:"status",children:[u.jsx("i",{className:H(b_[i.tipo],"mt-0.5")}),u.jsx("span",{className:"flex-1",children:i.mensagem}),u.jsx("button",{className:"opacity-70 hover:opacity-100",onClick:()=>n(o=>o.filter(a=>a.id!==i.id)),"aria-label":"Fechar",children:u.jsx("i",{className:"fas fa-times"})})]},i.id))})]})}function Ta({rotulo:t,valor:e,subtitulo:n,children:s,icone:r}){return u.jsxs("div",{className:"bg-white rounded-xl shadow-sm p-5 border border-gray-100",children:[u.jsxs("div",{className:"flex items-center justify-between",children:[u.jsx("p",{className:"text-sm text-gray-500 font-medium",children:t}),r&&u.jsx("i",{className:`${r} text-indigo-300`})]}),s??u.jsxs(u.Fragment,{children:[u.jsx("p",{className:"text-2xl font-bold text-gray-800 mt-1",children:e}),n&&u.jsx("p",{className:"text-xs text-gray-400 mt-0.5",children:n})]})]})}/*!
|
|
67
|
+
*/function zl(){return zl=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var s in n)({}).hasOwnProperty.call(n,s)&&(t[s]=n[s])}return t},zl.apply(null,arguments)}function yy(t,e){if(t==null)return{};var n={};for(var s in t)if({}.hasOwnProperty.call(t,s)){if(e.indexOf(s)!==-1)continue;n[s]=t[s]}return n}function YS(t){return!!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)}function XS(t,e){return t.button===0&&(!e||e==="_self")&&!YS(t)}const qS=["onClick","relative","reloadDocument","replace","state","target","to","preventScrollReset","viewTransition"],GS=["aria-current","caseSensitive","className","end","style","to","viewTransition","children"],JS="6";try{window.__reactRouterVersion=JS}catch{}const ZS=w.createContext({isTransitioning:!1}),e_="startTransition",Xp=ub[e_];function t_(t){let{basename:e,children:n,future:s,window:r}=t,i=w.useRef();i.current==null&&(i.current=oS({window:r,v5Compat:!0}));let o=i.current,[a,l]=w.useState({action:o.action,location:o.location}),{v7_startTransition:c}=s||{},d=w.useCallback(f=>{c&&Xp?Xp(()=>l(f)):l(f)},[l,c]);return w.useLayoutEffect(()=>o.listen(d),[o,d]),w.useEffect(()=>VS(s),[s]),w.createElement(QS,{basename:e,children:n,location:a.location,navigationType:a.action,navigator:o,future:s})}const n_=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",s_=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,r_=w.forwardRef(function(e,n){let{onClick:s,relative:r,reloadDocument:i,replace:o,state:a,target:l,to:c,preventScrollReset:d,viewTransition:f}=e,h=yy(e,qS),{basename:p}=w.useContext(Os),v,x=!1;if(typeof c=="string"&&s_.test(c)&&(v=c,n_))try{let m=new URL(window.location.href),_=c.startsWith("//")?new URL(m.protocol+c):new URL(c),b=mi(_.pathname,p);_.origin===m.origin&&b!=null?c=b+_.search+_.hash:x=!0}catch{}let S=PS(c,{relative:r}),y=o_(c,{replace:o,state:a,target:l,preventScrollReset:d,relative:r,viewTransition:f});function g(m){s&&s(m),m.defaultPrevented||y(m)}return w.createElement("a",zl({},h,{href:v||S,onClick:x||i?s:g,ref:n,target:l}))}),vy=w.forwardRef(function(e,n){let{"aria-current":s="page",caseSensitive:r=!1,className:i="",end:o=!1,style:a,to:l,viewTransition:c,children:d}=e,f=yy(e,GS),h=wc(l,{relative:f.relative}),p=hr(),v=w.useContext(fy),{navigator:x,basename:S}=w.useContext(Os),y=v!=null&&a_(h)&&c===!0,g=x.encodeLocation?x.encodeLocation(h).pathname:h.pathname,m=p.pathname,_=v&&v.navigation&&v.navigation.location?v.navigation.location.pathname:null;r||(m=m.toLowerCase(),_=_?_.toLowerCase():null,g=g.toLowerCase()),_&&S&&(_=mi(_,S)||_);const b=g!=="/"&&g.endsWith("/")?g.length-1:g.length;let k=m===g||!o&&m.startsWith(g)&&m.charAt(b)==="/",C=_!=null&&(_===g||!o&&_.startsWith(g)&&_.charAt(g.length)==="/"),N={isActive:k,isPending:C,isTransitioning:y},R=k?s:void 0,M;typeof i=="function"?M=i(N):M=[i,k?"active":null,C?"pending":null,y?"transitioning":null].filter(Boolean).join(" ");let E=typeof a=="function"?a(N):a;return w.createElement(r_,zl({},f,{"aria-current":R,className:M,ref:n,style:E,to:l,viewTransition:c}),typeof d=="function"?d(N):d)});var Ld;(function(t){t.UseScrollRestoration="useScrollRestoration",t.UseSubmit="useSubmit",t.UseSubmitFetcher="useSubmitFetcher",t.UseFetcher="useFetcher",t.useViewTransitionState="useViewTransitionState"})(Ld||(Ld={}));var qp;(function(t){t.UseFetcher="useFetcher",t.UseFetchers="useFetchers",t.UseScrollRestoration="useScrollRestoration"})(qp||(qp={}));function i_(t){let e=w.useContext(vc);return e||Ne(!1),e}function o_(t,e){let{target:n,replace:s,state:r,preventScrollReset:i,relative:o,viewTransition:a}=e===void 0?{}:e,l=oa(),c=hr(),d=wc(t,{relative:o});return w.useCallback(f=>{if(XS(f,n)){f.preventDefault();let h=s!==void 0?s:Fl(c)===Fl(d);l(t,{replace:h,state:r,preventScrollReset:i,relative:o,viewTransition:a})}},[c,l,d,s,r,n,t,i,o,a])}function a_(t,e){e===void 0&&(e={});let n=w.useContext(ZS);n==null&&Ne(!1);let{basename:s}=i_(Ld.useViewTransitionState),r=wc(t,{relative:e.relative});if(!n.isTransitioning)return!1;let i=mi(n.currentLocation.pathname,s)||n.currentLocation.pathname,o=mi(n.nextLocation.pathname,s)||n.nextLocation.pathname;return Td(r.pathname,o)!=null||Td(r.pathname,i)!=null}const l_="/api";class by extends Error{constructor(n,s){super(s);U(this,"status");this.status=n,this.name="ApiError"}}async function V(t,e={}){const n=await fetch(l_+t,{...e,headers:e.body?{"Content-Type":"application/json",...e.headers||{}}:e.headers});if(!n.ok){let s=`Erro HTTP ${n.status}`;try{const r=await n.json();s=String(r.detail||r.mensagem||s)}catch{}throw new by(n.status,s)}if(n.status!==204)return n.json()}const Ce=t=>({method:"POST",body:JSON.stringify(t)}),Q={health:()=>V("/health"),doctor:()=>V("/doctor"),shutdown:()=>V("/shutdown",Ce({})),metricas:()=>V("/metrics"),leads:{listar:()=>V("/leads"),criar:t=>V("/leads",Ce(t)),atualizar:(t,e)=>V(`/leads/${t}`,{method:"PATCH",body:JSON.stringify(e)}),remover:t=>V(`/leads/${t}`,{method:"DELETE"}),importar:t=>V("/leads/import",Ce({leads:t})),enriquecer:t=>V(`/leads/${t}/enrich`,Ce({}))},crm:{leadsListar:()=>V("/crm/leads"),criarLead:t=>V("/crm/leads",Ce(t)),editarLead:(t,e)=>V(`/crm/leads/${t}`,{method:"PUT",body:JSON.stringify(e)}),exportarCsvUrl:()=>"/api/crm/leads/export",moverLead:(t,e)=>V(`/crm/leads/${t}/etapa`,{method:"PUT",body:JSON.stringify({etapa:e})}),sugestoes:()=>V("/crm/sugestoes"),aplicar:(t,e)=>V("/crm/sugestoes/aplicar",Ce({lead_id:t,para:e}))},campanhas:{listar:()=>V("/campaigns"),criar:t=>V("/campaigns",Ce(t)),status:(t,e)=>V(`/campaigns/${t}/status`,{method:"PUT",body:JSON.stringify({status:e})}),iniciar:t=>V(`/campaigns/${t}/start`,Ce({})),pausar:t=>V(`/campaigns/${t}/pause`,Ce({})),parar:t=>V(`/campaigns/${t}/stop`,Ce({})),remover:t=>V(`/campaigns/${t}`,{method:"DELETE"})},extrair:{maps:t=>V("/extractors/maps",Ce(t)),instagram:(t,e)=>V("/extractors/instagram",Ce({profile_url:t,limit:e})),cnpj:t=>V("/extract/cnpj",Ce({cnpj:t})),cnpjBusca:t=>V("/extract/cnpj/search",Ce(t)),cnpjExtract:t=>V("/extractors/cnpj",Ce(t))},config:{obter:()=>V("/config"),salvar:t=>V("/config",{method:"PUT",body:JSON.stringify(t)}),testarLlm:()=>V("/config/test/llm",Ce({})),testarIntegracao:t=>V("/config/test/integracao",Ce({url:t}))},integracoes:()=>V("/integrations/status"),agentes:{listar:()=>V("/agents"),status:(t,e)=>V(`/agents/${t}/status`,Ce({status:e})),salvarPrompt:(t,e)=>V(`/agents/${t}/prompt`,Ce({prompt:e})),templates:()=>V("/agents/templates"),salvarTemplates:t=>V("/agents/templates",{method:"PUT",body:JSON.stringify(t)}),testarTemplate:(t,e)=>V("/agents/templates/test",Ce({template:t,lead_id:e})),chat:t=>V("/agents/attendance/chat",Ce({mensagens:t}))},funil:()=>V("/funnel"),webhook:{obter:()=>V("/webhook"),salvar:t=>V("/webhook",{method:"PUT",body:JSON.stringify(t)}),testar:t=>V("/webhook/test",Ce({url:t}))}};function H(...t){return t.filter(Boolean).join(" ")}function c_(t){return(t||"?").trim().charAt(0).toUpperCase()||"?"}function $o(t){if(!t)return"—";try{return new Date(t).toLocaleString("pt-BR",{day:"2-digit",month:"2-digit",year:"2-digit",hour:"2-digit",minute:"2-digit"})}catch{return t}}function Sc(t){const e=(t||"").replace(/\D/g,"");return e?e.length===11?`(${e.slice(0,2)}) ${e.slice(2,7)}-${e.slice(7)}`:e.length===10?`(${e.slice(0,2)}) ${e.slice(2,6)}-${e.slice(6)}`:t||"—":"—"}function u_(t){const e=["nome","telefone","email","empresa","cidade","observacoes"],n=e.filter(s=>String(t[s]||"").trim().length>0);return Math.round(n.length/e.length*100)}function d_(t){const e={nome:"nome",telefone:"telefone",email:"e-mail",empresa:"empresa",cidade:"cidade",observacoes:"observações"};return["nome","telefone","email","empresa","cidade","observacoes"].filter(s=>String(t[s]||"").trim().length===0).map(s=>e[s])}function f_(t,e){if(t>=100)return"Lead 100% completo — excelente! 🎉";const n=e.slice(0,2).join(" e ");return`Faltam ${100-t}% (${n}${e.length>2?"...":""}) para o lead ficar completo`}function h_(t,e){const n=new Blob([JSON.stringify(t,null,2)],{type:"application/json"}),s=URL.createObjectURL(n),r=document.createElement("a");r.href=s,r.download=e,r.click(),URL.revokeObjectURL(s)}const p_={md:"max-w-lg",lg:"max-w-2xl",xl:"max-w-4xl"};function qt({aberto:t,onFechar:e,titulo:n,children:s,icone:r="fas fa-circle-info",largura:i="md"}){return w.useEffect(()=>{const o=a=>{a.key==="Escape"&&e()};return t&&window.addEventListener("keydown",o),()=>window.removeEventListener("keydown",o)},[t,e]),t?u.jsx("div",{className:"fixed inset-0 z-50 bg-black/40 flex items-center justify-center p-4",onMouseDown:o=>{o.target===o.currentTarget&&e()},children:u.jsxs("div",{className:H("bg-white rounded-2xl shadow-xl w-full",p_[i]),children:[u.jsxs("div",{className:"flex items-center justify-between px-6 py-4 border-b border-gray-100",children:[u.jsxs("h3",{className:"text-base font-semibold text-gray-800 flex items-center gap-2",children:[u.jsx("i",{className:H(r,"text-indigo-500")})," ",n]}),u.jsx("button",{onClick:e,className:"text-gray-400 hover:text-gray-600","aria-label":"Fechar",children:u.jsx("i",{className:"fas fa-times"})})]}),u.jsx("div",{className:"px-6 py-5 max-h-[70vh] overflow-y-auto",children:s})]})}):null}const m_=[{icone:"fas fa-users",texto:"Cadastre leads manualmente ou importe pelos Extratores (Maps, Instagram, CNPJ)."},{icone:"fas fa-columns",texto:"Arraste os cards no CRM conforme avança no funil (Leads → Em contato → Proposta → Fechado)."},{icone:"fas fa-bullhorn",texto:"Monte campanhas de disparo com seus templates e acompanhe as taxas no Painel."},{icone:"fas fa-robot",texto:"Use os Agentes (disparo e atendimento) e configure o LLM em Ferramentas para turbiná-los."}];function g_({titulo:t,nomeUsuario:e}){const[n,s]=w.useState(!1);return u.jsxs("header",{className:"bg-white shadow-sm px-8 py-4 flex items-center justify-between shrink-0",children:[u.jsx("div",{children:u.jsx("h2",{className:"text-lg font-semibold text-gray-800",children:t})}),u.jsxs("div",{className:"flex items-center space-x-4",children:[u.jsxs("button",{onClick:()=>s(!0),className:"text-sm text-indigo-600 hover:text-indigo-800 font-medium",children:[u.jsx("i",{className:"fas fa-play-circle mr-1"})," Ver tutorial"]}),u.jsx("div",{className:"w-8 h-8 rounded-full bg-indigo-100 flex items-center justify-center text-indigo-600 font-bold text-sm",children:c_(e)}),u.jsx("span",{className:"text-sm font-medium text-gray-700",children:e})]}),u.jsxs(qt,{aberto:n,onFechar:()=>s(!1),titulo:"Tutorial rápido",icone:"fas fa-graduation-cap",children:[u.jsx("ol",{className:"space-y-4",children:m_.map((r,i)=>u.jsxs("li",{className:"flex gap-3 items-start",children:[u.jsx("span",{className:"w-8 h-8 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center shrink-0",children:u.jsx("i",{className:r.icone})}),u.jsx("p",{className:"text-sm text-gray-600 pt-1.5",children:r.texto})]},i))}),u.jsx("p",{className:"text-xs text-gray-400 mt-5",children:"Dica: o LLM (para enriquecimento e agentes) é configurado em Ferramentas."})]})]})}const x_=[{itens:[{para:"/",icone:"fas fa-chart-pie text-indigo-300",rotulo:"Painel",fim:!0}]},{secao:"Conexões",itens:[{para:"/leads",icone:"fas fa-users",rotulo:"Leads"},{para:"/agentes",icone:"fas fa-robot",rotulo:"Agentes"},{para:"/ferramentas",icone:"fas fa-tools",rotulo:"Ferramentas"}]},{itens:[{para:"/extrator-maps",icone:"fas fa-map-marked-alt",rotulo:"Extrator Maps"},{para:"/extrator-instagram",icone:"fab fa-instagram",rotulo:"Extrator Instagram"},{para:"/extrator-cnpj",icone:"fas fa-building",rotulo:"Extrator CNPJ"}]},{secao:"Gestão",itens:[{para:"/disparos",icone:"fas fa-bullhorn",rotulo:"Disparos"},{para:"/crm",icone:"fas fa-columns",rotulo:"CRM"},{para:"/funil",icone:"fas fa-filter",rotulo:"Funil de Prospecção"}]},{secao:"Integrações",itens:[{para:"/webhook",icone:"fas fa-link",rotulo:"Webhook"},{para:"/suporte",icone:"fas fa-headset",rotulo:"Suporte"}]}];function y_({onSair:t}){const e=hr(),[n,s]=w.useState(!1);w.useEffect(()=>{e.pathname==="/agentes"&&s(!0)},[e.pathname]);const r=i=>{if(i.rotulo==="Agentes")return e.pathname==="/agentes";const[o,a]=i.para.split("?");return a?e.pathname===o&&e.search.includes(a):i.fim?e.pathname===o:e.pathname.startsWith(o)};return u.jsxs("aside",{className:"w-64 bg-[#1e1b4b] text-white flex flex-col shrink-0 h-screen sticky top-0",children:[u.jsx("div",{className:"p-6 border-b border-gray-700",children:u.jsxs("h1",{className:"text-2xl font-bold tracking-tight flex items-center gap-2",children:[u.jsx("span",{className:"text-2xl",children:"⚡"}),"LeadMaster",u.jsxs("span",{className:"text-[10px] font-medium text-indigo-300 border border-indigo-400/40 rounded-md px-1.5 py-0.5",children:["v","0.1.28"]})]})}),u.jsx("nav",{className:"flex-1 overflow-y-auto py-4",children:u.jsx("ul",{className:"space-y-1",children:x_.map((i,o)=>u.jsx("li",{children:u.jsxs("ul",{children:[i.secao&&u.jsx("li",{className:"px-6 py-2 text-xs font-semibold text-gray-400 uppercase tracking-wider list-none",children:i.secao}),i.itens.map(a=>a.rotulo==="Agentes"?u.jsxs("li",{children:[u.jsxs("button",{type:"button",onClick:()=>s(l=>!l),className:H("sidebar-link w-full flex items-center px-6 py-2.5 text-sm",r(a)&&"active"),children:[u.jsx("i",{className:H(a.icone,"w-5 text-gray-400")}),u.jsx("span",{className:"ml-3",children:a.rotulo}),u.jsx("i",{className:H("fas fa-chevron-down ml-auto text-xs text-gray-400 transition-transform",n&&"rotate-180")})]}),n&&u.jsxs("ul",{className:"pl-12 space-y-1 mt-1",children:[u.jsx("li",{children:u.jsx(Gp,{para:"/agentes?tab=disparo",rotulo:"Agente de Disparo",ativo:e.pathname==="/agentes"&&e.search.includes("disparo")})}),u.jsx("li",{children:u.jsx(Gp,{para:"/agentes?tab=atendimento",rotulo:"Agente de Atendimento",ativo:e.pathname==="/agentes"&&e.search.includes("atendimento")})})]})]},"agentes"):u.jsx("li",{children:u.jsxs(vy,{to:a.para,className:H("sidebar-link flex items-center px-6 py-2.5 text-sm",r(a)&&"active"),children:[u.jsx("i",{className:H(a.icone,"w-5 text-gray-400")}),u.jsx("span",{className:"ml-3",children:a.rotulo})]})},a.para))]})},o))})}),u.jsx("div",{className:"p-4 border-t border-gray-700",children:u.jsxs("button",{onClick:t,className:"w-full flex items-center justify-center px-4 py-2.5 bg-gradient-to-r from-indigo-500 to-purple-500 rounded-lg text-sm font-medium hover:opacity-90 transition",children:[u.jsx("i",{className:"fas fa-sign-out-alt mr-2"})," Sair"]})})]})}function Gp({para:t,rotulo:e,ativo:n}){return u.jsx(vy,{to:t,className:H("sidebar-link block px-4 py-2 text-xs text-gray-300 rounded",n&&"active"),children:e})}const wy=w.createContext({toast:()=>{}});function tn(){return w.useContext(wy)}const v_={sucesso:"bg-green-600",erro:"bg-red-600",info:"bg-indigo-600"},b_={sucesso:"fas fa-check-circle",erro:"fas fa-exclamation-circle",info:"fas fa-info-circle"};function w_({children:t}){const[e,n]=w.useState([]),s=w.useRef(0),r=w.useCallback((i,o)=>{const a=++s.current;n(l=>[...l,{id:a,tipo:i,mensagem:o}]),setTimeout(()=>n(l=>l.filter(c=>c.id!==a)),4500)},[]);return u.jsxs(wy.Provider,{value:{toast:r},children:[t,u.jsx("div",{className:"fixed top-4 right-4 z-[100] space-y-2 w-80",children:e.map(i=>u.jsxs("div",{className:H(v_[i.tipo],"text-white text-sm rounded-lg shadow-lg px-4 py-3 flex items-start gap-2 animate-pulse-once"),role:"status",children:[u.jsx("i",{className:H(b_[i.tipo],"mt-0.5")}),u.jsx("span",{className:"flex-1",children:i.mensagem}),u.jsx("button",{className:"opacity-70 hover:opacity-100",onClick:()=>n(o=>o.filter(a=>a.id!==i.id)),"aria-label":"Fechar",children:u.jsx("i",{className:"fas fa-times"})})]},i.id))})]})}function Ta({rotulo:t,valor:e,subtitulo:n,children:s,icone:r}){return u.jsxs("div",{className:"bg-white rounded-xl shadow-sm p-5 border border-gray-100",children:[u.jsxs("div",{className:"flex items-center justify-between",children:[u.jsx("p",{className:"text-sm text-gray-500 font-medium",children:t}),r&&u.jsx("i",{className:`${r} text-indigo-300`})]}),s??u.jsxs(u.Fragment,{children:[u.jsx("p",{className:"text-2xl font-bold text-gray-800 mt-1",children:e}),n&&u.jsx("p",{className:"text-xs text-gray-400 mt-0.5",children:n})]})]})}/*!
|
|
68
68
|
* @kurkle/color v0.3.4
|
|
69
69
|
* https://github.com/kurkle/color#readme
|
|
70
70
|
* (c) 2024 Jukka Kurkela
|
package/frontend/dist/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
7
7
|
<title>LeadMaster — Painel</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-BUIOmUBy.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/assets/index-NeGNWLr8.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body class="bg-gray-100 min-h-screen">
|
package/package.json
CHANGED
package/scripts/cli.mjs
CHANGED
|
@@ -672,11 +672,10 @@ function cmdStart(args) {
|
|
|
672
672
|
}
|
|
673
673
|
|
|
674
674
|
// -------------------------------------------------------------------------
|
|
675
|
-
//
|
|
676
|
-
//
|
|
677
|
-
//
|
|
678
|
-
//
|
|
679
|
-
// sempre encerram. No Linux/macOS, SIGINT/SIGHUP mantêm o stop gracioso.
|
|
675
|
+
// Camadas SECUNDÁRIAS de keep-alive (o Dummy Server acima é a principal):
|
|
676
|
+
// setInterval mantém o loop ativo, stdin.resume ouve digitação, e o
|
|
677
|
+
// beforeExit re-arma o timer se o loop esvaziar. Erros de stdin são
|
|
678
|
+
// ignorados — nenhum deles pode derrubar o launcher.
|
|
680
679
|
// -------------------------------------------------------------------------
|
|
681
680
|
const ehWindows = platform() === 'win32';
|
|
682
681
|
const naoAbsorver = () => { stop(); process.exit(0); };
|
|
@@ -691,23 +690,8 @@ function cmdStart(args) {
|
|
|
691
690
|
process.on('SIGBREAK', naoAbsorver);
|
|
692
691
|
}
|
|
693
692
|
|
|
694
|
-
// Keep-alive (regra inviolável do AGENTS.md): mantém o event loop ativo
|
|
695
|
-
// mesmo sem I/O de console (MobaXterm minimizado / sem stream ativo).
|
|
696
693
|
setInterval(() => {}, 1000);
|
|
697
|
-
|
|
698
|
-
// Terminal preso (regra inviolável do AGENTS.md) — SOLUÇÃO DEFINITIVA:
|
|
699
|
-
// ao retomar a entrada padrão IMEDIATAMENTE antes das mensagens finais
|
|
700
|
-
// de sucesso, o Node permanece vivo indefinidamente aguardando qualquer
|
|
701
|
-
// digitação do usuário. O prompt do MobaXterm NUNCA é devolvido e a PTY
|
|
702
|
-
// (e com ela o uvicorn) não é fechada. Esta linha NÃO depende de timers
|
|
703
|
-
// nem de npx — NUNCA REMOVER.
|
|
704
694
|
process.stdin.resume();
|
|
705
|
-
|
|
706
|
-
// Rede de segurança (regra inviolável do AGENTS.md): se o event loop
|
|
707
|
-
// esvaziar (stdin em EOF, timer perdido, qualquer surpresa do terminal/
|
|
708
|
-
// PTY do MobaXterm), o Node re-ativa o keep-alive no 'beforeExit' em vez
|
|
709
|
-
// de encerrar — o prompt NUNCA é devolvido e o uvicorn não fica órfão.
|
|
710
|
-
// Erros no stream de stdin também nunca derrubam o launcher.
|
|
711
695
|
process.stdin.on('error', () => {});
|
|
712
696
|
process.on('beforeExit', () => {
|
|
713
697
|
setInterval(() => {}, 1000);
|
|
@@ -721,6 +705,12 @@ function cmdStart(args) {
|
|
|
721
705
|
? 'ℹ Para encerrar: Ctrl+Break ou feche a janela (Ctrl+C é absorvido no Windows contra sinais espúrios do MobaXterm).'
|
|
722
706
|
: 'ℹ Para encerrar: Ctrl+C.',
|
|
723
707
|
);
|
|
708
|
+
|
|
709
|
+
// Congela o fluxo principal PARA SEMPRE (regra inviolável): a promessa
|
|
710
|
+
// nunca resolve, então nenhum código posterior pode rodar e nenhum exit
|
|
711
|
+
// "natural" acontece. A saída acontece somente pelo ciclo de vida do
|
|
712
|
+
// filho (Python morre) ou por SIGTERM/SIGBREAK — ambos com log.
|
|
713
|
+
await new Promise(() => {});
|
|
724
714
|
})().catch((err) => {
|
|
725
715
|
console.error('✗ Erro inesperado ao iniciar:', err && err.message ? err.message : err);
|
|
726
716
|
process.exit(1);
|