@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,855 @@
|
|
|
1
|
+
import "../../chunk-MLKGABMK.js";
|
|
2
|
+
|
|
3
|
+
// src/services/codex-reviewd/config.ts
|
|
4
|
+
import { readFileSync } from "fs";
|
|
5
|
+
var DEFAULTS = {
|
|
6
|
+
port: 9300,
|
|
7
|
+
concurrency: 2,
|
|
8
|
+
defaultTimeoutMs: 5 * 60 * 1e3,
|
|
9
|
+
pollIntervalMs: 2e3,
|
|
10
|
+
repos: {},
|
|
11
|
+
defaultPrompt: "default-review"
|
|
12
|
+
};
|
|
13
|
+
function loadConfig(configPath) {
|
|
14
|
+
const filePath = configPath ?? process.env.CODEX_REVIEWD_CONFIG;
|
|
15
|
+
if (!filePath) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
"CODEX_REVIEWD_CONFIG environment variable is not set. Provide a path to the daemon configuration JSON file."
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
let raw;
|
|
21
|
+
try {
|
|
22
|
+
raw = readFileSync(filePath, "utf-8");
|
|
23
|
+
} catch (err) {
|
|
24
|
+
throw new Error(`Failed to read config file at ${filePath}: ${err.message}`);
|
|
25
|
+
}
|
|
26
|
+
let parsed;
|
|
27
|
+
try {
|
|
28
|
+
parsed = JSON.parse(raw);
|
|
29
|
+
} catch (err) {
|
|
30
|
+
throw new Error(`Failed to parse config file at ${filePath}: ${err.message}`);
|
|
31
|
+
}
|
|
32
|
+
if (!parsed.webhookSecret || typeof parsed.webhookSecret !== "string") {
|
|
33
|
+
throw new Error("Config missing required field: webhookSecret");
|
|
34
|
+
}
|
|
35
|
+
if (!parsed.githubAppId || typeof parsed.githubAppId !== "string") {
|
|
36
|
+
throw new Error("Config missing required field: githubAppId");
|
|
37
|
+
}
|
|
38
|
+
if (!parsed.githubAppPrivateKeyPath || typeof parsed.githubAppPrivateKeyPath !== "string") {
|
|
39
|
+
throw new Error("Config missing required field: githubAppPrivateKeyPath");
|
|
40
|
+
}
|
|
41
|
+
if (!parsed.codexApiKeyPath || typeof parsed.codexApiKeyPath !== "string") {
|
|
42
|
+
throw new Error("Config missing required field: codexApiKeyPath");
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
...DEFAULTS,
|
|
46
|
+
...parsed,
|
|
47
|
+
port: typeof parsed.port === "number" ? parsed.port : DEFAULTS.port,
|
|
48
|
+
concurrency: typeof parsed.concurrency === "number" ? parsed.concurrency : DEFAULTS.concurrency,
|
|
49
|
+
defaultTimeoutMs: typeof parsed.defaultTimeoutMs === "number" ? parsed.defaultTimeoutMs : DEFAULTS.defaultTimeoutMs,
|
|
50
|
+
pollIntervalMs: typeof parsed.pollIntervalMs === "number" ? parsed.pollIntervalMs : DEFAULTS.pollIntervalMs,
|
|
51
|
+
repos: parsed.repos && typeof parsed.repos === "object" ? parsed.repos : DEFAULTS.repos,
|
|
52
|
+
defaultPrompt: typeof parsed.defaultPrompt === "string" ? parsed.defaultPrompt : DEFAULTS.defaultPrompt,
|
|
53
|
+
webhookSecret: parsed.webhookSecret,
|
|
54
|
+
githubAppId: parsed.githubAppId,
|
|
55
|
+
githubAppPrivateKeyPath: parsed.githubAppPrivateKeyPath,
|
|
56
|
+
codexApiKeyPath: parsed.codexApiKeyPath
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/services/codex-reviewd/github.ts
|
|
61
|
+
import { createPrivateKey, createSign } from "crypto";
|
|
62
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
63
|
+
var GITHUB_API = "https://api.github.com";
|
|
64
|
+
function createAppJwt(appId, privateKeyPem) {
|
|
65
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
66
|
+
const header = Buffer.from(JSON.stringify({ alg: "RS256", typ: "JWT" })).toString("base64url");
|
|
67
|
+
const payload = Buffer.from(JSON.stringify({
|
|
68
|
+
iat: now - 60,
|
|
69
|
+
// issued 60s ago (clock skew buffer)
|
|
70
|
+
exp: now + 600,
|
|
71
|
+
// expires in 10 minutes
|
|
72
|
+
iss: appId
|
|
73
|
+
})).toString("base64url");
|
|
74
|
+
const signingInput = `${header}.${payload}`;
|
|
75
|
+
const key = createPrivateKey(privateKeyPem);
|
|
76
|
+
const signer = createSign("RSA-SHA256");
|
|
77
|
+
signer.update(signingInput);
|
|
78
|
+
const signature = signer.sign(key, "base64url");
|
|
79
|
+
return `${signingInput}.${signature}`;
|
|
80
|
+
}
|
|
81
|
+
var GitHubClient = class {
|
|
82
|
+
appId;
|
|
83
|
+
privateKeyPem;
|
|
84
|
+
tokenCache = /* @__PURE__ */ new Map();
|
|
85
|
+
constructor(opts) {
|
|
86
|
+
this.appId = opts.appId;
|
|
87
|
+
this.privateKeyPem = readFileSync2(opts.privateKeyPath, "utf-8");
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get an installation access token, using cache when possible.
|
|
91
|
+
* Tokens are cached until 5 minutes before expiry.
|
|
92
|
+
*/
|
|
93
|
+
async getInstallationToken(installationId) {
|
|
94
|
+
const cached = this.tokenCache.get(installationId);
|
|
95
|
+
if (cached && cached.expiresAt > Date.now() + 5 * 60 * 1e3) {
|
|
96
|
+
return cached.token;
|
|
97
|
+
}
|
|
98
|
+
const jwt = createAppJwt(this.appId, this.privateKeyPem);
|
|
99
|
+
const res = await fetch(`${GITHUB_API}/app/installations/${installationId}/access_tokens`, {
|
|
100
|
+
method: "POST",
|
|
101
|
+
headers: {
|
|
102
|
+
Authorization: `Bearer ${jwt}`,
|
|
103
|
+
Accept: "application/vnd.github+json",
|
|
104
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
if (!res.ok) {
|
|
108
|
+
const body = await res.text();
|
|
109
|
+
throw new Error(`Failed to get installation token (${res.status}): ${body}`);
|
|
110
|
+
}
|
|
111
|
+
const data = await res.json();
|
|
112
|
+
this.tokenCache.set(installationId, {
|
|
113
|
+
token: data.token,
|
|
114
|
+
expiresAt: new Date(data.expires_at).getTime()
|
|
115
|
+
});
|
|
116
|
+
return data.token;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Create a check run on a commit.
|
|
120
|
+
* Used to report "codex/build-my-review" status.
|
|
121
|
+
*/
|
|
122
|
+
async createCheckRun(params) {
|
|
123
|
+
const token = await this.getInstallationToken(params.installationId);
|
|
124
|
+
const res = await fetch(`${GITHUB_API}/repos/${params.owner}/${params.repo}/check-runs`, {
|
|
125
|
+
method: "POST",
|
|
126
|
+
headers: {
|
|
127
|
+
Authorization: `token ${token}`,
|
|
128
|
+
Accept: "application/vnd.github+json",
|
|
129
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
130
|
+
"Content-Type": "application/json"
|
|
131
|
+
},
|
|
132
|
+
body: JSON.stringify({
|
|
133
|
+
name: "codex/build-my-review",
|
|
134
|
+
head_sha: params.headSha,
|
|
135
|
+
status: params.status,
|
|
136
|
+
...params.conclusion ? { conclusion: params.conclusion } : {},
|
|
137
|
+
output: {
|
|
138
|
+
title: params.title,
|
|
139
|
+
summary: params.summary,
|
|
140
|
+
...params.text ? { text: params.text } : {}
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
});
|
|
144
|
+
if (!res.ok) {
|
|
145
|
+
const body = await res.text();
|
|
146
|
+
throw new Error(`Failed to create check run (${res.status}): ${body}`);
|
|
147
|
+
}
|
|
148
|
+
return await res.json();
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Update an existing check run.
|
|
152
|
+
*/
|
|
153
|
+
async updateCheckRun(params) {
|
|
154
|
+
const token = await this.getInstallationToken(params.installationId);
|
|
155
|
+
const res = await fetch(`${GITHUB_API}/repos/${params.owner}/${params.repo}/check-runs/${params.checkRunId}`, {
|
|
156
|
+
method: "PATCH",
|
|
157
|
+
headers: {
|
|
158
|
+
Authorization: `token ${token}`,
|
|
159
|
+
Accept: "application/vnd.github+json",
|
|
160
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
161
|
+
"Content-Type": "application/json"
|
|
162
|
+
},
|
|
163
|
+
body: JSON.stringify({
|
|
164
|
+
status: params.status,
|
|
165
|
+
...params.conclusion ? { conclusion: params.conclusion } : {},
|
|
166
|
+
output: {
|
|
167
|
+
title: params.title,
|
|
168
|
+
summary: params.summary,
|
|
169
|
+
...params.text ? { text: params.text } : {}
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
});
|
|
173
|
+
if (!res.ok) {
|
|
174
|
+
const body = await res.text();
|
|
175
|
+
throw new Error(`Failed to update check run (${res.status}): ${body}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Post a comment on a PR (via the issues API).
|
|
180
|
+
*/
|
|
181
|
+
async postPRComment(params) {
|
|
182
|
+
const token = await this.getInstallationToken(params.installationId);
|
|
183
|
+
const res = await fetch(`${GITHUB_API}/repos/${params.owner}/${params.repo}/issues/${params.prNumber}/comments`, {
|
|
184
|
+
method: "POST",
|
|
185
|
+
headers: {
|
|
186
|
+
Authorization: `token ${token}`,
|
|
187
|
+
Accept: "application/vnd.github+json",
|
|
188
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
189
|
+
"Content-Type": "application/json"
|
|
190
|
+
},
|
|
191
|
+
body: JSON.stringify({ body: params.body })
|
|
192
|
+
});
|
|
193
|
+
if (!res.ok) {
|
|
194
|
+
const body = await res.text();
|
|
195
|
+
throw new Error(`Failed to post PR comment (${res.status}): ${body}`);
|
|
196
|
+
}
|
|
197
|
+
return await res.json();
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// src/services/codex-reviewd/queue.ts
|
|
202
|
+
var ReviewQueue = class {
|
|
203
|
+
jobs = /* @__PURE__ */ new Map();
|
|
204
|
+
pending = [];
|
|
205
|
+
runningCount = 0;
|
|
206
|
+
concurrency;
|
|
207
|
+
maxRetries;
|
|
208
|
+
nextId = 1;
|
|
209
|
+
constructor(opts) {
|
|
210
|
+
this.concurrency = opts.concurrency;
|
|
211
|
+
this.maxRetries = opts.maxRetries ?? 2;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Add a new review job to the queue.
|
|
215
|
+
* Returns the job ID.
|
|
216
|
+
*/
|
|
217
|
+
enqueue(params) {
|
|
218
|
+
const id = `review-${this.nextId++}`;
|
|
219
|
+
const job = {
|
|
220
|
+
id,
|
|
221
|
+
repo: params.repo,
|
|
222
|
+
prNumber: params.prNumber,
|
|
223
|
+
headSha: params.headSha,
|
|
224
|
+
baseSha: params.baseSha,
|
|
225
|
+
baseBranch: params.baseBranch,
|
|
226
|
+
headBranch: params.headBranch,
|
|
227
|
+
prTitle: params.prTitle,
|
|
228
|
+
prBody: params.prBody,
|
|
229
|
+
installationId: params.installationId,
|
|
230
|
+
status: "pending",
|
|
231
|
+
result: null,
|
|
232
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
233
|
+
startedAt: null,
|
|
234
|
+
completedAt: null,
|
|
235
|
+
retries: 0,
|
|
236
|
+
error: null
|
|
237
|
+
};
|
|
238
|
+
this.jobs.set(id, job);
|
|
239
|
+
this.pending.push(id);
|
|
240
|
+
return id;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Dequeue the next pending job if concurrency allows.
|
|
244
|
+
* Returns null if no jobs available or at capacity.
|
|
245
|
+
*/
|
|
246
|
+
dequeue() {
|
|
247
|
+
if (this.runningCount >= this.concurrency) return null;
|
|
248
|
+
if (this.pending.length === 0) return null;
|
|
249
|
+
const id = this.pending.shift();
|
|
250
|
+
const job = this.jobs.get(id);
|
|
251
|
+
if (!job) return null;
|
|
252
|
+
job.status = "running";
|
|
253
|
+
job.startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
254
|
+
this.runningCount++;
|
|
255
|
+
return job;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Mark a job as successfully completed.
|
|
259
|
+
*/
|
|
260
|
+
complete(id, result) {
|
|
261
|
+
const job = this.jobs.get(id);
|
|
262
|
+
if (!job) return;
|
|
263
|
+
job.status = "complete";
|
|
264
|
+
job.result = result;
|
|
265
|
+
job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
266
|
+
if (job.status === "complete") {
|
|
267
|
+
this.runningCount = Math.max(0, this.runningCount - 1);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Mark a job as failed. Re-enqueues if retries remain.
|
|
272
|
+
* Returns true if the job will be retried.
|
|
273
|
+
*/
|
|
274
|
+
fail(id, error) {
|
|
275
|
+
const job = this.jobs.get(id);
|
|
276
|
+
if (!job) return false;
|
|
277
|
+
this.runningCount = Math.max(0, this.runningCount - 1);
|
|
278
|
+
job.retries++;
|
|
279
|
+
job.error = error;
|
|
280
|
+
if (job.retries <= this.maxRetries) {
|
|
281
|
+
job.status = "pending";
|
|
282
|
+
job.startedAt = null;
|
|
283
|
+
this.pending.push(id);
|
|
284
|
+
return true;
|
|
285
|
+
}
|
|
286
|
+
job.status = "failed";
|
|
287
|
+
job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Get a job by ID.
|
|
292
|
+
*/
|
|
293
|
+
get(id) {
|
|
294
|
+
return this.jobs.get(id);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Check if a review for this repo+PR+SHA is already queued or running.
|
|
298
|
+
* Prevents duplicate reviews for the same commit.
|
|
299
|
+
*/
|
|
300
|
+
isDuplicate(repo, prNumber, headSha) {
|
|
301
|
+
for (const job of this.jobs.values()) {
|
|
302
|
+
if (job.repo === repo && job.prNumber === prNumber && job.headSha === headSha && (job.status === "pending" || job.status === "running")) {
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Get count of jobs by status.
|
|
310
|
+
*/
|
|
311
|
+
stats() {
|
|
312
|
+
const counts = { pending: 0, running: 0, complete: 0, failed: 0 };
|
|
313
|
+
for (const job of this.jobs.values()) {
|
|
314
|
+
counts[job.status]++;
|
|
315
|
+
}
|
|
316
|
+
return counts;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Number of currently running jobs.
|
|
320
|
+
*/
|
|
321
|
+
get activeCount() {
|
|
322
|
+
return this.runningCount;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Number of pending jobs.
|
|
326
|
+
*/
|
|
327
|
+
get pendingCount() {
|
|
328
|
+
return this.pending.length;
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
// src/services/codex-reviewd/server.ts
|
|
333
|
+
import { createHmac, timingSafeEqual } from "crypto";
|
|
334
|
+
import { createServer } from "http";
|
|
335
|
+
function readBody(req) {
|
|
336
|
+
return new Promise((resolve, reject) => {
|
|
337
|
+
const chunks = [];
|
|
338
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
339
|
+
req.on("end", () => resolve(Buffer.concat(chunks)));
|
|
340
|
+
req.on("error", reject);
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
function validateSignature(body, secret, signatureHeader) {
|
|
344
|
+
if (!signatureHeader) return false;
|
|
345
|
+
const expected = "sha256=" + createHmac("sha256", secret).update(body).digest("hex");
|
|
346
|
+
if (signatureHeader.length !== expected.length) return false;
|
|
347
|
+
try {
|
|
348
|
+
return timingSafeEqual(
|
|
349
|
+
Buffer.from(signatureHeader, "utf-8"),
|
|
350
|
+
Buffer.from(expected, "utf-8")
|
|
351
|
+
);
|
|
352
|
+
} catch {
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
function isForkPR(event) {
|
|
357
|
+
return event.pull_request.head.repo.full_name !== event.pull_request.base.repo.full_name;
|
|
358
|
+
}
|
|
359
|
+
function createWebhookServer(opts) {
|
|
360
|
+
const { port, webhookSecret, queue } = opts;
|
|
361
|
+
const server = createServer(async (req, res) => {
|
|
362
|
+
if (req.method === "GET" && req.url === "/health") {
|
|
363
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
364
|
+
res.end(JSON.stringify({
|
|
365
|
+
status: "ok",
|
|
366
|
+
stats: queue.stats()
|
|
367
|
+
}));
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
if (req.method === "POST" && req.url === "/webhook") {
|
|
371
|
+
let body;
|
|
372
|
+
try {
|
|
373
|
+
body = await readBody(req);
|
|
374
|
+
} catch {
|
|
375
|
+
res.writeHead(400);
|
|
376
|
+
res.end("Bad request: could not read body");
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
const signature = req.headers["x-hub-signature-256"];
|
|
380
|
+
if (!validateSignature(body, webhookSecret, signature)) {
|
|
381
|
+
res.writeHead(401);
|
|
382
|
+
res.end("Unauthorized: invalid signature");
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
const eventType = req.headers["x-github-event"];
|
|
386
|
+
if (eventType !== "pull_request") {
|
|
387
|
+
res.writeHead(200);
|
|
388
|
+
res.end("Ignored: not a pull_request event");
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
let event;
|
|
392
|
+
try {
|
|
393
|
+
event = JSON.parse(body.toString("utf-8"));
|
|
394
|
+
} catch {
|
|
395
|
+
res.writeHead(400);
|
|
396
|
+
res.end("Bad request: invalid JSON");
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
const ACCEPTED_ACTIONS = /* @__PURE__ */ new Set(["opened", "synchronize", "reopened", "ready_for_review"]);
|
|
400
|
+
if (!ACCEPTED_ACTIONS.has(event.action)) {
|
|
401
|
+
res.writeHead(200);
|
|
402
|
+
res.end(`Ignored: action "${event.action}"`);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
if (isForkPR(event)) {
|
|
406
|
+
res.writeHead(200);
|
|
407
|
+
res.end("Skipped: fork PR");
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
if (!event.installation?.id) {
|
|
411
|
+
res.writeHead(400);
|
|
412
|
+
res.end("Bad request: missing installation ID");
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
const repoName = event.pull_request.base.repo.full_name;
|
|
416
|
+
const headSha = event.pull_request.head.sha;
|
|
417
|
+
if (queue.isDuplicate(repoName, event.number, headSha)) {
|
|
418
|
+
res.writeHead(200);
|
|
419
|
+
res.end("Duplicate: review already queued for this commit");
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const jobId = queue.enqueue({
|
|
423
|
+
repo: repoName,
|
|
424
|
+
prNumber: event.number,
|
|
425
|
+
headSha,
|
|
426
|
+
baseSha: event.pull_request.base.sha,
|
|
427
|
+
baseBranch: event.pull_request.base.ref,
|
|
428
|
+
headBranch: event.pull_request.head.ref,
|
|
429
|
+
prTitle: event.pull_request.title,
|
|
430
|
+
prBody: event.pull_request.body ?? void 0,
|
|
431
|
+
installationId: event.installation.id
|
|
432
|
+
});
|
|
433
|
+
console.log(`[codex-reviewd] Enqueued job ${jobId}: ${repoName}#${event.number} (${headSha.slice(0, 7)})`);
|
|
434
|
+
res.writeHead(202, { "Content-Type": "application/json" });
|
|
435
|
+
res.end(JSON.stringify({ jobId, status: "queued" }));
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
res.writeHead(404);
|
|
439
|
+
res.end("Not found");
|
|
440
|
+
});
|
|
441
|
+
server.listen(port, () => {
|
|
442
|
+
console.log(`[codex-reviewd] Webhook server listening on port ${port}`);
|
|
443
|
+
});
|
|
444
|
+
return server;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// src/services/codex-reviewd/worker.ts
|
|
448
|
+
import { spawn } from "child_process";
|
|
449
|
+
import { mkdtempSync, readFileSync as readFileSync3, rmSync } from "fs";
|
|
450
|
+
import { tmpdir } from "os";
|
|
451
|
+
import { join } from "path";
|
|
452
|
+
|
|
453
|
+
// src/services/codex-reviewd/prompts.ts
|
|
454
|
+
var defaultReview = {
|
|
455
|
+
name: "default-review",
|
|
456
|
+
description: "General-purpose code review prompt",
|
|
457
|
+
render(diff, ctx) {
|
|
458
|
+
return `You are reviewing PR #${ctx.prNumber} in ${ctx.repo} (${ctx.headBranch} -> ${ctx.baseBranch}).
|
|
459
|
+
${ctx.prTitle ? `PR Title: ${ctx.prTitle}` : ""}
|
|
460
|
+
|
|
461
|
+
Review this diff for:
|
|
462
|
+
1. **Correctness bugs** \u2014 logic errors, off-by-ones, null/undefined mishandling, race conditions
|
|
463
|
+
2. **Security issues** \u2014 injection, auth bypass, secret leakage, unsafe deserialization
|
|
464
|
+
3. **Performance** \u2014 O(n\xB2) where O(n) is possible, missing indexes, unbounded allocations
|
|
465
|
+
4. **Maintainability** \u2014 dead code, unclear naming, missing error handling
|
|
466
|
+
|
|
467
|
+
Rules:
|
|
468
|
+
- Be specific: cite file and line numbers from the diff
|
|
469
|
+
- Skip style/formatting nits \u2014 linters handle those
|
|
470
|
+
- If the diff is clean, say "LGTM \u2014 no issues found" and nothing else
|
|
471
|
+
- Categorize each finding as [CRITICAL], [WARNING], or [SUGGESTION]
|
|
472
|
+
|
|
473
|
+
Diff:
|
|
474
|
+
\`\`\`diff
|
|
475
|
+
${diff}
|
|
476
|
+
\`\`\``;
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
var exeOsReview = {
|
|
480
|
+
name: "exe-os-review",
|
|
481
|
+
description: "exe-os specific review with ESM/security/architecture checks",
|
|
482
|
+
render(diff, ctx) {
|
|
483
|
+
return `You are reviewing PR #${ctx.prNumber} in ${ctx.repo} (${ctx.headBranch} -> ${ctx.baseBranch}).
|
|
484
|
+
${ctx.prTitle ? `PR Title: ${ctx.prTitle}` : ""}
|
|
485
|
+
|
|
486
|
+
This is the exe-os repository \u2014 an AI employee operating system with local-first encrypted storage.
|
|
487
|
+
|
|
488
|
+
Review this diff against exe-os rules:
|
|
489
|
+
|
|
490
|
+
## Security (CRITICAL)
|
|
491
|
+
- No secrets, PII, or API keys in code
|
|
492
|
+
- Auth middleware must be preserved
|
|
493
|
+
- E2EE/local-first: SQLCipher DB never accessed directly; MCP is the ONLY interface
|
|
494
|
+
- Customer data immutability: identities, behaviors, procedures never overwritten
|
|
495
|
+
- External connections must use TLS
|
|
496
|
+
- No require() in ESM files (src/lib/, src/mcp/, src/tui/) \u2014 this has caused 4+ production outages
|
|
497
|
+
|
|
498
|
+
## Deployment
|
|
499
|
+
- Stack manifest images must have SHA256 digests
|
|
500
|
+
- No :latest tags in manifests or compose
|
|
501
|
+
- Compose services must have healthchecks
|
|
502
|
+
- CI must be green on exact commit before merge
|
|
503
|
+
|
|
504
|
+
## Architecture
|
|
505
|
+
- Zero hardcoded employee names \u2014 use role-resolver.ts
|
|
506
|
+
- All queries must filter by session_scope
|
|
507
|
+
- MCP is the only data interface
|
|
508
|
+
|
|
509
|
+
## General
|
|
510
|
+
- Correctness bugs, race conditions, null handling
|
|
511
|
+
- Performance regressions
|
|
512
|
+
- Missing error handling
|
|
513
|
+
|
|
514
|
+
Rules:
|
|
515
|
+
- Be specific: cite file and line numbers from the diff
|
|
516
|
+
- Categorize each finding as [CRITICAL], [WARNING], or [SUGGESTION]
|
|
517
|
+
- If clean, say "LGTM \u2014 no issues found"
|
|
518
|
+
|
|
519
|
+
Diff:
|
|
520
|
+
\`\`\`diff
|
|
521
|
+
${diff}
|
|
522
|
+
\`\`\``;
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
var stackManifestReview = {
|
|
526
|
+
name: "stack-manifest-review",
|
|
527
|
+
description: "Review for deploy/stack-manifests changes",
|
|
528
|
+
render(diff, ctx) {
|
|
529
|
+
return `You are reviewing PR #${ctx.prNumber} in ${ctx.repo} (${ctx.headBranch} -> ${ctx.baseBranch}).
|
|
530
|
+
${ctx.prTitle ? `PR Title: ${ctx.prTitle}` : ""}
|
|
531
|
+
|
|
532
|
+
This diff modifies stack manifests (Docker compose, deployment configs).
|
|
533
|
+
|
|
534
|
+
Review for:
|
|
535
|
+
1. **Image tags** \u2014 MUST use SHA256 digests, NEVER :latest
|
|
536
|
+
2. **Healthchecks** \u2014 every service MUST have a healthcheck
|
|
537
|
+
3. **Secrets** \u2014 no hardcoded credentials, tokens, or API keys
|
|
538
|
+
4. **Resource limits** \u2014 memory/CPU limits should be set
|
|
539
|
+
5. **Network** \u2014 TLS required for external connections
|
|
540
|
+
6. **Volumes** \u2014 persistent data paths must be correct
|
|
541
|
+
7. **Restart policy** \u2014 services should have restart: unless-stopped or always
|
|
542
|
+
|
|
543
|
+
Rules:
|
|
544
|
+
- Be specific: cite exact service names and line numbers
|
|
545
|
+
- Categorize each finding as [CRITICAL], [WARNING], or [SUGGESTION]
|
|
546
|
+
- If clean, say "LGTM \u2014 no issues found"
|
|
547
|
+
|
|
548
|
+
Diff:
|
|
549
|
+
\`\`\`diff
|
|
550
|
+
${diff}
|
|
551
|
+
\`\`\``;
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
var TEMPLATES = /* @__PURE__ */ new Map([
|
|
555
|
+
[defaultReview.name, defaultReview],
|
|
556
|
+
[exeOsReview.name, exeOsReview],
|
|
557
|
+
[stackManifestReview.name, stackManifestReview]
|
|
558
|
+
]);
|
|
559
|
+
function getPromptTemplate(name) {
|
|
560
|
+
return TEMPLATES.get(name) ?? defaultReview;
|
|
561
|
+
}
|
|
562
|
+
function listPromptTemplates() {
|
|
563
|
+
return Array.from(TEMPLATES.keys());
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// src/services/codex-reviewd/worker.ts
|
|
567
|
+
function exec(cmd, args, opts) {
|
|
568
|
+
return new Promise((resolve, reject) => {
|
|
569
|
+
const child = spawn(cmd, args, {
|
|
570
|
+
cwd: opts.cwd,
|
|
571
|
+
env: opts.env ?? process.env,
|
|
572
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
573
|
+
timeout: opts.timeoutMs
|
|
574
|
+
});
|
|
575
|
+
let stdout = "";
|
|
576
|
+
let stderr = "";
|
|
577
|
+
child.stdout.on("data", (chunk) => {
|
|
578
|
+
stdout += chunk.toString();
|
|
579
|
+
});
|
|
580
|
+
child.stderr.on("data", (chunk) => {
|
|
581
|
+
stderr += chunk.toString();
|
|
582
|
+
});
|
|
583
|
+
child.on("close", (code) => {
|
|
584
|
+
if (code === 0) {
|
|
585
|
+
resolve(stdout);
|
|
586
|
+
} else {
|
|
587
|
+
reject(new Error(`Command "${cmd} ${args.join(" ")}" exited with code ${code}: ${stderr}`));
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
child.on("error", reject);
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
var MANIFEST_PATTERNS = [
|
|
594
|
+
/^deploy\/stack-manifests\//,
|
|
595
|
+
/^stack\.release\.json$/,
|
|
596
|
+
/^\.github\/workflows\/release/,
|
|
597
|
+
/^deploy\/docker\//,
|
|
598
|
+
/^deploy\/compose\//
|
|
599
|
+
];
|
|
600
|
+
function shouldUseManifestPrompt(diff) {
|
|
601
|
+
const changedFiles = diff.match(/^diff --git a\/(.+?) b\//gm)?.map((m) => m.replace(/^diff --git a\//, "").replace(/ b\/.*/, "")) ?? [];
|
|
602
|
+
return changedFiles.some((f) => MANIFEST_PATTERNS.some((p) => p.test(f)));
|
|
603
|
+
}
|
|
604
|
+
function determineConclusion(reviewText) {
|
|
605
|
+
if (!reviewText || reviewText.trim() === "LGTM" || reviewText.includes("no significant issues")) {
|
|
606
|
+
return "success";
|
|
607
|
+
}
|
|
608
|
+
if (reviewText.toLowerCase().includes("lgtm")) {
|
|
609
|
+
return "success";
|
|
610
|
+
}
|
|
611
|
+
const blockingPatterns = /\b(CRITICAL|P0|P1|SECURITY|VULNERABILITY|BLOCKED?)\b/i;
|
|
612
|
+
if (blockingPatterns.test(reviewText)) {
|
|
613
|
+
return "failure";
|
|
614
|
+
}
|
|
615
|
+
return "neutral";
|
|
616
|
+
}
|
|
617
|
+
async function processJob(job, config, github) {
|
|
618
|
+
const [owner, repo] = job.repo.split("/");
|
|
619
|
+
const tmpDir = mkdtempSync(join(tmpdir(), "codex-reviewd-"));
|
|
620
|
+
let checkRunId;
|
|
621
|
+
try {
|
|
622
|
+
const checkRun = await github.createCheckRun({
|
|
623
|
+
installationId: job.installationId,
|
|
624
|
+
owner,
|
|
625
|
+
repo,
|
|
626
|
+
headSha: job.headSha,
|
|
627
|
+
status: "in_progress",
|
|
628
|
+
title: "Codex review in progress",
|
|
629
|
+
summary: `Reviewing PR #${job.prNumber}...`
|
|
630
|
+
});
|
|
631
|
+
checkRunId = checkRun.id;
|
|
632
|
+
const cloneUrl = `https://github.com/${job.repo}.git`;
|
|
633
|
+
await exec("git", [
|
|
634
|
+
"clone",
|
|
635
|
+
"--depth=1",
|
|
636
|
+
"--no-tags",
|
|
637
|
+
"--branch",
|
|
638
|
+
job.headBranch,
|
|
639
|
+
cloneUrl,
|
|
640
|
+
tmpDir
|
|
641
|
+
], { timeoutMs: 6e4 });
|
|
642
|
+
await exec("git", [
|
|
643
|
+
"fetch",
|
|
644
|
+
"--depth=1",
|
|
645
|
+
"origin",
|
|
646
|
+
job.baseSha
|
|
647
|
+
], { cwd: tmpDir, timeoutMs: 6e4 });
|
|
648
|
+
const diff = await exec("git", [
|
|
649
|
+
"diff",
|
|
650
|
+
`${job.baseSha}...${job.headSha}`,
|
|
651
|
+
"--"
|
|
652
|
+
], { cwd: tmpDir, timeoutMs: 3e4 });
|
|
653
|
+
if (!diff.trim()) {
|
|
654
|
+
const result2 = "No changes detected in diff.";
|
|
655
|
+
await github.updateCheckRun({
|
|
656
|
+
installationId: job.installationId,
|
|
657
|
+
owner,
|
|
658
|
+
repo,
|
|
659
|
+
checkRunId: checkRun.id,
|
|
660
|
+
status: "completed",
|
|
661
|
+
conclusion: "neutral",
|
|
662
|
+
title: "No changes to review",
|
|
663
|
+
summary: result2
|
|
664
|
+
});
|
|
665
|
+
return result2;
|
|
666
|
+
}
|
|
667
|
+
const repoConfig = config.repos[job.repo];
|
|
668
|
+
let templateName = repoConfig?.prompt ?? config.defaultPrompt;
|
|
669
|
+
if (shouldUseManifestPrompt(diff)) {
|
|
670
|
+
templateName = "stack-manifest-review";
|
|
671
|
+
}
|
|
672
|
+
const template = getPromptTemplate(templateName);
|
|
673
|
+
const prompt = template.render(diff, {
|
|
674
|
+
repo: job.repo,
|
|
675
|
+
prNumber: job.prNumber,
|
|
676
|
+
baseBranch: job.baseBranch,
|
|
677
|
+
headBranch: job.headBranch,
|
|
678
|
+
prTitle: job.prTitle,
|
|
679
|
+
prBody: job.prBody
|
|
680
|
+
});
|
|
681
|
+
const codexApiKey = readFileSync3(config.codexApiKeyPath, "utf-8").trim();
|
|
682
|
+
const timeoutMs = repoConfig?.timeoutMs ?? config.defaultTimeoutMs;
|
|
683
|
+
const childEnv = {
|
|
684
|
+
PATH: process.env.PATH,
|
|
685
|
+
HOME: process.env.HOME,
|
|
686
|
+
CODEX_API_KEY: codexApiKey
|
|
687
|
+
};
|
|
688
|
+
const result = await exec("codex", [
|
|
689
|
+
"exec",
|
|
690
|
+
"--sandbox",
|
|
691
|
+
"read-only",
|
|
692
|
+
"--ephemeral",
|
|
693
|
+
prompt
|
|
694
|
+
], {
|
|
695
|
+
cwd: tmpDir,
|
|
696
|
+
env: childEnv,
|
|
697
|
+
timeoutMs
|
|
698
|
+
});
|
|
699
|
+
const conclusion = determineConclusion(result);
|
|
700
|
+
const titleMap = { success: "LGTM", neutral: "Review findings", failure: "Blocking findings" };
|
|
701
|
+
await github.updateCheckRun({
|
|
702
|
+
installationId: job.installationId,
|
|
703
|
+
owner,
|
|
704
|
+
repo,
|
|
705
|
+
checkRunId: checkRun.id,
|
|
706
|
+
status: "completed",
|
|
707
|
+
conclusion,
|
|
708
|
+
title: titleMap[conclusion],
|
|
709
|
+
summary: result.slice(0, 65535)
|
|
710
|
+
// GitHub API limit
|
|
711
|
+
});
|
|
712
|
+
await github.postPRComment({
|
|
713
|
+
installationId: job.installationId,
|
|
714
|
+
owner,
|
|
715
|
+
repo,
|
|
716
|
+
prNumber: job.prNumber,
|
|
717
|
+
body: `## Codex Code Review
|
|
718
|
+
|
|
719
|
+
${result}
|
|
720
|
+
|
|
721
|
+
---
|
|
722
|
+
*Automated review by codex-reviewd*`
|
|
723
|
+
});
|
|
724
|
+
return result;
|
|
725
|
+
} catch (err) {
|
|
726
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
727
|
+
if (checkRunId) {
|
|
728
|
+
try {
|
|
729
|
+
await github.updateCheckRun({
|
|
730
|
+
installationId: job.installationId,
|
|
731
|
+
owner,
|
|
732
|
+
repo,
|
|
733
|
+
checkRunId,
|
|
734
|
+
status: "completed",
|
|
735
|
+
conclusion: "failure",
|
|
736
|
+
title: "Review failed",
|
|
737
|
+
summary: `codex-reviewd encountered an error:
|
|
738
|
+
|
|
739
|
+
${errorMessage}`.slice(0, 65535)
|
|
740
|
+
});
|
|
741
|
+
} catch (updateErr) {
|
|
742
|
+
console.error("[codex-reviewd] Failed to update check-run on error:", updateErr);
|
|
743
|
+
}
|
|
744
|
+
} else {
|
|
745
|
+
try {
|
|
746
|
+
await github.createCheckRun({
|
|
747
|
+
installationId: job.installationId,
|
|
748
|
+
owner,
|
|
749
|
+
repo,
|
|
750
|
+
headSha: job.headSha,
|
|
751
|
+
status: "completed",
|
|
752
|
+
conclusion: "failure",
|
|
753
|
+
title: "Review failed",
|
|
754
|
+
summary: `codex-reviewd encountered an error:
|
|
755
|
+
|
|
756
|
+
${errorMessage}`.slice(0, 65535)
|
|
757
|
+
});
|
|
758
|
+
} catch (createErr) {
|
|
759
|
+
console.error("[codex-reviewd] Failed to create check-run on error:", createErr);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
throw err;
|
|
763
|
+
} finally {
|
|
764
|
+
try {
|
|
765
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
766
|
+
} catch {
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
function startWorker(opts) {
|
|
771
|
+
const { config, queue, github } = opts;
|
|
772
|
+
let running = true;
|
|
773
|
+
const poll = async () => {
|
|
774
|
+
while (running) {
|
|
775
|
+
const job = queue.dequeue();
|
|
776
|
+
if (job) {
|
|
777
|
+
processJob(job, config, github).then((result) => {
|
|
778
|
+
queue.complete(job.id, result);
|
|
779
|
+
console.log(`[codex-reviewd] Job ${job.id} completed: ${job.repo}#${job.prNumber}`);
|
|
780
|
+
}).catch((err) => {
|
|
781
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
782
|
+
const willRetry = queue.fail(job.id, error);
|
|
783
|
+
console.error(
|
|
784
|
+
`[codex-reviewd] Job ${job.id} failed: ${error}` + (willRetry ? " (will retry)" : " (permanent failure)")
|
|
785
|
+
);
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
await new Promise((resolve) => setTimeout(resolve, config.pollIntervalMs));
|
|
789
|
+
}
|
|
790
|
+
};
|
|
791
|
+
poll().catch((err) => {
|
|
792
|
+
console.error("[codex-reviewd] Worker loop crashed:", err);
|
|
793
|
+
});
|
|
794
|
+
return {
|
|
795
|
+
stop() {
|
|
796
|
+
running = false;
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// src/services/codex-reviewd/index.ts
|
|
802
|
+
function startDaemon(configPath) {
|
|
803
|
+
const config = loadConfig(configPath);
|
|
804
|
+
const port = Number(process.env.CODEX_REVIEWD_PORT) || config.port;
|
|
805
|
+
const queue = new ReviewQueue({
|
|
806
|
+
concurrency: config.concurrency
|
|
807
|
+
});
|
|
808
|
+
const github = new GitHubClient({
|
|
809
|
+
appId: config.githubAppId,
|
|
810
|
+
privateKeyPath: config.githubAppPrivateKeyPath
|
|
811
|
+
});
|
|
812
|
+
const server = createWebhookServer({
|
|
813
|
+
port,
|
|
814
|
+
webhookSecret: config.webhookSecret,
|
|
815
|
+
queue
|
|
816
|
+
});
|
|
817
|
+
const worker = startWorker({
|
|
818
|
+
config,
|
|
819
|
+
queue,
|
|
820
|
+
github
|
|
821
|
+
});
|
|
822
|
+
console.log(`[codex-reviewd] Daemon started (port=${port}, concurrency=${config.concurrency})`);
|
|
823
|
+
const stop = async () => {
|
|
824
|
+
console.log("[codex-reviewd] Shutting down...");
|
|
825
|
+
worker.stop();
|
|
826
|
+
await new Promise((resolve) => {
|
|
827
|
+
server.close(() => resolve());
|
|
828
|
+
});
|
|
829
|
+
console.log("[codex-reviewd] Shutdown complete.");
|
|
830
|
+
};
|
|
831
|
+
const onSignal = () => {
|
|
832
|
+
stop().then(() => process.exit(0)).catch(() => process.exit(1));
|
|
833
|
+
};
|
|
834
|
+
process.on("SIGTERM", onSignal);
|
|
835
|
+
process.on("SIGINT", onSignal);
|
|
836
|
+
return { stop };
|
|
837
|
+
}
|
|
838
|
+
var isMain = process.argv[1]?.endsWith("codex-reviewd/index.js") || process.argv[1]?.endsWith("codex-reviewd/index.ts");
|
|
839
|
+
if (isMain) {
|
|
840
|
+
startDaemon();
|
|
841
|
+
}
|
|
842
|
+
export {
|
|
843
|
+
GitHubClient,
|
|
844
|
+
ReviewQueue,
|
|
845
|
+
createWebhookServer,
|
|
846
|
+
determineConclusion,
|
|
847
|
+
getPromptTemplate,
|
|
848
|
+
isForkPR,
|
|
849
|
+
listPromptTemplates,
|
|
850
|
+
loadConfig,
|
|
851
|
+
shouldUseManifestPrompt,
|
|
852
|
+
startDaemon,
|
|
853
|
+
startWorker,
|
|
854
|
+
validateSignature
|
|
855
|
+
};
|