@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
|
@@ -263,7 +263,9 @@ export function createAgentRoutes(opts: {
|
|
|
263
263
|
router.put('/agents/:id/budget', async (c) => {
|
|
264
264
|
const config = await c.req.json();
|
|
265
265
|
try {
|
|
266
|
-
|
|
266
|
+
const aid = c.req.param('id');
|
|
267
|
+
await lifecycle.setBudgetConfig(aid, config);
|
|
268
|
+
import('./agent-notify.js').then(({ notifyAgent }) => notifyAgent(aid, 'budget', lifecycle)).catch(() => {});
|
|
267
269
|
return c.json({ success: true, budgetConfig: config });
|
|
268
270
|
} catch (e: any) {
|
|
269
271
|
return c.json({ error: e.message }, 400);
|
|
@@ -366,6 +368,178 @@ export function createAgentRoutes(opts: {
|
|
|
366
368
|
}
|
|
367
369
|
});
|
|
368
370
|
|
|
371
|
+
// ─── Port Availability Check ──────────────────────────────
|
|
372
|
+
|
|
373
|
+
router.post('/system/check-port', async (c) => {
|
|
374
|
+
try {
|
|
375
|
+
const { port } = await c.req.json();
|
|
376
|
+
const p = parseInt(port);
|
|
377
|
+
if (!p || p < 1 || p > 65535) {
|
|
378
|
+
return c.json({ available: false, error: 'Invalid port number (1-65535)' });
|
|
379
|
+
}
|
|
380
|
+
// Try to bind to the port on all interfaces to check availability
|
|
381
|
+
const net = await import('net');
|
|
382
|
+
const tryBind = (host: string) => new Promise<boolean>((resolve) => {
|
|
383
|
+
const server = net.createServer();
|
|
384
|
+
server.once('error', () => resolve(false));
|
|
385
|
+
server.once('listening', () => { server.close(() => resolve(true)); });
|
|
386
|
+
server.listen(p, host);
|
|
387
|
+
});
|
|
388
|
+
// Check both 0.0.0.0 and 127.0.0.1 — a port is only available if free on both
|
|
389
|
+
const [availAll, availLocal] = await Promise.all([tryBind('0.0.0.0'), tryBind('127.0.0.1')]);
|
|
390
|
+
const available = availAll && availLocal;
|
|
391
|
+
if (!available) {
|
|
392
|
+
// Try to identify what's using it
|
|
393
|
+
let processInfo = '';
|
|
394
|
+
try {
|
|
395
|
+
const { execSync } = await import('child_process');
|
|
396
|
+
if (process.platform === 'darwin' || process.platform === 'linux') {
|
|
397
|
+
const lsofBin = process.platform === 'darwin' ? '/usr/sbin/lsof' : 'lsof';
|
|
398
|
+
const out = execSync(`${lsofBin} -i :${p} -P -n 2>/dev/null | head -5`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 3000 }).trim();
|
|
399
|
+
if (out) {
|
|
400
|
+
const lines = out.split('\n').slice(1); // skip header
|
|
401
|
+
if (lines.length > 0) {
|
|
402
|
+
const parts = lines[0].split(/\s+/);
|
|
403
|
+
processInfo = parts[0] ? `${parts[0]} (PID ${parts[1]})` : '';
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
} else if (process.platform === 'win32') {
|
|
407
|
+
const out = execSync(`netstat -ano | findstr :${p}`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 3000 }).trim();
|
|
408
|
+
if (out) {
|
|
409
|
+
const parts = out.split(/\s+/);
|
|
410
|
+
processInfo = `PID ${parts[parts.length - 1]}`;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
} catch {}
|
|
414
|
+
return c.json({ available: false, port: p, inUse: true, process: processInfo || 'Unknown process' });
|
|
415
|
+
}
|
|
416
|
+
return c.json({ available: true, port: p });
|
|
417
|
+
} catch (e: any) {
|
|
418
|
+
return c.json({ available: false, error: e.message });
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// ─── Screen Unlock ──────────────────────────────────────
|
|
423
|
+
|
|
424
|
+
router.post('/system/unlock-screen', async (c) => {
|
|
425
|
+
try {
|
|
426
|
+
const platform = process.platform;
|
|
427
|
+
if (platform === 'darwin') {
|
|
428
|
+
// macOS: Use AppleScript via osascript to wake and unlock
|
|
429
|
+
const { execSync } = await import('child_process');
|
|
430
|
+
// First wake the display
|
|
431
|
+
try { execSync('caffeinate -u -t 2', { stdio: 'pipe', timeout: 5000 }); } catch {}
|
|
432
|
+
// Check if screen is locked
|
|
433
|
+
const isLocked = (() => {
|
|
434
|
+
try {
|
|
435
|
+
const out = execSync('python3 -c "import Quartz; d=Quartz.CGSessionCopyCurrentDictionary(); print(d.get(\'CGSSessionScreenIsLocked\', 0))"', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 3000 }).trim();
|
|
436
|
+
return out === '1' || out === 'True';
|
|
437
|
+
} catch {
|
|
438
|
+
// Fallback: check if loginwindow is frontmost
|
|
439
|
+
try {
|
|
440
|
+
const out = execSync('osascript -e \'tell application "System Events" to get name of first application process whose frontmost is true\'', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 3000 }).trim();
|
|
441
|
+
return out === 'loginwindow' || out === 'ScreenSaverEngine';
|
|
442
|
+
} catch { return false; }
|
|
443
|
+
}
|
|
444
|
+
})();
|
|
445
|
+
if (!isLocked) {
|
|
446
|
+
return c.json({ success: true, wasLocked: false, message: 'Screen is already unlocked' });
|
|
447
|
+
}
|
|
448
|
+
// Get password from agent's security config or request body
|
|
449
|
+
const body = await c.req.json().catch(() => ({}));
|
|
450
|
+
const password = body.password;
|
|
451
|
+
if (!password) {
|
|
452
|
+
return c.json({ success: false, locked: true, error: 'Screen is locked but no password provided. Configure the system password in Settings > Security or the agent\'s Permissions tab.' });
|
|
453
|
+
}
|
|
454
|
+
// Use cliclick or AppleScript to type password and press Enter
|
|
455
|
+
// Method 1: Use osascript to simulate keystrokes at the login window
|
|
456
|
+
try {
|
|
457
|
+
execSync(`osascript -e 'tell application "System Events" to keystroke "${password.replace(/["\\]/g, '\\$&')}"' -e 'delay 0.3' -e 'tell application "System Events" to key code 36'`, {
|
|
458
|
+
stdio: 'pipe', timeout: 10000
|
|
459
|
+
});
|
|
460
|
+
// Wait a moment and check if unlocked
|
|
461
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
462
|
+
const stillLocked = (() => {
|
|
463
|
+
try {
|
|
464
|
+
const out = execSync('python3 -c "import Quartz; d=Quartz.CGSessionCopyCurrentDictionary(); print(d.get(\'CGSSessionScreenIsLocked\', 0))"', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 3000 }).trim();
|
|
465
|
+
return out === '1' || out === 'True';
|
|
466
|
+
} catch { return false; }
|
|
467
|
+
})();
|
|
468
|
+
if (stillLocked) {
|
|
469
|
+
return c.json({ success: false, error: 'Failed to unlock — password may be incorrect' });
|
|
470
|
+
}
|
|
471
|
+
return c.json({ success: true, wasLocked: true, message: 'Screen unlocked successfully' });
|
|
472
|
+
} catch (e: any) {
|
|
473
|
+
return c.json({ success: false, error: 'Unlock attempt failed: ' + e.message });
|
|
474
|
+
}
|
|
475
|
+
} else if (platform === 'linux') {
|
|
476
|
+
const { execSync } = await import('child_process');
|
|
477
|
+
// Check for common screen lockers and unlock them
|
|
478
|
+
const body = await c.req.json().catch(() => ({}));
|
|
479
|
+
const password = body.password;
|
|
480
|
+
// Try loginctl unlock-session
|
|
481
|
+
try {
|
|
482
|
+
execSync('loginctl unlock-session $(loginctl list-sessions --no-legend | head -1 | awk \'{print $1}\')', { stdio: 'pipe', timeout: 5000 });
|
|
483
|
+
return c.json({ success: true, message: 'Session unlocked via loginctl' });
|
|
484
|
+
} catch {}
|
|
485
|
+
// Try xdotool for X11 based lockers
|
|
486
|
+
if (password) {
|
|
487
|
+
try {
|
|
488
|
+
execSync(`xdotool key --clearmodifiers super; sleep 0.5; xdotool type --clearmodifiers "${password.replace(/["\\]/g, '\\$&')}"; xdotool key Return`, { stdio: 'pipe', timeout: 10000 });
|
|
489
|
+
return c.json({ success: true, message: 'Unlock attempted via xdotool' });
|
|
490
|
+
} catch {}
|
|
491
|
+
}
|
|
492
|
+
return c.json({ success: false, error: 'Could not unlock Linux session. Supported: loginctl, xdotool.' });
|
|
493
|
+
} else if (platform === 'win32') {
|
|
494
|
+
return c.json({ success: false, error: 'Windows unlock not yet supported. Use Remote Desktop or disable lock screen.' });
|
|
495
|
+
} else {
|
|
496
|
+
return c.json({ success: false, error: `Unsupported platform: ${platform}` });
|
|
497
|
+
}
|
|
498
|
+
} catch (e: any) {
|
|
499
|
+
return c.json({ success: false, error: e.message });
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
router.get('/system/screen-status', async (c) => {
|
|
504
|
+
try {
|
|
505
|
+
const platform = process.platform;
|
|
506
|
+
if (platform === 'darwin') {
|
|
507
|
+
const { execSync } = await import('child_process');
|
|
508
|
+
const isLocked = (() => {
|
|
509
|
+
try {
|
|
510
|
+
const out = execSync('python3 -c "import Quartz; d=Quartz.CGSessionCopyCurrentDictionary(); print(d.get(\'CGSSessionScreenIsLocked\', 0))"', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 3000 }).trim();
|
|
511
|
+
return out === '1' || out === 'True';
|
|
512
|
+
} catch {
|
|
513
|
+
try {
|
|
514
|
+
const out = execSync('osascript -e \'tell application "System Events" to get name of first application process whose frontmost is true\'', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 3000 }).trim();
|
|
515
|
+
return out === 'loginwindow' || out === 'ScreenSaverEngine';
|
|
516
|
+
} catch { return false; }
|
|
517
|
+
}
|
|
518
|
+
})();
|
|
519
|
+
// Check if display is asleep
|
|
520
|
+
const displayAsleep = (() => {
|
|
521
|
+
try {
|
|
522
|
+
const out = execSync('ioreg -r -d 1 -k IODisplayWrangler | grep -i "currentpowerstate"', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 3000 });
|
|
523
|
+
return out.includes('= 0') || out.includes('= 1');
|
|
524
|
+
} catch { return false; }
|
|
525
|
+
})();
|
|
526
|
+
return c.json({ locked: isLocked, displayAsleep, platform: 'macOS' });
|
|
527
|
+
} else if (platform === 'linux') {
|
|
528
|
+
const { execSync } = await import('child_process');
|
|
529
|
+
const isLocked = (() => {
|
|
530
|
+
try {
|
|
531
|
+
const out = execSync('loginctl show-session $(loginctl list-sessions --no-legend | head -1 | awk \'{print $1}\') -p LockedHint --value', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 3000 }).trim();
|
|
532
|
+
return out === 'yes';
|
|
533
|
+
} catch { return false; }
|
|
534
|
+
})();
|
|
535
|
+
return c.json({ locked: isLocked, platform: 'Linux' });
|
|
536
|
+
}
|
|
537
|
+
return c.json({ locked: false, platform });
|
|
538
|
+
} catch (e: any) {
|
|
539
|
+
return c.json({ locked: false, error: e.message });
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
|
|
369
543
|
// ─── Agent Creation Bridge ──────────────────────────────
|
|
370
544
|
|
|
371
545
|
/**
|
|
@@ -1128,7 +1302,7 @@ export function createAgentRoutes(opts: {
|
|
|
1128
1302
|
|
|
1129
1303
|
// Also clear directly in DB to ensure no stale data
|
|
1130
1304
|
try {
|
|
1131
|
-
const db = lifecycle.getDb?.() || (globalThis as any).__engineDb;
|
|
1305
|
+
const db = (lifecycle as any).getDb?.() || (globalThis as any).__engineDb;
|
|
1132
1306
|
if (db) {
|
|
1133
1307
|
const isPostgres = !!(db as any).pool;
|
|
1134
1308
|
if (isPostgres) {
|
|
@@ -1315,6 +1489,85 @@ export function createAgentRoutes(opts: {
|
|
|
1315
1489
|
icon: Emoji.telegram || Emoji.chat, requiresIntegration: 'telegram',
|
|
1316
1490
|
tools: ['telegram_send', 'telegram_send_media', 'telegram_get_me', 'telegram_get_chat'],
|
|
1317
1491
|
},
|
|
1492
|
+
// ── Microsoft 365 ──────────────────────────────────
|
|
1493
|
+
{
|
|
1494
|
+
id: 'outlook_mail', name: 'Outlook Mail', description: 'Full email management — inbox, send, reply, forward, search, threads, drafts, rules, auto-reply, categories',
|
|
1495
|
+
icon: Emoji.envelope, requiresOAuth: 'microsoft',
|
|
1496
|
+
tools: ['outlook_mail_list', 'outlook_mail_read', 'outlook_mail_thread', 'outlook_mail_send', 'outlook_mail_reply',
|
|
1497
|
+
'outlook_mail_forward', 'outlook_mail_move', 'outlook_mail_delete', 'outlook_mail_update', 'outlook_mail_search',
|
|
1498
|
+
'outlook_mail_draft', 'outlook_mail_send_draft', 'outlook_mail_folders', 'outlook_mail_create_folder',
|
|
1499
|
+
'outlook_mail_attachment_download', 'outlook_mail_auto_reply', 'outlook_mail_get_auto_reply',
|
|
1500
|
+
'outlook_mail_rules', 'outlook_mail_categories', 'outlook_mail_profile'],
|
|
1501
|
+
},
|
|
1502
|
+
{
|
|
1503
|
+
id: 'outlook_calendar', name: 'Outlook Calendar', description: 'Calendar events, scheduling, free/busy lookup, Teams meeting creation, invite responses',
|
|
1504
|
+
icon: Emoji.calendar, requiresOAuth: 'microsoft',
|
|
1505
|
+
tools: ['outlook_calendar_list', 'outlook_calendar_events', 'outlook_calendar_create', 'outlook_calendar_update',
|
|
1506
|
+
'outlook_calendar_delete', 'outlook_calendar_respond', 'outlook_calendar_freebusy'],
|
|
1507
|
+
},
|
|
1508
|
+
{
|
|
1509
|
+
id: 'onedrive', name: 'OneDrive', description: 'Cloud file management — list, search, read, upload, share, create folders',
|
|
1510
|
+
icon: Emoji.folder, requiresOAuth: 'microsoft',
|
|
1511
|
+
tools: ['onedrive_list', 'onedrive_search', 'onedrive_read', 'onedrive_upload', 'onedrive_create_folder',
|
|
1512
|
+
'onedrive_delete', 'onedrive_share'],
|
|
1513
|
+
},
|
|
1514
|
+
{
|
|
1515
|
+
id: 'teams', name: 'Microsoft Teams', description: 'Team messaging, channels, chats, file sharing, presence, member management',
|
|
1516
|
+
icon: Emoji.chat, requiresOAuth: 'microsoft',
|
|
1517
|
+
tools: ['teams_list_teams', 'teams_list_channels', 'teams_create_channel', 'teams_send_channel_message',
|
|
1518
|
+
'teams_reply_to_message', 'teams_read_channel_messages', 'teams_list_chats', 'teams_send_chat_message',
|
|
1519
|
+
'teams_read_chat_messages', 'teams_list_members', 'teams_add_member', 'teams_share_file',
|
|
1520
|
+
'teams_presence', 'teams_set_status'],
|
|
1521
|
+
},
|
|
1522
|
+
{
|
|
1523
|
+
id: 'todo', name: 'Microsoft To Do', description: 'Task lists, task CRUD with due dates, reminders, and importance',
|
|
1524
|
+
icon: Emoji.check, requiresOAuth: 'microsoft',
|
|
1525
|
+
tools: ['todo_list_lists', 'todo_list_tasks', 'todo_create_task', 'todo_update_task', 'todo_delete_task', 'todo_create_list'],
|
|
1526
|
+
},
|
|
1527
|
+
{
|
|
1528
|
+
id: 'outlook_contacts', name: 'Outlook Contacts', description: 'Contact management, address book, people search',
|
|
1529
|
+
icon: Emoji.people, requiresOAuth: 'microsoft',
|
|
1530
|
+
tools: ['outlook_contacts_list', 'outlook_contacts_create', 'outlook_contacts_update', 'outlook_contacts_delete', 'outlook_people_search'],
|
|
1531
|
+
},
|
|
1532
|
+
{
|
|
1533
|
+
id: 'excel', name: 'Microsoft Excel', description: 'Read/write cells, ranges, tables, worksheets, formulas, charts, formatting',
|
|
1534
|
+
icon: Emoji.chartUp, requiresOAuth: 'microsoft',
|
|
1535
|
+
tools: ['excel_list_worksheets', 'excel_read_range', 'excel_write_range', 'excel_add_row', 'excel_list_tables',
|
|
1536
|
+
'excel_read_table', 'excel_create_worksheet', 'excel_create_session', 'excel_close_session',
|
|
1537
|
+
'excel_evaluate_formula', 'excel_named_ranges', 'excel_read_named_range', 'excel_list_charts',
|
|
1538
|
+
'excel_chart_image', 'excel_pivot_refresh', 'excel_set_cell_format'],
|
|
1539
|
+
},
|
|
1540
|
+
{
|
|
1541
|
+
id: 'sharepoint', name: 'SharePoint', description: 'Sites, document libraries, lists, search, file management across SharePoint Online',
|
|
1542
|
+
icon: Emoji.database, requiresOAuth: 'microsoft',
|
|
1543
|
+
tools: ['sharepoint_list_sites', 'sharepoint_get_site', 'sharepoint_list_drives', 'sharepoint_list_files',
|
|
1544
|
+
'sharepoint_upload_file', 'sharepoint_list_lists', 'sharepoint_list_items', 'sharepoint_create_list_item',
|
|
1545
|
+
'sharepoint_update_list_item', 'sharepoint_search'],
|
|
1546
|
+
},
|
|
1547
|
+
{
|
|
1548
|
+
id: 'onenote', name: 'OneNote', description: 'Notebooks, sections, pages — read, create, and update notes',
|
|
1549
|
+
icon: Emoji.note, requiresOAuth: 'microsoft',
|
|
1550
|
+
tools: ['onenote_list_notebooks', 'onenote_list_sections', 'onenote_list_pages', 'onenote_read_page',
|
|
1551
|
+
'onenote_create_page', 'onenote_update_page'],
|
|
1552
|
+
},
|
|
1553
|
+
{
|
|
1554
|
+
id: 'powerpoint', name: 'PowerPoint', description: 'Presentation metadata, PDF export, thumbnails, templates, embed URLs',
|
|
1555
|
+
icon: Emoji.art, requiresOAuth: 'microsoft',
|
|
1556
|
+
tools: ['powerpoint_get_info', 'powerpoint_export_pdf', 'powerpoint_get_thumbnails',
|
|
1557
|
+
'powerpoint_create_from_template', 'powerpoint_get_embed_url'],
|
|
1558
|
+
},
|
|
1559
|
+
{
|
|
1560
|
+
id: 'planner', name: 'Microsoft Planner', description: 'Project boards — plans, buckets, tasks (Kanban-style task management)',
|
|
1561
|
+
icon: Emoji.clipboard, requiresOAuth: 'microsoft',
|
|
1562
|
+
tools: ['planner_list_plans', 'planner_list_buckets', 'planner_list_tasks', 'planner_create_task',
|
|
1563
|
+
'planner_update_task', 'planner_delete_task'],
|
|
1564
|
+
},
|
|
1565
|
+
{
|
|
1566
|
+
id: 'powerbi', name: 'Power BI', description: 'Workspaces, reports, dashboards, datasets, DAX queries, data refresh',
|
|
1567
|
+
icon: Emoji.barChart, requiresOAuth: 'microsoft',
|
|
1568
|
+
tools: ['powerbi_list_workspaces', 'powerbi_list_reports', 'powerbi_list_dashboards', 'powerbi_list_datasets',
|
|
1569
|
+
'powerbi_refresh_dataset', 'powerbi_refresh_history', 'powerbi_execute_query', 'powerbi_dashboard_tiles'],
|
|
1570
|
+
},
|
|
1318
1571
|
];
|
|
1319
1572
|
|
|
1320
1573
|
// ═══════════════════════════════════════════════════════════
|
|
@@ -1845,7 +2098,7 @@ export function createAgentRoutes(opts: {
|
|
|
1845
2098
|
if (body.requireApproval) profile.requireApproval = body.requireApproval;
|
|
1846
2099
|
if (body.rateLimits) profile.rateLimits = body.rateLimits;
|
|
1847
2100
|
if (body.constraints) profile.constraints = body.constraints;
|
|
1848
|
-
permissions.setProfile(agentId, profile, managed.
|
|
2101
|
+
permissions.setProfile(agentId, profile, managed.orgId);
|
|
1849
2102
|
}
|
|
1850
2103
|
|
|
1851
2104
|
managed.updatedAt = new Date().toISOString();
|
|
@@ -1948,7 +2201,7 @@ export function createAgentRoutes(opts: {
|
|
|
1948
2201
|
}
|
|
1949
2202
|
profile.tools.blocked = [...newBlocked];
|
|
1950
2203
|
profile.tools.allowed = [...newAllowed];
|
|
1951
|
-
permissions.setProfile(agentId, profile, managed.
|
|
2204
|
+
permissions.setProfile(agentId, profile, managed.orgId);
|
|
1952
2205
|
}
|
|
1953
2206
|
|
|
1954
2207
|
managed.updatedAt = new Date().toISOString();
|
package/src/engine/db-adapter.ts
CHANGED
|
@@ -237,6 +237,19 @@ export class EngineDatabase {
|
|
|
237
237
|
return this.db.all<T>(sql, params);
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
+
async get<T = any>(sql: string, params?: any[]): Promise<T | undefined> {
|
|
241
|
+
return this.db.get<T>(sql, params);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async getSettings(): Promise<Record<string, any>> {
|
|
245
|
+
const rows = await this.db.all<any>('SELECT key, value FROM engine_settings', []);
|
|
246
|
+
const result: Record<string, any> = {};
|
|
247
|
+
for (const row of rows) {
|
|
248
|
+
try { result[row.key] = JSON.parse(row.value); } catch { result[row.key] = row.value; }
|
|
249
|
+
}
|
|
250
|
+
return result;
|
|
251
|
+
}
|
|
252
|
+
|
|
240
253
|
async execute(sql: string, params?: any[]): Promise<void> {
|
|
241
254
|
return this.db.run(sql, params);
|
|
242
255
|
}
|
|
@@ -1095,6 +1108,9 @@ export class EngineDatabase {
|
|
|
1095
1108
|
const config = sj(row.config);
|
|
1096
1109
|
const agent: ManagedAgent = {
|
|
1097
1110
|
id: row.id,
|
|
1111
|
+
name: row.display_name || row.name || config?.displayName || config?.name || row.id,
|
|
1112
|
+
displayName: row.display_name || config?.displayName || config?.name,
|
|
1113
|
+
display_name: row.display_name || config?.displayName || config?.name,
|
|
1098
1114
|
orgId: row.org_id,
|
|
1099
1115
|
config,
|
|
1100
1116
|
state: row.state,
|
package/src/engine/lifecycle.ts
CHANGED
|
@@ -39,6 +39,8 @@ export interface ManagedAgent {
|
|
|
39
39
|
displayName?: string; // Human-facing display name
|
|
40
40
|
display_name?: string; // Snake_case alias (DB compat)
|
|
41
41
|
orgId: string; // Which company owns this agent
|
|
42
|
+
org_id?: string; // Snake_case alias (DB compat)
|
|
43
|
+
client_org_id?: string; // Client org binding (if external)
|
|
42
44
|
config: AgentConfig;
|
|
43
45
|
state: AgentState;
|
|
44
46
|
permissionProfileId?: string; // Permission profile reference
|
|
@@ -1202,6 +1204,8 @@ export class AgentLifecycleManager {
|
|
|
1202
1204
|
await this.persistAgent(agent);
|
|
1203
1205
|
// Emit generic agent save event — all config keys may have changed
|
|
1204
1206
|
configBus.emitAgentConfig(agentId, '_save', undefined, 'lifecycle');
|
|
1207
|
+
// Push config to standalone agent process in real-time
|
|
1208
|
+
import('./agent-notify.js').then(({ notifyAgent }) => notifyAgent(agentId, 'config', this)).catch(() => {});
|
|
1205
1209
|
}
|
|
1206
1210
|
}
|
|
1207
1211
|
|
package/src/engine/routes.ts
CHANGED
|
@@ -96,6 +96,10 @@ import type { DatabaseAdapter } from '../db/adapter.js';
|
|
|
96
96
|
const engine = new Hono<AppEnv>();
|
|
97
97
|
let _engineApp: Hono<AppEnv> = engine;
|
|
98
98
|
|
|
99
|
+
// Forward declarations (set later via setEngineDb)
|
|
100
|
+
let _engineDb: import('./db-adapter.js').EngineDatabase | null = null;
|
|
101
|
+
let _adminDb: DatabaseAdapter | null = null;
|
|
102
|
+
|
|
99
103
|
// ─── Shared Instances ───────────────────────────────────
|
|
100
104
|
|
|
101
105
|
const permissionEngine = new PermissionEngine(FULL_SKILL_DEFINITIONS);
|
|
@@ -754,9 +758,6 @@ engine.post('/email-poller/rediscover', async (c) => {
|
|
|
754
758
|
|
|
755
759
|
// ─── setEngineDb ────────────────────────────────────────
|
|
756
760
|
|
|
757
|
-
let _engineDb: import('./db-adapter.js').EngineDatabase | null = null;
|
|
758
|
-
let _adminDb: DatabaseAdapter | null = null;
|
|
759
|
-
|
|
760
761
|
export async function setEngineDb(
|
|
761
762
|
db: import('./db-adapter.js').EngineDatabase,
|
|
762
763
|
adminDb?: DatabaseAdapter,
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screen Unlock & Machine Access Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides auto-unlock functionality for macOS and Linux.
|
|
5
|
+
* Called by the heartbeat system, agent startup, and browser automation
|
|
6
|
+
* when the screen is detected as locked.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { execSync } from 'child_process';
|
|
10
|
+
|
|
11
|
+
let _caffeinate: any = null;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Check if the screen is currently locked.
|
|
15
|
+
*/
|
|
16
|
+
export function isScreenLocked(): boolean {
|
|
17
|
+
try {
|
|
18
|
+
if (process.platform === 'darwin') {
|
|
19
|
+
try {
|
|
20
|
+
const out = execSync('python3 -c "import Quartz; d=Quartz.CGSessionCopyCurrentDictionary(); print(d.get(\'CGSSessionScreenIsLocked\', 0))"', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 3000 }).trim();
|
|
21
|
+
return out === '1' || out === 'True';
|
|
22
|
+
} catch {
|
|
23
|
+
try {
|
|
24
|
+
const out = execSync('osascript -e \'tell application "System Events" to get name of first application process whose frontmost is true\'', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 3000 }).trim();
|
|
25
|
+
return out === 'loginwindow' || out === 'ScreenSaverEngine';
|
|
26
|
+
} catch { return false; }
|
|
27
|
+
}
|
|
28
|
+
} else if (process.platform === 'linux') {
|
|
29
|
+
try {
|
|
30
|
+
const out = execSync('loginctl show-session $(loginctl list-sessions --no-legend | head -1 | awk \'{print $1}\') -p LockedHint --value', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 3000 }).trim();
|
|
31
|
+
return out === 'yes';
|
|
32
|
+
} catch { return false; }
|
|
33
|
+
}
|
|
34
|
+
} catch {}
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Attempt to unlock the screen with the given password.
|
|
40
|
+
* Returns true if successful.
|
|
41
|
+
*/
|
|
42
|
+
export async function unlockScreen(password: string): Promise<{ success: boolean; message: string }> {
|
|
43
|
+
if (!password) return { success: false, message: 'No password provided' };
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
if (process.platform === 'darwin') {
|
|
47
|
+
// Wake the display first
|
|
48
|
+
try { execSync('caffeinate -u -t 2', { stdio: 'pipe', timeout: 5000 }); } catch {}
|
|
49
|
+
await new Promise(r => setTimeout(r, 500));
|
|
50
|
+
|
|
51
|
+
if (!isScreenLocked()) {
|
|
52
|
+
return { success: true, message: 'Screen is already unlocked' };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Type password using AppleScript
|
|
56
|
+
const escaped = password.replace(/["\\]/g, '\\$&');
|
|
57
|
+
execSync(`osascript -e 'tell application "System Events" to keystroke "${escaped}"' -e 'delay 0.3' -e 'tell application "System Events" to key code 36'`, {
|
|
58
|
+
stdio: 'pipe', timeout: 10000
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Wait and verify
|
|
62
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
63
|
+
if (isScreenLocked()) {
|
|
64
|
+
return { success: false, message: 'Failed to unlock — password may be incorrect' };
|
|
65
|
+
}
|
|
66
|
+
return { success: true, message: 'Screen unlocked successfully' };
|
|
67
|
+
} else if (process.platform === 'linux') {
|
|
68
|
+
// Try loginctl first
|
|
69
|
+
try {
|
|
70
|
+
execSync('loginctl unlock-session $(loginctl list-sessions --no-legend | head -1 | awk \'{print $1}\')', { stdio: 'pipe', timeout: 5000 });
|
|
71
|
+
return { success: true, message: 'Session unlocked via loginctl' };
|
|
72
|
+
} catch {}
|
|
73
|
+
// Try xdotool
|
|
74
|
+
try {
|
|
75
|
+
const escaped = password.replace(/["\\]/g, '\\$&');
|
|
76
|
+
execSync(`xdotool key --clearmodifiers super; sleep 0.5; xdotool type --clearmodifiers "${escaped}"; xdotool key Return`, { stdio: 'pipe', timeout: 10000 });
|
|
77
|
+
return { success: true, message: 'Unlock attempted via xdotool' };
|
|
78
|
+
} catch {}
|
|
79
|
+
return { success: false, message: 'Could not unlock Linux session' };
|
|
80
|
+
}
|
|
81
|
+
return { success: false, message: `Unsupported platform: ${process.platform}` };
|
|
82
|
+
} catch (e: any) {
|
|
83
|
+
return { success: false, message: e.message };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Ensure the screen is unlocked. Uses the security config to get the password.
|
|
89
|
+
* Call this before any operation that requires screen access (browser, desktop automation).
|
|
90
|
+
*/
|
|
91
|
+
export async function ensureScreenUnlocked(getSecurityConfig: () => Promise<any>): Promise<boolean> {
|
|
92
|
+
if (!isScreenLocked()) return true;
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
const config = await getSecurityConfig();
|
|
96
|
+
const screenAccess = config?.screenAccess;
|
|
97
|
+
if (!screenAccess?.enabled || !screenAccess?.autoUnlock) return false;
|
|
98
|
+
if (!screenAccess?.systemPassword) return false;
|
|
99
|
+
|
|
100
|
+
const result = await unlockScreen(screenAccess.systemPassword);
|
|
101
|
+
return result.success;
|
|
102
|
+
} catch {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Start caffeinate to prevent system sleep. Call once at server startup if configured.
|
|
109
|
+
*/
|
|
110
|
+
export function startPreventSleep(): void {
|
|
111
|
+
if (_caffeinate) return; // Already running
|
|
112
|
+
if (process.platform !== 'darwin' && process.platform !== 'linux') return;
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const { spawn } = require('child_process');
|
|
116
|
+
if (process.platform === 'darwin') {
|
|
117
|
+
// caffeinate -d prevents display sleep, -i prevents idle sleep
|
|
118
|
+
_caffeinate = spawn('caffeinate', ['-d', '-i'], { stdio: 'ignore', detached: true });
|
|
119
|
+
_caffeinate.unref();
|
|
120
|
+
} else {
|
|
121
|
+
// Linux: systemd-inhibit
|
|
122
|
+
_caffeinate = spawn('systemd-inhibit', ['--what=idle:sleep', '--who=agenticmail', '--why=Agent activity', 'sleep', 'infinity'], { stdio: 'ignore', detached: true });
|
|
123
|
+
_caffeinate.unref();
|
|
124
|
+
}
|
|
125
|
+
} catch {}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Stop preventing system sleep.
|
|
130
|
+
*/
|
|
131
|
+
export function stopPreventSleep(): void {
|
|
132
|
+
if (_caffeinate) {
|
|
133
|
+
try { _caffeinate.kill(); } catch {}
|
|
134
|
+
_caffeinate = null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Emoji } from '../emoji.js';
|
|
2
|
+
import type { SkillDefinition, ToolDefinition } from '../skills.js';
|
|
3
|
+
|
|
4
|
+
export const SKILL_DEF: Omit<SkillDefinition, 'tools'> = {
|
|
5
|
+
id: 'database-access',
|
|
6
|
+
name: 'External Database Access',
|
|
7
|
+
description: 'Query external databases (Postgres, MySQL, MongoDB, Redis, Supabase, etc.) that have been granted to this agent by an admin. Supports read/write operations based on granted permissions.',
|
|
8
|
+
category: 'database',
|
|
9
|
+
risk: 'medium',
|
|
10
|
+
icon: Emoji.database,
|
|
11
|
+
source: 'builtin',
|
|
12
|
+
version: '1.0.0',
|
|
13
|
+
author: 'AgenticMail',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const TOOLS: ToolDefinition[] = [
|
|
17
|
+
{
|
|
18
|
+
id: 'db_list_connections',
|
|
19
|
+
name: 'List Database Connections',
|
|
20
|
+
description: 'List all external database connections this agent has been granted access to.',
|
|
21
|
+
category: 'read',
|
|
22
|
+
risk: 'low',
|
|
23
|
+
skillId: 'database-access',
|
|
24
|
+
sideEffects: [],
|
|
25
|
+
parameters: { type: 'object', properties: {} },
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: 'db_query',
|
|
29
|
+
name: 'Query External Database',
|
|
30
|
+
description: 'Execute a SQL query on a granted external database connection.',
|
|
31
|
+
category: 'read',
|
|
32
|
+
risk: 'medium',
|
|
33
|
+
skillId: 'database-access',
|
|
34
|
+
sideEffects: ['database_write'],
|
|
35
|
+
parameters: {
|
|
36
|
+
type: 'object',
|
|
37
|
+
properties: {
|
|
38
|
+
connectionId: { type: 'string', description: 'Database connection ID' },
|
|
39
|
+
sql: { type: 'string', description: 'SQL query to execute' },
|
|
40
|
+
params: { type: 'array', items: { type: 'string' }, description: 'Query parameters' },
|
|
41
|
+
},
|
|
42
|
+
required: ['connectionId', 'sql'],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: 'db_describe_table',
|
|
47
|
+
name: 'Describe Table Schema',
|
|
48
|
+
description: 'Get the schema (columns, types, constraints) of a table in an external database.',
|
|
49
|
+
category: 'read',
|
|
50
|
+
risk: 'low',
|
|
51
|
+
skillId: 'database-access',
|
|
52
|
+
sideEffects: ['network-request'],
|
|
53
|
+
parameters: {
|
|
54
|
+
type: 'object',
|
|
55
|
+
properties: {
|
|
56
|
+
connectionId: { type: 'string', description: 'Database connection ID' },
|
|
57
|
+
table: { type: 'string', description: 'Table name' },
|
|
58
|
+
},
|
|
59
|
+
required: ['connectionId', 'table'],
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 'db_list_tables',
|
|
64
|
+
name: 'List Tables',
|
|
65
|
+
description: 'List all tables in an external database connection.',
|
|
66
|
+
category: 'read',
|
|
67
|
+
risk: 'low',
|
|
68
|
+
skillId: 'database-access',
|
|
69
|
+
sideEffects: ['network-request'],
|
|
70
|
+
parameters: {
|
|
71
|
+
type: 'object',
|
|
72
|
+
properties: {
|
|
73
|
+
connectionId: { type: 'string', description: 'Database connection ID' },
|
|
74
|
+
},
|
|
75
|
+
required: ['connectionId'],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
];
|
|
@@ -101,6 +101,7 @@ export const AGENTICMAIL_TOOLS: ToolDefinition[] = AGENTICMAIL_MODULES.flatMap(m
|
|
|
101
101
|
// ─── Enterprise Utility Skills ─────────────────────────
|
|
102
102
|
|
|
103
103
|
import * as EntDatabase from './enterprise-database.js';
|
|
104
|
+
import * as DatabaseAccess from './database-access.js';
|
|
104
105
|
import * as EntSpreadsheet from './enterprise-spreadsheet.js';
|
|
105
106
|
import * as EntDocuments from './enterprise-documents.js';
|
|
106
107
|
import * as EntHttp from './enterprise-http.js';
|
|
@@ -109,7 +110,7 @@ import * as EntCodeSandbox from './enterprise-code-sandbox.js';
|
|
|
109
110
|
import * as EntDiff from './enterprise-diff.js';
|
|
110
111
|
|
|
111
112
|
export const ENTERPRISE_MODULES = [
|
|
112
|
-
EntDatabase, EntSpreadsheet, EntDocuments, EntHttp,
|
|
113
|
+
EntDatabase, DatabaseAccess, EntSpreadsheet, EntDocuments, EntHttp,
|
|
113
114
|
EntSecurityScan, EntCodeSandbox, EntDiff,
|
|
114
115
|
] as const;
|
|
115
116
|
|
|
@@ -152,7 +153,7 @@ export {
|
|
|
152
153
|
GwsSheets, GwsSlides, GwsMeet, GwsChat,
|
|
153
154
|
GwsForms, GwsSites, GwsKeep, GwsAdmin,
|
|
154
155
|
GwsVault, GwsGroups, GwsMaps, GwsContacts, GwsTasks,
|
|
155
|
-
EntDatabase, EntSpreadsheet, EntDocuments, EntHttp,
|
|
156
|
+
EntDatabase, DatabaseAccess, EntSpreadsheet, EntDocuments, EntHttp,
|
|
156
157
|
EntSecurityScan, EntCodeSandbox, EntDiff,
|
|
157
158
|
CoreTools, MeetingLifecycle, AgentMemory, VisualMemory, KnowledgeSearch,
|
|
158
159
|
};
|
package/src/engine/skills.ts
CHANGED
|
@@ -481,6 +481,8 @@ export class PermissionEngine {
|
|
|
481
481
|
console.error(`[permissions] Failed to persist profile for agent ${agentId}:`, err);
|
|
482
482
|
});
|
|
483
483
|
}
|
|
484
|
+
// Push to standalone agent in real-time
|
|
485
|
+
import('./agent-notify.js').then(({ notifyAgent }) => notifyAgent(agentId, 'permissions')).catch(() => {});
|
|
484
486
|
}
|
|
485
487
|
|
|
486
488
|
getProfile(agentId: string): AgentPermissionProfile | undefined {
|
|
@@ -72,6 +72,24 @@ export function createTaskQueueRoutes(taskQueue: TaskQueueManager) {
|
|
|
72
72
|
});
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
+
// POST /task-pipeline/webhook — receive task events from standalone agent processes
|
|
76
|
+
// Agents create/update tasks in shared DB but SSE subscribers are on this process.
|
|
77
|
+
// This endpoint re-emits the event to all SSE subscribers for real-time updates.
|
|
78
|
+
router.post('/webhook', async (c) => {
|
|
79
|
+
try {
|
|
80
|
+
const event = await c.req.json();
|
|
81
|
+
if (event && event.task) {
|
|
82
|
+
// Re-emit to local SSE subscribers
|
|
83
|
+
for (const l of (taskQueue as any).listeners || []) {
|
|
84
|
+
try { l(event); } catch { /* ignore */ }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return c.json({ ok: true });
|
|
88
|
+
} catch {
|
|
89
|
+
return c.json({ ok: false }, 400);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
75
93
|
// GET /task-pipeline/:id — single task detail
|
|
76
94
|
router.get('/:id', (c) => {
|
|
77
95
|
const task = taskQueue.getTask(c.req.param('id'));
|