@agenticmail/enterprise 0.5.72 → 0.5.74
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/dist/chunk-G7BU3BUW.js +898 -0
- package/dist/chunk-KQCDQUAK.js +2167 -0
- package/dist/chunk-QDXUZP7Y.js +48 -0
- package/dist/chunk-WBHMHTF3.js +13099 -0
- package/dist/cli-recover-JYCMVLVL.js +97 -0
- package/dist/cli-verify-F7R5RO65.js +98 -0
- package/dist/cli.js +3 -3
- package/dist/dashboard/pages/agent-detail.js +35 -14
- package/dist/dashboard/pages/settings.js +100 -6
- package/dist/factory-GT6SUZSQ.js +9 -0
- package/dist/index.js +4 -4
- package/dist/postgres-HAHOD7HX.js +607 -0
- package/dist/routes-BWJXOYXC.js +6276 -0
- package/dist/runtime-LID6KTDP.js +47 -0
- package/dist/server-LSDU47XE.js +12 -0
- package/dist/setup-TPYVQULV.js +20 -0
- package/package.json +1 -1
- package/src/admin/routes.ts +43 -0
- package/src/dashboard/pages/agent-detail.js +35 -14
- package/src/dashboard/pages/settings.js +100 -6
- package/src/db/adapter.ts +12 -0
- package/src/db/postgres.ts +9 -0
- package/src/engine/agent-routes.ts +39 -3
|
@@ -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-
|
|
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-
|
|
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-
|
|
51
|
+
import("./setup-TPYVQULV.js").then((m) => m.runSetupWizard()).catch(fatal);
|
|
52
52
|
break;
|
|
53
53
|
}
|
|
54
54
|
function fatal(err) {
|
|
@@ -3925,18 +3925,22 @@ function EmailSection(props) {
|
|
|
3925
3925
|
});
|
|
3926
3926
|
} else if (form.provider === 'microsoft') {
|
|
3927
3927
|
var baseUrl = window.location.origin;
|
|
3928
|
+
var hasOrgMs = emailConfig && emailConfig.orgEmailConfig && emailConfig.orgEmailConfig.provider === 'microsoft';
|
|
3928
3929
|
Object.assign(body, {
|
|
3929
|
-
oauthClientId: form.oauthClientId,
|
|
3930
|
-
oauthClientSecret: form.oauthClientSecret,
|
|
3930
|
+
oauthClientId: form.oauthClientId || undefined,
|
|
3931
|
+
oauthClientSecret: form.oauthClientSecret || undefined,
|
|
3931
3932
|
oauthTenantId: form.oauthTenantId,
|
|
3932
3933
|
oauthRedirectUri: baseUrl + '/api/engine/oauth/callback',
|
|
3934
|
+
useOrgConfig: hasOrgMs && !form.oauthClientId ? true : undefined,
|
|
3933
3935
|
});
|
|
3934
3936
|
} else if (form.provider === 'google') {
|
|
3935
3937
|
var gBaseUrl = window.location.origin;
|
|
3938
|
+
var hasOrgG = emailConfig && emailConfig.orgEmailConfig && emailConfig.orgEmailConfig.provider === 'google';
|
|
3936
3939
|
Object.assign(body, {
|
|
3937
|
-
oauthClientId: form.oauthClientId,
|
|
3938
|
-
oauthClientSecret: form.oauthClientSecret,
|
|
3940
|
+
oauthClientId: form.oauthClientId || undefined,
|
|
3941
|
+
oauthClientSecret: form.oauthClientSecret || undefined,
|
|
3939
3942
|
oauthRedirectUri: gBaseUrl + '/api/engine/oauth/callback',
|
|
3943
|
+
useOrgConfig: hasOrgG && !form.oauthClientId ? true : undefined,
|
|
3940
3944
|
});
|
|
3941
3945
|
}
|
|
3942
3946
|
|
|
@@ -4023,6 +4027,15 @@ function EmailSection(props) {
|
|
|
4023
4027
|
),
|
|
4024
4028
|
h('div', { className: 'card-body' },
|
|
4025
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
|
+
|
|
4026
4039
|
// ─── Provider Selection ─────────────────────────
|
|
4027
4040
|
h('div', { style: { marginBottom: 20 } },
|
|
4028
4041
|
h('label', { style: labelStyle }, 'Connection Method'),
|
|
@@ -4145,16 +4158,24 @@ function EmailSection(props) {
|
|
|
4145
4158
|
),
|
|
4146
4159
|
|
|
4147
4160
|
// ─── Google OAuth Config ────────────────────────
|
|
4148
|
-
form.provider === 'google' &&
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
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
|
+
),
|
|
4156
4177
|
|
|
4157
|
-
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 } },
|
|
4158
4179
|
h('div', null,
|
|
4159
4180
|
h('label', { style: labelStyle }, 'OAuth Client ID *'),
|
|
4160
4181
|
h('input', { style: inputStyle, value: form.oauthClientId, placeholder: 'xxxx.apps.googleusercontent.com', onChange: function(e) { set('oauthClientId', e.target.value); } })
|
|
@@ -4170,7 +4191,7 @@ function EmailSection(props) {
|
|
|
4170
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.'),
|
|
4171
4192
|
h('button', { className: 'btn btn-primary btn-sm', onClick: openOAuth }, 'Authorize with Google')
|
|
4172
4193
|
)
|
|
4173
|
-
),
|
|
4194
|
+
); })(),
|
|
4174
4195
|
|
|
4175
4196
|
// ─── Test Result ─────────────────────────────────
|
|
4176
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' },
|
|
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('
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
),
|
package/dist/index.js
CHANGED
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
executeTool,
|
|
36
36
|
runAgentLoop,
|
|
37
37
|
toolsToDefinitions
|
|
38
|
-
} from "./chunk-
|
|
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-
|
|
53
|
+
} from "./chunk-KQCDQUAK.js";
|
|
54
54
|
import {
|
|
55
55
|
provision,
|
|
56
56
|
runSetupWizard
|
|
57
|
-
} from "./chunk-
|
|
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-
|
|
102
|
+
} from "./chunk-QDXUZP7Y.js";
|
|
103
103
|
import {
|
|
104
104
|
AGENTICMAIL_TOOLS,
|
|
105
105
|
ALL_TOOLS,
|