@agenticmail/enterprise 0.5.320 → 0.5.322
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/dist/agent-tools-BNSTIK4P.js +13949 -0
- package/dist/chunk-7HBGXW7Z.js +4929 -0
- package/dist/chunk-RF2LGX3E.js +1519 -0
- package/dist/chunk-YCWOCIPH.js +5101 -0
- package/dist/cli-agent-ION2W5JF.js +2441 -0
- package/dist/cli-serve-53FVANQK.js +260 -0
- package/dist/cli.js +3 -3
- package/dist/index.js +3 -3
- package/dist/microsoft-2IIHDLJB.js +4159 -0
- package/dist/runtime-OVGSOTAH.js +45 -0
- package/dist/server-6NDO2S52.js +28 -0
- package/dist/setup-T6KYFR7O.js +20 -0
- package/package.json +31 -3
- package/src/agent-tools/tools/enterprise-database.ts +2 -2
- package/src/agent-tools/tools/microsoft/onedrive.ts +203 -2
- 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
|
@@ -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>
|