@askexenow/exe-os 0.9.299 → 0.9.301
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 +1 -1
- package/deploy/compose/.env.example +1 -1
- package/deploy/compose/docker-compose.yml +31 -5
- package/deploy/compose/erp-nginx/nginx.conf +6 -3
- package/deploy/compose/generate-env.ts +1 -1
- package/deploy/compose/observability/otel-collector-config.yaml +10 -1
- package/deploy/compose/setup.sh +1 -1
- package/dist/active-agent-56J56WW5.js +27 -0
- package/dist/active-agent-UNJO6AJ2.js +27 -0
- package/dist/active-agent-VDWK7TES.js +28 -0
- package/dist/active-agent-Y5LSIMVC.js +28 -0
- package/dist/agentic-ontology-MZ4WHFDE.js +25 -0
- package/dist/agentic-ontology-QEV7GI3T.js +25 -0
- package/dist/assets/com.askexe.exed.plist +6 -5
- package/dist/backfill-metadata-IHKI5GXV.js +600 -0
- package/dist/backfill-metadata-RQZ4BN7G.js +600 -0
- package/dist/backfill-metadata-ZU3SZNBD.js +600 -0
- package/dist/behaviors-A3L5CWMK.js +46 -0
- package/dist/behaviors-G4KWGS24.js +46 -0
- package/dist/behaviors-WO67R6C4.js +46 -0
- package/dist/bin/agentic-ontology-backfill.js +5 -5
- package/dist/bin/agentic-reflection-backfill.js +6 -6
- package/dist/bin/agentic-semantic-label.js +5 -5
- package/dist/bin/backfill-conversations.js +6 -6
- package/dist/bin/backfill-responses.js +6 -6
- package/dist/bin/backfill-vectors.js +8 -8
- package/dist/bin/bulk-sync-postgres.js +13 -7
- package/dist/bin/cc-doctor.js +5 -5
- package/dist/bin/cleanup-stale-review-tasks.js +10 -10
- package/dist/bin/cli.js +16 -16
- package/dist/bin/deferred-daemon-restart.js +1 -1
- package/dist/bin/exe-agent-config.js +2 -2
- package/dist/bin/exe-agent.js +10 -10
- package/dist/bin/exe-assign.js +8 -8
- package/dist/bin/exe-boot.js +36 -21
- package/dist/bin/exe-call.js +4 -4
- package/dist/bin/exe-cloud.js +13 -7
- package/dist/bin/exe-dispatch.js +10 -10
- package/dist/bin/exe-doctor.js +2 -2
- package/dist/bin/exe-export-behaviors.js +7 -7
- package/dist/bin/exe-forget.js +6 -6
- package/dist/bin/exe-gateway.js +7 -7
- package/dist/bin/exe-healthcheck.js +5 -5
- package/dist/bin/exe-heartbeat.js +10 -10
- package/dist/bin/exe-kill.js +13 -13
- package/dist/bin/exe-launch-agent.js +29 -19
- package/dist/bin/exe-new-employee.js +6 -6
- package/dist/bin/exe-pending-messages.js +11 -11
- package/dist/bin/exe-pending-notifications.js +10 -10
- package/dist/bin/exe-pending-reviews.js +10 -10
- package/dist/bin/exe-rename.js +4 -4
- package/dist/bin/exe-review.js +12 -12
- package/dist/bin/exe-search.js +5 -5
- package/dist/bin/exe-session-cleanup.js +15 -15
- package/dist/bin/exe-settings.js +13 -7
- package/dist/bin/exe-start-codex.js +11 -11
- package/dist/bin/exe-start-opencode.js +8 -8
- package/dist/bin/exe-status.js +11 -11
- package/dist/bin/exe-team.js +3 -3
- package/dist/bin/exe-watchdog.js +3 -3
- package/dist/bin/git-sweep.js +11 -11
- package/dist/bin/graph-backfill.js +6 -6
- package/dist/bin/graph-export.js +5 -5
- package/dist/bin/import-history.js +9 -9
- package/dist/bin/install-launchd.js +7 -3
- package/dist/bin/install.js +19 -15
- package/dist/bin/intercom-check.js +4 -4
- package/dist/bin/mcp-sessions.js +2 -2
- package/dist/bin/orchestration-metrics.js +4 -4
- package/dist/bin/postgres-agentic-reflection-backfill.js +2 -2
- package/dist/bin/postgres-agentic-semantic-backfill.js +1 -1
- package/dist/bin/pre-publish.js +24 -1
- package/dist/bin/scan-tasks.js +10 -10
- package/dist/bin/setup.js +1 -1
- package/dist/bin/shard-migrate.js +4 -4
- package/dist/bin/stack-update.js +123 -3
- package/dist/bin/vps-health-gate.js +1 -1
- package/dist/capability-cards-VTGDTOZ4.js +89 -0
- package/dist/capability-cards-XAQSL26B.js +89 -0
- package/dist/capacity-monitor-6MQLFFQT.js +51 -0
- package/dist/capacity-monitor-BB3LKJLE.js +51 -0
- package/dist/capacity-monitor-G2MAJPRP.js +51 -0
- package/dist/catchup-brief-BQSL5M5S.js +175 -0
- package/dist/catchup-brief-COALBX6L.js +175 -0
- package/dist/catchup-brief-VBGEJQRS.js +175 -0
- package/dist/cc-binary-detect-B5JDCJ5J.js +19 -0
- package/dist/chunk-22LDUTY7.js +14597 -0
- package/dist/chunk-24JVDLQJ.js +345 -0
- package/dist/chunk-24M4AJPG.js +128 -0
- package/dist/chunk-2B7RCTPT.js +85 -0
- package/dist/chunk-2QBA6YE6.js +127 -0
- package/dist/chunk-2RGDEBZC.js +731 -0
- package/dist/chunk-2T3OYZMR.js +1158 -0
- package/dist/chunk-32DBQWR5.js +333 -0
- package/dist/chunk-3ABY3QDX.js +199 -0
- package/dist/chunk-3EOPMTG2.js +128 -0
- package/dist/chunk-3G3ECFB5.js +668 -0
- package/dist/chunk-3LHOFGHT.js +280 -0
- package/dist/chunk-3NS4V4JW.js +382 -0
- package/dist/chunk-3NYY2NZ3.js +836 -0
- package/dist/chunk-3RA62PNQ.js +58 -0
- package/dist/chunk-3ROUD5WA.js +97 -0
- package/dist/chunk-3RY2ARDN.js +129 -0
- package/dist/chunk-3XRS5AVV.js +567 -0
- package/dist/chunk-3Y5IRIRU.js +290 -0
- package/dist/chunk-3YK7X5FD.js +1186 -0
- package/dist/chunk-3ZWWUKBI.js +210 -0
- package/dist/chunk-463G3VAH.js +122 -0
- package/dist/chunk-4L6PVYFE.js +54 -0
- package/dist/chunk-4LC7BFI2.js +76 -0
- package/dist/chunk-4O67LBMK.js +377 -0
- package/dist/chunk-4OIU3N6U.js +167 -0
- package/dist/chunk-4Z3FWLOE.js +836 -0
- package/dist/chunk-5BAU4T5G.js +208 -0
- package/dist/chunk-5FP7YHCG.js +1158 -0
- package/dist/chunk-5SYYMNPE.js +30 -0
- package/dist/chunk-5TO5PH7O.js +304 -0
- package/dist/chunk-5U3JZP62.js +1352 -0
- package/dist/chunk-5VNFXIGF.js +85 -0
- package/dist/chunk-5XD2Y463.js +402 -0
- package/dist/chunk-63AENHJC.js +123 -0
- package/dist/chunk-673IFJYB.js +731 -0
- package/dist/chunk-6UVUJNLY.js +1186 -0
- package/dist/chunk-7AWH47AR.js +448 -0
- package/dist/chunk-7KPWYWYL.js +290 -0
- package/dist/chunk-7P4B6AEP.js +227 -0
- package/dist/chunk-7URNGDEY.js +2145 -0
- package/dist/chunk-7VHOALNC.js +244 -0
- package/dist/chunk-ADZQBZOX.js +122 -0
- package/dist/chunk-APSZAEDO.js +1186 -0
- package/dist/chunk-ASHF6VO4.js +2265 -0
- package/dist/chunk-ASJHCAVL.js +38 -0
- package/dist/chunk-BT2LEHIW.js +448 -0
- package/dist/chunk-BTS5QUWB.js +50 -0
- package/dist/chunk-BWJDJ3BS.js +604 -0
- package/dist/chunk-CME46VWP.js +150 -0
- package/dist/chunk-D3ICCKXY.js +54 -0
- package/dist/chunk-D3IOU3NO.js +377 -0
- package/dist/chunk-DFGXRKI2.js +221 -0
- package/dist/chunk-DICIFTCS.js +150 -0
- package/dist/chunk-DIFI5JDC.js +76 -0
- package/dist/chunk-DO65VHQZ.js +128 -0
- package/dist/chunk-DPOIJ5SM.js +284 -0
- package/dist/chunk-E2OMUBXQ.js +567 -0
- package/dist/chunk-ECMXIV6N.js +97 -0
- package/dist/chunk-EDMVA3PT.js +727 -0
- package/dist/chunk-F5OSXH4A.js +4388 -0
- package/dist/chunk-F5OWHPRG.js +236 -0
- package/dist/chunk-F7MZA3QP.js +199 -0
- package/dist/chunk-FAZNXNA5.js +33 -0
- package/dist/chunk-FCHG5RC4.js +197 -0
- package/dist/chunk-FFKSPZO2.js +157 -0
- package/dist/chunk-FNHYH5U6.js +331 -0
- package/dist/chunk-FRNXQSB4.js +134 -0
- package/dist/chunk-FTAASABV.js +362 -0
- package/dist/chunk-FWPDAQ6Q.js +1350 -0
- package/dist/chunk-FZB73QOI.js +210 -0
- package/dist/chunk-GBL5QSTM.js +197 -0
- package/dist/chunk-GJBR6QLD.js +630 -0
- package/dist/chunk-GRSYAHKI.js +535 -0
- package/dist/chunk-GRXWINOW.js +244 -0
- package/dist/chunk-GUPNVUG5.js +348 -0
- package/dist/chunk-GY66UPMX.js +167 -0
- package/dist/chunk-HCCG67BY.js +43 -0
- package/dist/chunk-HCSZZXZZ.js +197 -0
- package/dist/chunk-HNGNZU62.js +240 -0
- package/dist/chunk-HP2D5LIE.js +214 -0
- package/dist/chunk-HUABQHDC.js +1352 -0
- package/dist/chunk-HYKO2LNW.js +157 -0
- package/dist/chunk-IFL6DG2K.js +181 -0
- package/dist/chunk-IKPQRHVQ.js +304 -0
- package/dist/chunk-J5HFRVNW.js +362 -0
- package/dist/chunk-J6SD7LT2.js +171 -0
- package/dist/chunk-JCWA3X6A.js +402 -0
- package/dist/chunk-JHPK33IP.js +2162 -0
- package/dist/chunk-JURL2S27.js +128 -0
- package/dist/chunk-JWGDH5I2.js +127 -0
- package/dist/chunk-KBXQFXYM.js +567 -0
- package/dist/chunk-KGY5QIOJ.js +1350 -0
- package/dist/chunk-KLES22FB.js +1094 -0
- package/dist/chunk-KPUYYOFS.js +122 -0
- package/dist/chunk-KY43UELJ.js +331 -0
- package/dist/chunk-L32V4O5Z.js +58 -0
- package/dist/chunk-LAFARYU5.js +456 -0
- package/dist/chunk-LC7ETNTJ.js +1350 -0
- package/dist/chunk-LEJ5FKIK.js +55 -0
- package/dist/chunk-LNLLCAI4.js +377 -0
- package/dist/chunk-LQWZYMNU.js +448 -0
- package/dist/chunk-LSDXEHKL.js +381 -0
- package/dist/chunk-LY3SOO73.js +76 -0
- package/dist/chunk-M6CIHXXB.js +159 -0
- package/dist/chunk-MJOQ35DX.js +427 -0
- package/dist/chunk-MO5HER5Y.js +345 -0
- package/dist/chunk-MS2EOZJQ.js +290 -0
- package/dist/chunk-MUIMJGSQ.js +128 -0
- package/dist/chunk-MY4TGLT6.js +284 -0
- package/dist/chunk-N3ARGCVG.js +345 -0
- package/dist/chunk-N4XG2M2U.js +735 -0
- package/dist/chunk-N72JNFJ4.js +535 -0
- package/dist/chunk-NJMPNYBS.js +427 -0
- package/dist/chunk-NM3AUMFE.js +2145 -0
- package/dist/chunk-NPPQ3TR4.js +735 -0
- package/dist/chunk-NTWF4DAF.js +581 -0
- package/dist/chunk-NXL3VKXM.js +331 -0
- package/dist/chunk-OJACH2JF.js +128 -0
- package/dist/chunk-OMSLHEEF.js +456 -0
- package/dist/chunk-OO4IFABD.js +382 -0
- package/dist/chunk-OYIP3QVN.js +167 -0
- package/dist/chunk-P2IOW54H.js +668 -0
- package/dist/chunk-P5KXQ3RN.js +731 -0
- package/dist/chunk-P5UXP53T.js +81 -0
- package/dist/chunk-PH6VRRFR.js +395 -0
- package/dist/chunk-Q3GKOF7Z.js +85 -0
- package/dist/chunk-Q65NCNL4.js +1352 -0
- package/dist/chunk-QIGS2LRT.js +735 -0
- package/dist/chunk-QKBN3CY2.js +381 -0
- package/dist/chunk-QNNAVMQH.js +1094 -0
- package/dist/chunk-QODDW4YI.js +171 -0
- package/dist/chunk-QPAYPTSH.js +2162 -0
- package/dist/chunk-QRWDJ5RI.js +381 -0
- package/dist/chunk-RBFZCHVB.js +105 -0
- package/dist/chunk-RCEULTPF.js +185 -0
- package/dist/chunk-RCGHXBCX.js +630 -0
- package/dist/chunk-ROSCLRTH.js +204 -0
- package/dist/chunk-RYAOSGUW.js +227 -0
- package/dist/chunk-S2SPGHPY.js +38 -0
- package/dist/chunk-S73ZAJ2S.js +262 -0
- package/dist/chunk-SBPEWD7Z.js +171 -0
- package/dist/chunk-SDPUWZP5.js +333 -0
- package/dist/chunk-SJ4UF7YK.js +1094 -0
- package/dist/chunk-SOZ7D77I.js +204 -0
- package/dist/chunk-SVLSHDNL.js +54 -0
- package/dist/chunk-SVUYBT5N.js +262 -0
- package/dist/chunk-T7PTLVJV.js +284 -0
- package/dist/chunk-TDX2LK2M.js +240 -0
- package/dist/chunk-TGUSLO4B.js +50 -0
- package/dist/chunk-TPJH6PE6.js +1158 -0
- package/dist/chunk-TVW7EDOJ.js +382 -0
- package/dist/chunk-TYRUIE6P.js +58 -0
- package/dist/chunk-U5RKGLV6.js +50 -0
- package/dist/chunk-UFGTHBHP.js +127 -0
- package/dist/chunk-ULCYWCPI.js +1079 -0
- package/dist/chunk-UN5EPVBN.js +14597 -0
- package/dist/chunk-URLH7ZVR.js +70 -0
- package/dist/chunk-USYRTGR7.js +402 -0
- package/dist/chunk-V4ABCEHM.js +30 -0
- package/dist/chunk-V6LOEOXG.js +3372 -0
- package/dist/chunk-VAZOVAW4.js +2162 -0
- package/dist/chunk-VEUQVKKT.js +185 -0
- package/dist/chunk-VIDDJ5RF.js +214 -0
- package/dist/chunk-VKCNXOQ6.js +214 -0
- package/dist/chunk-VNB4ROYG.js +348 -0
- package/dist/chunk-VWUQFZFB.js +395 -0
- package/dist/chunk-W77GRCNA.js +85 -0
- package/dist/chunk-WB2B25UM.js +230 -0
- package/dist/chunk-WCUZX7F7.js +204 -0
- package/dist/chunk-WL5RMOZQ.js +362 -0
- package/dist/chunk-WPAXAOHD.js +1079 -0
- package/dist/chunk-WVMG4ZRH.js +14597 -0
- package/dist/chunk-WYVOTRRZ.js +129 -0
- package/dist/chunk-XABJRAUW.js +3346 -0
- package/dist/chunk-XQQ7D4I4.js +85 -0
- package/dist/chunk-YDFY6YCH.js +280 -0
- package/dist/chunk-YGUMRYCN.js +33 -0
- package/dist/chunk-YHJPTIPR.js +836 -0
- package/dist/chunk-YJSP5PPG.js +128 -0
- package/dist/chunk-YLKS7KKC.js +2145 -0
- package/dist/chunk-YOMETWOJ.js +4388 -0
- package/dist/chunk-YU3KEVCO.js +333 -0
- package/dist/chunk-Z4FVFSE3.js +81 -0
- package/dist/chunk-Z4TLSNUW.js +244 -0
- package/dist/chunk-ZDPU3JTF.js +221 -0
- package/dist/chunk-ZDY4LYAJ.js +81 -0
- package/dist/chunk-ZG33AACD.js +70 -0
- package/dist/chunk-ZKHPZ6KN.js +181 -0
- package/dist/chunk-ZO2TM5N5.js +97 -0
- package/dist/chunk-ZP6T5K6I.js +535 -0
- package/dist/chunk-ZR6ZJT32.js +123 -0
- package/dist/chunk-ZSUACDQC.js +4388 -0
- package/dist/co-activation-JGF5YIDU.js +74 -0
- package/dist/co-activation-XM25BLZM.js +74 -0
- package/dist/co-occurrence-CKEMDPWO.js +95 -0
- package/dist/co-occurrence-HLLC6GT2.js +95 -0
- package/dist/co-occurrence-W2LIAPHI.js +95 -0
- package/dist/code-context-index-FCL47WKE.js +30 -0
- package/dist/conversation-entity-extractor-WC2RU6RS.js +114 -0
- package/dist/core-memory-CRSR2PSL.js +110 -0
- package/dist/core-memory-VSKFRMEV.js +110 -0
- package/dist/core-memory-ZDA76EU3.js +110 -0
- package/dist/crdt-sync-6VH2YDVY.js +33 -0
- package/dist/crdt-sync-BJKZB6T6.js +33 -0
- package/dist/crm-webhook-E5PAFAUN.js +10 -0
- package/dist/crm-webhook-RXFPZJXP.js +10 -0
- package/dist/crm-webhook-Z26LEFKG.js +10 -0
- package/dist/cto-delegation-gate-45IBLPTK.js +280 -0
- package/dist/cto-delegation-gate-EMY6ZZ2F.js +280 -0
- package/dist/cto-delegation-gate-SF4EUB2Q.js +280 -0
- package/dist/daemon-orchestration-VB3BLYIT.js +143 -0
- package/dist/daemon-orchestration-W66UYGUD.js +143 -0
- package/dist/daemon-orchestration-Y5Y6YNE3.js +143 -0
- package/dist/db-backup-HFJ53IBU.js +43 -0
- package/dist/db-backup-NVUTS7L5.js +43 -0
- package/dist/doc-graph-extractor-ID45AQ2P.js +133 -0
- package/dist/doc-graph-extractor-MLYQYT4B.js +133 -0
- package/dist/doc-graph-extractor-SVFSXKL6.js +133 -0
- package/dist/dreaming-AZYRAGKA.js +34 -0
- package/dist/dreaming-N6B7KBIE.js +34 -0
- package/dist/dreaming-WG5CDUHX.js +34 -0
- package/dist/entity-boost-XAFCDDB6.js +375 -0
- package/dist/exe-drift-3SGA53CL.js +70 -0
- package/dist/exe-drift-CPUEAPIU.js +70 -0
- package/dist/exe-export-4RTGDV53.js +77 -0
- package/dist/exe-export-APUNLKWF.js +77 -0
- package/dist/exe-export-NM4SXB3P.js +77 -0
- package/dist/exe-import-6GLNCP62.js +80 -0
- package/dist/exe-import-AZMIF34Z.js +80 -0
- package/dist/exe-import-U4H4ES3Z.js +80 -0
- package/dist/exe-key-FIPXUTMF.js +673 -0
- package/dist/exe-key-LJV23AJI.js +673 -0
- package/dist/exe-key-WTLCMOYJ.js +673 -0
- package/dist/exe-snapshot-ILO3WSEC.js +338 -0
- package/dist/exe-snapshot-IODRQLBX.js +338 -0
- package/dist/exe-snapshot-ZOZBW7V6.js +338 -0
- package/dist/fast-db-init-7LYYUCSJ.js +7 -0
- package/dist/fast-db-init-ATRZGHOL.js +7 -0
- package/dist/fast-db-init-IU7GYFWB.js +7 -0
- package/dist/gateway/index.js +11 -11
- package/dist/git-staleness-GGCFPHQ5.js +112 -0
- package/dist/git-staleness-XNOKI4D3.js +112 -0
- package/dist/git-task-sweep-3MO4OVND.js +42 -0
- package/dist/git-task-sweep-M3SWXFKJ.js +42 -0
- package/dist/git-task-sweep-Y6KNWB67.js +42 -0
- package/dist/global-procedures-626WAU3I.js +22 -0
- package/dist/global-procedures-EBAPPWGZ.js +22 -0
- package/dist/graph-auto-extract-TKHQ4OR3.js +183 -0
- package/dist/graph-auto-extract-VGFEWFZX.js +183 -0
- package/dist/graph-auto-extract-VJOUQBPK.js +183 -0
- package/dist/graph-rag-KECA5TE4.js +35 -0
- package/dist/hooks/bug-report-worker.js +12 -12
- package/dist/hooks/codex-stop-task-finalizer.js +12 -12
- package/dist/hooks/commit-complete.js +12 -12
- package/dist/hooks/error-recall.js +6 -6
- package/dist/hooks/exe-heartbeat-hook.js +3 -3
- package/dist/hooks/ingest-worker.js +3 -3
- package/dist/hooks/ingest.js +6 -6
- package/dist/hooks/instructions-loaded.js +4 -4
- package/dist/hooks/manifest.json +20 -20
- package/dist/hooks/notification.js +4 -4
- package/dist/hooks/post-compact.js +12 -12
- package/dist/hooks/post-tool-combined.js +6 -6
- package/dist/hooks/pre-compact.js +16 -16
- package/dist/hooks/pre-tool-use.js +15 -15
- package/dist/hooks/prompt-submit.js +28 -26
- package/dist/hooks/session-end.js +20 -20
- package/dist/hooks/session-start.js +12 -12
- package/dist/hooks/stop.js +18 -18
- package/dist/hooks/subagent-stop.js +11 -11
- package/dist/hooks/summary-worker.js +18 -18
- package/dist/index.js +20 -20
- package/dist/installer-37KFNAWE.js +344 -0
- package/dist/installer-3FB5EMPB.js +40 -0
- package/dist/installer-BRQ42CPB.js +344 -0
- package/dist/installer-F55NR4E2.js +298 -0
- package/dist/installer-KOYBUS4J.js +40 -0
- package/dist/installer-PXZJG256.js +298 -0
- package/dist/lib/cloud-sync.js +13 -7
- package/dist/lib/consolidation.js +7 -7
- package/dist/lib/database.js +6 -4
- package/dist/lib/db-daemon-client.js +11 -202
- package/dist/lib/db.js +6 -4
- package/dist/lib/embedder.js +3 -3
- package/dist/lib/employee-templates.js +4 -4
- package/dist/lib/employees.js +2 -2
- package/dist/lib/exe-daemon-client.js +2 -2
- package/dist/lib/exe-daemon.js +53 -51
- package/dist/lib/hybrid-search.js +5 -5
- package/dist/lib/identity.js +2 -2
- package/dist/lib/messaging.js +10 -10
- package/dist/lib/reminders.js +3 -3
- package/dist/lib/schedules.js +5 -5
- package/dist/lib/session-registry.js +4 -4
- package/dist/lib/skill-learning.js +6 -6
- package/dist/lib/store.js +4 -4
- package/dist/lib/task-router.js +3 -3
- package/dist/lib/tasks.js +11 -11
- package/dist/lib/tmux-routing.js +9 -9
- package/dist/lib/token-spend.js +3 -3
- package/dist/mcp/register-tools.js +65 -63
- package/dist/mcp/server.js +66 -64
- package/dist/mcp/tools/complete-reminder.js +4 -4
- package/dist/mcp/tools/create-reminder.js +4 -4
- package/dist/mcp/tools/create-task.js +13 -13
- package/dist/mcp/tools/deactivate-behavior.js +7 -7
- package/dist/mcp/tools/list-reminders.js +4 -4
- package/dist/mcp/tools/list-tasks.js +13 -13
- package/dist/mcp/tools/send-message.js +12 -12
- package/dist/mcp/tools/update-task.js +12 -12
- package/dist/mcp-http-config-7KJZI7UD.js +31 -0
- package/dist/mcp-http-config-OF3MB7M5.js +31 -0
- package/dist/memory-cards-CPIZVXWI.js +180 -0
- package/dist/memory-cards-ZIT7ZKL5.js +180 -0
- package/dist/memory-graph-extractor-JIYWLBFF.js +22 -0
- package/dist/memory-graph-extractor-LY2VORZT.js +22 -0
- package/dist/memory-graph-extractor-MDPSLZDM.js +22 -0
- package/dist/memory-poisoning-defense-5UZT3WWA.js +224 -0
- package/dist/memory-poisoning-defense-SEM25TY5.js +224 -0
- package/dist/memory-queue-client-WKWRFERJ.js +16 -0
- package/dist/memory-reflection-J2W7CJ7C.js +244 -0
- package/dist/memory-reflection-TA2VQYPH.js +244 -0
- package/dist/message-queue-client-IFQQ2HI7.js +92 -0
- package/dist/notifications-CZBQ3H5T.js +47 -0
- package/dist/notifications-EIIL2EQV.js +47 -0
- package/dist/notifications-RLMSI4YE.js +47 -0
- package/dist/orchestration-events-TGQYA72K.js +27 -0
- package/dist/orchestration-events-VUYR6MXE.js +27 -0
- package/dist/orchestrator-JQD5G3CW.js +35 -0
- package/dist/orchestrator-MAMR4C37.js +35 -0
- package/dist/orchestrator-VE5WHEJH.js +35 -0
- package/dist/pipeline-router-3Q3YBYSM.js +15 -0
- package/dist/pipeline-router-DKXD6DJO.js +15 -0
- package/dist/pipeline-router-YNW63BY5.js +15 -0
- package/dist/plan-limits-YGXTYCW4.js +28 -0
- package/dist/plan-limits-ZM4MNZKY.js +28 -0
- package/dist/project-boot-E2TWYTAC.js +299 -0
- package/dist/project-boot-TDOZKKDR.js +299 -0
- package/dist/projection-worker-TMKUSVGD.js +1084 -0
- package/dist/projection-worker-WFPRM4AI.js +1084 -0
- package/dist/projection-worker-YKV3PFCV.js +1084 -0
- package/dist/prospective-memory-CNJDBNWF.js +232 -0
- package/dist/prospective-memory-OAFZUODU.js +232 -0
- package/dist/reranker-AFU75HEX.js +19 -0
- package/dist/reranker-RYNSJNDF.js +19 -0
- package/dist/reranker-YQIRNGDM.js +19 -0
- package/dist/retrieval-health-M5BVB7EV.js +12 -0
- package/dist/retrieval-health-RSQEIYIB.js +12 -0
- package/dist/review-polling-LGX7DUNT.js +126 -0
- package/dist/review-polling-MJBCYV4I.js +126 -0
- package/dist/review-polling-ZMB3OBPC.js +126 -0
- package/dist/runtime/index.js +16 -16
- package/dist/services/codex-reviewd/index.js +855 -0
- package/dist/session-events-5N47BRFK.js +38 -0
- package/dist/session-events-PT6SVS2P.js +38 -0
- package/dist/session-events-UTMCKDIN.js +38 -0
- package/dist/session-kill-telemetry-FRQA5MVD.js +31 -0
- package/dist/session-kill-telemetry-HKL2NQMR.js +31 -0
- package/dist/session-scope-2BD6QLNI.js +88 -0
- package/dist/session-scope-GQNCM6UQ.js +88 -0
- package/dist/session-scope-MMGM232A.js +88 -0
- package/dist/setup-wizard-SELXXVLD.js +12 -0
- package/dist/setup-wizard-W64I6SHC.js +12 -0
- package/dist/setup-wizard-X7YSRDNQ.js +12 -0
- package/dist/skill-refinement-CCP4ULZ3.js +159 -0
- package/dist/skill-refinement-FXCXTUS2.js +159 -0
- package/dist/skill-refinement-WCPDNHZ5.js +159 -0
- package/dist/stack-update-5VSGG36W.js +84 -0
- package/dist/steward-gate-JDR3SLH3.js +15 -0
- package/dist/steward-gate-PIXNK4BK.js +15 -0
- package/dist/task-enforcement-LEBWCYZT.js +506 -0
- package/dist/task-enforcement-VOSQRAQB.js +506 -0
- package/dist/task-enforcement-WCEA4FZI.js +506 -0
- package/dist/task-scope-CQZ33PRU.js +37 -0
- package/dist/task-scope-JTTEZKDU.js +37 -0
- package/dist/task-scope-L5GDL2AV.js +37 -0
- package/dist/tasks-crud-DC4GCXQQ.js +79 -0
- package/dist/tasks-crud-S36AFYYM.js +79 -0
- package/dist/tasks-crud-T32IRPXF.js +79 -0
- package/dist/tasks-notify-OBFVHJDP.js +40 -0
- package/dist/tasks-notify-OUQWUM6W.js +40 -0
- package/dist/tasks-notify-W2W2BJRB.js +40 -0
- package/dist/tasks-review-34WV7BX2.js +49 -0
- package/dist/tasks-review-N33MTHWJ.js +49 -0
- package/dist/tasks-review-OSBG2YN2.js +49 -0
- package/dist/telemetry-upload-3CSVO3J7.js +741 -0
- package/dist/telemetry-upload-EYHEWTKG.js +741 -0
- package/dist/telemetry-upload-XLBW4DRP.js +741 -0
- package/dist/token-budget-I6FMMDFX.js +86 -0
- package/dist/token-budget-ZG2MQ5GD.js +86 -0
- package/dist/tool-capability-index-IWQBQKM7.js +10 -0
- package/dist/tool-telemetry-2E3Z7CRV.js +17 -0
- package/dist/tool-telemetry-ODL4F2CW.js +17 -0
- package/dist/tui/App.js +17 -17
- package/dist/tui-data-VWT4Q5UT.js +260 -0
- package/dist/tui-data-XFBFBSBE.js +260 -0
- package/dist/tui-data-Z5UF7KEI.js +260 -0
- package/dist/wiki-acl-EUOPNUIQ.js +111 -0
- package/dist/wiki-acl-SZFHCEC4.js +111 -0
- package/dist/worker-gate-OOO6BWZ6.js +21 -0
- package/dist/worker-gate-OQMKAMP7.js +21 -0
- package/dist/worker-gate-ZPP3SZK6.js +21 -0
- package/dist/workflow-engine-P7WYJP2B.js +28 -0
- package/dist/workflow-engine-QY3IFFR2.js +28 -0
- package/dist/workflow-engine-UYNB5RTB.js +28 -0
- package/dist/worktree-CNOQZBNT.js +28 -0
- package/dist/worktree-H5C4LMQR.js +28 -0
- package/dist/worktree-sweep-KFWF3XZD.js +21 -0
- package/dist/worktree-sweep-SE7ITXC4.js +21 -0
- package/package.json +1 -1
- package/release-notes.json +117 -191
- package/src/commands/exe.md +18 -1
|
@@ -0,0 +1,1158 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getMasterKey,
|
|
3
|
+
setMasterKey
|
|
4
|
+
} from "./chunk-Z42MXYWW.js";
|
|
5
|
+
import {
|
|
6
|
+
LEGACY_LANCE_PATH,
|
|
7
|
+
MODELS_DIR,
|
|
8
|
+
loadConfig,
|
|
9
|
+
saveConfig
|
|
10
|
+
} from "./chunk-R36FAN53.js";
|
|
11
|
+
import {
|
|
12
|
+
atomicWriteJsonSync,
|
|
13
|
+
atomicWriteSync
|
|
14
|
+
} from "./chunk-LYH5HE24.js";
|
|
15
|
+
|
|
16
|
+
// src/lib/setup-wizard.ts
|
|
17
|
+
import crypto from "crypto";
|
|
18
|
+
import { execSync } from "child_process";
|
|
19
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync, unlinkSync as unlinkSync2, writeFileSync, chmodSync } from "fs";
|
|
20
|
+
import os from "os";
|
|
21
|
+
import path2 from "path";
|
|
22
|
+
import { createInterface } from "readline";
|
|
23
|
+
|
|
24
|
+
// src/lib/model-downloader.ts
|
|
25
|
+
import { createWriteStream, createReadStream, existsSync, unlinkSync, renameSync, statSync } from "fs";
|
|
26
|
+
import { mkdir, statfs } from "fs/promises";
|
|
27
|
+
import { createHash } from "crypto";
|
|
28
|
+
import path from "path";
|
|
29
|
+
var GGUF_URL = process.env.EXE_EMBED_MODEL_URL ?? "";
|
|
30
|
+
var EXPECTED_SHA256 = process.env.EXE_EMBED_MODEL_SHA256 ?? "";
|
|
31
|
+
var EXPECTED_SIZE = Number(process.env.EXE_EMBED_MODEL_SIZE ?? "0") || 396836064;
|
|
32
|
+
var LOCAL_FILENAME = "exe-embeddings-v1-q4_k_m.gguf";
|
|
33
|
+
var MIN_FREE_BYTES = EXPECTED_SIZE + 100 * 1024 * 1024;
|
|
34
|
+
var INACTIVITY_TIMEOUT_MS = 6e4;
|
|
35
|
+
async function downloadModel(opts) {
|
|
36
|
+
const { destDir, onProgress, fetchFn = globalThis.fetch, url = GGUF_URL } = opts;
|
|
37
|
+
const destPath = path.join(destDir, LOCAL_FILENAME);
|
|
38
|
+
const tmpPath = destPath + ".tmp";
|
|
39
|
+
if (!url) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
"Embedding model download URL not configured (set EXE_EMBED_MODEL_URL). Embeddings are optional and OFF by default \u2014 graph + keyword search needs no model."
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
await mkdir(destDir, { recursive: true });
|
|
45
|
+
await assertEnoughFreeSpace(destDir);
|
|
46
|
+
if (existsSync(destPath)) {
|
|
47
|
+
const hash = await fileHash(destPath);
|
|
48
|
+
if (hash === EXPECTED_SHA256) {
|
|
49
|
+
return destPath;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const MAX_RETRIES = 3;
|
|
53
|
+
let lastErr;
|
|
54
|
+
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
55
|
+
try {
|
|
56
|
+
const resumeFrom = existsSync(tmpPath) ? statSync(tmpPath).size : 0;
|
|
57
|
+
if (resumeFrom >= EXPECTED_SIZE) {
|
|
58
|
+
const actualHash2 = await fileHash(tmpPath);
|
|
59
|
+
if (actualHash2 === EXPECTED_SHA256) {
|
|
60
|
+
renameSync(tmpPath, destPath);
|
|
61
|
+
return destPath;
|
|
62
|
+
}
|
|
63
|
+
unlinkSync(tmpPath);
|
|
64
|
+
throw new Error(
|
|
65
|
+
`SHA256 mismatch: expected ${EXPECTED_SHA256}, got ${actualHash2}`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
let downloaded = resumeFrom;
|
|
69
|
+
const controller = new AbortController();
|
|
70
|
+
let inactivityTimer = setTimeout(() => controller.abort(), INACTIVITY_TIMEOUT_MS);
|
|
71
|
+
const resetInactivityTimer = () => {
|
|
72
|
+
clearTimeout(inactivityTimer);
|
|
73
|
+
inactivityTimer = setTimeout(() => controller.abort(), INACTIVITY_TIMEOUT_MS);
|
|
74
|
+
};
|
|
75
|
+
const response = await fetchFn(url, {
|
|
76
|
+
redirect: "follow",
|
|
77
|
+
signal: controller.signal,
|
|
78
|
+
headers: resumeFrom > 0 ? { Range: `bytes=${resumeFrom}-` } : void 0
|
|
79
|
+
});
|
|
80
|
+
if (!response.ok || !response.body) {
|
|
81
|
+
throw new Error(`Download failed: HTTP ${response.status}`);
|
|
82
|
+
}
|
|
83
|
+
if (resumeFrom > 0 && response.status !== 206) {
|
|
84
|
+
clearTimeout(inactivityTimer);
|
|
85
|
+
unlinkSync(tmpPath);
|
|
86
|
+
throw new Error("Download server did not honor Range resume");
|
|
87
|
+
}
|
|
88
|
+
const rangeTotal = parseTotalSize(response.headers.get("content-range"));
|
|
89
|
+
const lengthHeaderRaw = response.headers.get("content-length");
|
|
90
|
+
const lengthHeader = lengthHeaderRaw != null ? Number(lengthHeaderRaw) : null;
|
|
91
|
+
const advertisedTotal = rangeTotal ?? (lengthHeader != null ? response.status === 206 ? resumeFrom + lengthHeader : lengthHeader : null);
|
|
92
|
+
const contentLength = advertisedTotal ?? EXPECTED_SIZE;
|
|
93
|
+
const fileStream = createWriteStream(tmpPath, { flags: resumeFrom > 0 ? "a" : "w" });
|
|
94
|
+
const reader = response.body.getReader();
|
|
95
|
+
try {
|
|
96
|
+
while (true) {
|
|
97
|
+
const { done, value } = await reader.read();
|
|
98
|
+
if (done) break;
|
|
99
|
+
resetInactivityTimer();
|
|
100
|
+
if (!fileStream.write(value)) {
|
|
101
|
+
await new Promise((resolve) => fileStream.once("drain", resolve));
|
|
102
|
+
}
|
|
103
|
+
downloaded += value.byteLength;
|
|
104
|
+
onProgress?.(downloaded, contentLength);
|
|
105
|
+
}
|
|
106
|
+
} finally {
|
|
107
|
+
clearTimeout(inactivityTimer);
|
|
108
|
+
fileStream.end();
|
|
109
|
+
await new Promise((resolve, reject) => {
|
|
110
|
+
fileStream.on("finish", resolve);
|
|
111
|
+
fileStream.on("error", reject);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
const finalSize = statSync(tmpPath).size;
|
|
115
|
+
if (advertisedTotal != null && finalSize !== advertisedTotal) {
|
|
116
|
+
throw new Error(`Downloaded size mismatch: expected ${advertisedTotal}, got ${finalSize} (truncated \u2014 will resume)`);
|
|
117
|
+
}
|
|
118
|
+
const actualHash = await fileHash(tmpPath);
|
|
119
|
+
if (actualHash !== EXPECTED_SHA256) {
|
|
120
|
+
unlinkSync(tmpPath);
|
|
121
|
+
throw new Error(
|
|
122
|
+
`SHA256 mismatch: expected ${EXPECTED_SHA256}, got ${actualHash}`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
renameSync(tmpPath, destPath);
|
|
126
|
+
return destPath;
|
|
127
|
+
} catch (err) {
|
|
128
|
+
lastErr = err instanceof Error ? err : new Error(String(err));
|
|
129
|
+
if (lastErr.message.includes("SHA256 mismatch")) break;
|
|
130
|
+
if (attempt < MAX_RETRIES) {
|
|
131
|
+
process.stderr.write(`
|
|
132
|
+
Download attempt ${attempt} failed, retrying...
|
|
133
|
+
`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
throw lastErr;
|
|
138
|
+
}
|
|
139
|
+
function parseTotalSize(contentRange) {
|
|
140
|
+
const match = contentRange?.match(/\/(\d+)$/);
|
|
141
|
+
return match ? Number(match[1]) : null;
|
|
142
|
+
}
|
|
143
|
+
async function assertEnoughFreeSpace(destDir) {
|
|
144
|
+
const stats = await statfs(destDir);
|
|
145
|
+
const available = stats.bavail * stats.bsize;
|
|
146
|
+
if (available < MIN_FREE_BYTES) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
`Insufficient disk space for model download: need at least ${MIN_FREE_BYTES} bytes free, have ${available}`
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async function fileHash(filePath) {
|
|
153
|
+
return new Promise((resolve, reject) => {
|
|
154
|
+
const hash = createHash("sha256");
|
|
155
|
+
const stream = createReadStream(filePath);
|
|
156
|
+
stream.on("data", (chunk) => hash.update(chunk));
|
|
157
|
+
stream.on("end", () => resolve(hash.digest("hex")));
|
|
158
|
+
stream.on("error", reject);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// src/lib/setup-wizard.ts
|
|
163
|
+
function findPackageRoot() {
|
|
164
|
+
let dir = path2.dirname(new URL(import.meta.url).pathname);
|
|
165
|
+
const root = path2.parse(dir).root;
|
|
166
|
+
while (dir !== root) {
|
|
167
|
+
const pkgPath = path2.join(dir, "package.json");
|
|
168
|
+
if (existsSync2(pkgPath)) {
|
|
169
|
+
try {
|
|
170
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
171
|
+
if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
|
|
172
|
+
} catch {
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
dir = path2.dirname(dir);
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
var SETUP_STATE_PATH = path2.join(os.homedir(), ".exe-os", "setup-state.json");
|
|
180
|
+
function loadSetupState() {
|
|
181
|
+
try {
|
|
182
|
+
return JSON.parse(readFileSync(SETUP_STATE_PATH, "utf8"));
|
|
183
|
+
} catch {
|
|
184
|
+
return { completedSteps: [], startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function saveSetupState(state) {
|
|
188
|
+
mkdirSync(path2.dirname(SETUP_STATE_PATH), { recursive: true });
|
|
189
|
+
atomicWriteJsonSync(SETUP_STATE_PATH, state);
|
|
190
|
+
}
|
|
191
|
+
function clearSetupState() {
|
|
192
|
+
try {
|
|
193
|
+
unlinkSync2(SETUP_STATE_PATH);
|
|
194
|
+
} catch {
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function ask(rl, prompt, allowEmpty = false) {
|
|
198
|
+
return new Promise((resolve) => {
|
|
199
|
+
const doAsk = () => {
|
|
200
|
+
rl.question(prompt, (answer) => {
|
|
201
|
+
const trimmed = answer.trim();
|
|
202
|
+
if (!allowEmpty && trimmed.length === 0) {
|
|
203
|
+
doAsk();
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
resolve(trimmed);
|
|
207
|
+
});
|
|
208
|
+
};
|
|
209
|
+
doAsk();
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
function askHeadless(envVar, fallback, log, prompt) {
|
|
213
|
+
const value = envVar ?? fallback;
|
|
214
|
+
if (value) log(` [headless] ${prompt.replace(/[:\s]+$/, "")}: ${value}`);
|
|
215
|
+
return value;
|
|
216
|
+
}
|
|
217
|
+
function getAvailableMemoryGB() {
|
|
218
|
+
if (process.platform === "darwin") {
|
|
219
|
+
try {
|
|
220
|
+
const vmstat = execSync("vm_stat", { encoding: "utf8" });
|
|
221
|
+
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
222
|
+
const pageSize = pageSizeMatch?.[1] ? parseInt(pageSizeMatch[1], 10) : 16384;
|
|
223
|
+
const free = vmstat.match(/Pages free:\s+(\d+)/);
|
|
224
|
+
const inactive = vmstat.match(/Pages inactive:\s+(\d+)/);
|
|
225
|
+
const speculative = vmstat.match(/Pages speculative:\s+(\d+)/);
|
|
226
|
+
const freePages = free?.[1] ? parseInt(free[1], 10) : 0;
|
|
227
|
+
const inactivePages = inactive?.[1] ? parseInt(inactive[1], 10) : 0;
|
|
228
|
+
const speculativePages = speculative?.[1] ? parseInt(speculative[1], 10) : 0;
|
|
229
|
+
return (freePages + inactivePages + speculativePages) * pageSize / (1024 * 1024 * 1024);
|
|
230
|
+
} catch {
|
|
231
|
+
return os.freemem() / (1024 * 1024 * 1024);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return os.freemem() / (1024 * 1024 * 1024);
|
|
235
|
+
}
|
|
236
|
+
function isWSL() {
|
|
237
|
+
if (process.platform !== "linux") return false;
|
|
238
|
+
try {
|
|
239
|
+
const release = execSync("uname -r", { encoding: "utf8", timeout: 3e3 }).toLowerCase();
|
|
240
|
+
return release.includes("microsoft");
|
|
241
|
+
} catch {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function getTotalMemoryGB() {
|
|
246
|
+
return os.totalmem() / (1024 * 1024 * 1024);
|
|
247
|
+
}
|
|
248
|
+
function isLowMemory() {
|
|
249
|
+
return getAvailableMemoryGB() < 2;
|
|
250
|
+
}
|
|
251
|
+
async function validateModel(log) {
|
|
252
|
+
const totalGB = getTotalMemoryGB();
|
|
253
|
+
const freeGB = getAvailableMemoryGB();
|
|
254
|
+
if (totalGB <= 8 || isLowMemory()) {
|
|
255
|
+
log(`System memory: ${totalGB.toFixed(0)}GB total, ${freeGB.toFixed(1)}GB free`);
|
|
256
|
+
log("Skipping in-memory model validation (low memory \u2014 will validate on first use).");
|
|
257
|
+
const modelPath = path2.join(MODELS_DIR, LOCAL_FILENAME);
|
|
258
|
+
if (existsSync2(modelPath)) {
|
|
259
|
+
const { statSync: statSync2 } = await import("fs");
|
|
260
|
+
const size = statSync2(modelPath).size;
|
|
261
|
+
if (size > 300 * 1e6) {
|
|
262
|
+
log(`Model file verified (${(size / 1e6).toFixed(0)} MB).`);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
throw new Error(`Model file too small (${(size / 1e6).toFixed(0)} MB) \u2014 may be corrupted. Delete and re-run setup.`);
|
|
266
|
+
}
|
|
267
|
+
throw new Error("Model file not found after download.");
|
|
268
|
+
}
|
|
269
|
+
log("Validating model...");
|
|
270
|
+
const result = await validateModelViaWorker();
|
|
271
|
+
if (result.dim !== 1024) {
|
|
272
|
+
throw new Error(
|
|
273
|
+
result.error ? `Model validation failed: ${result.error}` : `Model produced ${result.dim}-dim embeddings, expected 1024`
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
log("Model validation passed (1024-dim embeddings confirmed).");
|
|
277
|
+
}
|
|
278
|
+
async function validateModelViaWorker() {
|
|
279
|
+
const { fork } = await import("child_process");
|
|
280
|
+
const workerUrl = new URL("./embed-worker.js", import.meta.url);
|
|
281
|
+
const workerPath = workerUrl.pathname;
|
|
282
|
+
if (!existsSync2(workerPath)) {
|
|
283
|
+
return { dim: 0, error: `embed worker not found at ${workerPath}` };
|
|
284
|
+
}
|
|
285
|
+
const HEAP_FLAG_RE = /^--(max[-_]old[-_]space[-_]size|max[-_]semi[-_]space[-_]size|max[-_]heap[-_]size)(=|$)/i;
|
|
286
|
+
const execArgv = [
|
|
287
|
+
...process.execArgv.filter((a) => !HEAP_FLAG_RE.test(a)),
|
|
288
|
+
"--max-old-space-size=6144"
|
|
289
|
+
];
|
|
290
|
+
const env = { ...process.env, EXE_EMBED_WORKER_CONTEXT: "1" };
|
|
291
|
+
return await new Promise((resolve) => {
|
|
292
|
+
const child = fork(workerPath, [], { stdio: ["ignore", "ignore", "inherit", "ipc"], execArgv, env });
|
|
293
|
+
let settled = false;
|
|
294
|
+
const finish = (r) => {
|
|
295
|
+
if (settled) return;
|
|
296
|
+
settled = true;
|
|
297
|
+
clearTimeout(timer);
|
|
298
|
+
try {
|
|
299
|
+
child.removeAllListeners();
|
|
300
|
+
} catch {
|
|
301
|
+
}
|
|
302
|
+
try {
|
|
303
|
+
child.kill("SIGKILL");
|
|
304
|
+
} catch {
|
|
305
|
+
}
|
|
306
|
+
resolve(r);
|
|
307
|
+
};
|
|
308
|
+
const timer = setTimeout(() => finish({ dim: 0, error: "validation timed out after 120s" }), 12e4);
|
|
309
|
+
child.on("message", (msg) => {
|
|
310
|
+
if (msg?.type === "ready") finish({ dim: msg.dim ?? 0, error: msg.error });
|
|
311
|
+
});
|
|
312
|
+
child.on("error", (err) => finish({ dim: 0, error: err.message }));
|
|
313
|
+
child.on("exit", (code, signal) => finish({ dim: 0, error: `worker exited before ready (code=${code}, signal=${signal ?? "none"})` }));
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
async function runSetupWizard(opts = {}) {
|
|
317
|
+
const {
|
|
318
|
+
skipModel: skipModelOpt = false,
|
|
319
|
+
skipModelValidation = false,
|
|
320
|
+
nonInteractive = false,
|
|
321
|
+
log = (msg) => process.stderr.write(msg + "\n"),
|
|
322
|
+
runInstaller
|
|
323
|
+
} = opts;
|
|
324
|
+
let skipModel = skipModelOpt;
|
|
325
|
+
if (process.platform === "win32") {
|
|
326
|
+
log(
|
|
327
|
+
"\nexe-os does not support native Windows. Use WSL2 instead:\n 1. Run `wsl --install` in PowerShell\n 2. Open Ubuntu/WSL2\n 3. Install and run exe-os inside WSL2\n"
|
|
328
|
+
);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
const sigintHandler = () => {
|
|
332
|
+
process.stderr.write("\n\n\u26A0 Setup interrupted. If your encryption key was already created,\n");
|
|
333
|
+
process.stderr.write(" run `exe-os setup` again to resume and see your recovery phrase.\n\n");
|
|
334
|
+
process.exit(130);
|
|
335
|
+
};
|
|
336
|
+
process.on("SIGINT", sigintHandler);
|
|
337
|
+
if (nonInteractive) {
|
|
338
|
+
log("[headless] Non-interactive mode enabled. Using env vars for config.");
|
|
339
|
+
}
|
|
340
|
+
const rl = opts.createReadline ? opts.createReadline() : createInterface({ input: process.stdin, output: process.stderr });
|
|
341
|
+
const askOrEnv = (prompt, envVar, fallback = "") => {
|
|
342
|
+
if (nonInteractive) {
|
|
343
|
+
return Promise.resolve(askHeadless(envVar ? process.env[envVar] : void 0, fallback, log, prompt));
|
|
344
|
+
}
|
|
345
|
+
return ask(rl, prompt, fallback.length > 0);
|
|
346
|
+
};
|
|
347
|
+
const askOptional = (prompt, envVar, fallback = "") => {
|
|
348
|
+
if (nonInteractive) {
|
|
349
|
+
return Promise.resolve(askHeadless(envVar ? process.env[envVar] : void 0, fallback, log, prompt));
|
|
350
|
+
}
|
|
351
|
+
return ask(rl, prompt, true);
|
|
352
|
+
};
|
|
353
|
+
try {
|
|
354
|
+
log("");
|
|
355
|
+
log("=== exe-os Setup ===");
|
|
356
|
+
log("");
|
|
357
|
+
if (process.platform === "darwin") {
|
|
358
|
+
const currentShell = process.env.SHELL ?? "";
|
|
359
|
+
if (currentShell.includes("bash")) {
|
|
360
|
+
log(" \u26A0 Your default shell is bash.");
|
|
361
|
+
log(" macOS uses zsh by default since Catalina (2019).");
|
|
362
|
+
log(" exe-os works with bash, but switching to zsh is recommended:");
|
|
363
|
+
log(" chsh -s /bin/zsh");
|
|
364
|
+
log(" Then restart your terminal.");
|
|
365
|
+
log("");
|
|
366
|
+
const cont = await askOrEnv(" Continue with bash? (y/n, default: y): ", void 0, "y");
|
|
367
|
+
if (cont.toLowerCase() === "n") {
|
|
368
|
+
log(" Run `chsh -s /bin/zsh`, restart your terminal, then run setup again.");
|
|
369
|
+
rl.close();
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
log("");
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
if (isWSL()) {
|
|
376
|
+
log(" Detected: Windows Subsystem for Linux (WSL)");
|
|
377
|
+
log("");
|
|
378
|
+
if (process.cwd().startsWith("/mnt/")) {
|
|
379
|
+
log(" \u26A0 Your current directory is on the Windows filesystem (/mnt/).");
|
|
380
|
+
log(" This is ~10x slower than the native Linux filesystem.");
|
|
381
|
+
log(" For best performance, keep your projects in ~/ (e.g., ~/projects/)");
|
|
382
|
+
log(" and run exe-os from there.");
|
|
383
|
+
log("");
|
|
384
|
+
}
|
|
385
|
+
log(" Encryption: using file-based key storage (OS keychain not available in WSL).");
|
|
386
|
+
log(" This is normal \u2014 your key is still encrypted and machine-bound.");
|
|
387
|
+
log("");
|
|
388
|
+
}
|
|
389
|
+
log("What are you setting up?");
|
|
390
|
+
log("");
|
|
391
|
+
log(" [1] First device / brand new Exe OS memory");
|
|
392
|
+
log(" [2] Another device / I already have a 24-word recovery phrase");
|
|
393
|
+
log("");
|
|
394
|
+
const installType = await askOrEnv("Choice (1/2): ", "EXE_INSTALL_TYPE", "1");
|
|
395
|
+
let isPairing = false;
|
|
396
|
+
let pairingRosterPulled = false;
|
|
397
|
+
if (installType === "2") {
|
|
398
|
+
isPairing = true;
|
|
399
|
+
log("");
|
|
400
|
+
const { importMnemonic } = await import("./lib/keychain.js");
|
|
401
|
+
log("On your existing device, open Terminal and run:");
|
|
402
|
+
log(" exe-os cloud link --show-full");
|
|
403
|
+
log("Then copy the 24-word phrase here.");
|
|
404
|
+
log("");
|
|
405
|
+
const mnemonic = await askOrEnv("Paste the 24-word recovery phrase: ", "EXE_PASSPHRASE");
|
|
406
|
+
try {
|
|
407
|
+
const key = await importMnemonic(mnemonic);
|
|
408
|
+
await setMasterKey(key);
|
|
409
|
+
log("Master key imported and stored securely.");
|
|
410
|
+
log("");
|
|
411
|
+
log("Now paste the Cloud API key from that same `exe-os cloud link --show-full` output.");
|
|
412
|
+
log("It starts with: exe_sk_");
|
|
413
|
+
log("");
|
|
414
|
+
const apiKey = await askOptional("Cloud API key (starts with exe_sk_): ", "EXE_LICENSE_KEY");
|
|
415
|
+
if (apiKey && apiKey.startsWith("exe_sk_")) {
|
|
416
|
+
const cloudEndpoint = "https://api.askexe.com";
|
|
417
|
+
const cloudCfg = { apiKey, endpoint: cloudEndpoint };
|
|
418
|
+
const earlyConfig = await loadConfig();
|
|
419
|
+
earlyConfig.cloud = cloudCfg;
|
|
420
|
+
await saveConfig(earlyConfig);
|
|
421
|
+
const { saveLicense: saveLic, mirrorLicenseKey: mirrorLic } = await import("./lib/license.js");
|
|
422
|
+
saveLic(apiKey);
|
|
423
|
+
mirrorLic(apiKey);
|
|
424
|
+
log("Cloud sync configured.");
|
|
425
|
+
try {
|
|
426
|
+
const { initSyncCrypto } = await import("./lib/crypto.js");
|
|
427
|
+
const { cloudPullRoster } = await import("./lib/cloud-sync.js");
|
|
428
|
+
initSyncCrypto(key);
|
|
429
|
+
const result = await cloudPullRoster({ apiKey, endpoint: cloudEndpoint });
|
|
430
|
+
if (result.added > 0) {
|
|
431
|
+
log(`Pulled ${result.added} employee(s) from Exe Cloud.`);
|
|
432
|
+
pairingRosterPulled = true;
|
|
433
|
+
}
|
|
434
|
+
} catch {
|
|
435
|
+
log("Could not pull roster from cloud \u2014 you can set up employees manually.");
|
|
436
|
+
}
|
|
437
|
+
} else {
|
|
438
|
+
log("No API key provided \u2014 cloud sync will need to be configured later.");
|
|
439
|
+
log("Run /exe-cloud after setup to connect.");
|
|
440
|
+
}
|
|
441
|
+
log("");
|
|
442
|
+
} catch (err) {
|
|
443
|
+
log(`Key import failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
444
|
+
log("Check your phrase and try again, or choose option 1 for a fresh install.");
|
|
445
|
+
rl.close();
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
const state = loadSetupState();
|
|
450
|
+
if (state.completedSteps.length > 0) {
|
|
451
|
+
const visibleStep = Math.max(...state.completedSteps.filter((step) => step < 50), 0) + 1;
|
|
452
|
+
log(`Resuming setup from step ${visibleStep}...`);
|
|
453
|
+
}
|
|
454
|
+
if (existsSync2(LEGACY_LANCE_PATH)) {
|
|
455
|
+
log("\u26A0 Found v1.0 LanceDB at ~/.exe-os/local.lance");
|
|
456
|
+
log(" v1.1 uses libSQL (SQLite). Your existing memories are not automatically migrated.");
|
|
457
|
+
log(" The old directory will not be modified or deleted.");
|
|
458
|
+
log("");
|
|
459
|
+
}
|
|
460
|
+
if (!state.completedSteps.includes(1)) {
|
|
461
|
+
const existingKey = await getMasterKey();
|
|
462
|
+
if (existingKey) {
|
|
463
|
+
log("Encryption key already exists \u2014 skipping generation.");
|
|
464
|
+
} else {
|
|
465
|
+
log("Generating 256-bit encryption key...");
|
|
466
|
+
const key = crypto.randomBytes(32);
|
|
467
|
+
await setMasterKey(key);
|
|
468
|
+
log("Encryption key generated and stored securely.");
|
|
469
|
+
log("");
|
|
470
|
+
const { exportMnemonic } = await import("./lib/keychain.js");
|
|
471
|
+
const mnemonic = await exportMnemonic(key);
|
|
472
|
+
log("=============================================================");
|
|
473
|
+
log(" YOUR 24-WORD RECOVERY PHRASE");
|
|
474
|
+
log("=============================================================");
|
|
475
|
+
log("");
|
|
476
|
+
log(" " + mnemonic);
|
|
477
|
+
log("");
|
|
478
|
+
log(" SAVE THIS NOW before continuing.");
|
|
479
|
+
log(" Best: put it in your password manager, or write it down and keep it safe.");
|
|
480
|
+
log(" This phrase is the ONLY way to decrypt your memories if you lose this computer.");
|
|
481
|
+
log(" We cannot recover it for you.");
|
|
482
|
+
log("");
|
|
483
|
+
log(" Like a Bitcoin wallet \u2014 lose the phrase, lose everything.");
|
|
484
|
+
log("=============================================================");
|
|
485
|
+
log("");
|
|
486
|
+
const confirmation = nonInteractive ? "" : await ask(rl, 'Type "I SAVED MY RECOVERY PHRASE" after you have saved it: ', true);
|
|
487
|
+
if (nonInteractive) {
|
|
488
|
+
const recoveryPath = path2.join(os.homedir(), ".exe-os", "recovery-phrase.txt");
|
|
489
|
+
mkdirSync(path2.dirname(recoveryPath), { recursive: true });
|
|
490
|
+
writeFileSync(recoveryPath, mnemonic + "\n", { mode: 384 });
|
|
491
|
+
chmodSync(recoveryPath, 384);
|
|
492
|
+
log(`[headless] Recovery phrase written to ${recoveryPath} (0600). It is not marked as confirmed.`);
|
|
493
|
+
}
|
|
494
|
+
if (!nonInteractive && confirmation.toUpperCase().trim() !== "I SAVED MY RECOVERY PHRASE") {
|
|
495
|
+
throw new Error(
|
|
496
|
+
"Setup cancelled: recovery phrase was not confirmed. Save the 24-word phrase before continuing \u2014 it is required to recover encrypted memories."
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
if (!nonInteractive) {
|
|
500
|
+
const { markKeyBackupConfirmed } = await import("./key-backup-status-2EPRIAXU.js");
|
|
501
|
+
markKeyBackupConfirmed("setup-wizard");
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
state.completedSteps.push(1);
|
|
505
|
+
saveSetupState(state);
|
|
506
|
+
} else {
|
|
507
|
+
log("Step 1 already complete \u2014 skipping.");
|
|
508
|
+
}
|
|
509
|
+
log("");
|
|
510
|
+
let cloudConfig;
|
|
511
|
+
if (isPairing) {
|
|
512
|
+
const pairingConfig = await loadConfig();
|
|
513
|
+
if (pairingConfig.cloud?.apiKey) {
|
|
514
|
+
cloudConfig = pairingConfig.cloud;
|
|
515
|
+
log("Cloud sync: using shared API key from pairing.");
|
|
516
|
+
}
|
|
517
|
+
state.completedSteps.push(2);
|
|
518
|
+
saveSetupState(state);
|
|
519
|
+
} else if (!state.completedSteps.includes(2)) {
|
|
520
|
+
log("Exe Cloud: your memories are end-to-end encrypted, compressed, and");
|
|
521
|
+
log("backed up on Exe Cloud. Free for all plans. We can't read your data \u2014");
|
|
522
|
+
log("only your encryption key can decrypt it.");
|
|
523
|
+
log("Cloud setup may POST your device ID to api.askexe.com to provision sync.");
|
|
524
|
+
log("Free-tier telemetry is sent for product health and plan enforcement.");
|
|
525
|
+
log("");
|
|
526
|
+
const enableCloud = (await askOrEnv("Enable Exe Cloud sync? [Y/n]: ", "EXE_ENABLE_CLOUD", "y")).toLowerCase() !== "n";
|
|
527
|
+
const existingKey = enableCloud ? await askOptional("Paste your Exe OS license key, or press Enter to start as a free user: ", "EXE_LICENSE_KEY") : "";
|
|
528
|
+
if (!enableCloud) {
|
|
529
|
+
log("Cloud sync disabled. Setup will stay local-only.");
|
|
530
|
+
}
|
|
531
|
+
if (existingKey && existingKey.startsWith("exe_sk_")) {
|
|
532
|
+
const cloudEndpoint = "https://api.askexe.com";
|
|
533
|
+
try {
|
|
534
|
+
const { loadDeviceId } = await import("./lib/license.js");
|
|
535
|
+
const deviceId = loadDeviceId();
|
|
536
|
+
const res = await fetch(`${cloudEndpoint}/auth/activate`, {
|
|
537
|
+
method: "POST",
|
|
538
|
+
headers: { "Content-Type": "application/json" },
|
|
539
|
+
body: JSON.stringify({ apiKey: existingKey, deviceId }),
|
|
540
|
+
signal: AbortSignal.timeout(1e4)
|
|
541
|
+
});
|
|
542
|
+
if (res.ok) {
|
|
543
|
+
const data = await res.json();
|
|
544
|
+
if (data.valid) {
|
|
545
|
+
cloudConfig = { apiKey: existingKey, endpoint: cloudEndpoint };
|
|
546
|
+
const { saveLicense: saveLicense2, mirrorLicenseKey: mirrorLicenseKey2 } = await import("./lib/license.js");
|
|
547
|
+
saveLicense2(existingKey);
|
|
548
|
+
mirrorLicenseKey2(existingKey);
|
|
549
|
+
log(`API key validated. Plan: ${data.plan}, email: ${data.email}`);
|
|
550
|
+
log("Cloud sync configured.");
|
|
551
|
+
} else {
|
|
552
|
+
log("API key is invalid or expired. Proceeding with auto-provisioning.");
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
} catch {
|
|
556
|
+
log("Could not validate key \u2014 saving it and proceeding.");
|
|
557
|
+
cloudConfig = { apiKey: existingKey, endpoint: "https://api.askexe.com" };
|
|
558
|
+
const { saveLicense: saveLicense2, mirrorLicenseKey: mirrorLicenseKey2 } = await import("./lib/license.js");
|
|
559
|
+
saveLicense2(existingKey);
|
|
560
|
+
mirrorLicenseKey2(existingKey);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
if (enableCloud && !cloudConfig) {
|
|
564
|
+
try {
|
|
565
|
+
const { loadDeviceId } = await import("./lib/license.js");
|
|
566
|
+
const deviceId = loadDeviceId();
|
|
567
|
+
let res;
|
|
568
|
+
try {
|
|
569
|
+
res = await fetch("https://api.askexe.com/auth/auto-provision", {
|
|
570
|
+
method: "POST",
|
|
571
|
+
headers: { "Content-Type": "application/json" },
|
|
572
|
+
body: JSON.stringify({ deviceId }),
|
|
573
|
+
signal: AbortSignal.timeout(1e4)
|
|
574
|
+
});
|
|
575
|
+
} catch {
|
|
576
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
577
|
+
res = await fetch("https://api.askexe.com/auth/auto-provision", {
|
|
578
|
+
method: "POST",
|
|
579
|
+
headers: { "Content-Type": "application/json" },
|
|
580
|
+
body: JSON.stringify({ deviceId }),
|
|
581
|
+
signal: AbortSignal.timeout(1e4)
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
if (res.ok) {
|
|
585
|
+
const data = await res.json();
|
|
586
|
+
if (data.apiKey) {
|
|
587
|
+
cloudConfig = { apiKey: data.apiKey, endpoint: "https://api.askexe.com" };
|
|
588
|
+
const { saveLicense: saveLicense2, mirrorLicenseKey: mirrorLicenseKey2 } = await import("./lib/license.js");
|
|
589
|
+
saveLicense2(data.apiKey);
|
|
590
|
+
mirrorLicenseKey2(data.apiKey);
|
|
591
|
+
log("Cloud sync activated automatically.");
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
} catch {
|
|
595
|
+
log("Cloud sync will activate when online.");
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
state.completedSteps.push(2);
|
|
599
|
+
saveSetupState(state);
|
|
600
|
+
} else {
|
|
601
|
+
log("Step 2 already complete \u2014 skipping.");
|
|
602
|
+
}
|
|
603
|
+
log("");
|
|
604
|
+
if (!state.completedSteps.includes(3)) {
|
|
605
|
+
const totalGB = getTotalMemoryGB();
|
|
606
|
+
if (!skipModel && !nonInteractive) {
|
|
607
|
+
log("Search uses keyword + graph by default (fast, no model needed).");
|
|
608
|
+
log("Embedding model adds semantic search but requires ~600MB download.");
|
|
609
|
+
log("");
|
|
610
|
+
const installModel = await ask(rl, "Install embedding model? [y/N]: ", true);
|
|
611
|
+
if (!installModel || installModel.toLowerCase() !== "y") {
|
|
612
|
+
skipModel = true;
|
|
613
|
+
}
|
|
614
|
+
} else if (!skipModel) {
|
|
615
|
+
skipModel = true;
|
|
616
|
+
}
|
|
617
|
+
if (totalGB <= 8 && !skipModel) {
|
|
618
|
+
log(`System: ${totalGB.toFixed(0)}GB RAM \u2014 embedding model requires 16GB+. Skipping.`);
|
|
619
|
+
skipModel = true;
|
|
620
|
+
}
|
|
621
|
+
if (!skipModel) {
|
|
622
|
+
const freeGB = getAvailableMemoryGB();
|
|
623
|
+
if (freeGB < 2) {
|
|
624
|
+
log(`\u26A0 Low memory: ${freeGB.toFixed(1)}GB free. Close other apps first.`);
|
|
625
|
+
if (!nonInteractive) await ask(rl, "Press Enter when ready, or Ctrl+C to abort: ", true);
|
|
626
|
+
}
|
|
627
|
+
log("Downloading the embedding model (optional \u2014 embeddings are off by default)...");
|
|
628
|
+
await downloadModel({
|
|
629
|
+
destDir: MODELS_DIR,
|
|
630
|
+
onProgress: (downloaded, total) => {
|
|
631
|
+
const pct = (downloaded / total * 100).toFixed(1);
|
|
632
|
+
const dlMB = (downloaded / 1e6).toFixed(0);
|
|
633
|
+
const totalMB = (total / 1e6).toFixed(0);
|
|
634
|
+
process.stderr.write(`\rDownloading: ${pct}% (${dlMB}/${totalMB} MB)`);
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
process.stderr.write("\n");
|
|
638
|
+
log("Model downloaded.");
|
|
639
|
+
} else {
|
|
640
|
+
log("Search: keyword + graph (no embedding model)");
|
|
641
|
+
}
|
|
642
|
+
state.completedSteps.push(3);
|
|
643
|
+
saveSetupState(state);
|
|
644
|
+
} else {
|
|
645
|
+
log("Step 3 already complete \u2014 skipping.");
|
|
646
|
+
}
|
|
647
|
+
if (!state.completedSteps.includes(4)) {
|
|
648
|
+
if (!skipModel && !skipModelValidation) {
|
|
649
|
+
await validateModel(log);
|
|
650
|
+
}
|
|
651
|
+
state.completedSteps.push(4);
|
|
652
|
+
saveSetupState(state);
|
|
653
|
+
} else {
|
|
654
|
+
log("Step 4 already complete \u2014 skipping.");
|
|
655
|
+
}
|
|
656
|
+
const config = await loadConfig();
|
|
657
|
+
if (!state.completedSteps.includes(5)) {
|
|
658
|
+
if (cloudConfig) {
|
|
659
|
+
config.cloud = cloudConfig;
|
|
660
|
+
}
|
|
661
|
+
const { applyDefaultOrchestrationPhase } = await import("./orchestration-phase-EMDEZHIU.js");
|
|
662
|
+
applyDefaultOrchestrationPhase(config);
|
|
663
|
+
await saveConfig(config);
|
|
664
|
+
log("");
|
|
665
|
+
log(`Claude Code trust dialog will be accepted for this project only: ${process.cwd()}`);
|
|
666
|
+
try {
|
|
667
|
+
const claudeJsonPath = path2.join(os.homedir(), ".claude.json");
|
|
668
|
+
let claudeJson = {};
|
|
669
|
+
try {
|
|
670
|
+
claudeJson = JSON.parse(readFileSync(claudeJsonPath, "utf8"));
|
|
671
|
+
} catch {
|
|
672
|
+
}
|
|
673
|
+
if (!claudeJson.projects) claudeJson.projects = {};
|
|
674
|
+
const projects = claudeJson.projects;
|
|
675
|
+
const dir = process.cwd();
|
|
676
|
+
if (!projects[dir]) projects[dir] = {};
|
|
677
|
+
projects[dir].hasTrustDialogAccepted = true;
|
|
678
|
+
atomicWriteSync(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
679
|
+
} catch {
|
|
680
|
+
}
|
|
681
|
+
state.completedSteps.push(5);
|
|
682
|
+
saveSetupState(state);
|
|
683
|
+
} else {
|
|
684
|
+
log("Step 5 already complete \u2014 skipping.");
|
|
685
|
+
}
|
|
686
|
+
if (!state.completedSteps.includes(55)) {
|
|
687
|
+
const { savePreferences, loadPreferences: loadPrefs } = await import("./preferences-ERXO6SMJ.js");
|
|
688
|
+
const existingPrefs = loadPrefs();
|
|
689
|
+
const prefs = { ...existingPrefs };
|
|
690
|
+
log("=== Config Defaults ===");
|
|
691
|
+
log("");
|
|
692
|
+
const ghosttyDetected = existsSync2(path2.join(os.homedir(), ".config", "ghostty")) || existsSync2(path2.join(os.homedir(), "Library", "Application Support", "com.mitchellh.ghostty"));
|
|
693
|
+
if (ghosttyDetected) {
|
|
694
|
+
const ghosttyAnswer = await askOrEnv("Detected Ghostty terminal. Use exe-os Ghostty defaults? (Y/n) ", void 0, "y");
|
|
695
|
+
prefs.ghostty = ghosttyAnswer.toLowerCase() !== "n";
|
|
696
|
+
}
|
|
697
|
+
const weztermDetected = existsSync2(path2.join(os.homedir(), ".wezterm.lua")) || existsSync2(path2.join(os.homedir(), ".config", "wezterm")) || (() => {
|
|
698
|
+
try {
|
|
699
|
+
execSync("which wezterm 2>/dev/null", { timeout: 5e3 });
|
|
700
|
+
return true;
|
|
701
|
+
} catch {
|
|
702
|
+
return false;
|
|
703
|
+
}
|
|
704
|
+
})();
|
|
705
|
+
if (weztermDetected) {
|
|
706
|
+
const weztermAnswer = await askOrEnv("Detected WezTerm terminal. Use exe-os WezTerm defaults? (Y/n) ", void 0, "y");
|
|
707
|
+
prefs.wezterm = weztermAnswer.toLowerCase() !== "n";
|
|
708
|
+
}
|
|
709
|
+
const tmuxAnswer = await askOrEnv("Use exe-os tmux config? (Y/n) ", void 0, "y");
|
|
710
|
+
prefs.tmux = tmuxAnswer.toLowerCase() !== "n";
|
|
711
|
+
const statusLineAnswer = await askOrEnv("Install CC context bar in status line? (Y/n) ", void 0, "y");
|
|
712
|
+
prefs.ccStatusLine = statusLineAnswer.toLowerCase() !== "n";
|
|
713
|
+
prefs.codexStatusLine = prefs.ccStatusLine;
|
|
714
|
+
savePreferences(prefs);
|
|
715
|
+
log("");
|
|
716
|
+
state.completedSteps.push(55);
|
|
717
|
+
saveSetupState(state);
|
|
718
|
+
}
|
|
719
|
+
if (!state.completedSteps.includes(56)) {
|
|
720
|
+
log("=== AI Runtime ===");
|
|
721
|
+
log("");
|
|
722
|
+
log(" 1) Claude Code (Anthropic \u2014 recommended)");
|
|
723
|
+
log(" 2) Codex (OpenAI)");
|
|
724
|
+
log(" 3) OpenCode (75+ providers \u2014 open source)");
|
|
725
|
+
log("");
|
|
726
|
+
const rtChoice = await askOrEnv("Choose your AI runtime [1]: ", "EXE_RUNTIME", "1");
|
|
727
|
+
const rtMap = {
|
|
728
|
+
"1": { runtime: "claude", defaultModel: "claude-sonnet-4" },
|
|
729
|
+
"2": { runtime: "codex", defaultModel: "o3" },
|
|
730
|
+
"3": { runtime: "opencode", defaultModel: "anthropic/claude-sonnet-4" }
|
|
731
|
+
};
|
|
732
|
+
const selected = rtMap[rtChoice.trim()] ?? rtMap["1"];
|
|
733
|
+
const chosenModel = selected.defaultModel;
|
|
734
|
+
log(`Runtime: ${selected.runtime}`);
|
|
735
|
+
log(`Default model: ${chosenModel}`);
|
|
736
|
+
try {
|
|
737
|
+
const { loadConfig: lc, saveConfig: sc } = await import("./lib/config.js");
|
|
738
|
+
const cfg = await lc();
|
|
739
|
+
cfg.defaultRuntime = selected.runtime;
|
|
740
|
+
cfg.defaultModel = chosenModel;
|
|
741
|
+
await sc(cfg);
|
|
742
|
+
log(`Saved: ${selected.runtime} / ${chosenModel}`);
|
|
743
|
+
} catch (e) {
|
|
744
|
+
log(`Warning: could not save runtime config (${e instanceof Error ? e.message : String(e)})`);
|
|
745
|
+
}
|
|
746
|
+
log("");
|
|
747
|
+
state.completedSteps.push(56);
|
|
748
|
+
saveSetupState(state);
|
|
749
|
+
}
|
|
750
|
+
const {
|
|
751
|
+
loadEmployees,
|
|
752
|
+
saveEmployees,
|
|
753
|
+
addEmployee,
|
|
754
|
+
registerBinSymlinks,
|
|
755
|
+
EMPLOYEES_PATH,
|
|
756
|
+
DEFAULT_COORDINATOR_TEMPLATE_NAME,
|
|
757
|
+
validateEmployeeName,
|
|
758
|
+
VALID_AGENT_NAME_DESCRIPTION,
|
|
759
|
+
isCoordinatorRole
|
|
760
|
+
} = await import("./lib/employees.js");
|
|
761
|
+
const { getTemplateByRole } = await import("./lib/employee-templates.js");
|
|
762
|
+
const { identityPath } = await import("./lib/identity.js");
|
|
763
|
+
const { getTemplate: getIdentityTemplate } = await import("./lib/identity-templates.js");
|
|
764
|
+
const {
|
|
765
|
+
checkLicense,
|
|
766
|
+
saveLicense,
|
|
767
|
+
mirrorLicenseKey,
|
|
768
|
+
validateLicense
|
|
769
|
+
} = await import("./lib/license.js");
|
|
770
|
+
const createdEmployees = [];
|
|
771
|
+
let cooName = DEFAULT_COORDINATOR_TEMPLATE_NAME;
|
|
772
|
+
const reservedNames = /* @__PURE__ */ new Set(["test", "ls", "cd", "rm", "mv", "cp", "cat", "echo", "exit", "kill", "ps", "top", "sudo", "root", "admin", "node", "npm", "git"]);
|
|
773
|
+
const promptForEmployeeName = async (prompt, envVar, fallback) => {
|
|
774
|
+
while (true) {
|
|
775
|
+
const input = await askOrEnv(prompt, envVar, fallback);
|
|
776
|
+
const candidate = (input || fallback).toLowerCase();
|
|
777
|
+
const validation = validateEmployeeName(candidate);
|
|
778
|
+
if (!validation.valid) {
|
|
779
|
+
log(validation.error ?? VALID_AGENT_NAME_DESCRIPTION);
|
|
780
|
+
} else if (reservedNames.has(candidate)) {
|
|
781
|
+
log(`"${candidate}" is a reserved system command. Choose a different name.`);
|
|
782
|
+
} else {
|
|
783
|
+
return candidate;
|
|
784
|
+
}
|
|
785
|
+
if (nonInteractive) {
|
|
786
|
+
const fallbackValidation = validateEmployeeName(fallback);
|
|
787
|
+
if (fallbackValidation.valid && !reservedNames.has(fallback)) return fallback;
|
|
788
|
+
throw new Error(`Invalid default employee name '${fallback}'`);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
};
|
|
792
|
+
if (pairingRosterPulled) {
|
|
793
|
+
const roster = await loadEmployees(EMPLOYEES_PATH).catch(() => []);
|
|
794
|
+
const existingCoo = roster.find((e) => isCoordinatorRole(e.role));
|
|
795
|
+
if (existingCoo) {
|
|
796
|
+
cooName = existingCoo.name;
|
|
797
|
+
log("");
|
|
798
|
+
log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
799
|
+
log(" \u2502 Team synced from cloud \u2502");
|
|
800
|
+
log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
801
|
+
log("");
|
|
802
|
+
const maxNameLen = Math.max(...roster.map((e) => e.name.length), 4);
|
|
803
|
+
for (const emp of roster) {
|
|
804
|
+
const badge = emp.name === cooName ? " \u2605" : " ";
|
|
805
|
+
log(` ${badge} ${emp.name.padEnd(maxNameLen)} ${emp.role}`);
|
|
806
|
+
}
|
|
807
|
+
log("");
|
|
808
|
+
createdEmployees.push(...roster.map((e) => ({ name: e.name, role: e.role })));
|
|
809
|
+
}
|
|
810
|
+
let missingIdentities = [];
|
|
811
|
+
for (const emp of roster) {
|
|
812
|
+
const idPath = identityPath(emp.name);
|
|
813
|
+
if (!existsSync2(idPath)) {
|
|
814
|
+
missingIdentities.push(emp.name);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
if (missingIdentities.length > 0) {
|
|
818
|
+
log("");
|
|
819
|
+
log(`\u26A0 Identity files missing for: ${missingIdentities.join(", ")}`);
|
|
820
|
+
log(" Your main device needs to push them to cloud first.");
|
|
821
|
+
log("");
|
|
822
|
+
log(" On your MAIN device, run: exe-os cloud sync");
|
|
823
|
+
log(" Then come back here and press Enter to retry the pull.");
|
|
824
|
+
log("");
|
|
825
|
+
if (!nonInteractive) await ask(rl, "Press Enter after syncing from your main device... ", true);
|
|
826
|
+
try {
|
|
827
|
+
const { initSyncCrypto: retryInitCrypto } = await import("./lib/crypto.js");
|
|
828
|
+
const { cloudPullRoster: retryPull } = await import("./lib/cloud-sync.js");
|
|
829
|
+
const retryKey = await getMasterKey();
|
|
830
|
+
if (retryKey) {
|
|
831
|
+
retryInitCrypto(retryKey);
|
|
832
|
+
const retryConfig = await loadConfig();
|
|
833
|
+
if (retryConfig.cloud?.apiKey && retryConfig.cloud?.endpoint) {
|
|
834
|
+
const retryResult = await retryPull({
|
|
835
|
+
apiKey: retryConfig.cloud.apiKey,
|
|
836
|
+
endpoint: retryConfig.cloud.endpoint
|
|
837
|
+
});
|
|
838
|
+
if (retryResult.identitiesUpdated && retryResult.identitiesUpdated > 0) {
|
|
839
|
+
log(`Pulled ${retryResult.identitiesUpdated} identity file(s) from cloud.`);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
missingIdentities = [];
|
|
844
|
+
for (const emp of roster) {
|
|
845
|
+
if (!existsSync2(identityPath(emp.name))) {
|
|
846
|
+
missingIdentities.push(emp.name);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
if (missingIdentities.length > 0) {
|
|
850
|
+
log(`\u26A0 Still missing: ${missingIdentities.join(", ")}. Identities will sync on next daemon cycle.`);
|
|
851
|
+
} else {
|
|
852
|
+
log("All identity files synced successfully.");
|
|
853
|
+
}
|
|
854
|
+
} catch {
|
|
855
|
+
log("Retry pull failed \u2014 identities will sync when the daemon starts.");
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
for (const emp of roster) {
|
|
859
|
+
registerBinSymlinks(emp.name);
|
|
860
|
+
}
|
|
861
|
+
try {
|
|
862
|
+
const { generateSessionWrappers } = await import("./lib/session-wrappers.js");
|
|
863
|
+
const pkgRoot = findPackageRoot();
|
|
864
|
+
if (pkgRoot) {
|
|
865
|
+
const wrapResult = generateSessionWrappers(pkgRoot);
|
|
866
|
+
if (wrapResult.created > 0) {
|
|
867
|
+
log(`Session shortcuts generated: ${roster.map((e) => `${e.name}1`).join(", ")}, ...`);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
} catch {
|
|
871
|
+
}
|
|
872
|
+
state.completedSteps.push(6, 7, 8);
|
|
873
|
+
saveSetupState(state);
|
|
874
|
+
log("");
|
|
875
|
+
} else if (!state.completedSteps.includes(6)) {
|
|
876
|
+
log("=== Your First Hire ===");
|
|
877
|
+
log("");
|
|
878
|
+
log("Your new coordinator will hold all your vision, your roadmap, all your");
|
|
879
|
+
log("projects and everything you think about in business, life and beyond.");
|
|
880
|
+
log("They can call and hire new employees, executives, and coordinate");
|
|
881
|
+
log("your entire team. Engineers, marketers, specialists, all working");
|
|
882
|
+
log("in parallel while you focus on what matters.");
|
|
883
|
+
log("");
|
|
884
|
+
cooName = await promptForEmployeeName(
|
|
885
|
+
`Name your coordinator (default: ${DEFAULT_COORDINATOR_TEMPLATE_NAME}): `,
|
|
886
|
+
"EXE_COO_NAME",
|
|
887
|
+
DEFAULT_COORDINATOR_TEMPLATE_NAME
|
|
888
|
+
);
|
|
889
|
+
let employees = await loadEmployees(EMPLOYEES_PATH).catch(() => []);
|
|
890
|
+
if (!employees.some((e) => e.name === cooName)) {
|
|
891
|
+
const cooEmployee = {
|
|
892
|
+
name: cooName,
|
|
893
|
+
role: "COO",
|
|
894
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
895
|
+
templateName: DEFAULT_COORDINATOR_TEMPLATE_NAME,
|
|
896
|
+
templateVersion: 1
|
|
897
|
+
};
|
|
898
|
+
employees = addEmployee(employees, cooEmployee);
|
|
899
|
+
await saveEmployees(employees, EMPLOYEES_PATH);
|
|
900
|
+
}
|
|
901
|
+
const cooIdentityContent = getIdentityTemplate("coo");
|
|
902
|
+
if (cooIdentityContent) {
|
|
903
|
+
const cooIdPath = identityPath(cooName);
|
|
904
|
+
mkdirSync(path2.dirname(cooIdPath), { recursive: true });
|
|
905
|
+
const replaced = cooIdentityContent.replace(/agent_id:\s*exe/g, `agent_id: ${cooName}`).replace(/\$\{agent_id\}/g, cooName);
|
|
906
|
+
atomicWriteSync(cooIdPath, replaced);
|
|
907
|
+
}
|
|
908
|
+
registerBinSymlinks(cooName);
|
|
909
|
+
createdEmployees.push({ name: cooName, role: "COO" });
|
|
910
|
+
state.completedSteps.push(6);
|
|
911
|
+
saveSetupState(state);
|
|
912
|
+
} else {
|
|
913
|
+
log("Step 6 already complete \u2014 skipping.");
|
|
914
|
+
const roster = await loadEmployees(EMPLOYEES_PATH).catch(() => []);
|
|
915
|
+
const existingCoo = roster.find((e) => isCoordinatorRole(e.role));
|
|
916
|
+
if (existingCoo) cooName = existingCoo.name;
|
|
917
|
+
}
|
|
918
|
+
log("");
|
|
919
|
+
if (!state.completedSteps.includes(7)) {
|
|
920
|
+
let license;
|
|
921
|
+
try {
|
|
922
|
+
license = await checkLicense();
|
|
923
|
+
} catch {
|
|
924
|
+
license = { valid: true, plan: "free", email: "", expiresAt: null, deviceLimit: 1, employeeLimit: 2, memoryLimit: 1e3 };
|
|
925
|
+
}
|
|
926
|
+
let isLicensed = license.valid && license.plan !== "free";
|
|
927
|
+
if (!isLicensed) {
|
|
928
|
+
let licenseInput = await askOptional("Hire other employees with your Exe OS license key, or press Enter to continue as a free user (COO only): ", "EXE_LICENSE_KEY");
|
|
929
|
+
if (licenseInput && !licenseInput.startsWith("exe_sk_")) {
|
|
930
|
+
if (nonInteractive) {
|
|
931
|
+
log("EXE_LICENSE_KEY doesn't look like a license key (should start with exe_sk_). Skipping.");
|
|
932
|
+
licenseInput = "";
|
|
933
|
+
} else {
|
|
934
|
+
log("That doesn't look like a license key (should start with exe_sk_).");
|
|
935
|
+
licenseInput = await ask(rl, "Try again (or press Enter to skip): ", true);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
if (licenseInput && licenseInput.startsWith("exe_sk_")) {
|
|
939
|
+
saveLicense(licenseInput);
|
|
940
|
+
mirrorLicenseKey(licenseInput);
|
|
941
|
+
try {
|
|
942
|
+
const result = await validateLicense(licenseInput);
|
|
943
|
+
if (result.valid && result.plan !== "free") {
|
|
944
|
+
isLicensed = true;
|
|
945
|
+
const planName = result.plan === "pro" ? "Solopreneur" : result.plan.charAt(0).toUpperCase() + result.plan.slice(1);
|
|
946
|
+
log(`License activated. Plan: ${planName}`);
|
|
947
|
+
} else if (!result.valid) {
|
|
948
|
+
log("That license key is invalid or expired.");
|
|
949
|
+
log("Get a new key at askexe.com.");
|
|
950
|
+
} else {
|
|
951
|
+
log("Key saved for cloud sync, but specialists require a paid plan.");
|
|
952
|
+
log("Upgrade at askexe.com when you're ready.");
|
|
953
|
+
}
|
|
954
|
+
} catch {
|
|
955
|
+
isLicensed = true;
|
|
956
|
+
log("Couldn't reach the license server \u2014 key saved, specialists enabled.");
|
|
957
|
+
log(" Your key will be re-validated when connected.");
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
if (!isLicensed) {
|
|
962
|
+
log("");
|
|
963
|
+
log("You're all set. You're starting in Phase 1: COO / Chief of Staff mode.");
|
|
964
|
+
log("Your COO will learn your company context first. You can unlock executives later anytime.");
|
|
965
|
+
log("When you're ready for specialists, add a license key at askexe.com.");
|
|
966
|
+
log("");
|
|
967
|
+
log(`Type your COO's launcher to start: ${cooName}1`);
|
|
968
|
+
state.completedSteps.push(7, 8);
|
|
969
|
+
saveSetupState(state);
|
|
970
|
+
} else {
|
|
971
|
+
state.completedSteps.push(7);
|
|
972
|
+
saveSetupState(state);
|
|
973
|
+
}
|
|
974
|
+
} else {
|
|
975
|
+
log("Step 7 already complete \u2014 skipping.");
|
|
976
|
+
}
|
|
977
|
+
if (!state.completedSteps.includes(8)) {
|
|
978
|
+
let employees = await loadEmployees(EMPLOYEES_PATH).catch(() => []);
|
|
979
|
+
log("=== Orchestration Phase ===");
|
|
980
|
+
log("");
|
|
981
|
+
log("Recommended default: Phase 1 \u2014 COO / Chief of Staff mode.");
|
|
982
|
+
log("Start with one-on-one conversations so your COO learns your company,");
|
|
983
|
+
log("vision, priorities, constraints, and operating style before delegating.");
|
|
984
|
+
log("");
|
|
985
|
+
log("You can jump ahead now if you want. This is a suggestion, not a blocker.");
|
|
986
|
+
log("");
|
|
987
|
+
log(" Phase 1: COO only \u2014 build company context first");
|
|
988
|
+
log(" Phase 2: Executive bench \u2014 add CTO/CMO for repeated domain work");
|
|
989
|
+
log(" Phase 3: Parallel org \u2014 specialists execute in parallel with reviews");
|
|
990
|
+
log("");
|
|
991
|
+
const unlockExecutives = (await askOrEnv("Unlock Phase 2 executives now? (y/N): ", void 0, "n")).toLowerCase() === "y";
|
|
992
|
+
const { setOrchestrationPhase } = await import("./orchestration-phase-EMDEZHIU.js");
|
|
993
|
+
if (!unlockExecutives) {
|
|
994
|
+
await setOrchestrationPhase("phase_1_coo", "setup-wizard");
|
|
995
|
+
log("");
|
|
996
|
+
log("Starting in Phase 1. Your executive templates are available when you're ready.");
|
|
997
|
+
log("Later: run `exe-os org unlock executives` to move to Phase 2.");
|
|
998
|
+
state.completedSteps.push(8);
|
|
999
|
+
saveSetupState(state);
|
|
1000
|
+
} else {
|
|
1001
|
+
await setOrchestrationPhase("phase_2_executives", "setup-wizard");
|
|
1002
|
+
log("");
|
|
1003
|
+
log("Phase 2 enabled. Let's name your executive bench.");
|
|
1004
|
+
log("");
|
|
1005
|
+
const ctoTemplate = getTemplateByRole("CTO");
|
|
1006
|
+
const ctoDefault = ctoTemplate?.name ?? "cto";
|
|
1007
|
+
log(` CTO \u2014 engineering, architecture, code reviews (default: ${ctoDefault})`);
|
|
1008
|
+
const cmoTemplate = getTemplateByRole("CMO");
|
|
1009
|
+
const cmoDefault = cmoTemplate?.name ?? "cmo";
|
|
1010
|
+
log(` CMO \u2014 design, brand, content, marketing (default: ${cmoDefault})`);
|
|
1011
|
+
log("");
|
|
1012
|
+
const ctoName = await promptForEmployeeName(`Name your CTO (default: ${ctoDefault}): `, "EXE_CTO_NAME", ctoDefault);
|
|
1013
|
+
if (!employees.some((e) => e.name === ctoName)) {
|
|
1014
|
+
const ctoEmployee = {
|
|
1015
|
+
name: ctoName,
|
|
1016
|
+
role: "CTO",
|
|
1017
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1018
|
+
templateName: ctoDefault,
|
|
1019
|
+
templateVersion: 1
|
|
1020
|
+
};
|
|
1021
|
+
employees = addEmployee(employees, ctoEmployee);
|
|
1022
|
+
await saveEmployees(employees, EMPLOYEES_PATH);
|
|
1023
|
+
}
|
|
1024
|
+
const ctoIdentityContent = getIdentityTemplate("cto");
|
|
1025
|
+
if (ctoIdentityContent) {
|
|
1026
|
+
const ctoIdPath = identityPath(ctoName);
|
|
1027
|
+
mkdirSync(path2.dirname(ctoIdPath), { recursive: true });
|
|
1028
|
+
const replaced = ctoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${ctoName}`).replace(/\$\{agent_id\}/g, ctoName);
|
|
1029
|
+
atomicWriteSync(ctoIdPath, replaced);
|
|
1030
|
+
}
|
|
1031
|
+
registerBinSymlinks(ctoName);
|
|
1032
|
+
createdEmployees.push({ name: ctoName, role: "CTO" });
|
|
1033
|
+
log(`Created ${ctoName} (CTO)`);
|
|
1034
|
+
const cmoName = await promptForEmployeeName(`Name your CMO (default: ${cmoDefault}): `, "EXE_CMO_NAME", cmoDefault);
|
|
1035
|
+
if (!employees.some((e) => e.name === cmoName)) {
|
|
1036
|
+
const cmoEmployee = {
|
|
1037
|
+
name: cmoName,
|
|
1038
|
+
role: "CMO",
|
|
1039
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1040
|
+
templateName: cmoDefault,
|
|
1041
|
+
templateVersion: 1
|
|
1042
|
+
};
|
|
1043
|
+
employees = addEmployee(employees, cmoEmployee);
|
|
1044
|
+
await saveEmployees(employees, EMPLOYEES_PATH);
|
|
1045
|
+
}
|
|
1046
|
+
const cmoIdentityContent = getIdentityTemplate("cmo");
|
|
1047
|
+
if (cmoIdentityContent) {
|
|
1048
|
+
const cmoIdPath = identityPath(cmoName);
|
|
1049
|
+
mkdirSync(path2.dirname(cmoIdPath), { recursive: true });
|
|
1050
|
+
const replaced = cmoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${cmoName}`).replace(/\$\{agent_id\}/g, cmoName);
|
|
1051
|
+
atomicWriteSync(cmoIdPath, replaced);
|
|
1052
|
+
}
|
|
1053
|
+
registerBinSymlinks(cmoName);
|
|
1054
|
+
createdEmployees.push({ name: cmoName, role: "CMO" });
|
|
1055
|
+
log(`Created ${cmoName} (CMO)`);
|
|
1056
|
+
log("");
|
|
1057
|
+
state.completedSteps.push(8);
|
|
1058
|
+
saveSetupState(state);
|
|
1059
|
+
}
|
|
1060
|
+
} else {
|
|
1061
|
+
log("Step 8 already complete \u2014 skipping.");
|
|
1062
|
+
}
|
|
1063
|
+
let pathJustConfigured = false;
|
|
1064
|
+
if (!pairingRosterPulled) {
|
|
1065
|
+
try {
|
|
1066
|
+
const { generateSessionWrappers } = await import("./lib/session-wrappers.js");
|
|
1067
|
+
const pkgRoot = findPackageRoot();
|
|
1068
|
+
if (pkgRoot) {
|
|
1069
|
+
const wrapResult = generateSessionWrappers(pkgRoot);
|
|
1070
|
+
if (wrapResult.created > 0) {
|
|
1071
|
+
log(`Session shortcuts generated (${cooName}1, ${cooName}2, ...)`);
|
|
1072
|
+
}
|
|
1073
|
+
if (wrapResult.pathConfigured) {
|
|
1074
|
+
const binDir = path2.join(os.homedir(), ".exe-os", "bin");
|
|
1075
|
+
process.env.PATH = `${binDir}:${process.env.PATH ?? ""}`;
|
|
1076
|
+
pathJustConfigured = true;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
} catch {
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
if (runInstaller) {
|
|
1083
|
+
log("Installing Claude Code MCP, hooks, launchers, and daemon supervision...");
|
|
1084
|
+
await runInstaller();
|
|
1085
|
+
} else {
|
|
1086
|
+
log("Skipping installer wiring (not provided). Run `exe-os claude install` to finish MCP + hooks setup.");
|
|
1087
|
+
}
|
|
1088
|
+
clearSetupState();
|
|
1089
|
+
log("=== Getting Started ===");
|
|
1090
|
+
log("");
|
|
1091
|
+
log(` cd into any project folder, then type \`${cooName}1\` to launch your COO.`);
|
|
1092
|
+
log(` Your COO manages the team \u2014 you talk to them, they coordinate everyone else.`);
|
|
1093
|
+
log("");
|
|
1094
|
+
let version = "";
|
|
1095
|
+
const pkgRoot2 = findPackageRoot();
|
|
1096
|
+
if (pkgRoot2) {
|
|
1097
|
+
try {
|
|
1098
|
+
version = JSON.parse(readFileSync(path2.join(pkgRoot2, "package.json"), "utf-8")).version;
|
|
1099
|
+
} catch {
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
log("");
|
|
1103
|
+
log(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588");
|
|
1104
|
+
log(" \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ");
|
|
1105
|
+
log(" \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588");
|
|
1106
|
+
log(" \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588");
|
|
1107
|
+
log(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588");
|
|
1108
|
+
if (version) log(`${"".padStart(18)}v${version}`);
|
|
1109
|
+
log("");
|
|
1110
|
+
const syncMode = cloudConfig ? "Exe Cloud (E2EE)" : "local-only";
|
|
1111
|
+
let searchMode = "keyword + graph";
|
|
1112
|
+
if (!skipModel) searchMode = "hybrid (vector + keyword + graph)";
|
|
1113
|
+
const boxWidth = 49;
|
|
1114
|
+
const row = (label, value) => {
|
|
1115
|
+
const prefix = ` \u2502 ${label.padEnd(10)}`;
|
|
1116
|
+
const available = boxWidth - 4 - label.padEnd(10).length;
|
|
1117
|
+
const text = value.length > available ? `...${value.slice(-(available - 3))}` : value;
|
|
1118
|
+
return `${prefix}${text.padEnd(available)}\u2502`;
|
|
1119
|
+
};
|
|
1120
|
+
log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
1121
|
+
log(" \u2502 Setup Complete \u2502");
|
|
1122
|
+
log(" \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
1123
|
+
log(row("Database", config.dbPath.replace(os.homedir(), "~")));
|
|
1124
|
+
log(row("Sync", syncMode));
|
|
1125
|
+
log(row("Encryption", "SQLCipher + AES-256-GCM"));
|
|
1126
|
+
log(row("Search", searchMode));
|
|
1127
|
+
if (createdEmployees.length > 0) {
|
|
1128
|
+
log(` \u2502 Team ${createdEmployees.length} employee${createdEmployees.length > 1 ? "s" : ""}${" ".repeat(createdEmployees.length >= 10 ? 22 : 23)}\u2502`);
|
|
1129
|
+
}
|
|
1130
|
+
log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
1131
|
+
if (createdEmployees.length > 0) {
|
|
1132
|
+
log("");
|
|
1133
|
+
const maxNameLen = Math.max(...createdEmployees.map((e) => e.name.length), 4);
|
|
1134
|
+
for (const emp of createdEmployees) {
|
|
1135
|
+
const badge = emp.name === cooName ? " \u2605" : " ";
|
|
1136
|
+
log(` ${badge} ${emp.name.padEnd(maxNameLen)} ${emp.role}`);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
log("");
|
|
1140
|
+
log(" Next: cd into a project folder, then run:");
|
|
1141
|
+
log(` $ ${cooName}1`);
|
|
1142
|
+
if (pathJustConfigured) {
|
|
1143
|
+
const shell = process.env.SHELL ?? "/bin/zsh";
|
|
1144
|
+
const rcFile = shell.includes("bash") ? "~/.bashrc" : "~/.zshrc";
|
|
1145
|
+
log("");
|
|
1146
|
+
log(` (Run \`source ${rcFile}\` first, or open a new terminal)`);
|
|
1147
|
+
}
|
|
1148
|
+
log("");
|
|
1149
|
+
process.removeListener("SIGINT", sigintHandler);
|
|
1150
|
+
} finally {
|
|
1151
|
+
rl.close();
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
export {
|
|
1156
|
+
validateModel,
|
|
1157
|
+
runSetupWizard
|
|
1158
|
+
};
|