@askexenow/exe-os 0.9.294 → 0.9.296

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 (279) hide show
  1. package/deploy/compose/cloudflared/config.yml.example +14 -9
  2. package/deploy/compose/docker-compose.yml +86 -8
  3. package/deploy/compose/sso-edge/default.conf.template +87 -0
  4. package/deploy/compose/sso-edge/entrypoint.sh +23 -0
  5. package/deploy/compose/sso-edge/sso-redirect.conf +63 -0
  6. package/deploy/stack-manifests/v0.9.json +2 -2
  7. package/dist/active-agent-AFX2FODG.js +28 -0
  8. package/dist/active-agent-E2IJA7YX.js +27 -0
  9. package/dist/agentic-ontology-A2YUZK5O.js +25 -0
  10. package/dist/assets/com.askexe.exed.plist +4 -1
  11. package/dist/backfill-metadata-OC7EOD5U.js +600 -0
  12. package/dist/behaviors-H5ZOVHDH.js +46 -0
  13. package/dist/bin/agentic-ontology-backfill.js +5 -5
  14. package/dist/bin/agentic-reflection-backfill.js +6 -6
  15. package/dist/bin/agentic-semantic-label.js +5 -5
  16. package/dist/bin/backfill-conversations.js +6 -6
  17. package/dist/bin/backfill-responses.js +6 -6
  18. package/dist/bin/backfill-vectors.js +8 -8
  19. package/dist/bin/bulk-sync-postgres.js +7 -7
  20. package/dist/bin/cc-doctor.js +4 -4
  21. package/dist/bin/cleanup-stale-review-tasks.js +11 -11
  22. package/dist/bin/cli.js +16 -16
  23. package/dist/bin/deferred-daemon-restart.js +1 -1
  24. package/dist/bin/exe-agent-config.js +2 -2
  25. package/dist/bin/exe-agent.js +4 -4
  26. package/dist/bin/exe-assign.js +8 -8
  27. package/dist/bin/exe-boot.js +21 -18
  28. package/dist/bin/exe-call.js +4 -4
  29. package/dist/bin/exe-cloud.js +7 -7
  30. package/dist/bin/exe-dispatch.js +11 -11
  31. package/dist/bin/exe-doctor.js +3 -2
  32. package/dist/bin/exe-export-behaviors.js +7 -7
  33. package/dist/bin/exe-forget.js +6 -6
  34. package/dist/bin/exe-gateway.js +7 -7
  35. package/dist/bin/exe-healthcheck.js +6 -4
  36. package/dist/bin/exe-heartbeat.js +11 -11
  37. package/dist/bin/exe-kill.js +14 -14
  38. package/dist/bin/exe-launch-agent.js +18 -18
  39. package/dist/bin/exe-new-employee.js +6 -6
  40. package/dist/bin/exe-pending-messages.js +12 -12
  41. package/dist/bin/exe-pending-notifications.js +11 -11
  42. package/dist/bin/exe-pending-reviews.js +11 -11
  43. package/dist/bin/exe-rename.js +4 -4
  44. package/dist/bin/exe-review.js +13 -13
  45. package/dist/bin/exe-search.js +5 -5
  46. package/dist/bin/exe-session-cleanup.js +16 -16
  47. package/dist/bin/exe-settings.js +39 -9
  48. package/dist/bin/exe-start-codex.js +11 -11
  49. package/dist/bin/exe-start-opencode.js +8 -8
  50. package/dist/bin/exe-status.js +12 -12
  51. package/dist/bin/exe-team.js +3 -3
  52. package/dist/bin/git-sweep.js +12 -12
  53. package/dist/bin/graph-backfill.js +4 -4
  54. package/dist/bin/graph-export.js +5 -5
  55. package/dist/bin/import-history.js +7 -7
  56. package/dist/bin/install-launchd.js +13 -6
  57. package/dist/bin/install.js +26 -14
  58. package/dist/bin/intercom-check.js +4 -4
  59. package/dist/bin/mcp-sessions.js +2 -2
  60. package/dist/bin/orchestration-metrics.js +4 -4
  61. package/dist/bin/postgres-agentic-reflection-backfill.js +2 -2
  62. package/dist/bin/postgres-agentic-semantic-backfill.js +1 -1
  63. package/dist/bin/scan-tasks.js +11 -11
  64. package/dist/bin/setup.js +1 -1
  65. package/dist/bin/shard-migrate.js +4 -4
  66. package/dist/bin/stack-update.js +2 -2
  67. package/dist/bin/vps-health-gate.js +1 -1
  68. package/dist/capability-cards-4USI7CUW.js +89 -0
  69. package/dist/capacity-monitor-WLCBTEYR.js +51 -0
  70. package/dist/catchup-brief-ZR3NX6LZ.js +175 -0
  71. package/dist/chunk-22TVSRQQ.js +226 -0
  72. package/dist/chunk-2E43UXRH.js +395 -0
  73. package/dist/chunk-2PIGT6UJ.js +460 -0
  74. package/dist/chunk-3XTMW2MZ.js +535 -0
  75. package/dist/chunk-465PQFTH.js +262 -0
  76. package/dist/chunk-5CCXU2AW.js +129 -0
  77. package/dist/chunk-5D6MPWR7.js +1094 -0
  78. package/dist/chunk-5Q4MR6SL.js +123 -0
  79. package/dist/chunk-6327RBWR.js +345 -0
  80. package/dist/chunk-6MZZREZY.js +199 -0
  81. package/dist/chunk-7DI2Q4O5.js +1186 -0
  82. package/dist/chunk-7PW5VNIY.js +122 -0
  83. package/dist/chunk-7T7Y56HW.js +43 -0
  84. package/dist/chunk-7UHCWCLT.js +128 -0
  85. package/dist/chunk-A2ZUMF6L.js +1350 -0
  86. package/dist/chunk-AKV44JEH.js +185 -0
  87. package/dist/chunk-ANHWGX5N.js +735 -0
  88. package/dist/chunk-BQ3P4TKD.js +97 -0
  89. package/dist/chunk-BUZMT3KZ.js +604 -0
  90. package/dist/chunk-C2SBESBO.js +210 -0
  91. package/dist/chunk-CLSXZUZW.js +51 -0
  92. package/dist/chunk-CONHLVAR.js +1079 -0
  93. package/dist/chunk-D3WTZPFX.js +456 -0
  94. package/dist/chunk-DE6SOIYL.js +197 -0
  95. package/dist/chunk-EIVNMA3Q.js +284 -0
  96. package/dist/chunk-EJIF4FNT.js +12 -0
  97. package/dist/chunk-FDFOW564.js +171 -0
  98. package/dist/chunk-GZUBJ5EC.js +127 -0
  99. package/dist/chunk-HGZITN22.js +105 -0
  100. package/dist/chunk-HSRKDU6X.js +362 -0
  101. package/dist/chunk-IIEN2PHV.js +85 -0
  102. package/dist/chunk-JQ56VLMM.js +567 -0
  103. package/dist/chunk-JVHHXRFY.js +280 -0
  104. package/dist/chunk-JXCXGZ3S.js +55 -0
  105. package/dist/chunk-K5ZO532Q.js +4388 -0
  106. package/dist/chunk-K6CAAMXF.js +97 -0
  107. package/dist/chunk-KA26YTNU.js +81 -0
  108. package/dist/chunk-KMUW5C3R.js +381 -0
  109. package/dist/chunk-KOO3J5PV.js +20 -0
  110. package/dist/chunk-LSV7OFIH.js +290 -0
  111. package/dist/chunk-LSVFDVNY.js +1158 -0
  112. package/dist/chunk-LXDQTW32.js +230 -0
  113. package/dist/chunk-MEP7OUVZ.js +181 -0
  114. package/dist/chunk-MN2B2LKS.js +240 -0
  115. package/dist/chunk-N2EAYPYQ.js +1352 -0
  116. package/dist/chunk-N7I2A667.js +70 -0
  117. package/dist/chunk-NLZHVIOP.js +630 -0
  118. package/dist/chunk-NUH5TRZL.js +227 -0
  119. package/dist/chunk-OAHEIH3G.js +167 -0
  120. package/dist/chunk-OBHRQGCK.js +58 -0
  121. package/dist/chunk-ODFA7B2V.js +54 -0
  122. package/dist/chunk-OSNUP45F.js +731 -0
  123. package/dist/chunk-OTPRHBTO.js +33 -0
  124. package/dist/chunk-P6MUA4QU.js +157 -0
  125. package/dist/chunk-PGIOFKSK.js +2093 -0
  126. package/dist/chunk-PSE7VHWK.js +50 -0
  127. package/dist/chunk-QIFUVZFW.js +331 -0
  128. package/dist/chunk-RDPXKTVK.js +221 -0
  129. package/dist/chunk-RKYTYJGB.js +76 -0
  130. package/dist/chunk-RXLR6EFM.js +348 -0
  131. package/dist/chunk-SDB67PQJ.js +159 -0
  132. package/dist/chunk-SF2T7MP3.js +402 -0
  133. package/dist/chunk-SLU3FRFQ.js +2133 -0
  134. package/dist/chunk-SNDZJ5IV.js +214 -0
  135. package/dist/chunk-STEEAABW.js +448 -0
  136. package/dist/chunk-TUTWNHIQ.js +244 -0
  137. package/dist/chunk-UDP35QBR.js +30 -0
  138. package/dist/chunk-UKFHNJBI.js +85 -0
  139. package/dist/chunk-VC2DTK2X.js +382 -0
  140. package/dist/chunk-VRRAE5JX.js +836 -0
  141. package/dist/chunk-VVJTBQPR.js +38 -0
  142. package/dist/chunk-W3EQ362K.js +581 -0
  143. package/dist/chunk-WHIXIFHC.js +2242 -0
  144. package/dist/chunk-WRNGJJNR.js +377 -0
  145. package/dist/chunk-WUKHLCBE.js +3313 -0
  146. package/dist/chunk-WVPLHGDG.js +150 -0
  147. package/dist/chunk-XJZBSTL5.js +204 -0
  148. package/dist/chunk-Y3PMNUM5.js +304 -0
  149. package/dist/chunk-YHVS4QOV.js +14597 -0
  150. package/dist/chunk-YJ2OYAOC.js +668 -0
  151. package/dist/chunk-YYAD2GXX.js +128 -0
  152. package/dist/chunk-ZQML7EWE.js +333 -0
  153. package/dist/co-activation-XJLH46OX.js +74 -0
  154. package/dist/co-occurrence-GNN2X526.js +95 -0
  155. package/dist/code-context-index-OCPRLFG5.js +30 -0
  156. package/dist/core-memory-J4W2IYOF.js +110 -0
  157. package/dist/crdt-sync-QCBTSHIH.js +33 -0
  158. package/dist/crm-webhook-EM442VUW.js +10 -0
  159. package/dist/cto-delegation-gate-MLJMVHBK.js +280 -0
  160. package/dist/daemon-orchestration-2VNLZVTW.js +139 -0
  161. package/dist/db-backup-VUGFTPJ4.js +43 -0
  162. package/dist/doc-graph-extractor-PNRSFPSS.js +133 -0
  163. package/dist/dreaming-SK5VEQRF.js +34 -0
  164. package/dist/entity-boost-TQWWJUC2.js +375 -0
  165. package/dist/exe-drift-N34UPO7S.js +70 -0
  166. package/dist/exe-export-KACBKGVV.js +77 -0
  167. package/dist/exe-import-GXGDWACG.js +80 -0
  168. package/dist/exe-key-XPDOZBWW.js +673 -0
  169. package/dist/exe-snapshot-32GQKGQ5.js +338 -0
  170. package/dist/fast-db-init-F3TDD5VV.js +7 -0
  171. package/dist/gateway/index.js +8 -8
  172. package/dist/git-staleness-J45WNYRF.js +112 -0
  173. package/dist/git-task-sweep-BTGVQPFB.js +42 -0
  174. package/dist/global-procedures-6JCQWU4D.js +22 -0
  175. package/dist/graph-auto-extract-3ZQNXTPC.js +183 -0
  176. package/dist/hooks/bug-report-worker.js +13 -13
  177. package/dist/hooks/codex-stop-task-finalizer.js +13 -13
  178. package/dist/hooks/commit-complete.js +13 -13
  179. package/dist/hooks/error-recall.js +6 -6
  180. package/dist/hooks/exe-heartbeat-hook.js +3 -3
  181. package/dist/hooks/ingest-worker.js +3 -3
  182. package/dist/hooks/ingest.js +6 -6
  183. package/dist/hooks/instructions-loaded.js +4 -4
  184. package/dist/hooks/manifest.json +20 -20
  185. package/dist/hooks/notification.js +4 -4
  186. package/dist/hooks/post-compact.js +12 -12
  187. package/dist/hooks/post-tool-combined.js +6 -6
  188. package/dist/hooks/pre-compact.js +16 -16
  189. package/dist/hooks/pre-tool-use.js +16 -16
  190. package/dist/hooks/prompt-submit.js +24 -24
  191. package/dist/hooks/session-end.js +21 -21
  192. package/dist/hooks/session-start.js +12 -12
  193. package/dist/hooks/stop.js +19 -19
  194. package/dist/hooks/subagent-stop.js +12 -12
  195. package/dist/hooks/summary-worker.js +19 -19
  196. package/dist/index.js +19 -19
  197. package/dist/installer-5VPFY7SB.js +298 -0
  198. package/dist/installer-OENFPMA2.js +344 -0
  199. package/dist/installer-OIX4QOG5.js +40 -0
  200. package/dist/lib/cloud-sync.js +7 -7
  201. package/dist/lib/consolidation.js +6 -5
  202. package/dist/lib/database.js +2 -2
  203. package/dist/lib/db-daemon-client.js +2 -2
  204. package/dist/lib/db.js +2 -2
  205. package/dist/lib/embed-worker.js +1 -0
  206. package/dist/lib/embedder.js +7 -3
  207. package/dist/lib/employee-templates.js +4 -4
  208. package/dist/lib/employees.js +2 -2
  209. package/dist/lib/exe-daemon-client.js +2 -2
  210. package/dist/lib/exe-daemon.js +160 -79
  211. package/dist/lib/hybrid-search.js +5 -5
  212. package/dist/lib/identity.js +2 -2
  213. package/dist/lib/messaging.js +11 -11
  214. package/dist/lib/reminders.js +3 -3
  215. package/dist/lib/schedules.js +5 -5
  216. package/dist/lib/session-registry.js +4 -4
  217. package/dist/lib/skill-learning.js +6 -6
  218. package/dist/lib/store.js +4 -4
  219. package/dist/lib/task-router.js +3 -3
  220. package/dist/lib/tasks.js +12 -12
  221. package/dist/lib/tmux-routing.js +12 -10
  222. package/dist/lib/tmux-transport.js +1 -1
  223. package/dist/lib/token-spend.js +3 -3
  224. package/dist/lib/transport.js +2 -2
  225. package/dist/mcp/register-tools.js +62 -61
  226. package/dist/mcp/server.js +63 -62
  227. package/dist/mcp/tools/complete-reminder.js +4 -4
  228. package/dist/mcp/tools/create-reminder.js +4 -4
  229. package/dist/mcp/tools/create-task.js +14 -14
  230. package/dist/mcp/tools/deactivate-behavior.js +7 -7
  231. package/dist/mcp/tools/list-reminders.js +4 -4
  232. package/dist/mcp/tools/list-tasks.js +14 -14
  233. package/dist/mcp/tools/send-message.js +13 -13
  234. package/dist/mcp/tools/update-task.js +13 -13
  235. package/dist/mcp-http-config-PQTOLCTP.js +29 -0
  236. package/dist/memory-cards-4RVDZIY2.js +180 -0
  237. package/dist/memory-graph-extractor-L6YC7G4M.js +22 -0
  238. package/dist/memory-poisoning-defense-4YVJYH4G.js +224 -0
  239. package/dist/memory-queue-client-MVAUOZNJ.js +16 -0
  240. package/dist/memory-reflection-SHHDQNOH.js +244 -0
  241. package/dist/message-queue-client-DCKZT6X2.js +92 -0
  242. package/dist/notifications-JFR3G42W.js +47 -0
  243. package/dist/orchestration-events-MGCGPTDN.js +27 -0
  244. package/dist/orchestrator-DAFL2YZB.js +35 -0
  245. package/dist/pipeline-router-WWSZVPCH.js +15 -0
  246. package/dist/plan-limits-C7XCSDZC.js +28 -0
  247. package/dist/project-boot-N3NTBVLE.js +299 -0
  248. package/dist/projection-worker-MTPAPCWX.js +1084 -0
  249. package/dist/prospective-memory-BTIVUJSB.js +232 -0
  250. package/dist/reranker-UA6WVESJ.js +19 -0
  251. package/dist/retrieval-health-7XNZJEBF.js +12 -0
  252. package/dist/review-polling-4ALGMXC3.js +126 -0
  253. package/dist/runtime/index.js +13 -13
  254. package/dist/self-query-router-MROFQLQB.js +192 -0
  255. package/dist/session-events-CK44XOU4.js +38 -0
  256. package/dist/session-kill-telemetry-MT6ITDOG.js +31 -0
  257. package/dist/session-scope-3XDBWV65.js +88 -0
  258. package/dist/setup-wizard-X6DOD7MC.js +12 -0
  259. package/dist/skill-refinement-G2CCY3GM.js +159 -0
  260. package/dist/stack-update-JF7F56AS.js +84 -0
  261. package/dist/steward-gate-YF2CYXE7.js +15 -0
  262. package/dist/task-enforcement-YN6HK7NE.js +506 -0
  263. package/dist/task-scope-CVK6ISCZ.js +37 -0
  264. package/dist/tasks-crud-NTNET4JE.js +79 -0
  265. package/dist/tasks-notify-4LJVFPCV.js +40 -0
  266. package/dist/tasks-review-3V4WOIRG.js +49 -0
  267. package/dist/telemetry-upload-5PNUKGTM.js +741 -0
  268. package/dist/token-budget-E46G7ZAQ.js +86 -0
  269. package/dist/tool-capability-index-JDSMKJER.js +10 -0
  270. package/dist/tool-telemetry-J3NLS3LJ.js +17 -0
  271. package/dist/tui/App.js +18 -18
  272. package/dist/tui-data-6DOMUUCM.js +260 -0
  273. package/dist/wiki-acl-5UK37LKF.js +111 -0
  274. package/dist/worker-gate-FM7AEC7G.js +21 -0
  275. package/dist/workflow-engine-2EDUHUIY.js +28 -0
  276. package/dist/worktree-7YKKJIYR.js +28 -0
  277. package/dist/worktree-sweep-C3ELFGDN.js +21 -0
  278. package/package.json +1 -1
  279. package/release-notes.json +88 -88
@@ -0,0 +1,230 @@
1
+ // src/bin/vps-health-gate.ts
2
+ import { spawnSync } from "child_process";
3
+ import { appendFileSync, existsSync, mkdirSync, readdirSync } from "fs";
4
+ import http from "http";
5
+ import path from "path";
6
+ var DEPLOY_LOG = "/opt/exe-stack/deploy-log.jsonl";
7
+ var BACKUP_DIR = "/opt/exe-stack/backups";
8
+ async function checkCRM() {
9
+ const start = Date.now();
10
+ try {
11
+ const status = await httpGet("http://localhost:3000/api");
12
+ return {
13
+ check: "crm",
14
+ status: status >= 200 && status < 400 ? "pass" : "fail",
15
+ message: status >= 200 && status < 400 ? `CRM healthy (HTTP ${status})` : `CRM unhealthy (HTTP ${status})`,
16
+ durationMs: Date.now() - start
17
+ };
18
+ } catch (err) {
19
+ return {
20
+ check: "crm",
21
+ status: "fail",
22
+ message: `CRM unreachable: ${err instanceof Error ? err.message : err}`,
23
+ durationMs: Date.now() - start
24
+ };
25
+ }
26
+ }
27
+ async function checkGateway() {
28
+ const start = Date.now();
29
+ try {
30
+ const status = await httpGet("http://localhost:3100/health");
31
+ return {
32
+ check: "gateway",
33
+ status: status >= 200 && status < 300 ? "pass" : "fail",
34
+ message: status >= 200 && status < 300 ? `Gateway healthy (HTTP ${status})` : `Gateway unhealthy (HTTP ${status})`,
35
+ durationMs: Date.now() - start
36
+ };
37
+ } catch (err) {
38
+ return {
39
+ check: "gateway",
40
+ status: "fail",
41
+ message: `Gateway unreachable: ${err instanceof Error ? err.message : err}`,
42
+ durationMs: Date.now() - start
43
+ };
44
+ }
45
+ }
46
+ function checkPostgres() {
47
+ const start = Date.now();
48
+ const databaseUrl = process.env.DATABASE_URL || "postgres://exe@localhost:5432/exedb";
49
+ const result = spawnSync("psql", [databaseUrl, "-c", "SELECT 1"], {
50
+ encoding: "utf8",
51
+ stdio: ["pipe", "pipe", "pipe"],
52
+ timeout: 1e4
53
+ });
54
+ return {
55
+ check: "postgres",
56
+ status: result.status === 0 ? "pass" : "fail",
57
+ message: result.status === 0 ? "Postgres responding" : `Postgres failed: ${result.stderr?.trim() || `exit ${result.status}`}`,
58
+ durationMs: Date.now() - start
59
+ };
60
+ }
61
+ function checkRawEvents() {
62
+ const start = Date.now();
63
+ const databaseUrl = process.env.DATABASE_URL || "postgres://exe@localhost:5432/exedb";
64
+ const result = spawnSync(
65
+ "psql",
66
+ [databaseUrl, "-t", "-c", "SELECT count(*) FROM raw.raw_events"],
67
+ {
68
+ encoding: "utf8",
69
+ stdio: ["pipe", "pipe", "pipe"],
70
+ timeout: 1e4
71
+ }
72
+ );
73
+ if (result.status !== 0) {
74
+ return {
75
+ check: "raw_events",
76
+ status: "fail",
77
+ message: `raw.raw_events query failed: ${result.stderr?.trim() || `exit ${result.status}`}`,
78
+ durationMs: Date.now() - start
79
+ };
80
+ }
81
+ const count = parseInt(result.stdout?.trim() || "0", 10);
82
+ return {
83
+ check: "raw_events",
84
+ status: count > 0 ? "pass" : "fail",
85
+ message: count > 0 ? `raw.raw_events has ${count} rows` : "raw.raw_events is empty",
86
+ durationMs: Date.now() - start
87
+ };
88
+ }
89
+ async function checkGoTrue() {
90
+ const start = Date.now();
91
+ try {
92
+ const status = await httpGet("http://localhost:9999/health");
93
+ return {
94
+ check: "gotrue",
95
+ status: status >= 200 && status < 300 ? "pass" : "fail",
96
+ message: status >= 200 && status < 300 ? `GoTrue healthy (HTTP ${status})` : `GoTrue unhealthy (HTTP ${status})`,
97
+ durationMs: Date.now() - start
98
+ };
99
+ } catch (err) {
100
+ return {
101
+ check: "gotrue",
102
+ status: "fail",
103
+ message: `GoTrue unreachable: ${err instanceof Error ? err.message : err}`,
104
+ durationMs: Date.now() - start
105
+ };
106
+ }
107
+ }
108
+ async function runHealthGate() {
109
+ console.log("[health-gate] Running post-deploy health checks...\n");
110
+ const results = [];
111
+ results.push(checkPostgres());
112
+ results.push(checkRawEvents());
113
+ results.push(await checkCRM());
114
+ results.push(await checkGateway());
115
+ results.push(await checkGoTrue());
116
+ const passed = results.every((r) => r.status === "pass");
117
+ for (const r of results) {
118
+ const icon = r.status === "pass" ? "\u2713" : "\u2717";
119
+ const color = r.status === "pass" ? "\x1B[32m" : "\x1B[31m";
120
+ console.log(` ${color}${icon}\x1B[0m ${r.check.padEnd(12)} ${r.message} (${r.durationMs}ms)`);
121
+ }
122
+ console.log("");
123
+ const result = {
124
+ passed,
125
+ results,
126
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
127
+ };
128
+ return result;
129
+ }
130
+ function logResult(result) {
131
+ mkdirSync(path.dirname(DEPLOY_LOG), { recursive: true });
132
+ const line = JSON.stringify({
133
+ ...result,
134
+ type: "health_gate"
135
+ }) + "\n";
136
+ try {
137
+ appendFileSync(DEPLOY_LOG, line);
138
+ console.log(`[health-gate] Result logged to ${DEPLOY_LOG}`);
139
+ } catch (err) {
140
+ console.warn(`[health-gate] Failed to write deploy log: ${err instanceof Error ? err.message : err}`);
141
+ }
142
+ }
143
+ function restorePreDeployBackup() {
144
+ if (!existsSync(BACKUP_DIR)) return false;
145
+ const backups = readdirSync(BACKUP_DIR).filter((f) => f.startsWith("pg-pre-deploy-") && f.endsWith(".dump")).sort().reverse();
146
+ if (backups.length === 0) {
147
+ console.warn("[health-gate] No pre-deploy backup found to restore");
148
+ return false;
149
+ }
150
+ const latest = backups[0];
151
+ const filepath = path.join(BACKUP_DIR, latest);
152
+ const databaseUrl = process.env.DATABASE_URL || "postgres://exe@localhost:5432/exedb";
153
+ console.log(`[health-gate] Restoring pre-deploy backup: ${latest}`);
154
+ const result = spawnSync("pg_restore", ["-d", databaseUrl, "--clean", "--if-exists", filepath], {
155
+ encoding: "utf8",
156
+ stdio: ["pipe", "pipe", "pipe"],
157
+ timeout: 3e5
158
+ });
159
+ if (result.status !== 0) {
160
+ console.error(`[health-gate] pg_restore failed: ${result.stderr?.trim() || `exit ${result.status}`}`);
161
+ return false;
162
+ }
163
+ console.log("[health-gate] \u2713 Pre-deploy backup restored");
164
+ return true;
165
+ }
166
+ function httpGet(url) {
167
+ return new Promise((resolve, reject) => {
168
+ const req = http.request(url, { method: "GET", timeout: 1e4 }, (res) => {
169
+ res.resume();
170
+ resolve(res.statusCode ?? 0);
171
+ });
172
+ req.on("timeout", () => req.destroy(new Error("timeout")));
173
+ req.on("error", reject);
174
+ req.end();
175
+ });
176
+ }
177
+ async function main(args) {
178
+ if (args.includes("--help") || args.includes("-h")) {
179
+ console.log(`
180
+ exe-os vps-health-gate \u2014 Post-deploy health checks
181
+
182
+ Runs 5 checks: Postgres, raw_events, CRM, Gateway, GoTrue.
183
+ If any check fails, triggers rollback and exits with code 1.
184
+
185
+ Usage:
186
+ exe-os vps-health-gate Run health gate
187
+ exe-os vps-health-gate --check-only Run checks without rollback on failure
188
+ `);
189
+ return;
190
+ }
191
+ const checkOnly = args.includes("--check-only");
192
+ const result = await runHealthGate();
193
+ logResult(result);
194
+ if (result.passed) {
195
+ console.log("[health-gate] \u2713 All checks passed \u2014 deploy is healthy");
196
+ return;
197
+ }
198
+ const failed = result.results.filter((r) => r.status === "fail");
199
+ console.error(`[health-gate] \u2717 ${failed.length} check(s) failed`);
200
+ if (checkOnly) {
201
+ process.exitCode = 1;
202
+ return;
203
+ }
204
+ console.log("[health-gate] Starting rollback...");
205
+ restorePreDeployBackup();
206
+ try {
207
+ const { rollbackStackUpdate, defaultStackPaths } = await import("./stack-update-JF7F56AS.js");
208
+ const paths = defaultStackPaths();
209
+ await rollbackStackUpdate({
210
+ manifestRef: paths.manifestRef,
211
+ composeFile: paths.composeFile,
212
+ envFile: paths.envFile
213
+ });
214
+ console.log("[health-gate] \u2713 Stack rolled back to previous version");
215
+ } catch (err) {
216
+ console.error(`[health-gate] Stack rollback failed: ${err instanceof Error ? err.message : err}`);
217
+ }
218
+ process.exitCode = 1;
219
+ }
220
+
221
+ export {
222
+ checkCRM,
223
+ checkGateway,
224
+ checkPostgres,
225
+ checkRawEvents,
226
+ checkGoTrue,
227
+ runHealthGate,
228
+ logResult,
229
+ main
230
+ };
@@ -0,0 +1,181 @@
1
+ import {
2
+ getClient
3
+ } from "./chunk-WUKHLCBE.js";
4
+ import {
5
+ loadConfig
6
+ } from "./chunk-R36FAN53.js";
7
+
8
+ // src/lib/reminders.ts
9
+ import crypto from "crypto";
10
+ async function getCloudConfig() {
11
+ try {
12
+ const config = await loadConfig();
13
+ if (config.cloud?.apiKey && config.cloud?.endpoint) {
14
+ return { apiKey: config.cloud.apiKey, endpoint: config.cloud.endpoint };
15
+ }
16
+ } catch {
17
+ }
18
+ return null;
19
+ }
20
+ function apiBaseUrl(cloud) {
21
+ try {
22
+ const url = new URL(cloud.endpoint);
23
+ if (url.hostname.startsWith("sync.")) {
24
+ url.hostname = url.hostname.replace(/^sync\./, "api.");
25
+ return url.origin;
26
+ }
27
+ } catch {
28
+ }
29
+ return "https://api.askexe.com";
30
+ }
31
+ async function cloudPushReminder(cloud, text, dueDate) {
32
+ try {
33
+ const base = apiBaseUrl(cloud);
34
+ await fetch(`${base}/v1/reminders`, {
35
+ method: "POST",
36
+ headers: {
37
+ "Authorization": `Bearer ${cloud.apiKey}`,
38
+ "Content-Type": "application/json"
39
+ },
40
+ body: JSON.stringify({ text, due_date: dueDate })
41
+ });
42
+ } catch (err) {
43
+ process.stderr.write(`[reminders] cloud push failed: ${err instanceof Error ? err.message : String(err)}
44
+ `);
45
+ }
46
+ }
47
+ async function cloudFetchReminders(cloud) {
48
+ try {
49
+ const base = apiBaseUrl(cloud);
50
+ const res = await fetch(`${base}/v1/reminders`, {
51
+ method: "GET",
52
+ headers: {
53
+ "Authorization": `Bearer ${cloud.apiKey}`
54
+ }
55
+ });
56
+ if (!res.ok) return [];
57
+ const data = await res.json();
58
+ if (!Array.isArray(data.items)) return [];
59
+ return data.items.map((r) => ({
60
+ id: r.id,
61
+ text: r.text,
62
+ createdAt: r.created_at,
63
+ dueDate: r.due_date,
64
+ completedAt: r.completed_at,
65
+ source: "cloud"
66
+ }));
67
+ } catch (err) {
68
+ process.stderr.write(`[reminders] cloud fetch failed: ${err instanceof Error ? err.message : String(err)}
69
+ `);
70
+ return [];
71
+ }
72
+ }
73
+ async function cloudDeleteReminder(cloud, id) {
74
+ try {
75
+ const base = apiBaseUrl(cloud);
76
+ await fetch(`${base}/v1/reminders/${encodeURIComponent(id)}`, {
77
+ method: "DELETE",
78
+ headers: {
79
+ "Authorization": `Bearer ${cloud.apiKey}`
80
+ }
81
+ });
82
+ } catch (err) {
83
+ process.stderr.write(`[reminders] cloud delete failed: ${err instanceof Error ? err.message : String(err)}
84
+ `);
85
+ }
86
+ }
87
+ function dedup(local, cloud) {
88
+ const localKeys = /* @__PURE__ */ new Set();
89
+ for (const r of local) {
90
+ localKeys.add(`${r.text.trim().toLowerCase()}|${r.dueDate ?? ""}`);
91
+ }
92
+ const merged = local.map((r) => ({ ...r, source: "local" }));
93
+ for (const r of cloud) {
94
+ const key = `${r.text.trim().toLowerCase()}|${r.dueDate ?? ""}`;
95
+ if (localKeys.has(key)) {
96
+ const existing = merged.find(
97
+ (m) => m.text.trim().toLowerCase() === r.text.trim().toLowerCase() && (m.dueDate ?? "") === (r.dueDate ?? "")
98
+ );
99
+ if (existing) existing.source = "both";
100
+ } else {
101
+ merged.push({ ...r, source: "cloud" });
102
+ }
103
+ }
104
+ return merged;
105
+ }
106
+ async function createReminder(text, dueDate) {
107
+ const client = getClient();
108
+ const id = crypto.randomUUID();
109
+ const now = (/* @__PURE__ */ new Date()).toISOString();
110
+ await client.execute({
111
+ sql: `INSERT INTO reminders (id, text, created_at, due_date) VALUES (?, ?, ?, ?)`,
112
+ args: [id, text, now, dueDate ?? null]
113
+ });
114
+ const cloud = await getCloudConfig();
115
+ if (cloud) {
116
+ cloudPushReminder(cloud, text, dueDate ?? null).catch(() => {
117
+ });
118
+ }
119
+ return { id, text, createdAt: now, dueDate: dueDate ?? null, completedAt: null };
120
+ }
121
+ async function listReminders(includeCompleted = false) {
122
+ const client = getClient();
123
+ const sql = includeCompleted ? `SELECT id, text, created_at, due_date, completed_at FROM reminders ORDER BY due_date ASC NULLS LAST LIMIT 500` : `SELECT id, text, created_at, due_date, completed_at FROM reminders WHERE completed_at IS NULL ORDER BY due_date ASC NULLS LAST LIMIT 500`;
124
+ const result = await client.execute(sql);
125
+ const local = result.rows.map((row) => ({
126
+ id: String(row.id),
127
+ text: String(row.text),
128
+ createdAt: String(row.created_at),
129
+ dueDate: row.due_date ? String(row.due_date) : null,
130
+ completedAt: row.completed_at ? String(row.completed_at) : null
131
+ }));
132
+ const cloud = await getCloudConfig();
133
+ if (cloud) {
134
+ const cloudReminders = await cloudFetchReminders(cloud);
135
+ return dedup(local, cloudReminders);
136
+ }
137
+ return local;
138
+ }
139
+ async function completeReminder(idOrText) {
140
+ const client = getClient();
141
+ const now = (/* @__PURE__ */ new Date()).toISOString();
142
+ let result = await client.execute({
143
+ sql: `SELECT id, text FROM reminders WHERE id = ? AND completed_at IS NULL`,
144
+ args: [idOrText]
145
+ });
146
+ if (result.rows.length === 0) {
147
+ result = await client.execute({
148
+ sql: `SELECT id, text FROM reminders WHERE completed_at IS NULL AND text LIKE '%' || ? || '%' LIMIT 1`,
149
+ args: [idOrText]
150
+ });
151
+ }
152
+ if (result.rows.length === 0) return null;
153
+ const row = result.rows[0];
154
+ const id = String(row.id);
155
+ const text = String(row.text);
156
+ await client.execute({
157
+ sql: `UPDATE reminders SET completed_at = ? WHERE id = ?`,
158
+ args: [now, id]
159
+ });
160
+ const cloud = await getCloudConfig();
161
+ if (cloud) {
162
+ cloudDeleteReminder(cloud, id).catch(() => {
163
+ });
164
+ cloudFetchReminders(cloud).then((cloudReminders) => {
165
+ for (const cr of cloudReminders) {
166
+ if (cr.text.trim().toLowerCase() === text.trim().toLowerCase()) {
167
+ cloudDeleteReminder(cloud, cr.id).catch(() => {
168
+ });
169
+ }
170
+ }
171
+ }).catch(() => {
172
+ });
173
+ }
174
+ return { id, text, createdAt: "", dueDate: null, completedAt: now };
175
+ }
176
+
177
+ export {
178
+ createReminder,
179
+ listReminders,
180
+ completeReminder
181
+ };
@@ -0,0 +1,240 @@
1
+ import {
2
+ getClient,
3
+ isCoordinatorName,
4
+ loadEmployeesSync
5
+ } from "./chunk-WUKHLCBE.js";
6
+
7
+ // src/lib/steward-gate.ts
8
+ import crypto from "crypto";
9
+ var ROLE_PERMISSIONS = {
10
+ coordinator: /* @__PURE__ */ new Set([
11
+ "close_task",
12
+ "cancel_task",
13
+ "merge_entities",
14
+ "purge_document",
15
+ "deactivate_behavior",
16
+ "override"
17
+ ]),
18
+ manager: /* @__PURE__ */ new Set([
19
+ "close_task",
20
+ // their team only — enforced contextually
21
+ "deactivate_behavior"
22
+ // their team's behaviors
23
+ ]),
24
+ specialist: /* @__PURE__ */ new Set([
25
+ "deactivate_behavior_own",
26
+ // own behaviors only
27
+ "delete_own_memory"
28
+ ])
29
+ };
30
+ var UNIVERSAL_OPS = /* @__PURE__ */ new Set([
31
+ "update_own_task",
32
+ "store_memory",
33
+ "store_behavior"
34
+ ]);
35
+ var MANAGER_ROLES = /* @__PURE__ */ new Set(["CTO", "CMO"]);
36
+ var StewardGate = class {
37
+ /**
38
+ * Check whether an agent has authority for a destructive operation.
39
+ */
40
+ async checkAuthority(agent, operation, target) {
41
+ const role = await this.resolveRole(agent);
42
+ if (UNIVERSAL_OPS.has(operation)) {
43
+ const decision2 = {
44
+ allowed: true,
45
+ reason: `Operation "${operation}" is universally permitted.`,
46
+ confidence: 1,
47
+ requires_override: false
48
+ };
49
+ await this.logDecision(agent, operation, target, decision2);
50
+ return decision2;
51
+ }
52
+ const permissions = ROLE_PERMISSIONS[role];
53
+ let allowed = permissions.has(operation);
54
+ let reason;
55
+ if (!allowed && role === "specialist" && operation === "deactivate_behavior") {
56
+ const isOwn = await this.isOwnBehavior(agent, target);
57
+ if (isOwn) {
58
+ allowed = true;
59
+ reason = `Specialist "${agent}" can deactivate their own behavior.`;
60
+ } else {
61
+ reason = `Specialist "${agent}" cannot deactivate behaviors belonging to other agents.`;
62
+ }
63
+ } else if (allowed) {
64
+ reason = `Role "${role}" has authority for "${operation}".`;
65
+ } else {
66
+ reason = `Role "${role}" does not have authority for "${operation}". Requires coordinator override.`;
67
+ }
68
+ let requiresOverride = !allowed;
69
+ let confidence = allowed ? 0.95 : 0.9;
70
+ try {
71
+ const dreamingPath = "./dreaming.js";
72
+ const dreaming = await import(
73
+ /* @vite-ignore */
74
+ dreamingPath
75
+ );
76
+ if (typeof dreaming.calculateDrift === "function") {
77
+ const driftScore = await dreaming.calculateDrift(agent);
78
+ if (typeof driftScore === "number" && driftScore > 0.8) {
79
+ requiresOverride = true;
80
+ confidence = Math.max(0.5, confidence - 0.3);
81
+ reason += ` (\u26A0\uFE0F High drift score: ${driftScore.toFixed(2)} \u2014 requires override.)`;
82
+ }
83
+ }
84
+ } catch {
85
+ }
86
+ const decision = {
87
+ allowed: allowed && !requiresOverride,
88
+ reason,
89
+ confidence,
90
+ requires_override: requiresOverride
91
+ };
92
+ await this.logDecision(agent, operation, target, decision);
93
+ return decision;
94
+ }
95
+ /**
96
+ * Record an explicit coordinator override that bypasses the gate.
97
+ */
98
+ async override(agent, operation, target, reason) {
99
+ const role = await this.resolveRole(agent);
100
+ if (role !== "coordinator") {
101
+ const decision2 = {
102
+ allowed: false,
103
+ reason: `Only coordinators can issue overrides. "${agent}" is a ${role}.`,
104
+ confidence: 1,
105
+ requires_override: false
106
+ };
107
+ await this.logDecision(agent, `override:${operation}`, target, decision2);
108
+ return decision2;
109
+ }
110
+ const decision = {
111
+ allowed: true,
112
+ reason: `Coordinator override: ${reason}`,
113
+ confidence: 1,
114
+ requires_override: false
115
+ };
116
+ await this.logDecision(agent, `override:${operation}`, target, decision);
117
+ return decision;
118
+ }
119
+ /**
120
+ * Query the audit trail.
121
+ */
122
+ async getAuditLog(opts) {
123
+ await this.ensureAuditTable();
124
+ const client = getClient();
125
+ const conditions = [];
126
+ const args = [];
127
+ if (opts?.agent) {
128
+ conditions.push("agent = ?");
129
+ args.push(opts.agent);
130
+ }
131
+ if (opts?.operation) {
132
+ conditions.push("operation = ?");
133
+ args.push(opts.operation);
134
+ }
135
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
136
+ const limit = opts?.limit ?? 50;
137
+ const result = await client.execute({
138
+ sql: `SELECT * FROM steward_audit ${where} ORDER BY created_at DESC LIMIT ?`,
139
+ args: [...args, limit]
140
+ });
141
+ return result.rows.map((row) => ({
142
+ id: String(row.id),
143
+ agent: String(row.agent),
144
+ operation: String(row.operation),
145
+ target: String(row.target),
146
+ decision: {
147
+ allowed: Number(row.allowed) === 1,
148
+ reason: String(row.reason),
149
+ confidence: Number(row.confidence),
150
+ requires_override: Number(row.requires_override) === 1
151
+ },
152
+ timestamp: String(row.created_at)
153
+ }));
154
+ }
155
+ // -------------------------------------------------------------------------
156
+ // Internal methods
157
+ // -------------------------------------------------------------------------
158
+ /**
159
+ * Resolve an agent name to a role category.
160
+ */
161
+ async resolveRole(agent) {
162
+ if (isCoordinatorName(agent)) return "coordinator";
163
+ try {
164
+ const employees = loadEmployeesSync();
165
+ const employee = employees.find((e) => e.name === agent);
166
+ if (employee && MANAGER_ROLES.has(employee.role)) return "manager";
167
+ } catch {
168
+ }
169
+ return "specialist";
170
+ }
171
+ /**
172
+ * Check if a behavior belongs to the given agent.
173
+ */
174
+ async isOwnBehavior(agent, behaviorId) {
175
+ try {
176
+ const client = getClient();
177
+ const result = await client.execute({
178
+ sql: "SELECT agent_id FROM behaviors WHERE id = ? LIMIT 1",
179
+ args: [behaviorId]
180
+ });
181
+ if (result.rows.length === 0) return false;
182
+ return String(result.rows[0].agent_id) === agent;
183
+ } catch {
184
+ return false;
185
+ }
186
+ }
187
+ /**
188
+ * Ensure the steward_audit table exists.
189
+ */
190
+ async ensureAuditTable() {
191
+ const client = getClient();
192
+ await client.execute({
193
+ sql: `CREATE TABLE IF NOT EXISTS steward_audit (
194
+ id TEXT PRIMARY KEY,
195
+ agent TEXT NOT NULL,
196
+ operation TEXT NOT NULL,
197
+ target TEXT NOT NULL,
198
+ allowed INTEGER NOT NULL,
199
+ reason TEXT NOT NULL,
200
+ confidence REAL NOT NULL,
201
+ requires_override INTEGER NOT NULL DEFAULT 0,
202
+ created_at TEXT NOT NULL
203
+ )`,
204
+ args: []
205
+ });
206
+ }
207
+ /**
208
+ * Log a gate decision to the audit trail.
209
+ */
210
+ async logDecision(agent, operation, target, decision) {
211
+ try {
212
+ await this.ensureAuditTable();
213
+ const client = getClient();
214
+ await client.execute({
215
+ sql: `INSERT INTO steward_audit (id, agent, operation, target, allowed, reason, confidence, requires_override, created_at)
216
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
217
+ args: [
218
+ crypto.randomUUID(),
219
+ agent,
220
+ operation,
221
+ target,
222
+ decision.allowed ? 1 : 0,
223
+ decision.reason,
224
+ decision.confidence,
225
+ decision.requires_override ? 1 : 0,
226
+ (/* @__PURE__ */ new Date()).toISOString()
227
+ ]
228
+ });
229
+ } catch {
230
+ process.stderr.write(
231
+ `[steward-gate] Audit log write failed for ${agent}:${operation}
232
+ `
233
+ );
234
+ }
235
+ }
236
+ };
237
+
238
+ export {
239
+ StewardGate
240
+ };