{
  "id": "email-watcher",
  "name": "Email Watcher",
  "category": "automation",
  "tags": [
    "email",
    "automation",
    "watch",
    "inbox",
    "auto-summary",
    "gmail"
  ],
  "description": "Watches your inbox, lists unread, auto-summarizes new mail with the agent. Polls every 2 min via the email skill.",
  "triggers": [
    "email watcher",
    "watch inbox",
    "unread mail",
    "monitor email",
    "email feed",
    "inbox monitor"
  ],
  "defaultSize": {
    "w": 5,
    "h": 5
  },
  "source": "function EmailWatcher() {\n  const [mail, setMail] = React.useState([]);\n  const [busy, setBusy] = React.useState(false);\n  const [summarizing, setSummarizing] = React.useState(null);\n  const [summary, setSummary] = React.useState({});\n  const [error, setError] = React.useState('');\n  const refresh = async () => {\n    setBusy(true);\n    try {\n      const r = await titan.api.call('/api/skills/email', { action: 'list', folder: 'INBOX', unreadOnly: true, max: 20 });\n      setMail(Array.isArray(r?.messages) ? r.messages : []);\n      setError('');\n    } catch (e) { setError(String(e?.message||e)); }\n    finally { setBusy(false); }\n  };\n  React.useEffect(() => { refresh(); const id = setInterval(refresh, 120000); return () => clearInterval(id); }, []);\n  const summarize = async (m) => {\n    setSummarizing(m.id);\n    try {\n      const r = await titan.api.call('/api/message', { content: `Summarize this email in 2 sentences:\\n\\nFrom: ${m.from}\\nSubject: ${m.subject}\\n\\n${m.body || m.snippet || ''}` });\n      setSummary(s => ({ ...s, [m.id]: r?.body?.content || r?.content || r?.body?.text || r?.text || JSON.stringify(r) }));\n    } catch (e) { setSummary(s => ({ ...s, [m.id]: 'Error: ' + (e?.message||e) })); }\n    finally { setSummarizing(null); }\n  };\n  return (\n    <div style={{padding:12,fontFamily:'system-ui',height:'100%',display:'flex',flexDirection:'column'}}>\n      <div style={{display:'flex',gap:8,alignItems:'center',marginBottom:8}}>\n        <div style={{fontSize:16,fontWeight:600,flex:1}}>\ud83d\udcec Unread ({mail.length})</div>\n        <button onClick={refresh} disabled={busy} style={{padding:'6px 12px',borderRadius:6,border:'1px solid #ccc',background:'#fff',cursor:busy?'wait':'pointer'}}>{busy?'\u2026':'\u21bb'}</button>\n      </div>\n      {error && <div style={{color:'#FF3B30',fontSize:12,marginBottom:6}}>{error}</div>}\n      <div style={{flex:1,overflow:'auto'}}>\n        {mail.length === 0 ? <div style={{textAlign:'center',color:'#888',padding:30}}>{error?'Email skill needs configuring.':'Inbox zero \u2728'}</div> :\n          mail.map((m,i) => (\n            <div key={m.id||i} style={{padding:10,marginBottom:6,background:'#f9f9f9',borderRadius:8}}>\n              <div style={{fontSize:12,color:'#666'}}>{m.from}</div>\n              <div style={{fontSize:13,fontWeight:600,margin:'2px 0'}}>{m.subject}</div>\n              <div style={{fontSize:11,color:'#888'}}>{m.snippet}</div>\n              {summary[m.id] && <div style={{marginTop:6,padding:8,background:'#FFF7E6',borderRadius:6,fontSize:12,color:'#444'}}>\u2728 {summary[m.id]}</div>}\n              <button onClick={()=>summarize(m)} disabled={summarizing===m.id} style={{marginTop:6,padding:'4px 10px',border:'1px solid #ddd',background:'#fff',borderRadius:4,fontSize:11,cursor:summarizing===m.id?'wait':'pointer'}}>{summarizing===m.id?'Summarizing\u2026':'\u2728 Summarize'}</button>\n            </div>\n          ))\n        }\n      </div>\n    </div>\n  );\n}\nrender(<EmailWatcher/>);",
  "placeholders": []
}
