@askexenow/exe-os 0.9.287 → 0.9.289
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 +8 -1
- package/deploy/compose/README.md +27 -0
- package/deploy/compose/docker-compose.yml +72 -54
- package/deploy/compose/generate-env.ts +16 -2
- package/deploy/compose/setup.sh +63 -0
- package/dist/active-agent-DVMG6WVY.js +27 -0
- package/dist/active-agent-JJVXXRZV.js +26 -0
- package/dist/active-agent-KB4346K6.js +26 -0
- package/dist/active-agent-LTYLGBJX.js +27 -0
- package/dist/active-agent-V4W557J4.js +26 -0
- package/dist/active-agent-XZVU5XBO.js +27 -0
- package/dist/agentic-ontology-2LJST3BE.js +25 -0
- package/dist/agentic-ontology-4PNQX4YW.js +25 -0
- package/dist/agentic-ontology-WOTOTSR7.js +25 -0
- package/dist/backfill-metadata-O2BQIEVT.js +599 -0
- package/dist/backfill-metadata-PHXNTBNR.js +599 -0
- package/dist/backfill-metadata-W7PJ6YGP.js +599 -0
- package/dist/background-jobs-RIECIYW5.js +25 -0
- package/dist/background-jobs-YTYZRTCM.js +25 -0
- package/dist/behaviors-EM5KZSHT.js +39 -0
- package/dist/behaviors-MO5BWFPW.js +39 -0
- package/dist/behaviors-TMA2HRTL.js +39 -0
- 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 +11 -11
- package/dist/bin/bulk-sync-postgres.js +9 -9
- package/dist/bin/cc-doctor.js +8 -7
- package/dist/bin/cleanup-stale-review-tasks.js +14 -14
- package/dist/bin/cli.js +20 -20
- package/dist/bin/deferred-daemon-restart.js +1 -1
- package/dist/bin/exe-agent-config.js +5 -5
- package/dist/bin/exe-agent.js +10 -10
- package/dist/bin/exe-assign.js +10 -10
- package/dist/bin/exe-boot.js +33 -22
- package/dist/bin/exe-call.js +6 -6
- package/dist/bin/exe-cloud.js +8 -8
- package/dist/bin/exe-dispatch.js +14 -14
- package/dist/bin/exe-doctor.js +4 -1
- package/dist/bin/exe-export-behaviors.js +9 -9
- package/dist/bin/exe-forget.js +8 -8
- package/dist/bin/exe-gateway.js +9 -9
- package/dist/bin/exe-healthcheck.js +10 -7
- package/dist/bin/exe-heartbeat.js +14 -14
- package/dist/bin/exe-kill.js +17 -17
- package/dist/bin/exe-launch-agent.js +21 -21
- package/dist/bin/exe-new-employee.js +9 -9
- package/dist/bin/exe-pending-messages.js +15 -15
- package/dist/bin/exe-pending-notifications.js +14 -14
- package/dist/bin/exe-pending-reviews.js +14 -14
- package/dist/bin/exe-rename.js +6 -6
- package/dist/bin/exe-review.js +16 -16
- package/dist/bin/exe-search.js +7 -7
- package/dist/bin/exe-session-cleanup.js +19 -19
- package/dist/bin/exe-settings.js +8 -8
- package/dist/bin/exe-start-codex.js +13 -13
- package/dist/bin/exe-start-opencode.js +10 -10
- package/dist/bin/exe-start.sh +29 -7
- package/dist/bin/exe-status.js +15 -15
- package/dist/bin/exe-support.js +3 -3
- package/dist/bin/exe-team.js +5 -5
- package/dist/bin/git-sweep.js +15 -15
- package/dist/bin/graph-backfill.js +9 -9
- package/dist/bin/graph-export.js +7 -7
- package/dist/bin/import-history.js +11 -11
- package/dist/bin/install-launchd.js +24 -1
- package/dist/bin/install.js +36 -12
- package/dist/bin/intercom-check.js +4 -4
- package/dist/bin/mcp-sessions.js +2 -2
- package/dist/bin/orchestration-metrics.js +6 -6
- package/dist/bin/postgres-agentic-reflection-backfill.js +4 -4
- package/dist/bin/postgres-agentic-semantic-backfill.js +3 -3
- package/dist/bin/scan-tasks.js +14 -14
- package/dist/bin/setup.js +2 -2
- package/dist/bin/shard-migrate.js +7 -7
- package/dist/bin/stack-update.js +7 -6
- package/dist/bin/vps-health-gate.js +1 -1
- package/dist/branding-6PY5DNDC.js +97 -0
- package/dist/branding-PCLBJ3EP.js +97 -0
- package/dist/capability-cards-4NKVY6GD.js +88 -0
- package/dist/capability-cards-OEL47N2B.js +88 -0
- package/dist/capability-cards-UD5TCSAZ.js +88 -0
- package/dist/capacity-monitor-AU7MVZED.js +50 -0
- package/dist/capacity-monitor-CV7PWPYR.js +50 -0
- package/dist/capacity-monitor-UGMHVSUD.js +50 -0
- package/dist/catchup-brief-AZND3EET.js +174 -0
- package/dist/catchup-brief-HNEUKB7X.js +174 -0
- package/dist/catchup-brief-TFL6MYOZ.js +154 -0
- package/dist/chunk-22R3G3GD.js +297 -0
- package/dist/chunk-2CO47E5Q.js +210 -0
- package/dist/chunk-2F5SG3CE.js +230 -0
- package/dist/chunk-2F5UVNYP.js +167 -0
- package/dist/chunk-2IJCGYY2.js +30 -0
- package/dist/chunk-2QMWIGJK.js +197 -0
- package/dist/chunk-2V52EJI7.js +14365 -0
- package/dist/chunk-2WCXJVSN.js +456 -0
- package/dist/chunk-2X52UGP7.js +190 -0
- package/dist/chunk-2ZAOSGBX.js +668 -0
- package/dist/chunk-32K5NWMR.js +42 -0
- package/dist/chunk-32VOJ4GK.js +181 -0
- package/dist/chunk-3AUM4JVV.js +127 -0
- package/dist/chunk-3H5FNTXS.js +85 -0
- package/dist/chunk-3OC6MJIX.js +210 -0
- package/dist/chunk-3OSDE4Y2.js +1119 -0
- package/dist/chunk-3Q4UEXDE.js +297 -0
- package/dist/chunk-3RZNDPPW.js +2113 -0
- package/dist/chunk-3X2ZT5FN.js +3276 -0
- package/dist/chunk-43QFBQHT.js +1094 -0
- package/dist/chunk-44CP7NR2.js +333 -0
- package/dist/chunk-4EBW3URQ.js +4318 -0
- package/dist/chunk-4FMNDJMY.js +50 -0
- package/dist/chunk-4KVMYS3U.js +280 -0
- package/dist/chunk-4UTH3H4H.js +128 -0
- package/dist/chunk-5BKYHLA3.js +411 -0
- package/dist/chunk-5J2L25OK.js +203 -0
- package/dist/chunk-5NQOIKAB.js +214 -0
- package/dist/chunk-5P3HOBZX.js +487 -0
- package/dist/chunk-5RRYMKXN.js +150 -0
- package/dist/chunk-5TYYOPTD.js +50 -0
- package/dist/chunk-5VAARLQR.js +58 -0
- package/dist/chunk-5XOAYMSU.js +4318 -0
- package/dist/chunk-64GBV67L.js +1068 -0
- package/dist/chunk-6DQNLI55.js +240 -0
- package/dist/chunk-6GOT6FNJ.js +1352 -0
- package/dist/chunk-6KH24PJ7.js +221 -0
- package/dist/chunk-6MFM4N37.js +574 -0
- package/dist/chunk-6TV66RAI.js +192 -0
- package/dist/chunk-6UD5CM2H.js +244 -0
- package/dist/chunk-6WEETM7D.js +81 -0
- package/dist/chunk-6YR3J6WG.js +203 -0
- package/dist/chunk-6ZD3MW7T.js +97 -0
- package/dist/chunk-73ORCJNJ.js +231 -0
- package/dist/chunk-75GH76GO.js +129 -0
- package/dist/chunk-77HA7ATH.js +89 -0
- package/dist/chunk-7CHKD5IP.js +38 -0
- package/dist/chunk-7G52QPUX.js +271 -0
- package/dist/chunk-7GTKCVVG.js +735 -0
- package/dist/chunk-7K4YVOAK.js +76 -0
- package/dist/chunk-7LOYIUOF.js +456 -0
- package/dist/chunk-7M5ZHD4E.js +214 -0
- package/dist/chunk-7XUJF3LZ.js +284 -0
- package/dist/chunk-A3GC762G.js +333 -0
- package/dist/chunk-ALTFDYI6.js +97 -0
- package/dist/chunk-AN25OIRX.js +38 -0
- package/dist/chunk-AOWC2J6S.js +14225 -0
- package/dist/chunk-AVTDW4L6.js +562 -0
- package/dist/chunk-BEQTE7GH.js +668 -0
- package/dist/chunk-BJTBA4XS.js +290 -0
- package/dist/chunk-BJYLTU2G.js +621 -0
- package/dist/chunk-BQBPNRUW.js +231 -0
- package/dist/chunk-BQD4XYWX.js +159 -0
- package/dist/chunk-BR2OA4AZ.js +123 -0
- package/dist/chunk-BTP3LPMP.js +210 -0
- package/dist/chunk-BVFCZNJH.js +41 -0
- package/dist/chunk-BW7HTZMW.js +240 -0
- package/dist/chunk-BYOEIN37.js +176 -0
- package/dist/chunk-BZP3ZSRI.js +97 -0
- package/dist/chunk-C2NCSKRZ.js +373 -0
- package/dist/chunk-C3AH5JAS.js +510 -0
- package/dist/chunk-CEKZ77KA.js +471 -0
- package/dist/chunk-CMDKYYFK.js +630 -0
- package/dist/chunk-CNTBRVYW.js +54 -0
- package/dist/chunk-CTJQX44O.js +271 -0
- package/dist/chunk-CVG2PBCO.js +1105 -0
- package/dist/chunk-CZ47BFAT.js +299 -0
- package/dist/chunk-CZHC3HIO.js +362 -0
- package/dist/chunk-D6LUKYKM.js +731 -0
- package/dist/chunk-DFSI6HFJ.js +2078 -0
- package/dist/chunk-DIZOFRZO.js +284 -0
- package/dist/chunk-DJLDKRXK.js +30 -0
- package/dist/chunk-DRX46W5O.js +1068 -0
- package/dist/chunk-DYICAAAM.js +630 -0
- package/dist/chunk-E4BXNYLD.js +128 -0
- package/dist/chunk-EESAZNRC.js +348 -0
- package/dist/chunk-EKXOBH7F.js +227 -0
- package/dist/chunk-ELQZYKVN.js +394 -0
- package/dist/chunk-EQY6GDVD.js +369 -0
- package/dist/chunk-EVM22AGQ.js +382 -0
- package/dist/chunk-EY7TBDZ5.js +38 -0
- package/dist/chunk-EYLU6MJT.js +192 -0
- package/dist/chunk-F23GFLKY.js +4318 -0
- package/dist/chunk-F5SADWWW.js +240 -0
- package/dist/chunk-FDOEMBUB.js +345 -0
- package/dist/chunk-FE6HKM2N.js +157 -0
- package/dist/chunk-FG2OXKU5.js +539 -0
- package/dist/chunk-FP6TDXIL.js +456 -0
- package/dist/chunk-FTG36JG5.js +280 -0
- package/dist/chunk-FVWATWI2.js +377 -0
- package/dist/chunk-FZDW76SH.js +89 -0
- package/dist/chunk-G2OW4LUS.js +55 -0
- package/dist/chunk-G6GC2YSP.js +262 -0
- package/dist/chunk-GAYD7KBH.js +836 -0
- package/dist/chunk-GETGWHCO.js +227 -0
- package/dist/chunk-GGLUKNFC.js +1350 -0
- package/dist/chunk-GLEE2MUJ.js +262 -0
- package/dist/chunk-GUODMEAR.js +42 -0
- package/dist/chunk-H6LA4UV5.js +735 -0
- package/dist/chunk-H6PW4LNY.js +129 -0
- package/dist/chunk-HEMJ5RDU.js +345 -0
- package/dist/chunk-HH2JVSKL.js +1157 -0
- package/dist/chunk-HJQQ7746.js +185 -0
- package/dist/chunk-HLFNLJSB.js +271 -0
- package/dist/chunk-HMP6KB4V.js +382 -0
- package/dist/chunk-HX735WX7.js +33 -0
- package/dist/chunk-I35KAK3E.js +458 -0
- package/dist/chunk-I4DA5D5Q.js +1922 -0
- package/dist/chunk-I53O26HI.js +1119 -0
- package/dist/chunk-IBLEQQDQ.js +181 -0
- package/dist/chunk-IS2BEXUC.js +2113 -0
- package/dist/chunk-ISCEGQHA.js +244 -0
- package/dist/chunk-IUQBMSBI.js +1350 -0
- package/dist/chunk-J6PDP2GY.js +221 -0
- package/dist/chunk-JCERHH3L.js +85 -0
- package/dist/chunk-JCNCPBWU.js +97 -0
- package/dist/chunk-JEMLH7H2.js +1350 -0
- package/dist/chunk-JGOGSH55.js +14378 -0
- package/dist/chunk-JMR2X5FJ.js +630 -0
- package/dist/chunk-JR3MYBWG.js +2078 -0
- package/dist/chunk-JRZ47IFL.js +82 -0
- package/dist/chunk-JSEICUAL.js +197 -0
- package/dist/chunk-JZEROVAU.js +546 -0
- package/dist/chunk-K3KOLZTH.js +123 -0
- package/dist/chunk-K4OH3B2I.js +14248 -0
- package/dist/chunk-KFHAVF6J.js +97 -0
- package/dist/chunk-KJALZ6F6.js +128 -0
- package/dist/chunk-KMAIBYV3.js +402 -0
- package/dist/chunk-KMTNAXIB.js +54 -0
- package/dist/chunk-KQ4Z2G24.js +260 -0
- package/dist/chunk-KVH5DSTA.js +369 -0
- package/dist/chunk-L4R5NOVT.js +81 -0
- package/dist/chunk-LCB6YCE6.js +70 -0
- package/dist/chunk-LHW7TZGJ.js +244 -0
- package/dist/chunk-LIH36DXG.js +159 -0
- package/dist/chunk-M3VHV2RV.js +106 -0
- package/dist/chunk-M543SLJZ.js +1352 -0
- package/dist/chunk-M6KDMU5P.js +2113 -0
- package/dist/chunk-MDAGRPZG.js +197 -0
- package/dist/chunk-MFTGN7KN.js +411 -0
- package/dist/chunk-MLNOSXRZ.js +402 -0
- package/dist/chunk-MNI5K34D.js +290 -0
- package/dist/chunk-MUDH7ZLR.js +129 -0
- package/dist/chunk-MUHKJCF7.js +128 -0
- package/dist/chunk-MUMBWV57.js +379 -0
- package/dist/chunk-NAQLGLOG.js +176 -0
- package/dist/chunk-NIBCUAEI.js +123 -0
- package/dist/chunk-NIZCTXYW.js +89 -0
- package/dist/chunk-NS5G36TN.js +712 -0
- package/dist/chunk-NSKQWLQL.js +76 -0
- package/dist/chunk-NUA3WRTO.js +1157 -0
- package/dist/chunk-NV5SSKZE.js +171 -0
- package/dist/chunk-NXJ2CP2C.js +290 -0
- package/dist/chunk-O3IESEF6.js +85 -0
- package/dist/chunk-OAO2BK25.js +81 -0
- package/dist/chunk-OFY7RGLL.js +348 -0
- package/dist/chunk-OICU3UHF.js +181 -0
- package/dist/chunk-OK6HCC2Z.js +731 -0
- package/dist/chunk-ONTUBOYP.js +230 -0
- package/dist/chunk-OQB7TERT.js +54 -0
- package/dist/chunk-OXUHCIGV.js +1352 -0
- package/dist/chunk-P362EYLO.js +106 -0
- package/dist/chunk-P4T4JOCE.js +192 -0
- package/dist/chunk-PNQDP3OA.js +800 -0
- package/dist/chunk-PYTSVZWG.js +377 -0
- package/dist/chunk-Q2R3WUW4.js +448 -0
- package/dist/chunk-QAOWXQKA.js +333 -0
- package/dist/chunk-QEFT6G6J.js +2078 -0
- package/dist/chunk-QFGJERAP.js +1119 -0
- package/dist/chunk-QFVY5MHR.js +402 -0
- package/dist/chunk-QLMSROQC.js +604 -0
- package/dist/chunk-QNR4ZQDU.js +14365 -0
- package/dist/chunk-QO7M774X.js +1094 -0
- package/dist/chunk-QODXLGH2.js +70 -0
- package/dist/chunk-QQ3T45AO.js +348 -0
- package/dist/chunk-QV6HNEMH.js +230 -0
- package/dist/chunk-R5LCP56X.js +299 -0
- package/dist/chunk-RHC57KVT.js +85 -0
- package/dist/chunk-RHE7SHZJ.js +345 -0
- package/dist/chunk-RHTZA6X6.js +1922 -0
- package/dist/chunk-RJY45A5J.js +133 -0
- package/dist/chunk-RL4RQIEI.js +731 -0
- package/dist/chunk-RVOPNDGY.js +150 -0
- package/dist/chunk-RW4EMKQF.js +185 -0
- package/dist/chunk-S35K4C6F.js +127 -0
- package/dist/chunk-S3QEHFGE.js +373 -0
- package/dist/chunk-SCQEAMO3.js +299 -0
- package/dist/chunk-SFQYQH5Z.js +50 -0
- package/dist/chunk-SLFB2RY6.js +133 -0
- package/dist/chunk-SSC7EKY2.js +133 -0
- package/dist/chunk-SWFFGWAF.js +262 -0
- package/dist/chunk-SXZCFZ5T.js +157 -0
- package/dist/chunk-SYOGNG2R.js +379 -0
- package/dist/chunk-T5LT62O5.js +14365 -0
- package/dist/chunk-TDGPZF5T.js +539 -0
- package/dist/chunk-TEOJ63HX.js +362 -0
- package/dist/chunk-TF6DEHEL.js +167 -0
- package/dist/chunk-TH7ZNVGB.js +33 -0
- package/dist/chunk-TMV5LCTC.js +167 -0
- package/dist/chunk-TO5ZXGDF.js +190 -0
- package/dist/chunk-TTNYB6OH.js +33 -0
- package/dist/chunk-TUHR7Z7R.js +221 -0
- package/dist/chunk-U5RKF7MQ.js +836 -0
- package/dist/chunk-UDMFABWN.js +510 -0
- package/dist/chunk-UHKXYDBM.js +668 -0
- package/dist/chunk-UKS5CXQU.js +382 -0
- package/dist/chunk-UQBD2L52.js +128 -0
- package/dist/chunk-UTARH2WY.js +76 -0
- package/dist/chunk-UXYAQCIB.js +30 -0
- package/dist/chunk-UZHCPLB2.js +127 -0
- package/dist/chunk-V2OOLS63.js +41 -0
- package/dist/chunk-VBAY3OA7.js +604 -0
- package/dist/chunk-VK4KORCQ.js +204 -0
- package/dist/chunk-VNJKA3K5.js +171 -0
- package/dist/chunk-VP4MDSUA.js +1156 -0
- package/dist/chunk-VWA7OCXI.js +58 -0
- package/dist/chunk-VWZZF3YB.js +70 -0
- package/dist/chunk-VYPKS352.js +214 -0
- package/dist/chunk-W6JB72KR.js +448 -0
- package/dist/chunk-WG4PSSI5.js +510 -0
- package/dist/chunk-WJPZPASS.js +373 -0
- package/dist/chunk-WLDBPKRL.js +3246 -0
- package/dist/chunk-WO2SPDUE.js +231 -0
- package/dist/chunk-WXEPPHDU.js +1094 -0
- package/dist/chunk-WXNSOT6K.js +82 -0
- package/dist/chunk-X2PSVVHB.js +448 -0
- package/dist/chunk-X5Y4JSD4.js +128 -0
- package/dist/chunk-X7VPB6Z5.js +621 -0
- package/dist/chunk-XA2GMH53.js +85 -0
- package/dist/chunk-XC2ZMYDN.js +204 -0
- package/dist/chunk-XFQJH67J.js +157 -0
- package/dist/chunk-XQ5LT6UM.js +362 -0
- package/dist/chunk-XRMBKPIP.js +204 -0
- package/dist/chunk-XUC7YYW5.js +171 -0
- package/dist/chunk-XVDWHYIK.js +3276 -0
- package/dist/chunk-Y4ZA4GCQ.js +85 -0
- package/dist/chunk-Y6CVAZ7T.js +97 -0
- package/dist/chunk-YA7WVZF5.js +377 -0
- package/dist/chunk-YACAOZVG.js +185 -0
- package/dist/chunk-YEHV3FN5.js +836 -0
- package/dist/chunk-YMMYZXVZ.js +55 -0
- package/dist/chunk-YMZ6IGC3.js +284 -0
- package/dist/chunk-Z5P7AUFM.js +280 -0
- package/dist/chunk-Z5RXZRUC.js +227 -0
- package/dist/chunk-Z5YFGOLZ.js +1068 -0
- package/dist/chunk-ZLYKY6GP.js +150 -0
- package/dist/chunk-ZOP7NAM2.js +58 -0
- package/dist/chunk-ZPILUBWK.js +2142 -0
- package/dist/chunk-ZUNYZYKV.js +1157 -0
- package/dist/co-activation-54LO5GAA.js +73 -0
- package/dist/co-activation-ESPLEOMH.js +73 -0
- package/dist/co-activation-WCLF766F.js +73 -0
- package/dist/co-occurrence-52ZTRX2I.js +94 -0
- package/dist/co-occurrence-LPHW6UTZ.js +94 -0
- package/dist/co-occurrence-O4G6VQUU.js +94 -0
- package/dist/code-context-index-OX3LN34G.js +30 -0
- package/dist/code-context-index-QR5PAXM4.js +30 -0
- package/dist/conversation-wiki-populator-IMHNWKEU.js +105 -0
- package/dist/conversation-wiki-populator-IWSKIHQK.js +105 -0
- package/dist/core-memory-3LSCC75D.js +110 -0
- package/dist/core-memory-J6AEOYFN.js +110 -0
- package/dist/core-memory-XF4CLLDR.js +110 -0
- package/dist/cpu-steal-5YKTUPWF.js +23 -0
- package/dist/crdt-sync-5JOW6T2I.js +33 -0
- package/dist/crdt-sync-6L4OI4OA.js +33 -0
- package/dist/crdt-sync-UQ3PXFRB.js +33 -0
- package/dist/crm-webhook-BAXEYDPD.js +10 -0
- package/dist/crm-webhook-KVBGOUHU.js +10 -0
- package/dist/crm-webhook-VONTDB3M.js +10 -0
- package/dist/cto-delegation-gate-3WUTWBCT.js +279 -0
- package/dist/cto-delegation-gate-B7AKO7FX.js +279 -0
- package/dist/cto-delegation-gate-DZF3Z66I.js +279 -0
- package/dist/daemon-auth-55T2DI6G.js +13 -0
- package/dist/daemon-auth-M2G5PBME.js +13 -0
- package/dist/daemon-orchestration-3ANZVE7Y.js +138 -0
- package/dist/daemon-orchestration-APVUUNFB.js +138 -0
- package/dist/daemon-orchestration-ZBDBRKVR.js +138 -0
- package/dist/daemon-restart-report-F3P5AQS4.js +9 -0
- package/dist/db-backup-J7253HNV.js +33 -0
- package/dist/db-backup-LPCCZYIL.js +33 -0
- package/dist/db-backup-M733ORYE.js +33 -0
- package/dist/db-restore-events-AIL6GSEK.js +76 -0
- package/dist/db-restore-events-LB3O46HH.js +76 -0
- package/dist/db-restore-events-QF3KCGVZ.js +76 -0
- package/dist/doc-graph-extractor-CF2WBSGL.js +132 -0
- package/dist/doc-graph-extractor-IOSZSDDW.js +132 -0
- package/dist/doc-graph-extractor-RSYHLOKD.js +132 -0
- package/dist/dreaming-KA3SN53N.js +33 -0
- package/dist/dreaming-L4FLJJO2.js +33 -0
- package/dist/dreaming-YKEKUE55.js +33 -0
- package/dist/entity-boost-YFIFLE6N.js +375 -0
- package/dist/entity-boost-ZKACOJKH.js +375 -0
- package/dist/exe-drift-AVJRXHCB.js +69 -0
- package/dist/exe-drift-CLJ74KCO.js +69 -0
- package/dist/exe-drift-MYT5NQ52.js +69 -0
- package/dist/exe-export-QF5V54XC.js +75 -0
- package/dist/exe-export-T2FHC5GC.js +75 -0
- package/dist/exe-export-TBV2JI4P.js +75 -0
- package/dist/exe-import-6UAKJF3Y.js +78 -0
- package/dist/exe-import-KJQO4PJX.js +78 -0
- package/dist/exe-import-M4VYXCJZ.js +78 -0
- package/dist/exe-key-7PDQ72W2.js +580 -0
- package/dist/exe-key-KGQUC27D.js +580 -0
- package/dist/exe-key-Q772PMBM.js +580 -0
- package/dist/exe-org-KK22SSB3.js +73 -0
- package/dist/exe-org-VAUMR7TL.js +73 -0
- package/dist/exe-snapshot-KF3HPOWJ.js +337 -0
- package/dist/exe-snapshot-SK6PMOFA.js +337 -0
- package/dist/exe-snapshot-W5IVP6VF.js +337 -0
- package/dist/fast-db-init-EXNYB2HK.js +7 -0
- package/dist/fast-db-init-FMECTLNS.js +7 -0
- package/dist/fast-db-init-MZOQZ2BW.js +7 -0
- package/dist/founder-context-N2VZ5MY2.js +96 -0
- package/dist/founder-context-QGKRISJH.js +96 -0
- package/dist/gateway/index.js +13 -13
- package/dist/git-staleness-2EOHIOMZ.js +111 -0
- package/dist/git-staleness-U7ADZARV.js +111 -0
- package/dist/git-staleness-ZEYJXPFP.js +111 -0
- package/dist/git-task-sweep-I74JXGNT.js +41 -0
- package/dist/git-task-sweep-T27IFHBH.js +41 -0
- package/dist/git-task-sweep-YKLOPYYV.js +41 -0
- package/dist/global-procedures-B23F4IQ3.js +21 -0
- package/dist/global-procedures-LUBLZ6WN.js +21 -0
- package/dist/global-procedures-VJUQAYZ5.js +21 -0
- package/dist/graph-auto-extract-CSLZXRDY.js +182 -0
- package/dist/graph-auto-extract-DZRIETGW.js +182 -0
- package/dist/graph-auto-extract-ZTZ44VKT.js +182 -0
- package/dist/hook-integrity-HJBXTLQD.js +89 -0
- package/dist/hook-integrity-YPMNLP7B.js +89 -0
- package/dist/hooks/bug-report-worker.js +16 -16
- package/dist/hooks/codex-stop-task-finalizer.js +16 -16
- package/dist/hooks/commit-complete.js +17 -17
- package/dist/hooks/error-recall.js +9 -9
- package/dist/hooks/exe-heartbeat-hook.js +6 -6
- package/dist/hooks/ingest-worker.js +5 -5
- package/dist/hooks/ingest.js +13 -13
- package/dist/hooks/instructions-loaded.js +7 -7
- package/dist/hooks/manifest.json +20 -20
- package/dist/hooks/notification.js +7 -7
- package/dist/hooks/post-compact.js +16 -16
- package/dist/hooks/post-tool-combined.js +7 -7
- package/dist/hooks/pre-compact.js +21 -21
- package/dist/hooks/pre-tool-use.js +20 -20
- package/dist/hooks/prompt-submit.js +28 -28
- package/dist/hooks/session-end.js +26 -26
- package/dist/hooks/session-start.js +47 -17
- package/dist/hooks/stop.js +23 -23
- package/dist/hooks/subagent-stop.js +16 -16
- package/dist/hooks/summary-worker.js +23 -23
- package/dist/index.js +24 -24
- package/dist/installer-2MDIUMZS.js +343 -0
- package/dist/installer-AU5VMP4U.js +39 -0
- package/dist/installer-DS7H47GB.js +297 -0
- package/dist/installer-H7BIYSIK.js +39 -0
- package/dist/installer-JSUC44TR.js +39 -0
- package/dist/installer-L4NJWZGV.js +297 -0
- package/dist/installer-QE3LBMVF.js +343 -0
- package/dist/installer-QH75OOGL.js +297 -0
- package/dist/installer-XREYYGF2.js +343 -0
- package/dist/key-backup-status-IJCQT4NV.js +39 -0
- package/dist/key-backup-status-X5CBECJ3.js +39 -0
- package/dist/lib/agent-config.js +2 -2
- package/dist/lib/cloud-sync.js +7 -7
- package/dist/lib/config.js +13 -3
- package/dist/lib/consolidation.js +9 -9
- package/dist/lib/database.js +4 -4
- package/dist/lib/db-daemon-client.js +3 -3
- package/dist/lib/db.js +4 -4
- package/dist/lib/device-registry.js +1 -1
- package/dist/lib/embed-worker.js +18 -7
- package/dist/lib/embedder.js +4 -4
- package/dist/lib/employee-templates.js +6 -6
- package/dist/lib/employees.js +4 -4
- package/dist/lib/exe-daemon-client.js +3 -3
- package/dist/lib/exe-daemon.js +140 -63
- package/dist/lib/hybrid-search.js +7 -7
- package/dist/lib/identity-templates.js +1 -1
- package/dist/lib/identity.js +4 -4
- package/dist/lib/license.js +2 -2
- package/dist/lib/messaging.js +14 -14
- package/dist/lib/reminders.js +5 -5
- package/dist/lib/schedules.js +7 -7
- package/dist/lib/session-registry.js +6 -6
- package/dist/lib/skill-learning.js +8 -8
- package/dist/lib/status-brief.js +1 -1
- package/dist/lib/store.js +6 -6
- package/dist/lib/task-router.js +5 -5
- package/dist/lib/tasks.js +15 -15
- package/dist/lib/tmux-routing.js +13 -13
- package/dist/lib/token-spend.js +5 -5
- package/dist/lib/ws-client.js +5 -0
- package/dist/license-gate-R5EZ7HD3.js +14 -0
- package/dist/license-gate-X57APN2E.js +14 -0
- package/dist/mcp/register-tools.js +72 -70
- package/dist/mcp/server.js +74 -72
- package/dist/mcp/tools/complete-reminder.js +6 -6
- package/dist/mcp/tools/create-reminder.js +6 -6
- package/dist/mcp/tools/create-task.js +17 -17
- package/dist/mcp/tools/deactivate-behavior.js +9 -9
- package/dist/mcp/tools/list-reminders.js +6 -6
- package/dist/mcp/tools/list-tasks.js +17 -17
- package/dist/mcp/tools/send-message.js +16 -16
- package/dist/mcp/tools/update-task.js +16 -16
- package/dist/mcp-http-config-DV6S22TF.js +28 -0
- package/dist/mcp-http-config-KMP55RXI.js +28 -0
- package/dist/mcp-http-config-XYHPQVRA.js +28 -0
- package/dist/memory-cards-AULW7ITU.js +179 -0
- package/dist/memory-cards-AUWC6FN6.js +179 -0
- package/dist/memory-cards-NLTRIBSD.js +179 -0
- package/dist/memory-graph-extractor-7OWSK2ON.js +21 -0
- package/dist/memory-graph-extractor-NGJQIKAA.js +21 -0
- package/dist/memory-graph-extractor-QWFPKSX5.js +21 -0
- package/dist/memory-poisoning-defense-5WWOLHUQ.js +223 -0
- package/dist/memory-poisoning-defense-742X4H52.js +223 -0
- package/dist/memory-poisoning-defense-TLVXFY43.js +223 -0
- package/dist/memory-queue-4QU434ZH.js +19 -0
- package/dist/memory-queue-OXHHNDOC.js +19 -0
- package/dist/memory-queue-client-6KTL3U3I.js +16 -0
- package/dist/memory-queue-client-P4TZNVQB.js +16 -0
- package/dist/memory-reflection-6GF5OK2W.js +243 -0
- package/dist/memory-reflection-C52FI4W2.js +243 -0
- package/dist/memory-reflection-SGIE7OJ7.js +243 -0
- package/dist/message-queue-client-DFXF7LJD.js +92 -0
- package/dist/message-queue-client-ELWCWKBO.js +92 -0
- package/dist/notifications-67M5SPLO.js +46 -0
- package/dist/notifications-HUH2H5WZ.js +46 -0
- package/dist/notifications-U3NJYMXX.js +46 -0
- package/dist/oauth-server-NR3XEPA4.js +437 -0
- package/dist/oauth-server-RKCMPBIP.js +437 -0
- package/dist/orchestration-events-MC3IZ46I.js +26 -0
- package/dist/orchestration-events-NZCUTMCJ.js +26 -0
- package/dist/orchestration-events-TKODYRYP.js +26 -0
- package/dist/orchestration-phase-FPAVQ57X.js +23 -0
- package/dist/orchestration-phase-UCTFU32J.js +23 -0
- package/dist/orchestrator-3MJ6YJKT.js +34 -0
- package/dist/orchestrator-GNI5PCA6.js +34 -0
- package/dist/orchestrator-HOXFT4PP.js +34 -0
- package/dist/pipeline-router-NCUDK335.js +14 -0
- package/dist/pipeline-router-P2QAQHUY.js +14 -0
- package/dist/pipeline-router-POLBFEBM.js +14 -0
- package/dist/plan-limits-DGAFE7V6.js +27 -0
- package/dist/plan-limits-J4WXJVDS.js +27 -0
- package/dist/plan-limits-UDKZ2O7W.js +27 -0
- package/dist/project-boot-5R3GLCVN.js +299 -0
- package/dist/project-boot-FRCQHQTF.js +299 -0
- package/dist/project-boot-QHXOUJGT.js +299 -0
- package/dist/projection-worker-7EWWMJHG.js +1034 -0
- package/dist/projection-worker-QZW4DOY3.js +1034 -0
- package/dist/projection-worker-XDKC3GIZ.js +1034 -0
- package/dist/prospective-memory-7B65EHWB.js +231 -0
- package/dist/prospective-memory-JIGVZM2I.js +231 -0
- package/dist/push-notifications-ERC4SQSQ.js +15 -0
- package/dist/push-notifications-X7E7GSC7.js +15 -0
- package/dist/reranker-EUG4XM44.js +19 -0
- package/dist/reranker-SF3LMYGY.js +19 -0
- package/dist/reranker-SOM2WMD6.js +19 -0
- package/dist/retrieval-health-7FRD2KLM.js +11 -0
- package/dist/retrieval-health-P6QHP263.js +11 -0
- package/dist/retrieval-health-WLNAPJCX.js +11 -0
- package/dist/review-polling-66EJAMR3.js +125 -0
- package/dist/review-polling-SYKYNFRK.js +125 -0
- package/dist/review-polling-WHPJUENR.js +125 -0
- package/dist/runtime/index.js +20 -20
- package/dist/session-events-A6EDTM27.js +37 -0
- package/dist/session-events-DONPZ7DR.js +37 -0
- package/dist/session-events-WMK6FCKZ.js +37 -0
- package/dist/session-kill-telemetry-2BU72YXD.js +30 -0
- package/dist/session-kill-telemetry-NV2S2YZ2.js +30 -0
- package/dist/session-kill-telemetry-Y47QAFHP.js +30 -0
- package/dist/session-scope-H3FJVQ6E.js +87 -0
- package/dist/session-scope-I56DVQEY.js +87 -0
- package/dist/session-scope-RYBNHQ43.js +87 -0
- package/dist/setup-wizard-MX3S3DVH.js +12 -0
- package/dist/setup-wizard-NID5EPDN.js +12 -0
- package/dist/setup-wizard-YRBCVPCU.js +12 -0
- package/dist/shard-manager-AX4W5B3N.js +30 -0
- package/dist/shard-manager-F3YYEG5S.js +30 -0
- package/dist/skill-refinement-57DCIDKT.js +158 -0
- package/dist/skill-refinement-KRMGOT5M.js +158 -0
- package/dist/skill-refinement-XTBCHOMO.js +158 -0
- package/dist/stack-update-3LZQWW3G.js +80 -0
- package/dist/stack-update-CZ2QHS6T.js +76 -0
- package/dist/stack-update-XNEO4WQH.js +76 -0
- package/dist/steward-gate-J7VMPHEN.js +14 -0
- package/dist/steward-gate-KC4NOULU.js +14 -0
- package/dist/steward-gate-PVUKWYED.js +14 -0
- package/dist/task-enforcement-AI433TPY.js +439 -0
- package/dist/task-enforcement-G4MYUJ2E.js +439 -0
- package/dist/task-enforcement-QBF44BXN.js +439 -0
- package/dist/task-scope-D2VOYU3P.js +36 -0
- package/dist/task-scope-HGL6VACL.js +36 -0
- package/dist/task-scope-XRH4KDJB.js +36 -0
- package/dist/tasks-crud-2KYGDJG2.js +78 -0
- package/dist/tasks-crud-DFE4XOW7.js +78 -0
- package/dist/tasks-crud-J5TSLFQN.js +78 -0
- package/dist/tasks-notify-2VRKOK74.js +39 -0
- package/dist/tasks-notify-AJSRQHLZ.js +39 -0
- package/dist/tasks-notify-Q23MIKDA.js +39 -0
- package/dist/tasks-review-ISSCHGTG.js +48 -0
- package/dist/tasks-review-NRSVHN7V.js +48 -0
- package/dist/tasks-review-VV3RLPLT.js +48 -0
- package/dist/telemetry-upload-ISI6TEX4.js +740 -0
- package/dist/telemetry-upload-VZ3A6EPD.js +740 -0
- package/dist/telemetry-upload-XML6WVPW.js +740 -0
- package/dist/token-budget-KVRHMY7V.js +85 -0
- package/dist/token-budget-SIXJ7ED5.js +85 -0
- package/dist/token-budget-WV2GIFYJ.js +85 -0
- package/dist/tool-capability-index-NOMFY27N.js +10 -0
- package/dist/tool-capability-index-TK5K76RB.js +10 -0
- package/dist/tool-telemetry-6DGIQUV3.js +17 -0
- package/dist/tool-telemetry-NTFTPF3L.js +17 -0
- package/dist/tool-telemetry-NXPM2T5E.js +17 -0
- package/dist/tui/App.js +81 -39
- package/dist/tui-data-2LNENF36.js +259 -0
- package/dist/tui-data-C4474APN.js +259 -0
- package/dist/tui-data-KP66NOW3.js +259 -0
- package/dist/webhook-pipe-VQMOLXMW.js +114 -0
- package/dist/webhook-pipe-ZAEPBTDB.js +114 -0
- package/dist/wiki-acl-33D5QTU4.js +111 -0
- package/dist/wiki-acl-4A3ZUPJK.js +111 -0
- package/dist/wiki-acl-DRTEVIHT.js +111 -0
- package/dist/wiki-client-AN52BINX.js +157 -0
- package/dist/wiki-client-XZ6VZTH6.js +157 -0
- package/dist/worker-gate-EVSFKALM.js +21 -0
- package/dist/worker-gate-NCEAKLJE.js +21 -0
- package/dist/worker-gate-O2KXQN5T.js +21 -0
- package/dist/workflow-engine-MUO435MX.js +28 -0
- package/dist/workflow-engine-RV6JLGHQ.js +28 -0
- package/dist/workflow-engine-WFN3HPAZ.js +28 -0
- package/dist/worktree-36S7LYES.js +27 -0
- package/dist/worktree-O66YDTSF.js +27 -0
- package/dist/worktree-WTNPY42O.js +27 -0
- package/dist/worktree-sweep-M2ENRTY6.js +20 -0
- package/dist/worktree-sweep-M5AXCSU7.js +20 -0
- package/dist/worktree-sweep-NKEGKQT3.js +20 -0
- package/package.json +1 -1
- package/release-notes.json +58 -58
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
requestDeployRestart
|
|
4
|
+
} from "./chunk-7L2EV3XX.js";
|
|
5
|
+
import {
|
|
6
|
+
disposeDatabase,
|
|
7
|
+
ensureSchema,
|
|
8
|
+
getClient,
|
|
9
|
+
initDatabase
|
|
10
|
+
} from "./chunk-3X2ZT5FN.js";
|
|
11
|
+
import {
|
|
12
|
+
assertValidDbPath
|
|
13
|
+
} from "./chunk-2I23RPSI.js";
|
|
14
|
+
import "./chunk-SCQEAMO3.js";
|
|
15
|
+
import "./chunk-PNQDP3OA.js";
|
|
16
|
+
import "./chunk-FXU7JOXK.js";
|
|
17
|
+
import {
|
|
18
|
+
exportMnemonic,
|
|
19
|
+
getKeyStorageInfo,
|
|
20
|
+
getMasterKey,
|
|
21
|
+
importMnemonic,
|
|
22
|
+
setMasterKey
|
|
23
|
+
} from "./chunk-Z42MXYWW.js";
|
|
24
|
+
import {
|
|
25
|
+
loadConfig
|
|
26
|
+
} from "./chunk-5P3HOBZX.js";
|
|
27
|
+
import "./chunk-LYH5HE24.js";
|
|
28
|
+
import {
|
|
29
|
+
isMainModule
|
|
30
|
+
} from "./chunk-6Y4B3QF6.js";
|
|
31
|
+
import "./chunk-MLKGABMK.js";
|
|
32
|
+
|
|
33
|
+
// src/bin/exe-key.ts
|
|
34
|
+
import crypto from "crypto";
|
|
35
|
+
import { createInterface } from "readline";
|
|
36
|
+
import { existsSync, statSync, mkdirSync, copyFileSync, renameSync, rmSync, writeFileSync } from "fs";
|
|
37
|
+
import path from "path";
|
|
38
|
+
import os from "os";
|
|
39
|
+
import { execSync } from "child_process";
|
|
40
|
+
import { createClient } from "@libsql/client";
|
|
41
|
+
function isInteractiveTerminal() {
|
|
42
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.CI);
|
|
43
|
+
}
|
|
44
|
+
function shouldRefuseRotationMutation(dryRun, interactive) {
|
|
45
|
+
return !dryRun && !interactive;
|
|
46
|
+
}
|
|
47
|
+
function shouldRefuseTrustedKeyImport(dryRun, interactive) {
|
|
48
|
+
return !dryRun && !interactive;
|
|
49
|
+
}
|
|
50
|
+
function ask(rl, prompt) {
|
|
51
|
+
return new Promise((resolve) => rl.question(prompt, (answer) => resolve(answer.trim())));
|
|
52
|
+
}
|
|
53
|
+
function humanBytes(bytes) {
|
|
54
|
+
const gb = bytes / 1024 ** 3;
|
|
55
|
+
if (gb >= 1) return `${gb.toFixed(1)}GB`;
|
|
56
|
+
return `${(bytes / 1024 ** 2).toFixed(0)}MB`;
|
|
57
|
+
}
|
|
58
|
+
function expandHome(p) {
|
|
59
|
+
return p.replace(/^~(?=$|\/)/, os.homedir());
|
|
60
|
+
}
|
|
61
|
+
function dataDir() {
|
|
62
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
63
|
+
}
|
|
64
|
+
function dbSidecarPaths(dbPath) {
|
|
65
|
+
return [dbPath, `${dbPath}-wal`, `${dbPath}-shm`];
|
|
66
|
+
}
|
|
67
|
+
function daemonStatus() {
|
|
68
|
+
const pidPath = path.join(dataDir(), "exed.pid");
|
|
69
|
+
if (!existsSync(pidPath)) return { pid: null, alive: false };
|
|
70
|
+
const pid = execSync(`cat ${JSON.stringify(pidPath)}`, { encoding: "utf8" }).trim();
|
|
71
|
+
if (!pid) return { pid: null, alive: false };
|
|
72
|
+
try {
|
|
73
|
+
process.kill(Number(pid), 0);
|
|
74
|
+
return { pid, alive: true };
|
|
75
|
+
} catch {
|
|
76
|
+
return { pid, alive: false };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function stopDaemonIfAlive() {
|
|
80
|
+
const daemon = daemonStatus();
|
|
81
|
+
if (!daemon.alive || !daemon.pid) return;
|
|
82
|
+
if (Number(daemon.pid) <= 1) {
|
|
83
|
+
try {
|
|
84
|
+
execSync("docker inspect exed >/dev/null 2>&1 && docker stop exed >/dev/null", { timeout: 3e4 });
|
|
85
|
+
return;
|
|
86
|
+
} catch {
|
|
87
|
+
throw new Error("Refusing to signal PID 1. Stop the exed Docker container manually, then retry.");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const result = requestDeployRestart("key-rotation");
|
|
91
|
+
if (!result.ok) {
|
|
92
|
+
throw new Error(`Daemon stop failed: ${result.skipped}`);
|
|
93
|
+
}
|
|
94
|
+
for (let i = 0; i < 10; i++) {
|
|
95
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
96
|
+
if (!daemonStatus().alive) return;
|
|
97
|
+
}
|
|
98
|
+
throw new Error(`Daemon pid ${daemon.pid} did not stop after orchestrated kill; refusing to rotate`);
|
|
99
|
+
}
|
|
100
|
+
async function keyStatus() {
|
|
101
|
+
const key = await getMasterKey();
|
|
102
|
+
const storage = await getKeyStorageInfo();
|
|
103
|
+
if (!key) {
|
|
104
|
+
console.log("Encryption key: MISSING");
|
|
105
|
+
console.log(`Storage: ${storage.kind} \u2014 ${storage.note}`);
|
|
106
|
+
console.log("DB open: skipped");
|
|
107
|
+
return 1;
|
|
108
|
+
}
|
|
109
|
+
console.log("Encryption key: FOUND");
|
|
110
|
+
console.log(`Storage: ${storage.kind} \u2014 ${storage.note}`);
|
|
111
|
+
console.log(`Key length: ${key.length} bytes`);
|
|
112
|
+
try {
|
|
113
|
+
const config = await loadConfig();
|
|
114
|
+
await initDatabase({ dbPath: config.dbPath, encryptionKey: key.toString("hex") });
|
|
115
|
+
const client = getClient();
|
|
116
|
+
const memories = await client.execute("SELECT COUNT(*) as cnt FROM memories");
|
|
117
|
+
const tasks = await client.execute("SELECT COUNT(*) as cnt FROM tasks");
|
|
118
|
+
console.log(`DB open: OK (${memories.rows[0]?.cnt ?? 0} memories, ${tasks.rows[0]?.cnt ?? 0} tasks)`);
|
|
119
|
+
return 0;
|
|
120
|
+
} catch (err) {
|
|
121
|
+
console.log(`DB open: FAILED (${err instanceof Error ? err.message : String(err)})`);
|
|
122
|
+
return 2;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async function preflight() {
|
|
126
|
+
const key = await getMasterKey();
|
|
127
|
+
if (!key) throw new Error("memory encryption key not found");
|
|
128
|
+
console.log("\u2713 Memory encryption key found");
|
|
129
|
+
const config = await loadConfig();
|
|
130
|
+
assertValidDbPath(config.dbPath, "exe-key preflight");
|
|
131
|
+
const dbPath = expandHome(config.dbPath);
|
|
132
|
+
if (!existsSync(dbPath)) throw new Error(`DB not found at ${dbPath}`);
|
|
133
|
+
const dbSize = statSync(dbPath).size;
|
|
134
|
+
console.log(`\u2713 DB exists: ${dbPath} (${humanBytes(dbSize)})`);
|
|
135
|
+
await initDatabase({ dbPath: config.dbPath, encryptionKey: key.toString("hex") });
|
|
136
|
+
const client = getClient();
|
|
137
|
+
const memories = await client.execute("SELECT COUNT(*) as cnt FROM memories");
|
|
138
|
+
const tasks = await client.execute("SELECT COUNT(*) as cnt FROM tasks");
|
|
139
|
+
const behaviors = await client.execute("SELECT COUNT(*) as cnt FROM behaviors");
|
|
140
|
+
console.log(`\u2713 Current key opens DB: ${memories.rows[0]?.cnt ?? 0} memories, ${tasks.rows[0]?.cnt ?? 0} tasks, ${behaviors.rows[0]?.cnt ?? 0} behaviors`);
|
|
141
|
+
const daemon = daemonStatus();
|
|
142
|
+
console.log(`${daemon.alive ? "\u26A0" : "\u2713"} Daemon: ${daemon.alive ? `running (pid ${daemon.pid}) \u2014 rotation will stop it before mutation` : "not running"}`);
|
|
143
|
+
if (config.cloud?.apiKey) {
|
|
144
|
+
console.log("\u2713 Cloud sync is configured: this wizard will re-upload a clean encrypted cloud backup after rotation.");
|
|
145
|
+
} else {
|
|
146
|
+
console.log("\u2713 Cloud sync not configured");
|
|
147
|
+
}
|
|
148
|
+
const mnemonic = await exportMnemonic(key);
|
|
149
|
+
console.log(`\u2713 Current recovery phrase is available (${mnemonic.split(/\s+/).length} words; not printed)`);
|
|
150
|
+
return { key, dbPath, cloudConfigured: Boolean(config.cloud?.apiKey) };
|
|
151
|
+
}
|
|
152
|
+
function quoteIdent(name) {
|
|
153
|
+
return `"${name.replaceAll('"', '""')}"`;
|
|
154
|
+
}
|
|
155
|
+
async function getTableNames(client) {
|
|
156
|
+
const rs = await client.execute("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name");
|
|
157
|
+
return rs.rows.map((row) => String(row.name)).filter((name) => !name.includes("_fts"));
|
|
158
|
+
}
|
|
159
|
+
async function getColumns(client, table) {
|
|
160
|
+
const rs = await client.execute(`PRAGMA table_info(${quoteIdent(table)})`);
|
|
161
|
+
return rs.rows.map((row) => String(row.name));
|
|
162
|
+
}
|
|
163
|
+
async function copyTable(source, target, table) {
|
|
164
|
+
const sourceCols = await getColumns(source, table);
|
|
165
|
+
let targetCols;
|
|
166
|
+
try {
|
|
167
|
+
targetCols = await getColumns(target, table);
|
|
168
|
+
} catch {
|
|
169
|
+
return 0;
|
|
170
|
+
}
|
|
171
|
+
const targetSet = new Set(targetCols);
|
|
172
|
+
const cols = sourceCols.filter((col) => targetSet.has(col));
|
|
173
|
+
if (cols.length === 0) return 0;
|
|
174
|
+
const countRs = await source.execute(`SELECT COUNT(*) as cnt FROM ${quoteIdent(table)}`);
|
|
175
|
+
const count = Number(countRs.rows[0]?.cnt ?? 0);
|
|
176
|
+
const pageSize = table === "memories" ? 250 : 1e3;
|
|
177
|
+
const colSql = cols.map(quoteIdent).join(", ");
|
|
178
|
+
const placeholders = cols.map(() => "?").join(", ");
|
|
179
|
+
const insertSql = `INSERT OR REPLACE INTO ${quoteIdent(table)} (${colSql}) VALUES (${placeholders})`;
|
|
180
|
+
let offset = 0;
|
|
181
|
+
let copied = 0;
|
|
182
|
+
while (offset < count) {
|
|
183
|
+
const rs = await source.execute({
|
|
184
|
+
sql: `SELECT ${colSql} FROM ${quoteIdent(table)} LIMIT ? OFFSET ?`,
|
|
185
|
+
args: [pageSize, offset]
|
|
186
|
+
});
|
|
187
|
+
const stmts = rs.rows.map((row) => ({
|
|
188
|
+
sql: insertSql,
|
|
189
|
+
args: cols.map((col) => row[col])
|
|
190
|
+
}));
|
|
191
|
+
if (stmts.length > 0) {
|
|
192
|
+
await target.batch(stmts, "write");
|
|
193
|
+
copied += stmts.length;
|
|
194
|
+
}
|
|
195
|
+
offset += rs.rows.length;
|
|
196
|
+
if (rs.rows.length === 0) break;
|
|
197
|
+
if (table === "memories" && copied % 5e3 === 0) {
|
|
198
|
+
console.log(` copying memories: ${copied}/${count}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return copied;
|
|
202
|
+
}
|
|
203
|
+
async function rotateWizard(argv) {
|
|
204
|
+
const dryRun = argv.includes("--dry-run");
|
|
205
|
+
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
206
|
+
console.log(" EXE OS KEY ROTATION WIZARD");
|
|
207
|
+
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
208
|
+
console.log("");
|
|
209
|
+
console.log("\u{1F6A8}\u{1F6A8}\u{1F6A8} DANGER \u2014 KEY ROTATION IS A ONE-WAY SECURITY ACTION \u{1F6A8}\u{1F6A8}\u{1F6A8}");
|
|
210
|
+
console.log("*** READ THIS BEFORE CONTINUING ***");
|
|
211
|
+
console.log("");
|
|
212
|
+
console.log("Running `exe-os key rotate` will:");
|
|
213
|
+
console.log(" 1. Remove the current memory encryption key from active use.");
|
|
214
|
+
console.log(" 2. Create a NEW memory encryption key and a NEW 24-word recovery phrase.");
|
|
215
|
+
console.log(" 3. Re-encrypt your local memory database with the new key.");
|
|
216
|
+
console.log(" 4. Make the old key useless for any NEW data after rotation.");
|
|
217
|
+
console.log(" 5. Automatically re-upload Exe Cloud with the new key after you save the phrase.");
|
|
218
|
+
console.log("");
|
|
219
|
+
console.log("Your old-key encrypted backup is kept for safety, but your active Exe OS memory will use the NEW key.");
|
|
220
|
+
console.log("Do not continue unless you are ready to save the NEW 24-word recovery phrase.");
|
|
221
|
+
console.log("After rotation, this wizard will make cloud sync safe again automatically.");
|
|
222
|
+
console.log("");
|
|
223
|
+
if (shouldRefuseRotationMutation(dryRun, isInteractiveTerminal())) {
|
|
224
|
+
console.error("For safety, key rotation must be run in your local Terminal. To preview without changes, run: exe-os key rotate --dry-run");
|
|
225
|
+
return 1;
|
|
226
|
+
}
|
|
227
|
+
let pf;
|
|
228
|
+
try {
|
|
229
|
+
pf = await preflight();
|
|
230
|
+
} catch (err) {
|
|
231
|
+
console.error(`Preflight failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
232
|
+
return 1;
|
|
233
|
+
}
|
|
234
|
+
if (dryRun) {
|
|
235
|
+
console.log("");
|
|
236
|
+
console.log("Dry run complete. No key, DB, daemon, or cloud state changed.");
|
|
237
|
+
return 0;
|
|
238
|
+
}
|
|
239
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
240
|
+
try {
|
|
241
|
+
console.log("");
|
|
242
|
+
console.log("Before continuing, confirm you understand this creates a NEW 24-word recovery phrase.");
|
|
243
|
+
console.log("You must save the new phrase after rotation. Without it, you can lose access to encrypted memories.");
|
|
244
|
+
const answer = await ask(rl, 'Type exactly "I WANT TO CHANGE MY KEY" to continue: ');
|
|
245
|
+
if (answer !== "I WANT TO CHANGE MY KEY") {
|
|
246
|
+
console.log("Cancelled.");
|
|
247
|
+
return 1;
|
|
248
|
+
}
|
|
249
|
+
} finally {
|
|
250
|
+
rl.close();
|
|
251
|
+
}
|
|
252
|
+
const rotationId = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
253
|
+
const baseDir = path.join(dataDir(), "key-rotation", rotationId);
|
|
254
|
+
mkdirSync(baseDir, { recursive: true, mode: 448 });
|
|
255
|
+
const backupDir = path.join(baseDir, "pre-rotation-encrypted-backup");
|
|
256
|
+
mkdirSync(backupDir, { recursive: true, mode: 448 });
|
|
257
|
+
const newDbPath = path.join(baseDir, "new-memories.db");
|
|
258
|
+
const newKey = crypto.randomBytes(32);
|
|
259
|
+
const newKeyTempPath = path.join(baseDir, "NEW_KEY_DO_NOT_SHARE.base64");
|
|
260
|
+
writeFileSync(newKeyTempPath, `${newKey.toString("base64")}
|
|
261
|
+
`, { mode: 384 });
|
|
262
|
+
console.log(`Rotation workspace: ${baseDir}`);
|
|
263
|
+
console.log("Stopping daemon...");
|
|
264
|
+
await stopDaemonIfAlive();
|
|
265
|
+
console.log("Backing up encrypted DB/WAL/SHM...");
|
|
266
|
+
const dbDir = path.dirname(pf.dbPath);
|
|
267
|
+
for (const name of ["memories.db", "memories.db-wal", "memories.db-shm"]) {
|
|
268
|
+
const src = path.join(dbDir, name);
|
|
269
|
+
if (existsSync(src)) copyFileSync(src, path.join(backupDir, name));
|
|
270
|
+
}
|
|
271
|
+
console.log("Creating fresh encrypted DB with new key...");
|
|
272
|
+
await initDatabase({ dbPath: newDbPath, encryptionKey: newKey.toString("hex") });
|
|
273
|
+
await ensureSchema();
|
|
274
|
+
const target = getClient();
|
|
275
|
+
await target.execute("PRAGMA foreign_keys=OFF");
|
|
276
|
+
assertValidDbPath(pf.dbPath, "exe-key rotate source");
|
|
277
|
+
const source = createClient({ url: `file:${pf.dbPath}`, encryptionKey: pf.key.toString("hex") });
|
|
278
|
+
await source.execute("PRAGMA busy_timeout = 30000");
|
|
279
|
+
const tables = await getTableNames(source);
|
|
280
|
+
const copiedTables = [];
|
|
281
|
+
for (const table of tables) {
|
|
282
|
+
const copied = await copyTable(source, target, table);
|
|
283
|
+
copiedTables.push({ table, count: copied });
|
|
284
|
+
console.log(`\u2713 copied ${table}: ${copied}`);
|
|
285
|
+
}
|
|
286
|
+
const generationId = crypto.randomUUID();
|
|
287
|
+
await target.execute({ sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES (?, ?)", args: ["key_rotation_at", (/* @__PURE__ */ new Date()).toISOString()] });
|
|
288
|
+
await target.execute({ sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES (?, ?)", args: ["key_rotation_generation_id", generationId] });
|
|
289
|
+
await target.execute({ sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES (?, ?)", args: ["cloud_reupload_required", pf.cloudConfigured ? "1" : "0"] });
|
|
290
|
+
await target.execute("DELETE FROM sync_meta WHERE key IN ('last_cloud_pull_version', 'last_cloud_push_version')");
|
|
291
|
+
const verifyMem = await target.execute("SELECT COUNT(*) as cnt FROM memories");
|
|
292
|
+
const verifyTasks = await target.execute("SELECT COUNT(*) as cnt FROM tasks");
|
|
293
|
+
const expectedMemories = Number(verifyMem.rows[0]?.cnt ?? 0);
|
|
294
|
+
const expectedTasks = Number(verifyTasks.rows[0]?.cnt ?? 0);
|
|
295
|
+
console.log(`Verified new DB: ${expectedMemories} memories, ${expectedTasks} tasks`);
|
|
296
|
+
await target.execute("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
297
|
+
try {
|
|
298
|
+
source.close();
|
|
299
|
+
} catch {
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
target.close();
|
|
303
|
+
} catch {
|
|
304
|
+
}
|
|
305
|
+
console.log("Swapping DB files...");
|
|
306
|
+
for (const name of ["memories.db", "memories.db-wal", "memories.db-shm"]) {
|
|
307
|
+
const current = path.join(dbDir, name);
|
|
308
|
+
if (existsSync(current)) renameSync(current, path.join(backupDir, `moved-${name}`));
|
|
309
|
+
}
|
|
310
|
+
copyFileSync(newDbPath, pf.dbPath);
|
|
311
|
+
rmSync(path.join(dbDir, "memories.db-wal"), { force: true });
|
|
312
|
+
rmSync(path.join(dbDir, "memories.db-shm"), { force: true });
|
|
313
|
+
console.log("Installing new key into OS keychain...");
|
|
314
|
+
await setMasterKey(newKey);
|
|
315
|
+
await initDatabase({ dbPath: pf.dbPath, encryptionKey: newKey.toString("hex") });
|
|
316
|
+
const finalClient = getClient();
|
|
317
|
+
const finalMem = await finalClient.execute("SELECT COUNT(*) as cnt FROM memories");
|
|
318
|
+
const finalTasks = await finalClient.execute("SELECT COUNT(*) as cnt FROM tasks");
|
|
319
|
+
const finalMemoryCount = Number(finalMem.rows[0]?.cnt ?? 0);
|
|
320
|
+
const finalTaskCount = Number(finalTasks.rows[0]?.cnt ?? 0);
|
|
321
|
+
if (finalMemoryCount !== expectedMemories || finalTaskCount !== expectedTasks) {
|
|
322
|
+
throw new Error(`Post-swap verification mismatch: expected ${expectedMemories}/${expectedTasks}, got ${finalMemoryCount}/${finalTaskCount}. Backup kept at ${backupDir}`);
|
|
323
|
+
}
|
|
324
|
+
rmSync(newKeyTempPath, { force: true });
|
|
325
|
+
writeFileSync(path.join(baseDir, "rotation-manifest.json"), JSON.stringify({
|
|
326
|
+
rotationId,
|
|
327
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
328
|
+
backupDir,
|
|
329
|
+
generationId,
|
|
330
|
+
cloudReuploadRequired: pf.cloudConfigured,
|
|
331
|
+
finalCounts: { memories: finalMemoryCount, tasks: finalTaskCount },
|
|
332
|
+
copiedTables
|
|
333
|
+
}, null, 2) + "\n", { mode: 384 });
|
|
334
|
+
console.log("Restarting daemon and verifying daemon DB access...");
|
|
335
|
+
try {
|
|
336
|
+
const { connectEmbedDaemon, sendDaemonRequest, isClientConnected, disconnectClient } = await import("./lib/exe-daemon-client.js");
|
|
337
|
+
await connectEmbedDaemon();
|
|
338
|
+
const resp = await sendDaemonRequest({ type: "db-execute", sql: "SELECT COUNT(*) as cnt FROM memories", args: [] });
|
|
339
|
+
if (resp.error) throw new Error(String(resp.error));
|
|
340
|
+
console.log(`\u2713 Daemon connected: ${isClientConnected()} (${resp.db?.rows?.[0]?.cnt ?? "?"} memories)`);
|
|
341
|
+
disconnectClient();
|
|
342
|
+
} catch (err) {
|
|
343
|
+
console.log(`\u26A0 Daemon restart/verify failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
344
|
+
console.log(" You can retry by running any exe-os command that starts the daemon.");
|
|
345
|
+
}
|
|
346
|
+
console.log("");
|
|
347
|
+
console.log("Key rotation complete.");
|
|
348
|
+
console.log(`Backup kept at: ${backupDir}`);
|
|
349
|
+
console.log(`New DB verified: ${finalMemoryCount} memories, ${finalTaskCount} tasks`);
|
|
350
|
+
if (pf.cloudConfigured) {
|
|
351
|
+
console.log("Local key rotation is complete.");
|
|
352
|
+
console.log("Cloud sync is paused until your newly encrypted cloud backup is re-uploaded.");
|
|
353
|
+
console.log("");
|
|
354
|
+
}
|
|
355
|
+
const newRecoveryPhrase = await exportMnemonic(newKey);
|
|
356
|
+
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
357
|
+
console.log(" REQUIRED: SAVE YOUR NEW RECOVERY PHRASE");
|
|
358
|
+
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
359
|
+
console.log("Write these 24 words down now. They will not be uploaded to Exe Cloud.");
|
|
360
|
+
console.log("");
|
|
361
|
+
console.log(newRecoveryPhrase);
|
|
362
|
+
console.log("");
|
|
363
|
+
console.log("If you need to reveal it again later from this trusted local Terminal, run:");
|
|
364
|
+
console.log(" exe-os cloud link --show-full");
|
|
365
|
+
console.log("");
|
|
366
|
+
console.log("Do not continue to cloud re-upload until the NEW phrase is saved.");
|
|
367
|
+
if (pf.cloudConfigured) {
|
|
368
|
+
const rl2 = createInterface({ input: process.stdin, output: process.stdout });
|
|
369
|
+
try {
|
|
370
|
+
const saved = await ask(rl2, 'After saving the 24 words, type exactly "I SAVED MY NEW RECOVERY PHRASE" to continue: ');
|
|
371
|
+
if (saved !== "I SAVED MY NEW RECOVERY PHRASE") {
|
|
372
|
+
console.log("Cloud re-upload skipped. Save the phrase with:");
|
|
373
|
+
console.log(" exe-os cloud link --show-full");
|
|
374
|
+
console.log("Then run:");
|
|
375
|
+
console.log(" exe-os cloud reupload");
|
|
376
|
+
return 0;
|
|
377
|
+
}
|
|
378
|
+
} finally {
|
|
379
|
+
rl2.close();
|
|
380
|
+
}
|
|
381
|
+
console.log("Starting automatic cloud re-upload now...");
|
|
382
|
+
try {
|
|
383
|
+
const { main: runCloud } = await import("./bin/exe-cloud.js");
|
|
384
|
+
const originalArgv = process.argv;
|
|
385
|
+
try {
|
|
386
|
+
process.argv = [process.argv[0], process.argv[1], "reupload", "--local-db-is-source-of-truth"];
|
|
387
|
+
await runCloud();
|
|
388
|
+
} finally {
|
|
389
|
+
process.argv = originalArgv;
|
|
390
|
+
}
|
|
391
|
+
console.log("\u2713 Cloud re-upload finished. Main device rotation is complete.");
|
|
392
|
+
} catch (err) {
|
|
393
|
+
console.log(`\u26A0 Cloud re-upload did not finish: ${err instanceof Error ? err.message : String(err)}`);
|
|
394
|
+
console.log("Your local key rotation succeeded, but normal cloud sync remains blocked.");
|
|
395
|
+
console.log("Retry with the support fallback command:");
|
|
396
|
+
console.log(" exe-os cloud reupload");
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
console.log("");
|
|
400
|
+
console.log("Cleanup guidance:");
|
|
401
|
+
console.log(" 1. Verify the new recovery phrase opens this DB on another local terminal/device.");
|
|
402
|
+
console.log(" 2. Keep the old-key encrypted backup until verification is complete.");
|
|
403
|
+
console.log(` 3. After verification, manually review/remove the sensitive rotation workspace: ${baseDir}`);
|
|
404
|
+
return 0;
|
|
405
|
+
}
|
|
406
|
+
async function acceptRotationWizard(argv) {
|
|
407
|
+
const dryRun = argv.includes("--dry-run");
|
|
408
|
+
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
409
|
+
console.log(" EXE OS TRUSTED NODE KEY ACCEPTANCE");
|
|
410
|
+
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
411
|
+
console.log("");
|
|
412
|
+
console.log("This command is for a trusted VPS/projection worker after another device rotated the Exe OS key.");
|
|
413
|
+
console.log("");
|
|
414
|
+
console.log("It will:");
|
|
415
|
+
console.log(" 1. Keep a local old-key backup first.");
|
|
416
|
+
console.log(" 2. Import the NEW 24-word recovery phrase into this machine's secure key store.");
|
|
417
|
+
console.log(" 3. Stop the local daemon if it is running.");
|
|
418
|
+
console.log(" 4. Move this machine's old local encrypted SQLite DB aside as a backup.");
|
|
419
|
+
console.log(" 5. Create a fresh local SQLite DB encrypted with the NEW key.");
|
|
420
|
+
console.log(" 6. Pull from Exe Cloud to prove the NEW key can decrypt the newly uploaded cloud backup.");
|
|
421
|
+
console.log(" 7. Roll back to the old key/local DB automatically if cloud verification fails.");
|
|
422
|
+
console.log("");
|
|
423
|
+
console.log("It will NOT rotate or re-encrypt local memory. The source of truth after this is Exe Cloud.");
|
|
424
|
+
console.log("Use this only on devices/VPS nodes that are allowed to decrypt memory and project it into exe-db.");
|
|
425
|
+
console.log("");
|
|
426
|
+
if (shouldRefuseTrustedKeyImport(dryRun, isInteractiveTerminal())) {
|
|
427
|
+
console.error("For safety, trusted key acceptance must be run in a local SSH/Tailscale terminal. To preview without changes, run: exe-os key accept-rotation --dry-run");
|
|
428
|
+
return 1;
|
|
429
|
+
}
|
|
430
|
+
const config = await loadConfig();
|
|
431
|
+
assertValidDbPath(config.dbPath, "exe-key accept-rotation");
|
|
432
|
+
const dbPath = expandHome(config.dbPath);
|
|
433
|
+
const existingKey = await getMasterKey();
|
|
434
|
+
const daemon = daemonStatus();
|
|
435
|
+
console.log(`Daemon: ${daemon.alive ? `running (pid ${daemon.pid}) \u2014 will stop before changing key` : "not running"}`);
|
|
436
|
+
console.log(`DB path: ${dbPath}`);
|
|
437
|
+
console.log(`Existing key: ${existingKey ? "present" : "missing"}`);
|
|
438
|
+
console.log(`Cloud config: ${config.cloud?.apiKey ? "present" : "missing"}`);
|
|
439
|
+
if (!config.cloud?.apiKey || !config.cloud?.endpoint) {
|
|
440
|
+
console.error("Cloud config is missing. This command must prove the new key against Exe Cloud, so it cannot continue.");
|
|
441
|
+
console.error("Configure cloud first, or use `exe-os cloud` if this is a new device setup.");
|
|
442
|
+
return 1;
|
|
443
|
+
}
|
|
444
|
+
const existingDbFiles = dbSidecarPaths(dbPath).filter(existsSync);
|
|
445
|
+
if (existingDbFiles.length > 0) {
|
|
446
|
+
console.log(`Existing DB files: ${existingDbFiles.map((p) => path.basename(p)).join(", ")}`);
|
|
447
|
+
} else {
|
|
448
|
+
console.log("Existing DB files: none");
|
|
449
|
+
}
|
|
450
|
+
if (dryRun) {
|
|
451
|
+
console.log("");
|
|
452
|
+
console.log("Dry run complete. No key, DB, daemon, or cloud state changed.");
|
|
453
|
+
return 0;
|
|
454
|
+
}
|
|
455
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
456
|
+
let mnemonic = "";
|
|
457
|
+
try {
|
|
458
|
+
console.log("");
|
|
459
|
+
const trust = await ask(rl, 'Type exactly "I TRUST THIS DEVICE" to continue: ');
|
|
460
|
+
if (trust !== "I TRUST THIS DEVICE") {
|
|
461
|
+
console.log("Cancelled.");
|
|
462
|
+
return 1;
|
|
463
|
+
}
|
|
464
|
+
mnemonic = await ask(rl, "Paste the NEW 24-word recovery phrase: ");
|
|
465
|
+
} finally {
|
|
466
|
+
rl.close();
|
|
467
|
+
}
|
|
468
|
+
let newKey;
|
|
469
|
+
try {
|
|
470
|
+
newKey = await importMnemonic(mnemonic);
|
|
471
|
+
} catch (err) {
|
|
472
|
+
console.error(`Invalid recovery phrase: ${err instanceof Error ? err.message : String(err)}`);
|
|
473
|
+
return 1;
|
|
474
|
+
}
|
|
475
|
+
const acceptId = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
476
|
+
const baseDir = path.join(dataDir(), "key-acceptance", acceptId);
|
|
477
|
+
const backupDir = path.join(baseDir, "pre-acceptance-encrypted-db");
|
|
478
|
+
mkdirSync(backupDir, { recursive: true, mode: 448 });
|
|
479
|
+
if (existingKey) {
|
|
480
|
+
writeFileSync(path.join(baseDir, "OLD_KEY_BACKUP_DELETE_AFTER_VERIFICATION.base64"), `${existingKey.toString("base64")}
|
|
481
|
+
`, { mode: 384 });
|
|
482
|
+
}
|
|
483
|
+
const restoreOldState = async () => {
|
|
484
|
+
await disposeDatabase();
|
|
485
|
+
if (existingKey) await setMasterKey(existingKey);
|
|
486
|
+
for (const file of dbSidecarPaths(dbPath)) {
|
|
487
|
+
rmSync(file, { force: true });
|
|
488
|
+
const backup = path.join(backupDir, path.basename(file));
|
|
489
|
+
if (existsSync(backup)) copyFileSync(backup, file);
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
console.log(`Acceptance workspace: ${baseDir}`);
|
|
493
|
+
console.log("Stopping daemon if needed...");
|
|
494
|
+
await stopDaemonIfAlive();
|
|
495
|
+
await disposeDatabase();
|
|
496
|
+
console.log("Backing up/moving old local DB files...");
|
|
497
|
+
const dbDir = path.dirname(dbPath);
|
|
498
|
+
mkdirSync(dbDir, { recursive: true, mode: 448 });
|
|
499
|
+
for (const file of dbSidecarPaths(dbPath)) {
|
|
500
|
+
if (!existsSync(file)) continue;
|
|
501
|
+
const dest = path.join(backupDir, path.basename(file));
|
|
502
|
+
copyFileSync(file, dest);
|
|
503
|
+
renameSync(file, path.join(backupDir, `moved-${path.basename(file)}`));
|
|
504
|
+
console.log(`\u2713 moved ${path.basename(file)}`);
|
|
505
|
+
}
|
|
506
|
+
console.log("Installing new key into OS keychain...");
|
|
507
|
+
await setMasterKey(newKey);
|
|
508
|
+
console.log("Creating fresh local DB encrypted with accepted key...");
|
|
509
|
+
await initDatabase({ dbPath: config.dbPath, encryptionKey: newKey.toString("hex") });
|
|
510
|
+
await ensureSchema();
|
|
511
|
+
await disposeDatabase();
|
|
512
|
+
console.log("Verifying NEW key against Exe Cloud by pulling synced data...");
|
|
513
|
+
try {
|
|
514
|
+
const { initSyncCrypto } = await import("./lib/crypto.js");
|
|
515
|
+
const { cloudSync } = await import("./lib/cloud-sync.js");
|
|
516
|
+
const { initStore, disposeStore } = await import("./lib/store.js");
|
|
517
|
+
initSyncCrypto(newKey);
|
|
518
|
+
await initStore({ lightweight: true });
|
|
519
|
+
const result = await cloudSync({ apiKey: config.cloud.apiKey, endpoint: config.cloud.endpoint });
|
|
520
|
+
await disposeStore();
|
|
521
|
+
console.log(`\u2713 Cloud verification succeeded: ${result.totalMemories.toLocaleString()} memories visible after sync`);
|
|
522
|
+
} catch (err) {
|
|
523
|
+
console.error(`Cloud verification failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
524
|
+
console.error("Rolling back to the old key/local DB backup...");
|
|
525
|
+
await restoreOldState();
|
|
526
|
+
console.error("Rollback complete. The old key remains active on this machine.");
|
|
527
|
+
return 1;
|
|
528
|
+
}
|
|
529
|
+
writeFileSync(path.join(baseDir, "acceptance-manifest.json"), JSON.stringify({
|
|
530
|
+
acceptedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
531
|
+
dbPath,
|
|
532
|
+
backupDir,
|
|
533
|
+
cloudConfigured: Boolean(config.cloud?.apiKey)
|
|
534
|
+
}, null, 2) + "\n", { mode: 384 });
|
|
535
|
+
console.log("");
|
|
536
|
+
console.log("Trusted node key acceptance complete.");
|
|
537
|
+
console.log(`Old local DB backup: ${backupDir}`);
|
|
538
|
+
if (existingKey) console.log(`Old key backup kept at: ${path.join(baseDir, "OLD_KEY_BACKUP_DELETE_AFTER_VERIFICATION.base64")}`);
|
|
539
|
+
console.log("");
|
|
540
|
+
console.log("Next steps on this VPS/trusted node:");
|
|
541
|
+
console.log(" 1. Restart daemon/projection worker:");
|
|
542
|
+
console.log(" sudo systemctl restart exed");
|
|
543
|
+
console.log(" 2. Verify:");
|
|
544
|
+
console.log(" exe-os key status");
|
|
545
|
+
console.log(" exe-os cloud status");
|
|
546
|
+
console.log(" 3. If needed, pull cloud data now:");
|
|
547
|
+
console.log(" exe-os cloud sync");
|
|
548
|
+
return 0;
|
|
549
|
+
}
|
|
550
|
+
async function main(argv = process.argv.slice(2)) {
|
|
551
|
+
const sub = argv[0];
|
|
552
|
+
let code = 0;
|
|
553
|
+
if (sub === "status") {
|
|
554
|
+
code = await keyStatus();
|
|
555
|
+
} else if (sub === "rotate") {
|
|
556
|
+
code = await rotateWizard(argv.slice(1));
|
|
557
|
+
} else if (sub === "update") {
|
|
558
|
+
code = await acceptRotationWizard(argv.slice(1));
|
|
559
|
+
} else {
|
|
560
|
+
console.error("Usage:");
|
|
561
|
+
console.error(" exe-os key status");
|
|
562
|
+
console.error(" exe-os key rotate --dry-run");
|
|
563
|
+
console.error(" exe-os key rotate");
|
|
564
|
+
console.error(" exe-os key update --dry-run");
|
|
565
|
+
console.error(" exe-os key update");
|
|
566
|
+
code = 1;
|
|
567
|
+
}
|
|
568
|
+
if (code !== 0) process.exitCode = code;
|
|
569
|
+
}
|
|
570
|
+
if (isMainModule(import.meta.url) && process.argv[1]?.includes("exe-key")) {
|
|
571
|
+
main().catch((err) => {
|
|
572
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
573
|
+
process.exit(1);
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
export {
|
|
577
|
+
main,
|
|
578
|
+
shouldRefuseRotationMutation,
|
|
579
|
+
shouldRefuseTrustedKeyImport
|
|
580
|
+
};
|