@agenticmail/enterprise 0.5.71 → 0.5.73

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,97 @@
1
+ import {
2
+ DomainLock
3
+ } from "./chunk-UPU23ZRG.js";
4
+ import "./chunk-KFQGP6VL.js";
5
+
6
+ // src/domain-lock/cli-recover.ts
7
+ function getFlag(args, name) {
8
+ const idx = args.indexOf(name);
9
+ if (idx !== -1 && args[idx + 1]) return args[idx + 1];
10
+ return void 0;
11
+ }
12
+ async function runRecover(args) {
13
+ const { default: inquirer } = await import("inquirer");
14
+ const { default: chalk } = await import("chalk");
15
+ const { default: ora } = await import("ora");
16
+ console.log("");
17
+ console.log(chalk.bold(" AgenticMail Enterprise \u2014 Domain Recovery"));
18
+ console.log(chalk.dim(" Recover your domain registration on a new machine."));
19
+ console.log("");
20
+ let domain = getFlag(args, "--domain");
21
+ if (!domain) {
22
+ const answer = await inquirer.prompt([{
23
+ type: "input",
24
+ name: "domain",
25
+ message: "Domain to recover:",
26
+ suffix: chalk.dim(" (e.g. agents.agenticmail.io)"),
27
+ validate: (v) => v.includes(".") || "Enter a valid domain"
28
+ }]);
29
+ domain = answer.domain;
30
+ }
31
+ let key = getFlag(args, "--key");
32
+ if (!key) {
33
+ const answer = await inquirer.prompt([{
34
+ type: "password",
35
+ name: "key",
36
+ message: "Deployment key:",
37
+ mask: "*",
38
+ validate: (v) => {
39
+ if (v.length !== 64) return "Deployment key should be 64 hex characters";
40
+ if (!/^[0-9a-fA-F]+$/.test(v)) return "Deployment key should be hexadecimal";
41
+ return true;
42
+ }
43
+ }]);
44
+ key = answer.key;
45
+ }
46
+ const spinner = ora("Contacting AgenticMail registry...").start();
47
+ const lock = new DomainLock();
48
+ const result = await lock.recover(domain, key);
49
+ if (!result.success) {
50
+ spinner.fail("Recovery failed");
51
+ console.log("");
52
+ console.error(chalk.red(` ${result.error}`));
53
+ console.log("");
54
+ process.exit(1);
55
+ }
56
+ spinner.succeed("Domain recovery initiated");
57
+ const { default: bcrypt } = await import("bcryptjs");
58
+ const keyHash = await bcrypt.hash(key, 12);
59
+ const dbPath = getFlag(args, "--db");
60
+ const dbType = getFlag(args, "--db-type") || "sqlite";
61
+ if (dbPath) {
62
+ try {
63
+ const spinnerDb = ora("Saving to local database...").start();
64
+ const { createAdapter } = await import("./factory-GT6SUZSQ.js");
65
+ const db = await createAdapter({ type: dbType, connectionString: dbPath });
66
+ await db.migrate();
67
+ await db.updateSettings({
68
+ domain,
69
+ deploymentKeyHash: keyHash,
70
+ domainRegistrationId: result.registrationId,
71
+ domainDnsChallenge: result.dnsChallenge,
72
+ domainRegisteredAt: (/* @__PURE__ */ new Date()).toISOString(),
73
+ domainStatus: "pending_dns"
74
+ });
75
+ spinnerDb.succeed("Local database updated");
76
+ await db.disconnect();
77
+ } catch (err) {
78
+ console.log(chalk.yellow(`
79
+ Could not update local DB: ${err.message}`));
80
+ console.log(chalk.dim(" You can manually update settings after setup."));
81
+ }
82
+ }
83
+ console.log("");
84
+ console.log(chalk.green.bold(" Domain recovery successful!"));
85
+ console.log("");
86
+ console.log(chalk.bold(" Update your DNS TXT record:"));
87
+ console.log("");
88
+ console.log(` ${chalk.bold("Host:")} ${chalk.cyan(`_agenticmail-verify.${domain}`)}`);
89
+ console.log(` ${chalk.bold("Type:")} ${chalk.cyan("TXT")}`);
90
+ console.log(` ${chalk.bold("Value:")} ${chalk.cyan(result.dnsChallenge)}`);
91
+ console.log("");
92
+ console.log(chalk.dim(" Then run: npx @agenticmail/enterprise verify-domain"));
93
+ console.log("");
94
+ }
95
+ export {
96
+ runRecover
97
+ };
@@ -0,0 +1,98 @@
1
+ import {
2
+ DomainLock
3
+ } from "./chunk-UPU23ZRG.js";
4
+ import "./chunk-KFQGP6VL.js";
5
+
6
+ // src/domain-lock/cli-verify.ts
7
+ function getFlag(args, name) {
8
+ const idx = args.indexOf(name);
9
+ if (idx !== -1 && args[idx + 1]) return args[idx + 1];
10
+ return void 0;
11
+ }
12
+ async function runVerifyDomain(args) {
13
+ const { default: chalk } = await import("chalk");
14
+ const { default: ora } = await import("ora");
15
+ console.log("");
16
+ console.log(chalk.bold(" AgenticMail Enterprise \u2014 Domain Verification"));
17
+ console.log("");
18
+ let domain = getFlag(args, "--domain");
19
+ let dnsChallenge;
20
+ let dbConnected = false;
21
+ let db = null;
22
+ if (!domain) {
23
+ const dbPath = getFlag(args, "--db");
24
+ const dbType = getFlag(args, "--db-type") || "sqlite";
25
+ if (dbPath) {
26
+ try {
27
+ const { createAdapter } = await import("./factory-GT6SUZSQ.js");
28
+ db = await createAdapter({ type: dbType, connectionString: dbPath });
29
+ await db.migrate();
30
+ const settings = await db.getSettings();
31
+ domain = settings?.domain;
32
+ dnsChallenge = settings?.domainDnsChallenge;
33
+ dbConnected = true;
34
+ } catch {
35
+ }
36
+ }
37
+ }
38
+ if (!domain) {
39
+ const { default: inquirer } = await import("inquirer");
40
+ const answer = await inquirer.prompt([{
41
+ type: "input",
42
+ name: "domain",
43
+ message: "Domain to verify:",
44
+ suffix: chalk.dim(" (e.g. agents.agenticmail.io)"),
45
+ validate: (v) => v.includes(".") || "Enter a valid domain"
46
+ }]);
47
+ domain = answer.domain;
48
+ }
49
+ const spinner = ora("Checking DNS verification...").start();
50
+ const lock = new DomainLock();
51
+ const result = await lock.checkVerification(domain);
52
+ if (!result.success) {
53
+ spinner.fail("Verification check failed");
54
+ console.log("");
55
+ console.error(chalk.red(` ${result.error}`));
56
+ console.log("");
57
+ if (db) await db.disconnect();
58
+ process.exit(1);
59
+ }
60
+ if (result.verified) {
61
+ spinner.succeed("Domain verified!");
62
+ if (dbConnected && db) {
63
+ try {
64
+ await db.updateSettings({
65
+ domainStatus: "verified",
66
+ domainVerifiedAt: (/* @__PURE__ */ new Date()).toISOString()
67
+ });
68
+ } catch {
69
+ }
70
+ }
71
+ console.log("");
72
+ console.log(chalk.green.bold(` ${domain} is verified and protected.`));
73
+ console.log(chalk.dim(" Your deployment domain is locked. No other instance can claim it."));
74
+ console.log("");
75
+ } else {
76
+ spinner.info("DNS record not found yet");
77
+ console.log("");
78
+ console.log(chalk.yellow(" The DNS TXT record has not been detected."));
79
+ console.log("");
80
+ console.log(chalk.bold(" Make sure this record exists:"));
81
+ console.log("");
82
+ console.log(` ${chalk.bold("Host:")} ${chalk.cyan(`_agenticmail-verify.${domain}`)}`);
83
+ console.log(` ${chalk.bold("Type:")} ${chalk.cyan("TXT")}`);
84
+ if (dnsChallenge) {
85
+ console.log(` ${chalk.bold("Value:")} ${chalk.cyan(dnsChallenge)}`);
86
+ } else {
87
+ console.log(` ${chalk.bold("Value:")} ${chalk.dim("(check your setup records or dashboard)")}`);
88
+ }
89
+ console.log("");
90
+ console.log(chalk.dim(" DNS changes can take up to 48 hours to propagate."));
91
+ console.log(chalk.dim(" Run this command again after adding the record."));
92
+ console.log("");
93
+ }
94
+ if (db) await db.disconnect();
95
+ }
96
+ export {
97
+ runVerifyDomain
98
+ };
package/dist/cli.js CHANGED
@@ -14,10 +14,10 @@ switch (command) {
14
14
  import("./cli-submit-skill-LDFJGSKO.js").then((m) => m.runSubmitSkill(args.slice(1))).catch(fatal);
15
15
  break;
16
16
  case "recover":
17
- import("./cli-recover-C72I57LB.js").then((m) => m.runRecover(args.slice(1))).catch(fatal);
17
+ import("./cli-recover-JYCMVLVL.js").then((m) => m.runRecover(args.slice(1))).catch(fatal);
18
18
  break;
19
19
  case "verify-domain":
20
- import("./cli-verify-HKS5O6Q2.js").then((m) => m.runVerifyDomain(args.slice(1))).catch(fatal);
20
+ import("./cli-verify-F7R5RO65.js").then((m) => m.runVerifyDomain(args.slice(1))).catch(fatal);
21
21
  break;
22
22
  case "--help":
23
23
  case "-h":
@@ -48,7 +48,7 @@ Skill Development:
48
48
  break;
49
49
  case "setup":
50
50
  default:
51
- import("./setup-N7RALR7Z.js").then((m) => m.runSetupWizard()).catch(fatal);
51
+ import("./setup-TPYVQULV.js").then((m) => m.runSetupWizard()).catch(fatal);
52
52
  break;
53
53
  }
54
54
  function fatal(err) {
@@ -3875,6 +3875,23 @@ function EmailSection(props) {
3875
3875
 
3876
3876
  useEffect(function() { loadConfig(); }, [agentId]);
3877
3877
 
3878
+ // Listen for OAuth popup completion
3879
+ useEffect(function() {
3880
+ function onMessage(e) {
3881
+ if (e.data && e.data.type === 'oauth-result') {
3882
+ if (e.data.status === 'success') {
3883
+ toast('Email connected successfully', 'success');
3884
+ } else {
3885
+ toast('OAuth failed: ' + (e.data.message || 'Unknown error'), 'error');
3886
+ }
3887
+ loadConfig();
3888
+ if (reload) reload();
3889
+ }
3890
+ }
3891
+ window.addEventListener('message', onMessage);
3892
+ return function() { window.removeEventListener('message', onMessage); };
3893
+ }, []);
3894
+
3878
3895
  // Preset changed → auto-fill hosts
3879
3896
  var PRESETS = {
3880
3897
  microsoft365: { label: 'Microsoft 365 / Outlook', imapHost: 'outlook.office365.com', imapPort: 993, smtpHost: 'smtp.office365.com', smtpPort: 587 },
@@ -3908,18 +3925,22 @@ function EmailSection(props) {
3908
3925
  });
3909
3926
  } else if (form.provider === 'microsoft') {
3910
3927
  var baseUrl = window.location.origin;
3928
+ var hasOrgMs = emailConfig && emailConfig.orgEmailConfig && emailConfig.orgEmailConfig.provider === 'microsoft';
3911
3929
  Object.assign(body, {
3912
- oauthClientId: form.oauthClientId,
3913
- oauthClientSecret: form.oauthClientSecret,
3930
+ oauthClientId: form.oauthClientId || undefined,
3931
+ oauthClientSecret: form.oauthClientSecret || undefined,
3914
3932
  oauthTenantId: form.oauthTenantId,
3915
3933
  oauthRedirectUri: baseUrl + '/api/engine/oauth/callback',
3934
+ useOrgConfig: hasOrgMs && !form.oauthClientId ? true : undefined,
3916
3935
  });
3917
3936
  } else if (form.provider === 'google') {
3918
3937
  var gBaseUrl = window.location.origin;
3938
+ var hasOrgG = emailConfig && emailConfig.orgEmailConfig && emailConfig.orgEmailConfig.provider === 'google';
3919
3939
  Object.assign(body, {
3920
- oauthClientId: form.oauthClientId,
3921
- oauthClientSecret: form.oauthClientSecret,
3940
+ oauthClientId: form.oauthClientId || undefined,
3941
+ oauthClientSecret: form.oauthClientSecret || undefined,
3922
3942
  oauthRedirectUri: gBaseUrl + '/api/engine/oauth/callback',
3943
+ useOrgConfig: hasOrgG && !form.oauthClientId ? true : undefined,
3923
3944
  });
3924
3945
  }
3925
3946
 
@@ -4006,6 +4027,15 @@ function EmailSection(props) {
4006
4027
  ),
4007
4028
  h('div', { className: 'card-body' },
4008
4029
 
4030
+ // ─── Org Email Config Banner ──────────────────────
4031
+ emailConfig && emailConfig.orgEmailConfig && h('div', { style: { padding: '12px 16px', background: 'var(--success-soft)', borderRadius: 'var(--radius)', marginBottom: 16, display: 'flex', alignItems: 'center', gap: 10 } },
4032
+ h('span', { style: { fontSize: 18 } }, '\u2705'),
4033
+ h('div', null,
4034
+ h('div', { style: { fontSize: 13, fontWeight: 600 } }, 'Your organization has configured ', emailConfig.orgEmailConfig.label || emailConfig.orgEmailConfig.provider),
4035
+ h('div', { style: { fontSize: 12, color: 'var(--text-muted)' } }, 'Select ', emailConfig.orgEmailConfig.provider === 'google' ? 'Google OAuth' : 'Microsoft OAuth', ' below — Client ID and Secret will be inherited automatically.')
4036
+ )
4037
+ ),
4038
+
4009
4039
  // ─── Provider Selection ─────────────────────────
4010
4040
  h('div', { style: { marginBottom: 20 } },
4011
4041
  h('label', { style: labelStyle }, 'Connection Method'),
@@ -4128,16 +4158,24 @@ function EmailSection(props) {
4128
4158
  ),
4129
4159
 
4130
4160
  // ─── 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 + '/api/engine/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
- ),
4161
+ form.provider === 'google' && (function() {
4162
+ var hasOrg = emailConfig && emailConfig.orgEmailConfig && emailConfig.orgEmailConfig.provider === 'google';
4163
+ return h(Fragment, null,
4164
+ hasOrg
4165
+ ? h('div', { style: { padding: '12px 16px', background: 'var(--success-soft)', borderRadius: 'var(--radius)', fontSize: 12, marginBottom: 16 } },
4166
+ h('strong', null, '\u2705 Using organization Google Workspace credentials'), h('br'),
4167
+ 'Client ID: ', h('code', { style: { fontSize: 11 } }, emailConfig.orgEmailConfig.oauthClientId), h('br'),
4168
+ h('span', { style: { color: 'var(--text-muted)' } }, 'Just click "Save Configuration" then authorize with the agent\'s Google account.')
4169
+ )
4170
+ : h('div', { style: { padding: '12px 16px', background: 'var(--info-soft)', borderRadius: 'var(--radius)', fontSize: 12, color: 'var(--info)', marginBottom: 16 } },
4171
+ h('strong', null, 'Setup Instructions:'), h('br'),
4172
+ '1. Go to ', h('a', { href: 'https://console.cloud.google.com/apis/credentials', target: '_blank', style: { color: 'var(--accent)' } }, 'Google Cloud Console \u2192 Credentials'), h('br'),
4173
+ '2. Create an OAuth 2.0 Client ID (Web application) \u2192 add redirect URI: ', h('code', { style: { background: 'var(--bg-tertiary)', padding: '1px 4px', borderRadius: 3 } }, window.location.origin + '/api/engine/oauth/callback'), h('br'),
4174
+ '3. Enable the Gmail API in your project', h('br'),
4175
+ '4. Copy the Client ID and Client Secret below'
4176
+ ),
4139
4177
 
4140
- h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 16 } },
4178
+ !hasOrg && h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 16 } },
4141
4179
  h('div', null,
4142
4180
  h('label', { style: labelStyle }, 'OAuth Client ID *'),
4143
4181
  h('input', { style: inputStyle, value: form.oauthClientId, placeholder: 'xxxx.apps.googleusercontent.com', onChange: function(e) { set('oauthClientId', e.target.value); } })
@@ -4153,7 +4191,7 @@ function EmailSection(props) {
4153
4191
  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
4192
  h('button', { className: 'btn btn-primary btn-sm', onClick: openOAuth }, 'Authorize with Google')
4155
4193
  )
4156
- ),
4194
+ ); })(),
4157
4195
 
4158
4196
  // ─── Test Result ─────────────────────────────────
4159
4197
  testResult && h('div', { style: { padding: '12px 16px', borderRadius: 'var(--radius)', marginBottom: 16, background: testResult.success ? 'var(--success-soft)' : 'var(--danger-soft)' } },
@@ -53,6 +53,12 @@ export function SettingsPage() {
53
53
  var _apiKeyInput = useState('');
54
54
  var apiKeyInput = _apiKeyInput[0]; var setApiKeyInput = _apiKeyInput[1];
55
55
 
56
+ // Org Email Config
57
+ var _orgEmail = useState({ configured: false, provider: '', oauthClientId: '', oauthClientSecret: '', oauthTenantId: 'common', label: '' });
58
+ var orgEmail = _orgEmail[0]; var setOrgEmail = _orgEmail[1];
59
+ var _orgEmailSaving = useState(false);
60
+ var orgEmailSaving = _orgEmailSaving[0]; var setOrgEmailSaving = _orgEmailSaving[1];
61
+
56
62
  useEffect(() => {
57
63
  apiCall('/settings').then(d => { const s = d.settings || d || {}; setSettings(s); if (s.primaryColor) applyBrandColor(s.primaryColor); if (s.orgId) setOrgId(s.orgId); }).catch(() => {});
58
64
  apiCall('/api-keys').then(d => setApiKeys(d.keys || [])).catch(() => {});
@@ -66,6 +72,9 @@ export function SettingsPage() {
66
72
  }));
67
73
  }).catch(() => {});
68
74
  engineCall('/deploy-credentials?orgId=' + getOrgId()).then(d => setDeployCreds(d.credentials || [])).catch(() => {});
75
+ apiCall('/settings/org-email').then(d => {
76
+ if (d.configured) setOrgEmail({ configured: true, provider: d.provider, oauthClientId: d.oauthClientId || '', oauthClientSecret: '', oauthTenantId: d.oauthTenantId || 'common', label: d.label || '' });
77
+ }).catch(() => {});
69
78
  apiCall('/settings/tool-security').then(d => {
70
79
  var cfg = d.toolSecurityConfig || {};
71
80
  setToolSec({
@@ -108,6 +117,29 @@ export function SettingsPage() {
108
117
  try { await apiCall('/settings', { method: 'PATCH', body: JSON.stringify({ [key]: value }) }); toast('Settings saved', 'success'); } catch (e) { toast(e.message, 'error'); }
109
118
  };
110
119
 
120
+ const saveOrgEmail = async () => {
121
+ if (!orgEmail.provider) { toast('Select a provider', 'error'); return; }
122
+ if (!orgEmail.oauthClientId) { toast('Enter Client ID', 'error'); return; }
123
+ if (!orgEmail.oauthClientSecret) { toast('Enter Client Secret', 'error'); return; }
124
+ setOrgEmailSaving(true);
125
+ try {
126
+ var result = await apiCall('/settings/org-email', { method: 'PUT', body: JSON.stringify({ provider: orgEmail.provider, oauthClientId: orgEmail.oauthClientId, oauthClientSecret: orgEmail.oauthClientSecret, oauthTenantId: orgEmail.oauthTenantId }) });
127
+ setOrgEmail(function(prev) { return Object.assign({}, prev, { configured: true, label: result.orgEmailConfig?.label || prev.label, oauthClientSecret: '' }); });
128
+ toast('Organization email configuration saved', 'success');
129
+ } catch (e) { toast(e.message, 'error'); }
130
+ setOrgEmailSaving(false);
131
+ };
132
+
133
+ const removeOrgEmail = async () => {
134
+ var ok = await showConfirm({ title: 'Remove Organization Email', message: 'Agents using this org-level config will need to be individually configured.', danger: true, confirmText: 'Remove' });
135
+ if (!ok) return;
136
+ try {
137
+ await apiCall('/settings/org-email', { method: 'DELETE' });
138
+ setOrgEmail({ configured: false, provider: '', oauthClientId: '', oauthClientSecret: '', oauthTenantId: 'common', label: '' });
139
+ toast('Organization email configuration removed', 'success');
140
+ } catch (e) { toast(e.message, 'error'); }
141
+ };
142
+
111
143
  const saveSaml = async () => {
112
144
  try {
113
145
  await apiCall('/settings/sso/saml', { method: 'PUT', body: JSON.stringify({ entityId: settings.samlEntityId, ssoUrl: settings.samlSsoUrl, certificate: settings.samlCertificate }) });
@@ -225,14 +257,76 @@ export function SettingsPage() {
225
257
  )
226
258
  ),
227
259
  h('div', { className: 'card' },
228
- h('div', { className: 'card-header' }, h('h3', null, 'Email Configuration')),
260
+ h('div', { className: 'card-header' },
261
+ h('h3', null, 'Organization Email'),
262
+ orgEmail.configured && h('span', { className: 'badge badge-success', style: { marginLeft: 8 } }, orgEmail.label || 'Configured')
263
+ ),
229
264
  h('div', { className: 'card-body' },
230
- h('div', { style: { display: 'flex', alignItems: 'center', gap: 12, padding: 16, background: 'var(--bg-tertiary)', borderRadius: 'var(--radius)' } },
231
- h('div', { style: { fontSize: 24 } }, '\u2709\uFE0F'),
232
- h('div', null,
233
- h('p', { style: { fontSize: 14, fontWeight: 600, marginBottom: 4 } }, 'Email is configured per agent'),
234
- h('p', { style: { fontSize: 13, color: 'var(--text-muted)' } }, 'Each agent has its own email credentials (IMAP/SMTP, Microsoft 365 OAuth, or Google OAuth). Configure email from each agent\'s detail page under the Email tab.')
265
+ h('p', { style: { fontSize: 13, color: 'var(--text-muted)', marginBottom: 16 } }, 'Set up a shared OAuth application for all agents. Each agent will still authorize individually with their own account, but they\'ll use the same Client ID and Secret.'),
266
+
267
+ // Provider selector
268
+ h('div', { style: { display: 'flex', gap: 12, marginBottom: 16 } },
269
+ h('div', {
270
+ onClick: function() { setOrgEmail(function(p) { return Object.assign({}, p, { provider: 'google' }); }); },
271
+ style: { flex: 1, padding: '16px 12px', border: '2px solid ' + (orgEmail.provider === 'google' ? 'var(--accent)' : 'var(--border)'), borderRadius: 'var(--radius)', cursor: 'pointer', textAlign: 'center', background: orgEmail.provider === 'google' ? 'var(--accent-soft)' : 'var(--bg-primary)' }
272
+ },
273
+ h('div', { style: { fontSize: 20, marginBottom: 4 } }, '\uD83D\uDD35'),
274
+ h('div', { style: { fontSize: 13, fontWeight: 600 } }, 'Google Workspace'),
275
+ h('div', { style: { fontSize: 11, color: 'var(--text-muted)' } }, 'Gmail API OAuth')
276
+ ),
277
+ h('div', {
278
+ onClick: function() { setOrgEmail(function(p) { return Object.assign({}, p, { provider: 'microsoft' }); }); },
279
+ style: { flex: 1, padding: '16px 12px', border: '2px solid ' + (orgEmail.provider === 'microsoft' ? 'var(--accent)' : 'var(--border)'), borderRadius: 'var(--radius)', cursor: 'pointer', textAlign: 'center', background: orgEmail.provider === 'microsoft' ? 'var(--accent-soft)' : 'var(--bg-primary)' }
280
+ },
281
+ h('div', { style: { fontSize: 20, marginBottom: 4 } }, '\uD83C\uDFE2'),
282
+ h('div', { style: { fontSize: 13, fontWeight: 600 } }, 'Microsoft 365'),
283
+ h('div', { style: { fontSize: 11, color: 'var(--text-muted)' } }, 'Azure AD / Entra ID')
284
+ )
285
+ ),
286
+
287
+ // Setup instructions
288
+ orgEmail.provider && h('div', { style: { padding: '12px 16px', background: 'var(--info-soft)', borderRadius: 'var(--radius)', marginBottom: 16, fontSize: 12, color: 'var(--text-secondary)' } },
289
+ h('strong', { style: { color: 'var(--accent)' } }, 'Setup Instructions:'), h('br'),
290
+ orgEmail.provider === 'google'
291
+ ? h(Fragment, null,
292
+ '1. Go to ', h('a', { href: 'https://console.cloud.google.com/apis/credentials', target: '_blank', style: { color: 'var(--accent)' } }, 'Google Cloud Console \u2192 Credentials'), h('br'),
293
+ '2. Create an OAuth 2.0 Client ID (Web application) \u2192 add redirect URI: ', h('code', { style: { background: 'var(--bg-tertiary)', padding: '1px 4px', borderRadius: 3, fontSize: 11 } }, window.location.origin + '/api/engine/oauth/callback'), h('br'),
294
+ '3. Enable the Gmail API in your project', h('br'),
295
+ '4. Copy the Client ID and Client Secret below'
296
+ )
297
+ : h(Fragment, null,
298
+ '1. Go to ', h('a', { href: 'https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade', target: '_blank', style: { color: 'var(--accent)' } }, 'Azure Portal \u2192 App Registrations'), h('br'),
299
+ '2. Click "New Registration" \u2192 set redirect URI to: ', h('code', { style: { background: 'var(--bg-tertiary)', padding: '1px 4px', borderRadius: 3, fontSize: 11 } }, window.location.origin + '/api/engine/oauth/callback'), h('br'),
300
+ '3. Copy the Client ID and create a Client Secret below'
301
+ )
302
+ ),
303
+
304
+ // Credentials form
305
+ orgEmail.provider && h(Fragment, null,
306
+ h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 12 } },
307
+ h('div', null,
308
+ h('label', { className: 'form-label' }, 'OAuth Client ID *'),
309
+ h('input', { className: 'input', value: orgEmail.oauthClientId, placeholder: orgEmail.provider === 'google' ? 'xxxx.apps.googleusercontent.com' : 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', onChange: function(e) { setOrgEmail(function(p) { return Object.assign({}, p, { oauthClientId: e.target.value }); }); } })
310
+ ),
311
+ h('div', null,
312
+ h('label', { className: 'form-label' }, 'Client Secret *'),
313
+ h('input', { className: 'input', type: 'password', value: orgEmail.oauthClientSecret, placeholder: orgEmail.configured ? '\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022 (saved)' : 'Enter client secret', onChange: function(e) { setOrgEmail(function(p) { return Object.assign({}, p, { oauthClientSecret: e.target.value }); }); } })
314
+ )
315
+ ),
316
+ orgEmail.provider === 'microsoft' && h('div', { style: { marginBottom: 12 } },
317
+ h('label', { className: 'form-label' }, 'Tenant ID'),
318
+ h('input', { className: 'input', style: { maxWidth: 400 }, value: orgEmail.oauthTenantId, placeholder: 'common', onChange: function(e) { setOrgEmail(function(p) { return Object.assign({}, p, { oauthTenantId: e.target.value }); }); } }),
319
+ h('p', { className: 'form-help' }, 'Use "common" for multi-tenant or your specific tenant ID')
320
+ ),
321
+ h('div', { style: { display: 'flex', gap: 8 } },
322
+ h('button', { className: 'btn btn-primary', disabled: orgEmailSaving, onClick: saveOrgEmail }, orgEmailSaving ? 'Saving...' : (orgEmail.configured ? 'Update Configuration' : 'Save Configuration')),
323
+ orgEmail.configured && h('button', { className: 'btn btn-danger', onClick: removeOrgEmail }, 'Remove')
235
324
  )
325
+ ),
326
+
327
+ // Info about per-agent auth
328
+ orgEmail.configured && h('div', { style: { marginTop: 16, padding: '12px 16px', background: 'var(--bg-tertiary)', borderRadius: 'var(--radius)', fontSize: 12, color: 'var(--text-muted)' } },
329
+ '\u2139\uFE0F Each agent still needs to individually authorize via their Email tab. This org config provides the shared OAuth app credentials so agents don\'t need to enter Client ID/Secret individually.'
236
330
  )
237
331
  )
238
332
  ),
@@ -0,0 +1,9 @@
1
+ import {
2
+ createAdapter,
3
+ getSupportedDatabases
4
+ } from "./chunk-QDXUZP7Y.js";
5
+ import "./chunk-KFQGP6VL.js";
6
+ export {
7
+ createAdapter,
8
+ getSupportedDatabases
9
+ };
package/dist/index.js CHANGED
@@ -35,7 +35,7 @@ import {
35
35
  executeTool,
36
36
  runAgentLoop,
37
37
  toolsToDefinitions
38
- } from "./chunk-WH2LORAG.js";
38
+ } from "./chunk-WBHMHTF3.js";
39
39
  import "./chunk-TYW5XTOW.js";
40
40
  import {
41
41
  ValidationError,
@@ -50,11 +50,11 @@ import {
50
50
  requireRole,
51
51
  securityHeaders,
52
52
  validate
53
- } from "./chunk-PB2APZMU.js";
53
+ } from "./chunk-KQCDQUAK.js";
54
54
  import {
55
55
  provision,
56
56
  runSetupWizard
57
- } from "./chunk-UGBWZJ5G.js";
57
+ } from "./chunk-G7BU3BUW.js";
58
58
  import {
59
59
  ENGINE_TABLES,
60
60
  ENGINE_TABLES_POSTGRES,
@@ -99,7 +99,7 @@ import {
99
99
  import {
100
100
  createAdapter,
101
101
  getSupportedDatabases
102
- } from "./chunk-WP76IB36.js";
102
+ } from "./chunk-QDXUZP7Y.js";
103
103
  import {
104
104
  AGENTICMAIL_TOOLS,
105
105
  ALL_TOOLS,