@agenticmail/enterprise 0.5.319 → 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/README.md +118 -38
- package/SECURITY.md +42 -0
- package/dist/agent-heartbeat-3FWNHZFX.js +510 -0
- package/dist/agent-heartbeat-4RWHZR7H.js +510 -0
- package/dist/agent-heartbeat-6ZGB5ILY.js +510 -0
- package/dist/agent-heartbeat-BIVHLKFM.js +510 -0
- package/dist/agent-heartbeat-HRKVFK2T.js +510 -0
- package/dist/agent-heartbeat-JC5GWVXD.js +510 -0
- package/dist/agent-heartbeat-K6A4HMHB.js +510 -0
- package/dist/agent-heartbeat-LCDXWFVB.js +510 -0
- package/dist/agent-heartbeat-P7HZCZAQ.js +510 -0
- package/dist/agent-heartbeat-PUIRSNIO.js +510 -0
- package/dist/agent-heartbeat-SN5ILQ6Y.js +510 -0
- package/dist/agent-heartbeat-TW5YTDYC.js +510 -0
- package/dist/agent-heartbeat-Z2QQXROL.js +510 -0
- package/dist/agent-notify-OEQBCZLN.js +43 -0
- package/dist/{agent-tools-263HM5QU.js → agent-tools-3W7XLUYA.js} +1 -1
- package/dist/agent-tools-4QK7LLNP.js +9 -0
- package/dist/agent-tools-54VZGT6L.js +9 -0
- package/dist/{agent-tools-AT4D276V.js → agent-tools-AYYDPO27.js} +7 -7
- package/dist/{agent-tools-MSTAPX2I.js → agent-tools-F2X47FKF.js} +7 -7
- package/dist/{agent-tools-FA26SY5O.js → agent-tools-O6W3QAZL.js} +11 -6
- package/dist/agent-tools-OAWVZBMW.js +9 -0
- package/dist/agent-tools-QCCU74PN.js +13949 -0
- package/dist/chunk-2LHUARN6.js +4929 -0
- package/dist/chunk-2WVCNCYC.js +5087 -0
- package/dist/{chunk-6PWDS7KY.js → chunk-3FM6YQUK.js} +20 -20
- package/dist/chunk-3UAFHUEC.js +212 -0
- package/dist/{chunk-WJO57PMO.js → chunk-46GOWZT4.js} +20 -20
- package/dist/{chunk-BNRE7TSX.js → chunk-5KYJAUZV.js} +3 -3
- package/dist/chunk-6C5PKREN.js +467 -0
- package/dist/{chunk-447MTPZF.js → chunk-6ZMLNEHB.js} +3 -3
- package/dist/chunk-BPZQT5N5.js +25652 -0
- package/dist/chunk-BQM7MBPS.js +1380 -0
- package/dist/{chunk-ZRFKGPIU.js → chunk-C52OQNNY.js} +20 -20
- package/dist/chunk-C7HGQF4Y.js +25652 -0
- package/dist/chunk-CAHNZGGK.js +25656 -0
- package/dist/{chunk-FL3CH3ET.js → chunk-CK7R6UHE.js} +51 -27
- package/dist/chunk-D36RPWB7.js +25652 -0
- package/dist/{chunk-36NM2B4C.js → chunk-DJK2UPFH.js} +63 -93
- package/dist/chunk-DM7FTF7W.js +4929 -0
- package/dist/chunk-DMD24UFZ.js +5101 -0
- package/dist/{chunk-36XNMIHA.js → chunk-DXZGPUAF.js} +20 -20
- package/dist/chunk-F46WB5IL.js +5087 -0
- package/dist/chunk-F5QG5SQH.js +5087 -0
- package/dist/{chunk-JGEVQZDR.js → chunk-FLQ5FLHW.js} +13 -16
- package/dist/chunk-H7GP733U.js +5087 -0
- package/dist/{chunk-OZSQLOV6.js → chunk-HHBXWB5U.js} +415 -19
- package/dist/{chunk-D24JY75H.js → chunk-IMXS4N6W.js} +3 -3
- package/dist/{chunk-6PVBV6ZP.js → chunk-JNMDD7JY.js} +3 -3
- package/dist/chunk-JTV5LA47.js +1519 -0
- package/dist/chunk-KV6G7NZX.js +1519 -0
- package/dist/chunk-MU5MEBIK.js +1519 -0
- package/dist/chunk-NLT5MC7X.js +465 -0
- package/dist/{chunk-GTFZZUXX.js → chunk-NVLYIM4J.js} +51 -27
- package/dist/{chunk-6G5SXLXC.js → chunk-NZY2BIZH.js} +63 -93
- package/dist/chunk-O42L6G67.js +1519 -0
- package/dist/chunk-OCNERGGM.js +4891 -0
- package/dist/chunk-OJSNHONE.js +1519 -0
- package/dist/{chunk-2TAZJWJN.js → chunk-OWL3QVH7.js} +18 -0
- package/dist/{chunk-P3HVY2HS.js → chunk-OWTLNV4Q.js} +382 -7
- package/dist/chunk-PCNYEP6T.js +4891 -0
- package/dist/{chunk-YL3Z5KPR.js → chunk-PI4AQ4Z6.js} +438 -15
- package/dist/chunk-PN3EGTCA.js +194 -0
- package/dist/chunk-Q37UKNRC.js +1519 -0
- package/dist/chunk-QXTC6J7H.js +5087 -0
- package/dist/{chunk-SPBQVNDI.js → chunk-RKERL5LZ.js} +25 -21
- package/dist/chunk-RVBK2IOX.js +25652 -0
- package/dist/chunk-SAKODCZ5.js +4891 -0
- package/dist/{chunk-XV4TU65E.js → chunk-SALGFC5L.js} +51 -27
- package/dist/chunk-STGWZ2MS.js +1519 -0
- package/dist/chunk-UY3ZVQDP.js +25652 -0
- package/dist/chunk-V6OSD62M.js +5087 -0
- package/dist/chunk-VP6YAHX4.js +1519 -0
- package/dist/chunk-WDYJOEAI.js +5087 -0
- package/dist/chunk-WEAFQNOS.js +195 -0
- package/dist/chunk-XKUSAZGP.js +5087 -0
- package/dist/chunk-Z6K5FKAB.js +548 -0
- package/dist/chunk-ZGE3XAXY.js +1519 -0
- package/dist/chunk-ZGYVXYQQ.js +3296 -0
- package/dist/cli-agent-7TB2BWS6.js +2370 -0
- package/dist/cli-agent-AKXFFST2.js +2370 -0
- package/dist/cli-agent-DZTKLITB.js +2357 -0
- package/dist/cli-agent-FOF7PFEP.js +2357 -0
- package/dist/cli-agent-H74M2ZYN.js +2357 -0
- package/dist/cli-agent-HORWVPHB.js +2370 -0
- package/dist/cli-agent-HSZT6SKF.js +2423 -0
- package/dist/cli-agent-JLUQ4ZU6.js +2424 -0
- package/dist/cli-agent-MVCDH4HV.js +2370 -0
- package/dist/cli-agent-NZXOEPJ2.js +2357 -0
- package/dist/cli-agent-PADN3QRC.js +2357 -0
- package/dist/cli-agent-QAYEX3BE.js +2441 -0
- package/dist/cli-agent-QT64DT5J.js +2370 -0
- package/dist/cli-agent-TFL2M6UK.js +2424 -0
- package/dist/cli-agent-UIKXATTD.js +2357 -0
- package/dist/cli-agent-UJN6FYTO.js +2370 -0
- package/dist/cli-agent-VIQAYVY4.js +2357 -0
- package/dist/cli-agent-WNWFVOFM.js +2370 -0
- package/dist/cli-agent-XBQX67VJ.js +2423 -0
- package/dist/cli-agent-ZLSC6FF4.js +2357 -0
- package/dist/cli-serve-2IL5DTEY.js +153 -0
- package/dist/cli-serve-47N5UKKW.js +153 -0
- package/dist/cli-serve-4XGZFUV2.js +140 -0
- package/dist/cli-serve-6OT3UEAN.js +140 -0
- package/dist/cli-serve-7L6EY5UH.js +153 -0
- package/dist/cli-serve-BDGOOOKQ.js +260 -0
- package/dist/cli-serve-BFNIW2LF.js +153 -0
- package/dist/cli-serve-C7MN6U5Q.js +153 -0
- package/dist/cli-serve-CR3OY3IM.js +153 -0
- package/dist/cli-serve-DAJFRWQ7.js +153 -0
- package/dist/cli-serve-FW6FHFW4.js +153 -0
- package/dist/cli-serve-GEEOQS77.js +153 -0
- package/dist/cli-serve-H562I3ZK.js +153 -0
- package/dist/cli-serve-HDQZF4C4.js +153 -0
- package/dist/cli-serve-LICAOMEB.js +140 -0
- package/dist/cli-serve-LLGYLWFS.js +153 -0
- package/dist/cli-serve-N3OISDNB.js +153 -0
- package/dist/cli-serve-TIZ27EVR.js +153 -0
- package/dist/cli-serve-TUNI2RCN.js +153 -0
- package/dist/cli-serve-WNOZMAWD.js +153 -0
- package/dist/cli-validate-Z726VJCN.js +150 -0
- package/dist/cli.js +4 -4
- package/dist/connection-manager-KAWEUWUR.js +9 -0
- package/dist/dashboard/app.js +9 -3
- package/dist/dashboard/components/knowledge-link.js +15 -0
- package/dist/dashboard/components/settings-help.js +4 -2
- package/dist/dashboard/docs/agent-deployment.html +33 -1
- package/dist/dashboard/docs/settings-network.html +321 -0
- package/dist/dashboard/docs/settings-security.html +347 -0
- package/dist/dashboard/docs/settings-tool-security.html +176 -0
- package/dist/dashboard/docs/settings.html +36 -16
- package/dist/dashboard/pages/agent-detail/deployment.js +39 -6
- package/dist/dashboard/pages/agent-detail/tools.js +10 -0
- package/dist/dashboard/pages/database-access.js +4 -3
- package/dist/dashboard/pages/settings.js +174 -37
- package/dist/dashboard/pages/task-pipeline.js +400 -843
- package/dist/db-adapter-2T56ORSD.js +7 -0
- package/dist/db-adapter-IRHOUMVC.js +7 -0
- package/dist/index.js +41 -41
- package/dist/microsoft-VREAZ7M2.js +3955 -0
- package/dist/routes-3MMLQTB6.js +90 -0
- package/dist/routes-4ZUIJ4HE.js +90 -0
- package/dist/routes-5MXHKKH4.js +90 -0
- package/dist/routes-64NJFK3B.js +90 -0
- package/dist/routes-6AKQ2LBV.js +90 -0
- package/dist/routes-CRRBUDO4.js +90 -0
- package/dist/routes-DIAF3MC3.js +90 -0
- package/dist/routes-KMUNU6CY.js +90 -0
- package/dist/routes-LRRLXIZR.js +90 -0
- package/dist/routes-N647AJYG.js +90 -0
- package/dist/routes-SSSELAAR.js +90 -0
- package/dist/routes-STERVGKJ.js +90 -0
- package/dist/routes-ZEZZACZP.js +90 -0
- package/dist/runtime-5EQN4GFM.js +45 -0
- package/dist/runtime-5LP7PUD4.js +45 -0
- package/dist/runtime-6BULDBR3.js +45 -0
- package/dist/runtime-6YEENDN3.js +45 -0
- package/dist/runtime-7LQFRG3B.js +45 -0
- package/dist/runtime-AMXJU2MB.js +45 -0
- package/dist/runtime-D6WSE7FG.js +45 -0
- package/dist/runtime-EYVN7NFJ.js +45 -0
- package/dist/runtime-F6RPWQVW.js +45 -0
- package/dist/runtime-FYMJURFC.js +45 -0
- package/dist/runtime-JRNBL4O4.js +45 -0
- package/dist/runtime-OM2NIBMI.js +45 -0
- package/dist/runtime-QWPVD7CY.js +45 -0
- package/dist/runtime-YLIIPTE4.js +45 -0
- package/dist/runtime-YU6P22CG.js +45 -0
- package/dist/screen-unlock-4RPZBHOI.js +118 -0
- package/dist/server-AMCSXINC.js +28 -0
- package/dist/server-CU6LVQS4.js +28 -0
- package/dist/server-DFYGH2CV.js +28 -0
- package/dist/server-EELWOC3X.js +28 -0
- package/dist/server-EN5E2OWQ.js +28 -0
- package/dist/server-GW2HYJYI.js +28 -0
- package/dist/server-J25NCRWJ.js +28 -0
- package/dist/server-JDGNOTFV.js +28 -0
- package/dist/server-NE5HD5DJ.js +28 -0
- package/dist/server-NQOT7W77.js +28 -0
- package/dist/server-PWE5PQTR.js +28 -0
- package/dist/server-Q2Q32H2B.js +28 -0
- package/dist/server-Q77ME7TL.js +28 -0
- package/dist/server-WLLH4WST.js +28 -0
- package/dist/server-WTUJ2O3F.js +28 -0
- package/dist/server-X4CJTHHF.js +28 -0
- package/dist/server-XK3ILCJC.js +28 -0
- package/dist/server-ZRD3NDJE.js +28 -0
- package/dist/setup-44VBAO4J.js +20 -0
- package/dist/setup-4ONNQBWB.js +20 -0
- package/dist/setup-4OSBXSCL.js +20 -0
- package/dist/setup-4QFGRBLZ.js +20 -0
- package/dist/setup-6766SGAR.js +20 -0
- package/dist/setup-AYY24DKM.js +20 -0
- package/dist/setup-B34N4HPU.js +20 -0
- package/dist/setup-E2YLC2EY.js +20 -0
- package/dist/setup-ER6NXTY5.js +20 -0
- package/dist/setup-H2AGCBW5.js +20 -0
- package/dist/setup-ICOZRKCX.js +20 -0
- package/dist/setup-JFTJH7UF.js +20 -0
- package/dist/setup-PRFNI6YW.js +20 -0
- package/dist/setup-RAHBMYHE.js +20 -0
- package/dist/setup-TXPR5UQX.js +20 -0
- package/dist/setup-XCJMELVU.js +20 -0
- package/dist/setup-XIYEIFVK.js +20 -0
- package/dist/setup-Z4PZSHBI.js +20 -0
- package/dist/skills-FR7I5V7H.js +16 -0
- package/dist/skills-HCVBA6PK.js +16 -0
- package/dist/system-prompts-TM7OA32C.js +913 -0
- package/dist/task-queue-O7IVZYUO.js +9 -0
- package/dist/transport-encryption-2T7PIXKG.js +25 -0
- package/logs/cloudflared-error.log +61 -0
- package/logs/cloudflared-out.log +0 -0
- package/logs/enterprise-error.log +0 -0
- package/logs/enterprise-out.log +3 -0
- package/logs/fola-error.log +0 -0
- package/logs/fola-out.log +0 -0
- package/logs/john-error.log +8 -0
- package/logs/john-out.log +0 -0
- package/package.json +31 -3
- package/src/agent-tools/tool-resolver.ts +50 -61
- package/src/agent-tools/tools/enterprise-database.ts +5 -5
- package/src/agent-tools/tools/local/dependency-manager.ts +2 -2
- package/src/agent-tools/tools/microsoft/graph-api.ts +137 -26
- package/src/agent-tools/tools/microsoft/outlook-mail.ts +392 -100
- package/src/agent-tools/tools/microsoft/teams.ts +267 -48
- package/src/auth/routes.ts +4 -4
- package/src/cli-agent.ts +108 -8
- package/src/cli-serve.ts +140 -0
- package/src/dashboard/app.js +9 -3
- package/src/dashboard/components/knowledge-link.js +15 -0
- package/src/dashboard/components/settings-help.js +4 -2
- package/src/dashboard/docs/agent-deployment.html +33 -1
- package/src/dashboard/docs/settings-network.html +321 -0
- package/src/dashboard/docs/settings-security.html +347 -0
- package/src/dashboard/docs/settings-tool-security.html +176 -0
- package/src/dashboard/docs/settings.html +36 -16
- package/src/dashboard/pages/agent-detail/deployment.js +39 -6
- package/src/dashboard/pages/agent-detail/tools.js +10 -0
- package/src/dashboard/pages/database-access.js +4 -3
- package/src/dashboard/pages/settings.js +174 -37
- package/src/dashboard/pages/task-pipeline.js +400 -843
- package/src/database-access/agent-tools.ts +78 -63
- package/src/database-access/connection-manager.ts +13 -2
- package/src/database-access/routes.ts +13 -1
- package/src/db/adapter.ts +1 -0
- package/src/engine/agent-memory.ts +2 -1
- package/src/engine/agent-notify.ts +50 -0
- package/src/engine/agent-routes.ts +257 -4
- package/src/engine/db-adapter.ts +16 -0
- package/src/engine/lifecycle.ts +4 -0
- package/src/engine/routes.ts +4 -3
- package/src/engine/screen-unlock.ts +136 -0
- package/src/engine/skills/database-access.ts +78 -0
- package/src/engine/skills/index.ts +3 -2
- package/src/engine/skills.ts +2 -0
- package/src/engine/task-queue-routes.ts +18 -0
- package/src/engine/task-queue.ts +15 -2
- package/src/middleware/transport-encryption.ts +1 -4
- package/src/runtime/agent-loop.ts +4 -0
- package/src/runtime/index.ts +15 -6
- package/src/server.ts +14 -1
- package/src/system-prompts/google/index.ts +1 -2
- package/src/system-prompts/index.ts +1 -1
- package/src/system-prompts/microsoft/contacts.ts +34 -0
- package/src/system-prompts/microsoft/excel.ts +52 -0
- package/src/system-prompts/microsoft/index.ts +31 -0
- package/src/system-prompts/microsoft/onedrive.ts +41 -0
- package/src/system-prompts/microsoft/onenote.ts +36 -0
- package/src/system-prompts/microsoft/outlook-calendar.ts +37 -0
- package/src/system-prompts/microsoft/outlook-mail.ts +46 -0
- package/src/system-prompts/microsoft/planner.ts +37 -0
- package/src/system-prompts/microsoft/powerbi.ts +38 -0
- package/src/system-prompts/microsoft/powerpoint.ts +35 -0
- package/src/system-prompts/microsoft/sharepoint.ts +44 -0
- package/src/system-prompts/microsoft/teams.ts +49 -0
- package/src/system-prompts/microsoft/todo.ts +37 -0
- package/src/types/hono-env.ts +4 -0
- 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/dist/agent-tools-LRA7PPXG.js +0 -13922
- package/dist/agent-tools-VAU5DOQB.js +0 -13910
- package/dist/agent-tools-VWV7OWXU.js +0 -13922
- package/dist/chunk-2Z7MWTCX.js +0 -4977
- package/dist/chunk-3T4XU3VV.js +0 -5010
- package/dist/chunk-445QM4NX.js +0 -5061
- package/dist/chunk-5TW3Y7DJ.js +0 -1519
- package/dist/chunk-6I7VY3LT.js +0 -5060
- package/dist/chunk-6W5EK3UP.js +0 -4977
- package/dist/chunk-AQMSHJQT.js +0 -5069
- package/dist/chunk-ASSQW7HX.js +0 -5051
- package/dist/chunk-CIN27FGC.js +0 -5037
- package/dist/chunk-CMXY3NUB.js +0 -4977
- package/dist/chunk-DRLMRUDP.js +0 -5052
- package/dist/chunk-EHI7Z446.js +0 -1519
- package/dist/chunk-FEAILFAQ.js +0 -1519
- package/dist/chunk-GA3PYBZL.js +0 -1519
- package/dist/chunk-GWX63G5J.js +0 -1519
- package/dist/chunk-HHMZ4UY6.js +0 -1519
- package/dist/chunk-HVQMNF7E.js +0 -4921
- package/dist/chunk-HXM7F3YN.js +0 -1519
- package/dist/chunk-K6NGOUXG.js +0 -5060
- package/dist/chunk-KPG5WINJ.js +0 -4977
- package/dist/chunk-LBCUBYDL.js +0 -1519
- package/dist/chunk-LIRQSWLR.js +0 -5014
- package/dist/chunk-LRCKO5KE.js +0 -1519
- package/dist/chunk-M7XL3DJD.js +0 -5069
- package/dist/chunk-MHJULEIQ.js +0 -1519
- package/dist/chunk-MJGGW6MC.js +0 -106
- package/dist/chunk-MMYBDHDB.js +0 -4921
- package/dist/chunk-MQT5FXKD.js +0 -1519
- package/dist/chunk-OIMPEQF5.js +0 -4977
- package/dist/chunk-OOU7JUYE.js +0 -542
- package/dist/chunk-OW4GLBHP.js +0 -1519
- package/dist/chunk-Q4K4MMLU.js +0 -4977
- package/dist/chunk-RUK4CRPF.js +0 -1519
- package/dist/chunk-T7H65XQY.js +0 -1519
- package/dist/chunk-TQVFWG57.js +0 -5064
- package/dist/chunk-UEPK3IMC.js +0 -1519
- package/dist/chunk-VUWTXJH6.js +0 -1519
- package/dist/chunk-WCPGGSAD.js +0 -1519
- package/dist/chunk-WO63NZOJ.js +0 -1519
- package/dist/chunk-YPJDRVUM.js +0 -5064
- package/dist/chunk-ZROMH5DL.js +0 -4921
- package/src/dashboard/docs/_template.txt +0 -92
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import "./chunk-KFQGP6VL.js";
|
|
2
|
+
|
|
3
|
+
// src/cli-serve.ts
|
|
4
|
+
import { existsSync, readFileSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
import { homedir } from "os";
|
|
7
|
+
function loadEnvFile() {
|
|
8
|
+
const candidates = [
|
|
9
|
+
join(process.cwd(), ".env"),
|
|
10
|
+
join(homedir(), ".agenticmail", ".env")
|
|
11
|
+
];
|
|
12
|
+
for (const envPath of candidates) {
|
|
13
|
+
if (!existsSync(envPath)) continue;
|
|
14
|
+
try {
|
|
15
|
+
const content = readFileSync(envPath, "utf8");
|
|
16
|
+
for (const line of content.split("\n")) {
|
|
17
|
+
const trimmed = line.trim();
|
|
18
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
19
|
+
const eq = trimmed.indexOf("=");
|
|
20
|
+
if (eq < 0) continue;
|
|
21
|
+
const key = trimmed.slice(0, eq).trim();
|
|
22
|
+
let val = trimmed.slice(eq + 1).trim();
|
|
23
|
+
if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
|
|
24
|
+
val = val.slice(1, -1);
|
|
25
|
+
}
|
|
26
|
+
if (!process.env[key]) process.env[key] = val;
|
|
27
|
+
}
|
|
28
|
+
console.log(`Loaded config from ${envPath}`);
|
|
29
|
+
return;
|
|
30
|
+
} catch {
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function ensureSecrets() {
|
|
35
|
+
const { randomUUID } = await import("crypto");
|
|
36
|
+
const envDir = join(homedir(), ".agenticmail");
|
|
37
|
+
const envPath = join(envDir, ".env");
|
|
38
|
+
let dirty = false;
|
|
39
|
+
if (!process.env.JWT_SECRET) {
|
|
40
|
+
process.env.JWT_SECRET = randomUUID() + randomUUID();
|
|
41
|
+
dirty = true;
|
|
42
|
+
console.log("[startup] Generated new JWT_SECRET (existing sessions will need to re-login)");
|
|
43
|
+
}
|
|
44
|
+
if (!process.env.AGENTICMAIL_VAULT_KEY) {
|
|
45
|
+
process.env.AGENTICMAIL_VAULT_KEY = randomUUID() + randomUUID();
|
|
46
|
+
dirty = true;
|
|
47
|
+
console.log("[startup] Generated new AGENTICMAIL_VAULT_KEY");
|
|
48
|
+
console.log("[startup] \u26A0\uFE0F Previously encrypted credentials will need to be re-entered in the dashboard");
|
|
49
|
+
}
|
|
50
|
+
if (dirty) {
|
|
51
|
+
try {
|
|
52
|
+
if (!existsSync(envDir)) {
|
|
53
|
+
const { mkdirSync } = await import("fs");
|
|
54
|
+
mkdirSync(envDir, { recursive: true });
|
|
55
|
+
}
|
|
56
|
+
const { appendFileSync } = await import("fs");
|
|
57
|
+
const lines = [];
|
|
58
|
+
let existing = "";
|
|
59
|
+
if (existsSync(envPath)) {
|
|
60
|
+
existing = readFileSync(envPath, "utf8");
|
|
61
|
+
}
|
|
62
|
+
if (!existing.includes("JWT_SECRET=")) {
|
|
63
|
+
lines.push(`JWT_SECRET=${process.env.JWT_SECRET}`);
|
|
64
|
+
}
|
|
65
|
+
if (!existing.includes("AGENTICMAIL_VAULT_KEY=")) {
|
|
66
|
+
lines.push(`AGENTICMAIL_VAULT_KEY=${process.env.AGENTICMAIL_VAULT_KEY}`);
|
|
67
|
+
}
|
|
68
|
+
if (lines.length) {
|
|
69
|
+
appendFileSync(envPath, "\n" + lines.join("\n") + "\n", { mode: 384 });
|
|
70
|
+
console.log(`[startup] Saved secrets to ${envPath}`);
|
|
71
|
+
}
|
|
72
|
+
} catch (e) {
|
|
73
|
+
console.warn(`[startup] Could not save secrets to ${envPath}: ${e.message}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async function runServe(_args) {
|
|
78
|
+
loadEnvFile();
|
|
79
|
+
const DATABASE_URL = process.env.DATABASE_URL;
|
|
80
|
+
const PORT = parseInt(process.env.PORT || "8080", 10);
|
|
81
|
+
await ensureSecrets();
|
|
82
|
+
const JWT_SECRET = process.env.JWT_SECRET;
|
|
83
|
+
const VAULT_KEY = process.env.AGENTICMAIL_VAULT_KEY;
|
|
84
|
+
if (!DATABASE_URL) {
|
|
85
|
+
console.error("ERROR: DATABASE_URL is required.");
|
|
86
|
+
console.error("");
|
|
87
|
+
console.error("Set it via environment variable or .env file:");
|
|
88
|
+
console.error(" DATABASE_URL=postgresql://user:pass@host:5432/db npx @agenticmail/enterprise start");
|
|
89
|
+
console.error("");
|
|
90
|
+
console.error("Or create a .env file (in cwd or ~/.agenticmail/.env):");
|
|
91
|
+
console.error(" DATABASE_URL=postgresql://user:pass@host:5432/db");
|
|
92
|
+
console.error(" JWT_SECRET=your-secret-here");
|
|
93
|
+
console.error(" PORT=3200");
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
const { createAdapter, smartDbConfig } = await import("./factory-MQASIPEB.js");
|
|
97
|
+
const { createServer } = await import("./server-DFYGH2CV.js");
|
|
98
|
+
const db = await createAdapter(smartDbConfig(DATABASE_URL));
|
|
99
|
+
await db.migrate();
|
|
100
|
+
const server = createServer({
|
|
101
|
+
port: PORT,
|
|
102
|
+
db,
|
|
103
|
+
jwtSecret: JWT_SECRET,
|
|
104
|
+
corsOrigins: ["*"]
|
|
105
|
+
});
|
|
106
|
+
await server.start();
|
|
107
|
+
console.log(`AgenticMail Enterprise server running on :${PORT}`);
|
|
108
|
+
try {
|
|
109
|
+
const { startPreventSleep } = await import("./screen-unlock-4RPZBHOI.js");
|
|
110
|
+
const adminDb = server.getAdminDb?.() || server.adminDb;
|
|
111
|
+
if (adminDb) {
|
|
112
|
+
const settings = await adminDb.getSettings?.().catch(() => null);
|
|
113
|
+
const screenAccess = settings?.securityConfig?.screenAccess;
|
|
114
|
+
if (screenAccess?.enabled && screenAccess?.preventSleep) {
|
|
115
|
+
startPreventSleep();
|
|
116
|
+
console.log("[startup] Prevent-sleep enabled \u2014 system will stay awake while agents are active");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
} catch {
|
|
120
|
+
}
|
|
121
|
+
const tunnelToken = process.env.CLOUDFLARED_TOKEN;
|
|
122
|
+
if (tunnelToken) {
|
|
123
|
+
try {
|
|
124
|
+
const { execSync, spawn } = await import("child_process");
|
|
125
|
+
try {
|
|
126
|
+
execSync("which cloudflared", { timeout: 3e3 });
|
|
127
|
+
} catch {
|
|
128
|
+
console.log("[startup] cloudflared not found \u2014 skipping tunnel auto-start");
|
|
129
|
+
console.log("[startup] Install cloudflared to enable tunnel: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/");
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
execSync('pgrep -f "cloudflared.*tunnel.*run"', { timeout: 3e3 });
|
|
134
|
+
console.log("[startup] cloudflared tunnel already running");
|
|
135
|
+
return;
|
|
136
|
+
} catch {
|
|
137
|
+
}
|
|
138
|
+
const subdomain = process.env.AGENTICMAIL_SUBDOMAIN || process.env.AGENTICMAIL_DOMAIN || "";
|
|
139
|
+
console.log(`[startup] Starting cloudflared tunnel${subdomain ? ` for ${subdomain}.agenticmail.io` : ""}...`);
|
|
140
|
+
const child = spawn("cloudflared", ["tunnel", "--no-autoupdate", "run", "--token", tunnelToken], {
|
|
141
|
+
detached: true,
|
|
142
|
+
stdio: "ignore"
|
|
143
|
+
});
|
|
144
|
+
child.unref();
|
|
145
|
+
console.log("[startup] cloudflared tunnel started (pid " + child.pid + ")");
|
|
146
|
+
} catch (e) {
|
|
147
|
+
console.warn("[startup] Could not auto-start cloudflared: " + e.message);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
export {
|
|
152
|
+
runServe
|
|
153
|
+
};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ALL_TOOLS,
|
|
3
|
+
init_tool_catalog
|
|
4
|
+
} from "./chunk-ZGYVXYQQ.js";
|
|
5
|
+
import {
|
|
6
|
+
collectCommunityToolIds,
|
|
7
|
+
init_skill_validator,
|
|
8
|
+
validateSkillManifest
|
|
9
|
+
} from "./chunk-22U7TZPN.js";
|
|
10
|
+
import "./chunk-KFQGP6VL.js";
|
|
11
|
+
|
|
12
|
+
// src/engine/cli-validate.ts
|
|
13
|
+
init_skill_validator();
|
|
14
|
+
init_tool_catalog();
|
|
15
|
+
async function runValidate(args) {
|
|
16
|
+
const chalk = (await import("chalk")).default;
|
|
17
|
+
const fs = await import("fs/promises");
|
|
18
|
+
const path = await import("path");
|
|
19
|
+
const jsonMode = args.includes("--json");
|
|
20
|
+
const allMode = args.includes("--all");
|
|
21
|
+
const pathArgs = args.filter((a) => !a.startsWith("--"));
|
|
22
|
+
const builtinIds = new Set(ALL_TOOLS.map((t) => t.id || t.name));
|
|
23
|
+
const communityDir = path.resolve(process.cwd(), "community-skills");
|
|
24
|
+
const reports = [];
|
|
25
|
+
if (allMode) {
|
|
26
|
+
let entries;
|
|
27
|
+
try {
|
|
28
|
+
entries = await fs.readdir(communityDir, { withFileTypes: true });
|
|
29
|
+
} catch {
|
|
30
|
+
if (jsonMode) {
|
|
31
|
+
console.log(JSON.stringify({ error: "community-skills/ directory not found" }));
|
|
32
|
+
} else {
|
|
33
|
+
console.error(chalk.red("Error: community-skills/ directory not found"));
|
|
34
|
+
}
|
|
35
|
+
process.exit(1);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
if (!entry.isDirectory() || entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
40
|
+
const skillDir = path.join(communityDir, entry.name);
|
|
41
|
+
const report = await validatePath(skillDir, builtinIds, communityDir);
|
|
42
|
+
reports.push(report);
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
const target = pathArgs[0];
|
|
46
|
+
if (!target) {
|
|
47
|
+
if (jsonMode) {
|
|
48
|
+
console.log(JSON.stringify({ error: "No path specified. Usage: npx @agenticmail/enterprise validate <path> [--all] [--json]" }));
|
|
49
|
+
} else {
|
|
50
|
+
console.log(`${chalk.bold("Usage:")} npx @agenticmail/enterprise validate <path>`);
|
|
51
|
+
console.log("");
|
|
52
|
+
console.log(" <path> Path to a skill directory or agenticmail-skill.json file");
|
|
53
|
+
console.log(" --all Validate all skills in community-skills/");
|
|
54
|
+
console.log(" --json Machine-readable JSON output");
|
|
55
|
+
}
|
|
56
|
+
process.exit(1);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const report = await validatePath(path.resolve(target), builtinIds, communityDir);
|
|
60
|
+
reports.push(report);
|
|
61
|
+
}
|
|
62
|
+
if (jsonMode) {
|
|
63
|
+
console.log(JSON.stringify({ results: reports, totalErrors: reports.reduce((s, r) => s + r.errors.length, 0) }, null, 2));
|
|
64
|
+
} else {
|
|
65
|
+
console.log("");
|
|
66
|
+
for (const report of reports) {
|
|
67
|
+
if (report.valid) {
|
|
68
|
+
console.log(chalk.green(" \u2714") + " " + chalk.bold(report.skillId) + chalk.dim(` (${report.path})`));
|
|
69
|
+
} else {
|
|
70
|
+
console.log(chalk.red(" \u2718") + " " + chalk.bold(report.skillId) + chalk.dim(` (${report.path})`));
|
|
71
|
+
for (const err of report.errors) {
|
|
72
|
+
console.log(chalk.red(" \u2502 ") + err);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
for (const warn of report.warnings) {
|
|
76
|
+
console.log(chalk.yellow(" \u26A0 ") + warn);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
console.log("");
|
|
80
|
+
const passed = reports.filter((r) => r.valid).length;
|
|
81
|
+
const failed = reports.filter((r) => !r.valid).length;
|
|
82
|
+
if (failed > 0) {
|
|
83
|
+
console.log(chalk.red(` ${failed} failed`) + chalk.dim(`, ${passed} passed, ${reports.length} total`));
|
|
84
|
+
} else {
|
|
85
|
+
console.log(chalk.green(` ${passed} passed`) + chalk.dim(`, ${reports.length} total`));
|
|
86
|
+
}
|
|
87
|
+
console.log("");
|
|
88
|
+
}
|
|
89
|
+
if (reports.some((r) => !r.valid)) {
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function validatePath(targetPath, builtinIds, communityDir) {
|
|
94
|
+
const fs = await import("fs/promises");
|
|
95
|
+
const path = await import("path");
|
|
96
|
+
let manifestPath;
|
|
97
|
+
try {
|
|
98
|
+
const stat = await fs.stat(targetPath);
|
|
99
|
+
if (stat.isDirectory()) {
|
|
100
|
+
manifestPath = path.join(targetPath, "agenticmail-skill.json");
|
|
101
|
+
} else {
|
|
102
|
+
manifestPath = targetPath;
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
return {
|
|
106
|
+
path: targetPath,
|
|
107
|
+
skillId: path.basename(targetPath),
|
|
108
|
+
valid: false,
|
|
109
|
+
errors: [`Path not found: ${targetPath}`],
|
|
110
|
+
warnings: []
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
let raw;
|
|
114
|
+
try {
|
|
115
|
+
raw = await fs.readFile(manifestPath, "utf-8");
|
|
116
|
+
} catch {
|
|
117
|
+
return {
|
|
118
|
+
path: manifestPath,
|
|
119
|
+
skillId: path.basename(path.dirname(manifestPath)),
|
|
120
|
+
valid: false,
|
|
121
|
+
errors: [`Cannot read: ${manifestPath}`],
|
|
122
|
+
warnings: []
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
let manifest;
|
|
126
|
+
try {
|
|
127
|
+
manifest = JSON.parse(raw);
|
|
128
|
+
} catch (err) {
|
|
129
|
+
return {
|
|
130
|
+
path: manifestPath,
|
|
131
|
+
skillId: path.basename(path.dirname(manifestPath)),
|
|
132
|
+
valid: false,
|
|
133
|
+
errors: [`Invalid JSON: ${err.message}`],
|
|
134
|
+
warnings: []
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
const communityIds = await collectCommunityToolIds(communityDir, manifest.id);
|
|
138
|
+
const allExistingIds = /* @__PURE__ */ new Set([...builtinIds, ...communityIds]);
|
|
139
|
+
const result = validateSkillManifest(manifest, { existingToolIds: allExistingIds });
|
|
140
|
+
return {
|
|
141
|
+
path: manifestPath,
|
|
142
|
+
skillId: manifest.id || path.basename(path.dirname(manifestPath)),
|
|
143
|
+
valid: result.valid,
|
|
144
|
+
errors: result.errors,
|
|
145
|
+
warnings: result.warnings
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
export {
|
|
149
|
+
runValidate
|
|
150
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -5,7 +5,7 @@ var args = process.argv.slice(2);
|
|
|
5
5
|
var command = args[0];
|
|
6
6
|
switch (command) {
|
|
7
7
|
case "validate":
|
|
8
|
-
import("./cli-validate-
|
|
8
|
+
import("./cli-validate-Z726VJCN.js").then((m) => m.runValidate(args.slice(1))).catch(fatal);
|
|
9
9
|
break;
|
|
10
10
|
case "build-skill":
|
|
11
11
|
import("./cli-build-skill-2IOE7MYP.js").then((m) => m.runBuildSkill(args.slice(1))).catch(fatal);
|
|
@@ -57,14 +57,14 @@ Skill Development:
|
|
|
57
57
|
break;
|
|
58
58
|
case "serve":
|
|
59
59
|
case "start":
|
|
60
|
-
import("./cli-serve-
|
|
60
|
+
import("./cli-serve-BDGOOOKQ.js").then((m) => m.runServe(args.slice(1))).catch(fatal);
|
|
61
61
|
break;
|
|
62
62
|
case "agent":
|
|
63
|
-
import("./cli-agent-
|
|
63
|
+
import("./cli-agent-QAYEX3BE.js").then((m) => m.runAgent(args.slice(1))).catch(fatal);
|
|
64
64
|
break;
|
|
65
65
|
case "setup":
|
|
66
66
|
default:
|
|
67
|
-
import("./setup-
|
|
67
|
+
import("./setup-4OSBXSCL.js").then((m) => m.runSetupWizard()).catch(fatal);
|
|
68
68
|
break;
|
|
69
69
|
}
|
|
70
70
|
function fatal(err) {
|
package/dist/dashboard/app.js
CHANGED
|
@@ -156,7 +156,8 @@ function App() {
|
|
|
156
156
|
const [selectedOrgId, setSelectedOrgId] = useState('');
|
|
157
157
|
const [selectedOrg, setSelectedOrg] = useState(null);
|
|
158
158
|
const [orgVersion, setOrgVersion] = useState(0);
|
|
159
|
-
const
|
|
159
|
+
const [companyName, setCompanyName] = useState((window.__EM_BRANDING__ && window.__EM_BRANDING__.companyName) || '');
|
|
160
|
+
const onOrgChange = useCallback((id, org) => { setSelectedOrgId(id); setSelectedOrg(org); setOrgVersion(v => v + 1); if (org && org.name) setCompanyName(org.name); }, []);
|
|
160
161
|
|
|
161
162
|
// Check if already authenticated via cookie on mount, and check setup state
|
|
162
163
|
useEffect(() => {
|
|
@@ -189,6 +190,11 @@ function App() {
|
|
|
189
190
|
if (window.__transportEncryption) await window.__transportEncryption.waitForReady();
|
|
190
191
|
}
|
|
191
192
|
} catch {}
|
|
193
|
+
// Fetch company name for sidebar
|
|
194
|
+
try {
|
|
195
|
+
var s = await apiCall('/settings');
|
|
196
|
+
if (s && s.name) setCompanyName(s.name);
|
|
197
|
+
} catch {}
|
|
192
198
|
setAuthed(true);
|
|
193
199
|
setAuthChecked(true);
|
|
194
200
|
}).catch(() => setAuthChecked(true));
|
|
@@ -457,7 +463,7 @@ function App() {
|
|
|
457
463
|
const PageComponent = canAccessPage ? (pages[page] || DashboardPage) : null;
|
|
458
464
|
const sidebarClass = 'sidebar' + (sidebarPinned ? ' expanded' : sidebarHovered ? ' hover-expanded' : '') + (mobileMenuOpen ? ' mobile-open' : '');
|
|
459
465
|
|
|
460
|
-
return h(AppContext.Provider, { value: { toast, toasts, user, theme, setPage, permissions, impersonating, startImpersonation, stopImpersonation, selectedOrgId, selectedOrg, onOrgChange } },
|
|
466
|
+
return h(AppContext.Provider, { value: { toast, toasts, user, theme, setPage, permissions, impersonating, startImpersonation, stopImpersonation, selectedOrgId, selectedOrg, onOrgChange, companyName, setCompanyName } },
|
|
461
467
|
h('div', { className: 'app-layout' },
|
|
462
468
|
// Mobile hamburger
|
|
463
469
|
h('button', { className: 'mobile-hamburger', onClick: () => setMobileMenuOpen(true) },
|
|
@@ -473,7 +479,7 @@ function App() {
|
|
|
473
479
|
h('div', { className: sidebarClass, onMouseEnter: onSidebarEnter, onMouseLeave: onSidebarLeave },
|
|
474
480
|
h('div', { className: 'sidebar-brand' },
|
|
475
481
|
h('img', { src: (window.__EM_BRANDING__ && window.__EM_BRANDING__.logo) || '/dashboard/assets/logo.png', alt: 'AgenticMail', style: { width: 28, height: 28, objectFit: 'contain' } }),
|
|
476
|
-
h('div', { className: 'sidebar-brand-text' }, h('h2', null,
|
|
482
|
+
h('div', { className: 'sidebar-brand-text' }, h('h2', null, companyName || 'AgenticMail'), h('span', null, 'Enterprise')),
|
|
477
483
|
h('button', { className: 'sidebar-toggle' + (sidebarPinned ? ' pinned' : ''), onClick: toggleSidebarPin, title: sidebarPinned ? 'Unpin sidebar' : 'Pin sidebar' }, sidebarPinned ? I.chevronLeft() : I.panelLeft())
|
|
478
484
|
),
|
|
479
485
|
h('div', { className: 'sidebar-nav' },
|
|
@@ -62,3 +62,18 @@ export var AGENT_TAB_DOCS = {
|
|
|
62
62
|
deployment: 'agent-deployment',
|
|
63
63
|
'memory-transfer': 'memory-transfer',
|
|
64
64
|
};
|
|
65
|
+
|
|
66
|
+
/** Map of settings tab IDs to doc filenames */
|
|
67
|
+
export var SETTINGS_TAB_DOCS = {
|
|
68
|
+
general: 'settings',
|
|
69
|
+
models: 'settings',
|
|
70
|
+
'api-keys': 'settings',
|
|
71
|
+
authentication: 'settings',
|
|
72
|
+
platform: 'settings',
|
|
73
|
+
email: 'settings',
|
|
74
|
+
deployments: 'settings',
|
|
75
|
+
'security-system': 'settings-security',
|
|
76
|
+
'tool-security': 'settings-tool-security',
|
|
77
|
+
network: 'settings-network',
|
|
78
|
+
integrations: 'settings',
|
|
79
|
+
};
|
|
@@ -138,7 +138,8 @@ export var SETTINGS_HELP = {
|
|
|
138
138
|
h('li', null, h('strong', null, 'Rate Limiting'), ' \u2014 Limits how many times each tool can be called per minute per agent. Prevents any single agent from overwhelming the system. Adjust limits per tool type in the table.'),
|
|
139
139
|
h('li', null, h('strong', null, 'Circuit Breaker'), ' \u2014 Automatically pauses a tool that keeps failing (after 5 consecutive errors). Waits 30 seconds before retrying. Prevents error cascading when an external service is down.'),
|
|
140
140
|
h('li', null, h('strong', null, 'Telemetry'), ' \u2014 Collects performance metrics: call duration, success rates, and output sizes. Useful for identifying slow tools or agents using resources inefficiently.')
|
|
141
|
-
)
|
|
141
|
+
),
|
|
142
|
+
h('p', { style: { marginTop: 12 } }, h('a', { href: '/docs/settings-tool-security', style: { fontSize: 12 } }, 'View full Tool Security documentation \u2192'))
|
|
142
143
|
);
|
|
143
144
|
}
|
|
144
145
|
},
|
|
@@ -163,7 +164,8 @@ export var SETTINGS_HELP = {
|
|
|
163
164
|
h('li', null, h('strong', null, 'Rate Limiting'), ' \u2014 Limits API requests per IP per minute. Protects against abuse and denial-of-service. "Skip Paths" excludes health-check endpoints.'),
|
|
164
165
|
h('li', null, h('strong', null, 'HTTPS Enforcement'), ' \u2014 Forces all connections to use encrypted HTTPS. Highly recommended for production.'),
|
|
165
166
|
h('li', null, h('strong', null, 'Security Headers'), ' \u2014 Browser security policies: HSTS forces HTTPS, X-Frame-Options prevents clickjacking, Content-Type-Options prevents MIME sniffing. The defaults are recommended for most deployments.')
|
|
166
|
-
)
|
|
167
|
+
),
|
|
168
|
+
h('p', { style: { marginTop: 12 } }, h('a', { href: '/docs/settings-network', style: { fontSize: 12 } }, 'View full Network & Firewall documentation \u2192'))
|
|
167
169
|
);
|
|
168
170
|
}
|
|
169
171
|
},
|
|
@@ -162,12 +162,39 @@
|
|
|
162
162
|
<h3 id="local">Local (In-Process)</h3>
|
|
163
163
|
<p>For development and single-server deployments:</p>
|
|
164
164
|
<ul>
|
|
165
|
-
<li><strong>Port</strong> — HTTP port the agent listens on.</li>
|
|
165
|
+
<li><strong>Port</strong> — HTTP port the agent listens on. Validated in real-time (see below).</li>
|
|
166
166
|
<li><strong>Host</strong> — Hostname or IP (default: localhost).</li>
|
|
167
167
|
<li><strong>Process Manager</strong> — PM2 (with install detection), systemd, Manual, or In-Process (embedded).</li>
|
|
168
168
|
<li><strong>Process Name</strong> — PM2/systemd service name for lifecycle management.</li>
|
|
169
169
|
<li><strong>Working Directory</strong> — Auto-detected or manually specified.</li>
|
|
170
170
|
</ul>
|
|
171
|
+
|
|
172
|
+
<h4>Port Validation</h4>
|
|
173
|
+
<p>When you enter a port number, the system automatically checks whether it's available before allowing you to save:</p>
|
|
174
|
+
<div class="card">
|
|
175
|
+
<table>
|
|
176
|
+
<thead><tr><th>Indicator</th><th>Meaning</th></tr></thead>
|
|
177
|
+
<tbody>
|
|
178
|
+
<tr><td><strong style="color:var(--success)">Green border + checkmark</strong></td><td>Port is available — you can save and deploy.</td></tr>
|
|
179
|
+
<tr><td><strong style="color:var(--danger)">Red border + error</strong></td><td>Port is already in use — save is blocked. The error shows which process is using it (e.g., "Port 3100 is in use by node (PID 12345)").</td></tr>
|
|
180
|
+
</tbody>
|
|
181
|
+
</table>
|
|
182
|
+
</div>
|
|
183
|
+
<ul>
|
|
184
|
+
<li><strong>Debounced</strong> — Validation triggers 500ms after you stop typing, preventing excessive API calls.</li>
|
|
185
|
+
<li><strong>Bind test</strong> — Uses <code>net.createServer()</code> to attempt binding the port. This is the most reliable availability check.</li>
|
|
186
|
+
<li><strong>Process identification</strong> — If the port is in use, the system runs <code>lsof</code> (macOS/Linux) or <code>netstat</code> (Windows) to identify the process name and PID.</li>
|
|
187
|
+
<li><strong>Save blocked</strong> — You cannot save deployment configuration while a port conflict exists.</li>
|
|
188
|
+
</ul>
|
|
189
|
+
|
|
190
|
+
<div class="card">
|
|
191
|
+
<h3>API Reference</h3>
|
|
192
|
+
<pre><code>POST /system/check-port
|
|
193
|
+
Body: { "port": 4100 }
|
|
194
|
+
Response (available): { "available": true, "port": 3102 }
|
|
195
|
+
Response (in use): { "available": false, "port": 3102, "process": "node (PID 12345)" }</code></pre>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
171
198
|
<div class="tip">
|
|
172
199
|
<strong>Tip:</strong> PM2 availability is auto-detected. If PM2 isn't installed, the dashboard offers a one-click "Install PM2" button.
|
|
173
200
|
</div>
|
|
@@ -268,6 +295,11 @@ Response: { "agentId": "...", "assigned": ["kb-1", "kb-2"], "count": 2 }</code><
|
|
|
268
295
|
<p>The agent process may have crashed. Check logs on the deployment platform. Common causes: missing environment variables, incorrect model configuration, or insufficient memory.</p>
|
|
269
296
|
</div>
|
|
270
297
|
|
|
298
|
+
<div class="card">
|
|
299
|
+
<h3>Port is in use — can't save</h3>
|
|
300
|
+
<p>The port validation detected another process using the port. Either change the port number or stop the conflicting process. The error message shows the process name and PID — you can stop it with <code>kill <PID></code> or choose a different port. Common conflicts: another agent already running on that port, or a development server.</p>
|
|
301
|
+
</div>
|
|
302
|
+
|
|
271
303
|
<div class="card">
|
|
272
304
|
<h3>Delete confirmation name doesn't match</h3>
|
|
273
305
|
<p>The typed name must match exactly (case-insensitive) with the agent's display name. Check the agent name shown in the header.</p>
|