@askexenow/exe-os 0.9.238 → 0.9.243
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.customer.example +12 -0
- package/deploy/compose/.env.example +13 -1
- package/deploy/compose/cloudflared/config.yml.example +23 -4
- package/deploy/compose/docker-compose.yml +27 -7
- package/deploy/compose/generate-env.ts +49 -1
- package/deploy/compose/init-db.sql +10 -2
- package/deploy/stack-manifests/v0.9.json +165 -9
- package/dist/{active-agent-X3GALNAR.js → active-agent-KO4ZWDXE.js} +4 -4
- package/dist/{active-agent-6WX7GZBH.js → active-agent-KP2O52HA.js} +4 -4
- package/dist/{agentic-ontology-NBU3FHEX.js → agentic-ontology-DXE5J6I5.js} +1 -1
- package/dist/{backfill-metadata-NG2L5GUP.js → backfill-metadata-DFTIGPXP.js} +7 -7
- package/dist/{background-jobs-RWL46VRD.js → background-jobs-CRXY7T4Y.js} +2 -2
- package/dist/{behaviors-DH7XFONJ.js → behaviors-BL3QCHBT.js} +4 -4
- package/dist/bin/age-ontology-load.js +2 -2
- package/dist/bin/agentic-ontology-backfill.js +9 -9
- package/dist/bin/agentic-reflection-backfill.js +10 -10
- package/dist/bin/agentic-semantic-label.js +9 -9
- package/dist/bin/backfill-conversations.js +9 -9
- package/dist/bin/backfill-responses.js +9 -9
- package/dist/bin/backfill-vectors.js +11 -11
- package/dist/bin/bulk-sync-postgres.js +10 -10
- package/dist/bin/cc-doctor.js +3 -3
- package/dist/bin/cleanup-stale-review-tasks.js +13 -13
- package/dist/bin/cli.js +27 -22
- package/dist/bin/exe-agent-config.js +4 -4
- package/dist/bin/exe-agent.js +8 -8
- package/dist/bin/exe-assign.js +11 -11
- package/dist/bin/exe-boot.js +22 -22
- package/dist/bin/exe-call.js +5 -5
- package/dist/bin/exe-cloud.js +8 -8
- package/dist/bin/exe-dispatch.js +13 -13
- package/dist/bin/exe-doctor.js +1 -1
- package/dist/bin/exe-export-behaviors.js +10 -10
- package/dist/bin/exe-forget.js +9 -9
- package/dist/bin/exe-gateway.js +8 -8
- package/dist/bin/exe-healthcheck.js +3 -3
- package/dist/bin/exe-heartbeat.js +13 -13
- package/dist/bin/exe-kill.js +18 -18
- package/dist/bin/exe-launch-agent.js +22 -22
- package/dist/bin/exe-new-employee.js +8 -8
- package/dist/bin/exe-pending-messages.js +14 -14
- package/dist/bin/exe-pending-notifications.js +13 -13
- package/dist/bin/exe-pending-reviews.js +13 -13
- package/dist/bin/exe-rename.js +5 -5
- package/dist/bin/exe-review.js +17 -17
- package/dist/bin/exe-search.js +8 -8
- package/dist/bin/exe-session-cleanup.js +20 -20
- package/dist/bin/exe-settings.js +7 -7
- package/dist/bin/exe-start-codex.js +14 -14
- package/dist/bin/exe-start-opencode.js +11 -11
- package/dist/bin/exe-status.js +14 -14
- package/dist/bin/exe-support.js +3 -3
- package/dist/bin/exe-team.js +4 -4
- package/dist/bin/git-sweep.js +13 -13
- package/dist/bin/graph-backfill.js +8 -8
- package/dist/bin/graph-export.js +8 -8
- package/dist/bin/import-history.js +10 -10
- package/dist/bin/install.js +7 -7
- package/dist/bin/intercom-check.js +4 -4
- package/dist/bin/mcp-sessions.js +2 -2
- package/dist/bin/orchestration-metrics.js +5 -5
- 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 +13 -13
- package/dist/bin/setup.js +3 -3
- package/dist/bin/shard-migrate.js +8 -8
- package/dist/bin/stack-update.js +324 -20
- package/dist/bin/verify-stack.js +3 -383
- package/dist/bin/vps-backup.js +8 -160
- package/dist/bin/vps-health-gate.js +10 -220
- package/dist/{branding-I7YYX4FM.js → branding-XWMO5EDR.js} +1 -1
- package/dist/{capacity-monitor-KAKNWAA4.js → capacity-monitor-4CSBC7AP.js} +14 -14
- package/dist/{catchup-brief-ZB2OR45O.js → catchup-brief-LF5Z6Q6E.js} +17 -17
- package/dist/{chunk-NQU2RTCP.js → chunk-222SI7QC.js} +14 -14
- package/dist/{chunk-JZMVLAZ2.js → chunk-2WBBVEIB.js} +1 -1
- package/dist/{chunk-Q4MZN62R.js → chunk-3V53HH5T.js} +4 -4
- package/dist/{chunk-ES5JM6V2.js → chunk-57SULZJ2.js} +3 -3
- package/dist/{chunk-QI4IXJN7.js → chunk-5CHYEKMH.js} +7 -4
- package/dist/chunk-5DMAMQNU.js +168 -0
- package/dist/{chunk-MPG2FFQS.js → chunk-5JIG2FP2.js} +1 -1
- package/dist/{chunk-UWQ3XCDG.js → chunk-5WK7X5CF.js} +2 -2
- package/dist/{chunk-NS7FW3NG.js → chunk-6JAGJN77.js} +2 -2
- package/dist/{chunk-NCJNGQUZ.js → chunk-73UE2PHT.js} +1 -1
- package/dist/{chunk-JL3K5OTS.js → chunk-7IZWLMTP.js} +1 -1
- package/dist/{chunk-FQJWTRCB.js → chunk-A4K2ZT6N.js} +4 -4
- package/dist/{chunk-EAIZLNLP.js → chunk-AHXEU5XB.js} +1 -1
- package/dist/{chunk-NNEYTOUS.js → chunk-AWRL5FGM.js} +19 -78
- package/dist/{chunk-JBMZS5WO.js → chunk-BSPOEYAO.js} +1 -1
- package/dist/{chunk-M5TK7JET.js → chunk-CBDPEJOR.js} +5 -5
- package/dist/{chunk-2LYJTK47.js → chunk-CEJO7244.js} +2 -2
- package/dist/{chunk-JLHSEBNQ.js → chunk-CPXGLSIL.js} +3 -3
- package/dist/{chunk-WQXJIMBO.js → chunk-CWITU7DW.js} +2 -2
- package/dist/{chunk-T3ASODFG.js → chunk-DGBGIXCC.js} +4 -4
- package/dist/{chunk-U3XMIHPD.js → chunk-DLZYAYVM.js} +60 -14
- package/dist/{chunk-XCGJPZ6H.js → chunk-DR5BGWFR.js} +2 -2
- package/dist/{chunk-BZWKTFEB.js → chunk-ENVRFBTB.js} +2 -2
- package/dist/{chunk-KRLR26L2.js → chunk-F3GM6OOP.js} +4 -4
- package/dist/{chunk-ENWFSMOS.js → chunk-F7JLZXHC.js} +60 -26
- package/dist/{chunk-COMWI7SO.js → chunk-FFLILAG6.js} +1 -1
- package/dist/{chunk-NJS4GRIR.js → chunk-GHEWRYMY.js} +18 -2
- package/dist/{chunk-7PVUUC3O.js → chunk-GHT4REOS.js} +5 -5
- package/dist/{chunk-YDG343II.js → chunk-HANG6NLF.js} +4 -6
- package/dist/{chunk-2O5GJFYQ.js → chunk-HCBMPZDT.js} +1 -1
- package/dist/chunk-HOGTZLVU.js +244 -0
- package/dist/{chunk-LXP6VRFH.js → chunk-I5PIBL56.js} +3 -3
- package/dist/chunk-IRHNV4GY.js +388 -0
- package/dist/{chunk-F4TCKCKK.js → chunk-ITZVPCBQ.js} +33 -12
- package/dist/{chunk-IAPFFVYR.js → chunk-IZVKWBIP.js} +1 -1
- package/dist/{chunk-HFYCKIVJ.js → chunk-J7V7LPPX.js} +2 -2
- package/dist/{chunk-YUQ7GGAL.js → chunk-JLKUVK5J.js} +1 -1
- package/dist/{chunk-WQCSGDRG.js → chunk-JLNXKG3K.js} +1 -1
- package/dist/{chunk-ZZBOV6WA.js → chunk-K2BDE2B5.js} +4 -4
- package/dist/{chunk-KDJRFJDL.js → chunk-K333WOW4.js} +30 -2
- package/dist/{chunk-LUCHTCME.js → chunk-KEZXW3RP.js} +1 -1
- package/dist/{chunk-GXU3XRI5.js → chunk-KLQI7QY4.js} +3 -3
- package/dist/{chunk-UODVZGBQ.js → chunk-KN7LPTIB.js} +1 -1
- package/dist/{chunk-ESKBZN4Q.js → chunk-L4WRH3DL.js} +1 -1
- package/dist/{chunk-UISUGXJU.js → chunk-LAOB5BKV.js} +2 -2
- package/dist/{chunk-2VXHPSIJ.js → chunk-LQSFP2BV.js} +1 -1
- package/dist/{chunk-AYBC6AYP.js → chunk-LSFHEMVI.js} +9 -9
- package/dist/{chunk-IQNT6KAE.js → chunk-MCESA5UW.js} +2 -2
- package/dist/{chunk-UPMHG7ET.js → chunk-MEIHREPM.js} +1 -1
- package/dist/{chunk-D5C56WO3.js → chunk-MOZ2YQ54.js} +1 -1
- package/dist/{chunk-CLGB3FGL.js → chunk-MPX3TRMQ.js} +2 -2
- package/dist/{chunk-VK5IBXXT.js → chunk-NBY6R37W.js} +61 -232
- package/dist/{chunk-RXGTA6YQ.js → chunk-NEYQAEYU.js} +7 -7
- package/dist/{chunk-MBHZDXGN.js → chunk-NL35XNLI.js} +1 -1
- package/dist/{chunk-IDCJNL7C.js → chunk-NLGMHPEN.js} +1 -1
- package/dist/{chunk-N4IJWOIS.js → chunk-NRVV4Y5V.js} +4 -4
- package/dist/{chunk-PQBANSH6.js → chunk-NVZR7T4E.js} +1 -1
- package/dist/{chunk-BJOU5MBY.js → chunk-NWBHL5PI.js} +1 -1
- package/dist/{chunk-VEU6LVBR.js → chunk-OEMX65EA.js} +1 -1
- package/dist/{chunk-JHFXCYZP.js → chunk-ONAQAL3O.js} +1 -1
- package/dist/{chunk-NBV23TC4.js → chunk-OWQ3CCYJ.js} +12 -13
- package/dist/{chunk-4HMKJDPB.js → chunk-PI6V23GF.js} +5 -4
- package/dist/{chunk-CJEVAKKC.js → chunk-Q2OAQPWY.js} +1 -1
- package/dist/{chunk-C7BVANSU.js → chunk-QLDWASTX.js} +28 -32
- package/dist/{chunk-EPWDTS2Q.js → chunk-QMTGMCWB.js} +1 -1
- package/dist/{chunk-VI2FJY2M.js → chunk-QP4FHME2.js} +2 -2
- package/dist/{chunk-YUS7IS3I.js → chunk-QUNKPR6Y.js} +5 -5
- package/dist/{chunk-3NYRIK73.js → chunk-QUZVAHO7.js} +2 -2
- package/dist/{chunk-VHKL4S4T.js → chunk-RRHSONV5.js} +2 -2
- package/dist/{chunk-HUVSY6NF.js → chunk-RYDHEWYY.js} +2 -2
- package/dist/{chunk-QQFZID36.js → chunk-U7WOVXBB.js} +2 -2
- package/dist/chunk-UIRWDGMB.js +230 -0
- package/dist/{chunk-3JVO6X4W.js → chunk-V2GZMY6O.js} +1 -1
- package/dist/{chunk-JBUHOWIV.js → chunk-VHALWCUO.js} +1 -1
- package/dist/{chunk-7LIXU3TB.js → chunk-VQAP35DA.js} +20 -18
- package/dist/{chunk-5KDROSDV.js → chunk-VRIMTCX2.js} +1 -1
- package/dist/{chunk-SUNYJ6YE.js → chunk-VT2B5BHM.js} +1 -1
- package/dist/{chunk-UZIJDYDA.js → chunk-VWVJVQDH.js} +2 -2
- package/dist/{chunk-TRZ5KA2R.js → chunk-VXIMSRTO.js} +2 -2
- package/dist/{chunk-BTPXNV5W.js → chunk-WCXZF42W.js} +1 -1
- package/dist/{chunk-6OJJF4WP.js → chunk-XJUUWHVN.js} +1 -1
- package/dist/{chunk-F7LU65PQ.js → chunk-Y25OJWOQ.js} +14 -2
- package/dist/{chunk-2ORPA23Y.js → chunk-YMXXD2GW.js} +36 -8
- package/dist/{chunk-YENDNLAD.js → chunk-YMZHTTOQ.js} +1 -1
- package/dist/{chunk-EPLBVWIM.js → chunk-YRVW57UW.js} +139 -125
- package/dist/{chunk-BRFH5X7G.js → chunk-Z7VDUS6L.js} +1 -1
- package/dist/{chunk-G67R75DG.js → chunk-ZKFPHJIJ.js} +1 -1
- package/dist/{chunk-RM6PJ34R.js → chunk-ZVXJSQOR.js} +1 -1
- package/dist/{co-activation-OCQPRJ2I.js → co-activation-L6I2LSJO.js} +3 -3
- package/dist/{co-occurrence-S62AC2BR.js → co-occurrence-QARWYUAY.js} +3 -3
- package/dist/{code-context-index-FCQOPUEA.js → code-context-index-UIYQRDHD.js} +4 -4
- package/dist/{content-extractor-SPSH5X33.js → content-extractor-EYRVGD6O.js} +2 -2
- package/dist/{conversation-wiki-populator-YU35LNRK.js → conversation-wiki-populator-L7O6F3BB.js} +1 -1
- package/dist/{crdt-sync-VS254UOH.js → crdt-sync-R6YROKDH.js} +1 -1
- package/dist/{crm-webhook-CST5WBNY.js → crm-webhook-WK3PYJJK.js} +2 -2
- package/dist/{cto-delegation-gate-2PY563OA.js → cto-delegation-gate-5JZORQIT.js} +12 -12
- package/dist/{daemon-auth-2IZACWSG.js → daemon-auth-2HEOL6VG.js} +2 -2
- package/dist/{daemon-orchestration-P34RDHTM.js → daemon-orchestration-BJ3T5MMF.js} +16 -15
- package/dist/{db-backup-JEHRFLYW.js → db-backup-EWS52P2W.js} +2 -2
- package/dist/{dreaming-UF4LPNLV.js → dreaming-BOSBDRI3.js} +13 -13
- package/dist/{entity-boost-T5IYWWDZ.js → entity-boost-6ZVX7DFB.js} +26 -2
- package/dist/{exe-drift-DOWP33NY.js → exe-drift-WRE6RADZ.js} +4 -4
- package/dist/{exe-export-QCB5UOXQ.js → exe-export-7N5PBCMK.js} +8 -8
- package/dist/{exe-import-JHFIXRB5.js → exe-import-YOOE7S3H.js} +8 -8
- package/dist/{exe-key-ZVKBTZVI.js → exe-key-GXJSTCX2.js} +4 -4
- package/dist/{exe-org-3FNET2J7.js → exe-org-42YMQL75.js} +2 -2
- package/dist/{exe-snapshot-LBM3LL3I.js → exe-snapshot-ODUCFW7G.js} +18 -18
- package/dist/{fast-db-init-PTUUO2IO.js → fast-db-init-YSR7RMVZ.js} +1 -1
- package/dist/{founder-context-BQ5NBDUV.js → founder-context-Q2HUCZX4.js} +2 -2
- package/dist/gateway/index.js +9 -9
- package/dist/{gateway-client-YGSA5QMC.js → gateway-client-4QXHKN5C.js} +1 -1
- package/dist/{git-staleness-5SFBUMPC.js → git-staleness-BJDTCDPC.js} +3 -3
- package/dist/{git-task-sweep-XMK5IQXK.js → git-task-sweep-L3U3T5HM.js} +13 -13
- package/dist/{global-procedures-W4U257TI.js → global-procedures-HCHEHKY2.js} +4 -4
- package/dist/{graph-auto-extract-5ZD4AUSB.js → graph-auto-extract-FP5C76LS.js} +3 -3
- package/dist/{hook-integrity-SB53Y7UK.js → hook-integrity-2OU3T6UC.js} +1 -1
- package/dist/hooks/bug-report-worker.js +15 -14
- package/dist/hooks/codex-stop-task-finalizer.js +15 -14
- package/dist/hooks/commit-complete.js +16 -16
- package/dist/hooks/error-recall.js +10 -10
- package/dist/hooks/exe-heartbeat-hook.js +5 -5
- package/dist/hooks/ingest-worker.js +8 -8
- package/dist/hooks/ingest.js +13 -13
- package/dist/hooks/instructions-loaded.js +7 -7
- package/dist/hooks/manifest.json +20 -20
- package/dist/hooks/notification.js +6 -6
- package/dist/hooks/post-compact.js +15 -15
- package/dist/hooks/post-tool-combined.js +7 -7
- package/dist/hooks/pre-compact.js +20 -20
- package/dist/hooks/pre-tool-use.js +28 -25
- package/dist/hooks/prompt-submit.js +62 -31
- package/dist/hooks/session-end.js +26 -26
- package/dist/hooks/session-start.js +39 -15
- package/dist/hooks/stop.js +22 -22
- package/dist/hooks/subagent-stop.js +15 -15
- package/dist/hooks/summary-worker.js +32 -27
- package/dist/index.js +21 -21
- package/dist/{installer-2HULECDJ.js → installer-AWMUCRN4.js} +7 -7
- package/dist/{installer-BCOJG2SE.js → installer-HB3NH6FG.js} +9 -9
- package/dist/{installer-N5XZAFE4.js → installer-RU6EVOBL.js} +6 -6
- package/dist/{intercom-queue-RNM6EPGA.js → intercom-queue-A6UJEFIF.js} +1 -1
- package/dist/{key-backup-status-OZ2CXUDW.js → key-backup-status-4YKCV4ZV.js} +1 -1
- package/dist/lib/agent-config.js +2 -2
- package/dist/lib/cloud-sync.js +10 -8
- package/dist/lib/config.js +1 -1
- package/dist/lib/consolidation.js +8 -8
- package/dist/lib/database.js +3 -3
- package/dist/lib/db-daemon-client.js +5 -5
- 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 +109 -75
- package/dist/lib/hybrid-search.js +8 -8
- package/dist/lib/identity.js +3 -3
- package/dist/lib/keychain.js +1 -1
- package/dist/lib/license.js +2 -2
- package/dist/lib/messaging.js +13 -13
- package/dist/lib/post-tool-memory.js +3 -3
- package/dist/lib/reminders.js +4 -4
- package/dist/lib/schedules.js +8 -8
- package/dist/lib/session-registry.js +5 -5
- package/dist/lib/skill-learning.js +5 -5
- package/dist/lib/store.js +7 -7
- package/dist/lib/task-router.js +4 -4
- package/dist/lib/tasks.js +14 -13
- package/dist/lib/tmux-routing.js +12 -12
- package/dist/lib/token-spend.js +4 -4
- package/dist/lib/ws-client.js +1 -1
- package/dist/{license-gate-XJDIL6OZ.js → license-gate-6JQQFBHS.js} +3 -3
- package/dist/mcp/register-tools.js +68 -67
- package/dist/mcp/server.js +70 -69
- 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 +16 -15
- 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 +16 -15
- package/dist/mcp/tools/send-message.js +15 -15
- package/dist/mcp/tools/update-task.js +15 -14
- package/dist/{mcp-http-config-RTXPLRH5.js → mcp-http-config-XIJR5P2Z.js} +4 -4
- package/dist/{memory-cards-3FBGRV6J.js → memory-cards-H4BJJ5OK.js} +3 -3
- package/dist/{memory-graph-extractor-5D3FU5N5.js → memory-graph-extractor-SDGM3GVR.js} +4 -4
- package/dist/{memory-poisoning-defense-P6GL2RMF.js → memory-poisoning-defense-UVU67DGJ.js} +3 -3
- package/dist/{memory-queue-FTNBWLS4.js → memory-queue-FNT5WHXP.js} +2 -2
- package/dist/{memory-queue-client-DHSHEIHQ.js → memory-queue-client-JZCFYTWQ.js} +5 -5
- package/dist/{memory-reflection-5CVV2M3G.js → memory-reflection-GGB5K35L.js} +3 -3
- package/dist/{notifications-NV54INLG.js → notifications-P3XQZDTH.js} +12 -12
- package/dist/{orchestration-events-TEYCD6GO.js → orchestration-events-25WEKUKH.js} +4 -4
- package/dist/{orchestration-phase-SGA7PJ5G.js → orchestration-phase-C26XVKLZ.js} +2 -2
- package/dist/{orchestrator-JCNHGP6M.js → orchestrator-VIXTY4E4.js} +14 -14
- package/dist/{pipeline-router-IX635D3U.js → pipeline-router-S5PE5U6B.js} +4 -4
- package/dist/{plan-limits-H65VL6LC.js → plan-limits-DGIVM42H.js} +5 -5
- package/dist/{prediction-log-OMWHW7FL.js → prediction-log-DOEOHDHS.js} +1 -1
- package/dist/{project-boot-WMI6CWRX.js → project-boot-4ZL2W7DN.js} +12 -2
- package/dist/{projection-worker-JMGAPKH6.js → projection-worker-GG2W5OM3.js} +3 -3
- package/dist/{push-notifications-E2XXEWJZ.js → push-notifications-AMHVR6DF.js} +2 -2
- package/dist/{reranker-T4A2M7K2.js → reranker-UCPLQZE2.js} +2 -2
- package/dist/{review-polling-SAQ24T6L.js → review-polling-P2MWEXLR.js} +13 -13
- package/dist/runtime/index.js +15 -15
- package/dist/{session-events-JNUK47KH.js → session-events-5CD66R6U.js} +13 -13
- package/dist/{session-kill-telemetry-GLCDARKV.js → session-kill-telemetry-7FBHTEDN.js} +4 -4
- package/dist/{session-scope-UR7OFFOB.js → session-scope-VMIPAZU7.js} +12 -12
- package/dist/{setup-wizard-GQYG36KS.js → setup-wizard-BNR47URR.js} +3 -3
- package/dist/{shard-manager-G6MHCO7X.js → shard-manager-VGA2TYHM.js} +2 -2
- package/dist/{skill-refinement-WWWFGTUS.js → skill-refinement-NRG4WWRW.js} +3 -3
- package/dist/stack-release-PFZI22WC.js +521 -0
- package/dist/{stack-update-NO5MNARG.js → stack-update-JIWJGGLX.js} +3 -3
- package/dist/{steward-gate-TAD7GEVL.js → steward-gate-L7DJMF4C.js} +4 -4
- package/dist/{task-enforcement-2LI5KWFE.js → task-enforcement-XQL77PZH.js} +52 -12
- package/dist/{task-scope-AYK6BVC7.js → task-scope-R3XKBIHL.js} +12 -12
- package/dist/{tasks-crud-OD75EH2G.js → tasks-crud-DQOG2NPG.js} +12 -12
- package/dist/tasks-notify-4EQYG52H.js +37 -0
- package/dist/{tasks-review-CC2EGWBL.js → tasks-review-XPFJ4DSJ.js} +12 -12
- package/dist/{telemetry-upload-H6BU6QF7.js → telemetry-upload-OT5B5HUY.js} +7 -7
- package/dist/{token-budget-6TK55BBU.js → token-budget-D2LQKCAV.js} +3 -3
- package/dist/{tool-capability-index-WIV4K3FB.js → tool-capability-index-FAJ5ZHDF.js} +1 -1
- package/dist/{tool-telemetry-E7NWXX5R.js → tool-telemetry-QIF5BCLF.js} +1 -1
- package/dist/tui/App.js +26 -26
- package/dist/{tui-data-ROOXTJQ5.js → tui-data-UEV2QOR3.js} +108 -12
- package/dist/{whatsapp-config-W63RQ3AU.js → whatsapp-config-GOSELKTE.js} +7 -0
- package/dist/{worker-gate-MOQZ2D34.js → worker-gate-PRCKA23W.js} +2 -2
- package/dist/{workflow-engine-4MQJI5F2.js → workflow-engine-7X6LLH3M.js} +2 -2
- package/dist/{worktree-K2GDO4QX.js → worktree-RICSCT2S.js} +5 -5
- package/package.json +1 -1
- package/release-notes.json +144 -304
- package/stack.release.json +4 -3
- package/dist/preflight-EAH2MI76.js +0 -287
- /package/dist/{chunk-P2JDWX67.js → chunk-AQBEG33D.js} +0 -0
- /package/dist/{chunk-A4TPCHMA.js → chunk-B7JGEDVE.js} +0 -0
- /package/dist/{chunk-RX2KGETT.js → chunk-JXI4XUTV.js} +0 -0
- /package/dist/{chunk-SNYDRHV3.js → chunk-U3DUFHOT.js} +0 -0
- /package/dist/{chunk-YGJTKLGM.js → chunk-VBPC7IC7.js} +0 -0
- /package/dist/{chunk-HTUJBTBM.js → chunk-VUS6WXQ3.js} +0 -0
- /package/dist/{chunk-HFF6YG7R.js → chunk-XAYRZHLV.js} +0 -0
- /package/dist/{core-memory-67AVQ3Z7.js → core-memory-4KAIKQRQ.js} +0 -0
- /package/dist/{message-queue-client-KAJN6TIJ.js → message-queue-client-S6W5VMJV.js} +0 -0
- /package/dist/{oauth-server-QEXRSXEP.js → oauth-server-2ESBZB7F.js} +0 -0
- /package/dist/{webhook-pipe-LY4XEDL7.js → webhook-pipe-ZRUVOG5H.js} +0 -0
- /package/dist/{wiki-acl-AR7RIMRY.js → wiki-acl-MFLSS6DE.js} +0 -0
- /package/dist/{wiki-client-MAFYBXCQ.js → wiki-client-GBPR45BQ.js} +0 -0
package/dist/bin/verify-stack.js
CHANGED
|
@@ -1,389 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
} from "../chunk-
|
|
3
|
+
runVerifyStack
|
|
4
|
+
} from "../chunk-IRHNV4GY.js";
|
|
5
|
+
import "../chunk-6Y4B3QF6.js";
|
|
5
6
|
import "../chunk-MLKGABMK.js";
|
|
6
|
-
|
|
7
|
-
// src/bin/verify-stack.ts
|
|
8
|
-
import { execSync } from "child_process";
|
|
9
|
-
import { readFileSync, existsSync } from "fs";
|
|
10
|
-
import http from "http";
|
|
11
|
-
import path from "path";
|
|
12
|
-
var DEFAULT_COMPOSE = "/opt/exe-stack/docker-compose.yml";
|
|
13
|
-
var DEFAULT_ENV = "/opt/exe-stack/.env";
|
|
14
|
-
var CHECK_TIMEOUT_MS = 5e3;
|
|
15
|
-
var TOTAL_TIMEOUT_MS = 6e4;
|
|
16
|
-
var SERVICE_URLS = {
|
|
17
|
-
"exe-os": "http://127.0.0.1:8765/health",
|
|
18
|
-
"exe-gateway": "http://127.0.0.1:3100/health",
|
|
19
|
-
"exe-wiki": "http://127.0.0.1:3001/api/ping",
|
|
20
|
-
"exe-crm": "http://127.0.0.1:3000/healthz",
|
|
21
|
-
"exe-monitor-hub": "http://127.0.0.1:8090/api/health"
|
|
22
|
-
};
|
|
23
|
-
var FRONTEND_URLS = {
|
|
24
|
-
"exe-crm": "http://127.0.0.1:3000",
|
|
25
|
-
"exe-wiki": "http://127.0.0.1:3001",
|
|
26
|
-
"exe-monitor-hub": "http://127.0.0.1:8090"
|
|
27
|
-
};
|
|
28
|
-
var GOTRUE_TOKEN_URL = "http://127.0.0.1:9999/token?grant_type=password";
|
|
29
|
-
function loadEnvFile(envPath) {
|
|
30
|
-
if (!existsSync(envPath)) return {};
|
|
31
|
-
const raw = readFileSync(envPath, "utf8");
|
|
32
|
-
const vars = {};
|
|
33
|
-
for (const line of raw.split("\n")) {
|
|
34
|
-
const trimmed = line.trim();
|
|
35
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
36
|
-
const eqIdx = trimmed.indexOf("=");
|
|
37
|
-
if (eqIdx < 1) continue;
|
|
38
|
-
const key = trimmed.slice(0, eqIdx).trim();
|
|
39
|
-
let val = trimmed.slice(eqIdx + 1).trim();
|
|
40
|
-
if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
|
|
41
|
-
val = val.slice(1, -1);
|
|
42
|
-
}
|
|
43
|
-
vars[key] = val;
|
|
44
|
-
}
|
|
45
|
-
return vars;
|
|
46
|
-
}
|
|
47
|
-
function httpGet(url, timeoutMs, headers) {
|
|
48
|
-
return new Promise((resolve, reject) => {
|
|
49
|
-
const urlObj = new URL(url);
|
|
50
|
-
const opts = {
|
|
51
|
-
hostname: urlObj.hostname,
|
|
52
|
-
port: urlObj.port || 80,
|
|
53
|
-
path: urlObj.pathname + urlObj.search,
|
|
54
|
-
method: "GET",
|
|
55
|
-
timeout: timeoutMs,
|
|
56
|
-
headers: headers ?? {}
|
|
57
|
-
};
|
|
58
|
-
const req = http.request(opts, (res) => {
|
|
59
|
-
let body = "";
|
|
60
|
-
res.on("data", (chunk) => {
|
|
61
|
-
body += chunk.toString();
|
|
62
|
-
});
|
|
63
|
-
res.on("end", () => resolve({ status: res.statusCode ?? 0, body, contentType: res.headers["content-type"] ?? "" }));
|
|
64
|
-
});
|
|
65
|
-
req.on("timeout", () => {
|
|
66
|
-
req.destroy();
|
|
67
|
-
reject(new Error(`Timeout after ${timeoutMs}ms`));
|
|
68
|
-
});
|
|
69
|
-
req.on("error", reject);
|
|
70
|
-
req.end();
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
function httpPost(url, body, contentType, timeoutMs) {
|
|
74
|
-
return new Promise((resolve, reject) => {
|
|
75
|
-
const urlObj = new URL(url);
|
|
76
|
-
const opts = {
|
|
77
|
-
hostname: urlObj.hostname,
|
|
78
|
-
port: urlObj.port || 80,
|
|
79
|
-
path: urlObj.pathname + urlObj.search,
|
|
80
|
-
method: "POST",
|
|
81
|
-
timeout: timeoutMs,
|
|
82
|
-
headers: {
|
|
83
|
-
"Content-Type": contentType,
|
|
84
|
-
"Content-Length": Buffer.byteLength(body)
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
const req = http.request(opts, (res) => {
|
|
88
|
-
let data = "";
|
|
89
|
-
res.on("data", (chunk) => {
|
|
90
|
-
data += chunk.toString();
|
|
91
|
-
});
|
|
92
|
-
res.on("end", () => resolve({ status: res.statusCode ?? 0, body: data }));
|
|
93
|
-
});
|
|
94
|
-
req.on("timeout", () => {
|
|
95
|
-
req.destroy();
|
|
96
|
-
reject(new Error(`Timeout after ${timeoutMs}ms`));
|
|
97
|
-
});
|
|
98
|
-
req.on("error", reject);
|
|
99
|
-
req.write(body);
|
|
100
|
-
req.end();
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
async function checkContainersHealthy(composeFile) {
|
|
104
|
-
const check = "All containers healthy";
|
|
105
|
-
try {
|
|
106
|
-
const dir = path.dirname(composeFile);
|
|
107
|
-
const file = path.basename(composeFile);
|
|
108
|
-
const raw = execSync(`docker compose -f "${file}" ps --format json`, {
|
|
109
|
-
cwd: dir,
|
|
110
|
-
timeout: CHECK_TIMEOUT_MS,
|
|
111
|
-
encoding: "utf8",
|
|
112
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
113
|
-
});
|
|
114
|
-
const lines = raw.trim().split("\n").filter(Boolean);
|
|
115
|
-
if (lines.length === 0) {
|
|
116
|
-
return { check, status: "fail", message: "No containers found" };
|
|
117
|
-
}
|
|
118
|
-
const unhealthy = [];
|
|
119
|
-
const notRunning = [];
|
|
120
|
-
for (const line of lines) {
|
|
121
|
-
try {
|
|
122
|
-
const c = JSON.parse(line);
|
|
123
|
-
const name = c.Name || c.name || "unknown";
|
|
124
|
-
const state = (c.State || c.state || "").toLowerCase();
|
|
125
|
-
const health = (c.Health || c.health || "").toLowerCase();
|
|
126
|
-
if (state !== "running") notRunning.push(name);
|
|
127
|
-
else if (health && health !== "healthy") unhealthy.push(name);
|
|
128
|
-
} catch {
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
if (notRunning.length > 0) {
|
|
132
|
-
return { check, status: "fail", message: `Not running: ${notRunning.join(", ")}` };
|
|
133
|
-
}
|
|
134
|
-
if (unhealthy.length > 0) {
|
|
135
|
-
return { check, status: "warn", message: `Unhealthy: ${unhealthy.join(", ")}` };
|
|
136
|
-
}
|
|
137
|
-
return { check, status: "pass", message: `${lines.length} containers running and healthy` };
|
|
138
|
-
} catch (err) {
|
|
139
|
-
return { check, status: "fail", message: err instanceof Error ? err.message : String(err) };
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
async function checkServiceUrls() {
|
|
143
|
-
const check = "All service URLs respond 200";
|
|
144
|
-
const failures = [];
|
|
145
|
-
for (const [service, url] of Object.entries(SERVICE_URLS)) {
|
|
146
|
-
try {
|
|
147
|
-
const res = await httpGet(url, CHECK_TIMEOUT_MS);
|
|
148
|
-
if (res.status !== 200) {
|
|
149
|
-
failures.push(`${service}: HTTP ${res.status}`);
|
|
150
|
-
}
|
|
151
|
-
} catch (err) {
|
|
152
|
-
failures.push(`${service}: ${err instanceof Error ? err.message : String(err)}`);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
if (failures.length > 0) {
|
|
156
|
-
return { check, status: "fail", message: failures.join("; ") };
|
|
157
|
-
}
|
|
158
|
-
return { check, status: "pass", message: `${Object.keys(SERVICE_URLS).length} services responding` };
|
|
159
|
-
}
|
|
160
|
-
async function checkGoTrueLogin(env) {
|
|
161
|
-
const check = "GoTrue login works";
|
|
162
|
-
const email = env.GOTRUE_TEST_EMAIL || process.env.GOTRUE_TEST_EMAIL;
|
|
163
|
-
const password = env.GOTRUE_TEST_PASSWORD || process.env.GOTRUE_TEST_PASSWORD;
|
|
164
|
-
if (!email || !password) {
|
|
165
|
-
return { result: { check, status: "skip", message: "GOTRUE_TEST_EMAIL / GOTRUE_TEST_PASSWORD not set" } };
|
|
166
|
-
}
|
|
167
|
-
try {
|
|
168
|
-
const body = JSON.stringify({ email, password });
|
|
169
|
-
const res = await httpPost(GOTRUE_TOKEN_URL, body, "application/json", CHECK_TIMEOUT_MS);
|
|
170
|
-
if (res.status !== 200) {
|
|
171
|
-
return { result: { check, status: "fail", message: `HTTP ${res.status}: ${res.body.slice(0, 200)}` } };
|
|
172
|
-
}
|
|
173
|
-
const parsed = JSON.parse(res.body);
|
|
174
|
-
const jwt = parsed.access_token;
|
|
175
|
-
if (!jwt) {
|
|
176
|
-
return { result: { check, status: "fail", message: "No access_token in response" } };
|
|
177
|
-
}
|
|
178
|
-
return { result: { check, status: "pass", message: "Login succeeded" }, jwt };
|
|
179
|
-
} catch (err) {
|
|
180
|
-
return { result: { check, status: "fail", message: err instanceof Error ? err.message : String(err) } };
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
async function checkWhatsAppConnected() {
|
|
184
|
-
const check = "WhatsApp still connected";
|
|
185
|
-
try {
|
|
186
|
-
const res = await httpGet(SERVICE_URLS["exe-gateway"], CHECK_TIMEOUT_MS);
|
|
187
|
-
if (res.status !== 200) {
|
|
188
|
-
return { check, status: "warn", message: `Gateway health returned HTTP ${res.status}` };
|
|
189
|
-
}
|
|
190
|
-
try {
|
|
191
|
-
const data = JSON.parse(res.body);
|
|
192
|
-
const adapters = data.adapters || data.channels;
|
|
193
|
-
if (!adapters || !Array.isArray(adapters)) {
|
|
194
|
-
return { check, status: "skip", message: "No adapters array in gateway health response" };
|
|
195
|
-
}
|
|
196
|
-
const connected = adapters.filter(
|
|
197
|
-
(a) => a.status === "connected" || a.connected === true
|
|
198
|
-
);
|
|
199
|
-
if (connected.length === 0) {
|
|
200
|
-
return { check, status: "warn", message: `0/${adapters.length} adapters connected` };
|
|
201
|
-
}
|
|
202
|
-
return { check, status: "pass", message: `${connected.length}/${adapters.length} adapter(s) connected` };
|
|
203
|
-
} catch {
|
|
204
|
-
return { check, status: "skip", message: "Could not parse gateway health response" };
|
|
205
|
-
}
|
|
206
|
-
} catch (err) {
|
|
207
|
-
return { check, status: "fail", message: err instanceof Error ? err.message : String(err) };
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
async function checkFrontendsLoad() {
|
|
211
|
-
const check = "Each frontend loads";
|
|
212
|
-
const failures = [];
|
|
213
|
-
for (const [service, url] of Object.entries(FRONTEND_URLS)) {
|
|
214
|
-
try {
|
|
215
|
-
const res = await httpGet(url, CHECK_TIMEOUT_MS);
|
|
216
|
-
if (!res.contentType.includes("text/html")) {
|
|
217
|
-
failures.push(`${service}: Content-Type=${res.contentType} (expected text/html)`);
|
|
218
|
-
} else if (res.body.length < 1e3) {
|
|
219
|
-
failures.push(`${service}: body ${res.body.length} bytes (expected >1000)`);
|
|
220
|
-
}
|
|
221
|
-
} catch (err) {
|
|
222
|
-
failures.push(`${service}: ${err instanceof Error ? err.message : String(err)}`);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
if (failures.length > 0) {
|
|
226
|
-
return { check, status: "fail", message: failures.join("; ") };
|
|
227
|
-
}
|
|
228
|
-
return { check, status: "pass", message: `${Object.keys(FRONTEND_URLS).length} frontends serving HTML` };
|
|
229
|
-
}
|
|
230
|
-
async function checkMonitorMetrics() {
|
|
231
|
-
const check = "Monitor reports metrics";
|
|
232
|
-
try {
|
|
233
|
-
const res = await httpGet(SERVICE_URLS["exe-monitor-hub"], CHECK_TIMEOUT_MS);
|
|
234
|
-
if (res.status !== 200) {
|
|
235
|
-
return { check, status: "fail", message: `HTTP ${res.status}` };
|
|
236
|
-
}
|
|
237
|
-
return { check, status: "pass", message: "Monitor hub health OK" };
|
|
238
|
-
} catch (err) {
|
|
239
|
-
return { check, status: "fail", message: err instanceof Error ? err.message : String(err) };
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
async function checkRawPipeline(env) {
|
|
243
|
-
const check = "Raw pipeline alive";
|
|
244
|
-
const dbUrl = env.DATABASE_URL || env.EXED_DATABASE_URL || process.env.DATABASE_URL;
|
|
245
|
-
if (!dbUrl) {
|
|
246
|
-
return { check, status: "skip", message: "DATABASE_URL not set" };
|
|
247
|
-
}
|
|
248
|
-
try {
|
|
249
|
-
const result = execSync(
|
|
250
|
-
`psql "${dbUrl}" -t -c "SELECT COUNT(*) FROM raw.raw_events WHERE created_at > NOW() - INTERVAL '24 hours'" 2>&1`,
|
|
251
|
-
{ timeout: CHECK_TIMEOUT_MS, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }
|
|
252
|
-
);
|
|
253
|
-
const count = parseInt(result.trim(), 10);
|
|
254
|
-
if (isNaN(count)) {
|
|
255
|
-
return { check, status: "warn", message: `Unexpected psql output: ${result.trim().slice(0, 100)}` };
|
|
256
|
-
}
|
|
257
|
-
if (count === 0) {
|
|
258
|
-
return { check, status: "warn", message: "0 events in last 24h \u2014 pipeline may be idle" };
|
|
259
|
-
}
|
|
260
|
-
return { check, status: "pass", message: `${count} event(s) in last 24h` };
|
|
261
|
-
} catch (err) {
|
|
262
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
263
|
-
if (msg.includes("does not exist") || msg.includes("relation")) {
|
|
264
|
-
return { check, status: "skip", message: "raw.raw_events table does not exist" };
|
|
265
|
-
}
|
|
266
|
-
return { check, status: "fail", message: msg.slice(0, 200) };
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
async function checkCrossServiceAuth(jwt) {
|
|
270
|
-
const check = "Cross-service auth";
|
|
271
|
-
if (!jwt) {
|
|
272
|
-
return { check, status: "skip", message: "No GoTrue JWT available (check 3 skipped or failed)" };
|
|
273
|
-
}
|
|
274
|
-
const targets = {
|
|
275
|
-
"exe-wiki": "http://127.0.0.1:3001/api/ping",
|
|
276
|
-
"exe-crm": "http://127.0.0.1:3000/healthz"
|
|
277
|
-
};
|
|
278
|
-
const failures = [];
|
|
279
|
-
for (const [service, url] of Object.entries(targets)) {
|
|
280
|
-
try {
|
|
281
|
-
const res = await httpGet(url, CHECK_TIMEOUT_MS, { Authorization: `Bearer ${jwt}` });
|
|
282
|
-
if (res.status !== 200) {
|
|
283
|
-
failures.push(`${service}: HTTP ${res.status}`);
|
|
284
|
-
}
|
|
285
|
-
} catch (err) {
|
|
286
|
-
failures.push(`${service}: ${err instanceof Error ? err.message : String(err)}`);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
if (failures.length > 0) {
|
|
290
|
-
return { check, status: "fail", message: failures.join("; ") };
|
|
291
|
-
}
|
|
292
|
-
return { check, status: "pass", message: "JWT accepted by wiki + CRM" };
|
|
293
|
-
}
|
|
294
|
-
async function runVerifyStack(options) {
|
|
295
|
-
const composeFile = options?.composeFile ?? DEFAULT_COMPOSE;
|
|
296
|
-
const envFile = options?.envFile ?? DEFAULT_ENV;
|
|
297
|
-
const totalTimeout = options?.timeoutMs ?? TOTAL_TIMEOUT_MS;
|
|
298
|
-
const env = loadEnvFile(envFile);
|
|
299
|
-
const results = [];
|
|
300
|
-
const deadline = Date.now() + totalTimeout;
|
|
301
|
-
const addResult = (r) => {
|
|
302
|
-
results.push(r);
|
|
303
|
-
if (Date.now() > deadline) {
|
|
304
|
-
results.push({ check: "Total timeout", status: "fail", message: `Exceeded ${totalTimeout}ms` });
|
|
305
|
-
}
|
|
306
|
-
};
|
|
307
|
-
addResult(await checkContainersHealthy(composeFile));
|
|
308
|
-
if (Date.now() > deadline) return summarize(results);
|
|
309
|
-
addResult(await checkServiceUrls());
|
|
310
|
-
if (Date.now() > deadline) return summarize(results);
|
|
311
|
-
const goTrueResult = await checkGoTrueLogin(env);
|
|
312
|
-
addResult(goTrueResult.result);
|
|
313
|
-
if (Date.now() > deadline) return summarize(results);
|
|
314
|
-
addResult(await checkWhatsAppConnected());
|
|
315
|
-
if (Date.now() > deadline) return summarize(results);
|
|
316
|
-
addResult(await checkFrontendsLoad());
|
|
317
|
-
if (Date.now() > deadline) return summarize(results);
|
|
318
|
-
addResult(await checkMonitorMetrics());
|
|
319
|
-
if (Date.now() > deadline) return summarize(results);
|
|
320
|
-
addResult(await checkRawPipeline(env));
|
|
321
|
-
if (Date.now() > deadline) return summarize(results);
|
|
322
|
-
addResult(await checkCrossServiceAuth(goTrueResult.jwt));
|
|
323
|
-
return summarize(results);
|
|
324
|
-
}
|
|
325
|
-
function summarize(results) {
|
|
326
|
-
return {
|
|
327
|
-
results,
|
|
328
|
-
passed: results.filter((r) => r.status === "pass").length,
|
|
329
|
-
failed: results.filter((r) => r.status === "fail").length,
|
|
330
|
-
warned: results.filter((r) => r.status === "warn").length,
|
|
331
|
-
skipped: results.filter((r) => r.status === "skip").length
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
function printReport(report) {
|
|
335
|
-
const icons = { pass: "\u2705", fail: "\u274C", warn: "\u26A0\uFE0F ", skip: "\u23ED\uFE0F " };
|
|
336
|
-
console.log("\n\x1B[1mPost-Deploy Verification\x1B[0m\n");
|
|
337
|
-
for (const r of report.results) {
|
|
338
|
-
console.log(` ${icons[r.status] ?? "?"} ${r.check}: ${r.message}`);
|
|
339
|
-
}
|
|
340
|
-
console.log(
|
|
341
|
-
`
|
|
342
|
-
Pass: ${report.passed} Fail: ${report.failed} Warn: ${report.warned} Skip: ${report.skipped}
|
|
343
|
-
`
|
|
344
|
-
);
|
|
345
|
-
}
|
|
346
|
-
function printUsage() {
|
|
347
|
-
console.log(`
|
|
348
|
-
Usage: exe-os verify-stack [options]
|
|
349
|
-
|
|
350
|
-
Post-deploy verification \u2014 8 runtime checks after stack-update.
|
|
351
|
-
|
|
352
|
-
Options:
|
|
353
|
-
--compose <path> Path to docker-compose.yml (default: ${DEFAULT_COMPOSE})
|
|
354
|
-
--env <path> Path to .env file (default: ${DEFAULT_ENV})
|
|
355
|
-
--help Show this help message
|
|
356
|
-
|
|
357
|
-
Checks:
|
|
358
|
-
1. All containers healthy (docker compose ps)
|
|
359
|
-
2. All service URLs respond 200
|
|
360
|
-
3. GoTrue login works (requires GOTRUE_TEST_EMAIL + GOTRUE_TEST_PASSWORD)
|
|
361
|
-
4. WhatsApp still connected (adapter status)
|
|
362
|
-
5. Each frontend loads (HTML > 1000 bytes)
|
|
363
|
-
6. Monitor reports metrics
|
|
364
|
-
7. Raw pipeline alive (recent raw_events)
|
|
365
|
-
8. Cross-service auth (JWT \u2192 wiki + CRM)
|
|
366
|
-
`);
|
|
367
|
-
}
|
|
368
|
-
if (isMainModule(import.meta.url) && process.argv[1]?.includes("verify-stack")) {
|
|
369
|
-
const args = process.argv.slice(2);
|
|
370
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
371
|
-
printUsage();
|
|
372
|
-
process.exit(0);
|
|
373
|
-
}
|
|
374
|
-
const composeIdx = args.indexOf("--compose");
|
|
375
|
-
const envIdx = args.indexOf("--env");
|
|
376
|
-
const options = {};
|
|
377
|
-
if (composeIdx >= 0 && args[composeIdx + 1]) options.composeFile = args[composeIdx + 1];
|
|
378
|
-
if (envIdx >= 0 && args[envIdx + 1]) options.envFile = args[envIdx + 1];
|
|
379
|
-
runVerifyStack(options).then((report) => {
|
|
380
|
-
printReport(report);
|
|
381
|
-
process.exit(report.failed > 0 ? 1 : 0);
|
|
382
|
-
}).catch((err) => {
|
|
383
|
-
console.error(`[verify-stack] Fatal error: ${err instanceof Error ? err.message : String(err)}`);
|
|
384
|
-
process.exit(1);
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
7
|
export {
|
|
388
8
|
runVerifyStack
|
|
389
9
|
};
|
package/dist/bin/vps-backup.js
CHANGED
|
@@ -1,165 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
cleanOldBackups,
|
|
4
|
+
listBackups,
|
|
5
|
+
main,
|
|
6
|
+
preDeployBackup,
|
|
7
|
+
runPgBackup,
|
|
8
|
+
setupCron
|
|
9
|
+
} from "../chunk-5DMAMQNU.js";
|
|
2
10
|
import "../chunk-MLKGABMK.js";
|
|
3
|
-
|
|
4
|
-
// src/bin/vps-backup.ts
|
|
5
|
-
import { spawnSync } from "child_process";
|
|
6
|
-
import { existsSync, mkdirSync, readdirSync, statSync, unlinkSync } from "fs";
|
|
7
|
-
import path from "path";
|
|
8
|
-
var BACKUP_DIR = "/opt/exe-stack/backups";
|
|
9
|
-
var DEFAULT_DATABASE_URL = "postgres://exe@localhost:5432/exedb";
|
|
10
|
-
var MAX_SNAPSHOTS = 28;
|
|
11
|
-
var KEEP_DAYS = 7;
|
|
12
|
-
function runPgBackup(tag) {
|
|
13
|
-
mkdirSync(BACKUP_DIR, { recursive: true });
|
|
14
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
15
|
-
const filename = tag ? `pg-${tag}-${timestamp}.dump` : `pg-${timestamp}.dump`;
|
|
16
|
-
const filepath = path.join(BACKUP_DIR, filename);
|
|
17
|
-
const databaseUrl = process.env.DATABASE_URL || DEFAULT_DATABASE_URL;
|
|
18
|
-
const result = spawnSync("pg_dump", ["-Fc", "-d", databaseUrl, "-f", filepath], {
|
|
19
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
20
|
-
timeout: 3e5,
|
|
21
|
-
// 5 minutes max
|
|
22
|
-
env: { ...process.env }
|
|
23
|
-
});
|
|
24
|
-
if (result.status !== 0) {
|
|
25
|
-
const stderr = result.stderr?.toString() || "";
|
|
26
|
-
throw new Error(`pg_dump failed (exit ${result.status}): ${stderr}`);
|
|
27
|
-
}
|
|
28
|
-
const size = existsSync(filepath) ? statSync(filepath).size : 0;
|
|
29
|
-
console.log(`[vps-backup] \u2713 Backup created: ${filepath} (${formatBytes(size)})`);
|
|
30
|
-
return filepath;
|
|
31
|
-
}
|
|
32
|
-
function cleanOldBackups(keepDays = KEEP_DAYS) {
|
|
33
|
-
if (!existsSync(BACKUP_DIR)) return 0;
|
|
34
|
-
const files = readdirSync(BACKUP_DIR).filter((f) => f.startsWith("pg-") && f.endsWith(".dump")).map((f) => ({
|
|
35
|
-
name: f,
|
|
36
|
-
path: path.join(BACKUP_DIR, f),
|
|
37
|
-
mtime: statSync(path.join(BACKUP_DIR, f)).mtimeMs
|
|
38
|
-
})).sort((a, b) => b.mtime - a.mtime);
|
|
39
|
-
const cutoff = Date.now() - keepDays * 24 * 60 * 60 * 1e3;
|
|
40
|
-
let removed = 0;
|
|
41
|
-
for (let i = 0; i < files.length; i++) {
|
|
42
|
-
const file = files[i];
|
|
43
|
-
if (file.mtime >= cutoff && i < MAX_SNAPSHOTS) continue;
|
|
44
|
-
if (file.name.includes("pre-deploy-") && file.mtime >= cutoff) continue;
|
|
45
|
-
try {
|
|
46
|
-
unlinkSync(file.path);
|
|
47
|
-
removed++;
|
|
48
|
-
console.log(`[vps-backup] Removed old backup: ${file.name}`);
|
|
49
|
-
} catch (err) {
|
|
50
|
-
console.warn(`[vps-backup] Failed to remove ${file.name}: ${err instanceof Error ? err.message : err}`);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
if (removed > 0) {
|
|
54
|
-
console.log(`[vps-backup] \u2713 Cleaned ${removed} old backup(s)`);
|
|
55
|
-
} else {
|
|
56
|
-
console.log("[vps-backup] \u2713 No old backups to clean");
|
|
57
|
-
}
|
|
58
|
-
return removed;
|
|
59
|
-
}
|
|
60
|
-
function preDeployBackup(version) {
|
|
61
|
-
const sanitized = version.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
62
|
-
console.log(`[vps-backup] Creating pre-deploy backup for version ${version}...`);
|
|
63
|
-
return runPgBackup(`pre-deploy-${sanitized}`);
|
|
64
|
-
}
|
|
65
|
-
function setupCron() {
|
|
66
|
-
const which = spawnSync("which", ["exe-os"], { encoding: "utf8", timeout: 5e3 });
|
|
67
|
-
const exeOsBin = which.stdout?.trim() || "/usr/local/bin/exe-os";
|
|
68
|
-
const cronLine = `0 */6 * * * ${exeOsBin} vps-backup --clean 2>&1 | tail -5 >> /var/log/exe-backup.log`;
|
|
69
|
-
const cronComment = "# exe-os automated postgres backup (every 6 hours)";
|
|
70
|
-
const current = spawnSync("crontab", ["-l"], {
|
|
71
|
-
encoding: "utf8",
|
|
72
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
73
|
-
});
|
|
74
|
-
const existingCron = current.status === 0 ? current.stdout : "";
|
|
75
|
-
if (existingCron.includes("exe-os vps-backup") || existingCron.includes("exe-os vps-backup")) {
|
|
76
|
-
console.log("[vps-backup] \u2713 Cron job already installed");
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
const newCron = existingCron.trimEnd() + "\n\n" + cronComment + "\n" + cronLine + "\n";
|
|
80
|
-
const install = spawnSync("crontab", ["-"], {
|
|
81
|
-
input: newCron,
|
|
82
|
-
encoding: "utf8",
|
|
83
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
84
|
-
});
|
|
85
|
-
if (install.status !== 0) {
|
|
86
|
-
throw new Error(`Failed to install cron: ${install.stderr}`);
|
|
87
|
-
}
|
|
88
|
-
console.log("[vps-backup] \u2713 Cron job installed (every 6 hours)");
|
|
89
|
-
console.log(`[vps-backup] ${cronLine}`);
|
|
90
|
-
}
|
|
91
|
-
function listBackups() {
|
|
92
|
-
if (!existsSync(BACKUP_DIR)) {
|
|
93
|
-
console.log("[vps-backup] No backups directory found");
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
const files = readdirSync(BACKUP_DIR).filter((f) => f.startsWith("pg-") && f.endsWith(".dump")).map((f) => {
|
|
97
|
-
const stat = statSync(path.join(BACKUP_DIR, f));
|
|
98
|
-
return { name: f, size: stat.size, mtime: stat.mtimeMs };
|
|
99
|
-
}).sort((a, b) => b.mtime - a.mtime);
|
|
100
|
-
if (files.length === 0) {
|
|
101
|
-
console.log("[vps-backup] No backups found");
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
console.log(`
|
|
105
|
-
Backups in ${BACKUP_DIR} (${files.length} total):
|
|
106
|
-
`);
|
|
107
|
-
for (const f of files) {
|
|
108
|
-
const age = formatAge(Date.now() - f.mtime);
|
|
109
|
-
console.log(` ${f.name} ${formatBytes(f.size).padStart(10)} ${age} ago`);
|
|
110
|
-
}
|
|
111
|
-
console.log("");
|
|
112
|
-
}
|
|
113
|
-
function formatBytes(bytes) {
|
|
114
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
115
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
116
|
-
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
117
|
-
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
|
|
118
|
-
}
|
|
119
|
-
function formatAge(ms) {
|
|
120
|
-
const hours = Math.floor(ms / (1e3 * 60 * 60));
|
|
121
|
-
if (hours < 1) return `${Math.floor(ms / (1e3 * 60))}m`;
|
|
122
|
-
if (hours < 48) return `${hours}h`;
|
|
123
|
-
return `${Math.floor(hours / 24)}d`;
|
|
124
|
-
}
|
|
125
|
-
async function main(args) {
|
|
126
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
127
|
-
console.log(`
|
|
128
|
-
exe-os vps-backup \u2014 Postgres backup manager
|
|
129
|
-
|
|
130
|
-
Usage:
|
|
131
|
-
exe-os vps-backup Run backup now
|
|
132
|
-
exe-os vps-backup --setup Install cron job (every 6 hours)
|
|
133
|
-
exe-os vps-backup --clean Run backup + clean old backups
|
|
134
|
-
exe-os vps-backup --list List current backups
|
|
135
|
-
exe-os vps-backup --pre-deploy <version> Pre-deploy snapshot
|
|
136
|
-
`);
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
if (args.includes("--setup")) {
|
|
140
|
-
setupCron();
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
if (args.includes("--list")) {
|
|
144
|
-
listBackups();
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
const preDeployIdx = args.indexOf("--pre-deploy");
|
|
148
|
-
if (preDeployIdx !== -1) {
|
|
149
|
-
const version = args[preDeployIdx + 1];
|
|
150
|
-
if (!version) {
|
|
151
|
-
console.error("[vps-backup] --pre-deploy requires a version argument");
|
|
152
|
-
process.exitCode = 1;
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
preDeployBackup(version);
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
runPgBackup();
|
|
159
|
-
if (args.includes("--clean")) {
|
|
160
|
-
cleanOldBackups();
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
11
|
export {
|
|
164
12
|
cleanOldBackups,
|
|
165
13
|
listBackups,
|