@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 +68 -0
- package/CODE_OF_CONDUCT.md +31 -0
- package/SECURITY.md +42 -0
- package/package.json +31 -3
- package/.github/CODEOWNERS +0 -23
- package/.github/workflows/publish-community-skills.yml +0 -121
- package/.github/workflows/validate-community-skills.yml +0 -172
- package/agriculture_southwest_nigeria_research.txt +0 -10
- package/boa_credit_cards_research.txt +0 -10
- package/customer_support_research_feb2026.txt +0 -10
- package/ecosystem.config.cjs +0 -120
- package/src/dashboard/docs/_template.txt +0 -92
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.
|
|
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://
|
|
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
|
}
|
package/.github/CODEOWNERS
DELETED
|
@@ -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
|
package/ecosystem.config.cjs
DELETED
|
@@ -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>
|