@askexenow/exe-os 0.9.361 → 0.9.364
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 +10 -1
- package/deploy/compose/.env.example +10 -1
- package/deploy/compose/cloudflared/config.yml.example +15 -8
- package/deploy/compose/docker-compose.yml +109 -15
- package/deploy/compose/generate-env.ts +23 -1
- package/deploy/compose/status.sh +30 -0
- package/deploy/compose/uptime-check.sh +39 -2
- package/deploy/compose/wiki-schema-guard.sh +302 -0
- package/deploy/stack-manifests/v0.9.json +232 -2
- package/dist/.dist-verified.json +3 -3
- package/dist/{active-agent-UZAQUW7E.js → active-agent-MVEEEKUD.js} +9 -4
- package/dist/{active-agent-5RXOXM47.js → active-agent-WL3VEPS3.js} +9 -4
- package/dist/agent-defs-generator-MLQ4ULA2.js +240 -0
- package/dist/{agentic-ontology-EHUWSJCG.js → agentic-ontology-X3JMWNAM.js} +1 -1
- package/dist/artifact-backup-6VQ2332X.js +209 -0
- package/dist/artifact-provenance-C7HQ267L.js +13 -0
- package/dist/{backfill-gate-LRX77SUD.js → backfill-gate-BWFX6B55.js} +2 -2
- package/dist/{backfill-metadata-CTSVPOC6.js → backfill-metadata-FFDTWSGA.js} +6 -6
- package/dist/{background-jobs-Z6KHCWES.js → background-jobs-EB4BPQMT.js} +2 -2
- package/dist/{backup-verify-YJMSP24E.js → backup-verify-BZQ5RI5I.js} +27 -14
- package/dist/{behavior-injection-DTFGF6DT.js → behavior-injection-U7FGR6VM.js} +11 -11
- package/dist/{behaviors-XW7ZZKHF.js → behaviors-NLOMQW34.js} +10 -10
- package/dist/bin/age-ontology-load.js +2 -2
- package/dist/bin/agentic-ontology-backfill.js +8 -8
- package/dist/bin/agentic-reflection-backfill.js +9 -9
- package/dist/bin/agentic-semantic-label.js +8 -8
- package/dist/bin/backfill-conversations.js +8 -8
- package/dist/bin/backfill-responses.js +8 -8
- package/dist/bin/backfill-vectors.js +12 -12
- package/dist/bin/bulk-sync-postgres.js +21 -18
- package/dist/bin/cc-doctor.js +8 -7
- package/dist/bin/cleanup-stale-review-tasks.js +23 -22
- package/dist/bin/cli.js +53 -102
- package/dist/bin/customer-readiness.js +3 -1
- package/dist/bin/deferred-daemon-restart.js +111 -100
- package/dist/bin/exe-agent-config.js +4 -4
- package/dist/bin/exe-agent.js +13 -13
- package/dist/bin/exe-assign.js +10 -10
- package/dist/bin/exe-boot.js +52 -44
- package/dist/bin/exe-call.js +6 -6
- package/dist/bin/exe-cloud.js +24 -21
- package/dist/bin/exe-config-dump.js +4 -4
- package/dist/bin/exe-dispatch.js +27 -22
- package/dist/bin/exe-doctor.js +10 -7
- package/dist/bin/exe-export-behaviors.js +12 -12
- package/dist/bin/exe-forget.js +8 -8
- package/dist/bin/exe-gateway.js +8 -8
- package/dist/bin/exe-grant.js +5 -5
- package/dist/bin/exe-healthcheck.js +10 -7
- package/dist/bin/exe-heartbeat.js +30 -24
- package/dist/bin/exe-kill.js +27 -26
- package/dist/bin/exe-launch-agent.js +38 -35
- package/dist/bin/exe-mcp.js +4 -4
- package/dist/bin/exe-memory-reads.js +6 -6
- package/dist/bin/exe-new-employee.js +11 -10
- package/dist/bin/exe-os-mcp-proxy.js +4 -4
- package/dist/bin/exe-pending-messages.js +24 -23
- package/dist/bin/exe-pending-notifications.js +23 -22
- package/dist/bin/exe-pending-reviews.js +23 -22
- package/dist/bin/exe-rename.js +6 -6
- package/dist/bin/exe-review.js +26 -25
- package/dist/bin/exe-search.js +7 -7
- package/dist/bin/exe-session-cleanup.js +27 -26
- package/dist/bin/exe-settings.js +22 -19
- package/dist/bin/exe-start-codex.js +33 -19
- package/dist/bin/exe-start-opencode.js +13 -13
- package/dist/bin/exe-status.js +25 -23
- package/dist/bin/exe-support.js +5 -4
- package/dist/bin/exe-team.js +11 -5
- package/dist/bin/exe-verify-running-images.js +145 -0
- package/dist/bin/exe-watchdog.js +1 -1
- package/dist/bin/git-sweep.js +24 -23
- package/dist/bin/graph-backfill.js +9 -8
- package/dist/bin/graph-export.js +7 -7
- package/dist/bin/import-history.js +12 -10
- package/dist/bin/install.js +192 -121
- 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/pre-publish.js +1 -1
- package/dist/bin/reconcile-backlog.js +2 -2
- package/dist/bin/registry-proxy.js +1 -1
- package/dist/bin/scan-tasks.js +23 -22
- package/dist/bin/setup.js +4 -3
- package/dist/bin/shard-migrate.js +7 -7
- package/dist/bin/stack-update.js +7 -5
- package/dist/bin/vps-health-gate.js +1 -1
- package/dist/{boot-generation-ALCHPQOK.js → boot-generation-LGWKWMCF.js} +4 -4
- package/dist/{boot-review-sections-E4QOMWZM.js → boot-review-sections-IXBD7UGL.js} +22 -21
- package/dist/{branch-hygiene-Z4IBWAOX.js → branch-hygiene-UYHJ5SC5.js} +17 -10
- package/dist/{branding-7MZDHTKN.js → branding-J2MTHQUP.js} +2 -2
- package/dist/build-manifest.json +1158 -1018
- package/dist/{capability-cards-IE2DEJKT.js → capability-cards-3OGBIJRM.js} +3 -3
- package/dist/{capacity-monitor-3HVLTPQA.js → capacity-monitor-6VDEATYE.js} +24 -23
- package/dist/{catchup-brief-E2QZPNMH.js → catchup-brief-XYX5SOC6.js} +27 -26
- package/dist/{chunk-J5KRIGHE.js → chunk-2HRAVECR.js} +1 -1
- package/dist/{chunk-KDMVVHZH.js → chunk-2ROXEOGE.js} +95 -23
- package/dist/{chunk-YZLDE3XJ.js → chunk-34XAUB2R.js} +9 -5
- package/dist/{chunk-IXRNZ2Y2.js → chunk-3NETEIM6.js} +534 -221
- package/dist/{chunk-II5TSD4F.js → chunk-43PHKRHR.js} +2 -2
- package/dist/{chunk-PLLBBNMC.js → chunk-4DJCHH5R.js} +1 -1
- package/dist/{chunk-2PIEDT3G.js → chunk-4FNUBXYO.js} +1 -1
- package/dist/{chunk-R6AJ6VIJ.js → chunk-4KFTA7U7.js} +5 -1
- package/dist/{chunk-YZUHSV24.js → chunk-4LWBC7CM.js} +1 -1
- package/dist/{chunk-LEZAPRMW.js → chunk-4LYIZD3H.js} +71 -1
- package/dist/{chunk-PE4DEYIW.js → chunk-5G46JZTE.js} +3 -3
- package/dist/{org-key-admin-4W6LZ5KZ.js → chunk-5M6LXPR4.js} +62 -17
- package/dist/{chunk-P3ACGGW6.js → chunk-5WADTD5Y.js} +1 -1
- package/dist/{chunk-Q556G3P2.js → chunk-6BDSDDKT.js} +13 -4
- package/dist/{chunk-V6T42AQN.js → chunk-6G6JGJD3.js} +2 -2
- package/dist/{chunk-ASQPFNLC.js → chunk-6LNT6NCB.js} +2 -2
- package/dist/{chunk-NVRUZOEW.js → chunk-6ML32VHG.js} +5 -5
- package/dist/{chunk-ZGYRQHQ3.js → chunk-6MQWZZS5.js} +2 -2
- package/dist/{chunk-LYEQZ7TW.js → chunk-6NGFGT23.js} +272 -54
- package/dist/{chunk-RO326K57.js → chunk-6TF4ZOXP.js} +14 -5
- package/dist/{chunk-B3JV3F35.js → chunk-6WBEFNO4.js} +1 -1
- package/dist/{chunk-6LQGPGOS.js → chunk-74H5NWLY.js} +2 -2
- package/dist/{chunk-I4ILH2R6.js → chunk-7JR2IRBY.js} +5 -5
- package/dist/{chunk-CY5RX7QR.js → chunk-7WVR5UQF.js} +144 -99
- package/dist/{chunk-NO5KHKKB.js → chunk-7ZBIZFC3.js} +1 -1
- package/dist/{chunk-NGDXBN3M.js → chunk-A6PDF4BO.js} +2 -2
- package/dist/chunk-A7XLR3K7.js +45 -0
- package/dist/{chunk-FK3HX7VO.js → chunk-AA6AD7OM.js} +13 -13
- package/dist/{chunk-QNETW6LZ.js → chunk-AIVK4A5Y.js} +4 -4
- package/dist/{chunk-A4EPO6F3.js → chunk-ASBMFQAY.js} +9 -9
- package/dist/{chunk-V3ORKXAU.js → chunk-AU7AVWTM.js} +4 -4
- package/dist/{chunk-PRJBAIHV.js → chunk-AUIXAFYX.js} +221 -55
- package/dist/{chunk-EXAUIWUG.js → chunk-AYMOVFBG.js} +1 -1
- package/dist/{chunk-VEGTALBX.js → chunk-B5T43JSQ.js} +53 -21
- package/dist/{chunk-WYETVNK4.js → chunk-BIMCKCGZ.js} +1 -1
- package/dist/{chunk-4L33OFU4.js → chunk-BU36IRW2.js} +5 -2
- package/dist/{chunk-NKP4S2G5.js → chunk-CA7JP44I.js} +3 -3
- package/dist/{chunk-J7S2SOM2.js → chunk-CAV64C4J.js} +2 -2
- package/dist/chunk-CE323JHD.js +234 -0
- package/dist/{chunk-J34U3NT2.js → chunk-CLCNYC3F.js} +13 -2
- package/dist/chunk-CTXNEZFW.js +78 -0
- package/dist/{chunk-XQDF2I4D.js → chunk-DNRLIHUO.js} +1 -1
- package/dist/{chunk-NXTQAY7Z.js → chunk-DSQCXCPS.js} +7 -7
- package/dist/{chunk-YJJ7FRX5.js → chunk-DVPBCGC2.js} +11 -11
- package/dist/{chunk-F4GLFLQK.js → chunk-E5TFF3M7.js} +1 -1
- package/dist/{chunk-4P2BFNSB.js → chunk-ECVWCFY4.js} +2 -2
- package/dist/{chunk-BRIZ6OZ3.js → chunk-EKOWJXHN.js} +4 -0
- package/dist/{chunk-NVWBZXDK.js → chunk-EUEESRS6.js} +4 -4
- package/dist/{chunk-R7F6HKTH.js → chunk-EXDW3E2R.js} +3 -1
- package/dist/{chunk-QFQWHCOJ.js → chunk-FLK5IS6R.js} +3 -3
- package/dist/{chunk-6EM6USV7.js → chunk-FXPWMPU2.js} +2 -2
- package/dist/{chunk-CC4I7337.js → chunk-G4XMAGTW.js} +3 -3
- package/dist/{chunk-M67ARGXY.js → chunk-G6EUAI67.js} +1 -1
- package/dist/{chunk-AUSKITKI.js → chunk-GETICKB4.js} +53 -2
- package/dist/{chunk-WDA2KAV7.js → chunk-GSJLB6JI.js} +1 -1
- package/dist/{chunk-OLIXPGWN.js → chunk-GSWAKK5Q.js} +1 -1
- package/dist/{chunk-RBWLUYTO.js → chunk-GVZI4MK2.js} +1 -1
- package/dist/{chunk-J73I53JO.js → chunk-H5G2VUIX.js} +21 -10
- package/dist/{chunk-VQWRRXBD.js → chunk-HEFM2DBN.js} +62 -2
- package/dist/{chunk-W6J25BU7.js → chunk-HJQILEBL.js} +1 -1
- package/dist/{chunk-J5QNK5VL.js → chunk-HJVXKDEK.js} +1 -1
- package/dist/{chunk-PK5ATL23.js → chunk-HKQH4R5X.js} +6 -6
- package/dist/{working-memory-BACVOAIV.js → chunk-HSFBNCNC.js} +3 -3
- package/dist/{chunk-3YBJ36UX.js → chunk-IANRPLHA.js} +2 -2
- package/dist/{chunk-ZR4CQBAP.js → chunk-IR2MLURD.js} +1 -1
- package/dist/{chunk-IM7PRQ27.js → chunk-J2OTTJWG.js} +5 -10
- package/dist/{chunk-4UTSVUMY.js → chunk-J2W3XZHV.js} +4 -4
- package/dist/{chunk-5TKIVK3L.js → chunk-J4VETNHT.js} +1 -1
- package/dist/{chunk-RFKRCVGW.js → chunk-J7EXACGN.js} +1 -1
- package/dist/{chunk-DZLOUB4G.js → chunk-JCVDT3DG.js} +4 -4
- package/dist/{chunk-PU7UYQRC.js → chunk-JLG3GAQS.js} +1 -1
- package/dist/{chunk-RCOIKTHM.js → chunk-JN7IFPIQ.js} +1 -1
- package/dist/{chunk-E3YI6FVJ.js → chunk-JQTM2UFN.js} +1 -1
- package/dist/{chunk-A5544WYJ.js → chunk-JVLQJWUG.js} +111 -22
- package/dist/{chunk-GIFXL4AC.js → chunk-JWLZQSHW.js} +2 -2
- package/dist/{chunk-3Q2YK6UT.js → chunk-K2HYCBAG.js} +1 -1
- package/dist/{chunk-SSZIGWIG.js → chunk-K5RPFS6A.js} +1 -1
- package/dist/{chunk-ESGLOI6Q.js → chunk-KAF66DIP.js} +263 -35
- package/dist/chunk-L25OAFOU.js +93 -0
- package/dist/{chunk-FUQ2OSDV.js → chunk-L2VZBPJJ.js} +25 -8
- package/dist/chunk-LYXICKAH.js +57 -0
- package/dist/{chunk-EIBTRKUF.js → chunk-M2IZ3TQT.js} +1 -1
- package/dist/chunk-M4REI3JS.js +328 -0
- package/dist/{chunk-6DTALXOA.js → chunk-MM45YT2B.js} +1 -1
- package/dist/{chunk-NE5ZMNHN.js → chunk-MR56CIB5.js} +3 -3
- package/dist/chunk-NEHOQ3P2.js +19 -0
- package/dist/{chunk-INATSOZV.js → chunk-NQKZKOYF.js} +1 -1
- package/dist/{gotrue-session-2IT7MDGW.js → chunk-NUTZJZKW.js} +7 -8
- package/dist/{chunk-6KVG6RTP.js → chunk-O3OGCHUZ.js} +1 -1
- package/dist/{chunk-2PRAXZWM.js → chunk-OFQBR26Y.js} +10 -5
- package/dist/{chunk-UWEFIIEG.js → chunk-OJ56HXDB.js} +1 -1
- package/dist/{chunk-B6PFGUYJ.js → chunk-OZIDGXKH.js} +46 -5
- package/dist/{chunk-OUUWGAH4.js → chunk-P5OPYQZE.js} +4 -4
- package/dist/{chunk-PWNPP727.js → chunk-P7JLMFKX.js} +1 -1
- package/dist/{chunk-65WUZISK.js → chunk-PGJG5TCQ.js} +3 -3
- package/dist/{chunk-BGMLECK5.js → chunk-PX2OHZKN.js} +4 -4
- package/dist/{chunk-3TWIRKUD.js → chunk-QY6B23U2.js} +3 -3
- package/dist/{chunk-6H44454F.js → chunk-RKUGAHPO.js} +1 -1
- package/dist/{chunk-32FEF5BW.js → chunk-RSDCOZVM.js} +2 -2
- package/dist/{chunk-6EGNSEEX.js → chunk-SCGQOY5F.js} +1 -1
- package/dist/chunk-SO7KTH3Q.js +27 -0
- package/dist/{chunk-CIXA5TXF.js → chunk-T26JNDO3.js} +2 -2
- package/dist/chunk-TCTED52S.js +120 -0
- package/dist/{chunk-63Z76YCI.js → chunk-TF5T2ASS.js} +8 -8
- package/dist/{chunk-JCICPQJV.js → chunk-TLBAZU3V.js} +1 -1
- package/dist/{chunk-VEJKY5I6.js → chunk-TOLJH6XP.js} +2 -2
- package/dist/{chunk-IFJ4SVIP.js → chunk-TPXBX2LD.js} +2 -2
- package/dist/{chunk-AQF6XMZ7.js → chunk-U4KDN5B7.js} +1 -1
- package/dist/{chunk-7N63G4JS.js → chunk-U6E3CLKI.js} +3 -3
- package/dist/{chunk-GWBD5P7E.js → chunk-UCSD67VW.js} +14 -14
- package/dist/{chunk-VYFZVIWX.js → chunk-UHPMK6QZ.js} +16 -2
- package/dist/{chunk-CKOMH7TL.js → chunk-UIUO3N5Y.js} +2 -2
- package/dist/{chunk-ZZEKOI2M.js → chunk-UPCXDJ2S.js} +1 -1
- package/dist/chunk-UXX2JSZO.js +170 -0
- package/dist/{chunk-NBVSBSMZ.js → chunk-V3K6FLAS.js} +19 -7
- package/dist/{chunk-XTGR3LMF.js → chunk-VFYF7EMB.js} +2 -2
- package/dist/{chunk-WBG7XYVR.js → chunk-VHJVD3MZ.js} +8 -0
- package/dist/{chunk-HNB5IAVK.js → chunk-VVXXMY6I.js} +1 -1
- package/dist/{chunk-U32RDCUB.js → chunk-W33NLSKN.js} +52 -6
- package/dist/chunk-W352QOGG.js +45 -0
- package/dist/{chunk-RJJZH7Z7.js → chunk-W3Q53NBI.js} +71 -2
- package/dist/{chunk-HU4ZAYGH.js → chunk-X24VCGZA.js} +3 -3
- package/dist/chunk-X2X3IGZU.js +215 -0
- package/dist/{chunk-VAOUB2TK.js → chunk-X73CND7J.js} +1 -1
- package/dist/{chunk-4BI4YKHE.js → chunk-XE23TMKN.js} +10 -10
- package/dist/{chunk-FU3CUTIA.js → chunk-XI2BLVH6.js} +3 -3
- package/dist/chunk-XMVSLLED.js +38 -0
- package/dist/{chunk-7GPK2ANS.js → chunk-XOFIXD5U.js} +5 -5
- package/dist/{chunk-PGXESCSL.js → chunk-Y2DUIE6X.js} +8 -3
- package/dist/{chunk-BSPBWLUP.js → chunk-Y4JCCHHJ.js} +10 -4
- package/dist/{chunk-6W5MDNLX.js → chunk-YNR3DSAF.js} +2 -2
- package/dist/{chunk-5XEKQJE5.js → chunk-YWFFAM2S.js} +1 -1
- package/dist/{chunk-OZNCAMS3.js → chunk-Z6VZ62MY.js} +95 -10
- package/dist/{chunk-MZYNW5OY.js → chunk-Z75FBAP2.js} +1 -1
- package/dist/{chunk-3BAGFZFN.js → chunk-ZACPAM2C.js} +5 -5
- package/dist/{chunk-ZPW6FAEQ.js → chunk-ZSQNPN2W.js} +1 -1
- package/dist/{chunk-34ABBEHN.js → chunk-ZT5PSVWW.js} +43 -34
- package/dist/{chunk-VGWGXAHT.js → chunk-ZVZEYHWY.js} +104 -32
- package/dist/{cleanup-graph-garbage-SJHT3RXT.js → cleanup-graph-garbage-MLRFYWDJ.js} +9 -8
- package/dist/cloud-sync-command-LU5KLLQY.js +96 -0
- package/dist/cloud-sync-db-init-G7LBCE7T.js +46 -0
- package/dist/{cloud-sync-shutdown-43RY4ZBS.js → cloud-sync-shutdown-4IZXMEKK.js} +9 -3
- package/dist/{cloud-sync-state-DJRZORFI.js → cloud-sync-state-5DFKLWNB.js} +1 -1
- package/dist/{co-activation-5GP2E54J.js → co-activation-FCEZYVGI.js} +3 -3
- package/dist/{co-occurrence-OXF6MLM6.js → co-occurrence-5WBK7HPH.js} +7 -6
- package/dist/{code-context-index-DWR6HS35.js → code-context-index-4EQJW44K.js} +4 -4
- package/dist/{conversation-entity-extractor-YSXUBOXC.js → conversation-entity-extractor-JXAKVKF2.js} +9 -4
- package/dist/{conversation-wiki-populator-5EGRW2UZ.js → conversation-wiki-populator-6BCICVAB.js} +1 -1
- package/dist/{crdt-sync-FKEQAOQL.js → crdt-sync-RTAWVLV4.js} +2 -2
- package/dist/{crm-webhook-K4ZOGKOO.js → crm-webhook-EWALI4C5.js} +2 -2
- package/dist/{cto-delegation-gate-TQIOXGNV.js → cto-delegation-gate-HU4YUH7C.js} +22 -21
- package/dist/daemon-auth-LXP5I6BA.js +46 -0
- package/dist/{daemon-orchestration-HSW7IOH4.js → daemon-orchestration-35RSNUNI.js} +43 -28
- package/dist/{daemon-ready-VGPSRI3Z.js → daemon-ready-ZC2ANOR3.js} +1 -1
- package/dist/{daemon-restart-report-HZU5LWXN.js → daemon-restart-report-EIVD6WDJ.js} +1 -1
- package/dist/db-integrity-events-RBX7FN5E.js +16 -0
- package/dist/{db-restore-events-TFCZ4CPM.js → db-restore-events-NBARRGAC.js} +1 -1
- package/dist/{doc-graph-extractor-W5KHZUL4.js → doc-graph-extractor-PTNIPSDV.js} +12 -7
- package/dist/{documents-SLQWZNOW.js → documents-BUFAJHVZ.js} +10 -10
- package/dist/{dreaming-E2M2O32J.js → dreaming-ZPUWXFEJ.js} +26 -25
- package/dist/employee-boot-brief-QD2SP4FM.js +70 -0
- package/dist/{exe-drift-NUYEPGFR.js → exe-drift-KCZFM2RP.js} +4 -4
- package/dist/{exe-export-CFX2JAOJ.js → exe-export-W2SXNMYL.js} +12 -12
- package/dist/{exe-import-ZD5QMFN2.js → exe-import-YCYNUMER.js} +12 -12
- package/dist/{exe-key-O4KHCKZZ.js → exe-key-7IIKQRR2.js} +113 -102
- package/dist/{exe-org-TV7KW4D6.js → exe-org-223EX7VP.js} +88 -26
- package/dist/{exe-snapshot-P4YW62MR.js → exe-snapshot-QX3RERAL.js} +28 -27
- package/dist/{fast-db-init-YZNPKBNX.js → fast-db-init-PAC3C5O5.js} +1 -1
- package/dist/{founder-context-TU5G4AKR.js → founder-context-XM47756J.js} +4 -3
- package/dist/{founder-monitor-envelope-SMILO4BT.js → founder-monitor-envelope-4WFWI26F.js} +4 -4
- package/dist/fts-integrity-4M2MF2LQ.js +96 -0
- package/dist/gateway/index.js +18 -18
- package/dist/{git-staleness-CKSL73QX.js → git-staleness-XT6GXOYG.js} +3 -3
- package/dist/{global-procedures-X36SK7LZ.js → global-procedures-QICIAC33.js} +5 -5
- package/dist/gotrue-session-ODZ2ERJX.js +25 -0
- package/dist/{graph-auto-extract-OW7YWKRT.js → graph-auto-extract-RYX57CW5.js} +7 -6
- package/dist/{graph-rag-6GFTXM5O.js → graph-rag-MOBZTWOD.js} +4 -3
- package/dist/{hook-integrity-AIDFKMTA.js → hook-integrity-LGUYWWQX.js} +1 -1
- package/dist/{hook-prefetch-THLIXCLE.js → hook-prefetch-VE2NXAFN.js} +23 -22
- package/dist/hooks/bug-report-worker.js +27 -26
- package/dist/hooks/codex-stop-task-finalizer.js +28 -27
- package/dist/hooks/commit-complete.js +26 -25
- package/dist/hooks/error-recall.js +10 -9
- package/dist/hooks/exe-heartbeat-hook.js +6 -5
- package/dist/hooks/ingest-worker.js +8 -8
- package/dist/hooks/ingest.js +14 -13
- package/dist/hooks/instructions-loaded.js +7 -6
- package/dist/hooks/manifest.json +20 -20
- package/dist/hooks/notification.js +7 -6
- package/dist/hooks/post-compact.js +6 -5
- package/dist/hooks/post-tool-combined.js +31 -13
- package/dist/hooks/pre-compact.js +27 -25
- package/dist/hooks/pre-tool-use.js +58 -32
- package/dist/hooks/prompt-submit.js +41 -39
- package/dist/hooks/session-end.js +32 -30
- package/dist/hooks/session-start.js +28 -70
- package/dist/hooks/stop.js +33 -31
- package/dist/hooks/subagent-stop.js +46 -31
- package/dist/hooks/summary-worker.js +32 -31
- package/dist/index.js +37 -36
- package/dist/{installer-LORTXEPZ.js → installer-4VXHJEVU.js} +8 -6
- package/dist/{installer-CBHPY3RI.js → installer-CH7GIFHI.js} +6 -6
- package/dist/{installer-R4EKAE7F.js → installer-IK4HFXD4.js} +6 -6
- package/dist/{intercom-queue-QGXWXDYJ.js → intercom-queue-PI5APF65.js} +22 -21
- package/dist/{key-backup-status-3RC6XTUX.js → key-backup-status-G7CHESRL.js} +1 -1
- package/dist/lib/agent-config.js +2 -2
- package/dist/lib/cloud-sync.js +23 -18
- package/dist/lib/config.js +1 -1
- package/dist/lib/consolidation.js +8 -8
- package/dist/lib/crypto.js +3 -1
- package/dist/lib/database.js +17 -3
- package/dist/lib/db-backup.js +4 -2
- package/dist/lib/db-daemon-client.js +4 -4
- package/dist/lib/db-write-worker-client.js +3 -1
- package/dist/lib/db-write-worker.js +20 -2
- package/dist/lib/db.js +17 -3
- package/dist/lib/device-registry.js +2 -2
- package/dist/lib/embed-worker.js +1 -1
- package/dist/lib/embedder.js +4 -4
- package/dist/lib/employee-templates.js +6 -6
- package/dist/lib/employees.js +3 -3
- package/dist/lib/exe-daemon-client.js +3 -3
- package/dist/lib/exe-daemon.js +425 -227
- package/dist/lib/hybrid-search.js +7 -7
- package/dist/lib/identity.js +3 -3
- package/dist/lib/license.js +6 -4
- package/dist/lib/messaging.js +23 -22
- package/dist/lib/post-tool-memory.js +1 -1
- package/dist/lib/registry-proxy.js +3 -1
- package/dist/lib/reminders.js +4 -4
- package/dist/lib/schedules.js +7 -7
- package/dist/lib/session-registry.js +5 -5
- package/dist/lib/skill-learning.js +12 -11
- package/dist/lib/stack-invariants.js +21 -0
- package/dist/lib/status-brief.js +3 -3
- package/dist/lib/store.js +6 -6
- package/dist/lib/task-router.js +4 -4
- package/dist/lib/tasks.js +24 -23
- package/dist/lib/tmux-routing.js +22 -21
- package/dist/lib/token-spend.js +4 -4
- package/dist/{license-gate-NO2WGZPU.js → license-gate-Z5YXTWMH.js} +5 -4
- package/dist/{license-sync-CVEMSX3H.js → license-sync-LLX3FTHY.js} +4 -3
- package/dist/{mailbox-inbox-CP2VRBXZ.js → mailbox-inbox-4MEUOL3J.js} +2 -2
- package/dist/{mailbox-outbox-HXI7DYNC.js → mailbox-outbox-J6WIF3UY.js} +1 -1
- package/dist/mcp/register-tools.js +110 -99
- package/dist/mcp/server.js +116 -105
- 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 +27 -25
- package/dist/mcp/tools/deactivate-behavior.js +13 -12
- package/dist/mcp/tools/list-reminders.js +5 -5
- package/dist/mcp/tools/list-tasks.js +27 -25
- package/dist/mcp/tools/send-message.js +26 -24
- package/dist/mcp/tools/update-task.js +25 -24
- package/dist/{mcp-http-config-H4B5LHCL.js → mcp-http-config-PTGZH6RV.js} +4 -4
- package/dist/{mcp-session-identity-MCIJPH7T.js → mcp-session-identity-JRR4ZW2F.js} +22 -21
- package/dist/{memory-cards-PX3ZU7WC.js → memory-cards-ENOF74LR.js} +6 -6
- package/dist/{memory-graph-extractor-M5LHDSFC.js → memory-graph-extractor-V4ZUDCUN.js} +8 -7
- package/dist/{memory-poisoning-defense-LORMP5QJ.js → memory-poisoning-defense-VNCV5BFL.js} +3 -3
- package/dist/{memory-pressure-watchdog-AXJKFOCO.js → memory-pressure-watchdog-5WKDX7KP.js} +23 -22
- package/dist/{memory-queue-4VN3DTOE.js → memory-queue-RD5CSMSC.js} +2 -2
- package/dist/{memory-queue-client-OI4LDT4W.js → memory-queue-client-2NHZQRSD.js} +5 -5
- package/dist/{memory-reflection-XB6CE5MY.js → memory-reflection-H7AGGSO5.js} +3 -3
- package/dist/{monitor-grants-W3ISOLMC.js → monitor-grants-5KVETEJB.js} +3 -3
- package/dist/{notification-ledger-4JVPBNDO.js → notification-ledger-4DRPS7GP.js} +109 -47
- package/dist/{notifications-7EJE7FEP.js → notifications-ZNIPKB3G.js} +22 -21
- package/dist/{orchestration-events-GCMG4TBV.js → orchestration-events-FWR64GIC.js} +4 -4
- package/dist/{orchestration-phase-ZJ4XVNFO.js → orchestration-phase-ZED4QYF3.js} +2 -2
- package/dist/{orchestrator-W4PANW2L.js → orchestrator-AVQRCIMG.js} +24 -23
- package/dist/{org-brief-session-65THKUUQ.js → org-brief-session-XK2BTYHE.js} +12 -12
- package/dist/{org-consent-policy-QE3TE273.js → org-consent-policy-ULCYJC4W.js} +2 -2
- package/dist/{org-join-HTQ57JYH.js → org-join-P6PHLFFK.js} +10 -7
- package/dist/org-key-admin-BXGBQ3XY.js +38 -0
- package/dist/{org-key-pin-OTOKAELD.js → org-key-pin-CVVHZIMZ.js} +3 -3
- package/dist/{org-membership-SML6GCHP.js → org-membership-VC54DLZ7.js} +4 -4
- package/dist/{org-partner-config-XQGOB7EJ.js → org-partner-config-VQVT62IZ.js} +6 -6
- package/dist/{org-partner-runtime-VEQ2OQQM.js → org-partner-runtime-CCXM2LEA.js} +13 -13
- package/dist/{org-row-visibility-V2YHQMU7.js → org-row-visibility-OSDGUOYT.js} +1 -1
- package/dist/{pipeline-router-HJSXQN2M.js → pipeline-router-YA6JZ7SA.js} +4 -4
- package/dist/{plan-limits-GVLMARLS.js → plan-limits-YC6TLA4S.js} +7 -6
- package/dist/{platform-procedures-2VQGBJU7.js → platform-procedures-QNOMEXJF.js} +1 -1
- package/dist/postinstall-failure-M6PCKX4P.js +20 -0
- package/dist/{project-boot-YMHABZNL.js → project-boot-INRUUEND.js} +1 -1
- package/dist/{projection-worker-JUNR4VAH.js → projection-worker-G3AO6ASG.js} +4 -4
- package/dist/{prospective-memory-NOGTSZC4.js → prospective-memory-GXCBC5WL.js} +3 -3
- package/dist/{push-notifications-FIVZB27Y.js → push-notifications-BZZJTMN6.js} +23 -22
- package/dist/{reranker-ZZYVYCQW.js → reranker-O3NLXWT3.js} +2 -2
- package/dist/{retrieval-health-B7USNBNW.js → retrieval-health-5OSAJIQF.js} +1 -1
- package/dist/{review-polling-G7ZCVGXI.js → review-polling-3D2KID2T.js} +23 -22
- package/dist/runtime/index.js +34 -33
- package/dist/seat-benefit-VDQJYJOB.js +17 -0
- package/dist/{session-events-HIULW2JW.js → session-events-KJKEKAXC.js} +23 -22
- package/dist/{session-kill-telemetry-5FLZAMWE.js → session-kill-telemetry-RRAZEXLS.js} +23 -22
- package/dist/{session-mcp-config-YKNXG5DW.js → session-mcp-config-JTPM2XBN.js} +10 -1
- package/dist/{session-scope-64QIDBJS.js → session-scope-IPEVYKRA.js} +22 -21
- package/dist/{setup-wizard-JHR2HYWC.js → setup-wizard-7XF4NFQK.js} +4 -3
- package/dist/{shard-manager-YEOHEOHL.js → shard-manager-FW4KRSE4.js} +2 -2
- package/dist/{skill-refinement-BYZNTHQJ.js → skill-refinement-5444QK44.js} +4 -4
- package/dist/{stack-promote-4WRGX5YI.js → stack-promote-FZAXOG5N.js} +7 -5
- package/dist/{stack-release-HRUOH243.js → stack-release-AF4KZWQA.js} +15 -5
- package/dist/{stack-update-X5LCAIMH.js → stack-update-RIL3XYZG.js} +10 -4
- package/dist/{steward-gate-LWTZRKBJ.js → steward-gate-V3CDSK35.js} +4 -4
- package/dist/subagent-brief-injection-WZJRP6VC.js +96 -0
- package/dist/subagent-spawn-ledger-P6Q6JX3E.js +20 -0
- package/dist/{support-inbox-HA7N3XFN.js → support-inbox-45CEKHAK.js} +5 -4
- package/dist/{support-outbox-DSWU3IXH.js → support-outbox-HFJWG52M.js} +1 -1
- package/dist/{task-enforcement-4MFBYFXY.js → task-enforcement-HG6LBTYU.js} +23 -22
- package/dist/{task-request-inbox-VSXZKKPQ.js → task-request-inbox-ZIQW2TPL.js} +2 -2
- package/dist/{task-scope-MWBLCI4L.js → task-scope-ZWRHD2PQ.js} +22 -21
- package/dist/{tasks-crud-FXGSJNQG.js → tasks-crud-QN33WNXT.js} +22 -21
- package/dist/{tasks-notify-NHACVTKE.js → tasks-notify-DQKP253B.js} +23 -22
- package/dist/{tasks-review-L3FTWM6K.js → tasks-review-P7JTBLWK.js} +22 -21
- package/dist/{telemetry-upload-OFC56N3C.js → telemetry-upload-55GD4D27.js} +9 -8
- package/dist/{token-budget-JHZJH2OU.js → token-budget-PPDT7CLD.js} +4 -4
- package/dist/{tool-capability-index-WZWVBI2R.js → tool-capability-index-MOZ5EOIO.js} +1 -1
- package/dist/{tool-telemetry-MX4CODRA.js → tool-telemetry-R27EMAEB.js} +1 -1
- package/dist/tui/App.js +36 -35
- package/dist/{tui-data-OLCJT3X3.js → tui-data-KJNJBAAT.js} +22 -21
- package/dist/{update-support-Q5QYK6TG.js → update-support-VDS4ME3L.js} +18 -16
- package/dist/{work-state-heartbeat-FOF6RQSC.js → work-state-heartbeat-RUE6ETPX.js} +1 -1
- package/dist/{worker-gate-UEBG2QLF.js → worker-gate-LAXZSHSZ.js} +2 -2
- package/dist/{workflow-engine-E7PG3R34.js → workflow-engine-RPKV7XM3.js} +2 -2
- package/dist/working-memory-DPFRSKH3.js +18 -0
- package/dist/{worktree-VOLK2GOS.js → worktree-6LRKLO2U.js} +5 -5
- package/dist/{worktree-sweep-AATRCA33.js → worktree-sweep-NAPVXZHQ.js} +8 -6
- package/package.json +9 -5
- package/postinstall.mjs +7 -7
- package/release-notes.json +89 -32
- package/dist/chunk-HISFWAAK.js +0 -90
- package/dist/daemon-auth-OCHW2U6B.js +0 -20
- package/dist/session-summary-5EYI4XW4.js +0 -128
- /package/dist/{chunk-3NPMPEAC.js → chunk-3DWNESVC.js} +0 -0
- /package/dist/{chunk-YWN3XMPU.js → chunk-7VBIK4HP.js} +0 -0
- /package/dist/{chunk-STDYMMOX.js → chunk-ESOETGYC.js} +0 -0
- /package/dist/{chunk-6C4UAKMS.js → chunk-HVMZBCP4.js} +0 -0
- /package/dist/{chunk-Q2DLJR3C.js → chunk-IY7LTYEP.js} +0 -0
- /package/dist/{chunk-LRSBJCDL.js → chunk-QKOLA6FI.js} +0 -0
- /package/dist/{chunk-7AY76CBP.js → chunk-VNVDUM5X.js} +0 -0
- /package/dist/{core-memory-BA7UCIR6.js → core-memory-RZHRZPKR.js} +0 -0
- /package/dist/{entity-boost-VXXED26D.js → entity-boost-ZLQIQ4JU.js} +0 -0
- /package/dist/{memory-isolation-3HQ6NNX3.js → memory-isolation-OSZBBUHB.js} +0 -0
- /package/dist/{message-queue-client-5XW7ZOK2.js → message-queue-client-UKGJ6QKQ.js} +0 -0
- /package/dist/{oauth-server-H6EJUPEP.js → oauth-server-MHOTAUOI.js} +0 -0
- /package/dist/{webhook-pipe-QJRFZVKA.js → webhook-pipe-BVLWBMIC.js} +0 -0
- /package/dist/{wiki-acl-X67M7QT3.js → wiki-acl-E24PM3YR.js} +0 -0
- /package/dist/{wiki-client-57QWZIHQ.js → wiki-client-ZDPDQDX2.js} +0 -0
|
@@ -69,7 +69,16 @@ CRM_HOST_PORT=3000
|
|
|
69
69
|
|
|
70
70
|
# --- Wiki ---
|
|
71
71
|
WIKI_IMAGE_TAG=update.askexe.com/askexe/exe-wiki:v0.9.26
|
|
72
|
-
|
|
72
|
+
# Bug 2a8d3003 — DO NOT change this without migrating the data first.
|
|
73
|
+
# The wiki's users / workspaces / workspace_documents live in `public`. Point it at a
|
|
74
|
+
# different schema and Prisma will NOT error: it finds no tables, assumes a fresh
|
|
75
|
+
# database, creates empty ones, and the wiki comes up with zero documents and the
|
|
76
|
+
# admin locked out. It looks exactly like catastrophic data loss while every row is
|
|
77
|
+
# still sitting safely in `public`. That misread has a very expensive next step —
|
|
78
|
+
# restoring a backup over good data. This value used to default to `wiki`, and the
|
|
79
|
+
# only thing holding production together was a host-local compose override.
|
|
80
|
+
# exe-wiki-schema-guard blocks the boot if you get this wrong.
|
|
81
|
+
WIKI_DB_SCHEMA=public
|
|
73
82
|
WIKI_VECTOR_DB=exeOsMcp
|
|
74
83
|
WIKI_AUTH_TOKEN=CHANGEME_WIKI_AUTH_TOKEN
|
|
75
84
|
WIKI_JWT_SECRET=CHANGEME_WIKI_JWT_SECRET
|
|
@@ -99,7 +99,16 @@ CRM_HOST_PORT=3000
|
|
|
99
99
|
|
|
100
100
|
# --- Wiki ---
|
|
101
101
|
WIKI_IMAGE_TAG=ghcr.io/askexe/exe-wiki:v0.9.26
|
|
102
|
-
|
|
102
|
+
# Bug 2a8d3003 — DO NOT change this without migrating the data first.
|
|
103
|
+
# The wiki's users / workspaces / workspace_documents live in `public`. Point it at a
|
|
104
|
+
# different schema and Prisma will NOT error: it finds no tables, assumes a fresh
|
|
105
|
+
# database, creates empty ones, and the wiki comes up with zero documents and the
|
|
106
|
+
# admin locked out. It looks exactly like catastrophic data loss while every row is
|
|
107
|
+
# still sitting safely in `public`. That misread has a very expensive next step —
|
|
108
|
+
# restoring a backup over good data. This value used to default to `wiki`, and the
|
|
109
|
+
# only thing holding production together was a host-local compose override.
|
|
110
|
+
# exe-wiki-schema-guard blocks the boot if you get this wrong.
|
|
111
|
+
WIKI_DB_SCHEMA=public
|
|
103
112
|
WIKI_VECTOR_DB=exeOsMcp
|
|
104
113
|
WIKI_AUTH_TOKEN=CHANGEME_WIKI_AUTH_TOKEN
|
|
105
114
|
EXE_WIKI_ADMIN_TOKEN=CHANGEME_EXE_WIKI_ADMIN_TOKEN
|
|
@@ -8,16 +8,18 @@
|
|
|
8
8
|
# wiki.<domain> → http://exe-sso-edge:80 (unified SSO redirect)
|
|
9
9
|
# erp.<domain> → http://exe-sso-edge:80 (unified SSO redirect)
|
|
10
10
|
# gateway.<domain> → http://exe-gateway:3100
|
|
11
|
-
# dashboard
|
|
11
|
+
# dashboard.<domain> → http://exe-sso-edge:80 (unified SSO redirect — NOT
|
|
12
|
+
# exe-dashboard:80, which would skip the login gate)
|
|
12
13
|
# monitor.<domain> → http://exe-monitor-hub:8090
|
|
13
14
|
# auth.<domain> → http://exe-sso-edge:80 (auth gateway + real health aliases)
|
|
14
15
|
# api.<domain> → http://exe-os:8765
|
|
15
16
|
# No config.yml or credentials file needed — the token embeds everything.
|
|
16
17
|
#
|
|
17
|
-
# IMPORTANT: crm/wiki/erp MUST route through exe-sso-edge (NOT
|
|
18
|
-
# app container). The edge is what 302s unauthenticated
|
|
19
|
-
# auth.<domain>; routing direct to the app skips the redirect
|
|
20
|
-
# bug). exe-sso-edge picks the app by Host header, so all
|
|
18
|
+
# IMPORTANT: crm/wiki/erp/dashboard MUST route through exe-sso-edge (NOT
|
|
19
|
+
# straight to the app container). The edge is what 302s unauthenticated
|
|
20
|
+
# visitors to auth.<domain>; routing direct to the app skips the redirect
|
|
21
|
+
# (this was the bug). exe-sso-edge picks the app by Host header, so all four
|
|
22
|
+
# share one route.
|
|
21
23
|
#
|
|
22
24
|
# ADVANCED (config file mode): only needed if you want to manage routes locally
|
|
23
25
|
# instead of via the Cloudflare dashboard. Leave CLOUDFLARE_TUNNEL_TOKEN empty
|
|
@@ -44,9 +46,14 @@ ingress:
|
|
|
44
46
|
# Gateway (WhatsApp, webhooks, pairing)
|
|
45
47
|
- hostname: gateway.CHANGEME_DOMAIN
|
|
46
48
|
service: http://exe-gateway:3100
|
|
47
|
-
#
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
# Dashboard — through the unified SSO edge, same as crm/wiki/erp. The edge
|
|
50
|
+
# gates on the canonical exe_access_token cookie and 302s unauthenticated
|
|
51
|
+
# visitors to auth.<domain>/?product=Dashboard&redirect=<dashboard-url><uri>.
|
|
52
|
+
# Routing straight to exe-dashboard:80 skips that gate (same class of bug as
|
|
53
|
+
# 96f8b2b2 for crm/wiki/erp) and leaves an ungated hostname serving 200 to
|
|
54
|
+
# anonymous requests.
|
|
55
|
+
- hostname: dashboard.CHANGEME_DOMAIN
|
|
56
|
+
service: http://exe-sso-edge:80
|
|
50
57
|
# Monitor — /_/ admin panel blocked; only the API and UI are exposed publicly.
|
|
51
58
|
# The PocketBase superadmin UI must be accessed via SSH tunnel:
|
|
52
59
|
# ssh -L 8090:127.0.0.1:8090 <vps> then open http://localhost:8090/_/
|
|
@@ -376,6 +376,18 @@ services:
|
|
|
376
376
|
# SAME public value here so issuer validation accepts real browser sessions
|
|
377
377
|
# instead of rejecting them as iss-mismatch. Same default as the gotrue pin.
|
|
378
378
|
GOTRUE_JWT_ISSUER: ${GOTRUE_JWT_ISSUER:-${GOTRUE_EXTERNAL_URL:?GOTRUE_EXTERNAL_URL is required — set to https://auth.<your-domain> in .env}}
|
|
379
|
+
# Bug 550d6ab7: CRM verifies GoTrue tokens JWKS-first with an HS256
|
|
380
|
+
# shared-secret fallback (exe-crm access-token.service.ts verifyGoTrueToken
|
|
381
|
+
# -> getGoTrueSymmetricVerificationKey, landed in exe-crm 80c5cd95). Our
|
|
382
|
+
# GoTrue is configured with a SYMMETRIC GOTRUE_JWT_SECRET and no
|
|
383
|
+
# GOTRUE_JWT_KEYS, so it publishes an empty JWKS ({"keys":[]}) — and it
|
|
384
|
+
# MUST stay empty, because publishing an `oct` key would publish the
|
|
385
|
+
# signing secret itself. The HS256 fallback is therefore the ONLY viable
|
|
386
|
+
# verification path, and it returns null when this variable is unset. That
|
|
387
|
+
# is the same defect class as bug 0c0d5187 on exe-wiki (see the wiki
|
|
388
|
+
# service block below): the fix landed in the app, the secret was never
|
|
389
|
+
# handed to the container, so SSO stayed dead. Fail loud.
|
|
390
|
+
GOTRUE_JWT_SECRET: ${GOTRUE_JWT_SECRET:?GOTRUE_JWT_SECRET is required}
|
|
379
391
|
PG_DATABASE_URL: postgres://${POSTGRES_USER:-exe}:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}@exe-db:5432/${POSTGRES_DB:-exedb}?sslmode=disable
|
|
380
392
|
REDIS_URL: redis://:${REDIS_PASSWORD:?REDIS_PASSWORD is required}@redis:6379
|
|
381
393
|
CLICKHOUSE_URL: http://${CLICKHOUSE_USER:-exe}:${CLICKHOUSE_PASSWORD:?CLICKHOUSE_PASSWORD is required}@clickhouse:8123/${CLICKHOUSE_DB:-default}
|
|
@@ -460,17 +472,63 @@ services:
|
|
|
460
472
|
driver: json-file
|
|
461
473
|
options: { max-size: "10m", max-file: "3" }
|
|
462
474
|
|
|
475
|
+
# Bug 2a8d3003: one-shot pre-flight that refuses to let exe-wiki start against a
|
|
476
|
+
# schema where its data isn't. Reuses the already-present Postgres image purely for
|
|
477
|
+
# its psql client — no extra pull. See wiki-schema-guard.sh for the full rationale;
|
|
478
|
+
# the short version is that Prisma silently bootstraps an empty schema rather than
|
|
479
|
+
# erroring, so "wiki looks wiped" and "wiki is misconfigured" are indistinguishable
|
|
480
|
+
# at a glance, and the wrong diagnosis (restore from backup) destroys real data.
|
|
481
|
+
exe-wiki-schema-guard:
|
|
482
|
+
image: ${EXE_DB_IMAGE:-pgvector/pgvector:0.8.0-pg16@sha256:a132765ec351c65111b5b675928a3a0515a466a40f97277329db8b8209ad8bc9}
|
|
483
|
+
container_name: exe-wiki-schema-guard
|
|
484
|
+
restart: "no"
|
|
485
|
+
depends_on:
|
|
486
|
+
exe-db:
|
|
487
|
+
condition: service_healthy
|
|
488
|
+
environment:
|
|
489
|
+
# MUST stay byte-identical to exe-wiki's DATABASE_URL below — the guard's whole
|
|
490
|
+
# job is to assert on the schema the wiki itself will resolve.
|
|
491
|
+
DATABASE_URL: postgres://${POSTGRES_USER:-exe}:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}@exe-db:5432/${POSTGRES_DB:-exedb}?schema=${WIKI_DB_SCHEMA:-public}&sslmode=disable
|
|
492
|
+
WIKI_SCHEMA_GUARD: ${WIKI_SCHEMA_GUARD:-enforce}
|
|
493
|
+
volumes:
|
|
494
|
+
- ./wiki-schema-guard.sh:/usr/local/bin/wiki-schema-guard.sh:ro
|
|
495
|
+
# Fail OPEN when the script itself is missing, fail CLOSED on what it detects.
|
|
496
|
+
# On a stack dir that predates this change Docker materialises the bind source as
|
|
497
|
+
# an empty directory, and a guard that can't be found must not be the reason the
|
|
498
|
+
# wiki stays down — an absent guard is no worse than the status quo, whereas a
|
|
499
|
+
# guard that wedges the wiki is a new outage. stack-update installs the real
|
|
500
|
+
# script next to docker-compose.yml on every run.
|
|
501
|
+
entrypoint:
|
|
502
|
+
- bash
|
|
503
|
+
- -c
|
|
504
|
+
- |
|
|
505
|
+
if [ -f /usr/local/bin/wiki-schema-guard.sh ]; then
|
|
506
|
+
exec bash /usr/local/bin/wiki-schema-guard.sh
|
|
507
|
+
fi
|
|
508
|
+
echo "[wiki-schema-guard] script not installed next to docker-compose.yml — skipping."
|
|
509
|
+
echo "[wiki-schema-guard] run 'exe-os stack update' to install it; until then the"
|
|
510
|
+
echo "[wiki-schema-guard] wiki can boot against an empty schema undetected (bug 2a8d3003)."
|
|
511
|
+
networks:
|
|
512
|
+
- backend
|
|
513
|
+
logging:
|
|
514
|
+
driver: json-file
|
|
515
|
+
options: { max-size: "10m", max-file: "3" }
|
|
516
|
+
|
|
463
517
|
exe-wiki:
|
|
464
518
|
image: ${WIKI_IMAGE_TAG:-ghcr.io/askexe/exe-wiki:v0.9.26}
|
|
465
519
|
container_name: exe-wiki
|
|
466
520
|
restart: unless-stopped
|
|
467
521
|
# Wiki uses Prisma — runs migrate on boot via built-in entrypoint.
|
|
468
|
-
# If tables don't exist, Prisma creates them automatically.
|
|
522
|
+
# If tables don't exist, Prisma creates them automatically. That convenience is
|
|
523
|
+
# exactly why exe-wiki-schema-guard has to clear the boot first (bug 2a8d3003):
|
|
524
|
+
# pointed at the wrong schema, Prisma builds empty tables instead of complaining.
|
|
469
525
|
depends_on:
|
|
470
526
|
exe-db:
|
|
471
527
|
condition: service_healthy
|
|
472
528
|
gotrue:
|
|
473
529
|
condition: service_healthy
|
|
530
|
+
exe-wiki-schema-guard:
|
|
531
|
+
condition: service_completed_successfully
|
|
474
532
|
# SECURITY (bug 67d62490): no blanket `env_file: .env`. Each service
|
|
475
533
|
# receives ONLY the secrets it owns via the explicit `environment:` block
|
|
476
534
|
# below (values interpolated from .env at compose-parse time, never the
|
|
@@ -486,10 +544,32 @@ services:
|
|
|
486
544
|
ERROR_REPORTING_ENABLED: "true"
|
|
487
545
|
MONITOR_ERROR_URL: http://exe-monitor-hub:8090/api/exe-monitor/errors
|
|
488
546
|
MONITOR_API_KEY: ${MONITOR_API_KEY:-${EXE_MONITOR_KEY:-}}
|
|
489
|
-
|
|
547
|
+
# Bug 2a8d3003: the wiki's live data lives in the `public` schema and ALWAYS has.
|
|
548
|
+
# This default used to be `wiki`, and the ONLY thing keeping production pointed at
|
|
549
|
+
# its real content was a hand-written docker-compose.override.yml on the host that
|
|
550
|
+
# dropped the schema param. Drop that override — or honour WIKI_DB_SCHEMA=wiki —
|
|
551
|
+
# and the wiki boots against an empty `wiki` schema that Prisma will happily
|
|
552
|
+
# bootstrap: zero users, zero documents, admin locked out, and the real rows
|
|
553
|
+
# sitting untouched in `public` looking exactly like data loss. `public` is now the
|
|
554
|
+
# explicit, authoritative default so base and override agree.
|
|
555
|
+
#
|
|
556
|
+
# Why keep `?schema=` rather than omitting it: an omitted param makes resolution
|
|
557
|
+
# implicit (it falls back to the role's search_path, which ALTER ROLE can silently
|
|
558
|
+
# change). Naming the schema pins it deterministically and keeps the knob available
|
|
559
|
+
# for operators who genuinely want isolation — see WIKI_DB_SCHEMA in .env.example
|
|
560
|
+
# for the migration that requires. exe-wiki-schema-guard below enforces the choice.
|
|
561
|
+
DATABASE_URL: postgres://${POSTGRES_USER:-exe}:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}@exe-db:5432/${POSTGRES_DB:-exedb}?schema=${WIKI_DB_SCHEMA:-public}&sslmode=disable
|
|
490
562
|
AUTH_TOKEN: ${WIKI_AUTH_TOKEN:?WIKI_AUTH_TOKEN is required}
|
|
491
563
|
EXE_WIKI_ADMIN_TOKEN: ${EXE_WIKI_ADMIN_TOKEN:-}
|
|
492
564
|
GOTRUE_URL: http://gotrue:9999
|
|
565
|
+
# Bug 0c0d5187: the wiki verifies GoTrue HS256 tokens with GOTRUE_JWT_SECRET
|
|
566
|
+
# (server/utils/gotrue/index.js getGoTrueJwtSecret reads ONLY
|
|
567
|
+
# GOTRUE_JWT_SECRET || EXE_GOTRUE_JWT_SECRET) — NOT the wiki-local JWT_SECRET
|
|
568
|
+
# below. Without it, GoTrue's JWKS is empty so the asymmetric path is dead too,
|
|
569
|
+
# and every SSO exchange AND the wiki's own password form 401 with
|
|
570
|
+
# "Invalid or expired SSO token." Fail loud rather than ship a wiki nobody can
|
|
571
|
+
# log in to.
|
|
572
|
+
GOTRUE_JWT_SECRET: ${GOTRUE_JWT_SECRET:?GOTRUE_JWT_SECRET is required}
|
|
493
573
|
# Bug 98a528a7 (class): the PUBLIC auth domain the wiki login link must point at.
|
|
494
574
|
# Same lever as ERP — without it the wiki frontend can default to auth.askexe.com
|
|
495
575
|
# instead of the customer's auth.<domain>. The wiki image must build its SSO
|
|
@@ -983,9 +1063,16 @@ services:
|
|
|
983
1063
|
# Probe an app subdomain so the gate's server block (not the default 404)
|
|
984
1064
|
# answers. Any 2xx/3xx from the edge proves it is serving.
|
|
985
1065
|
# bug f1e79d3b: nginx:alpine ships BusyBox wget, which does NOT support
|
|
986
|
-
# --max-redirect — that flag made the probe error out.
|
|
987
|
-
#
|
|
988
|
-
|
|
1066
|
+
# --max-redirect — that flag made the probe error out.
|
|
1067
|
+
# Follow-up: probing "/" on a gated vhost cannot work either. Anonymous "/"
|
|
1068
|
+
# is exactly what the gate 302s to auth.<domain>, and BusyBox wget FOLLOWS
|
|
1069
|
+
# redirects with no way to cap them, so the probe chases the login funnel
|
|
1070
|
+
# and dies with "wget: too many redirections" — the edge is serving
|
|
1071
|
+
# correctly but reports unhealthy (seen live on askexe.com once crm was
|
|
1072
|
+
# routed through the edge). Probe the crm vhost's EXEMPT /healthz instead:
|
|
1073
|
+
# it never redirects and it proves vhost selection + gate exemption + the
|
|
1074
|
+
# CRM upstream in one request.
|
|
1075
|
+
test: ["CMD", "wget", "-qO-", "--header=Host: crm.${DOMAIN}", "http://127.0.0.1:80/healthz"]
|
|
989
1076
|
interval: 30s
|
|
990
1077
|
timeout: 5s
|
|
991
1078
|
retries: 3
|
|
@@ -1320,11 +1407,16 @@ services:
|
|
|
1320
1407
|
networks:
|
|
1321
1408
|
- backend
|
|
1322
1409
|
healthcheck:
|
|
1323
|
-
#
|
|
1324
|
-
# bug
|
|
1325
|
-
#
|
|
1326
|
-
#
|
|
1327
|
-
|
|
1410
|
+
# Liveness = the RQ worker process (PID 1) is still running.
|
|
1411
|
+
# bug ed19883e: the slim Frappe base has NEITHER pgrep NOR ps/procps
|
|
1412
|
+
# (exit 127 "not found") → the process-table probes were permanently
|
|
1413
|
+
# false-unhealthy → 180s stack-update gate → rollback. Also `bench
|
|
1414
|
+
# worker` runs the RQ worker in-process (frappe.utils.background_jobs
|
|
1415
|
+
# .start_worker → Worker.work()); PID 1 argv stays "bench worker", so a
|
|
1416
|
+
# `rq worker` grep would miss it even if ps existed. Use python (the
|
|
1417
|
+
# image base is python:3.14-slim) to read PID 1's argv directly — this
|
|
1418
|
+
# matches the exe-erp repo's own docker-compose.yml probe.
|
|
1419
|
+
test: ["CMD-SHELL", "python -c \"import sys; cmd=open('/proc/1/cmdline','rb').read().replace(b'\\0', b' '); sys.exit(0 if b'bench worker' in cmd else 1)\""]
|
|
1328
1420
|
interval: 30s
|
|
1329
1421
|
timeout: 5s
|
|
1330
1422
|
start_period: 30s
|
|
@@ -1369,11 +1461,13 @@ services:
|
|
|
1369
1461
|
networks:
|
|
1370
1462
|
- backend
|
|
1371
1463
|
healthcheck:
|
|
1372
|
-
#
|
|
1373
|
-
# bug
|
|
1374
|
-
#
|
|
1375
|
-
#
|
|
1376
|
-
|
|
1464
|
+
# Liveness = the scheduler process (PID 1) is still running.
|
|
1465
|
+
# bug ed19883e: the slim Frappe base has NEITHER pgrep NOR ps/procps
|
|
1466
|
+
# (exit 127 "not found") → the process-table probe was permanently
|
|
1467
|
+
# false-unhealthy → 180s stack-update gate → rollback. Use python (the
|
|
1468
|
+
# image base is python:3.14-slim) to read PID 1's argv directly — this
|
|
1469
|
+
# matches the exe-erp repo's own docker-compose.yml probe.
|
|
1470
|
+
test: ["CMD-SHELL", "python -c \"import sys; cmd=open('/proc/1/cmdline','rb').read().replace(b'\\0', b' '); sys.exit(0 if b'bench schedule' in cmd else 1)\""]
|
|
1377
1471
|
interval: 30s
|
|
1378
1472
|
timeout: 5s
|
|
1379
1473
|
start_period: 30s
|
|
@@ -27,7 +27,11 @@ const CLICKHOUSE_USER = "exe";
|
|
|
27
27
|
export const CRM_IMAGE_TAG = `${REGISTRY}/exe-crm:${CRM_RELEASE_TAG}`;
|
|
28
28
|
const CRM_HOST_PORT = "3000";
|
|
29
29
|
export const WIKI_IMAGE_TAG = `${REGISTRY}/exe-wiki:${WIKI_RELEASE_TAG}`;
|
|
30
|
-
|
|
30
|
+
// Bug 2a8d3003: the wiki's data lives in `public` and generated .env files must say
|
|
31
|
+
// so. This constant used to be "wiki", which meant every freshly generated stack
|
|
32
|
+
// pinned the wiki to an empty schema — Prisma bootstraps it silently rather than
|
|
33
|
+
// erroring, so the wiki simply comes up with no users and no documents.
|
|
34
|
+
const WIKI_DB_SCHEMA = "public";
|
|
31
35
|
const WIKI_VECTOR_DB = "exeOsMcp";
|
|
32
36
|
const WIKI_HOST_PORT = "3001";
|
|
33
37
|
export const EXE_OS_IMAGE_TAG = `${REGISTRY}/exe-os:${EXED_RELEASE_TAG}`;
|
|
@@ -174,6 +178,15 @@ export function generateEnv(options: GenerateEnvOptions): string {
|
|
|
174
178
|
"",
|
|
175
179
|
"# --- Wiki ---",
|
|
176
180
|
`WIKI_IMAGE_TAG=${WIKI_IMAGE_TAG}`,
|
|
181
|
+
"# Bug 2a8d3003 — DO NOT change this without migrating the data first.",
|
|
182
|
+
"# The wiki's users / workspaces / workspace_documents live in `public`. Point it at a",
|
|
183
|
+
"# different schema and Prisma will NOT error: it finds no tables, assumes a fresh",
|
|
184
|
+
"# database, creates empty ones, and the wiki comes up with zero documents and the",
|
|
185
|
+
"# admin locked out. It looks exactly like catastrophic data loss while every row is",
|
|
186
|
+
"# still sitting safely in `public`. That misread has a very expensive next step —",
|
|
187
|
+
"# restoring a backup over good data. This value used to default to `wiki`, and the",
|
|
188
|
+
"# only thing holding production together was a host-local compose override.",
|
|
189
|
+
"# exe-wiki-schema-guard blocks the boot if you get this wrong.",
|
|
177
190
|
`WIKI_DB_SCHEMA=${WIKI_DB_SCHEMA}`,
|
|
178
191
|
`WIKI_VECTOR_DB=${WIKI_VECTOR_DB}`,
|
|
179
192
|
`WIKI_AUTH_TOKEN=${randomSecret(RANDOM_SECRET_48)}`,
|
|
@@ -428,6 +441,15 @@ export function generateExampleEnv(): string {
|
|
|
428
441
|
"",
|
|
429
442
|
"# --- Wiki ---",
|
|
430
443
|
`WIKI_IMAGE_TAG=${WIKI_IMAGE_TAG}`,
|
|
444
|
+
"# Bug 2a8d3003 — DO NOT change this without migrating the data first.",
|
|
445
|
+
"# The wiki's users / workspaces / workspace_documents live in `public`. Point it at a",
|
|
446
|
+
"# different schema and Prisma will NOT error: it finds no tables, assumes a fresh",
|
|
447
|
+
"# database, creates empty ones, and the wiki comes up with zero documents and the",
|
|
448
|
+
"# admin locked out. It looks exactly like catastrophic data loss while every row is",
|
|
449
|
+
"# still sitting safely in `public`. That misread has a very expensive next step —",
|
|
450
|
+
"# restoring a backup over good data. This value used to default to `wiki`, and the",
|
|
451
|
+
"# only thing holding production together was a host-local compose override.",
|
|
452
|
+
"# exe-wiki-schema-guard blocks the boot if you get this wrong.",
|
|
431
453
|
`WIKI_DB_SCHEMA=${WIKI_DB_SCHEMA}`,
|
|
432
454
|
`WIKI_VECTOR_DB=${WIKI_VECTOR_DB}`,
|
|
433
455
|
"WIKI_AUTH_TOKEN=CHANGEME_WIKI_AUTH_TOKEN",
|
package/deploy/compose/status.sh
CHANGED
|
@@ -47,6 +47,36 @@ docker exec exe-db psql -U exe -d exedb -c "SELECT schemaname, COUNT(*) as table
|
|
|
47
47
|
|
|
48
48
|
echo ""
|
|
49
49
|
|
|
50
|
+
# Bug 2a8d3003: which schema is the wiki ACTUALLY running against?
|
|
51
|
+
# exe-wiki-schema-guard gates `docker compose up`, but compose dependencies are not
|
|
52
|
+
# evaluated by `docker start exe-wiki` or by restart:unless-stopped after a reboot —
|
|
53
|
+
# so a wiki can still come back on the wrong schema without the guard ever running.
|
|
54
|
+
# This makes that visible on demand. Read from the LIVE container, never from .env:
|
|
55
|
+
# a docker-compose.override.yml can rewrite DATABASE_URL and .env would not show it.
|
|
56
|
+
echo "Wiki schema (bug 2a8d3003):"
|
|
57
|
+
WIKI_URL=$(docker inspect exe-wiki --format '{{range .Config.Env}}{{println .}}{{end}}' 2>/dev/null | sed -n 's/^DATABASE_URL=//p')
|
|
58
|
+
if [[ -z "$WIKI_URL" ]]; then
|
|
59
|
+
echo " ⚠️ exe-wiki not running — cannot determine schema"
|
|
60
|
+
else
|
|
61
|
+
WIKI_SCHEMA=$(printf '%s' "$WIKI_URL" | sed -n 's/.*[?&]schema=\([^&]*\).*/\1/p')
|
|
62
|
+
[[ -z "$WIKI_SCHEMA" ]] && WIKI_SCHEMA="public"
|
|
63
|
+
COUNTS=$(docker exec exe-db psql -U exe -d exedb -tA -F' ' -c \
|
|
64
|
+
"SELECT COALESCE((SELECT count(*) FROM ${WIKI_SCHEMA}.users), -1),
|
|
65
|
+
COALESCE((SELECT count(*) FROM ${WIKI_SCHEMA}.workspace_documents), -1)" 2>/dev/null)
|
|
66
|
+
W_USERS=$(echo "$COUNTS" | awk '{print $1}')
|
|
67
|
+
W_DOCS=$(echo "$COUNTS" | awk '{print $2}')
|
|
68
|
+
if [[ "${W_USERS:-0}" -gt 0 || "${W_DOCS:-0}" -gt 0 ]]; then
|
|
69
|
+
echo -e " ${GREEN}✅${NC} schema '$WIKI_SCHEMA' — users=$W_USERS documents=$W_DOCS"
|
|
70
|
+
else
|
|
71
|
+
echo -e " ${RED}❌${NC} schema '$WIKI_SCHEMA' has NO users and NO documents — the wiki is"
|
|
72
|
+
echo -e " serving an EMPTY schema. This is a config fault, not data loss."
|
|
73
|
+
echo -e " ${YELLOW}DO NOT RESTORE FROM BACKUP.${NC} Check WIKI_DB_SCHEMA in .env and any"
|
|
74
|
+
echo -e " docker-compose.override.yml, then: docker compose up -d exe-wiki"
|
|
75
|
+
fi
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
echo ""
|
|
79
|
+
|
|
50
80
|
# Disk/Memory
|
|
51
81
|
echo "Resources:"
|
|
52
82
|
echo " RAM: $(free -h 2>/dev/null | awk '/^Mem:/ {print $3 "/" $2}' || echo 'N/A')"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# exe-os uptime check — runs every 5 min via cron.
|
|
3
|
-
# Checks: CRM, Gateway, WhatsApp state, Postgres.
|
|
3
|
+
# Checks: CRM, Gateway, WhatsApp state, Postgres, wiki schema (bug 2a8d3003).
|
|
4
4
|
# Writes JSONL to /opt/exe-stack/uptime.jsonl.
|
|
5
5
|
# Logs ALERT to stderr (captured by cron/syslog) on any failure.
|
|
6
6
|
#
|
|
@@ -92,10 +92,40 @@ check_whatsapp() {
|
|
|
92
92
|
# --- Run checks ---
|
|
93
93
|
NOW=$(ts)
|
|
94
94
|
|
|
95
|
+
# Bug 2a8d3003: is the wiki serving the schema its data is actually in?
|
|
96
|
+
# exe-wiki-schema-guard gates `docker compose up`, but nothing evaluates compose
|
|
97
|
+
# dependencies on `docker start exe-wiki` or on restart:unless-stopped after a
|
|
98
|
+
# reboot. Those paths can bring the wiki back on an empty schema with no guard run
|
|
99
|
+
# and no error anywhere — silent-empty, which is the whole failure mode. Checking it
|
|
100
|
+
# here bounds how long that can go unnoticed to one cron interval.
|
|
101
|
+
# Reads the LIVE container env, not .env: a compose override can rewrite DATABASE_URL.
|
|
102
|
+
check_wiki_schema() {
|
|
103
|
+
local url schema counts users docs
|
|
104
|
+
url=$(docker inspect exe-wiki --format '{{range .Config.Env}}{{println .}}{{end}}' 2>/dev/null \
|
|
105
|
+
| sed -n 's/^DATABASE_URL=//p')
|
|
106
|
+
[[ -z "$url" ]] && { echo "skip"; return; }
|
|
107
|
+
schema=$(printf '%s' "$url" | sed -n 's/.*[?&]schema=\([^&]*\).*/\1/p')
|
|
108
|
+
[[ -z "$schema" ]] && schema="public"
|
|
109
|
+
# Only ever interpolate a bare identifier into SQL.
|
|
110
|
+
[[ ! "$schema" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] && { echo "fail:bad-schema-name"; return; }
|
|
111
|
+
counts=$(docker exec exe-db psql -U "${POSTGRES_USER:-exe}" -d "${POSTGRES_DB:-exedb}" -tA -F' ' -c \
|
|
112
|
+
"SELECT COALESCE((SELECT count(*) FROM ${schema}.users), 0),
|
|
113
|
+
COALESCE((SELECT count(*) FROM ${schema}.workspace_documents), 0)" 2>/dev/null)
|
|
114
|
+
[[ -z "$counts" ]] && { echo "skip"; return; }
|
|
115
|
+
users=$(echo "$counts" | awk '{print $1}')
|
|
116
|
+
docs=$(echo "$counts" | awk '{print $2}')
|
|
117
|
+
if [[ "${users:-0}" -gt 0 || "${docs:-0}" -gt 0 ]]; then
|
|
118
|
+
echo "ok:$schema"
|
|
119
|
+
else
|
|
120
|
+
echo "fail:empty-schema-$schema"
|
|
121
|
+
fi
|
|
122
|
+
}
|
|
123
|
+
|
|
95
124
|
crm_status=$(check_http "CRM" "http://127.0.0.1:3000/healthz")
|
|
96
125
|
gateway_status=$(check_http "Gateway" "http://127.0.0.1:3100/health")
|
|
97
126
|
whatsapp_status=$(check_whatsapp)
|
|
98
127
|
postgres_status=$(check_postgres)
|
|
128
|
+
wiki_schema_status=$(check_wiki_schema)
|
|
99
129
|
|
|
100
130
|
# --- Determine overall health ---
|
|
101
131
|
overall="ok"
|
|
@@ -117,11 +147,18 @@ if [[ "$postgres_status" != "ok" ]]; then
|
|
|
117
147
|
overall="critical"
|
|
118
148
|
alerts="${alerts}Postgres($postgres_status) "
|
|
119
149
|
fi
|
|
150
|
+
# A wiki serving an empty schema is critical: it looks like total data loss to
|
|
151
|
+
# whoever opens it, and the wrong reflex (restore from backup) destroys the real
|
|
152
|
+
# rows still sitting in the other schema. Say so in the alert itself.
|
|
153
|
+
if [[ "$wiki_schema_status" == fail:* ]]; then
|
|
154
|
+
overall="critical"
|
|
155
|
+
alerts="${alerts}WikiSchema($wiki_schema_status — CONFIG FAULT, DO NOT RESTORE FROM BACKUP, see bug 2a8d3003) "
|
|
156
|
+
fi
|
|
120
157
|
|
|
121
158
|
# --- Write JSONL ---
|
|
122
159
|
# Single-line JSON — no jq dependency required
|
|
123
160
|
ENTRY=$(cat <<JSONEOF
|
|
124
|
-
{"ts":"${NOW}","overall":"${overall}","crm":"${crm_status}","gateway":"${gateway_status}","whatsapp":"${whatsapp_status}","postgres":"${postgres_status}"}
|
|
161
|
+
{"ts":"${NOW}","overall":"${overall}","crm":"${crm_status}","gateway":"${gateway_status}","whatsapp":"${whatsapp_status}","postgres":"${postgres_status}","wiki_schema":"${wiki_schema_status}"}
|
|
125
162
|
JSONEOF
|
|
126
163
|
)
|
|
127
164
|
|