@askexenow/exe-os 0.9.166 → 0.9.167

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.
Files changed (244) hide show
  1. package/deploy/compose/backup.sh +45 -7
  2. package/deploy/compose/setup.sh +7 -0
  3. package/deploy/stack-manifests/v0.9.json +40 -1
  4. package/dist/{active-agent-R2KMWMR6.js → active-agent-DGTIJN2U.js} +2 -2
  5. package/dist/{active-agent-CYMM3QQA.js → active-agent-HVMLG6FH.js} +2 -2
  6. package/dist/{agentic-ontology-GKAKYNPE.js → agentic-ontology-S54AFODT.js} +1 -1
  7. package/dist/{backfill-metadata-Z5SYUWAV.js → backfill-metadata-74IWETRF.js} +4 -3
  8. package/dist/{behaviors-QGU6XI5R.js → behaviors-LZVAVHTC.js} +2 -2
  9. package/dist/bin/agentic-ontology-backfill.js +5 -4
  10. package/dist/bin/agentic-reflection-backfill.js +6 -5
  11. package/dist/bin/agentic-semantic-label.js +5 -4
  12. package/dist/bin/backfill-conversations.js +5 -4
  13. package/dist/bin/backfill-responses.js +5 -4
  14. package/dist/bin/backfill-vectors.js +6 -5
  15. package/dist/bin/bulk-sync-postgres.js +6 -5
  16. package/dist/bin/cleanup-stale-review-tasks.js +9 -9
  17. package/dist/bin/cli.js +16 -13
  18. package/dist/bin/daily-summary.js +0 -217
  19. package/dist/bin/deferred-daemon-restart.js +8 -0
  20. package/dist/bin/exe-agent-config.js +1 -1
  21. package/dist/bin/exe-agent.js +10 -10
  22. package/dist/bin/exe-assign.js +7 -6
  23. package/dist/bin/exe-boot.js +20 -19
  24. package/dist/bin/exe-call.js +4 -4
  25. package/dist/bin/exe-cloud.js +3 -3
  26. package/dist/bin/exe-dispatch.js +9 -9
  27. package/dist/bin/exe-doctor.js +1 -1
  28. package/dist/bin/exe-export-behaviors.js +7 -6
  29. package/dist/bin/exe-forget.js +6 -5
  30. package/dist/bin/exe-gateway.js +5 -5
  31. package/dist/bin/exe-heartbeat.js +9 -9
  32. package/dist/bin/exe-kill.js +13 -12
  33. package/dist/bin/exe-launch-agent.js +11 -10
  34. package/dist/bin/exe-new-employee.js +6 -6
  35. package/dist/bin/exe-pending-messages.js +10 -10
  36. package/dist/bin/exe-pending-notifications.js +9 -9
  37. package/dist/bin/exe-pending-reviews.js +9 -9
  38. package/dist/bin/exe-rename.js +4 -4
  39. package/dist/bin/exe-review.js +12 -11
  40. package/dist/bin/exe-search.js +5 -4
  41. package/dist/bin/exe-session-cleanup.js +19 -14
  42. package/dist/bin/exe-settings.js +3 -3
  43. package/dist/bin/exe-start-codex.js +11 -10
  44. package/dist/bin/exe-start-opencode.js +8 -7
  45. package/dist/bin/exe-status.js +10 -10
  46. package/dist/bin/exe-team.js +2 -2
  47. package/dist/bin/git-sweep.js +9 -9
  48. package/dist/bin/graph-backfill.js +4 -3
  49. package/dist/bin/graph-export.js +5 -4
  50. package/dist/bin/import-history.js +171 -0
  51. package/dist/bin/install-launchd.js +41 -0
  52. package/dist/bin/install.js +50 -74
  53. package/dist/bin/intercom-check.js +4 -4
  54. package/dist/bin/postgres-agentic-reflection-backfill.js +2 -2
  55. package/dist/bin/postgres-agentic-semantic-backfill.js +4 -4
  56. package/dist/bin/pre-publish.js +1 -1
  57. package/dist/bin/scan-tasks.js +22 -12
  58. package/dist/bin/setup.js +1 -1
  59. package/dist/bin/shard-migrate.js +4 -3
  60. package/dist/bin/stack-update.js +61 -857
  61. package/dist/bin/vps-backup.js +170 -0
  62. package/dist/bin/vps-health-gate.js +232 -0
  63. package/dist/{capacity-monitor-ZEAE4WP2.js → capacity-monitor-JBZB2S4P.js} +10 -10
  64. package/dist/{catchup-brief-OGWCHENC.js → catchup-brief-HE2EMZS5.js} +12 -11
  65. package/dist/{chunk-DJJNB47C.js → chunk-27DO3EZO.js} +1 -1
  66. package/dist/{chunk-45FYZIHI.js → chunk-32YUET3Y.js} +2 -2
  67. package/dist/{chunk-Y75ECPO5.js → chunk-3FW5LUGI.js} +2 -2
  68. package/dist/{chunk-4OZGQZ4U.js → chunk-3M3O56VT.js} +636 -179
  69. package/dist/{chunk-77WQOD6J.js → chunk-4CXUZ4NI.js} +2 -2
  70. package/dist/{chunk-PBXWPHEK.js → chunk-4VEHJZ6R.js} +1 -1
  71. package/dist/{chunk-TH22QIEC.js → chunk-6A4COFDG.js} +1 -1
  72. package/dist/{chunk-ACBTCC2L.js → chunk-7OJH2A6I.js} +1 -1
  73. package/dist/{chunk-NHCOTCI6.js → chunk-A7SGEBXJ.js} +2 -2
  74. package/dist/{chunk-5MPQSNZF.js → chunk-AUTCT6AY.js} +1 -1
  75. package/dist/{chunk-OEKSTOTE.js → chunk-AZAZ2C75.js} +1 -1
  76. package/dist/chunk-CHCA3ZM2.js +167 -0
  77. package/dist/{chunk-X347L57O.js → chunk-CSTJQDOE.js} +4 -3
  78. package/dist/{chunk-B234R3VW.js → chunk-D7WLV6WD.js} +2 -2
  79. package/dist/{chunk-GMXF3AHJ.js → chunk-DGAONW36.js} +1 -1
  80. package/dist/chunk-EAT5YL3W.js +229 -0
  81. package/dist/{chunk-OD4H5YCJ.js → chunk-EKTQE2R5.js} +8 -8
  82. package/dist/{chunk-Z44PC42G.js → chunk-ELUBA7XL.js} +2 -2
  83. package/dist/{chunk-ZWS6XQER.js → chunk-F5AKOE4P.js} +7 -7
  84. package/dist/{chunk-T5YULDDO.js → chunk-FVI4UBKO.js} +27 -4
  85. package/dist/{chunk-ESRI7MFI.js → chunk-GAN7PW6G.js} +28 -24
  86. package/dist/{chunk-K4OWYJSP.js → chunk-GM2WZTG3.js} +2 -2
  87. package/dist/{chunk-TAB5QGIK.js → chunk-GZYQTPTF.js} +3 -3
  88. package/dist/{chunk-CXDU5DE3.js → chunk-IAUNGATJ.js} +1 -1
  89. package/dist/{chunk-YS63NS6M.js → chunk-IHSM5GR4.js} +1 -1
  90. package/dist/{chunk-23PTS2ZD.js → chunk-IP7KJAUW.js} +117 -15
  91. package/dist/{chunk-D6IMJAV2.js → chunk-J64P2LB2.js} +2 -2
  92. package/dist/{chunk-CXAVSQZM.js → chunk-JXMSCKRM.js} +1 -1
  93. package/dist/{chunk-RQMK3IQH.js → chunk-K4OTJP6N.js} +14 -7
  94. package/dist/{chunk-L7ROZR2H.js → chunk-KXAUMIOX.js} +1 -1
  95. package/dist/{chunk-TPC3LAP7.js → chunk-LGY2BIOT.js} +13 -0
  96. package/dist/{chunk-RPIDSBK7.js → chunk-LLHRJEE4.js} +3 -3
  97. package/dist/{chunk-6WG2VIKC.js → chunk-LM7H6XU4.js} +1 -1
  98. package/dist/{chunk-Y6GMKZZ2.js → chunk-LOFFGJSY.js} +150 -23
  99. package/dist/{chunk-W7SDGBEC.js → chunk-MFI5OXYW.js} +52 -84
  100. package/dist/{chunk-KNPEVPYG.js → chunk-MSSQWF6X.js} +2 -2
  101. package/dist/{chunk-QIQAO3VG.js → chunk-NEFFFKMD.js} +3 -3
  102. package/dist/{chunk-YUC552KZ.js → chunk-NEHONJJC.js} +3 -3
  103. package/dist/{chunk-KZ7SXZ2V.js → chunk-NFMQRLCD.js} +1 -1
  104. package/dist/{chunk-52HCNDPG.js → chunk-O4TATDOV.js} +1 -1
  105. package/dist/{chunk-AR3OYGLB.js → chunk-PEFBRL4S.js} +28 -6
  106. package/dist/{chunk-AEUXUEJG.js → chunk-PEXVU3HU.js} +5 -3
  107. package/dist/chunk-Q2G5C3HV.js +217 -0
  108. package/dist/{chunk-KOO56JVC.js → chunk-Q6N6LDEJ.js} +1 -1
  109. package/dist/{chunk-TXSJ2L5O.js → chunk-QI4IXJN7.js} +1 -1
  110. package/dist/{chunk-HLVQ5Y7B.js → chunk-RE4VLK45.js} +1 -1
  111. package/dist/{chunk-TF6SZGDT.js → chunk-SA2PH6WY.js} +1 -1
  112. package/dist/{chunk-5RSYY7BE.js → chunk-SJYOPYXH.js} +117 -9
  113. package/dist/{chunk-PJGHBANY.js → chunk-TTJE7CCU.js} +1 -1
  114. package/dist/{chunk-A7KEWR6S.js → chunk-TXWQPL2U.js} +1 -1
  115. package/dist/{chunk-XXSJ35J5.js → chunk-U5ZH52FB.js} +2 -2
  116. package/dist/{chunk-G4FDG3LK.js → chunk-UVNDLF74.js} +63 -40
  117. package/dist/{chunk-5OD3AFRW.js → chunk-V6RCZ25F.js} +1 -1
  118. package/dist/{chunk-LHMBIFKD.js → chunk-VYNNN2S3.js} +4 -4
  119. package/dist/chunk-WCYT54XP.js +934 -0
  120. package/dist/{chunk-5AMSQRHT.js → chunk-XGYSTVUH.js} +1 -1
  121. package/dist/{chunk-MKZBHM6A.js → chunk-XLWF3C4R.js} +4 -4
  122. package/dist/{chunk-YL36L2SN.js → chunk-Y7YHLV57.js} +1 -1
  123. package/dist/{chunk-HZC4MR4H.js → chunk-YBKB2PXY.js} +1 -1
  124. package/dist/{chunk-NWM3A4TK.js → chunk-ZDNLKXZA.js} +1 -1
  125. package/dist/{chunk-O7KW6QMH.js → chunk-ZW4TKQUM.js} +15 -5
  126. package/dist/{chunk-6BURHBE6.js → chunk-ZXB44R3E.js} +32 -11
  127. package/dist/co-occurrence-WCED475N.js +73 -0
  128. package/dist/{code-context-index-B6VIWPSF.js → code-context-index-LSZ3DKTJ.js} +2 -2
  129. package/dist/{crdt-sync-XA22KI3S.js → crdt-sync-PBXZTHZC.js} +1 -1
  130. package/dist/{crm-webhook-CIZNOEY4.js → crm-webhook-W7Q25VZU.js} +2 -2
  131. package/dist/{cto-delegation-gate-H5IULFRC.js → cto-delegation-gate-JKULOLMC.js} +8 -8
  132. package/dist/{daemon-orchestration-VO5XQIJL.js → daemon-orchestration-CHV6MB42.js} +13 -11
  133. package/dist/{exe-drift-DMT75WR3.js → exe-drift-PW36OULT.js} +2 -2
  134. package/dist/{exe-export-2RZWOSX6.js → exe-export-XQOD3KE6.js} +6 -5
  135. package/dist/{exe-import-NFNYATHL.js → exe-import-QOFP67LW.js} +6 -5
  136. package/dist/{exe-key-4D7CF3BU.js → exe-key-WQ34UZR6.js} +1 -1
  137. package/dist/{fast-db-init-LAEISZQ2.js → fast-db-init-UKETGWQI.js} +1 -1
  138. package/dist/gateway/index.js +6 -6
  139. package/dist/{git-staleness-M46AYLPP.js → git-staleness-ATV5CGAP.js} +1 -1
  140. package/dist/{git-task-sweep-PXOS56YT.js → git-task-sweep-KXZRIP4T.js} +9 -9
  141. package/dist/{global-procedures-KROQQX54.js → global-procedures-G6IKCYKM.js} +3 -3
  142. package/dist/{graph-auto-extract-QJ2BBJM2.js → graph-auto-extract-ZJXJOLE2.js} +1 -1
  143. package/dist/hooks/bug-report-worker.js +10 -10
  144. package/dist/hooks/codex-stop-task-finalizer.js +10 -10
  145. package/dist/hooks/commit-complete.js +11 -11
  146. package/dist/hooks/error-recall.js +8 -7
  147. package/dist/hooks/exe-heartbeat-hook.js +2 -2
  148. package/dist/hooks/ingest-worker.js +3 -3
  149. package/dist/hooks/ingest.js +9 -9
  150. package/dist/hooks/instructions-loaded.js +3 -3
  151. package/dist/hooks/notification.js +3 -3
  152. package/dist/hooks/post-compact.js +10 -10
  153. package/dist/hooks/post-tool-combined.js +5 -5
  154. package/dist/hooks/pre-compact.js +16 -16
  155. package/dist/hooks/pre-tool-use.js +14 -14
  156. package/dist/hooks/prompt-submit.js +30 -29
  157. package/dist/hooks/session-end.js +46 -25
  158. package/dist/hooks/session-start.js +48 -10
  159. package/dist/hooks/stop.js +17 -17
  160. package/dist/hooks/subagent-stop.js +10 -10
  161. package/dist/hooks/summary-worker.js +17 -16
  162. package/dist/index.js +17 -17
  163. package/dist/{installer-SDBLJBAB.js → installer-DE2LH5EC.js} +4 -4
  164. package/dist/{installer-ZA6QNQ4P.js → installer-M2MDS7HC.js} +4 -4
  165. package/dist/{installer-6KAY6LD6.js → installer-VE23YFXU.js} +4 -4
  166. package/dist/{intercom-queue-K3DVKSPJ.js → intercom-queue-RNM6EPGA.js} +1 -1
  167. package/dist/keyword-extractor-UJHFWVZE.js +11 -0
  168. package/dist/lib/cloud-sync.js +3 -3
  169. package/dist/lib/consolidation.js +5 -4
  170. package/dist/lib/database.js +1 -1
  171. package/dist/lib/db-daemon-client.js +1 -1
  172. package/dist/lib/db.js +1 -1
  173. package/dist/lib/embed-worker.js +98 -0
  174. package/dist/lib/embedder.js +2 -2
  175. package/dist/lib/employee-templates.js +4 -4
  176. package/dist/lib/employees.js +1 -1
  177. package/dist/lib/exe-daemon-client.js +1 -1
  178. package/dist/lib/exe-daemon.js +523 -500
  179. package/dist/lib/hybrid-search.js +5 -6
  180. package/dist/lib/identity.js +1 -1
  181. package/dist/lib/messaging.js +9 -9
  182. package/dist/lib/reminders.js +2 -2
  183. package/dist/lib/schedules.js +5 -4
  184. package/dist/lib/skill-learning.js +3 -3
  185. package/dist/lib/store.js +4 -3
  186. package/dist/lib/task-router.js +2 -2
  187. package/dist/lib/tasks.js +9 -9
  188. package/dist/lib/tmux-routing.js +8 -8
  189. package/dist/lib/tmux-transport.js +1 -1
  190. package/dist/lib/token-spend.js +2 -2
  191. package/dist/lib/transport.js +2 -2
  192. package/dist/lib/ws-client.js +3 -1
  193. package/dist/mcp/register-tools.js +54 -51
  194. package/dist/mcp/server.js +58 -55
  195. package/dist/mcp/tools/complete-reminder.js +3 -3
  196. package/dist/mcp/tools/create-reminder.js +3 -3
  197. package/dist/mcp/tools/create-task.js +11 -11
  198. package/dist/mcp/tools/deactivate-behavior.js +4 -4
  199. package/dist/mcp/tools/list-reminders.js +3 -3
  200. package/dist/mcp/tools/list-tasks.js +11 -11
  201. package/dist/mcp/tools/send-message.js +11 -11
  202. package/dist/mcp/tools/update-task.js +10 -10
  203. package/dist/{mcp-http-config-LK2EDOEJ.js → mcp-http-config-Z2E4VUOF.js} +2 -2
  204. package/dist/{memory-cards-V3DKSRWL.js → memory-cards-SFDKDIAW.js} +1 -1
  205. package/dist/memory-graph-extractor-YD4GNH7T.js +16 -0
  206. package/dist/{memory-poisoning-defense-3B75HS74.js → memory-poisoning-defense-VEGNFELN.js} +1 -1
  207. package/dist/{memory-queue-client-LFPZPPQA.js → memory-queue-client-5HB2XUH7.js} +2 -2
  208. package/dist/{memory-reflection-HTDAUUE5.js → memory-reflection-MTPRQNI6.js} +2 -2
  209. package/dist/{notifications-76VCYXWW.js → notifications-6TCE6OBG.js} +8 -8
  210. package/dist/{orchestrator-CBNSBI5P.js → orchestrator-W2GYJR23.js} +10 -10
  211. package/dist/{plan-limits-SOR3QXKV.js → plan-limits-4EP46323.js} +2 -2
  212. package/dist/{projection-worker-FK5YOEIL.js → projection-worker-EBUYNMU2.js} +1 -1
  213. package/dist/{review-polling-ZLNDUKL4.js → review-polling-2N7KQFZZ.js} +9 -9
  214. package/dist/runtime/index.js +15 -15
  215. package/dist/{session-events-CUSPL25D.js → session-events-K47FHAXJ.js} +9 -9
  216. package/dist/{session-kill-telemetry-FLBRHBDP.js → session-kill-telemetry-275YUXM5.js} +2 -2
  217. package/dist/{session-scope-PX2ABSJO.js → session-scope-XSFJZEER.js} +8 -8
  218. package/dist/{setup-wizard-Y6PBZGFX.js → setup-wizard-UEO7HYLQ.js} +1 -1
  219. package/dist/{skill-refinement-L7PGKCYO.js → skill-refinement-WXBTANDQ.js} +1 -1
  220. package/dist/stack-update-2B2UXREV.js +50 -0
  221. package/dist/{task-enforcement-7FUILB63.js → task-enforcement-2JIJSXPU.js} +14 -16
  222. package/dist/{task-scope-2N45TE32.js → task-scope-W73Z3XWE.js} +8 -8
  223. package/dist/{tasks-crud-ADLCGHGH.js → tasks-crud-HPJKI3QQ.js} +8 -8
  224. package/dist/{tasks-review-PJ2DUI6N.js → tasks-review-MXLMPGNZ.js} +8 -8
  225. package/dist/{token-budget-T5DFXVTM.js → token-budget-BA46CVHX.js} +1 -1
  226. package/dist/{tool-capability-index-6JJN6ZRC.js → tool-capability-index-42VVN5BS.js} +1 -1
  227. package/dist/{tool-telemetry-72PVO5HV.js → tool-telemetry-GZ5E2AUL.js} +1 -1
  228. package/dist/tui/App.js +22 -18
  229. package/dist/{tui-data-63JHE6EZ.js → tui-data-PVXWQCJX.js} +8 -8
  230. package/dist/{worker-gate-REVBJUZ6.js → worker-gate-WTTK64TK.js} +1 -1
  231. package/dist/{workflow-engine-W2WNHJG5.js → workflow-engine-LT3WTT7V.js} +2 -2
  232. package/package.json +1 -1
  233. package/release-notes.json +209 -209
  234. /package/dist/{chunk-BNOZUS6J.js → chunk-6VVCAVRT.js} +0 -0
  235. /package/dist/{chunk-IC7GKK6I.js → chunk-CWQZZ7X3.js} +0 -0
  236. /package/dist/{chunk-ZI2ZVERO.js → chunk-EIW5GOBW.js} +0 -0
  237. /package/dist/{chunk-2BGGDNRD.js → chunk-IPPJEM26.js} +0 -0
  238. /package/dist/{chunk-4ISDU5KR.js → chunk-K5UR73PM.js} +0 -0
  239. /package/dist/{chunk-ZWRTVUQ6.js → chunk-KIMO5S45.js} +0 -0
  240. /package/dist/{chunk-S2FX5KJ4.js → chunk-WBLILGAP.js} +0 -0
  241. /package/dist/{core-memory-PCJ3L46L.js → core-memory-RAC6M67J.js} +0 -0
  242. /package/dist/{entity-boost-GHFPE6A2.js → entity-boost-5FIRFRDC.js} +0 -0
  243. /package/dist/{message-queue-client-CHRQYBH5.js → message-queue-client-PTQ2S7D7.js} +0 -0
  244. /package/dist/{wiki-acl-QYRAYYVQ.js → wiki-acl-MSDRCIAI.js} +0 -0
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env node
2
+ 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
+ export {
164
+ cleanOldBackups,
165
+ listBackups,
166
+ main,
167
+ preDeployBackup,
168
+ runPgBackup,
169
+ setupCron
170
+ };
@@ -0,0 +1,232 @@
1
+ #!/usr/bin/env node
2
+ import "../chunk-MLKGABMK.js";
3
+
4
+ // src/bin/vps-health-gate.ts
5
+ import { spawnSync } from "child_process";
6
+ import { appendFileSync, existsSync, mkdirSync, readdirSync } from "fs";
7
+ import http from "http";
8
+ import path from "path";
9
+ var DEPLOY_LOG = "/opt/exe-stack/deploy-log.jsonl";
10
+ var BACKUP_DIR = "/opt/exe-stack/backups";
11
+ async function checkCRM() {
12
+ const start = Date.now();
13
+ try {
14
+ const status = await httpGet("http://localhost:3000/api");
15
+ return {
16
+ check: "crm",
17
+ status: status >= 200 && status < 400 ? "pass" : "fail",
18
+ message: status >= 200 && status < 400 ? `CRM healthy (HTTP ${status})` : `CRM unhealthy (HTTP ${status})`,
19
+ durationMs: Date.now() - start
20
+ };
21
+ } catch (err) {
22
+ return {
23
+ check: "crm",
24
+ status: "fail",
25
+ message: `CRM unreachable: ${err instanceof Error ? err.message : err}`,
26
+ durationMs: Date.now() - start
27
+ };
28
+ }
29
+ }
30
+ async function checkGateway() {
31
+ const start = Date.now();
32
+ try {
33
+ const status = await httpGet("http://localhost:3100/health");
34
+ return {
35
+ check: "gateway",
36
+ status: status >= 200 && status < 300 ? "pass" : "fail",
37
+ message: status >= 200 && status < 300 ? `Gateway healthy (HTTP ${status})` : `Gateway unhealthy (HTTP ${status})`,
38
+ durationMs: Date.now() - start
39
+ };
40
+ } catch (err) {
41
+ return {
42
+ check: "gateway",
43
+ status: "fail",
44
+ message: `Gateway unreachable: ${err instanceof Error ? err.message : err}`,
45
+ durationMs: Date.now() - start
46
+ };
47
+ }
48
+ }
49
+ function checkPostgres() {
50
+ const start = Date.now();
51
+ const databaseUrl = process.env.DATABASE_URL || "postgres://exe@localhost:5432/exedb";
52
+ const result = spawnSync("psql", [databaseUrl, "-c", "SELECT 1"], {
53
+ encoding: "utf8",
54
+ stdio: ["pipe", "pipe", "pipe"],
55
+ timeout: 1e4
56
+ });
57
+ return {
58
+ check: "postgres",
59
+ status: result.status === 0 ? "pass" : "fail",
60
+ message: result.status === 0 ? "Postgres responding" : `Postgres failed: ${result.stderr?.trim() || `exit ${result.status}`}`,
61
+ durationMs: Date.now() - start
62
+ };
63
+ }
64
+ function checkRawEvents() {
65
+ const start = Date.now();
66
+ const databaseUrl = process.env.DATABASE_URL || "postgres://exe@localhost:5432/exedb";
67
+ const result = spawnSync(
68
+ "psql",
69
+ [databaseUrl, "-t", "-c", "SELECT count(*) FROM raw.raw_events"],
70
+ {
71
+ encoding: "utf8",
72
+ stdio: ["pipe", "pipe", "pipe"],
73
+ timeout: 1e4
74
+ }
75
+ );
76
+ if (result.status !== 0) {
77
+ return {
78
+ check: "raw_events",
79
+ status: "fail",
80
+ message: `raw.raw_events query failed: ${result.stderr?.trim() || `exit ${result.status}`}`,
81
+ durationMs: Date.now() - start
82
+ };
83
+ }
84
+ const count = parseInt(result.stdout?.trim() || "0", 10);
85
+ return {
86
+ check: "raw_events",
87
+ status: count > 0 ? "pass" : "fail",
88
+ message: count > 0 ? `raw.raw_events has ${count} rows` : "raw.raw_events is empty",
89
+ durationMs: Date.now() - start
90
+ };
91
+ }
92
+ async function checkGoTrue() {
93
+ const start = Date.now();
94
+ try {
95
+ const status = await httpGet("http://localhost:9999/health");
96
+ return {
97
+ check: "gotrue",
98
+ status: status >= 200 && status < 300 ? "pass" : "fail",
99
+ message: status >= 200 && status < 300 ? `GoTrue healthy (HTTP ${status})` : `GoTrue unhealthy (HTTP ${status})`,
100
+ durationMs: Date.now() - start
101
+ };
102
+ } catch (err) {
103
+ return {
104
+ check: "gotrue",
105
+ status: "fail",
106
+ message: `GoTrue unreachable: ${err instanceof Error ? err.message : err}`,
107
+ durationMs: Date.now() - start
108
+ };
109
+ }
110
+ }
111
+ async function runHealthGate() {
112
+ console.log("[health-gate] Running post-deploy health checks...\n");
113
+ const results = [];
114
+ results.push(checkPostgres());
115
+ results.push(checkRawEvents());
116
+ results.push(await checkCRM());
117
+ results.push(await checkGateway());
118
+ results.push(await checkGoTrue());
119
+ const passed = results.every((r) => r.status === "pass");
120
+ for (const r of results) {
121
+ const icon = r.status === "pass" ? "\u2713" : "\u2717";
122
+ const color = r.status === "pass" ? "\x1B[32m" : "\x1B[31m";
123
+ console.log(` ${color}${icon}\x1B[0m ${r.check.padEnd(12)} ${r.message} (${r.durationMs}ms)`);
124
+ }
125
+ console.log("");
126
+ const result = {
127
+ passed,
128
+ results,
129
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
130
+ };
131
+ return result;
132
+ }
133
+ function logResult(result) {
134
+ mkdirSync(path.dirname(DEPLOY_LOG), { recursive: true });
135
+ const line = JSON.stringify({
136
+ ...result,
137
+ type: "health_gate"
138
+ }) + "\n";
139
+ try {
140
+ appendFileSync(DEPLOY_LOG, line);
141
+ console.log(`[health-gate] Result logged to ${DEPLOY_LOG}`);
142
+ } catch (err) {
143
+ console.warn(`[health-gate] Failed to write deploy log: ${err instanceof Error ? err.message : err}`);
144
+ }
145
+ }
146
+ function restorePreDeployBackup() {
147
+ if (!existsSync(BACKUP_DIR)) return false;
148
+ const backups = readdirSync(BACKUP_DIR).filter((f) => f.startsWith("pg-pre-deploy-") && f.endsWith(".dump")).sort().reverse();
149
+ if (backups.length === 0) {
150
+ console.warn("[health-gate] No pre-deploy backup found to restore");
151
+ return false;
152
+ }
153
+ const latest = backups[0];
154
+ const filepath = path.join(BACKUP_DIR, latest);
155
+ const databaseUrl = process.env.DATABASE_URL || "postgres://exe@localhost:5432/exedb";
156
+ console.log(`[health-gate] Restoring pre-deploy backup: ${latest}`);
157
+ const result = spawnSync("pg_restore", ["-d", databaseUrl, "--clean", "--if-exists", filepath], {
158
+ encoding: "utf8",
159
+ stdio: ["pipe", "pipe", "pipe"],
160
+ timeout: 3e5
161
+ });
162
+ if (result.status !== 0) {
163
+ console.error(`[health-gate] pg_restore failed: ${result.stderr?.trim() || `exit ${result.status}`}`);
164
+ return false;
165
+ }
166
+ console.log("[health-gate] \u2713 Pre-deploy backup restored");
167
+ return true;
168
+ }
169
+ function httpGet(url) {
170
+ return new Promise((resolve, reject) => {
171
+ const req = http.request(url, { method: "GET", timeout: 1e4 }, (res) => {
172
+ res.resume();
173
+ resolve(res.statusCode ?? 0);
174
+ });
175
+ req.on("timeout", () => req.destroy(new Error("timeout")));
176
+ req.on("error", reject);
177
+ req.end();
178
+ });
179
+ }
180
+ async function main(args) {
181
+ if (args.includes("--help") || args.includes("-h")) {
182
+ console.log(`
183
+ exe-os vps-health-gate \u2014 Post-deploy health checks
184
+
185
+ Runs 5 checks: Postgres, raw_events, CRM, Gateway, GoTrue.
186
+ If any check fails, triggers rollback and exits with code 1.
187
+
188
+ Usage:
189
+ exe-os vps-health-gate Run health gate
190
+ exe-os vps-health-gate --check-only Run checks without rollback on failure
191
+ `);
192
+ return;
193
+ }
194
+ const checkOnly = args.includes("--check-only");
195
+ const result = await runHealthGate();
196
+ logResult(result);
197
+ if (result.passed) {
198
+ console.log("[health-gate] \u2713 All checks passed \u2014 deploy is healthy");
199
+ return;
200
+ }
201
+ const failed = result.results.filter((r) => r.status === "fail");
202
+ console.error(`[health-gate] \u2717 ${failed.length} check(s) failed`);
203
+ if (checkOnly) {
204
+ process.exitCode = 1;
205
+ return;
206
+ }
207
+ console.log("[health-gate] Starting rollback...");
208
+ restorePreDeployBackup();
209
+ try {
210
+ const { rollbackStackUpdate, defaultStackPaths } = await import("../stack-update-2B2UXREV.js");
211
+ const paths = defaultStackPaths();
212
+ await rollbackStackUpdate({
213
+ manifestRef: paths.manifestRef,
214
+ composeFile: paths.composeFile,
215
+ envFile: paths.envFile
216
+ });
217
+ console.log("[health-gate] \u2713 Stack rolled back to previous version");
218
+ } catch (err) {
219
+ console.error(`[health-gate] Stack rollback failed: ${err instanceof Error ? err.message : err}`);
220
+ }
221
+ process.exitCode = 1;
222
+ }
223
+ export {
224
+ checkCRM,
225
+ checkGateway,
226
+ checkGoTrue,
227
+ checkPostgres,
228
+ checkRawEvents,
229
+ logResult,
230
+ main,
231
+ runHealthGate
232
+ };
@@ -8,26 +8,26 @@ import {
8
8
  isAtCapacity,
9
9
  isWithinRelaunchCooldown,
10
10
  pollCapacityDead
11
- } from "./chunk-MKZBHM6A.js";
12
- import "./chunk-T5YULDDO.js";
13
- import "./chunk-W7SDGBEC.js";
11
+ } from "./chunk-XLWF3C4R.js";
12
+ import "./chunk-FVI4UBKO.js";
13
+ import "./chunk-MFI5OXYW.js";
14
14
  import "./chunk-LOQCOHEW.js";
15
- import "./chunk-TXSJ2L5O.js";
15
+ import "./chunk-QI4IXJN7.js";
16
16
  import "./chunk-64WZEXXA.js";
17
- import "./chunk-A7KEWR6S.js";
18
- import "./chunk-X347L57O.js";
19
17
  import "./chunk-GZIAQYGI.js";
18
+ import "./chunk-TXWQPL2U.js";
19
+ import "./chunk-CSTJQDOE.js";
20
20
  import "./chunk-ZQX6UOP6.js";
21
21
  import "./chunk-H2CFBUGF.js";
22
22
  import "./chunk-NGP6LSV2.js";
23
- import "./chunk-HLVQ5Y7B.js";
24
- import "./chunk-OPU3NYOO.js";
23
+ import "./chunk-RE4VLK45.js";
25
24
  import "./chunk-CVYC6DUW.js";
25
+ import "./chunk-OPU3NYOO.js";
26
26
  import "./chunk-GJV3WDWM.js";
27
27
  import "./chunk-MP2AFCGL.js";
28
- import "./chunk-YS63NS6M.js";
28
+ import "./chunk-IHSM5GR4.js";
29
29
  import "./chunk-HYZV25LY.js";
30
- import "./chunk-5RSYY7BE.js";
30
+ import "./chunk-SJYOPYXH.js";
31
31
  import "./chunk-RVSGXGWG.js";
32
32
  import "./chunk-FXU7JOXK.js";
33
33
  import "./chunk-MVMMULOJ.js";
@@ -1,31 +1,32 @@
1
1
  import {
2
2
  lightweightSearch
3
- } from "./chunk-23PTS2ZD.js";
4
- import "./chunk-6BURHBE6.js";
5
- import "./chunk-S2FX5KJ4.js";
3
+ } from "./chunk-IP7KJAUW.js";
4
+ import "./chunk-ZXB44R3E.js";
5
+ import "./chunk-CHCA3ZM2.js";
6
+ import "./chunk-WBLILGAP.js";
6
7
  import {
7
8
  sessionScopeFilter,
8
9
  strictSessionScopeFilter
9
- } from "./chunk-W7SDGBEC.js";
10
+ } from "./chunk-MFI5OXYW.js";
10
11
  import "./chunk-LOQCOHEW.js";
11
- import "./chunk-TXSJ2L5O.js";
12
+ import "./chunk-QI4IXJN7.js";
12
13
  import "./chunk-64WZEXXA.js";
13
- import "./chunk-A7KEWR6S.js";
14
- import "./chunk-X347L57O.js";
15
14
  import "./chunk-GZIAQYGI.js";
15
+ import "./chunk-TXWQPL2U.js";
16
+ import "./chunk-CSTJQDOE.js";
16
17
  import "./chunk-ZQX6UOP6.js";
17
18
  import "./chunk-H2CFBUGF.js";
18
19
  import "./chunk-NGP6LSV2.js";
19
- import "./chunk-HLVQ5Y7B.js";
20
- import "./chunk-OPU3NYOO.js";
20
+ import "./chunk-RE4VLK45.js";
21
21
  import "./chunk-CVYC6DUW.js";
22
+ import "./chunk-OPU3NYOO.js";
22
23
  import "./chunk-GJV3WDWM.js";
23
24
  import "./chunk-MP2AFCGL.js";
24
- import "./chunk-YS63NS6M.js";
25
+ import "./chunk-IHSM5GR4.js";
25
26
  import "./chunk-HYZV25LY.js";
26
27
  import {
27
28
  getClient
28
- } from "./chunk-5RSYY7BE.js";
29
+ } from "./chunk-SJYOPYXH.js";
29
30
  import "./chunk-RVSGXGWG.js";
30
31
  import "./chunk-FXU7JOXK.js";
31
32
  import "./chunk-6D23UNXU.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  clean,
3
3
  stableId
4
- } from "./chunk-2BGGDNRD.js";
4
+ } from "./chunk-IPPJEM26.js";
5
5
 
6
6
  // src/lib/reflection-checkpoints.ts
7
7
  function parsePayload(payload) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  buildClaudeHttpMcpEntry
3
- } from "./chunk-L7ROZR2H.js";
3
+ } from "./chunk-KXAUMIOX.js";
4
4
  import {
5
5
  loadPreferences
6
6
  } from "./chunk-GNHN5HRQ.js";
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-L3TB7CC3.js";
12
12
  import {
13
13
  ensureAllAgentSymlinks
14
- } from "./chunk-YS63NS6M.js";
14
+ } from "./chunk-IHSM5GR4.js";
15
15
  import {
16
16
  MCP_LEGACY_KEY,
17
17
  MCP_PRIMARY_KEY
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  sessionScopeFilter
3
- } from "./chunk-W7SDGBEC.js";
3
+ } from "./chunk-MFI5OXYW.js";
4
4
 
5
5
  // src/lib/git-task-sweep.ts
6
6
  import { execSync } from "child_process";
@@ -178,7 +178,7 @@ async function sweepTasks(projectName, options = {}) {
178
178
  }
179
179
  if (!dryRun) {
180
180
  try {
181
- const { updateTaskStatus } = await import("./tasks-crud-ADLCGHGH.js");
181
+ const { updateTaskStatus } = await import("./tasks-crud-HPJKI3QQ.js");
182
182
  await updateTaskStatus({
183
183
  taskId: task.id,
184
184
  status: "needs_review",