@agenticmail/enterprise 0.5.320 → 0.5.321

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/CHANGELOG.md ADDED
@@ -0,0 +1,68 @@
1
+ # Changelog
2
+
3
+ All notable changes to AgenticMail Enterprise are documented here.
4
+
5
+ ## [0.5.320] - 2026-03-05
6
+
7
+ ### Added
8
+ - **Microsoft 365 Integration** — 97 tools across 13 services (Outlook Mail, Calendar, OneDrive, Teams, Excel, SharePoint, OneNote, To Do, Contacts, PowerPoint, Planner, Power BI)
9
+ - **Microsoft Graph API helper** — Retry with backoff, rate-limit handling, auto-pagination, JSON batching
10
+ - **Microsoft system prompts** — 12 structured prompt files mirroring Google tools pattern
11
+ - **Task pipeline redesign** — Table/list view with status tabs, search, pagination, real-time updates via webhook
12
+ - **Client organization data isolation** — Org-bound users see only their organization's data
13
+ - **Visible roles configuration** — Parent org controls which roles client org users can see
14
+ - **Cross-platform dependency manager** — macOS, Linux, Windows support with policy-driven installation
15
+ - **Org-wide dependency policy** — Configurable from Settings > Security tab
16
+ - **PM2 production persistence** — ecosystem.config.cjs, LaunchAgent, log rotation
17
+ - **LOG_LEVEL env var** — Production log noise suppression
18
+ - **Port validation** — Checks availability before local agent deployment
19
+ - **Screen unlock** — Agents can auto-unlock machine screen
20
+ - **Per-section editing** — Independent edit buttons on Security and Permissions tabs
21
+ - **Dynamic sidebar company name** — Updates in real-time from settings
22
+ - **Tiered tool loading** — ~75% tool count reduction for messaging channels
23
+
24
+ ### Fixed
25
+ - DB connection pool exhaustion (MaxClientsInSessionMode)
26
+ - Smart DB URL auto-configuration for Supabase/Neon
27
+ - Stop-impersonation logging user out
28
+ - Client org skills/roles showing all data during impersonation
29
+ - Agent UUID display in compliance reports
30
+
31
+ ## [0.5.315] - 2026-03-03
32
+
33
+ ### Added
34
+ - Client organization data isolation across all dashboard pages
35
+ - `allowed_roles` JSONB column for role visibility control
36
+ - Impersonation token refresh preserving org restrictions
37
+
38
+ ## [0.5.313] - 2026-03-01
39
+
40
+ ### Added
41
+ - Smart DB URL auto-configuration (Supabase/Neon detection)
42
+ - 7 enterprise DLP rule packs (53 rules)
43
+ - SOC 2 Type II compliance reports with HTML export
44
+ - Comprehensive README rewrite
45
+
46
+ ### Fixed
47
+ - DB connection pool exhaustion
48
+ - Compliance report generation crashes
49
+
50
+ ## [0.5.312] - 2026-02-28
51
+
52
+ ### Added
53
+ - Transport encryption (AES-256-GCM)
54
+ - Org switchers across all dashboard pages
55
+ - DLP rule editing, enable/disable toggle, detail modal
56
+ - Journal action detail modal
57
+
58
+ ### Fixed
59
+ - Double encryption with Hono wildcard middleware
60
+ - Engine sub-app body forwarding
61
+ - Org switching not reloading data
62
+ - Knowledge base auto-assign persistence
63
+ - Workforce/guardrails/audit org filtering
64
+
65
+ [0.5.320]: https://github.com/agenticmail/enterprise/releases/tag/v0.5.320
66
+ [0.5.315]: https://github.com/agenticmail/enterprise/releases/tag/v0.5.315
67
+ [0.5.313]: https://github.com/agenticmail/enterprise/releases/tag/v0.5.313
68
+ [0.5.312]: https://github.com/agenticmail/enterprise/releases/tag/v0.5.312
@@ -0,0 +1,31 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
6
+
7
+ ## Our Standards
8
+
9
+ Examples of behavior that contributes to a positive environment:
10
+
11
+ * Using welcoming and inclusive language
12
+ * Being respectful of differing viewpoints and experiences
13
+ * Gracefully accepting constructive criticism
14
+ * Focusing on what is best for the community
15
+ * Showing empathy towards other community members
16
+
17
+ Examples of unacceptable behavior:
18
+
19
+ * The use of sexualized language or imagery, and sexual attention or advances of any kind
20
+ * Trolling, insulting or derogatory comments, and personal or political attacks
21
+ * Public or private harassment
22
+ * Publishing others' private information without explicit permission
23
+ * Other conduct which could reasonably be considered inappropriate in a professional setting
24
+
25
+ ## Enforcement
26
+
27
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to **conduct@agenticmail.io**. All complaints will be reviewed and investigated promptly and fairly.
28
+
29
+ ## Attribution
30
+
31
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1.
package/SECURITY.md ADDED
@@ -0,0 +1,42 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ | Version | Supported |
6
+ | ------- | ------------------ |
7
+ | 0.5.x | :white_check_mark: |
8
+ | < 0.5 | :x: |
9
+
10
+ ## Reporting a Vulnerability
11
+
12
+ **Do not report security vulnerabilities through public GitHub issues.**
13
+
14
+ Instead, please report them via email to **security@agenticmail.io**.
15
+
16
+ You should receive an acknowledgment within 48 hours. We will send a detailed response within 7 days indicating next steps.
17
+
18
+ Please include:
19
+
20
+ - Description of the vulnerability
21
+ - Steps to reproduce
22
+ - Impact assessment
23
+ - Any suggested fixes (optional)
24
+
25
+ ## Security Measures
26
+
27
+ AgenticMail Enterprise implements multiple layers of security:
28
+
29
+ - **Transport Encryption** — AES-256-GCM encryption for all API traffic
30
+ - **Data Loss Prevention (DLP)** — Real-time content scanning with 53 built-in rules across 7 categories
31
+ - **Role-Based Access Control (RBAC)** — Granular permissions with preset profiles
32
+ - **Multi-Tenant Isolation** — Client organization data isolation across all endpoints
33
+ - **Audit Logging** — Comprehensive action journal with org-scoped filtering
34
+ - **SOC 2 Type II Compliance** — Automated reporting across all 9 Common Criteria (CC1-CC9)
35
+ - **OAuth 2.0 / SAML / OIDC** — Enterprise SSO with provider-based tool auto-detection
36
+ - **Rate Limiting** — Configurable per-endpoint and per-agent limits
37
+ - **CORS / Security Headers** — Strict origin validation and security header enforcement
38
+ - **Outbound Guard** — PII and credential scanning on all outgoing communications
39
+
40
+ ## Disclosure Policy
41
+
42
+ We follow responsible disclosure. Security issues are patched in private and released as part of the next version. Critical vulnerabilities may receive out-of-band patches.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/enterprise",
3
- "version": "0.5.320",
3
+ "version": "0.5.321",
4
4
  "description": "AgenticMail Enterprise — cloud-hosted AI agent identity, email, auth & compliance for organizations",
5
5
  "type": "module",
6
6
  "bin": {
@@ -28,10 +28,31 @@
28
28
  "saml",
29
29
  "oidc",
30
30
  "scim",
31
- "identity"
31
+ "identity",
32
+ "ai-agents",
33
+ "agent-platform",
34
+ "microsoft-365",
35
+ "google-workspace",
36
+ "compliance",
37
+ "soc2",
38
+ "gdpr",
39
+ "dlp",
40
+ "data-loss-prevention",
41
+ "oauth",
42
+ "multi-tenant",
43
+ "workforce-management",
44
+ "task-pipeline",
45
+ "telegram-bot",
46
+ "whatsapp-bot",
47
+ "voice-ai",
48
+ "google-meet",
49
+ "dependency-management",
50
+ "audit-log",
51
+ "rbac",
52
+ "encryption"
32
53
  ],
33
54
  "author": "Ope Olatunji (https://github.com/ope-olatunji)",
34
- "homepage": "https://github.com/agenticmail/enterprise",
55
+ "homepage": "https://agenticmail.io",
35
56
  "repository": {
36
57
  "type": "git",
37
58
  "url": "https://github.com/agenticmail/enterprise.git"
@@ -90,5 +111,12 @@
90
111
  "mongodb": "^6.3.0",
91
112
  "mysql2": "^3.9.0",
92
113
  "postgres": "^3.4.0"
114
+ },
115
+ "engines": {
116
+ "node": ">=18.0.0"
117
+ },
118
+ "funding": {
119
+ "type": "individual",
120
+ "url": "https://agenticmail.io"
93
121
  }
94
122
  }
@@ -1,23 +0,0 @@
1
- # ─── AgenticMail Enterprise Code Owners ───────────────
2
- #
3
- # These owners are automatically requested for review
4
- # when a PR touches matching paths.
5
- #
6
- # IMPORTANT: Enable "Require review from Code Owners" in
7
- # GitHub repo Settings → Branches → Branch protection rules
8
- # for the `main` branch to enforce this.
9
-
10
- # Core engine — requires core team review
11
- src/engine/ @agenticmail/core-team
12
- src/server.ts @agenticmail/core-team
13
- src/auth/ @agenticmail/core-team
14
- src/admin/ @agenticmail/core-team
15
-
16
- # Community skills — ALL submissions require maintainer review
17
- # No community skill can be merged without explicit approval
18
- community-skills/ @agenticmail/skill-reviewers
19
-
20
- # CI/CD and repo config — requires admin review
21
- .github/ @agenticmail/core-team
22
- CLAUDE.md @agenticmail/core-team
23
- package.json @agenticmail/core-team
@@ -1,121 +0,0 @@
1
- name: Publish Community Skills
2
-
3
- # IMPORTANT: This workflow only runs AFTER code is merged into main.
4
- # It does NOT auto-approve or auto-merge PRs.
5
- # All community skill PRs must be reviewed and approved by a maintainer
6
- # (enforced by CODEOWNERS + branch protection rules) before this runs.
7
- #
8
- # After a maintainer-approved merge:
9
- # 1. Rebuilds community-skills/index.json (the registry index deployed instances fetch)
10
- # 2. Optionally pushes each skill to a live registry API
11
-
12
- on:
13
- push:
14
- branches: [main]
15
- paths:
16
- - 'community-skills/**'
17
-
18
- permissions:
19
- contents: write
20
-
21
- jobs:
22
- publish:
23
- runs-on: ubuntu-latest
24
- steps:
25
- - uses: actions/checkout@v4
26
- with:
27
- fetch-depth: 2
28
-
29
- - uses: actions/setup-node@v4
30
- with:
31
- node-version: '20'
32
-
33
- # ── Generate index.json ─────────────────────────
34
- # This is the file that deployed instances fetch to discover new skills.
35
- # Every community-skills/<id>/agenticmail-skill.json gets listed here.
36
-
37
- - name: Generate community-skills/index.json
38
- run: |
39
- node -e "
40
- const fs = require('fs');
41
- const path = require('path');
42
- const dir = 'community-skills';
43
- const skills = [];
44
-
45
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
46
- if (!entry.isDirectory() || entry.name.startsWith('_') || entry.name.startsWith('.')) continue;
47
- const manifestPath = path.join(dir, entry.name, 'agenticmail-skill.json');
48
- try {
49
- const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
50
- skills.push({
51
- id: manifest.id,
52
- name: manifest.name,
53
- version: manifest.version,
54
- author: manifest.author,
55
- category: manifest.category,
56
- risk: manifest.risk,
57
- description: manifest.description,
58
- });
59
- } catch (err) {
60
- console.error('Skipping ' + entry.name + ': ' + err.message);
61
- }
62
- }
63
-
64
- const index = {
65
- generatedAt: new Date().toISOString(),
66
- count: skills.length,
67
- skills,
68
- };
69
-
70
- fs.writeFileSync(path.join(dir, 'index.json'), JSON.stringify(index, null, 2) + '\n');
71
- console.log('Generated index.json with ' + skills.length + ' skills');
72
- "
73
-
74
- - name: Commit index.json
75
- run: |
76
- git config user.name "github-actions[bot]"
77
- git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
78
- git add community-skills/index.json
79
- git diff --cached --quiet && echo "No changes to index.json" && exit 0
80
- git commit -m "chore: update community-skills index [skip ci]"
81
- git push
82
-
83
- # ── Publish to live registry (optional) ─────────
84
- # If ENTERPRISE_REGISTRY_URL is configured, also push directly to a live server.
85
-
86
- - name: Find changed skill directories
87
- id: changed
88
- run: |
89
- CHANGED=$(git diff --name-only HEAD~1 HEAD -- community-skills/ || true)
90
- DIRS=$(echo "$CHANGED" | grep -oP 'community-skills/[^/]+' | sort -u | grep -v '_template' || true)
91
- echo "dirs<<EOF" >> $GITHUB_OUTPUT
92
- echo "$DIRS" >> $GITHUB_OUTPUT
93
- echo "EOF" >> $GITHUB_OUTPUT
94
- COUNT=$(echo "$DIRS" | grep -c '.' || echo "0")
95
- echo "count=$COUNT" >> $GITHUB_OUTPUT
96
-
97
- - name: Publish to live registry
98
- if: steps.changed.outputs.count != '0' && env.REGISTRY_URL != ''
99
- env:
100
- REGISTRY_URL: ${{ secrets.ENTERPRISE_REGISTRY_URL }}
101
- REGISTRY_TOKEN: ${{ secrets.ENTERPRISE_API_KEY }}
102
- run: |
103
- while IFS= read -r dir; do
104
- [ -z "$dir" ] && continue
105
- SKILL_ID=$(basename "$dir")
106
- MANIFEST="$dir/agenticmail-skill.json"
107
- [ ! -f "$MANIFEST" ] && continue
108
-
109
- echo "Publishing $SKILL_ID..."
110
- HTTP_CODE=$(curl -s -o /tmp/response.json -w "%{http_code}" \
111
- -X POST "${REGISTRY_URL}/api/engine/community/skills/publish" \
112
- -H "Content-Type: application/json" \
113
- -H "Authorization: Bearer ${REGISTRY_TOKEN}" \
114
- -d @"$MANIFEST")
115
-
116
- if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
117
- echo "Published $SKILL_ID (HTTP $HTTP_CODE)"
118
- else
119
- echo "::warning::Failed to publish $SKILL_ID (HTTP $HTTP_CODE)"
120
- fi
121
- done <<< "${{ steps.changed.outputs.dirs }}"
@@ -1,172 +0,0 @@
1
- name: Validate Community Skills
2
-
3
- on:
4
- pull_request:
5
- paths:
6
- - 'community-skills/**'
7
- types: [opened, synchronize, reopened]
8
-
9
- permissions:
10
- contents: read
11
- pull-requests: write
12
-
13
- jobs:
14
- validate:
15
- runs-on: ubuntu-latest
16
- steps:
17
- - uses: actions/checkout@v4
18
- with:
19
- fetch-depth: 0
20
-
21
- - uses: actions/setup-node@v4
22
- with:
23
- node-version: '20'
24
- cache: 'npm'
25
-
26
- - run: npm ci
27
-
28
- - run: npm run build
29
-
30
- - name: Find changed skill directories
31
- id: changed
32
- run: |
33
- CHANGED=$(git diff --name-only ${{ github.event.pull_request.base.sha }} HEAD -- community-skills/ || true)
34
- DIRS=$(echo "$CHANGED" | grep -oP 'community-skills/[^/]+' | sort -u | grep -v '_template' || true)
35
- echo "dirs<<EOF" >> $GITHUB_OUTPUT
36
- echo "$DIRS" >> $GITHUB_OUTPUT
37
- echo "EOF" >> $GITHUB_OUTPUT
38
- COUNT=$(echo "$DIRS" | grep -c '.' || echo "0")
39
- echo "count=$COUNT" >> $GITHUB_OUTPUT
40
-
41
- - name: Validate each skill
42
- id: validate
43
- if: steps.changed.outputs.count != '0'
44
- run: |
45
- FAILED=0
46
- RESULTS=""
47
- while IFS= read -r dir; do
48
- [ -z "$dir" ] && continue
49
- SKILL_ID=$(basename "$dir")
50
- echo "::group::Validating $SKILL_ID"
51
- if [ -f "$dir/agenticmail-skill.json" ]; then
52
- OUTPUT=$(node dist/cli.js validate "$dir" --json 2>&1)
53
- echo "$OUTPUT"
54
- VALID=$(echo "$OUTPUT" | node -e "const d=require('fs').readFileSync('/dev/stdin','utf-8'); try{const j=JSON.parse(d); console.log(j.results?.[0]?.valid ? 'true':'false')}catch{console.log('false')}")
55
- if [ "$VALID" = "true" ]; then
56
- RESULTS="${RESULTS}| \`${SKILL_ID}\` | ✅ Passed | — |\n"
57
- else
58
- ERRORS=$(echo "$OUTPUT" | node -e "const d=require('fs').readFileSync('/dev/stdin','utf-8'); try{const j=JSON.parse(d); console.log((j.results?.[0]?.errors||[]).join(', '))}catch{console.log('parse error')}")
59
- RESULTS="${RESULTS}| \`${SKILL_ID}\` | ❌ Failed | ${ERRORS} |\n"
60
- FAILED=1
61
- fi
62
- else
63
- echo "::error::Missing agenticmail-skill.json in $dir"
64
- RESULTS="${RESULTS}| \`${SKILL_ID}\` | ❌ Failed | Missing agenticmail-skill.json |\n"
65
- FAILED=1
66
- fi
67
- echo "::endgroup::"
68
- done <<< "${{ steps.changed.outputs.dirs }}"
69
- echo "results<<EOF" >> $GITHUB_OUTPUT
70
- echo -e "$RESULTS" >> $GITHUB_OUTPUT
71
- echo "EOF" >> $GITHUB_OUTPUT
72
- echo "failed=$FAILED" >> $GITHUB_OUTPUT
73
- exit $FAILED
74
-
75
- - name: Check for README
76
- if: steps.changed.outputs.count != '0'
77
- id: readme
78
- run: |
79
- MISSING=""
80
- while IFS= read -r dir; do
81
- [ -z "$dir" ] && continue
82
- if [ ! -f "$dir/README.md" ]; then
83
- MISSING="${MISSING}$(basename $dir), "
84
- fi
85
- done <<< "${{ steps.changed.outputs.dirs }}"
86
- echo "missing=$MISSING" >> $GITHUB_OUTPUT
87
-
88
- - name: Label PR
89
- if: always() && steps.changed.outputs.count != '0'
90
- uses: actions/github-script@v7
91
- with:
92
- script: |
93
- const labels = ['community-skill', 'needs-maintainer-review'];
94
- if ('${{ steps.validate.outputs.failed }}' === '0') {
95
- labels.push('validated');
96
- } else {
97
- labels.push('validation-failed');
98
- }
99
- await github.rest.issues.addLabels({
100
- owner: context.repo.owner,
101
- repo: context.repo.repo,
102
- issue_number: context.issue.number,
103
- labels,
104
- });
105
-
106
- - name: Post review checklist
107
- if: always() && steps.changed.outputs.count != '0'
108
- uses: actions/github-script@v7
109
- with:
110
- script: |
111
- const passed = '${{ steps.validate.outputs.failed }}' === '0';
112
- const validationStatus = passed ? '✅ All checks passed' : '❌ Validation failed — see errors below';
113
- const missingReadme = '${{ steps.readme.outputs.missing }}'.trim();
114
-
115
- const body = `### Community Skill Review
116
-
117
- **Automated Validation:** ${validationStatus}
118
- **Skills checked:** ${{ steps.changed.outputs.count }}
119
-
120
- #### Validation Results
121
-
122
- | Skill | Status | Errors |
123
- |-------|--------|--------|
124
- ${{ steps.validate.outputs.results }}
125
-
126
- ${missingReadme ? `⚠️ **Missing README.md:** ${missingReadme}\n` : ''}
127
-
128
- ---
129
-
130
- #### Maintainer Review Checklist
131
-
132
- > **This PR requires manual review from a maintainer before merging.**
133
- > Automated validation only checks the manifest format — a human must
134
- > review the actual skill design, tool definitions, and risk assessment.
135
-
136
- - [ ] **Tool IDs are sensibly named** and follow the \`prefix_action\` convention
137
- - [ ] **Descriptions are accurate** and clearly explain what each tool does
138
- - [ ] **Risk levels are appropriate** — destructive tools should be \`high\`/\`critical\`
139
- - [ ] **Side effects are correctly declared** (sends-email, deletes-data, etc.)
140
- - [ ] **Category is correct** for the application type
141
- - [ ] **No malicious or deceptive tool definitions** hiding behind legitimate names
142
- - [ ] **Config schema is reasonable** — no unnecessary secrets or permissions
143
- - [ ] **README documents** all tools, configuration, and usage
144
- - [ ] **License is appropriate** for community contribution
145
-
146
- ---
147
- *Automated by [AgenticMail Enterprise CI](https://github.com/agenticmail/enterprise) — maintainer approval required to merge*`;
148
-
149
- const comments = await github.rest.issues.listComments({
150
- owner: context.repo.owner,
151
- repo: context.repo.repo,
152
- issue_number: context.issue.number,
153
- });
154
- const existing = comments.data.find(c =>
155
- c.body?.includes('Community Skill Review') && c.user?.type === 'Bot'
156
- );
157
-
158
- if (existing) {
159
- await github.rest.issues.updateComment({
160
- owner: context.repo.owner,
161
- repo: context.repo.repo,
162
- comment_id: existing.id,
163
- body,
164
- });
165
- } else {
166
- await github.rest.issues.createComment({
167
- owner: context.repo.owner,
168
- repo: context.repo.repo,
169
- issue_number: context.issue.number,
170
- body,
171
- });
172
- }
@@ -1,10 +0,0 @@
1
- Agriculture & Farmland in South West Nigeria – Research Report
2
-
3
- This research document contains analysis of agricultural practices, farmland opportunities, and market conditions in South West Nigeria.
4
-
5
- Note: This is a placeholder file as I cannot directly access the Google Docs content without authentication. The original document is available at:
6
- https://docs.google.com/document/d/1DHhVPN13Gjg9roFwUlpcRcT_EFwEVlJOyCHuUOIhuR4/edit
7
-
8
- To access the full content, you would need to:
9
- 1. Sign in to Google Docs
10
- 2. Download the document directly from the link above
@@ -1,10 +0,0 @@
1
- Bank of America Credit Cards – Competitor Research Report
2
-
3
- This research document contains analysis of Bank of America's credit card offerings, competitive positioning, and market insights.
4
-
5
- Note: This is a placeholder file as I cannot directly access the Google Docs content without authentication. The original document is available at:
6
- https://docs.google.com/document/d/1m0xznamEn5fMASM0jbje3TPJYLrwr50ptnGYZQe9q98/edit
7
-
8
- To access the full content, you would need to:
9
- 1. Sign in to Google Docs
10
- 2. Download the document directly from the link above
@@ -1,10 +0,0 @@
1
- Customer Support Research - Feb 2026
2
-
3
- This research document contains customer support analysis, trends, and insights for February 2026.
4
-
5
- Note: This is a placeholder file as I cannot directly access the Google Docs content without authentication. The original document is available at:
6
- https://docs.google.com/document/d/1GUAahCwtMWcIuZRyOAdAVPN2qu9D6j7fvQjS9WiANxU/edit
7
-
8
- To access the full content, you would need to:
9
- 1. Sign in to Google Docs
10
- 2. Download the document directly from the link above
@@ -1,120 +0,0 @@
1
- /**
2
- * PM2 Ecosystem Config — Production-grade process management
3
- *
4
- * Features:
5
- * - Exponential backoff on crash (prevents rapid restart loops)
6
- * - Max memory restart (prevents memory leaks)
7
- * - Graceful shutdown with kill timeout
8
- * - Log rotation via pm2-logrotate module
9
- * - Auto-start on boot via launchd (macOS) / systemd (Linux)
10
- *
11
- * Usage:
12
- * pm2 start ecosystem.config.cjs
13
- * pm2 save # persist for auto-start on reboot
14
- */
15
-
16
- const { readFileSync } = require('fs');
17
- const { resolve } = require('path');
18
-
19
- const BASE_DIR = __dirname;
20
-
21
- // Parse .env file into object
22
- function loadEnv(filename) {
23
- const filepath = resolve(BASE_DIR, filename);
24
- try {
25
- const content = readFileSync(filepath, 'utf-8');
26
- const env = {};
27
- for (const line of content.split('\n')) {
28
- const trimmed = line.trim();
29
- if (!trimmed || trimmed.startsWith('#')) continue;
30
- const eq = trimmed.indexOf('=');
31
- if (eq === -1) continue;
32
- const key = trimmed.slice(0, eq).trim();
33
- let val = trimmed.slice(eq + 1).trim();
34
- // Strip surrounding quotes
35
- if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
36
- val = val.slice(1, -1);
37
- }
38
- env[key] = val;
39
- }
40
- return env;
41
- } catch {
42
- return {};
43
- }
44
- }
45
-
46
- const envBase = loadEnv('.env');
47
- const envFola = { ...envBase, ...loadEnv('.env.fola'), NODE_ENV: 'production', LOG_LEVEL: 'warn' };
48
- const envJohn = { ...envBase, ...loadEnv('.env.john'), NODE_ENV: 'production', LOG_LEVEL: 'warn' };
49
- const envEnterprise = { ...envBase, NODE_ENV: 'production', LOG_LEVEL: 'warn' };
50
-
51
- // Shared restart policy
52
- const RESTART_POLICY = {
53
- autorestart: true,
54
- max_restarts: 50,
55
- min_uptime: '10s',
56
- exp_backoff_restart_delay: 1500,
57
- kill_timeout: 10000,
58
- watch: false,
59
- };
60
-
61
- // Shared log config
62
- function logConfig(name) {
63
- return {
64
- error_file: resolve(BASE_DIR, `logs/${name}-error.log`),
65
- out_file: resolve(BASE_DIR, `logs/${name}-out.log`),
66
- log_date_format: 'YYYY-MM-DD HH:mm:ss',
67
- merge_logs: true,
68
- };
69
- }
70
-
71
- module.exports = {
72
- apps: [
73
- {
74
- name: 'enterprise',
75
- script: 'dist/cli.js',
76
- args: 'serve',
77
- cwd: BASE_DIR,
78
- node_args: '--max-old-space-size=512',
79
- env: envEnterprise,
80
- max_memory_restart: '512M',
81
- listen_timeout: 15000,
82
- ...RESTART_POLICY,
83
- ...logConfig('enterprise'),
84
- },
85
- {
86
- name: 'fola-agent',
87
- script: 'dist/cli.js',
88
- args: 'agent',
89
- cwd: BASE_DIR,
90
- node_args: '--max-old-space-size=384',
91
- env: envFola,
92
- max_memory_restart: '384M',
93
- ...RESTART_POLICY,
94
- ...logConfig('fola'),
95
- },
96
- {
97
- name: 'john-agent',
98
- script: 'dist/cli.js',
99
- args: 'agent',
100
- cwd: BASE_DIR,
101
- node_args: '--max-old-space-size=384',
102
- env: envJohn,
103
- max_memory_restart: '384M',
104
- ...RESTART_POLICY,
105
- ...logConfig('john'),
106
- },
107
- {
108
- name: 'cloudflared',
109
- script: 'cloudflared',
110
- args: 'tunnel run agenticmail',
111
- cwd: BASE_DIR,
112
- interpreter: 'none',
113
- max_memory_restart: '128M',
114
- ...RESTART_POLICY,
115
- max_restarts: 100,
116
- exp_backoff_restart_delay: 3000,
117
- ...logConfig('cloudflared'),
118
- },
119
- ],
120
- };
@@ -1,92 +0,0 @@
1
- DOCS TEMPLATE — All doc pages must follow this exact structure:
2
-
3
- FILE: /Users/ope/Desktop/projects/agenticmail/enterprise/src/dashboard/docs/{page-name}.html
4
- URL: /docs/{page-name}
5
-
6
- STRUCTURE:
7
- <!DOCTYPE html>
8
- <html lang="en">
9
- <head>
10
- <meta charset="UTF-8">
11
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
12
- <title>{Page Title} — AgenticMail Enterprise</title>
13
- <style>
14
- :root {
15
- --bg-primary: #0f1117; --bg-secondary: #161822; --bg-tertiary: #1c1f2e; --bg-card: #181b28;
16
- --text-primary: #e8eaf0; --text-secondary: #9ca3b8; --text-muted: #6b7394;
17
- --accent: #6366f1; --accent-soft: rgba(99,102,241,0.12);
18
- --border: #2a2f45; --border-light: #353a52; --radius: 10px;
19
- --success: #15803d; --warning: #eab308; --danger: #ef4444;
20
- --info-soft: rgba(99,102,241,0.06);
21
- }
22
- [data-theme="light"] {
23
- --bg-primary: #d0c5a0; --bg-secondary: #ddd3b2; --bg-tertiary: #c8bc94; --bg-card: #e5dcc0;
24
- --text-primary: #2c2410; --text-secondary: #3d3520; --text-muted: #6b5e42;
25
- --accent: #2563eb; --accent-soft: rgba(37,99,235,0.1);
26
- --border: #b8ad8a; --border-light: #a89e7a; --info-soft: rgba(37,99,235,0.06);
27
- }
28
- * { box-sizing: border-box; margin: 0; padding: 0; }
29
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: var(--bg-primary); color: var(--text-primary); line-height: 1.7; padding: 32px; max-width: 900px; margin: 0 auto; }
30
- h1 { font-size: 28px; margin-bottom: 8px; }
31
- h2 { font-size: 20px; margin: 32px 0 12px; padding-bottom: 8px; border-bottom: 1px solid var(--border); }
32
- h3 { font-size: 16px; margin: 20px 0 8px; color: var(--accent); }
33
- p { margin-bottom: 12px; color: var(--text-secondary); }
34
- code { background: var(--bg-primary); border: 1px solid var(--border); padding: 2px 6px; border-radius: 4px; font-size: 13px; color: var(--accent); }
35
- pre { background: var(--bg-primary); border: 1px solid var(--border); padding: 16px; border-radius: var(--radius); overflow-x: auto; margin: 12px 0; font-size: 13px; line-height: 1.5; color: var(--text-secondary); }
36
- pre code { background: none; border: none; padding: 0; }
37
- .card { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px; margin: 16px 0; }
38
- .tip { background: var(--info-soft); border: 1px solid rgba(59,130,246,0.3); padding: 12px 16px; border-radius: var(--radius); margin: 12px 0; font-size: 13px; color: var(--text-secondary); }
39
- .warning { background: rgba(245,158,11,0.08); border: 1px solid rgba(245,158,11,0.3); padding: 12px 16px; border-radius: var(--radius); margin: 12px 0; font-size: 13px; color: var(--text-secondary); }
40
- .danger { background: rgba(239,68,68,0.08); border: 1px solid rgba(239,68,68,0.3); padding: 12px 16px; border-radius: var(--radius); margin: 12px 0; font-size: 13px; color: var(--text-secondary); }
41
- table { width: 100%; border-collapse: collapse; margin: 12px 0; font-size: 13px; }
42
- th, td { text-align: left; padding: 8px 12px; border: 1px solid var(--border); color: var(--text-secondary); }
43
- th { background: var(--bg-secondary); font-weight: 600; color: var(--text-primary); }
44
- ul, ol { padding-left: 24px; margin-bottom: 12px; color: var(--text-secondary); }
45
- li { margin-bottom: 6px; }
46
- .badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; }
47
- .badge-easy { background: rgba(21,128,61,0.2); color: var(--success); }
48
- .badge-medium { background: rgba(245,158,11,0.2); color: var(--warning); }
49
- .badge-advanced { background: rgba(239,68,68,0.2); color: var(--danger); }
50
- a { color: var(--accent); }
51
- .back { display: inline-block; margin-bottom: 20px; font-size: 13px; color: var(--text-muted); text-decoration: none; }
52
- .back:hover { color: var(--text-primary); }
53
- strong { color: var(--text-primary); }
54
- .nav-links { display: flex; gap: 12px; flex-wrap: wrap; margin: 16px 0; padding: 12px; background: var(--bg-tertiary); border-radius: var(--radius); }
55
- .nav-links a { font-size: 12px; padding: 4px 10px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 6px; text-decoration: none; }
56
- .toc { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px 20px; margin: 16px 0; }
57
- .toc h3 { margin: 0 0 8px; font-size: 14px; }
58
- .toc ul { list-style: none; padding: 0; }
59
- .toc li { margin: 4px 0; }
60
- .toc a { font-size: 13px; text-decoration: none; }
61
- </style>
62
- <script>
63
- // Sync theme with dashboard
64
- var t = localStorage.getItem('em_theme') || 'dark';
65
- document.documentElement.setAttribute('data-theme', t);
66
- </script>
67
- </head>
68
- <body>
69
- <a href="javascript:history.back()" class="back">← Back to Dashboard</a>
70
- <h1>{Page Title}</h1>
71
- <p style="color: var(--text-muted); margin-bottom: 24px;">{Subtitle — what this page/feature does}</p>
72
-
73
- REQUIRED SECTIONS:
74
- 1. Table of Contents (if page has 3+ sections)
75
- 2. Overview — what it is, why it matters (both technical and non-technical explanation)
76
- 3. How It Works — step-by-step with screenshots/diagrams described
77
- 4. Key Concepts — definitions, terminology
78
- 5. Configuration / Setup — how to set it up
79
- 6. Best Practices — tips for getting the most out of it
80
- 7. Troubleshooting — common issues
81
- 8. Related Pages — links to other doc pages
82
-
83
- TONE:
84
- - Friendly but professional (like Stripe docs)
85
- - Both technical and non-technical audiences
86
- - Use .tip, .warning, .danger boxes for callouts
87
- - Use .card for grouped information
88
- - Use tables for comparisons/reference
89
- - Use code blocks for API/config examples
90
- - Research paper depth but blog post readability
91
- </content>
92
- </invoke>