@agenticmail/enterprise 0.5.100 → 0.5.102

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,49 @@
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-5T72N6AX.js";
18
+ import "./chunk-NRF3YRF7.js";
19
+ import "./chunk-TYW5XTOW.js";
20
+ import "./chunk-AQH4DFYV.js";
21
+ import "./chunk-JLSQOQ5L.js";
22
+ import {
23
+ PROVIDER_REGISTRY,
24
+ listAllProviders,
25
+ resolveApiKeyForProvider,
26
+ resolveProvider
27
+ } from "./chunk-67KZYSLU.js";
28
+ import "./chunk-KFQGP6VL.js";
29
+ export {
30
+ AgentRuntime,
31
+ EmailChannel,
32
+ FollowUpScheduler,
33
+ PROVIDER_REGISTRY,
34
+ SessionManager,
35
+ SubAgentManager,
36
+ ToolRegistry,
37
+ callLLM,
38
+ createAgentRuntime,
39
+ createNoopHooks,
40
+ createRuntimeHooks,
41
+ estimateMessageTokens,
42
+ estimateTokens,
43
+ executeTool,
44
+ listAllProviders,
45
+ resolveApiKeyForProvider,
46
+ resolveProvider,
47
+ runAgentLoop,
48
+ toolsToDefinitions
49
+ };
@@ -0,0 +1,49 @@
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-NERC4SQV.js";
18
+ import "./chunk-NRF3YRF7.js";
19
+ import "./chunk-TYW5XTOW.js";
20
+ import "./chunk-AQH4DFYV.js";
21
+ import "./chunk-JLSQOQ5L.js";
22
+ import {
23
+ PROVIDER_REGISTRY,
24
+ listAllProviders,
25
+ resolveApiKeyForProvider,
26
+ resolveProvider
27
+ } from "./chunk-67KZYSLU.js";
28
+ import "./chunk-KFQGP6VL.js";
29
+ export {
30
+ AgentRuntime,
31
+ EmailChannel,
32
+ FollowUpScheduler,
33
+ PROVIDER_REGISTRY,
34
+ SessionManager,
35
+ SubAgentManager,
36
+ ToolRegistry,
37
+ callLLM,
38
+ createAgentRuntime,
39
+ createNoopHooks,
40
+ createRuntimeHooks,
41
+ estimateMessageTokens,
42
+ estimateTokens,
43
+ executeTool,
44
+ listAllProviders,
45
+ resolveApiKeyForProvider,
46
+ resolveProvider,
47
+ runAgentLoop,
48
+ toolsToDefinitions
49
+ };
@@ -0,0 +1,12 @@
1
+ import {
2
+ createServer
3
+ } from "./chunk-CNJQICZY.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,12 @@
1
+ import {
2
+ createServer
3
+ } from "./chunk-KL4U6ZNK.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-WIF5R3HF.js";
10
+ import "./chunk-QDXUZP7Y.js";
11
+ import "./chunk-KFQGP6VL.js";
12
+ export {
13
+ promptCompanyInfo,
14
+ promptDatabase,
15
+ promptDeployment,
16
+ promptDomain,
17
+ promptRegistration,
18
+ provision,
19
+ runSetupWizard
20
+ };
@@ -0,0 +1,20 @@
1
+ import {
2
+ promptCompanyInfo,
3
+ promptDatabase,
4
+ promptDeployment,
5
+ promptDomain,
6
+ promptRegistration,
7
+ provision,
8
+ runSetupWizard
9
+ } from "./chunk-Q5DKWAKT.js";
10
+ import "./chunk-QDXUZP7Y.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.100",
3
+ "version": "0.5.102",
4
4
  "description": "AgenticMail Enterprise — cloud-hosted AI agent identity, email, auth & compliance for organizations",
5
5
  "type": "module",
6
6
  "bin": {
@@ -367,6 +367,19 @@ function OverviewSection(props) {
367
367
  h('div', { className: 'card-header' }, h('span', null, 'Quick Actions')),
368
368
  h('div', { className: 'card-body', style: { display: 'flex', flexWrap: 'wrap', gap: 10 } },
369
369
 
370
+ // Reset state (when in error/degraded)
371
+ (agentState === 'error' || agentState === 'degraded') && h('button', {
372
+ className: 'btn btn-secondary btn-sm',
373
+ disabled: !!acting,
374
+ onClick: function() {
375
+ setActing('reset');
376
+ engineCall('/agents/' + agentId + '/reset-state', { method: 'POST' })
377
+ .then(function() { toast('Agent state reset to ready', 'success'); reload(); })
378
+ .catch(function(err) { toast(err.message, 'error'); })
379
+ .finally(function() { setActing(''); });
380
+ }
381
+ }, I.refresh(), ' Reset State'),
382
+
370
383
  // Deploy / Stop / Restart
371
384
  (agentState !== 'running' && agentState !== 'active') && h('button', {
372
385
  className: 'btn btn-primary btn-sm',
@@ -72,6 +72,24 @@ export function createAgentRoutes(opts: {
72
72
  }
73
73
  });
74
74
 
75
+ router.post('/agents/:id/reset-state', async (c) => {
76
+ try {
77
+ const agent = lifecycle.getAgent(c.req.param('id'));
78
+ if (!agent) return c.json({ error: 'Agent not found' }, 404);
79
+ if (!['error', 'degraded', 'deploying', 'provisioning', 'starting'].includes(agent.state)) {
80
+ return c.json({ error: `Cannot reset from state "${agent.state}"` }, 400);
81
+ }
82
+ // Reset to ready
83
+ (agent as any).state = 'ready';
84
+ (agent as any).stateMessage = 'State reset by admin';
85
+ (agent as any).updatedAt = new Date().toISOString();
86
+ await lifecycle.saveAgent(c.req.param('id'));
87
+ return c.json({ agent, message: 'State reset to ready' });
88
+ } catch (e: any) {
89
+ return c.json({ error: e.message }, 400);
90
+ }
91
+ });
92
+
75
93
  router.post('/agents/:id/stop', async (c) => {
76
94
  const { stoppedBy, reason } = await c.req.json();
77
95
  try {
@@ -404,11 +404,14 @@ export class DeploymentEngine {
404
404
  const size = cloud.size || 'shared-cpu-1x';
405
405
  const FLY_API = 'https://api.machines.dev/v1';
406
406
 
407
+ // Fly.io tokens: FlyV1 tokens use their own prefix, others use Bearer
408
+ const authHeader = apiToken.startsWith('FlyV1 ') || apiToken.startsWith('fm2_') ? apiToken.startsWith('FlyV1 ') ? apiToken : `FlyV1 ${apiToken}` : `Bearer ${apiToken}`;
409
+
407
410
  const flyFetch = async (path: string, method: string = 'GET', body?: any): Promise<any> => {
408
411
  const res = await fetch(`${FLY_API}${path}`, {
409
412
  method,
410
413
  headers: {
411
- 'Authorization': `Bearer ${apiToken}`,
414
+ 'Authorization': authHeader,
412
415
  'Content-Type': 'application/json',
413
416
  },
414
417
  body: body ? JSON.stringify(body) : undefined,
@@ -423,8 +426,18 @@ export class DeploymentEngine {
423
426
  // 1. Create app (ignore "already exists" errors)
424
427
  emit('provision', 'started', `Creating Fly.io app "${appName}"...`);
425
428
  try {
426
- // Fly.io org_slug must be a Fly org slug (e.g. 'personal'), not an internal org ID
427
- const flyOrg = (cloud.org && cloud.org.length < 30 && /^[a-z0-9-]+$/.test(cloud.org)) ? cloud.org : 'personal';
429
+ // Fly.io org_slug must be a Fly org slug (e.g. 'personal', 'ope-olatunji'), not an internal org ID
430
+ // If no valid org slug provided, auto-detect from token by listing apps
431
+ let flyOrg = (cloud.org && cloud.org.length < 40 && /^[a-z0-9-]+$/.test(cloud.org)) ? cloud.org : '';
432
+ if (!flyOrg) {
433
+ try {
434
+ const orgsRes = await flyFetch('/apps?org_slug=personal');
435
+ if (orgsRes?.apps?.length > 0 && orgsRes.apps[0].organization?.slug) {
436
+ flyOrg = orgsRes.apps[0].organization.slug;
437
+ }
438
+ } catch {}
439
+ if (!flyOrg) flyOrg = 'personal';
440
+ }
428
441
  await flyFetch('/apps', 'POST', {
429
442
  app_name: appName,
430
443
  org_slug: flyOrg,
@@ -618,10 +631,12 @@ export class DeploymentEngine {
618
631
 
619
632
  const appName = cloud.appName || `am-agent-${config.name.toLowerCase().replace(/[^a-z0-9-]/g, '-').slice(0, 30)}`;
620
633
  const FLY_API = 'https://api.machines.dev/v1';
634
+ const t = cloud.apiToken;
635
+ const auth = t.startsWith('FlyV1 ') ? t : t.startsWith('fm2_') ? `FlyV1 ${t}` : `Bearer ${t}`;
621
636
 
622
637
  try {
623
638
  const res = await fetch(`${FLY_API}/apps/${appName}/machines`, {
624
- headers: { 'Authorization': `Bearer ${cloud.apiToken}` },
639
+ headers: { 'Authorization': auth },
625
640
  });
626
641
  if (!res.ok) return { ...base, status: 'error', healthStatus: 'unhealthy' };
627
642
 
@@ -654,10 +669,12 @@ export class DeploymentEngine {
654
669
 
655
670
  const appName = cloud.appName || `am-agent-${config.name.toLowerCase().replace(/[^a-z0-9-]/g, '-').slice(0, 30)}`;
656
671
  const FLY_API = 'https://api.machines.dev/v1';
672
+ const t = cloud.apiToken;
673
+ const auth = t.startsWith('FlyV1 ') ? t : t.startsWith('fm2_') ? `FlyV1 ${t}` : `Bearer ${t}`;
657
674
 
658
675
  try {
659
676
  const res = await fetch(`${FLY_API}/apps/${appName}/machines`, {
660
- headers: { 'Authorization': `Bearer ${cloud.apiToken}` },
677
+ headers: { 'Authorization': auth },
661
678
  });
662
679
  if (!res.ok) return { success: false, message: `Failed to list machines: ${res.status}` };
663
680
  const machines = await res.json() as any[];
@@ -666,7 +683,7 @@ export class DeploymentEngine {
666
683
  const machineId = machines[0].id;
667
684
  const actionRes = await fetch(`${FLY_API}/apps/${appName}/machines/${machineId}/${action}`, {
668
685
  method: 'POST',
669
- headers: { 'Authorization': `Bearer ${cloud.apiToken}` },
686
+ headers: { 'Authorization': auth },
670
687
  });
671
688
  if (!actionRes.ok) {
672
689
  const err = await actionRes.text();
@@ -184,6 +184,8 @@ export class AgentLifecycleManager {
184
184
  private lastBirthdayCheck: string = '';
185
185
  /** External callback for sending birthday messages (set via setBirthdaySender) */
186
186
  private birthdaySender: ((agent: ManagedAgent) => Promise<void>) | null = null;
187
+ /** Vault for decrypting deploy credentials */
188
+ private vault?: any;
187
189
 
188
190
  constructor(opts?: { db?: EngineDatabase; permissions?: PermissionEngine }) {
189
191
  this.engineDb = opts?.db;
@@ -198,6 +200,10 @@ export class AgentLifecycleManager {
198
200
  await this.loadFromDb();
199
201
  }
200
202
 
203
+ setVault(vault: any): void {
204
+ this.vault = vault;
205
+ }
206
+
201
207
  /**
202
208
  * Load all agents from DB into memory
203
209
  */
@@ -923,6 +929,7 @@ export class AgentLifecycleManager {
923
929
  * Resolve org-level deploy credentials and merge into agent config.
924
930
  * If the agent's deployment config is missing an API token, look up
925
931
  * the org's deploy_credentials table for a matching target type.
932
+ * Also sanitizes app names to be valid for the target platform.
926
933
  */
927
934
  private async resolveDeployCredentials(agent: ManagedAgent): Promise<void> {
928
935
  const target = agent.config?.deployment?.target;
@@ -931,10 +938,19 @@ export class AgentLifecycleManager {
931
938
  // Ensure deployment.config exists
932
939
  if (!agent.config.deployment.config) agent.config.deployment.config = {} as any;
933
940
 
934
- // For fly/railway, check if cloud.apiToken is already set
941
+ // Sanitize cloud.appName if present (Fly.io requires lowercase alphanumeric + hyphens)
935
942
  if (target === 'fly' || target === 'railway') {
936
- const cloud = agent.config.deployment.config.cloud;
937
- if (cloud?.apiToken) return; // Agent has its own token
943
+ if (!agent.config.deployment.config.cloud) agent.config.deployment.config.cloud = {} as any;
944
+ const cloud = agent.config.deployment.config.cloud!;
945
+
946
+ if (cloud.appName) {
947
+ cloud.appName = cloud.appName.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '').slice(0, 30);
948
+ }
949
+ // Ensure provider is set
950
+ if (!cloud.provider) cloud.provider = target as any;
951
+
952
+ // If agent already has a token, we're done
953
+ if (cloud.apiToken) return;
938
954
 
939
955
  // Look up org-level credentials
940
956
  if (this.engineDb) {
@@ -942,14 +958,21 @@ export class AgentLifecycleManager {
942
958
  const orgId = agent.orgId || 'default';
943
959
  const creds = await this.engineDb.getDeployCredentialsByType(orgId, target);
944
960
  if (creds.length > 0) {
945
- const orgCred = creds[0];
946
- agent.config.deployment.config.cloud = {
947
- ...agent.config.deployment.config.cloud,
948
- provider: target,
949
- apiToken: orgCred.config?.apiToken || orgCred.config?.token,
950
- ...(orgCred.config?.region && { region: orgCred.config.region }),
951
- ...(orgCred.config?.org && { org: orgCred.config.org }),
952
- };
961
+ let credConfig = creds[0].config;
962
+
963
+ // Decrypt if encrypted
964
+ if (credConfig?._encrypted && this.vault) {
965
+ try {
966
+ credConfig = JSON.parse(this.vault.decrypt(credConfig._encrypted));
967
+ } catch (decErr) {
968
+ console.error('[lifecycle] Failed to decrypt deploy credential:', decErr);
969
+ }
970
+ }
971
+
972
+ if (credConfig?.apiToken || credConfig?.token) {
973
+ cloud.apiToken = credConfig.apiToken || credConfig.token;
974
+ if (credConfig.region && !cloud.region) cloud.region = credConfig.region;
975
+ }
953
976
  }
954
977
  } catch (err) {
955
978
  console.error('[lifecycle] Failed to resolve deploy credentials:', err);
@@ -231,7 +231,7 @@ export async function setEngineDb(
231
231
 
232
232
  // Cascade DB to all engine modules for persistent storage
233
233
  await Promise.all([
234
- lifecycle.setDb(db),
234
+ lifecycle.setDb(db).then(() => lifecycle.setVault(vault)),
235
235
  approvals.setDb(db),
236
236
  knowledgeBase.setDb(db),
237
237
  activity.setDb(db),