@askexenow/exe-os 0.9.154 → 0.9.156
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/deploy/compose/.env.example +25 -39
- package/deploy/compose/backup.sh +37 -0
- package/deploy/compose/branding.json +20 -0
- package/deploy/compose/cloudflared/config.yml.example +29 -0
- package/deploy/compose/docker-compose.yml +108 -0
- package/deploy/compose/gateway.json +11 -1
- package/deploy/compose/generate-env.ts +18 -4
- package/deploy/compose/init-db.sql +55 -0
- package/deploy/compose/setup.sh +166 -0
- package/deploy/compose/status.sh +48 -0
- package/dist/{active-agent-IVY5D7DJ.js → active-agent-GHJBTJRF.js} +4 -4
- package/dist/{active-agent-JN7A2D2E.js → active-agent-RY74REEW.js} +4 -4
- package/dist/{agentic-ontology-NU5FACOX.js → agentic-ontology-FP67RCR6.js} +1 -1
- package/dist/{backfill-metadata-XBWBPBN2.js → backfill-metadata-W7FUQRD7.js} +5 -5
- package/dist/{background-jobs-IUB22CRF.js → background-jobs-XYVQT4HN.js} +2 -2
- package/dist/{behaviors-4USTCRU7.js → behaviors-KA64SSPT.js} +4 -4
- package/dist/bin/age-ontology-load.js +2 -2
- package/dist/bin/agentic-ontology-backfill.js +7 -7
- package/dist/bin/agentic-reflection-backfill.js +8 -8
- package/dist/bin/agentic-semantic-label.js +7 -7
- package/dist/bin/backfill-conversations.js +7 -7
- package/dist/bin/backfill-responses.js +7 -7
- package/dist/bin/backfill-vectors.js +9 -9
- package/dist/bin/bulk-sync-postgres.js +8 -8
- package/dist/bin/cc-doctor.js +3 -3
- package/dist/bin/cleanup-stale-review-tasks.js +9 -9
- package/dist/bin/cli.js +18 -18
- package/dist/bin/exe-agent-config.js +4 -4
- package/dist/bin/exe-agent.js +5 -5
- package/dist/bin/exe-assign.js +9 -9
- package/dist/bin/exe-boot.js +16 -16
- package/dist/bin/exe-call.js +5 -5
- package/dist/bin/exe-cloud.js +7 -7
- package/dist/bin/exe-dispatch.js +9 -9
- package/dist/bin/exe-doctor.js +1 -1
- package/dist/bin/exe-export-behaviors.js +8 -8
- package/dist/bin/exe-forget.js +7 -7
- package/dist/bin/exe-gateway.js +8 -8
- package/dist/bin/exe-healthcheck.js +3 -3
- package/dist/bin/exe-heartbeat.js +9 -9
- package/dist/bin/exe-kill.js +12 -12
- package/dist/bin/exe-launch-agent.js +12 -12
- package/dist/bin/exe-new-employee.js +8 -8
- package/dist/bin/exe-pending-messages.js +10 -10
- package/dist/bin/exe-pending-notifications.js +9 -9
- package/dist/bin/exe-pending-reviews.js +9 -9
- package/dist/bin/exe-rename.js +5 -5
- package/dist/bin/exe-review.js +11 -11
- package/dist/bin/exe-search.js +6 -6
- package/dist/bin/exe-session-cleanup.js +13 -13
- package/dist/bin/exe-settings.js +7 -7
- package/dist/bin/exe-start-codex.js +12 -12
- package/dist/bin/exe-start-opencode.js +9 -9
- package/dist/bin/exe-status.js +10 -10
- package/dist/bin/exe-support.js +3 -3
- package/dist/bin/exe-team.js +4 -4
- package/dist/bin/git-sweep.js +9 -9
- package/dist/bin/graph-backfill.js +6 -6
- package/dist/bin/graph-export.js +6 -6
- package/dist/bin/install.js +7 -7
- package/dist/bin/intercom-check.js +4 -4
- package/dist/bin/postgres-agentic-reflection-backfill.js +4 -4
- package/dist/bin/postgres-agentic-semantic-backfill.js +3 -3
- package/dist/bin/scan-tasks.js +9 -9
- package/dist/bin/setup.js +2 -2
- package/dist/bin/shard-migrate.js +6 -6
- package/dist/bin/stack-update.js +2 -2
- package/dist/{branding-EHDA3CCK.js → branding-YUEILP4B.js} +1 -1
- package/dist/{capacity-monitor-VJLRBE7S.js → capacity-monitor-WAZTZAR5.js} +10 -10
- package/dist/{catchup-brief-T2RPTOTZ.js → catchup-brief-PKETW4ND.js} +11 -11
- package/dist/{chunk-OSPZOCPU.js → chunk-23UPL4NU.js} +3 -3
- package/dist/{chunk-TME75K53.js → chunk-2X5G7F5C.js} +3 -3
- package/dist/{chunk-23H5ZURC.js → chunk-3AN3RTUT.js} +4 -4
- package/dist/{chunk-XYFPCAA2.js → chunk-452JBQHH.js} +1 -1
- package/dist/{chunk-TOWAZ5IV.js → chunk-4GXRETYL.js} +16 -1
- package/dist/{chunk-AL7JZARP.js → chunk-4ZQDR3MI.js} +1 -1
- package/dist/{chunk-DW6P7UVY.js → chunk-66QQPSWI.js} +2 -2
- package/dist/{chunk-LHMOPUZE.js → chunk-6F46227N.js} +6 -6
- package/dist/{chunk-LVEOCWPL.js → chunk-77QEF6FR.js} +2 -2
- package/dist/{chunk-VRKPBY6D.js → chunk-7G44AU2D.js} +1 -1
- package/dist/{chunk-3RJBXMWJ.js → chunk-7VIH6LOQ.js} +2 -2
- package/dist/{chunk-5KUJDZ3J.js → chunk-7XRGVVG6.js} +3 -3
- package/dist/{chunk-NL4YO6I2.js → chunk-A6LSJC2O.js} +1 -1
- package/dist/{chunk-DMUNYW65.js → chunk-AK7S4GRC.js} +3 -3
- package/dist/{chunk-6M65LFNM.js → chunk-BRHV6CJT.js} +2 -2
- package/dist/{chunk-KSOPUPQX.js → chunk-CGLSVN6N.js} +9 -9
- package/dist/{chunk-Q7TTJD4A.js → chunk-CK5ZKW25.js} +1 -1
- package/dist/{chunk-K4KAPZC7.js → chunk-CMFLJNP6.js} +1 -1
- package/dist/{chunk-6YUACQQA.js → chunk-CTOQYEKJ.js} +1 -1
- package/dist/{chunk-UREIHGOQ.js → chunk-CXGOW4EJ.js} +3 -3
- package/dist/{chunk-6HFZ2KUC.js → chunk-DH65L4XI.js} +1 -1
- package/dist/{chunk-W6SKR3HZ.js → chunk-E2O7YYDS.js} +2 -2
- package/dist/{chunk-2G2KOWBI.js → chunk-EVB53OQD.js} +11 -11
- package/dist/{chunk-H5STRY47.js → chunk-F7ITFLVR.js} +1 -1
- package/dist/{chunk-SFZUC72J.js → chunk-FOG7AEEO.js} +2 -2
- package/dist/{chunk-T2B7637C.js → chunk-G2RRAFCH.js} +1 -1
- package/dist/{chunk-EYQIEK5M.js → chunk-GUCKE3GK.js} +1 -1
- package/dist/{chunk-KIUU4PNX.js → chunk-H2CFBUGF.js} +1 -1
- package/dist/{chunk-VB23RNNI.js → chunk-HBPFK6AO.js} +1 -1
- package/dist/{chunk-3I44JXWH.js → chunk-HDQJMTBG.js} +2 -2
- package/dist/{chunk-66RYFM6Z.js → chunk-HF6TVN2J.js} +3 -3
- package/dist/{chunk-3CZBCOYI.js → chunk-HH6ZCDZH.js} +2 -2
- package/dist/{chunk-Y3Z6QHUR.js → chunk-INWPOOB6.js} +1 -1
- package/dist/{chunk-DTT4TRFR.js → chunk-IRVLV6C5.js} +1 -1
- package/dist/{chunk-EHXOWGQG.js → chunk-IXJ4SLKR.js} +2 -2
- package/dist/{chunk-K23KJITV.js → chunk-J73N5EJ6.js} +2 -2
- package/dist/{chunk-OHYMA6C3.js → chunk-JFEFVLLD.js} +7 -7
- package/dist/{chunk-IWSXQKSB.js → chunk-JTHPKHKC.js} +1 -1
- package/dist/{chunk-KUPUTWQX.js → chunk-JYYWHPQC.js} +7 -7
- package/dist/{chunk-SE2DYYVB.js → chunk-KL5VDEBT.js} +1 -1
- package/dist/{chunk-ULFBLCIP.js → chunk-KPB5SN3Q.js} +1 -1
- package/dist/{chunk-L3JRSHHU.js → chunk-KZXC3G3P.js} +2 -2
- package/dist/{chunk-F2WGMIFZ.js → chunk-LVWXGZER.js} +1 -1
- package/dist/{chunk-HYRYMZRT.js → chunk-LWABYGNF.js} +1 -1
- package/dist/{chunk-G7IQNOSY.js → chunk-MBXAWOYB.js} +1 -1
- package/dist/{chunk-OC7Q4LOK.js → chunk-OCFYT3LE.js} +40 -9
- package/dist/{chunk-GCNWCYJI.js → chunk-ONKIWA3R.js} +2 -2
- package/dist/{chunk-2GUTGEFX.js → chunk-PELAHAJR.js} +1 -1
- package/dist/{chunk-VZDPV32D.js → chunk-PY7QM2C7.js} +3 -3
- package/dist/{chunk-Z6UYJ7HZ.js → chunk-Q46X2YPY.js} +4 -4
- package/dist/{chunk-PE6NCL7A.js → chunk-Q55XPOXU.js} +1 -1
- package/dist/{chunk-DWLDYEGO.js → chunk-RTNRPBQP.js} +10 -10
- package/dist/{chunk-EOO32RJZ.js → chunk-RVSGXGWG.js} +1 -1
- package/dist/{chunk-UIAYIZNR.js → chunk-RZE4KMRO.js} +2 -2
- package/dist/{chunk-V4MKR32F.js → chunk-S6DDN7IS.js} +2 -2
- package/dist/{chunk-TH2OFEQH.js → chunk-SEENMPG7.js} +2 -2
- package/dist/{chunk-GCB4MHTG.js → chunk-SNN634YS.js} +1 -1
- package/dist/{chunk-LWJ4AMMY.js → chunk-T5YT64SZ.js} +1 -1
- package/dist/{chunk-NNT2ZNMC.js → chunk-TJEETRHD.js} +1 -1
- package/dist/{chunk-45APPAB2.js → chunk-TM3WWKNB.js} +5 -5
- package/dist/{chunk-3S2HQUP6.js → chunk-U56WZR5E.js} +6 -6
- package/dist/{chunk-UJ2KUF4C.js → chunk-U5GTF2JP.js} +1 -1
- package/dist/{chunk-MLL5ICNL.js → chunk-UWUF5NWA.js} +7 -7
- package/dist/{chunk-XEN5RMGU.js → chunk-V5Y323LO.js} +1 -1
- package/dist/{chunk-XMRDT4PB.js → chunk-WZTQUBIE.js} +1 -1
- package/dist/{chunk-ICKEGWWP.js → chunk-X5O3FKRU.js} +1 -1
- package/dist/{chunk-4MN44ORL.js → chunk-XIGJOVTD.js} +1 -1
- package/dist/{chunk-2BTXFKAV.js → chunk-XIZR2YLR.js} +70 -71
- package/dist/{chunk-ABVCJBON.js → chunk-ZIJR3H2O.js} +2 -2
- package/dist/{chunk-3OGN523Z.js → chunk-ZPM2RMK2.js} +3 -3
- package/dist/{code-context-index-I5A7I4JQ.js → code-context-index-XZ22G57G.js} +4 -4
- package/dist/{conversation-wiki-populator-RSJ44BRO.js → conversation-wiki-populator-HVROKOEU.js} +1 -1
- package/dist/{crdt-sync-B7IUR3BR.js → crdt-sync-5JERNXAI.js} +1 -1
- package/dist/{crm-bridge-4QZRMOF7.js → crm-bridge-BVTB6LZK.js} +1 -1
- package/dist/{crm-webhook-YU7PDS7U.js → crm-webhook-DGL6XEOQ.js} +2 -2
- package/dist/{cto-delegation-gate-JDDOHVQL.js → cto-delegation-gate-UFSXT2CA.js} +8 -8
- package/dist/{daemon-auth-F47P6HTC.js → daemon-auth-H4EJ7KAQ.js} +2 -2
- package/dist/{daemon-orchestration-5OYKXYSR.js → daemon-orchestration-IP2LHJJK.js} +11 -11
- package/dist/{db-backup-W56YOLMC.js → db-backup-7UOCAPHO.js} +2 -2
- package/dist/{exe-drift-DXRU4SXJ.js → exe-drift-FNK7OXMY.js} +4 -4
- package/dist/{exe-export-X3AWJONG.js → exe-export-LLKDWX7F.js} +6 -6
- package/dist/{exe-import-GC5HO3TD.js → exe-import-XVAR7ZVC.js} +6 -6
- package/dist/{exe-key-R3ER4MYY.js → exe-key-E3YOJ2ME.js} +3 -3
- package/dist/{exe-org-OOO7KJVZ.js → exe-org-FEX66BTG.js} +2 -2
- package/dist/{fast-db-init-5DTYG5FZ.js → fast-db-init-SMQC6S3C.js} +1 -1
- package/dist/gateway/index.js +9 -9
- package/dist/{git-staleness-SVUTMS2F.js → git-staleness-HE6QCRSC.js} +3 -3
- package/dist/{git-task-sweep-EQHX4LXT.js → git-task-sweep-NWHG3FWG.js} +9 -9
- package/dist/{global-procedures-P7VOE476.js → global-procedures-KNA62DIE.js} +4 -4
- package/dist/{graph-auto-extract-UI374EYL.js → graph-auto-extract-4EZVBWQN.js} +3 -3
- package/dist/{hook-integrity-SA7S2SNI.js → hook-integrity-P3Z3HKMR.js} +1 -1
- package/dist/hooks/bug-report-worker.js +10 -10
- package/dist/hooks/codex-stop-task-finalizer.js +10 -10
- package/dist/hooks/commit-complete.js +11 -11
- package/dist/hooks/error-recall.js +7 -7
- package/dist/hooks/exe-heartbeat-hook.js +4 -4
- package/dist/hooks/ingest-worker.js +5 -5
- package/dist/hooks/ingest.js +12 -12
- package/dist/hooks/instructions-loaded.js +5 -5
- package/dist/hooks/notification.js +5 -5
- package/dist/hooks/post-compact.js +10 -10
- package/dist/hooks/post-tool-combined.js +5 -5
- package/dist/hooks/pre-compact.js +15 -15
- package/dist/hooks/pre-tool-use.js +14 -14
- package/dist/hooks/prompt-submit.js +59 -20
- package/dist/hooks/session-end.js +19 -19
- package/dist/hooks/session-start.js +9 -9
- package/dist/hooks/stop.js +17 -17
- package/dist/hooks/subagent-stop.js +10 -10
- package/dist/hooks/summary-worker.js +18 -18
- package/dist/index.js +17 -17
- package/dist/{installer-L72MRJPI.js → installer-4GPRFPIU.js} +6 -6
- package/dist/{installer-SLJ3YCHB.js → installer-MMXK6EHQ.js} +6 -6
- package/dist/{installer-LX2TU7RS.js → installer-TAFFG7WH.js} +6 -6
- package/dist/{key-backup-status-ORNMJEEA.js → key-backup-status-KQUGSNVJ.js} +1 -1
- package/dist/lib/agent-config.js +2 -2
- package/dist/lib/cloud-sync.js +6 -6
- package/dist/lib/config.js +1 -1
- package/dist/lib/consolidation.js +6 -6
- package/dist/lib/database.js +3 -3
- package/dist/lib/db-daemon-client.js +3 -3
- package/dist/lib/db.js +3 -3
- package/dist/lib/device-registry.js +1 -1
- package/dist/lib/embedder.js +4 -4
- package/dist/lib/employee-templates.js +5 -5
- package/dist/lib/employees.js +3 -3
- package/dist/lib/exe-daemon-client.js +3 -3
- package/dist/lib/exe-daemon.js +39 -39
- package/dist/lib/hybrid-search.js +6 -6
- package/dist/lib/identity.js +3 -3
- package/dist/lib/license.js +2 -2
- package/dist/lib/messaging.js +9 -9
- package/dist/lib/reminders.js +4 -4
- package/dist/lib/schedules.js +6 -6
- package/dist/lib/skill-learning.js +5 -5
- package/dist/lib/store.js +5 -5
- package/dist/lib/task-router.js +4 -4
- package/dist/lib/tasks.js +9 -9
- package/dist/lib/tmux-routing.js +8 -8
- package/dist/lib/token-spend.js +4 -4
- package/dist/{license-gate-J5YN264E.js → license-gate-OAPGTQXF.js} +3 -3
- package/dist/mcp/register-tools.js +57 -57
- package/dist/mcp/server.js +58 -58
- package/dist/mcp/tools/complete-reminder.js +5 -5
- package/dist/mcp/tools/create-reminder.js +5 -5
- package/dist/mcp/tools/create-task.js +11 -11
- package/dist/mcp/tools/deactivate-behavior.js +6 -6
- package/dist/mcp/tools/list-reminders.js +5 -5
- package/dist/mcp/tools/list-tasks.js +11 -11
- package/dist/mcp/tools/send-message.js +11 -11
- package/dist/mcp/tools/update-task.js +10 -10
- package/dist/{mcp-http-config-T76QB243.js → mcp-http-config-FPHVLE3N.js} +4 -4
- package/dist/{memory-cards-NTRYLVOU.js → memory-cards-VYZSCHZR.js} +3 -3
- package/dist/{memory-poisoning-defense-OJ2DEGBA.js → memory-poisoning-defense-NGJ63VZE.js} +3 -3
- package/dist/{memory-queue-NYIGZNCG.js → memory-queue-2SHTE6GU.js} +2 -2
- package/dist/{memory-queue-client-YJOLYALV.js → memory-queue-client-M7NHD4GY.js} +5 -5
- package/dist/{memory-reflection-4YOUTIMO.js → memory-reflection-XXN375ZD.js} +3 -3
- package/dist/{notifications-SF2XN5JE.js → notifications-Z6Q2SEHP.js} +8 -8
- package/dist/{orchestration-phase-FXKZYK6R.js → orchestration-phase-D3PNCSUY.js} +2 -2
- package/dist/{orchestrator-2W3VNAKG.js → orchestrator-RHJGFMAS.js} +10 -10
- package/dist/{plan-limits-LEM76SOQ.js → plan-limits-GCKK3L6F.js} +5 -5
- package/dist/{projection-worker-RQHV4VIR.js → projection-worker-GHWA6NEA.js} +2 -2
- package/dist/{push-notifications-NSYLKFXR.js → push-notifications-VJZFCUFZ.js} +2 -2
- package/dist/{reranker-OMADCS3D.js → reranker-JJRY3V3V.js} +2 -2
- package/dist/{review-polling-HD26LRW2.js → review-polling-XUIKH7HF.js} +9 -9
- package/dist/runtime/index.js +11 -11
- package/dist/{session-events-NYMENC3B.js → session-events-KURSY7LK.js} +9 -9
- package/dist/{session-kill-telemetry-LJU2MMZC.js → session-kill-telemetry-PD4UM5FM.js} +4 -4
- package/dist/{session-scope-QIDIKKFB.js → session-scope-5MOCMTAM.js} +8 -8
- package/dist/{setup-wizard-ANL7CVWX.js → setup-wizard-6SW2ND2B.js} +2 -2
- package/dist/{shard-manager-SP4YL5JQ.js → shard-manager-6JBG2K5X.js} +2 -2
- package/dist/{skill-refinement-3W3CIIG3.js → skill-refinement-JBZRPZKW.js} +3 -3
- package/dist/{task-enforcement-YXEOTTUG.js → task-enforcement-2WCWSZQ3.js} +8 -8
- package/dist/{task-scope-XXPTORGS.js → task-scope-HW6BE2PI.js} +8 -8
- package/dist/{tasks-crud-3UCNTXKQ.js → tasks-crud-WACRTPQK.js} +8 -8
- package/dist/{tasks-review-IPOWGI4L.js → tasks-review-LIWD4PGN.js} +8 -8
- package/dist/{token-budget-NP22DW2M.js → token-budget-5QD4ZSDX.js} +3 -3
- package/dist/{tool-capability-index-OBZXORBP.js → tool-capability-index-LBDYUK6L.js} +1 -1
- package/dist/{tool-telemetry-5JF2OAHG.js → tool-telemetry-2VGSVV3J.js} +1 -1
- package/dist/tui/App.js +21 -21
- package/dist/{tui-data-Z7FCER3K.js → tui-data-UKFAWSNP.js} +8 -8
- package/dist/{worker-gate-PJYHXNUB.js → worker-gate-NJRW5QYT.js} +2 -2
- package/dist/{workflow-engine-GA7JS7X2.js → workflow-engine-ICAQJSYT.js} +2 -2
- package/package.json +1 -1
- package/release-notes.json +187 -187
- package/stack.release.json +2 -2
- /package/dist/{chunk-ZYETFCDX.js → chunk-E5PVJXIP.js} +0 -0
- /package/dist/{chunk-J2OPV5FE.js → chunk-FMBRO3D7.js} +0 -0
- /package/dist/{chunk-NQND3GFO.js → chunk-J2KP4ZDX.js} +0 -0
- /package/dist/{chunk-PBBIAKN5.js → chunk-LKKKOWTH.js} +0 -0
- /package/dist/{chunk-LYMBXTEO.js → chunk-LZLXG7TK.js} +0 -0
- /package/dist/{chunk-7E6ZBXO7.js → chunk-PYDL42BL.js} +0 -0
- /package/dist/{chunk-7U664OM4.js → chunk-RES22KSZ.js} +0 -0
- /package/dist/{core-memory-KL5BOUXU.js → core-memory-QRQ62AZY.js} +0 -0
- /package/dist/{entity-boost-LIBVNNXO.js → entity-boost-MDWFYORT.js} +0 -0
- /package/dist/{message-queue-client-NTLKYGVO.js → message-queue-client-BJZEA6RV.js} +0 -0
- /package/dist/{oauth-server-TOWAZR4K.js → oauth-server-UM2TQJLJ.js} +0 -0
- /package/dist/{webhook-pipe-PJOFVBD3.js → webhook-pipe-VSLEA26V.js} +0 -0
- /package/dist/{wiki-acl-ZRCU7XYC.js → wiki-acl-RZCXSF5O.js} +0 -0
- /package/dist/{wiki-client-MMVRPTPK.js → wiki-client-NZR7RW4I.js} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# exe-os VPS stack — example environment variables
|
|
2
|
-
#
|
|
3
|
-
#
|
|
2
|
+
# Run `exe-os stack-init` or `node deploy/compose/generate-env.js` to auto-generate
|
|
3
|
+
# all secrets. Or copy to .env and replace CHANGEME_* values manually.
|
|
4
4
|
|
|
5
5
|
# --- Data Layer ---
|
|
6
6
|
POSTGRES_USER=exe
|
|
@@ -13,67 +13,53 @@ CLICKHOUSE_PASSWORD=CHANGEME_CLICKHOUSE_PASSWORD
|
|
|
13
13
|
|
|
14
14
|
REDIS_PASSWORD=CHANGEME_REDIS_PASSWORD
|
|
15
15
|
|
|
16
|
+
# --- GoTrue (shared auth) ---
|
|
17
|
+
GOTRUE_JWT_SECRET=CHANGEME_GOTRUE_JWT_SECRET
|
|
18
|
+
GOTRUE_SITE_URL=https://crm.askexe.com
|
|
19
|
+
GOTRUE_EXTERNAL_URL=https://auth.askexe.com
|
|
20
|
+
GOTRUE_DISABLE_SIGNUP=false
|
|
21
|
+
GOTRUE_MAILER_AUTOCONFIRM=true
|
|
22
|
+
|
|
16
23
|
# --- CRM ---
|
|
17
|
-
CRM_IMAGE_TAG=ghcr.io/askexe/exe-crm:v0.9.
|
|
18
|
-
CRM_SERVER_URL=https://
|
|
24
|
+
CRM_IMAGE_TAG=ghcr.io/askexe/exe-crm:v0.9.3
|
|
25
|
+
CRM_SERVER_URL=https://crm.askexe.com
|
|
19
26
|
CRM_APP_SECRET=CHANGEME_CRM_APP_SECRET
|
|
27
|
+
EXE_CRM_ADMIN_TOKEN=CHANGEME_EXE_CRM_ADMIN_TOKEN
|
|
20
28
|
CRM_HOST_PORT=3000
|
|
21
29
|
|
|
22
30
|
# --- Wiki ---
|
|
23
|
-
WIKI_IMAGE_TAG=ghcr.io/askexe/exe-wiki:v0.9.
|
|
31
|
+
WIKI_IMAGE_TAG=ghcr.io/askexe/exe-wiki:v0.9.4
|
|
24
32
|
WIKI_DB_SCHEMA=wiki
|
|
25
33
|
WIKI_VECTOR_DB=postgres
|
|
26
34
|
WIKI_AUTH_TOKEN=CHANGEME_WIKI_AUTH_TOKEN
|
|
35
|
+
EXE_WIKI_ADMIN_TOKEN=CHANGEME_EXE_WIKI_ADMIN_TOKEN
|
|
27
36
|
WIKI_JWT_SECRET=CHANGEME_WIKI_JWT_SECRET
|
|
28
37
|
WIKI_SIG_KEY=CHANGEME_WIKI_SIG_KEY
|
|
29
38
|
WIKI_SIG_SALT=CHANGEME_WIKI_SIG_SALT
|
|
30
39
|
WIKI_HOST_PORT=3001
|
|
31
40
|
|
|
32
|
-
# --- exe-os ---
|
|
33
|
-
EXE_OS_IMAGE_TAG=ghcr.io/askexe/exe-os:v0.9.
|
|
41
|
+
# --- exe-os (daemon) ---
|
|
42
|
+
EXE_OS_IMAGE_TAG=ghcr.io/askexe/exe-os:v0.9.154
|
|
34
43
|
EXED_MCP_TOKEN=CHANGEME_EXED_MCP_TOKEN
|
|
35
44
|
EXED_DEVICE_ID=vps-default
|
|
36
|
-
# VPS-only: enables cloud/local SQLite -> exe-db Postgres projection.
|
|
37
|
-
# Keep false on laptops/dev boxes.
|
|
38
45
|
EXE_CLOUD_SYNC_TO_POSTGRES=true
|
|
46
|
+
EXE_LICENSE_KEY=CHANGEME_EXE_LICENSE_KEY
|
|
39
47
|
|
|
40
48
|
# --- Gateway ---
|
|
41
|
-
GATEWAY_IMAGE_TAG=ghcr.io/askexe/exe-gateway:v0.9.
|
|
49
|
+
GATEWAY_IMAGE_TAG=ghcr.io/askexe/exe-gateway:v0.9.3
|
|
42
50
|
EXE_GATEWAY_AUTH_TOKEN=CHANGEME_EXE_GATEWAY_AUTH_TOKEN
|
|
43
51
|
EXE_GATEWAY_WS_RELAY_AUTH_TOKEN=CHANGEME_EXE_GATEWAY_WS_RELAY_AUTH_TOKEN
|
|
44
52
|
EXE_GATEWAY_WHATSAPP_VERIFY_TOKEN=CHANGEME_EXE_GATEWAY_WHATSAPP_VERIFY_TOKEN
|
|
45
|
-
# SET_MANUALLY
|
|
46
|
-
WHATSAPP_ACCESS_TOKEN=CHANGEME_WHATSAPP_ACCESS_TOKEN
|
|
47
53
|
API_ROUTER_URL=https://gateway.askexe.com
|
|
48
|
-
API_ROUTER_KEY=CHANGEME_API_ROUTER_KEY
|
|
49
|
-
# BYOK: to use your own API keys instead of the Exe API Router,
|
|
50
|
-
# set BYOK_ENABLED=true and provide ANTHROPIC_API_KEY below.
|
|
51
|
-
# BYOK_ENABLED=false
|
|
52
|
-
# ANTHROPIC_API_KEY=CHANGEME_ANTHROPIC_API_KEY
|
|
53
54
|
GATEWAY_HTTP_HOST_PORT=3100
|
|
54
55
|
GATEWAY_WS_HOST_PORT=3101
|
|
55
56
|
|
|
56
|
-
# --- Monitoring
|
|
57
|
-
|
|
57
|
+
# --- Monitoring ---
|
|
58
|
+
MONITOR_HUB_IMAGE_TAG=ghcr.io/askexe/exe-monitor-hub:v0.9.4
|
|
59
|
+
MONITOR_AGENT_IMAGE_TAG=ghcr.io/askexe/exe-monitor-agent:v0.9.4
|
|
60
|
+
EXE_MONITOR_ADMIN_TOKEN=CHANGEME_EXE_MONITOR_ADMIN_TOKEN
|
|
58
61
|
MONITOR_HUB_URL=https://monitor.askexe.com
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
MONITOR_AGENT_KEY=CHANGEME_MONITOR_AGENT_PUBLIC_KEY_FROM_MONITOR_HUB
|
|
62
|
+
MONITOR_AGENT_TOKEN=CHANGEME_MONITOR_AGENT_TOKEN
|
|
63
|
+
MONITOR_AGENT_KEY=CHANGEME_MONITOR_AGENT_KEY
|
|
62
64
|
MONITOR_AGENT_LISTEN=:45876
|
|
63
|
-
|
|
64
|
-
# --- AskExe central monitoring hub auth (AskExe-owned infra only) ---
|
|
65
|
-
# Customer VPSs normally run only MONITOR_AGENT_* above. These hub values are
|
|
66
|
-
# for monitor.askexe.com on exe-db-jkt.
|
|
67
|
-
MONITOR_HUB_PUBLIC_URL=https://monitor.askexe.com
|
|
68
|
-
MONITOR_HUB_SOURCE_DIR=/opt/exe-monitor
|
|
69
|
-
MONITOR_HUB_HOST_PORT=8090
|
|
70
|
-
MONITOR_HUB_DATA_DIR=/opt/exe-monitor-data
|
|
71
|
-
MONITOR_TRUSTED_AUTH_HEADER=X-AskExe-User-Email
|
|
72
|
-
# Keep false during bootstrap; flip true after the GoTrue auth proxy is live.
|
|
73
|
-
MONITOR_DISABLE_PASSWORD_AUTH=false
|
|
74
|
-
MONITOR_USER_CREATION=true
|
|
75
|
-
MONITOR_SHARE_ALL_SYSTEMS=false
|
|
76
|
-
|
|
77
|
-
# --- License ---
|
|
78
|
-
# injected by deploy_client
|
|
79
|
-
EXE_LICENSE_KEY=CHANGEME_EXE_LICENSE_KEY
|
|
65
|
+
MONITOR_HUB_PORT=8090
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Automated backup for exe-os stack — runs daily via cron or systemd timer.
|
|
3
|
+
# Backs up: postgres (all databases), gateway auth state, wiki storage.
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
BACKUP_DIR="${BACKUP_DIR:-/opt/exe-backups}"
|
|
7
|
+
RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-7}"
|
|
8
|
+
DATE=$(date +%Y%m%d-%H%M%S)
|
|
9
|
+
COMPOSE_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
10
|
+
|
|
11
|
+
mkdir -p "$BACKUP_DIR"
|
|
12
|
+
|
|
13
|
+
echo "[backup] Starting exe-os stack backup ($DATE)"
|
|
14
|
+
|
|
15
|
+
# 1. Postgres dump (all databases)
|
|
16
|
+
echo "[backup] Dumping postgres..."
|
|
17
|
+
docker exec exe-db pg_dumpall -U exe > "$BACKUP_DIR/postgres-$DATE.sql" 2>/dev/null
|
|
18
|
+
gzip "$BACKUP_DIR/postgres-$DATE.sql"
|
|
19
|
+
echo "[backup] Postgres: $(du -h "$BACKUP_DIR/postgres-$DATE.sql.gz" | cut -f1)"
|
|
20
|
+
|
|
21
|
+
# 2. Gateway auth state (Baileys creds)
|
|
22
|
+
echo "[backup] Backing up gateway auth state..."
|
|
23
|
+
docker cp exe-gateway:/data/. "$BACKUP_DIR/gateway-$DATE/" 2>/dev/null || echo "[backup] Gateway backup skipped (not running)"
|
|
24
|
+
tar -czf "$BACKUP_DIR/gateway-$DATE.tar.gz" -C "$BACKUP_DIR" "gateway-$DATE" 2>/dev/null && rm -rf "$BACKUP_DIR/gateway-$DATE"
|
|
25
|
+
|
|
26
|
+
# 3. Wiki storage (uploaded docs)
|
|
27
|
+
echo "[backup] Backing up wiki storage..."
|
|
28
|
+
docker cp exe-wiki:/app/server/storage/. "$BACKUP_DIR/wiki-$DATE/" 2>/dev/null || echo "[backup] Wiki backup skipped"
|
|
29
|
+
tar -czf "$BACKUP_DIR/wiki-$DATE.tar.gz" -C "$BACKUP_DIR" "wiki-$DATE" 2>/dev/null && rm -rf "$BACKUP_DIR/wiki-$DATE"
|
|
30
|
+
|
|
31
|
+
# 4. Retention — delete backups older than N days
|
|
32
|
+
echo "[backup] Cleaning backups older than $RETENTION_DAYS days..."
|
|
33
|
+
find "$BACKUP_DIR" -name "*.gz" -mtime "+$RETENTION_DAYS" -delete 2>/dev/null
|
|
34
|
+
find "$BACKUP_DIR" -name "*.sql" -mtime "+$RETENTION_DAYS" -delete 2>/dev/null
|
|
35
|
+
|
|
36
|
+
echo "[backup] Done. Backups at $BACKUP_DIR:"
|
|
37
|
+
ls -lh "$BACKUP_DIR"/*.gz 2>/dev/null | tail -5
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Exe OS",
|
|
3
|
+
"logo": null,
|
|
4
|
+
"colors": {
|
|
5
|
+
"primary": "#F5D76E",
|
|
6
|
+
"background": "#0F0E1A",
|
|
7
|
+
"surface": "rgba(245, 215, 110, 0.08)",
|
|
8
|
+
"text": "#f8f5ea",
|
|
9
|
+
"muted": "rgba(248, 245, 234, 0.72)"
|
|
10
|
+
},
|
|
11
|
+
"fonts": {
|
|
12
|
+
"heading": "Epilogue",
|
|
13
|
+
"body": "Manrope",
|
|
14
|
+
"mono": "Space Grotesk"
|
|
15
|
+
},
|
|
16
|
+
"support": {
|
|
17
|
+
"email": "support@askexe.com",
|
|
18
|
+
"url": "https://askexe.com"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Cloudflare Tunnel config — routes *.askexe.com to local services.
|
|
2
|
+
# Copy to config.yml and replace TUNNEL_ID with your tunnel UUID.
|
|
3
|
+
# Create tunnel: cloudflared tunnel create <name>
|
|
4
|
+
# Then copy credentials JSON to this directory.
|
|
5
|
+
|
|
6
|
+
tunnel: CHANGEME_TUNNEL_ID
|
|
7
|
+
credentials-file: /etc/cloudflared/CHANGEME_TUNNEL_ID.json
|
|
8
|
+
|
|
9
|
+
ingress:
|
|
10
|
+
# CRM
|
|
11
|
+
- hostname: crm.CHANGEME_DOMAIN
|
|
12
|
+
service: http://exe-crm:3000
|
|
13
|
+
# Wiki
|
|
14
|
+
- hostname: wiki.CHANGEME_DOMAIN
|
|
15
|
+
service: http://exe-wiki:3001
|
|
16
|
+
# Gateway (WhatsApp, webhooks, pairing)
|
|
17
|
+
- hostname: gateway.CHANGEME_DOMAIN
|
|
18
|
+
service: http://exe-gateway:3100
|
|
19
|
+
# Monitor
|
|
20
|
+
- hostname: monitor.CHANGEME_DOMAIN
|
|
21
|
+
service: http://exe-monitor-hub:8090
|
|
22
|
+
# Auth (GoTrue)
|
|
23
|
+
- hostname: auth.CHANGEME_DOMAIN
|
|
24
|
+
service: http://gotrue:9999
|
|
25
|
+
# exe-os daemon (MCP)
|
|
26
|
+
- hostname: api.CHANGEME_DOMAIN
|
|
27
|
+
service: http://exe-os:8765
|
|
28
|
+
# Catch-all
|
|
29
|
+
- service: http_status:404
|
|
@@ -36,6 +36,7 @@ services:
|
|
|
36
36
|
PGDATA: /var/lib/postgresql/data/pgdata
|
|
37
37
|
volumes:
|
|
38
38
|
- postgres_data:/var/lib/postgresql/data
|
|
39
|
+
- ./init-db.sql:/docker-entrypoint-initdb.d/01-init.sql:ro
|
|
39
40
|
networks:
|
|
40
41
|
backend:
|
|
41
42
|
ipv4_address: 10.42.0.10
|
|
@@ -104,6 +105,71 @@ services:
|
|
|
104
105
|
driver: json-file
|
|
105
106
|
options: { max-size: "10m", max-file: "3" }
|
|
106
107
|
|
|
108
|
+
gotrue:
|
|
109
|
+
image: supabase/gotrue:v2.172.1@sha256:b0dd7aa28dd1f9a8bd31f136c8b912661f701d9b863171e5843cb08f18f49de4
|
|
110
|
+
container_name: gotrue
|
|
111
|
+
restart: unless-stopped
|
|
112
|
+
depends_on:
|
|
113
|
+
exe-db:
|
|
114
|
+
condition: service_healthy
|
|
115
|
+
env_file:
|
|
116
|
+
- path: .env
|
|
117
|
+
required: false
|
|
118
|
+
environment:
|
|
119
|
+
GOTRUE_DB_DRIVER: postgres
|
|
120
|
+
GOTRUE_DB_DATABASE_URL: postgres://${POSTGRES_USER:-exe}:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}@exe-db:5432/${POSTGRES_DB:-exedb}?sslmode=disable&search_path=auth
|
|
121
|
+
GOTRUE_SITE_URL: ${GOTRUE_SITE_URL:-https://crm.askexe.com}
|
|
122
|
+
GOTRUE_URI_ALLOW_LIST: ${GOTRUE_URI_ALLOW_LIST:-}
|
|
123
|
+
GOTRUE_JWT_SECRET: ${GOTRUE_JWT_SECRET:?GOTRUE_JWT_SECRET is required}
|
|
124
|
+
GOTRUE_JWT_EXP: ${GOTRUE_JWT_EXP:-3600}
|
|
125
|
+
GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated
|
|
126
|
+
API_EXTERNAL_URL: ${GOTRUE_EXTERNAL_URL:-https://auth.askexe.com}
|
|
127
|
+
GOTRUE_DISABLE_SIGNUP: ${GOTRUE_DISABLE_SIGNUP:-false}
|
|
128
|
+
GOTRUE_MAILER_AUTOCONFIRM: ${GOTRUE_MAILER_AUTOCONFIRM:-true}
|
|
129
|
+
GOTRUE_SMTP_HOST: ${SMTP_HOST:-}
|
|
130
|
+
GOTRUE_SMTP_PORT: ${SMTP_PORT:-587}
|
|
131
|
+
GOTRUE_SMTP_USER: ${SMTP_USER:-}
|
|
132
|
+
GOTRUE_SMTP_PASS: ${SMTP_PASS:-}
|
|
133
|
+
GOTRUE_SMTP_ADMIN_EMAIL: ${SMTP_FROM:-noreply@askexe.com}
|
|
134
|
+
ports:
|
|
135
|
+
- "127.0.0.1:${GOTRUE_HOST_PORT:-9999}:9999"
|
|
136
|
+
networks:
|
|
137
|
+
backend:
|
|
138
|
+
ipv4_address: 10.42.0.13
|
|
139
|
+
healthcheck:
|
|
140
|
+
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:9999/health"]
|
|
141
|
+
interval: 15s
|
|
142
|
+
timeout: 5s
|
|
143
|
+
start_period: 10s
|
|
144
|
+
retries: 5
|
|
145
|
+
logging:
|
|
146
|
+
driver: json-file
|
|
147
|
+
options: { max-size: "10m", max-file: "3" }
|
|
148
|
+
|
|
149
|
+
exe-monitor-hub:
|
|
150
|
+
image: ${MONITOR_HUB_IMAGE_TAG:-ghcr.io/askexe/exe-monitor-hub:v0.9.4}
|
|
151
|
+
container_name: exe-monitor-hub
|
|
152
|
+
restart: unless-stopped
|
|
153
|
+
environment:
|
|
154
|
+
EXE_MONITOR_ADMIN_TOKEN: ${EXE_MONITOR_ADMIN_TOKEN:-}
|
|
155
|
+
GOTRUE_URL: http://gotrue:9999
|
|
156
|
+
ports:
|
|
157
|
+
- "127.0.0.1:${MONITOR_HUB_PORT:-8090}:8090"
|
|
158
|
+
volumes:
|
|
159
|
+
- monitor_hub_data:/app/pb_data
|
|
160
|
+
networks:
|
|
161
|
+
backend:
|
|
162
|
+
ipv4_address: 10.42.0.14
|
|
163
|
+
healthcheck:
|
|
164
|
+
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:8090/api/health"]
|
|
165
|
+
interval: 30s
|
|
166
|
+
timeout: 5s
|
|
167
|
+
start_period: 15s
|
|
168
|
+
retries: 5
|
|
169
|
+
logging:
|
|
170
|
+
driver: json-file
|
|
171
|
+
options: { max-size: "10m", max-file: "3" }
|
|
172
|
+
|
|
107
173
|
# ------------------------------------------------------------------
|
|
108
174
|
# Apps
|
|
109
175
|
# ------------------------------------------------------------------
|
|
@@ -112,9 +178,14 @@ services:
|
|
|
112
178
|
image: ${CRM_IMAGE_TAG:-ghcr.io/askexe/exe-crm:v0.9.2}
|
|
113
179
|
container_name: exe-crm
|
|
114
180
|
restart: unless-stopped
|
|
181
|
+
# Auto-migrate on boot: run database init before starting the app.
|
|
182
|
+
# Twenty CRM won't create tables automatically — this ensures they exist.
|
|
183
|
+
command: ["sh", "-c", "yarn database:init:prod 2>/dev/null || true && node dist/src/main"]
|
|
115
184
|
depends_on:
|
|
116
185
|
exe-db:
|
|
117
186
|
condition: service_healthy
|
|
187
|
+
gotrue:
|
|
188
|
+
condition: service_healthy
|
|
118
189
|
clickhouse:
|
|
119
190
|
condition: service_healthy
|
|
120
191
|
redis:
|
|
@@ -128,6 +199,8 @@ services:
|
|
|
128
199
|
EXE_LICENSE_KEY: ${EXE_LICENSE_KEY:?EXE_LICENSE_KEY is required — purchase at https://askexe.com}
|
|
129
200
|
SERVER_URL: ${CRM_SERVER_URL:-https://crm.askexe.com}
|
|
130
201
|
APP_SECRET: ${CRM_APP_SECRET:?CRM_APP_SECRET is required}
|
|
202
|
+
EXE_CRM_ADMIN_TOKEN: ${EXE_CRM_ADMIN_TOKEN:-}
|
|
203
|
+
GOTRUE_URL: http://gotrue:9999
|
|
131
204
|
PG_DATABASE_URL: postgres://${POSTGRES_USER:-exe}:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}@exe-db:5432/${POSTGRES_DB:-exedb}
|
|
132
205
|
REDIS_URL: redis://:${REDIS_PASSWORD:?REDIS_PASSWORD is required}@redis:6379
|
|
133
206
|
CLICKHOUSE_URL: http://${CLICKHOUSE_USER:-exe}:${CLICKHOUSE_PASSWORD:?CLICKHOUSE_PASSWORD is required}@clickhouse:8123/${CLICKHOUSE_DB:-default}
|
|
@@ -198,9 +271,13 @@ services:
|
|
|
198
271
|
image: ${WIKI_IMAGE_TAG:-ghcr.io/askexe/exe-wiki:v0.9.2}
|
|
199
272
|
container_name: exe-wiki
|
|
200
273
|
restart: unless-stopped
|
|
274
|
+
# Wiki uses Prisma — runs migrate on boot via built-in entrypoint.
|
|
275
|
+
# If tables don't exist, Prisma creates them automatically.
|
|
201
276
|
depends_on:
|
|
202
277
|
exe-db:
|
|
203
278
|
condition: service_healthy
|
|
279
|
+
gotrue:
|
|
280
|
+
condition: service_healthy
|
|
204
281
|
env_file:
|
|
205
282
|
- path: .env
|
|
206
283
|
required: false
|
|
@@ -211,6 +288,8 @@ services:
|
|
|
211
288
|
STORAGE_DIR: /app/server/storage
|
|
212
289
|
DATABASE_URL: postgres://${POSTGRES_USER:-exe}:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}@exe-db:5432/${POSTGRES_DB:-exedb}?schema=${WIKI_DB_SCHEMA:-wiki}
|
|
213
290
|
AUTH_TOKEN: ${WIKI_AUTH_TOKEN:?WIKI_AUTH_TOKEN is required}
|
|
291
|
+
EXE_WIKI_ADMIN_TOKEN: ${EXE_WIKI_ADMIN_TOKEN:-}
|
|
292
|
+
GOTRUE_URL: http://gotrue:9999
|
|
214
293
|
JWT_SECRET: ${WIKI_JWT_SECRET:?WIKI_JWT_SECRET is required}
|
|
215
294
|
SIG_KEY: ${WIKI_SIG_KEY:?WIKI_SIG_KEY is required}
|
|
216
295
|
SIG_SALT: ${WIKI_SIG_SALT:?WIKI_SIG_SALT is required}
|
|
@@ -290,6 +369,7 @@ services:
|
|
|
290
369
|
EXE_GATEWAY_PORT: "3100"
|
|
291
370
|
EXE_GATEWAY_HOST: "127.0.0.1"
|
|
292
371
|
EXE_GATEWAY_AUTH_TOKEN: ${EXE_GATEWAY_AUTH_TOKEN:?EXE_GATEWAY_AUTH_TOKEN is required}
|
|
372
|
+
GOTRUE_URL: http://gotrue:9999
|
|
293
373
|
EXE_GATEWAY_WHATSAPP_VERIFY_TOKEN: ${EXE_GATEWAY_WHATSAPP_VERIFY_TOKEN:?EXE_GATEWAY_WHATSAPP_VERIFY_TOKEN is required}
|
|
294
374
|
EXE_GATEWAY_WS_RELAY_ENABLED: "true"
|
|
295
375
|
EXE_GATEWAY_WS_RELAY_HOST: "127.0.0.1"
|
|
@@ -351,6 +431,32 @@ services:
|
|
|
351
431
|
driver: json-file
|
|
352
432
|
options: { max-size: "10m", max-file: "3" }
|
|
353
433
|
|
|
434
|
+
# ------------------------------------------------------------------
|
|
435
|
+
# Infrastructure — Cloudflare Tunnel (replaces nginx + SSL certs)
|
|
436
|
+
# ------------------------------------------------------------------
|
|
437
|
+
|
|
438
|
+
cloudflared:
|
|
439
|
+
image: cloudflare/cloudflared:latest
|
|
440
|
+
container_name: cloudflared
|
|
441
|
+
restart: unless-stopped
|
|
442
|
+
command: tunnel --config /etc/cloudflared/config.yml run
|
|
443
|
+
volumes:
|
|
444
|
+
- ${CLOUDFLARED_CONFIG_DIR:-./cloudflared}:/etc/cloudflared:ro
|
|
445
|
+
networks:
|
|
446
|
+
backend:
|
|
447
|
+
ipv4_address: 10.42.0.31
|
|
448
|
+
frontend:
|
|
449
|
+
ipv4_address: 10.43.0.31
|
|
450
|
+
healthcheck:
|
|
451
|
+
test: ["CMD", "cloudflared", "tunnel", "info", "--output", "json"]
|
|
452
|
+
interval: 30s
|
|
453
|
+
timeout: 5s
|
|
454
|
+
start_period: 15s
|
|
455
|
+
retries: 5
|
|
456
|
+
logging:
|
|
457
|
+
driver: json-file
|
|
458
|
+
options: { max-size: "10m", max-file: "3" }
|
|
459
|
+
|
|
354
460
|
# ------------------------------------------------------------------
|
|
355
461
|
# Volumes
|
|
356
462
|
# ------------------------------------------------------------------
|
|
@@ -373,6 +479,8 @@ volumes:
|
|
|
373
479
|
driver: local
|
|
374
480
|
monitor_agent_data:
|
|
375
481
|
driver: local
|
|
482
|
+
monitor_hub_data:
|
|
483
|
+
driver: local
|
|
376
484
|
|
|
377
485
|
# ------------------------------------------------------------------
|
|
378
486
|
# Networks
|
|
@@ -5,11 +5,11 @@ const REGISTRY = "ghcr.io/askexe";
|
|
|
5
5
|
// own package semver internally, but customer deployments use the tested stack
|
|
6
6
|
// image alias so one stack manifest can pin the whole release. exe-os/exed is
|
|
7
7
|
// the exception because the runtime package version is the orchestrator release.
|
|
8
|
-
const STACK_IMAGE_TAG = "v0.9.
|
|
9
|
-
const EXED_RELEASE_TAG = "v0.9.
|
|
8
|
+
const STACK_IMAGE_TAG = "v0.9.4";
|
|
9
|
+
const EXED_RELEASE_TAG = "v0.9.154";
|
|
10
10
|
|
|
11
11
|
const POSTGRES_USER = "exe";
|
|
12
|
-
const POSTGRES_DB = "
|
|
12
|
+
const POSTGRES_DB = "exedb";
|
|
13
13
|
const CLICKHOUSE_DB = "default";
|
|
14
14
|
const CLICKHOUSE_USER = "exe";
|
|
15
15
|
export const CRM_IMAGE_TAG = `${REGISTRY}/exe-crm:${STACK_IMAGE_TAG}`;
|
|
@@ -21,6 +21,7 @@ const WIKI_HOST_PORT = "3001";
|
|
|
21
21
|
export const EXE_OS_IMAGE_TAG = `${REGISTRY}/exe-os:${EXED_RELEASE_TAG}`;
|
|
22
22
|
export const GATEWAY_IMAGE_TAG = `${REGISTRY}/exe-gateway:${STACK_IMAGE_TAG}`;
|
|
23
23
|
export const MONITOR_AGENT_IMAGE_TAG = `${REGISTRY}/exe-monitor-agent:${STACK_IMAGE_TAG}`;
|
|
24
|
+
export const MONITOR_HUB_IMAGE_TAG = `${REGISTRY}/exe-monitor-hub:${STACK_IMAGE_TAG}`;
|
|
24
25
|
const GATEWAY_HTTP_HOST_PORT = "3100";
|
|
25
26
|
const GATEWAY_WS_HOST_PORT = "3101";
|
|
26
27
|
const RANDOM_SECRET_16 = 16;
|
|
@@ -56,10 +57,18 @@ export function generateEnv(options: GenerateEnvOptions): string {
|
|
|
56
57
|
"",
|
|
57
58
|
`REDIS_PASSWORD=${randomSecret(RANDOM_SECRET_32)}`,
|
|
58
59
|
"",
|
|
60
|
+
"# --- GoTrue (shared auth) ---",
|
|
61
|
+
`GOTRUE_JWT_SECRET=${randomSecret(RANDOM_SECRET_48)}`,
|
|
62
|
+
`GOTRUE_SITE_URL=https://crm.${normalizedDomain}`,
|
|
63
|
+
`GOTRUE_EXTERNAL_URL=https://auth.${normalizedDomain}`,
|
|
64
|
+
"GOTRUE_DISABLE_SIGNUP=false",
|
|
65
|
+
"GOTRUE_MAILER_AUTOCONFIRM=true",
|
|
66
|
+
"",
|
|
59
67
|
"# --- CRM ---",
|
|
60
68
|
`CRM_IMAGE_TAG=${CRM_IMAGE_TAG}`,
|
|
61
69
|
`CRM_SERVER_URL=https://${normalizedDomain}`,
|
|
62
70
|
`CRM_APP_SECRET=${randomSecret(RANDOM_SECRET_48)}`,
|
|
71
|
+
`EXE_CRM_ADMIN_TOKEN=${randomSecret(RANDOM_SECRET_48)}`,
|
|
63
72
|
`CRM_HOST_PORT=${CRM_HOST_PORT}`,
|
|
64
73
|
"",
|
|
65
74
|
"# --- Wiki ---",
|
|
@@ -67,6 +76,7 @@ export function generateEnv(options: GenerateEnvOptions): string {
|
|
|
67
76
|
`WIKI_DB_SCHEMA=${WIKI_DB_SCHEMA}`,
|
|
68
77
|
`WIKI_VECTOR_DB=${WIKI_VECTOR_DB}`,
|
|
69
78
|
`WIKI_AUTH_TOKEN=${randomSecret(RANDOM_SECRET_48)}`,
|
|
79
|
+
`EXE_WIKI_ADMIN_TOKEN=${randomSecret(RANDOM_SECRET_48)}`,
|
|
70
80
|
`WIKI_JWT_SECRET=${randomSecret(RANDOM_SECRET_48)}`,
|
|
71
81
|
`WIKI_SIG_KEY=${randomSecret(RANDOM_SECRET_48)}`,
|
|
72
82
|
`WIKI_SIG_SALT=${randomSecret(RANDOM_SECRET_16)}`,
|
|
@@ -95,12 +105,15 @@ export function generateEnv(options: GenerateEnvOptions): string {
|
|
|
95
105
|
`GATEWAY_HTTP_HOST_PORT=${GATEWAY_HTTP_HOST_PORT}`,
|
|
96
106
|
`GATEWAY_WS_HOST_PORT=${GATEWAY_WS_HOST_PORT}`,
|
|
97
107
|
"",
|
|
98
|
-
"# --- Monitoring
|
|
108
|
+
"# --- Monitoring ---",
|
|
109
|
+
`MONITOR_HUB_IMAGE_TAG=${MONITOR_HUB_IMAGE_TAG}`,
|
|
99
110
|
`MONITOR_AGENT_IMAGE_TAG=${MONITOR_AGENT_IMAGE_TAG}`,
|
|
111
|
+
`EXE_MONITOR_ADMIN_TOKEN=${randomSecret(RANDOM_SECRET_48)}`,
|
|
100
112
|
`MONITOR_HUB_URL=${DEFAULT_MONITOR_HUB_URL}`,
|
|
101
113
|
"MONITOR_AGENT_TOKEN=CHANGEME_MONITOR_AGENT_TOKEN_FROM_MONITOR_HUB",
|
|
102
114
|
"MONITOR_AGENT_KEY=CHANGEME_MONITOR_AGENT_PUBLIC_KEY_FROM_MONITOR_HUB",
|
|
103
115
|
`MONITOR_AGENT_LISTEN=${DEFAULT_MONITOR_AGENT_LISTEN}`,
|
|
116
|
+
"MONITOR_HUB_PORT=8090",
|
|
104
117
|
"",
|
|
105
118
|
"# --- License ---",
|
|
106
119
|
LICENSE_KEY_COMMENT,
|
|
@@ -129,6 +142,7 @@ export function generateExampleEnv(): string {
|
|
|
129
142
|
`CRM_IMAGE_TAG=${CRM_IMAGE_TAG}`,
|
|
130
143
|
"CRM_SERVER_URL=https://CHANGEME_DOMAIN",
|
|
131
144
|
"CRM_APP_SECRET=CHANGEME_CRM_APP_SECRET",
|
|
145
|
+
"EXE_CRM_ADMIN_TOKEN=CHANGEME_EXE_CRM_ADMIN_TOKEN",
|
|
132
146
|
`CRM_HOST_PORT=${CRM_HOST_PORT}`,
|
|
133
147
|
"",
|
|
134
148
|
"# --- Wiki ---",
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
-- exe-os database initialization — runs on first boot.
|
|
2
|
+
-- Creates the exe superuser, schemas, and extensions.
|
|
3
|
+
-- Idempotent: safe to run multiple times.
|
|
4
|
+
|
|
5
|
+
-- Ensure exe user exists with superuser
|
|
6
|
+
DO $$ BEGIN
|
|
7
|
+
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'exe') THEN
|
|
8
|
+
CREATE ROLE exe WITH LOGIN SUPERUSER PASSWORD current_setting('app.postgres_password', true);
|
|
9
|
+
ELSE
|
|
10
|
+
ALTER ROLE exe SUPERUSER;
|
|
11
|
+
END IF;
|
|
12
|
+
END $$;
|
|
13
|
+
|
|
14
|
+
-- Create extensions
|
|
15
|
+
CREATE EXTENSION IF NOT EXISTS vector;
|
|
16
|
+
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
|
17
|
+
|
|
18
|
+
-- Create all schemas
|
|
19
|
+
CREATE SCHEMA IF NOT EXISTS raw;
|
|
20
|
+
CREATE SCHEMA IF NOT EXISTS graph;
|
|
21
|
+
CREATE SCHEMA IF NOT EXISTS gateway;
|
|
22
|
+
CREATE SCHEMA IF NOT EXISTS wiki;
|
|
23
|
+
CREATE SCHEMA IF NOT EXISTS crm;
|
|
24
|
+
CREATE SCHEMA IF NOT EXISTS auth;
|
|
25
|
+
|
|
26
|
+
-- Grant exe full access to all schemas
|
|
27
|
+
DO $$ DECLARE s text; BEGIN
|
|
28
|
+
FOR s IN SELECT schema_name FROM information_schema.schemata
|
|
29
|
+
WHERE schema_name NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
|
|
30
|
+
LOOP
|
|
31
|
+
EXECUTE 'GRANT ALL ON SCHEMA ' || quote_ident(s) || ' TO exe';
|
|
32
|
+
EXECUTE 'GRANT ALL ON ALL TABLES IN SCHEMA ' || quote_ident(s) || ' TO exe';
|
|
33
|
+
EXECUTE 'GRANT ALL ON ALL SEQUENCES IN SCHEMA ' || quote_ident(s) || ' TO exe';
|
|
34
|
+
EXECUTE 'ALTER DEFAULT PRIVILEGES IN SCHEMA ' || quote_ident(s) || ' GRANT ALL ON TABLES TO exe';
|
|
35
|
+
EXECUTE 'ALTER DEFAULT PRIVILEGES IN SCHEMA ' || quote_ident(s) || ' GRANT ALL ON SEQUENCES TO exe';
|
|
36
|
+
END LOOP;
|
|
37
|
+
END $$;
|
|
38
|
+
|
|
39
|
+
-- Create raw.raw_events landing pad
|
|
40
|
+
CREATE TABLE IF NOT EXISTS raw.raw_events (
|
|
41
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
42
|
+
source TEXT NOT NULL,
|
|
43
|
+
source_id TEXT,
|
|
44
|
+
event_type TEXT NOT NULL,
|
|
45
|
+
payload JSONB NOT NULL,
|
|
46
|
+
metadata JSONB,
|
|
47
|
+
timestamp TIMESTAMPTZ DEFAULT now(),
|
|
48
|
+
created_at TIMESTAMPTZ DEFAULT now(),
|
|
49
|
+
processed_at TIMESTAMPTZ,
|
|
50
|
+
error TEXT,
|
|
51
|
+
projections JSONB DEFAULT '{}'::jsonb
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
CREATE INDEX IF NOT EXISTS idx_raw_events_unprocessed ON raw.raw_events (created_at) WHERE processed_at IS NULL;
|
|
55
|
+
CREATE UNIQUE INDEX IF NOT EXISTS uq_raw_events_dedup ON raw.raw_events (source, source_id, event_type);
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# exe-os stack first-time setup — run once on a fresh VPS.
|
|
3
|
+
# Usage: ./setup.sh --client <name> --domain <domain> [--license <key>]
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
|
7
|
+
info() { echo -e "${GREEN}[setup]${NC} $1"; }
|
|
8
|
+
warn() { echo -e "${YELLOW}[setup]${NC} $1"; }
|
|
9
|
+
err() { echo -e "${RED}[setup]${NC} $1" >&2; }
|
|
10
|
+
|
|
11
|
+
# Parse args
|
|
12
|
+
CLIENT="" DOMAIN="" LICENSE=""
|
|
13
|
+
while [[ $# -gt 0 ]]; do
|
|
14
|
+
case $1 in
|
|
15
|
+
--client) CLIENT="$2"; shift 2;;
|
|
16
|
+
--domain) DOMAIN="$2"; shift 2;;
|
|
17
|
+
--license) LICENSE="$2"; shift 2;;
|
|
18
|
+
*) err "Unknown arg: $1"; exit 1;;
|
|
19
|
+
esac
|
|
20
|
+
done
|
|
21
|
+
[[ -z "$CLIENT" || -z "$DOMAIN" ]] && { err "Usage: ./setup.sh --client <name> --domain <domain>"; exit 1; }
|
|
22
|
+
|
|
23
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
24
|
+
cd "$SCRIPT_DIR"
|
|
25
|
+
|
|
26
|
+
# Step 1: Docker + GHCR auth
|
|
27
|
+
info "Step 1: Docker registry authentication"
|
|
28
|
+
if ! docker info >/dev/null 2>&1; then
|
|
29
|
+
err "Docker is not running. Install Docker first: https://docs.docker.com/engine/install/"
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
if [[ -f .ghcr-token ]]; then
|
|
34
|
+
info "Logging into GHCR with stored token..."
|
|
35
|
+
cat .ghcr-token | docker login ghcr.io -u exe-os-pull --password-stdin 2>/dev/null || true
|
|
36
|
+
elif [[ -n "${GHCR_TOKEN:-}" ]]; then
|
|
37
|
+
info "Logging into GHCR with GHCR_TOKEN env var..."
|
|
38
|
+
echo "$GHCR_TOKEN" | docker login ghcr.io -u exe-os-pull --password-stdin 2>/dev/null || true
|
|
39
|
+
else
|
|
40
|
+
warn "No GHCR token found. Set GHCR_TOKEN env var or create .ghcr-token file."
|
|
41
|
+
warn "Images must be pullable — public or pre-authed."
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Step 2: Generate .env
|
|
45
|
+
info "Step 2: Generating .env file"
|
|
46
|
+
if [[ -f .env ]]; then
|
|
47
|
+
warn ".env already exists — skipping generation. Delete .env to regenerate."
|
|
48
|
+
else
|
|
49
|
+
if command -v node >/dev/null 2>&1; then
|
|
50
|
+
node -e "
|
|
51
|
+
const { generateEnv } = require('../../dist/deploy/compose/generate-env.js');
|
|
52
|
+
console.log(generateEnv({ clientName: '$CLIENT', domain: '$DOMAIN', licenseKey: '${LICENSE:-}' || undefined }));
|
|
53
|
+
" > .env 2>/dev/null || {
|
|
54
|
+
# Fallback: generate inline
|
|
55
|
+
info "Generating secrets inline..."
|
|
56
|
+
gen() { openssl rand -hex "$1"; }
|
|
57
|
+
cat > .env << ENVEOF
|
|
58
|
+
POSTGRES_USER=exe
|
|
59
|
+
POSTGRES_PASSWORD=$(gen 32)
|
|
60
|
+
POSTGRES_DB=exedb
|
|
61
|
+
CLICKHOUSE_DB=default
|
|
62
|
+
CLICKHOUSE_USER=exe
|
|
63
|
+
CLICKHOUSE_PASSWORD=$(gen 32)
|
|
64
|
+
REDIS_PASSWORD=$(gen 32)
|
|
65
|
+
GOTRUE_JWT_SECRET=$(gen 48)
|
|
66
|
+
GOTRUE_SITE_URL=https://crm.${DOMAIN}
|
|
67
|
+
GOTRUE_EXTERNAL_URL=https://auth.${DOMAIN}
|
|
68
|
+
GOTRUE_DISABLE_SIGNUP=false
|
|
69
|
+
GOTRUE_MAILER_AUTOCONFIRM=true
|
|
70
|
+
CRM_IMAGE_TAG=ghcr.io/askexe/exe-crm:v0.9.3
|
|
71
|
+
CRM_SERVER_URL=https://crm.${DOMAIN}
|
|
72
|
+
CRM_APP_SECRET=$(gen 48)
|
|
73
|
+
EXE_CRM_ADMIN_TOKEN=$(gen 48)
|
|
74
|
+
CRM_HOST_PORT=3000
|
|
75
|
+
WIKI_IMAGE_TAG=ghcr.io/askexe/exe-wiki:v0.9.4
|
|
76
|
+
WIKI_DB_SCHEMA=wiki
|
|
77
|
+
WIKI_VECTOR_DB=postgres
|
|
78
|
+
WIKI_AUTH_TOKEN=$(gen 48)
|
|
79
|
+
EXE_WIKI_ADMIN_TOKEN=$(gen 48)
|
|
80
|
+
WIKI_JWT_SECRET=$(gen 48)
|
|
81
|
+
WIKI_SIG_KEY=$(gen 48)
|
|
82
|
+
WIKI_SIG_SALT=$(gen 16)
|
|
83
|
+
WIKI_HOST_PORT=3001
|
|
84
|
+
EXE_OS_IMAGE_TAG=ghcr.io/askexe/exe-os:v0.9.155
|
|
85
|
+
EXED_MCP_TOKEN=$(gen 48)
|
|
86
|
+
EXED_DEVICE_ID=vps-${CLIENT}
|
|
87
|
+
EXE_CLOUD_SYNC_TO_POSTGRES=true
|
|
88
|
+
EXE_LICENSE_KEY=${LICENSE:-CHANGEME_EXE_LICENSE_KEY}
|
|
89
|
+
GATEWAY_IMAGE_TAG=ghcr.io/askexe/exe-gateway:v0.9.3
|
|
90
|
+
EXE_GATEWAY_AUTH_TOKEN=$(gen 48)
|
|
91
|
+
EXE_GATEWAY_WS_RELAY_AUTH_TOKEN=$(gen 48)
|
|
92
|
+
EXE_GATEWAY_WHATSAPP_VERIFY_TOKEN=$(gen 32)
|
|
93
|
+
API_ROUTER_URL=https://gateway.${DOMAIN}
|
|
94
|
+
GATEWAY_HTTP_HOST_PORT=3100
|
|
95
|
+
GATEWAY_WS_HOST_PORT=3101
|
|
96
|
+
MONITOR_HUB_IMAGE_TAG=ghcr.io/askexe/exe-monitor-hub:v0.9.4
|
|
97
|
+
MONITOR_AGENT_IMAGE_TAG=ghcr.io/askexe/exe-monitor-agent:v0.9.4
|
|
98
|
+
EXE_MONITOR_ADMIN_TOKEN=$(gen 48)
|
|
99
|
+
MONITOR_HUB_URL=https://monitor.${DOMAIN}
|
|
100
|
+
MONITOR_AGENT_TOKEN=CHANGEME_MONITOR_AGENT_TOKEN
|
|
101
|
+
MONITOR_AGENT_KEY=CHANGEME_MONITOR_AGENT_KEY
|
|
102
|
+
MONITOR_AGENT_LISTEN=:45876
|
|
103
|
+
MONITOR_HUB_PORT=8090
|
|
104
|
+
ENVEOF
|
|
105
|
+
}
|
|
106
|
+
fi
|
|
107
|
+
info ".env generated with auto-generated secrets"
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
# Step 3: Cloudflared tunnel config
|
|
111
|
+
info "Step 3: Cloudflare Tunnel setup"
|
|
112
|
+
if [[ ! -f cloudflared/config.yml ]]; then
|
|
113
|
+
if [[ -f cloudflared/config.yml.example ]]; then
|
|
114
|
+
warn "Copy cloudflared/config.yml.example → cloudflared/config.yml"
|
|
115
|
+
warn "Then set TUNNEL_ID and DOMAIN in the config."
|
|
116
|
+
warn "Create tunnel: cloudflared tunnel create exe-${CLIENT}"
|
|
117
|
+
fi
|
|
118
|
+
else
|
|
119
|
+
info "Cloudflared config exists."
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
# Step 4: Pull images
|
|
123
|
+
info "Step 4: Pulling Docker images..."
|
|
124
|
+
docker compose pull 2>&1 || { err "Image pull failed — check GHCR authentication"; exit 1; }
|
|
125
|
+
|
|
126
|
+
# Step 5: Start stack
|
|
127
|
+
info "Step 5: Starting stack..."
|
|
128
|
+
docker compose up -d 2>&1
|
|
129
|
+
|
|
130
|
+
# Step 6: Wait for health
|
|
131
|
+
info "Step 6: Waiting for services to be healthy..."
|
|
132
|
+
sleep 10
|
|
133
|
+
HEALTHY=0
|
|
134
|
+
for i in $(seq 1 30); do
|
|
135
|
+
COUNT=$(docker ps --filter "health=healthy" --format '{{.Names}}' | wc -l | tr -d ' ')
|
|
136
|
+
TOTAL=$(docker ps --format '{{.Names}}' | wc -l | tr -d ' ')
|
|
137
|
+
echo -ne "\r $COUNT/$TOTAL healthy (attempt $i/30)..."
|
|
138
|
+
if [[ "$COUNT" -ge "$TOTAL" ]]; then HEALTHY=1; break; fi
|
|
139
|
+
sleep 5
|
|
140
|
+
done
|
|
141
|
+
echo ""
|
|
142
|
+
[[ "$HEALTHY" -eq 1 ]] && info "All services healthy!" || warn "Some services not healthy yet — check docker ps"
|
|
143
|
+
|
|
144
|
+
# Step 7: Verify
|
|
145
|
+
info "Step 7: Verification"
|
|
146
|
+
docker ps --format 'table {{.Names}}\t{{.Status}}'
|
|
147
|
+
echo ""
|
|
148
|
+
info "Stack deployed! Next steps:"
|
|
149
|
+
echo " 1. Configure Cloudflare tunnel (if not done)"
|
|
150
|
+
echo " 2. Open https://crm.${DOMAIN} to create admin account"
|
|
151
|
+
echo " 3. Open https://wiki.${DOMAIN} to set up wiki"
|
|
152
|
+
echo " 4. Configure WhatsApp: edit gateway.json, restart gateway, pair at https://gateway.${DOMAIN}/pair/<name>"
|
|
153
|
+
echo " 5. Verify: curl https://crm.${DOMAIN}/healthz && curl https://wiki.${DOMAIN}/api/ping"
|
|
154
|
+
|
|
155
|
+
# Step 8: Firewall — ensure outbound HTTPS is open
|
|
156
|
+
info "Step 8: Checking network connectivity..."
|
|
157
|
+
if curl -s --max-time 5 https://ghcr.io >/dev/null 2>&1; then
|
|
158
|
+
info "Outbound HTTPS working (GHCR reachable)"
|
|
159
|
+
else
|
|
160
|
+
warn "Cannot reach ghcr.io — check firewall/network. Docker pulls will fail."
|
|
161
|
+
fi
|
|
162
|
+
if curl -s --max-time 5 https://api.cloudflare.com >/dev/null 2>&1; then
|
|
163
|
+
info "Cloudflare reachable"
|
|
164
|
+
else
|
|
165
|
+
warn "Cannot reach Cloudflare — tunnel won't work."
|
|
166
|
+
fi
|