@agenticmail/enterprise 0.5.53 → 0.5.54

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.
@@ -0,0 +1,47 @@
1
+ import {
2
+ AgentRuntime,
3
+ EmailChannel,
4
+ FollowUpScheduler,
5
+ SessionManager,
6
+ SubAgentManager,
7
+ ToolRegistry,
8
+ callLLM,
9
+ createAgentRuntime,
10
+ createNoopHooks,
11
+ createRuntimeHooks,
12
+ estimateMessageTokens,
13
+ estimateTokens,
14
+ executeTool,
15
+ runAgentLoop,
16
+ toolsToDefinitions
17
+ } from "./chunk-ZVCBP4IS.js";
18
+ import "./chunk-TYW5XTOW.js";
19
+ import "./chunk-JLSQOQ5L.js";
20
+ import {
21
+ PROVIDER_REGISTRY,
22
+ listAllProviders,
23
+ resolveApiKeyForProvider,
24
+ resolveProvider
25
+ } from "./chunk-67KZYSLU.js";
26
+ import "./chunk-KFQGP6VL.js";
27
+ export {
28
+ AgentRuntime,
29
+ EmailChannel,
30
+ FollowUpScheduler,
31
+ PROVIDER_REGISTRY,
32
+ SessionManager,
33
+ SubAgentManager,
34
+ ToolRegistry,
35
+ callLLM,
36
+ createAgentRuntime,
37
+ createNoopHooks,
38
+ createRuntimeHooks,
39
+ estimateMessageTokens,
40
+ estimateTokens,
41
+ executeTool,
42
+ listAllProviders,
43
+ resolveApiKeyForProvider,
44
+ resolveProvider,
45
+ runAgentLoop,
46
+ toolsToDefinitions
47
+ };
@@ -0,0 +1,12 @@
1
+ import {
2
+ createServer
3
+ } from "./chunk-CPYEURFL.js";
4
+ import "./chunk-3SMTCIR4.js";
5
+ import "./chunk-JLSQOQ5L.js";
6
+ import "./chunk-RO537U6H.js";
7
+ import "./chunk-DRXMYYKN.js";
8
+ import "./chunk-67KZYSLU.js";
9
+ import "./chunk-KFQGP6VL.js";
10
+ export {
11
+ createServer
12
+ };
@@ -0,0 +1,20 @@
1
+ import {
2
+ promptCompanyInfo,
3
+ promptDatabase,
4
+ promptDeployment,
5
+ promptDomain,
6
+ promptRegistration,
7
+ provision,
8
+ runSetupWizard
9
+ } from "./chunk-WUWGI4C2.js";
10
+ import "./chunk-M4PRT53C.js";
11
+ import "./chunk-KFQGP6VL.js";
12
+ export {
13
+ promptCompanyInfo,
14
+ promptDatabase,
15
+ promptDeployment,
16
+ promptDomain,
17
+ promptRegistration,
18
+ provision,
19
+ runSetupWizard
20
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/enterprise",
3
- "version": "0.5.53",
3
+ "version": "0.5.54",
4
4
  "description": "AgenticMail Enterprise — cloud-hosted AI agent identity, email, auth & compliance for organizations",
5
5
  "type": "module",
6
6
  "bin": {
@@ -3800,6 +3800,390 @@ var _tsCardTitle = { fontSize: 15, fontWeight: 600, marginBottom: 4, display: 'f
3800
3800
  var _tsCardDesc = { fontSize: 12, color: 'var(--text-muted)', marginBottom: 16 };
3801
3801
  var _tsToggleRow = { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 };
3802
3802
  var _tsGrid = { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 };
3803
+ // --- EmailSection -------------------------------------------------------
3804
+
3805
+ function EmailSection(props) {
3806
+ var agentId = props.agentId;
3807
+ var engineAgent = props.engineAgent || {};
3808
+ var reload = props.reload;
3809
+
3810
+ var app = useApp();
3811
+ var toast = app.toast;
3812
+
3813
+ var _config = useState(null);
3814
+ var emailConfig = _config[0]; var setEmailConfig = _config[1];
3815
+ var _loading = useState(true);
3816
+ var loading = _loading[0]; var setLoading = _loading[1];
3817
+ var _testing = useState(false);
3818
+ var testing = _testing[0]; var setTesting = _testing[1];
3819
+ var _testResult = useState(null);
3820
+ var testResult = _testResult[0]; var setTestResult = _testResult[1];
3821
+ var _saving = useState(false);
3822
+ var saving = _saving[0]; var setSaving = _saving[1];
3823
+ var _showOauthHelp = useState(false);
3824
+ var showOauthHelp = _showOauthHelp[0]; var setShowOauthHelp = _showOauthHelp[1];
3825
+
3826
+ // Form state
3827
+ var _form = useState({
3828
+ provider: 'imap',
3829
+ preset: '',
3830
+ email: '',
3831
+ password: '',
3832
+ imapHost: '',
3833
+ imapPort: 993,
3834
+ smtpHost: '',
3835
+ smtpPort: 587,
3836
+ oauthClientId: '',
3837
+ oauthClientSecret: '',
3838
+ oauthTenantId: 'common',
3839
+ });
3840
+ var form = _form[0]; var setForm = _form[1];
3841
+
3842
+ function set(key, val) {
3843
+ setForm(function(prev) { var n = Object.assign({}, prev); n[key] = val; return n; });
3844
+ }
3845
+
3846
+ // Load current config
3847
+ function loadConfig() {
3848
+ setLoading(true);
3849
+ engineCall('/bridge/agents/' + agentId + '/email-config')
3850
+ .then(function(d) {
3851
+ setEmailConfig(d);
3852
+ if (d.configured) {
3853
+ setForm(function(prev) { return Object.assign({}, prev, {
3854
+ provider: d.provider || 'imap',
3855
+ email: d.email || '',
3856
+ imapHost: d.imapHost || '',
3857
+ imapPort: d.imapPort || 993,
3858
+ smtpHost: d.smtpHost || '',
3859
+ smtpPort: d.smtpPort || 587,
3860
+ oauthClientId: d.oauthClientId || '',
3861
+ oauthTenantId: d.oauthTenantId || 'common',
3862
+ }); });
3863
+ } else {
3864
+ // Pre-fill email from agent identity
3865
+ var identity = (engineAgent.config || {}).identity || {};
3866
+ var agentEmail = identity.email || (engineAgent.config || {}).email || '';
3867
+ if (agentEmail && agentEmail.indexOf('@agenticmail.local') === -1) {
3868
+ set('email', agentEmail);
3869
+ }
3870
+ }
3871
+ setLoading(false);
3872
+ })
3873
+ .catch(function() { setLoading(false); });
3874
+ }
3875
+
3876
+ useEffect(function() { loadConfig(); }, [agentId]);
3877
+
3878
+ // Preset changed → auto-fill hosts
3879
+ var PRESETS = {
3880
+ microsoft365: { label: 'Microsoft 365 / Outlook', imapHost: 'outlook.office365.com', imapPort: 993, smtpHost: 'smtp.office365.com', smtpPort: 587 },
3881
+ gmail: { label: 'Google Workspace / Gmail', imapHost: 'imap.gmail.com', imapPort: 993, smtpHost: 'smtp.gmail.com', smtpPort: 587 },
3882
+ yahoo: { label: 'Yahoo Mail', imapHost: 'imap.mail.yahoo.com', imapPort: 993, smtpHost: 'smtp.mail.yahoo.com', smtpPort: 465 },
3883
+ zoho: { label: 'Zoho Mail', imapHost: 'imap.zoho.com', imapPort: 993, smtpHost: 'smtp.zoho.com', smtpPort: 587 },
3884
+ fastmail: { label: 'Fastmail', imapHost: 'imap.fastmail.com', imapPort: 993, smtpHost: 'smtp.fastmail.com', smtpPort: 587 },
3885
+ custom: { label: 'Custom IMAP/SMTP', imapHost: '', imapPort: 993, smtpHost: '', smtpPort: 587 },
3886
+ };
3887
+
3888
+ function applyPreset(key) {
3889
+ var p = PRESETS[key];
3890
+ if (p) {
3891
+ setForm(function(prev) { return Object.assign({}, prev, { preset: key, imapHost: p.imapHost, imapPort: p.imapPort, smtpHost: p.smtpHost, smtpPort: p.smtpPort }); });
3892
+ }
3893
+ }
3894
+
3895
+ // Save
3896
+ async function handleSave() {
3897
+ setSaving(true);
3898
+ try {
3899
+ var body = { provider: form.provider, email: form.email };
3900
+ if (form.provider === 'imap') {
3901
+ Object.assign(body, {
3902
+ password: form.password || undefined,
3903
+ preset: form.preset !== 'custom' ? form.preset : undefined,
3904
+ imapHost: form.imapHost,
3905
+ imapPort: form.imapPort,
3906
+ smtpHost: form.smtpHost,
3907
+ smtpPort: form.smtpPort,
3908
+ });
3909
+ } else if (form.provider === 'microsoft') {
3910
+ var baseUrl = window.location.origin;
3911
+ Object.assign(body, {
3912
+ oauthClientId: form.oauthClientId,
3913
+ oauthClientSecret: form.oauthClientSecret,
3914
+ oauthTenantId: form.oauthTenantId,
3915
+ oauthRedirectUri: baseUrl + '/oauth/callback',
3916
+ });
3917
+ } else if (form.provider === 'google') {
3918
+ var gBaseUrl = window.location.origin;
3919
+ Object.assign(body, {
3920
+ oauthClientId: form.oauthClientId,
3921
+ oauthClientSecret: form.oauthClientSecret,
3922
+ oauthRedirectUri: gBaseUrl + '/oauth/callback',
3923
+ });
3924
+ }
3925
+
3926
+ var result = await engineCall('/bridge/agents/' + agentId + '/email-config', {
3927
+ method: 'PUT',
3928
+ body: JSON.stringify(body),
3929
+ });
3930
+
3931
+ if (result.emailConfig && result.emailConfig.oauthAuthUrl) {
3932
+ toast('OAuth configured — click "Authorize" to complete setup', 'info');
3933
+ } else {
3934
+ toast('Email configuration saved', 'success');
3935
+ }
3936
+ loadConfig();
3937
+ if (reload) reload();
3938
+ } catch (err) {
3939
+ toast(err.message, 'error');
3940
+ }
3941
+ setSaving(false);
3942
+ }
3943
+
3944
+ // Test connection
3945
+ async function handleTest() {
3946
+ setTesting(true);
3947
+ setTestResult(null);
3948
+ try {
3949
+ var result = await engineCall('/bridge/agents/' + agentId + '/email-config/test', { method: 'POST' });
3950
+ setTestResult(result);
3951
+ if (result.success) toast('Connection successful!', 'success');
3952
+ else toast('Connection failed: ' + (result.error || 'Unknown error'), 'error');
3953
+ } catch (err) {
3954
+ setTestResult({ success: false, error: err.message });
3955
+ toast('Test failed: ' + err.message, 'error');
3956
+ }
3957
+ setTesting(false);
3958
+ }
3959
+
3960
+ // Disconnect
3961
+ async function handleDisconnect() {
3962
+ try {
3963
+ await engineCall('/bridge/agents/' + agentId + '/email-config', { method: 'DELETE' });
3964
+ toast('Email disconnected', 'success');
3965
+ setEmailConfig(null);
3966
+ setTestResult(null);
3967
+ loadConfig();
3968
+ if (reload) reload();
3969
+ } catch (err) {
3970
+ toast(err.message, 'error');
3971
+ }
3972
+ }
3973
+
3974
+ // Open OAuth window
3975
+ function openOAuth() {
3976
+ if (emailConfig && emailConfig.oauthAuthUrl) {
3977
+ window.open(emailConfig.oauthAuthUrl, '_blank', 'width=600,height=700');
3978
+ }
3979
+ }
3980
+
3981
+ if (loading) return h('div', { className: 'card', style: { padding: 40, textAlign: 'center' } }, 'Loading email config...');
3982
+
3983
+ var statusBadge = !emailConfig || !emailConfig.configured
3984
+ ? h('span', { className: 'badge badge-neutral' }, 'Not Connected')
3985
+ : emailConfig.status === 'connected'
3986
+ ? h('span', { className: 'badge badge-success' }, 'Connected')
3987
+ : emailConfig.status === 'configured'
3988
+ ? h('span', { className: 'badge badge-info' }, 'Configured')
3989
+ : emailConfig.status === 'awaiting_oauth'
3990
+ ? h('span', { className: 'badge badge-warning' }, 'Awaiting Authorization')
3991
+ : emailConfig.status === 'error'
3992
+ ? h('span', { className: 'badge badge-danger' }, 'Error')
3993
+ : h('span', { className: 'badge badge-neutral' }, emailConfig.status || 'Unknown');
3994
+
3995
+ var labelStyle = { display: 'block', fontSize: 12, fontWeight: 600, marginBottom: 4, color: 'var(--text-secondary)' };
3996
+ var inputStyle = { width: '100%', padding: '8px 10px', borderRadius: 'var(--radius)', border: '1px solid var(--border)', background: 'var(--bg-primary)', fontSize: 13, fontFamily: 'inherit' };
3997
+ var helpStyle = { fontSize: 11, color: 'var(--text-muted)', margin: '4px 0 0' };
3998
+
3999
+ return h('div', { className: 'card' },
4000
+ h('div', { className: 'card-header', style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' } },
4001
+ h('div', null,
4002
+ h('h3', { className: 'card-title' }, 'Email Connection'),
4003
+ h('p', { style: { fontSize: 12, color: 'var(--text-muted)', margin: '2px 0 0' } }, 'Connect this agent to an email account so it can send and receive emails.')
4004
+ ),
4005
+ statusBadge
4006
+ ),
4007
+ h('div', { className: 'card-body' },
4008
+
4009
+ // ─── Provider Selection ─────────────────────────
4010
+ h('div', { style: { marginBottom: 20 } },
4011
+ h('label', { style: labelStyle }, 'Connection Method'),
4012
+ h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10 } },
4013
+ [
4014
+ { id: 'imap', label: 'Email + Password', desc: 'IMAP/SMTP — works with any email provider', icon: '📧' },
4015
+ { id: 'microsoft', label: 'Microsoft OAuth', desc: 'Azure AD / Entra ID — for M365 orgs', icon: '🏢' },
4016
+ { id: 'google', label: 'Google OAuth', desc: 'Google Workspace — for GWS orgs', icon: '🔵' },
4017
+ ].map(function(m) {
4018
+ var selected = form.provider === m.id;
4019
+ return h('div', {
4020
+ key: m.id,
4021
+ onClick: function() { set('provider', m.id); },
4022
+ style: {
4023
+ padding: '14px 16px', borderRadius: 'var(--radius-lg)',
4024
+ border: selected ? '2px solid var(--accent)' : '1px solid var(--border)',
4025
+ background: selected ? 'var(--accent-soft)' : 'var(--bg-secondary)',
4026
+ cursor: 'pointer', transition: 'all 0.15s',
4027
+ }
4028
+ },
4029
+ h('div', { style: { fontSize: 20, marginBottom: 4 } }, m.icon),
4030
+ h('div', { style: { fontWeight: 600, fontSize: 13, marginBottom: 2 } }, m.label),
4031
+ h('div', { style: { fontSize: 11, color: 'var(--text-muted)' } }, m.desc)
4032
+ );
4033
+ })
4034
+ )
4035
+ ),
4036
+
4037
+ // ─── IMAP/SMTP Config ───────────────────────────
4038
+ form.provider === 'imap' && h(Fragment, null,
4039
+ h('div', { style: { marginBottom: 16 } },
4040
+ h('label', { style: labelStyle }, 'Email Provider'),
4041
+ h('select', { style: inputStyle, value: form.preset, onChange: function(e) { applyPreset(e.target.value); } },
4042
+ h('option', { value: '' }, '-- Select your email provider --'),
4043
+ Object.entries(PRESETS).map(function(entry) {
4044
+ return h('option', { key: entry[0], value: entry[0] }, entry[1].label);
4045
+ })
4046
+ )
4047
+ ),
4048
+
4049
+ h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 16 } },
4050
+ h('div', null,
4051
+ h('label', { style: labelStyle }, 'Email Address *'),
4052
+ h('input', { style: inputStyle, type: 'email', value: form.email, placeholder: 'agent@company.com', onChange: function(e) { set('email', e.target.value); } }),
4053
+ h('p', { style: helpStyle }, 'The email address created for this agent in your email system')
4054
+ ),
4055
+ h('div', null,
4056
+ h('label', { style: labelStyle }, form.password ? 'App Password *' : 'App Password * (enter to set/update)'),
4057
+ h('input', { style: inputStyle, type: 'password', value: form.password, placeholder: emailConfig && emailConfig.configured ? '•••••••• (leave blank to keep current)' : 'Enter app password', onChange: function(e) { set('password', e.target.value); } }),
4058
+ h('p', { style: helpStyle }, 'For Microsoft 365: ', h('a', { href: 'https://mysignins.microsoft.com/security-info', target: '_blank', style: { color: 'var(--accent)' } }, 'Create app password'), ' | For Gmail: ', h('a', { href: 'https://myaccount.google.com/apppasswords', target: '_blank', style: { color: 'var(--accent)' } }, 'Create app password'))
4059
+ )
4060
+ ),
4061
+
4062
+ // Server settings (auto-filled by preset, expandable for custom)
4063
+ (form.preset === 'custom' || form.preset === '') && h('div', { style: { display: 'grid', gridTemplateColumns: '1fr auto 1fr auto', gap: 12, marginBottom: 16 } },
4064
+ h('div', null,
4065
+ h('label', { style: labelStyle }, 'IMAP Host *'),
4066
+ h('input', { style: inputStyle, value: form.imapHost, placeholder: 'imap.example.com', onChange: function(e) { set('imapHost', e.target.value); } })
4067
+ ),
4068
+ h('div', { style: { width: 80 } },
4069
+ h('label', { style: labelStyle }, 'Port'),
4070
+ h('input', { style: inputStyle, type: 'number', value: form.imapPort, onChange: function(e) { set('imapPort', parseInt(e.target.value) || 993); } })
4071
+ ),
4072
+ h('div', null,
4073
+ h('label', { style: labelStyle }, 'SMTP Host *'),
4074
+ h('input', { style: inputStyle, value: form.smtpHost, placeholder: 'smtp.example.com', onChange: function(e) { set('smtpHost', e.target.value); } })
4075
+ ),
4076
+ h('div', { style: { width: 80 } },
4077
+ h('label', { style: labelStyle }, 'Port'),
4078
+ h('input', { style: inputStyle, type: 'number', value: form.smtpPort, onChange: function(e) { set('smtpPort', parseInt(e.target.value) || 587); } })
4079
+ )
4080
+ ),
4081
+
4082
+ form.preset && form.preset !== 'custom' && form.preset !== '' && h('div', { style: { padding: '8px 12px', background: 'var(--bg-secondary)', borderRadius: 'var(--radius)', fontSize: 12, color: 'var(--text-muted)', marginBottom: 16 } },
4083
+ 'Server: ', h('strong', null, form.imapHost), ':', form.imapPort, ' (IMAP) / ', h('strong', null, form.smtpHost), ':', form.smtpPort, ' (SMTP)',
4084
+ ' — ', h('a', { href: '#', onClick: function(e) { e.preventDefault(); set('preset', 'custom'); }, style: { color: 'var(--accent)' } }, 'Edit manually')
4085
+ ),
4086
+
4087
+ h('div', { style: { padding: '12px 16px', background: 'var(--info-soft)', borderRadius: 'var(--radius)', fontSize: 12, color: 'var(--info)', marginBottom: 16 } },
4088
+ h('strong', null, 'How to set up:'), h('br'),
4089
+ '1. Create an email account for this agent in your email system (e.g., Microsoft 365 Admin Center or Google Admin Console)', h('br'),
4090
+ '2. Create an app password for that account (regular passwords may not work with 2FA enabled)', h('br'),
4091
+ '3. Enter the email and app password above, select your provider, and hit Save', h('br'),
4092
+ '4. Click "Test Connection" to verify everything works'
4093
+ )
4094
+ ),
4095
+
4096
+ // ─── Microsoft OAuth Config ─────────────────────
4097
+ form.provider === 'microsoft' && h(Fragment, null,
4098
+ h('div', { style: { padding: '12px 16px', background: 'var(--info-soft)', borderRadius: 'var(--radius)', fontSize: 12, color: 'var(--info)', marginBottom: 16 } },
4099
+ h('strong', null, 'Setup Instructions:'), h('br'),
4100
+ '1. Go to ', h('a', { href: 'https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade', target: '_blank', style: { color: 'var(--accent)' } }, 'Azure Portal → App Registrations'), h('br'),
4101
+ '2. Click "New Registration" → name it (e.g., "AgenticMail Agent") → set redirect URI to: ', h('code', { style: { background: 'var(--bg-tertiary)', padding: '1px 4px', borderRadius: 3 } }, window.location.origin + '/oauth/callback'), h('br'),
4102
+ '3. Under "Certificates & Secrets" → create a Client Secret', h('br'),
4103
+ '4. Under "API Permissions" → add Microsoft Graph: Mail.ReadWrite, Mail.Send, offline_access', h('br'),
4104
+ '5. Copy the Application (client) ID and Client Secret below'
4105
+ ),
4106
+
4107
+ h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 16 } },
4108
+ h('div', null,
4109
+ h('label', { style: labelStyle }, 'Application (Client) ID *'),
4110
+ h('input', { style: inputStyle, value: form.oauthClientId, placeholder: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', onChange: function(e) { set('oauthClientId', e.target.value); } })
4111
+ ),
4112
+ h('div', null,
4113
+ h('label', { style: labelStyle }, 'Client Secret *'),
4114
+ h('input', { style: inputStyle, type: 'password', value: form.oauthClientSecret, placeholder: 'Enter client secret', onChange: function(e) { set('oauthClientSecret', e.target.value); } })
4115
+ )
4116
+ ),
4117
+ h('div', { style: { marginBottom: 16 } },
4118
+ h('label', { style: labelStyle }, 'Tenant ID'),
4119
+ h('input', { style: Object.assign({}, inputStyle, { maxWidth: 400 }), value: form.oauthTenantId, placeholder: 'common (or your tenant ID)', onChange: function(e) { set('oauthTenantId', e.target.value); } }),
4120
+ h('p', { style: helpStyle }, 'Use "common" for multi-tenant, or your org\'s tenant ID for single-tenant apps')
4121
+ ),
4122
+
4123
+ emailConfig && emailConfig.status === 'awaiting_oauth' && h('div', { style: { padding: '12px 16px', background: 'var(--warning-soft)', borderRadius: 'var(--radius)', marginBottom: 16 } },
4124
+ h('div', { style: { fontWeight: 600, marginBottom: 4, fontSize: 13 } }, 'Authorization Required'),
4125
+ h('p', { style: { fontSize: 12, margin: '0 0 8px', color: 'var(--text-secondary)' } }, 'Click the button below to sign in with the agent\'s Microsoft account and grant email permissions.'),
4126
+ h('button', { className: 'btn btn-primary btn-sm', onClick: openOAuth }, 'Authorize with Microsoft')
4127
+ )
4128
+ ),
4129
+
4130
+ // ─── Google OAuth Config ────────────────────────
4131
+ form.provider === 'google' && h(Fragment, null,
4132
+ h('div', { style: { padding: '12px 16px', background: 'var(--info-soft)', borderRadius: 'var(--radius)', fontSize: 12, color: 'var(--info)', marginBottom: 16 } },
4133
+ h('strong', null, 'Setup Instructions:'), h('br'),
4134
+ '1. Go to ', h('a', { href: 'https://console.cloud.google.com/apis/credentials', target: '_blank', style: { color: 'var(--accent)' } }, 'Google Cloud Console → Credentials'), h('br'),
4135
+ '2. Create an OAuth 2.0 Client ID (Web application) → add redirect URI: ', h('code', { style: { background: 'var(--bg-tertiary)', padding: '1px 4px', borderRadius: 3 } }, window.location.origin + '/oauth/callback'), h('br'),
4136
+ '3. Enable the Gmail API in your project', h('br'),
4137
+ '4. Copy the Client ID and Client Secret below'
4138
+ ),
4139
+
4140
+ h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 16 } },
4141
+ h('div', null,
4142
+ h('label', { style: labelStyle }, 'OAuth Client ID *'),
4143
+ h('input', { style: inputStyle, value: form.oauthClientId, placeholder: 'xxxx.apps.googleusercontent.com', onChange: function(e) { set('oauthClientId', e.target.value); } })
4144
+ ),
4145
+ h('div', null,
4146
+ h('label', { style: labelStyle }, 'Client Secret *'),
4147
+ h('input', { style: inputStyle, type: 'password', value: form.oauthClientSecret, placeholder: 'Enter client secret', onChange: function(e) { set('oauthClientSecret', e.target.value); } })
4148
+ )
4149
+ ),
4150
+
4151
+ emailConfig && emailConfig.status === 'awaiting_oauth' && h('div', { style: { padding: '12px 16px', background: 'var(--warning-soft)', borderRadius: 'var(--radius)', marginBottom: 16 } },
4152
+ h('div', { style: { fontWeight: 600, marginBottom: 4, fontSize: 13 } }, 'Authorization Required'),
4153
+ h('p', { style: { fontSize: 12, margin: '0 0 8px', color: 'var(--text-secondary)' } }, 'Click the button below to sign in with the agent\'s Google account and grant Gmail permissions.'),
4154
+ h('button', { className: 'btn btn-primary btn-sm', onClick: openOAuth }, 'Authorize with Google')
4155
+ )
4156
+ ),
4157
+
4158
+ // ─── Test Result ─────────────────────────────────
4159
+ testResult && h('div', { style: { padding: '12px 16px', borderRadius: 'var(--radius)', marginBottom: 16, background: testResult.success ? 'var(--success-soft)' : 'var(--danger-soft)' } },
4160
+ testResult.success
4161
+ ? h(Fragment, null,
4162
+ h('div', { style: { fontWeight: 600, color: 'var(--success)', marginBottom: 4, fontSize: 13 } }, 'Connection Successful'),
4163
+ testResult.inbox && h('div', { style: { fontSize: 12, color: 'var(--text-secondary)' } }, 'Inbox: ', testResult.inbox.total, ' messages (', testResult.inbox.unread, ' unread)'),
4164
+ testResult.email && h('div', { style: { fontSize: 12, color: 'var(--text-secondary)' } }, 'Email: ', testResult.email)
4165
+ )
4166
+ : h(Fragment, null,
4167
+ h('div', { style: { fontWeight: 600, color: 'var(--danger)', marginBottom: 4, fontSize: 13 } }, 'Connection Failed'),
4168
+ h('div', { style: { fontSize: 12, color: 'var(--text-secondary)' } }, testResult.error || 'Unknown error')
4169
+ )
4170
+ ),
4171
+
4172
+ // ─── Error display ────────────────────────────────
4173
+ emailConfig && emailConfig.lastError && h('div', { style: { padding: '8px 12px', background: 'var(--danger-soft)', borderRadius: 'var(--radius)', fontSize: 12, color: 'var(--danger)', marginBottom: 16 } },
4174
+ h('strong', null, 'Last Error: '), emailConfig.lastError
4175
+ ),
4176
+
4177
+ // ─── Actions ──────────────────────────────────────
4178
+ h('div', { style: { display: 'flex', gap: 8, borderTop: '1px solid var(--border)', paddingTop: 16 } },
4179
+ h('button', { className: 'btn btn-primary', disabled: saving, onClick: handleSave }, saving ? 'Saving...' : 'Save Configuration'),
4180
+ emailConfig && emailConfig.configured && h('button', { className: 'btn btn-secondary', disabled: testing, onClick: handleTest }, testing ? 'Testing...' : 'Test Connection'),
4181
+ emailConfig && emailConfig.configured && h('button', { className: 'btn btn-danger btn-ghost', onClick: function() { if (confirm('Disconnect email? The agent will no longer be able to send/receive.')) handleDisconnect(); } }, 'Disconnect')
4182
+ )
4183
+ )
4184
+ );
4185
+ }
4186
+
3803
4187
  var _tsSectionTitle = { fontSize: 14, fontWeight: 600, color: 'var(--text-secondary)', marginBottom: 12, marginTop: 8 };
3804
4188
 
3805
4189
  function TSToggle(props) {
@@ -4166,8 +4550,8 @@ function AgentDetailPage(props) {
4166
4550
  var _agents = useState([]);
4167
4551
  var agents = _agents[0]; var setAgents = _agents[1];
4168
4552
 
4169
- var TABS = ['overview', 'personal', 'configuration', 'manager', 'skills', 'permissions', 'activity', 'communication', 'workforce', 'memory', 'guardrails', 'budget', 'tool-security', 'deployment'];
4170
- var TAB_LABELS = { 'tool-security': 'Tool Security', 'manager': 'Manager & Catch-Up' };
4553
+ var TABS = ['overview', 'personal', 'email', 'configuration', 'manager', 'skills', 'permissions', 'activity', 'communication', 'workforce', 'memory', 'guardrails', 'budget', 'tool-security', 'deployment'];
4554
+ var TAB_LABELS = { 'tool-security': 'Tool Security', 'manager': 'Manager & Catch-Up', 'email': 'Email' };
4171
4555
 
4172
4556
  var load = function() {
4173
4557
  setLoading(true);
@@ -4288,6 +4672,7 @@ function AgentDetailPage(props) {
4288
4672
  // ─── Tab Content ────────────────────────────────────
4289
4673
  tab === 'overview' && h(OverviewSection, { agentId: agentId, agent: agent, engineAgent: engineAgent, profile: profile, reload: load, agents: agents, onBack: onBack }),
4290
4674
  tab === 'personal' && h(PersonalDetailsSection, { agentId: agentId, agent: agent, engineAgent: engineAgent, reload: load }),
4675
+ tab === 'email' && h(EmailSection, { agentId: agentId, engineAgent: engineAgent, reload: load }),
4291
4676
  tab === 'configuration' && h(ConfigurationSection, { agentId: agentId, engineAgent: engineAgent, reload: load }),
4292
4677
  tab === 'manager' && h(ManagerCatchUpSection, { agentId: agentId, engineAgent: engineAgent, agents: agents, reload: load }),
4293
4678
  tab === 'skills' && h(SkillsSection, { agentId: agentId, engineAgent: engineAgent, reload: load }),
@@ -764,7 +764,7 @@ export function CreateAgentWizard({ onClose, onCreated, toast }) {
764
764
  h('div', { className: 'form-group' },
765
765
  h('label', { className: 'form-label' }, 'Email Address'),
766
766
  h('input', { className: 'input', value: form.email, onChange: e => set('email', e.target.value), placeholder: form.name ? form.name.toLowerCase().replace(/\s+/g, '.') + '@yourdomain.com' : 'first.last@yourdomain.com' }),
767
- h('p', { className: 'form-help' }, 'Leave blank for auto-generated from their name')
767
+ h('p', { className: 'form-help' }, 'The email address created for this agent in your email system. Configure credentials in the Email tab after creation.')
768
768
  )
769
769
  ),
770
770
  h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 } },