@askexenow/exe-os 0.9.384 → 0.9.389
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.askexe-control-plane.example +6 -0
- package/deploy/compose/.env.customer.example +1 -1
- package/deploy/compose/.env.example +1 -1
- package/deploy/compose/docker-compose.yml +16 -0
- package/deploy/compose/generate-env.ts +1 -1
- package/deploy/compose/sso-edge/sso-redirect.conf +18 -3
- package/deploy/stack-manifests/v0.9.json +1160 -1
- package/dist/.dist-verified.json +3 -3
- package/dist/{active-agent-F5V4E4UL.js → active-agent-RZ24KSJN.js} +8 -6
- package/dist/{active-agent-YTBB4ZQM.js → active-agent-YWSWPIEA.js} +8 -6
- package/dist/{agent-defs-generator-7TFISIJQ.js → agent-defs-generator-GY3UBREJ.js} +8 -6
- package/dist/{agent-heartbeat-CQPGJIFF.js → agent-heartbeat-GUVUUQVM.js} +1 -1
- package/dist/{agent-loop-EZ7LDAGD.js → agent-loop-HPNCH3HK.js} +1 -1
- package/dist/{agentic-ontology-XVTUVV7W.js → agentic-ontology-RHYNXEKE.js} +1 -1
- package/dist/{artifact-backup-TF6YWQT2.js → artifact-backup-HGUFSIJH.js} +19 -6
- package/dist/{backfill-metadata-J6MXIDCW.js → backfill-metadata-XLFASEOD.js} +11 -9
- package/dist/{backup-verify-6DVBQMDP.js → backup-verify-TUQEICWA.js} +1 -1
- package/dist/{behavior-injection-XDA7ZCYN.js → behavior-injection-GXO7ERGN.js} +14 -12
- package/dist/{behavior-promotion-4VLQ7LXK.js → behavior-promotion-V63WIZ4N.js} +13 -11
- package/dist/{behaviors-SCCZP7RZ.js → behaviors-RMLDPLOF.js} +18 -11
- package/dist/bin/agentic-ontology-backfill.js +12 -10
- package/dist/bin/agentic-reflection-backfill.js +13 -11
- package/dist/bin/agentic-semantic-label.js +12 -10
- package/dist/bin/backfill-conversations.js +11 -9
- package/dist/bin/backfill-responses.js +11 -9
- package/dist/bin/backfill-vectors.js +13 -11
- package/dist/bin/bulk-sync-postgres.js +20 -18
- package/dist/bin/cc-doctor.js +15 -13
- package/dist/bin/cleanup-stale-review-tasks.js +44 -32
- package/dist/bin/cli.js +109 -30
- package/dist/bin/customer-readiness.js +55 -25
- package/dist/bin/deferred-daemon-restart.js +111 -108
- package/dist/bin/exe-actions.js +7 -1
- package/dist/bin/exe-agent-config.js +8 -6
- package/dist/bin/exe-agent.js +18 -16
- package/dist/bin/exe-assign.js +13 -11
- package/dist/bin/exe-boot.js +49 -47
- package/dist/bin/exe-call.js +9 -7
- package/dist/bin/exe-cicd.js +19 -8
- package/dist/bin/exe-cloud.js +59 -25
- package/dist/bin/exe-config-dump.js +8 -6
- package/dist/bin/exe-dispatch.js +23 -21
- package/dist/bin/exe-doctor.js +11 -8
- package/dist/bin/exe-export-behaviors.js +16 -14
- package/dist/bin/exe-forget.js +14 -12
- package/dist/bin/exe-gateway.js +12 -10
- package/dist/bin/exe-grant.js +6 -6
- package/dist/bin/exe-healthcheck.js +15 -13
- package/dist/bin/exe-heartbeat.js +28 -26
- package/dist/bin/exe-kill.js +28 -26
- package/dist/bin/exe-launch-agent.js +35 -33
- package/dist/bin/exe-mcp.js +9 -7
- package/dist/bin/exe-memory-reads.js +11 -9
- package/dist/bin/exe-new-employee.js +13 -11
- package/dist/bin/exe-os-mcp-proxy.js +9 -7
- package/dist/bin/exe-pending-messages.js +23 -21
- package/dist/bin/exe-pending-notifications.js +22 -20
- package/dist/bin/exe-pending-reviews.js +23 -21
- package/dist/bin/exe-preflight.js +1 -1
- package/dist/bin/exe-rename.js +9 -7
- package/dist/bin/exe-review.js +59 -55
- package/dist/bin/exe-search-quality.js +16 -3
- package/dist/bin/exe-search.js +13 -11
- package/dist/bin/exe-session-cleanup.js +29 -27
- package/dist/bin/exe-settings.js +22 -20
- package/dist/bin/exe-start-codex.js +23 -21
- package/dist/bin/exe-start-opencode.js +21 -19
- package/dist/bin/exe-status.js +24 -22
- package/dist/bin/exe-support.js +3 -3
- package/dist/bin/exe-team.js +8 -6
- package/dist/bin/exe-verify-running-images.js +644 -17
- package/dist/bin/git-sweep.js +24 -22
- package/dist/bin/graph-backfill.js +12 -10
- package/dist/bin/graph-export.js +12 -10
- package/dist/bin/hooks-cli.js +4 -4
- package/dist/bin/import-history.js +16 -14
- package/dist/bin/install.js +113 -110
- package/dist/bin/intercom-check.js +5 -5
- package/dist/bin/mcp-sessions.js +2 -2
- package/dist/bin/orchestration-metrics.js +8 -6
- package/dist/bin/postgres-agentic-reflection-backfill.js +2 -2
- package/dist/bin/postgres-agentic-semantic-backfill.js +1 -1
- package/dist/bin/pre-build-guard.js +55 -16
- package/dist/bin/pre-publish.js +1 -1
- package/dist/bin/prune-orphan-chunks.js +154 -28
- package/dist/bin/reconcile-backlog.js +5 -3
- package/dist/bin/registry-proxy.js +1 -1
- package/dist/bin/repair-document-chunks.js +11 -9
- package/dist/bin/scan-tasks.js +23 -21
- package/dist/bin/setup.js +3 -3
- package/dist/bin/shard-migrate.js +12 -10
- package/dist/bin/stack-update.js +622 -43
- package/dist/bin/verify-stack.js +2 -2
- package/dist/bin/vps-health-gate.js +1 -1
- package/dist/{boot-generation-Q7LGQ3AO.js → boot-generation-VCQXVYGT.js} +7 -5
- package/dist/{boot-review-sections-G5774FR5.js → boot-review-sections-3QO6Q7MP.js} +21 -19
- package/dist/{branch-hygiene-44WLSOZR.js → branch-hygiene-DDXXI6ZA.js} +59 -21
- package/dist/bug-landed-reconciler-TQVNOUCU.js +353 -0
- package/dist/build-manifest.json +1269 -1194
- package/dist/{capability-cards-I3RHCF4F.js → capability-cards-XPDLT6LU.js} +6 -4
- package/dist/{capacity-monitor-7I7GDONU.js → capacity-monitor-N3AW242L.js} +23 -21
- package/dist/{catchup-brief-3T5PARIR.js → catchup-brief-3PKX7FUP.js} +29 -27
- package/dist/{chunk-C5ISP5FO.js → chunk-2BKJAOO4.js} +11 -1
- package/dist/{chunk-JJTPPAZY.js → chunk-2CUQHG6H.js} +1609 -1356
- package/dist/{chunk-HU3VD4MQ.js → chunk-2Q2GGYBX.js} +1 -1
- package/dist/{chunk-CHIUS5QB.js → chunk-36LMIOVU.js} +9 -9
- package/dist/{chunk-46VSBDUW.js → chunk-3DCBDG4T.js} +2 -2
- package/dist/{chunk-W3KPQE7H.js → chunk-3GL3E4TD.js} +3 -3
- package/dist/{chunk-GL47M7NY.js → chunk-3UD3OF3X.js} +202 -117
- package/dist/{chunk-WNBZJSQT.js → chunk-3VW5ZP2F.js} +1 -1
- package/dist/{chunk-JDDM6C57.js → chunk-3X74IQBU.js} +1 -1
- package/dist/{chunk-NVFNADTX.js → chunk-3ZL4MDQ6.js} +18 -4
- package/dist/{chunk-R5E7WNAC.js → chunk-4ESNDGMB.js} +3 -3
- package/dist/{chunk-CYCIX7AW.js → chunk-4FLLIQRQ.js} +2 -2
- package/dist/{chunk-3RGTLZNO.js → chunk-4GAKF7KR.js} +99 -74
- package/dist/{chunk-RVO5O5SR.js → chunk-4S3A52AV.js} +38 -10
- package/dist/{chunk-7J2ZQ4XN.js → chunk-4VQ3QR6B.js} +29 -28
- package/dist/{chunk-MROSARM5.js → chunk-5BJBTFFQ.js} +7 -1
- package/dist/chunk-5LQZABW5.js +6 -0
- package/dist/chunk-5ONMHTNI.js +236 -0
- package/dist/{chunk-APL7HUE3.js → chunk-5QQJUO3F.js} +200 -31
- package/dist/{chunk-UOPCVFVR.js → chunk-5RK75SWH.js} +205 -278
- package/dist/{chunk-T5FEAQES.js → chunk-5TYJYGS5.js} +1 -1
- package/dist/{chunk-P3QQ52QK.js → chunk-5U6EOTZV.js} +3 -3
- package/dist/{chunk-ALRHGEAJ.js → chunk-637FL62O.js} +1 -1
- package/dist/{chunk-PUBA5B4M.js → chunk-6L4VIYLZ.js} +33 -19
- package/dist/{chunk-VF2KRROX.js → chunk-754P2UXM.js} +1 -1
- package/dist/{chunk-CM7N5MBY.js → chunk-7FZG7WP4.js} +5 -5
- package/dist/{chunk-NYLJQ2M2.js → chunk-7NEBFB3L.js} +4 -4
- package/dist/{chunk-E7C2WNR5.js → chunk-AEIOFFFX.js} +5 -5
- package/dist/{chunk-VOVFUKEB.js → chunk-AIB2EWO2.js} +5 -5
- package/dist/{chunk-EGOEB42T.js → chunk-AP2C4OGS.js} +3 -3
- package/dist/{chunk-MPZ2AVNS.js → chunk-ATNV3BVZ.js} +1 -1
- package/dist/{chunk-F4BBMIPG.js → chunk-B4XJQBQB.js} +2 -2
- package/dist/{chunk-BPVFZ6Q4.js → chunk-B5EGDNG6.js} +2 -2
- package/dist/{chunk-AGC2V7JS.js → chunk-B6CBN6EF.js} +1 -1
- package/dist/{chunk-KTKIFXIP.js → chunk-B7FDRN7G.js} +1 -1
- package/dist/{chunk-C5HUMAA7.js → chunk-B7WVYLAQ.js} +67 -15
- package/dist/chunk-BGVP5RMT.js +185 -0
- package/dist/{chunk-FVLNNNH6.js → chunk-BNI4LIU5.js} +35 -4
- package/dist/{chunk-P4XLIPB7.js → chunk-BU5JRLZT.js} +1 -1
- package/dist/{chunk-PHUHIVD5.js → chunk-C6U7XWOC.js} +34 -5
- package/dist/chunk-C7GHNJPW.js +8 -0
- package/dist/{chunk-4AR5XKCH.js → chunk-CL2MU3OX.js} +1 -1
- package/dist/{chunk-ZPP63JSQ.js → chunk-CL3AB7Z2.js} +1 -1
- package/dist/{chunk-FHIFTSPL.js → chunk-CP7XUSOF.js} +8 -3
- package/dist/{chunk-3OX34OC3.js → chunk-CUDNRHHT.js} +30 -10
- package/dist/chunk-CYUUNIEL.js +21 -0
- package/dist/{chunk-P2UY34XE.js → chunk-D4C57S2H.js} +5 -5
- package/dist/{chunk-XSUALA32.js → chunk-DDYFNBYV.js} +3 -3
- package/dist/{chunk-LSNBTGW4.js → chunk-DPYZW42H.js} +1 -1
- package/dist/{chunk-FMIYFHLE.js → chunk-E2PRXEZK.js} +9 -3
- package/dist/{chunk-L63V25HS.js → chunk-E54SPUYJ.js} +3 -3
- package/dist/{chunk-DMUOTCDN.js → chunk-E5CKRHIZ.js} +1 -1
- package/dist/{chunk-BV2IET6B.js → chunk-EVMOKRBC.js} +15 -2
- package/dist/{chunk-YLFCH3VA.js → chunk-FDWI3T6I.js} +133 -31
- package/dist/{chunk-PWC3C5ME.js → chunk-FNJTCJGY.js} +4 -4
- package/dist/{chunk-TNS63ATU.js → chunk-FWRPDSO3.js} +350 -50
- package/dist/{chunk-JA3Y5TV6.js → chunk-GDLB6BPM.js} +141 -74
- package/dist/{chunk-IGJMS7C5.js → chunk-GOVGG7HU.js} +2 -2
- package/dist/{chunk-MB47DRF5.js → chunk-GP7CTIUK.js} +2 -2
- package/dist/{chunk-L5EPGGDP.js → chunk-GWAN2BDB.js} +4 -4
- package/dist/{chunk-YRQ26MNP.js → chunk-H3YF7X4J.js} +12 -5
- package/dist/{chunk-VLBHZ6TF.js → chunk-H6PLIFUE.js} +2 -2
- package/dist/{chunk-GSLFH4AI.js → chunk-HRNM3N4Y.js} +6 -15
- package/dist/chunk-IG2ISRTF.js +48 -0
- package/dist/{chunk-MWEIBVBS.js → chunk-IJCWBYA5.js} +14 -1
- package/dist/{chunk-NKEFYE4R.js → chunk-IPTUKX3N.js} +1 -1
- package/dist/{chunk-RB3J2WYQ.js → chunk-IVE7H6KA.js} +1 -1
- package/dist/{chunk-HA63SH5W.js → chunk-IWY2OGQG.js} +1 -1
- package/dist/{chunk-BQEZPRUC.js → chunk-IZWMWJZT.js} +64 -46
- package/dist/{chunk-AHESD3KW.js → chunk-J4UVI652.js} +1 -1
- package/dist/{chunk-PLII76NJ.js → chunk-JBUCA4OX.js} +33 -6
- package/dist/{chunk-2PZTMSMG.js → chunk-JOF4HQDF.js} +5 -5
- package/dist/{chunk-OBBO6EJR.js → chunk-JQN3QGSF.js} +1 -1
- package/dist/{chunk-P4PIZOL2.js → chunk-JWYIH5DR.js} +3 -3
- package/dist/{chunk-3XY57PKT.js → chunk-KZLKE7I3.js} +210 -48
- package/dist/{chunk-DYVLEMKS.js → chunk-L3GXMYBK.js} +1 -1
- package/dist/{chunk-72V3S44T.js → chunk-LUA4SLJY.js} +46 -19
- package/dist/{chunk-ZT4LFTUJ.js → chunk-LW3JCBXP.js} +20 -3
- package/dist/{chunk-YLB365YX.js → chunk-M5XHN4OM.js} +3 -3
- package/dist/{chunk-VHHX4UCP.js → chunk-MDTWARSF.js} +22 -93
- package/dist/{chunk-JFJP6ATJ.js → chunk-MWKXQSF6.js} +3 -2
- package/dist/{chunk-VJEJ7JNB.js → chunk-N32DVIKY.js} +1 -1
- package/dist/{chunk-MUCNYSJP.js → chunk-NRLJOV7M.js} +32 -4
- package/dist/{chunk-PL4CFSQ7.js → chunk-NSXJOSH7.js} +1 -1
- package/dist/{chunk-NF5FOSLD.js → chunk-NVTG66CK.js} +1 -1
- package/dist/chunk-O45GBJEH.js +1500 -0
- package/dist/{chunk-4AAMFWJT.js → chunk-OHZSTZXN.js} +4 -2
- package/dist/chunk-OSIS7ZQW.js +344 -0
- package/dist/{chunk-E3ZM32LF.js → chunk-P22VFGFK.js} +14 -5
- package/dist/{chunk-KILR4FBR.js → chunk-PAFLR7WD.js} +3 -3
- package/dist/{chunk-R3CZWFFC.js → chunk-PEYQ6MWO.js} +15 -3
- package/dist/{chunk-RDWIKDMY.js → chunk-PZR54BEI.js} +8 -20
- package/dist/{chunk-2FKU4ZEO.js → chunk-QDBKMEYY.js} +9 -9
- package/dist/{chunk-7UHZBVP3.js → chunk-QDVLVLXP.js} +97 -31
- package/dist/{chunk-PRDDPQLC.js → chunk-QLXEQRHD.js} +5 -5
- package/dist/{chunk-MUAWCFW6.js → chunk-QNPDXV5V.js} +5 -2
- package/dist/{chunk-LR5O2XWZ.js → chunk-QUZYLDNJ.js} +5 -5
- package/dist/chunk-RBQUXHYK.js +48 -0
- package/dist/{chunk-3SUPEE6H.js → chunk-RDMBSHGG.js} +3 -3
- package/dist/{chunk-I5XIW2BP.js → chunk-RGUM474V.js} +7 -7
- package/dist/{chunk-OAFENIHN.js → chunk-RJ67XAJU.js} +76 -28
- package/dist/{chunk-LFUBEHFW.js → chunk-RT57D7C4.js} +39 -1
- package/dist/{chunk-MKM6D7JM.js → chunk-RWG7DLOG.js} +42 -5
- package/dist/{chunk-P3UX5EH4.js → chunk-RWKAHHIX.js} +3 -3
- package/dist/{chunk-XEBKIWI7.js → chunk-RYNT3HB7.js} +12 -12
- package/dist/{chunk-EUGEFBGV.js → chunk-S2V272KJ.js} +3 -3
- package/dist/{chunk-W6BZ4UGA.js → chunk-SGYEM2PD.js} +1 -1
- package/dist/{chunk-VROK4X2L.js → chunk-SJP57MQM.js} +1 -1
- package/dist/{chunk-5MVKTNZP.js → chunk-SL4JWAMQ.js} +54 -4
- package/dist/{chunk-MOANZQXF.js → chunk-SLMKLEU6.js} +1 -1
- package/dist/{chunk-RZN2LEAK.js → chunk-SQA7XCYI.js} +3 -3
- package/dist/{chunk-4YNA3CM6.js → chunk-SSFS4NCH.js} +262 -56
- package/dist/{chunk-6FIC57PH.js → chunk-T4P2G3PO.js} +1 -1
- package/dist/{chunk-5U2IJBFV.js → chunk-TA3B4N24.js} +1 -1
- package/dist/{chunk-ZOTTYCP5.js → chunk-TEWWBVQP.js} +40 -4
- package/dist/{chunk-SDYWZRPN.js → chunk-TLSFGXXE.js} +1 -1
- package/dist/{chunk-L3VUW5M4.js → chunk-TQS2YHLB.js} +1 -1
- package/dist/{chunk-KXYKSLW4.js → chunk-TU4M757W.js} +399 -116
- package/dist/{chunk-MC4IM2CC.js → chunk-TYD4F4XU.js} +6 -6
- package/dist/{chunk-TKS5GMYA.js → chunk-U44Y7RC7.js} +2 -0
- package/dist/{chunk-B7AMNZTC.js → chunk-UKBPEEEQ.js} +2 -2
- package/dist/{chunk-ZBPZDADW.js → chunk-UWVXQEQQ.js} +467 -78
- package/dist/{chunk-P2VVMGMI.js → chunk-V4WH3FV7.js} +35 -16
- package/dist/{worktree-ownership-guard-O6JQF2CL.js → chunk-V6F4I2XY.js} +13 -14
- package/dist/{chunk-JFTUAV4J.js → chunk-VBKUESIW.js} +1 -1
- package/dist/{chunk-AZSTIAVL.js → chunk-VBPYYJPC.js} +1 -1
- package/dist/{chunk-LKTN22L6.js → chunk-VIP4LKLO.js} +57 -24
- package/dist/{chunk-L5CGXEZC.js → chunk-WAAGVFFN.js} +63 -71
- package/dist/{chunk-D3LXVAIQ.js → chunk-WC7AE3PT.js} +244 -103
- package/dist/{chunk-EOTZSAQL.js → chunk-WUCUDHKR.js} +1 -1
- package/dist/{chunk-VF3BZOZK.js → chunk-X7HZHKY4.js} +50 -3
- package/dist/{chunk-LFBLQE2P.js → chunk-XCAKYVKI.js} +1 -1
- package/dist/{chunk-UXN4BICC.js → chunk-XMX5J52Z.js} +1 -1
- package/dist/{chunk-6YDY6ZTD.js → chunk-XTCXGWTV.js} +9 -4
- package/dist/{chunk-XUZK23V7.js → chunk-XW2FW6LS.js} +2 -2
- package/dist/{chunk-CH7BUBP3.js → chunk-XWVHUDEK.js} +5 -4
- package/dist/{chunk-S26CV7BE.js → chunk-YA5LK6KB.js} +45 -8
- package/dist/{chunk-ELCRJGCH.js → chunk-YMRQIENV.js} +2 -2
- package/dist/{chunk-QNZ4562V.js → chunk-Z3LXWCB7.js} +1 -1
- package/dist/{chunk-EYMFVITZ.js → chunk-Z7I6NQMA.js} +2 -2
- package/dist/{chunk-6BJCDWSM.js → chunk-ZB4FS2EG.js} +1 -1
- package/dist/{chunk-ZAEUEDTN.js → chunk-ZD6FZ3WL.js} +1 -1
- package/dist/{chunk-FEU6QEEL.js → chunk-ZM6EZAVY.js} +1 -0
- package/dist/{chunk-2KY7WZZF.js → chunk-ZPA4R2UI.js} +1 -1
- package/dist/chunk-ZPPPHVSU.js +285 -0
- package/dist/{chunk-ELEGH4DX.js → chunk-ZUGQPYUY.js} +51 -4
- package/dist/{chunk-UX2EO653.js → chunk-ZZWFZ46U.js} +66 -8
- package/dist/{cleanup-graph-garbage-VQAJ2RBT.js → cleanup-graph-garbage-HFUD5ZQT.js} +12 -10
- package/dist/{cloud-sync-command-J7NEFUY7.js → cloud-sync-command-3JHJJKPN.js} +25 -3
- package/dist/{cloud-sync-db-init-KWEMNMGA.js → cloud-sync-db-init-2LHIQOSF.js} +1 -1
- package/dist/{cloud-sync-shutdown-P63AUTUI.js → cloud-sync-shutdown-ZXAXA3Z7.js} +6 -4
- package/dist/{cloud-sync-state-QF3TMMJ4.js → cloud-sync-state-VSQFGPP6.js} +1 -1
- package/dist/{co-activation-7IHRPBZN.js → co-activation-NX4EH4AP.js} +6 -4
- package/dist/{co-occurrence-R5AG4OAU.js → co-occurrence-5LBYCW3U.js} +10 -8
- package/dist/{consent-passphrase-5ZBDJ5G7.js → consent-passphrase-65W3DJIJ.js} +2 -2
- package/dist/{content-extractor-ZLXC6GNR.js → content-extractor-OGXETBOX.js} +2 -2
- package/dist/{conversation-entity-extractor-7FRKLLBD.js → conversation-entity-extractor-FQCOAH4F.js} +5 -4
- package/dist/conversations-retention-XTBFJBUM.js +166 -0
- package/dist/{crdt-sync-IFRZOEIS.js → crdt-sync-7TDUBTLH.js} +4 -4
- package/dist/{crm-webhook-L2S63ASV.js → crm-webhook-776JTY55.js} +2 -2
- package/dist/{cto-delegation-gate-3WU7OHX7.js → cto-delegation-gate-ZNUWVYCN.js} +25 -23
- package/dist/{daemon-orchestration-3VQYKLOR.js → daemon-orchestration-76BOFDEP.js} +30 -24
- package/dist/{doc-graph-extractor-YIR5E7OF.js → doc-graph-extractor-F724KZJX.js} +10 -8
- package/dist/{documents-QEHPTYIY.js → documents-Q24V4GRD.js} +13 -11
- package/dist/{dreaming-LNFE7DTN.js → dreaming-IY6NQTSP.js} +27 -25
- package/dist/{employee-boot-brief-ZTXDYNWM.js → employee-boot-brief-CCTXO5DQ.js} +35 -29
- package/dist/{entity-boost-R5N6JWXD.js → entity-boost-XGOB7HDM.js} +1 -1
- package/dist/{exe-drift-WYSJVZFO.js → exe-drift-NEPXLNGP.js} +7 -5
- package/dist/{exe-export-GOLNAEAV.js → exe-export-ZHJQFKR2.js} +14 -12
- package/dist/{exe-import-U4BSI6OH.js → exe-import-7SVNI4FW.js} +14 -12
- package/dist/{exe-key-V42G3NGO.js → exe-key-QJKU56WZ.js} +119 -108
- package/dist/{exe-org-U4GLQ6OP.js → exe-org-SJXHLV6K.js} +76 -51
- package/dist/{exe-snapshot-U7ONBYNY.js → exe-snapshot-EFWPXTXE.js} +45 -36
- package/dist/{fast-db-init-W3NGKAEU.js → fast-db-init-BQZOQNT3.js} +1 -1
- package/dist/{founder-context-ZSIBRVDM.js → founder-context-KG2ZAOXY.js} +2 -2
- package/dist/{founder-monitor-envelope-L3IWZLFY.js → founder-monitor-envelope-NYB5LLU4.js} +4 -4
- package/dist/gateway/index.js +20 -18
- package/dist/{gateway-client-DJFCVIPT.js → gateway-client-ODMUXUL3.js} +1 -1
- package/dist/{git-staleness-OF24QXFZ.js → git-staleness-OPGEAJA7.js} +6 -4
- package/dist/{global-procedures-WSIOWO43.js → global-procedures-3KXY4LL6.js} +8 -6
- package/dist/{graph-auto-extract-IEVVN3L3.js → graph-auto-extract-I7H2F5NJ.js} +10 -8
- package/dist/{graph-query-JDZWAVCU.js → graph-query-E7JBSNY5.js} +1 -1
- package/dist/{graph-rag-BKAD2XQA.js → graph-rag-H24CMFP2.js} +5 -4
- package/dist/{hook-integrity-TPWDGX2M.js → hook-integrity-PGQ3OX4S.js} +1 -1
- package/dist/{hook-prefetch-FD6VGJJA.js → hook-prefetch-7AZJER6Z.js} +23 -21
- package/dist/hook-registration-liveness-NGQRFKAA.js +11 -0
- package/dist/hooks/bug-report-worker.js +26 -24
- package/dist/hooks/codex-stop-task-finalizer.js +28 -26
- package/dist/hooks/commit-complete.js +26 -24
- package/dist/hooks/error-recall.js +16 -14
- package/dist/hooks/exe-heartbeat-hook.js +9 -7
- package/dist/hooks/ingest-worker.js +12 -10
- package/dist/hooks/ingest.js +22 -17
- package/dist/hooks/instructions-loaded.js +11 -9
- package/dist/hooks/manifest.json +20 -20
- package/dist/hooks/notification.js +10 -8
- package/dist/hooks/post-compact.js +9 -7
- package/dist/hooks/post-tool-combined.js +14 -14
- package/dist/hooks/pre-compact.js +26 -24
- package/dist/hooks/pre-tool-use.js +2 -2
- package/dist/hooks/prompt-submit.js +47 -41
- package/dist/hooks/session-end.js +38 -42
- package/dist/hooks/session-start.js +26 -18
- package/dist/hooks/stop.js +29 -27
- package/dist/hooks/subagent-stop.js +29 -27
- package/dist/hooks/summary-worker.js +32 -30
- package/dist/index.js +37 -35
- package/dist/{installer-OTI5SA43.js → installer-2ZS3LHCU.js} +12 -9
- package/dist/{installer-NMOBSEZ2.js → installer-NH3A3HWC.js} +14 -9
- package/dist/{installer-SRJGE4GU.js → installer-UJ73PGRD.js} +21 -9
- package/dist/{intercom-queue-4FFXCBHO.js → intercom-queue-OE25GJF2.js} +21 -19
- package/dist/lib/agent-config.js +2 -2
- package/dist/lib/cloud-sync.js +24 -18
- package/dist/lib/consolidation.js +13 -11
- package/dist/lib/crypto.js +3 -3
- package/dist/lib/database.js +6 -4
- package/dist/lib/db-backup.js +1 -1
- package/dist/lib/db-write-worker-client.js +3 -1
- package/dist/lib/db-write-worker.js +65 -89
- package/dist/lib/db.js +6 -4
- package/dist/lib/delivery-truth.js +5 -1
- package/dist/lib/device-registry.js +1 -1
- package/dist/lib/embedder.js +2 -2
- package/dist/lib/employee-templates.js +9 -7
- package/dist/lib/employees.js +6 -4
- package/dist/lib/exe-daemon.js +425 -314
- package/dist/lib/file-grep.js +15 -21
- package/dist/lib/hybrid-search.js +19 -13
- package/dist/lib/identity-templates.js +1 -1
- package/dist/lib/identity.js +6 -4
- package/dist/lib/keychain.js +1 -1
- package/dist/lib/license.js +22 -6
- package/dist/lib/messaging.js +22 -20
- package/dist/lib/post-tool-memory.js +10 -8
- package/dist/lib/registry-proxy.js +1 -1
- package/dist/lib/reminders.js +7 -5
- package/dist/lib/runtime-table.js +1 -1
- package/dist/lib/schedules.js +12 -10
- package/dist/lib/session-registry.js +8 -6
- package/dist/lib/skill-learning.js +13 -11
- package/dist/lib/status-brief.js +2 -2
- package/dist/lib/store.js +17 -9
- package/dist/lib/task-router.js +7 -5
- package/dist/lib/tasks.js +23 -21
- package/dist/lib/tmux-routing.js +21 -19
- package/dist/lib/tmux-status.js +4 -1
- package/dist/lib/token-spend.js +7 -5
- package/dist/lib/ws-client.js +1 -1
- package/dist/{license-gate-R4JWTWM4.js → license-gate-XQ2KN5I5.js} +3 -3
- package/dist/{license-recheck-3MBJ4IJX.js → license-recheck-IIBKR2V5.js} +1 -1
- package/dist/{license-sync-BVSG3WMW.js → license-sync-76JVI2M5.js} +151 -8
- package/dist/{local-secret-inventory-JWNBHZZ4.js → local-secret-inventory-MJT7NJLY.js} +2 -2
- package/dist/{mailbox-inbox-MTAT4MXX.js → mailbox-inbox-BPZP4GIZ.js} +1 -1
- package/dist/maintenance-worker-54VZTFIK.js +371 -0
- package/dist/mcp/register-tools.js +110 -107
- package/dist/mcp/server.js +113 -110
- package/dist/mcp/tools/complete-reminder.js +8 -6
- package/dist/mcp/tools/create-reminder.js +8 -6
- package/dist/mcp/tools/create-task.js +26 -24
- package/dist/mcp/tools/deactivate-behavior.js +15 -13
- package/dist/mcp/tools/list-reminders.js +8 -6
- package/dist/mcp/tools/list-tasks.js +26 -24
- package/dist/mcp/tools/send-message.js +25 -23
- package/dist/mcp/tools/update-task.js +24 -22
- package/dist/{mcp-child-registry-TIZERM7O.js → mcp-child-registry-5VUG5ATZ.js} +1 -1
- package/dist/{mcp-http-config-VUMSFWFH.js → mcp-http-config-SKXESWHA.js} +9 -7
- package/dist/{mcp-session-identity-DZHWEJRV.js → mcp-session-identity-HYMLJXXA.js} +21 -19
- package/dist/{memory-cards-JVXTMSAT.js → memory-cards-PAZDUQ3B.js} +16 -32
- package/dist/{memory-graph-extractor-PPBJMYFJ.js → memory-graph-extractor-BC6QKBY6.js} +11 -9
- package/dist/{memory-poisoning-defense-K5Q74XQ4.js → memory-poisoning-defense-BRGIHF6J.js} +9 -7
- package/dist/{memory-pressure-watchdog-YMJH5CSA.js → memory-pressure-watchdog-HR6TPOMT.js} +22 -20
- package/dist/{memory-reflection-7BZWIHRE.js → memory-reflection-LO7VFBL3.js} +38 -59
- package/dist/memory-write-repository-J25USX63.js +16 -0
- package/dist/{monitor-grants-Q7X3MYQP.js → monitor-grants-YQTO6NWR.js} +3 -3
- package/dist/{monitor-identity-ZQB4IXEE.js → monitor-identity-POVTG76Y.js} +2 -2
- package/dist/{notification-ledger-XRAXL5OI.js → notification-ledger-KLD6GZTG.js} +22 -20
- package/dist/{notifications-JE3PX55X.js → notifications-3R6HNHDR.js} +21 -19
- package/dist/{orchestration-events-JCQ5F5IJ.js → orchestration-events-CHY3GOJD.js} +7 -5
- package/dist/{orchestrator-X65INDTR.js → orchestrator-GAL3HOAD.js} +23 -21
- package/dist/{org-brief-session-3PQ22UIX.js → org-brief-session-LQ2DBYVF.js} +17 -15
- package/dist/{org-consent-policy-VGELJ7K7.js → org-consent-policy-KFUP7QPG.js} +5 -5
- package/dist/{org-join-6TO5ZYUZ.js → org-join-MXZCIQWX.js} +8 -8
- package/dist/{org-key-admin-XHYVRRAZ.js → org-key-admin-4UK6QUT7.js} +9 -9
- package/dist/{org-key-pin-TTTYGTQL.js → org-key-pin-ZOX4OM3O.js} +3 -3
- package/dist/{org-membership-Y7T2BS57.js → org-membership-D5TPN45F.js} +4 -4
- package/dist/{org-partner-config-OP4NEUNF.js → org-partner-config-3FXSYPQA.js} +7 -7
- package/dist/{org-partner-runtime-YNVUNT2R.js → org-partner-runtime-TH3LMPII.js} +20 -16
- package/dist/{org-row-visibility-JBBXNYXD.js → org-row-visibility-Y5R33C5U.js} +1 -1
- package/dist/{pipeline-router-EIBB7QNG.js → pipeline-router-E2JZLDK6.js} +7 -5
- package/dist/{plan-limits-MEWXYLEN.js → plan-limits-NYI6R4IK.js} +9 -7
- package/dist/{platform-procedures-Z7ZGBJWN.js → platform-procedures-RTD5E3BD.js} +5 -3
- package/dist/{pre-tool-use-impl-C6KJY22W.js → pre-tool-use-impl-LT4FRXBP.js} +127 -83
- package/dist/{project-boot-VEYFCCSL.js → project-boot-LIMXQKAF.js} +25 -17
- package/dist/{project-name-UYORSNGE.js → project-name-V62GWALX.js} +7 -5
- package/dist/{projection-worker-WYFDWS57.js → projection-worker-KLE3IZQ2.js} +5 -2
- package/dist/{prospective-memory-E6XBQFJA.js → prospective-memory-HRN7JFT2.js} +6 -4
- package/dist/{push-notifications-M7YU63FY.js → push-notifications-XC6EQEXF.js} +22 -20
- package/dist/{reproject-worktree-memories-B5XMGJSD.js → reproject-worktree-memories-4CAVZSFE.js} +21 -19
- package/dist/{reranker-SRA4BR7N.js → reranker-2RU6IIX2.js} +1 -1
- package/dist/{retrieval-health-P2JPZUPV.js → retrieval-health-4Q5TOV2S.js} +1 -1
- package/dist/{review-polling-KQPN7IQE.js → review-polling-WOWIMBCL.js} +22 -20
- package/dist/runtime/index.js +30 -28
- package/dist/{session-events-6LDDKKY3.js → session-events-OPMS2C5F.js} +22 -20
- package/dist/{session-kill-telemetry-5DSRGWCL.js → session-kill-telemetry-3GWATSIX.js} +22 -20
- package/dist/{session-scope-XG5R3P3D.js → session-scope-TIRGR4MH.js} +21 -19
- package/dist/{setup-wizard-7QFLZIKT.js → setup-wizard-B2JBVGNH.js} +3 -3
- package/dist/{shard-manager-HHHHV2KZ.js → shard-manager-C7LYX6E4.js} +5 -1
- package/dist/{skill-refinement-I5RMAHSC.js → skill-refinement-FWQFYNBI.js} +7 -5
- package/dist/skill-retrieval-PPLFC5RY.js +166 -0
- package/dist/skill-usage-NDB67PU2.js +25 -0
- package/dist/{stack-generate-manifest-AKMZ3AUX.js → stack-generate-manifest-AXI55MEQ.js} +6 -6
- package/dist/{stack-promote-34CE2HHF.js → stack-promote-6N23OGZY.js} +6 -6
- package/dist/stack-release-2CXFYVWM.js +2770 -0
- package/dist/{stack-update-ZQQ5YYPJ.js → stack-update-U53FBVCQ.js} +13 -5
- package/dist/{steward-gate-AQJ6KT2C.js → steward-gate-TUA3QCN7.js} +7 -5
- package/dist/{subagent-brief-injection-3GU7YAWY.js → subagent-brief-injection-N52RWYFZ.js} +34 -32
- package/dist/{subagent-spawn-ledger-52I66CLW.js → subagent-spawn-ledger-OI23OT4I.js} +1 -1
- package/dist/support-bug-actions-XWCJI6S5.js +30 -0
- package/dist/support-inbox-MMVTCXRX.js +77 -0
- package/dist/{support-outbox-KNI3FR3G.js → support-outbox-2TG2UV6J.js} +2 -2
- package/dist/{task-enforcement-CAA6D2MH.js → task-enforcement-JDMBAAOY.js} +22 -20
- package/dist/{task-request-inbox-QBZVU66E.js → task-request-inbox-PKJCYKJV.js} +9 -5
- package/dist/{task-scope-NHXB4ZRN.js → task-scope-32HQEV6W.js} +27 -19
- package/dist/{tasks-crud-JHSWL5NM.js → tasks-crud-CYKUKS3F.js} +21 -19
- package/dist/{tasks-notify-7PBE4U7T.js → tasks-notify-YND5MKWJ.js} +22 -20
- package/dist/{tasks-review-PPPVEE62.js → tasks-review-CG2A5GM3.js} +23 -19
- package/dist/{telemetry-upload-YU2VRNHX.js → telemetry-upload-WLUMEFAB.js} +11 -9
- package/dist/{token-budget-QCMWKG3K.js → token-budget-3YHAY5LL.js} +7 -5
- package/dist/{tool-capability-index-7AWQAJRP.js → tool-capability-index-2ADOWH43.js} +2 -2
- package/dist/{tool-gates-5Q3RSQEG.js → tool-gates-7ENOOYMR.js} +5 -3
- package/dist/{tool-gates-QD26D2NE.js → tool-gates-EKJTLVGN.js} +1 -1
- package/dist/{tool-telemetry-LTOIC64I.js → tool-telemetry-VUP7S6HC.js} +1 -1
- package/dist/tui/App.js +59 -35
- package/dist/{tui-data-NDBXD6U7.js → tui-data-BOQTOW2G.js} +25 -23
- package/dist/{update-support-BMJM4NG7.js → update-support-WT3S3AQ4.js} +21 -21
- package/dist/{whatsapp-QQLDAHUX.js → whatsapp-OZGIF2EM.js} +2 -2
- package/dist/{wiki-acl-W6WDCVCP.js → wiki-acl-LTEQJVDA.js} +1 -1
- package/dist/{work-claims-6DM32MGO.js → work-claims-CMV2GWIW.js} +8 -6
- package/dist/{work-state-heartbeat-HG7D4AWJ.js → work-state-heartbeat-S45TXK4M.js} +1 -1
- package/dist/{worker-gate-FTMW7GBB.js → worker-gate-7Z6NMM3G.js} +1 -1
- package/dist/{workflow-engine-ZWC6CCXE.js → workflow-engine-ZSQDXZQ7.js} +2 -2
- package/dist/{worktree-EMQCPGFE.js → worktree-NMWDVT6N.js} +8 -6
- package/dist/worktree-ownership-guard-ZVIWJAOP.js +35 -0
- package/dist/{worktree-sweep-XVUJZBXV.js → worktree-sweep-Q62ZIT3U.js} +9 -7
- package/package.json +14 -8
- package/release-notes.json +7 -41
- package/src/commands/exe/afk.md +6 -0
- package/src/commands/exe/call.md +6 -0
- package/src/commands/exe/employee-heartbeat.md +6 -0
- package/src/commands/exe/intercom.md +6 -0
- package/src/commands/exe/kill.md +6 -0
- package/src/commands/exe/launch.md +6 -0
- package/src/commands/exe/logs.md +1 -1
- package/src/commands/exe/sessions.md +6 -0
- package/src/commands/exe/setup.md +7 -3
- package/src/commands/exe/status.md +6 -0
- package/src/commands/exe-reference.md +25 -36
- package/src/commands/exe.md +19 -28
- package/stack.release.json +11 -11
- package/dist/chunk-3B6FLNLV.js +0 -30
- package/dist/chunk-FXU7JOXK.js +0 -6
- package/dist/chunk-QFAFKEB5.js +0 -820
- package/dist/conversations-retention-C4BLKFEL.js +0 -54
- package/dist/stack-release-5PGWV5D4.js +0 -1607
- package/dist/support-inbox-NY5TB3FN.js +0 -51
- /package/dist/{chunk-U2D6PJ5T.js → chunk-65G7ZTGE.js} +0 -0
- /package/dist/{chunk-DN3ZR3UE.js → chunk-CP7Z35MJ.js} +0 -0
- /package/dist/{chunk-XDVOGDBC.js → chunk-KBBWALJV.js} +0 -0
- /package/dist/{chunk-JRIH6I7D.js → chunk-LZXYPTY4.js} +0 -0
- /package/dist/{chunk-GIRD7O5X.js → chunk-MCWEW2SG.js} +0 -0
- /package/dist/{chunk-TKAU7IJ2.js → chunk-MQHUJLCA.js} +0 -0
- /package/dist/{chunk-M4XY4JRK.js → chunk-O53LTOXK.js} +0 -0
- /package/dist/{chunk-DZN7SDY2.js → chunk-OSVTH3SG.js} +0 -0
- /package/dist/{chunk-AJK2PVQW.js → chunk-QXXEXGX3.js} +0 -0
- /package/dist/{chunk-AWWDKF22.js → chunk-SFWNTO2F.js} +0 -0
- /package/dist/{chunk-2Q2CD6CD.js → chunk-WC5HF2FN.js} +0 -0
- /package/dist/{core-memory-O6D5UC3T.js → core-memory-MMMW3TF3.js} +0 -0
- /package/dist/{memory-isolation-EBFFC6HF.js → memory-isolation-67ACKQ2M.js} +0 -0
- /package/dist/{oauth-server-ZKBUHDFI.js → oauth-server-OILIKR7D.js} +0 -0
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
deployStalenessAlertPath,
|
|
7
7
|
evaluateDeployStaleness,
|
|
8
8
|
writeDeployStalenessAlert
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-B7WVYLAQ.js";
|
|
10
10
|
import {
|
|
11
11
|
REVISION_LABEL,
|
|
12
12
|
VERSION_LABEL,
|
|
@@ -15,13 +15,13 @@ import {
|
|
|
15
15
|
} from "./chunk-L25OAFOU.js";
|
|
16
16
|
import {
|
|
17
17
|
declaredArtifactsFromManifest
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-RT57D7C4.js";
|
|
19
19
|
import {
|
|
20
20
|
loadLicense
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-FWRPDSO3.js";
|
|
22
22
|
|
|
23
23
|
// src/lib/stack-update.ts
|
|
24
|
-
import { execFileSync, spawnSync } from "child_process";
|
|
24
|
+
import { execFileSync, spawnSync as spawnSync2 } from "child_process";
|
|
25
25
|
import { createVerify, randomBytes, verify as verifySignature } from "crypto";
|
|
26
26
|
import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
|
|
27
27
|
import http from "http";
|
|
@@ -119,6 +119,240 @@ ${remedy}
|
|
|
119
119
|
return gaps;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
// src/lib/stack-lock-derive.ts
|
|
123
|
+
import { spawnSync } from "child_process";
|
|
124
|
+
var GIT_SHA_LABEL = "org.exe.git_sha";
|
|
125
|
+
var GIT_REF_LABEL = "org.exe.git_ref";
|
|
126
|
+
function normalizeProbeResult(observed) {
|
|
127
|
+
if (observed === null) return null;
|
|
128
|
+
if (Array.isArray(observed)) return { containers: observed, uninspectable: [] };
|
|
129
|
+
return { containers: observed.containers ?? [], uninspectable: observed.uninspectable ?? [] };
|
|
130
|
+
}
|
|
131
|
+
function deriveStackLockFromContainers(lock, observed, now = () => /* @__PURE__ */ new Date()) {
|
|
132
|
+
const base = { ...lock ?? {} };
|
|
133
|
+
const services = { ...lock?.services ?? {} };
|
|
134
|
+
const probed = normalizeProbeResult(observed);
|
|
135
|
+
if (probed === null) {
|
|
136
|
+
return {
|
|
137
|
+
lock: base,
|
|
138
|
+
observations: [],
|
|
139
|
+
drifted: [],
|
|
140
|
+
unobserved: Object.keys(services),
|
|
141
|
+
uninspectable: [],
|
|
142
|
+
unobservable: true,
|
|
143
|
+
incomplete: true
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
const unreadable = new Set(probed.uninspectable.map((s) => s.trim()).filter(Boolean));
|
|
147
|
+
const byComposeService = /* @__PURE__ */ new Map();
|
|
148
|
+
for (const container of probed.containers) {
|
|
149
|
+
const key = container.composeService.trim();
|
|
150
|
+
if (!key) continue;
|
|
151
|
+
const existing = byComposeService.get(key);
|
|
152
|
+
if (existing) existing.push(container);
|
|
153
|
+
else byComposeService.set(key, [container]);
|
|
154
|
+
}
|
|
155
|
+
const at = now().toISOString();
|
|
156
|
+
const observations = [];
|
|
157
|
+
const unobserved = [];
|
|
158
|
+
const uninspectable = [];
|
|
159
|
+
const claimedUninspectable = /* @__PURE__ */ new Set();
|
|
160
|
+
const lockComposeServices = new Set(
|
|
161
|
+
Object.entries(services).map(
|
|
162
|
+
([name, entry]) => (entry.composeService ?? name).trim() || name
|
|
163
|
+
)
|
|
164
|
+
);
|
|
165
|
+
for (const [serviceName, entry] of Object.entries(services)) {
|
|
166
|
+
const composeService = (entry.composeService ?? serviceName).trim() || serviceName;
|
|
167
|
+
if (unreadable.has(composeService)) {
|
|
168
|
+
uninspectable.push(serviceName);
|
|
169
|
+
claimedUninspectable.add(composeService);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
const replicas = byComposeService.get(composeService) ?? [];
|
|
173
|
+
const container = replicas[0];
|
|
174
|
+
if (!container) {
|
|
175
|
+
unobserved.push(serviceName);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const recordedImage = typeof entry.image === "string" ? entry.image : void 0;
|
|
179
|
+
const recordedGitSha = typeof entry.gitSha === "string" ? entry.gitSha : void 0;
|
|
180
|
+
const observedGitSha = container.gitSha?.trim() || void 0;
|
|
181
|
+
const imageDrifted = normalizeImage(recordedImage) !== normalizeImage(container.image) || Boolean(entry.imageId && container.imageId && entry.imageId !== container.imageId);
|
|
182
|
+
const shaDrifted = observedGitSha !== void 0 && (recordedGitSha ?? "").toLowerCase() !== observedGitSha.toLowerCase();
|
|
183
|
+
const derived = {
|
|
184
|
+
...entry,
|
|
185
|
+
image: container.image,
|
|
186
|
+
observedAt: at,
|
|
187
|
+
imageId: container.imageId
|
|
188
|
+
};
|
|
189
|
+
if (observedGitSha) {
|
|
190
|
+
derived.gitSha = observedGitSha;
|
|
191
|
+
derived.provenance = "container-label";
|
|
192
|
+
} else {
|
|
193
|
+
derived.provenance = "container-image";
|
|
194
|
+
if (imageDrifted) {
|
|
195
|
+
delete derived.gitSha;
|
|
196
|
+
derived.gitShaUnknown = true;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (container.gitRef?.trim()) derived.gitRef = container.gitRef.trim();
|
|
200
|
+
else if (imageDrifted) delete derived.gitRef;
|
|
201
|
+
const staleContainers = [
|
|
202
|
+
...replicas.slice(1),
|
|
203
|
+
...probed.containers.filter(
|
|
204
|
+
(c) => isSidecarOf(composeService, c.composeService.trim()) && !lockComposeServices.has(c.composeService.trim())
|
|
205
|
+
)
|
|
206
|
+
].filter((c) => c !== container && runsSomethingElse(container, c)).map((c) => ({
|
|
207
|
+
composeService: c.composeService.trim(),
|
|
208
|
+
image: c.image,
|
|
209
|
+
...c.imageId ? { imageId: c.imageId } : {},
|
|
210
|
+
gitSha: c.gitSha?.trim() || void 0
|
|
211
|
+
}));
|
|
212
|
+
if (staleContainers.length > 0) {
|
|
213
|
+
derived.staleContainers = staleContainers;
|
|
214
|
+
derived.inconsistent = true;
|
|
215
|
+
} else {
|
|
216
|
+
delete derived.staleContainers;
|
|
217
|
+
delete derived.inconsistent;
|
|
218
|
+
}
|
|
219
|
+
services[serviceName] = derived;
|
|
220
|
+
observations.push({
|
|
221
|
+
service: serviceName,
|
|
222
|
+
composeService,
|
|
223
|
+
recordedImage,
|
|
224
|
+
recordedGitSha,
|
|
225
|
+
observedImage: container.image,
|
|
226
|
+
observedGitSha,
|
|
227
|
+
observedGitRef: container.gitRef?.trim() || void 0,
|
|
228
|
+
...staleContainers.length > 0 ? { staleContainers } : {},
|
|
229
|
+
drifted: imageDrifted || shaDrifted || staleContainers.length > 0
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
for (const composeService of unreadable) {
|
|
233
|
+
if (!claimedUninspectable.has(composeService)) uninspectable.push(composeService);
|
|
234
|
+
}
|
|
235
|
+
const inconsistent = observations.filter((o) => o.staleContainers?.length).map((o) => o.service);
|
|
236
|
+
const incomplete = uninspectable.length > 0 || unobserved.length > 0 || observations.length === 0 || inconsistent.length > 0;
|
|
237
|
+
base.services = services;
|
|
238
|
+
base.derivedAt = at;
|
|
239
|
+
base.derivedFrom = "container-labels";
|
|
240
|
+
if (incomplete) base.derivationUnverified = [...uninspectable, ...unobserved, ...inconsistent];
|
|
241
|
+
else delete base.derivationUnverified;
|
|
242
|
+
return {
|
|
243
|
+
lock: base,
|
|
244
|
+
observations,
|
|
245
|
+
drifted: observations.filter((o) => o.drifted),
|
|
246
|
+
unobserved,
|
|
247
|
+
uninspectable,
|
|
248
|
+
unobservable: false,
|
|
249
|
+
incomplete
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function formatStackLockDrift(drifted) {
|
|
253
|
+
return drifted.map((d) => {
|
|
254
|
+
const was = `${d.recordedImage ?? "(none)"}${d.recordedGitSha ? ` / ${d.recordedGitSha.slice(0, 12)}` : ""}`;
|
|
255
|
+
const is = `${d.observedImage}${d.observedGitSha ? ` / ${d.observedGitSha.slice(0, 12)}` : ""}`;
|
|
256
|
+
const siblings = (d.staleContainers ?? []).map((c) => `
|
|
257
|
+
also running: ${c.composeService} -> ${c.image}${c.gitSha ? ` / ${c.gitSha.slice(0, 12)}` : ""}`).join("");
|
|
258
|
+
return ` - ${d.service} (${d.composeService}): lock recorded ${was}; container is running ${is}${siblings}`;
|
|
259
|
+
}).join("\n");
|
|
260
|
+
}
|
|
261
|
+
function isSidecarOf(composeService, candidate) {
|
|
262
|
+
if (!composeService || !candidate || candidate === composeService) return false;
|
|
263
|
+
return candidate.startsWith(`${composeService}-`) || candidate.startsWith(`${composeService}_`);
|
|
264
|
+
}
|
|
265
|
+
function imageRepo(image) {
|
|
266
|
+
const trimmed = image.trim();
|
|
267
|
+
const at = trimmed.lastIndexOf("@");
|
|
268
|
+
const base = at === -1 ? trimmed : trimmed.slice(0, at);
|
|
269
|
+
const slash = base.lastIndexOf("/");
|
|
270
|
+
const colon = base.lastIndexOf(":");
|
|
271
|
+
return colon > slash ? base.slice(0, colon) : base;
|
|
272
|
+
}
|
|
273
|
+
function runsSomethingElse(primary, sidecar) {
|
|
274
|
+
if ((primary.composeService.trim() === sidecar.composeService.trim() || imageRepo(primary.image) === imageRepo(sidecar.image)) && primary.imageId && sidecar.imageId && primary.imageId !== sidecar.imageId) return true;
|
|
275
|
+
if ((primary.composeService.trim() === sidecar.composeService.trim() || imageRepo(primary.image) === imageRepo(sidecar.image)) && normalizeImage(primary.image) !== normalizeImage(sidecar.image)) return true;
|
|
276
|
+
const primarySha = primary.gitSha?.trim().toLowerCase();
|
|
277
|
+
const sidecarSha = sidecar.gitSha?.trim().toLowerCase();
|
|
278
|
+
if (primarySha && sidecarSha) return primarySha !== sidecarSha;
|
|
279
|
+
if (imageRepo(primary.image) !== imageRepo(sidecar.image)) return false;
|
|
280
|
+
return normalizeImage(primary.image) !== normalizeImage(sidecar.image);
|
|
281
|
+
}
|
|
282
|
+
function normalizeImage(image) {
|
|
283
|
+
if (!image) return "";
|
|
284
|
+
const trimmed = image.trim();
|
|
285
|
+
const at = trimmed.lastIndexOf("@");
|
|
286
|
+
return at === -1 ? trimmed : trimmed.slice(at + 1);
|
|
287
|
+
}
|
|
288
|
+
var defaultContainerProvenanceProbe = (composeArgs) => {
|
|
289
|
+
const ps = spawnSync("docker", [...composeArgs, "ps", "--format", "json"], { encoding: "utf8" });
|
|
290
|
+
if (ps.status !== 0 || typeof ps.stdout !== "string") return null;
|
|
291
|
+
const records = parseComposePsRecords(ps.stdout);
|
|
292
|
+
if (records.length === 0) return null;
|
|
293
|
+
const containers = [];
|
|
294
|
+
const uninspectable = [];
|
|
295
|
+
for (const { service, name } of records) {
|
|
296
|
+
const inspect = spawnSync("docker", ["inspect", name, "--format", '{"Config":{{json .Config}},"Image":{{json .Image}}}'], { encoding: "utf8" });
|
|
297
|
+
if (inspect.status !== 0 || typeof inspect.stdout !== "string") {
|
|
298
|
+
uninspectable.push(service);
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
let inspected;
|
|
302
|
+
try {
|
|
303
|
+
inspected = JSON.parse(inspect.stdout.trim());
|
|
304
|
+
} catch {
|
|
305
|
+
uninspectable.push(service);
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
const config = inspected?.Config ?? {};
|
|
309
|
+
const imageId = typeof inspected?.Image === "string" ? inspected.Image : "";
|
|
310
|
+
const image = typeof config.Image === "string" ? config.Image : "";
|
|
311
|
+
if (!image || !imageId) {
|
|
312
|
+
uninspectable.push(service);
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
const labels = config.Labels ?? {};
|
|
316
|
+
containers.push({
|
|
317
|
+
composeService: service,
|
|
318
|
+
image,
|
|
319
|
+
imageId,
|
|
320
|
+
gitSha: typeof labels[GIT_SHA_LABEL] === "string" ? labels[GIT_SHA_LABEL] : void 0,
|
|
321
|
+
gitRef: typeof labels[GIT_REF_LABEL] === "string" ? labels[GIT_REF_LABEL] : void 0
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
return { containers, uninspectable };
|
|
325
|
+
};
|
|
326
|
+
function parseComposePsRecords(stdout) {
|
|
327
|
+
const trimmed = stdout.trim().replace(/^/, "");
|
|
328
|
+
if (!trimmed) return [];
|
|
329
|
+
const records = [];
|
|
330
|
+
if (trimmed.startsWith("[")) {
|
|
331
|
+
try {
|
|
332
|
+
const parsed = JSON.parse(trimmed);
|
|
333
|
+
if (Array.isArray(parsed)) records.push(...parsed);
|
|
334
|
+
} catch {
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (records.length === 0) {
|
|
338
|
+
for (const line of trimmed.split("\n")) {
|
|
339
|
+
const l = line.trim();
|
|
340
|
+
if (!l) continue;
|
|
341
|
+
try {
|
|
342
|
+
records.push(JSON.parse(l));
|
|
343
|
+
} catch {
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
const out = [];
|
|
348
|
+
for (const obj of records) {
|
|
349
|
+
const service = String(obj.Service ?? "").trim();
|
|
350
|
+
const name = String(obj.Name ?? "").trim();
|
|
351
|
+
if (service && name) out.push({ service, name });
|
|
352
|
+
}
|
|
353
|
+
return out;
|
|
354
|
+
}
|
|
355
|
+
|
|
122
356
|
// src/lib/stack-update.ts
|
|
123
357
|
var SLOW_SERVICE_HEALTH_DEFAULTS = {
|
|
124
358
|
// Frappe `bench migrate` on every boot can take well over the 180s default.
|
|
@@ -862,6 +1096,7 @@ async function rollbackStackUpdate(options) {
|
|
|
862
1096
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
863
1097
|
});
|
|
864
1098
|
}
|
|
1099
|
+
reconcileDeployRecordNonFatal("a rollback", lockFilePath, composeArgs, () => /* @__PURE__ */ new Date());
|
|
865
1100
|
console.log("[stack-update] Rollback complete.");
|
|
866
1101
|
return { status: "rolled_back", targetVersion: "previous", changes: [], backupEnvFile: rollbackEnv, lockFile: lockFilePath, serviceStatus: lockData?.serviceStatus };
|
|
867
1102
|
}
|
|
@@ -908,7 +1143,7 @@ function isExecFormMigration(migrationCommand) {
|
|
|
908
1143
|
}
|
|
909
1144
|
function isComposeServiceRunning(composeArgs, composeServiceName) {
|
|
910
1145
|
try {
|
|
911
|
-
const result =
|
|
1146
|
+
const result = spawnSync2("docker", [...composeArgs, "ps", "--quiet", composeServiceName], {
|
|
912
1147
|
encoding: "utf8",
|
|
913
1148
|
stdio: ["pipe", "pipe", "pipe"],
|
|
914
1149
|
timeout: 1e4
|
|
@@ -978,6 +1213,72 @@ function writeStackUpdateLock(lockFile, data) {
|
|
|
978
1213
|
writeFileSync(lockFile, JSON.stringify(data, null, 2) + "\n", { mode: 420 });
|
|
979
1214
|
chmodSync(lockFile, 420);
|
|
980
1215
|
}
|
|
1216
|
+
function reconcileStackLockFromContainers(lockFile, composeArgs, options = {}) {
|
|
1217
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
1218
|
+
const probe = options.probe ?? defaultContainerProvenanceProbe;
|
|
1219
|
+
const lock = readStackUpdateLock(lockFile);
|
|
1220
|
+
if (!lock) {
|
|
1221
|
+
return { drifted: [], unobserved: [], uninspectable: [], observed: 0, incomplete: true, unobservable: true, written: false };
|
|
1222
|
+
}
|
|
1223
|
+
let observed;
|
|
1224
|
+
try {
|
|
1225
|
+
observed = probe(composeArgs);
|
|
1226
|
+
} catch {
|
|
1227
|
+
observed = null;
|
|
1228
|
+
}
|
|
1229
|
+
const derivation = deriveStackLockFromContainers(lock, observed, now);
|
|
1230
|
+
if (derivation.unobservable) {
|
|
1231
|
+
console.warn(
|
|
1232
|
+
`[stack-update] \u26A0 Could not observe the running containers, so ${path.basename(lockFile)} was NOT derived. It still reports whatever was last written to it \u2014 treat it as unverified.`
|
|
1233
|
+
);
|
|
1234
|
+
return {
|
|
1235
|
+
drifted: [],
|
|
1236
|
+
unobserved: derivation.unobserved,
|
|
1237
|
+
uninspectable: [],
|
|
1238
|
+
observed: 0,
|
|
1239
|
+
incomplete: true,
|
|
1240
|
+
unobservable: true,
|
|
1241
|
+
written: false
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1244
|
+
if (derivation.drifted.length > 0) {
|
|
1245
|
+
console.warn(
|
|
1246
|
+
`[stack-update] \u26A0 Deploy record drift (bug 32920edc): ${derivation.drifted.length} service(s) were delivered by a route that never updated ${path.basename(lockFile)}:
|
|
1247
|
+
${formatStackLockDrift(derivation.drifted)}`
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1250
|
+
if (derivation.incomplete) {
|
|
1251
|
+
const inconsistent = derivation.observations.filter((o) => o.staleContainers?.length).map((o) => o.service);
|
|
1252
|
+
console.warn(
|
|
1253
|
+
`[stack-update] \u26A0 ${path.basename(lockFile)} derivation is INCOMPLETE (${derivation.observations.length} service(s) observed` + (derivation.uninspectable.length > 0 ? `; could not read: ${derivation.uninspectable.join(", ")}` : "") + (derivation.unobserved.length > 0 ? `; no running container: ${derivation.unobserved.join(", ")}` : "") + (inconsistent.length > 0 ? `; inconsistent containers: ${inconsistent.join(", ")}` : "") + `). Those entries are UNVERIFIED; observed conflicts remain in the record.`
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
const result = {
|
|
1257
|
+
drifted: derivation.drifted,
|
|
1258
|
+
unobserved: derivation.unobserved,
|
|
1259
|
+
uninspectable: derivation.uninspectable,
|
|
1260
|
+
observed: derivation.observations.length,
|
|
1261
|
+
incomplete: derivation.incomplete,
|
|
1262
|
+
unobservable: false,
|
|
1263
|
+
written: false
|
|
1264
|
+
};
|
|
1265
|
+
if (options.dryRun) return result;
|
|
1266
|
+
writeStackUpdateLock(lockFile, derivation.lock);
|
|
1267
|
+
return { ...result, written: true };
|
|
1268
|
+
}
|
|
1269
|
+
function reconcileDeployRecordNonFatal(stage, lockFile, composeArgs, now) {
|
|
1270
|
+
try {
|
|
1271
|
+
const result = reconcileStackLockFromContainers(lockFile, composeArgs, { now });
|
|
1272
|
+
if (result.unobservable || result.incomplete) {
|
|
1273
|
+
console.warn(
|
|
1274
|
+
`[stack-update] \u26A0 Deploy record after ${stage} is NOT fully verified (${result.observed} service(s) read from containers). Treat ${path.basename(lockFile)} as partial evidence.`
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
} catch (deriveErr) {
|
|
1278
|
+
const reason = deriveErr instanceof Error ? deriveErr.message : String(deriveErr);
|
|
1279
|
+
console.warn(`[stack-update] \u26A0 Deploy-record derivation failed after ${stage} (non-fatal): ${reason}`);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
981
1282
|
function composeOverrideFileFor(composeFile) {
|
|
982
1283
|
return path.join(path.dirname(composeFile), "docker-compose.override.yml");
|
|
983
1284
|
}
|
|
@@ -1568,7 +1869,7 @@ function collectImageAvailabilityIssues(plan) {
|
|
|
1568
1869
|
let inspectOutput = "";
|
|
1569
1870
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
1570
1871
|
try {
|
|
1571
|
-
const result =
|
|
1872
|
+
const result = spawnSync2("docker", ["manifest", "inspect", manifestInspectRef(image), "--verbose"], {
|
|
1572
1873
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1573
1874
|
timeout: 3e4
|
|
1574
1875
|
});
|
|
@@ -1583,7 +1884,7 @@ function collectImageAvailabilityIssues(plan) {
|
|
|
1583
1884
|
console.log(
|
|
1584
1885
|
`[stack-update] Image ${image} not yet available on proxy (attempt ${attempt}/${maxAttempts}), retrying in ${delayMs / 1e3}s\u2026 (bug d11c9809)`
|
|
1585
1886
|
);
|
|
1586
|
-
|
|
1887
|
+
spawnSync2("sleep", [String(delayMs / 1e3)], { stdio: "ignore" });
|
|
1587
1888
|
}
|
|
1588
1889
|
} catch {
|
|
1589
1890
|
inspected = true;
|
|
@@ -1888,41 +2189,21 @@ async function resolveStackImageCredentials(options, release) {
|
|
|
1888
2189
|
}
|
|
1889
2190
|
return null;
|
|
1890
2191
|
}
|
|
1891
|
-
async function
|
|
1892
|
-
const exec = options.exec ?? defaultExec;
|
|
1893
|
-
const images = manifestImagesForPull(plan.release);
|
|
1894
|
-
const maxAttempts = Math.max(1, Math.floor(options.verifyImageMaxAttempts ?? 3));
|
|
1895
|
-
const baseDelayMs = Math.max(0, Math.floor(options.verifyImageRetryBaseDelayMs ?? 1e3));
|
|
2192
|
+
async function withStackImageCredentials(plan, options, verify) {
|
|
1896
2193
|
let registryForLogout;
|
|
1897
|
-
const creds = await resolveStackImageCredentials(options, plan.release);
|
|
1898
|
-
if (creds) {
|
|
1899
|
-
(options.dockerLogin ?? defaultDockerLogin)(creds);
|
|
1900
|
-
registryForLogout = creds.registry;
|
|
1901
|
-
}
|
|
1902
2194
|
try {
|
|
1903
|
-
const
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
1908
|
-
try {
|
|
1909
|
-
exec("docker", ["manifest", "inspect", manifestInspectRef(image)]);
|
|
1910
|
-
ok = true;
|
|
1911
|
-
break;
|
|
1912
|
-
} catch (err) {
|
|
1913
|
-
lastError = err instanceof Error ? err.message : String(err);
|
|
1914
|
-
if (attempt < maxAttempts) {
|
|
1915
|
-
const delayMs = baseDelayMs * Math.pow(2, attempt - 1);
|
|
1916
|
-
console.warn(
|
|
1917
|
-
`[stack-update] manifest inspect failed for ${image} (attempt ${attempt}/${maxAttempts}): ${lastError}. Retrying in ${delayMs}ms.`
|
|
1918
|
-
);
|
|
1919
|
-
if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
1922
|
-
}
|
|
1923
|
-
results.push(ok ? { image, ok: true } : { image, ok: false, error: `manifest inspect failed after ${maxAttempts} attempt(s): ${lastError}` });
|
|
2195
|
+
const creds = await resolveStackImageCredentials(options, plan.release);
|
|
2196
|
+
if (creds) {
|
|
2197
|
+
(options.dockerLogin ?? defaultDockerLogin)(creds);
|
|
2198
|
+
registryForLogout = creds.registry;
|
|
1924
2199
|
}
|
|
1925
|
-
|
|
2200
|
+
} catch (err) {
|
|
2201
|
+
throw new Error(
|
|
2202
|
+
`Pre-deploy registry authentication check failed before any production service was changed. Aborting stack update for service(s) ${allServiceList(plan.release)}: ${errorMessage(err)}`
|
|
2203
|
+
);
|
|
2204
|
+
}
|
|
2205
|
+
try {
|
|
2206
|
+
return await verify();
|
|
1926
2207
|
} finally {
|
|
1927
2208
|
if (registryForLogout) {
|
|
1928
2209
|
try {
|
|
@@ -1932,6 +2213,38 @@ async function verifyManifestImagesAvailable(plan, options) {
|
|
|
1932
2213
|
}
|
|
1933
2214
|
}
|
|
1934
2215
|
}
|
|
2216
|
+
async function inspectManifestImagesAvailable(plan, options) {
|
|
2217
|
+
const exec = options.exec ?? defaultExec;
|
|
2218
|
+
const images = manifestImagesForPull(plan.release);
|
|
2219
|
+
const maxAttempts = Math.max(1, Math.floor(options.verifyImageMaxAttempts ?? 3));
|
|
2220
|
+
const baseDelayMs = Math.max(0, Math.floor(options.verifyImageRetryBaseDelayMs ?? 1e3));
|
|
2221
|
+
const results = [];
|
|
2222
|
+
for (const image of images) {
|
|
2223
|
+
let lastError = "";
|
|
2224
|
+
let ok = false;
|
|
2225
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
2226
|
+
try {
|
|
2227
|
+
exec("docker", ["manifest", "inspect", manifestInspectRef(image)]);
|
|
2228
|
+
ok = true;
|
|
2229
|
+
break;
|
|
2230
|
+
} catch (err) {
|
|
2231
|
+
lastError = err instanceof Error ? err.message : String(err);
|
|
2232
|
+
if (attempt < maxAttempts) {
|
|
2233
|
+
const delayMs = baseDelayMs * Math.pow(2, attempt - 1);
|
|
2234
|
+
console.warn(
|
|
2235
|
+
`[stack-update] manifest inspect failed for ${image} (attempt ${attempt}/${maxAttempts}): ${lastError}. Retrying in ${delayMs}ms.`
|
|
2236
|
+
);
|
|
2237
|
+
if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
results.push(ok ? { image, ok: true } : { image, ok: false, error: `manifest inspect failed after ${maxAttempts} attempt(s): ${lastError}` });
|
|
2242
|
+
}
|
|
2243
|
+
return results;
|
|
2244
|
+
}
|
|
2245
|
+
async function verifyManifestImagesAvailable(plan, options) {
|
|
2246
|
+
return withStackImageCredentials(plan, options, () => inspectManifestImagesAvailable(plan, options));
|
|
2247
|
+
}
|
|
1935
2248
|
function servicesForPullImage(release, image) {
|
|
1936
2249
|
return Object.entries(release.services).filter(([, service]) => imagePullRef(service.image) === image).map(([serviceName, service]) => {
|
|
1937
2250
|
const composeService = service.composeService ?? serviceName;
|
|
@@ -1962,7 +2275,7 @@ function readStagedComposeTemplate(options, currentComposeRaw) {
|
|
|
1962
2275
|
async function assertPreDeployImagesPullable(plan, options) {
|
|
1963
2276
|
let results;
|
|
1964
2277
|
try {
|
|
1965
|
-
results = await
|
|
2278
|
+
results = await inspectManifestImagesAvailable(plan, options);
|
|
1966
2279
|
} catch (err) {
|
|
1967
2280
|
throw new Error(
|
|
1968
2281
|
`Pre-deploy registry authentication check failed before any production service was changed. Aborting stack update for service(s) ${allServiceList(plan.release)}: ${errorMessage(err)}`
|
|
@@ -1980,8 +2293,21 @@ ${details}
|
|
|
1980
2293
|
Fix registry authentication or publish the missing image(s), then re-run stack-update.`
|
|
1981
2294
|
);
|
|
1982
2295
|
}
|
|
2296
|
+
async function verifyPreDeployImages(plan, options) {
|
|
2297
|
+
await withStackImageCredentials(plan, options, async () => {
|
|
2298
|
+
console.log("[stack-update] Pre-deploy image auth/pullability check started");
|
|
2299
|
+
await assertPreDeployImagesPullable(plan, options);
|
|
2300
|
+
console.log("[stack-update] \u2713 Pre-deploy image auth/pullability check passed");
|
|
2301
|
+
console.log("[stack-update] Deploy-time image-provenance check (G4) started");
|
|
2302
|
+
assertImageProvenance(plan, options);
|
|
2303
|
+
console.log("[stack-update] \u2713 Deploy-time image-provenance check (G4) passed");
|
|
2304
|
+
console.log("[stack-update] Deploy-time image version-label check (G4b) started");
|
|
2305
|
+
assertImageVersionLabels(plan, options);
|
|
2306
|
+
console.log("[stack-update] \u2713 Deploy-time image version-label check (G4b) passed");
|
|
2307
|
+
});
|
|
2308
|
+
}
|
|
1983
2309
|
var defaultContainerCountSnapshot = () => {
|
|
1984
|
-
const snapshot =
|
|
2310
|
+
const snapshot = spawnSync2("docker", ["ps", "--format", "json"], { encoding: "utf8", timeout: 1e4 });
|
|
1985
2311
|
return snapshot.stdout?.split("\n").filter(Boolean).length ?? 0;
|
|
1986
2312
|
};
|
|
1987
2313
|
var defaultImageLabelReader = (image, label) => {
|
|
@@ -2097,7 +2423,7 @@ A first-party image whose version label does not match its tag cannot be traced
|
|
|
2097
2423
|
}
|
|
2098
2424
|
var PROBE_TIMEOUT_MS = 1e4;
|
|
2099
2425
|
function commandSucceeds(cmd, args = []) {
|
|
2100
|
-
const res =
|
|
2426
|
+
const res = spawnSync2(cmd, args, {
|
|
2101
2427
|
stdio: "ignore",
|
|
2102
2428
|
timeout: PROBE_TIMEOUT_MS,
|
|
2103
2429
|
killSignal: "SIGKILL"
|
|
@@ -2105,7 +2431,7 @@ function commandSucceeds(cmd, args = []) {
|
|
|
2105
2431
|
return res.status === 0;
|
|
2106
2432
|
}
|
|
2107
2433
|
function shellSucceeds(command) {
|
|
2108
|
-
const res =
|
|
2434
|
+
const res = spawnSync2("sh", ["-lc", command], {
|
|
2109
2435
|
stdio: "ignore",
|
|
2110
2436
|
timeout: PROBE_TIMEOUT_MS,
|
|
2111
2437
|
killSignal: "SIGKILL"
|
|
@@ -2536,7 +2862,7 @@ function hardenHost(exec) {
|
|
|
2536
2862
|
return result;
|
|
2537
2863
|
}
|
|
2538
2864
|
function hardenUfw(exec, result) {
|
|
2539
|
-
const whichUfw =
|
|
2865
|
+
const whichUfw = spawnSync2("which", ["ufw"], { stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 });
|
|
2540
2866
|
const ufwInstalled = whichUfw.status === 0;
|
|
2541
2867
|
if (!ufwInstalled) {
|
|
2542
2868
|
if (!existsSync("/etc/os-release")) {
|
|
@@ -2561,7 +2887,7 @@ function hardenUfw(exec, result) {
|
|
|
2561
2887
|
return;
|
|
2562
2888
|
}
|
|
2563
2889
|
}
|
|
2564
|
-
const statusResult =
|
|
2890
|
+
const statusResult = spawnSync2("ufw", ["status", "verbose"], {
|
|
2565
2891
|
encoding: "utf8",
|
|
2566
2892
|
stdio: ["pipe", "pipe", "pipe"],
|
|
2567
2893
|
timeout: 1e4
|
|
@@ -2713,7 +3039,7 @@ function hardenSsh(exec, result) {
|
|
|
2713
3039
|
}
|
|
2714
3040
|
function areStackContainersRunning(composeFile, envFile) {
|
|
2715
3041
|
try {
|
|
2716
|
-
const result =
|
|
3042
|
+
const result = spawnSync2("docker", [...composeArgsForStack(composeFile, envFile), "ps", "-q"], {
|
|
2717
3043
|
stdio: ["pipe", "pipe", "pipe"],
|
|
2718
3044
|
timeout: 15e3
|
|
2719
3045
|
});
|
|
@@ -2740,7 +3066,7 @@ var CRITICAL_VOLUMES = [
|
|
|
2740
3066
|
"clickhouse_data",
|
|
2741
3067
|
"erp_sites"
|
|
2742
3068
|
];
|
|
2743
|
-
var defaultVolumeExists = (volumeName) =>
|
|
3069
|
+
var defaultVolumeExists = (volumeName) => spawnSync2(
|
|
2744
3070
|
"docker",
|
|
2745
3071
|
["volume", "inspect", volumeName],
|
|
2746
3072
|
{
|
|
@@ -3034,15 +3360,7 @@ ${lines.join("\n")}`
|
|
|
3034
3360
|
return { status: "planned", targetVersion: plan.targetVersion, changes: plan.changes, lockFile };
|
|
3035
3361
|
}
|
|
3036
3362
|
if (!options.skipImageAvailabilityCheck) {
|
|
3037
|
-
|
|
3038
|
-
await assertPreDeployImagesPullable(plan, options);
|
|
3039
|
-
console.log("[stack-update] \u2713 Pre-deploy image auth/pullability check passed");
|
|
3040
|
-
console.log("[stack-update] Deploy-time image-provenance check (G4) started");
|
|
3041
|
-
assertImageProvenance(plan, options);
|
|
3042
|
-
console.log("[stack-update] \u2713 Deploy-time image-provenance check (G4) passed");
|
|
3043
|
-
console.log("[stack-update] Deploy-time image version-label check (G4b) started");
|
|
3044
|
-
assertImageVersionLabels(plan, options);
|
|
3045
|
-
console.log("[stack-update] \u2713 Deploy-time image version-label check (G4b) passed");
|
|
3363
|
+
await verifyPreDeployImages(plan, options);
|
|
3046
3364
|
}
|
|
3047
3365
|
await postDeployAudit(options, "started", plan.targetVersion, previousVersion);
|
|
3048
3366
|
try {
|
|
@@ -3388,7 +3706,7 @@ Push the missing image(s) to the registry, or re-run with --break-glass <reason>
|
|
|
3388
3706
|
if (bundledIsolation && (failedComposeServices.has(service) || failedManifestServices.has(resolveOwningManifestService(service, plan.release.services)))) {
|
|
3389
3707
|
continue;
|
|
3390
3708
|
}
|
|
3391
|
-
const serviceDefined = options.composeServiceExists ? options.composeServiceExists(service) :
|
|
3709
|
+
const serviceDefined = options.composeServiceExists ? options.composeServiceExists(service) : spawnSync2("docker", [...composeArgs, "ps", "--quiet", service], {
|
|
3392
3710
|
encoding: "utf8",
|
|
3393
3711
|
stdio: ["pipe", "pipe", "pipe"],
|
|
3394
3712
|
timeout: 1e4
|
|
@@ -3396,7 +3714,7 @@ Push the missing image(s) to the registry, or re-run with --break-glass <reason>
|
|
|
3396
3714
|
if (!serviceDefined) continue;
|
|
3397
3715
|
progress.logServiceStep(restartIndex, service, "Restarting");
|
|
3398
3716
|
if (service === "exe-wiki") {
|
|
3399
|
-
const guard = options.runWikiSchemaGuard ? { status: options.runWikiSchemaGuard() } :
|
|
3717
|
+
const guard = options.runWikiSchemaGuard ? { status: options.runWikiSchemaGuard() } : spawnSync2(
|
|
3400
3718
|
"docker",
|
|
3401
3719
|
[...composeArgs, "run", "--rm", "--no-deps", "exe-wiki-schema-guard"],
|
|
3402
3720
|
{ encoding: "utf8", stdio: ["pipe", "inherit", "inherit"], timeout: 12e4 }
|
|
@@ -3412,7 +3730,7 @@ Push the missing image(s) to the registry, or re-run with --break-glass <reason>
|
|
|
3412
3730
|
updateServiceStatus(lockFile, manifestServiceName, "restarted", now);
|
|
3413
3731
|
const maxWait = resolveServiceHealthTimeout(service, plan.release, options.healthTimeoutSecs);
|
|
3414
3732
|
const probeHealth = options.inspectContainerHealth ?? ((svc) => {
|
|
3415
|
-
const inspectResult =
|
|
3733
|
+
const inspectResult = spawnSync2(
|
|
3416
3734
|
"docker",
|
|
3417
3735
|
["inspect", "--format", "{{.State.Health.Status}}", svc],
|
|
3418
3736
|
{ encoding: "utf8", timeout: 5e3 }
|
|
@@ -3567,6 +3885,7 @@ Push the missing image(s) to the registry, or re-run with --break-glass <reason>
|
|
|
3567
3885
|
preUpdateImageDefaults: partialLock.preUpdateImageDefaults ?? configBackup.preUpdateImageDefaults,
|
|
3568
3886
|
services: { ...fullTargetPlan.release.services, ...partialLock.services ?? {}, ...plan.release.services }
|
|
3569
3887
|
});
|
|
3888
|
+
reconcileDeployRecordNonFatal("a partial update", lockFile, composeArgs, now);
|
|
3570
3889
|
const partialStaleness = evaluateDeployStaleness(readStackUpdateLock(lockFile), now);
|
|
3571
3890
|
if (partialStaleness) writeDeployStalenessAlert(partialStaleness);
|
|
3572
3891
|
await postDeployAudit(
|
|
@@ -3672,6 +3991,7 @@ Fix these before the stack is safe to operate.`);
|
|
|
3672
3991
|
preUpdateImageDefaults: finalLock.preUpdateImageDefaults ?? configBackup.preUpdateImageDefaults,
|
|
3673
3992
|
services: { ...fullTargetPlan.release.services, ...finalLock.services ?? {}, ...plan.release.services }
|
|
3674
3993
|
});
|
|
3994
|
+
reconcileDeployRecordNonFatal("a successful update", lockFile, composeArgs, now);
|
|
3675
3995
|
clearDeployStalenessAlert();
|
|
3676
3996
|
await postDeployAudit(options, "success", plan.targetVersion, previousVersion, void 0, { changes: plan.changes.length });
|
|
3677
3997
|
return { status: "updated", targetVersion: plan.targetVersion, changes: plan.changes, backupEnvFile, lockFile, serviceStatus: readStackUpdateLock(lockFile)?.serviceStatus };
|
|
@@ -3838,7 +4158,7 @@ async function verifyReleaseHealth(release, retries, delayMs, env, skipServices)
|
|
|
3838
4158
|
var defaultComposePsCapture = (composeArgs) => {
|
|
3839
4159
|
let result;
|
|
3840
4160
|
try {
|
|
3841
|
-
result =
|
|
4161
|
+
result = spawnSync2("docker", [...composeArgs, "ps", "--all", "--format", "json"], {
|
|
3842
4162
|
encoding: "utf8",
|
|
3843
4163
|
stdio: ["pipe", "pipe", "pipe"],
|
|
3844
4164
|
timeout: 2e4
|
|
@@ -3907,29 +4227,38 @@ function snapshotComposeServiceStates(composeArgs, wantedServices, capture) {
|
|
|
3907
4227
|
if (records.length === 0) return null;
|
|
3908
4228
|
const byService = /* @__PURE__ */ new Map();
|
|
3909
4229
|
for (const svc of wantedServices) {
|
|
3910
|
-
byService.set(svc, { service: svc, state: "", health: "", restartCount: 0, missing: true });
|
|
4230
|
+
byService.set(svc, { service: svc, state: "", health: "", restartCount: 0, exitCode: null, missing: true });
|
|
3911
4231
|
}
|
|
3912
4232
|
for (const obj of records) {
|
|
3913
4233
|
const service = String(obj.Service ?? obj.Name ?? "");
|
|
3914
4234
|
if (!service || !byService.has(service)) continue;
|
|
3915
4235
|
const restartRaw = obj.RestartCount;
|
|
4236
|
+
const exitRaw = obj.ExitCode;
|
|
3916
4237
|
byService.set(service, {
|
|
3917
4238
|
service,
|
|
3918
4239
|
state: String(obj.State ?? "").toLowerCase(),
|
|
3919
4240
|
health: String(obj.Health ?? "").toLowerCase(),
|
|
3920
4241
|
restartCount: typeof restartRaw === "number" ? restartRaw : Number(restartRaw) || 0,
|
|
4242
|
+
// Absent / unparsable stays null. Compose omits ExitCode on some versions
|
|
4243
|
+
// and reports it as a string on others; only a real number is an answer.
|
|
4244
|
+
exitCode: typeof exitRaw === "number" ? exitRaw : typeof exitRaw === "string" && exitRaw.trim() !== "" && Number.isFinite(Number(exitRaw)) ? Number(exitRaw) : null,
|
|
3921
4245
|
missing: false
|
|
3922
4246
|
});
|
|
3923
4247
|
}
|
|
3924
4248
|
return byService;
|
|
3925
4249
|
}
|
|
3926
|
-
async function verifyComposeServicesRunning(composeArgs, wantedServices, timeoutSecs = 180, capture) {
|
|
4250
|
+
async function verifyComposeServicesRunning(composeArgs, wantedServices, timeoutSecs = 180, capture, oneShotServices, requireObservableState = false) {
|
|
3927
4251
|
if (wantedServices.length === 0) return;
|
|
3928
4252
|
const psCapture = capture ?? defaultComposePsCapture;
|
|
3929
4253
|
const deadline = Date.now() + timeoutSecs * 1e3;
|
|
3930
4254
|
for (; ; ) {
|
|
3931
4255
|
const states = snapshotComposeServiceStates(composeArgs, wantedServices, psCapture);
|
|
3932
4256
|
if (states === null) {
|
|
4257
|
+
if (requireObservableState) {
|
|
4258
|
+
throw new Error(
|
|
4259
|
+
"Post-deploy health verification failed closed (Phase 3): container runtime state unavailable (docker compose ps returned nothing usable)"
|
|
4260
|
+
);
|
|
4261
|
+
}
|
|
3933
4262
|
console.warn("[stack-update] Phase 3 skipped: container runtime state unavailable (docker compose ps returned nothing)");
|
|
3934
4263
|
return;
|
|
3935
4264
|
}
|
|
@@ -3941,6 +4270,21 @@ async function verifyComposeServicesRunning(composeArgs, wantedServices, timeout
|
|
|
3941
4270
|
hardFailures.push(`${svc}: container missing (never created)`);
|
|
3942
4271
|
continue;
|
|
3943
4272
|
}
|
|
4273
|
+
if (oneShotServices?.has(svc)) {
|
|
4274
|
+
if (s.state === "exited") {
|
|
4275
|
+
if (s.exitCode === 0) continue;
|
|
4276
|
+
hardFailures.push(
|
|
4277
|
+
s.exitCode === null ? `${svc}: one-shot container exited but compose reported no exit status, so completion could not be confirmed` : `${svc}: one-shot container failed (exit code ${s.exitCode})`
|
|
4278
|
+
);
|
|
4279
|
+
continue;
|
|
4280
|
+
}
|
|
4281
|
+
if (s.state === "dead") {
|
|
4282
|
+
hardFailures.push(`${svc}: container dead`);
|
|
4283
|
+
continue;
|
|
4284
|
+
}
|
|
4285
|
+
pending.push(`${svc}: one-shot still running (no exit status yet)`);
|
|
4286
|
+
continue;
|
|
4287
|
+
}
|
|
3944
4288
|
if (s.state === "exited" || s.state === "dead") {
|
|
3945
4289
|
hardFailures.push(`${svc}: container ${s.state} (restarts: ${s.restartCount})`);
|
|
3946
4290
|
continue;
|
|
@@ -3981,7 +4325,7 @@ var INGRESS_PROBE_TIMEOUT_MS = 4e3;
|
|
|
3981
4325
|
var defaultDockerCapture = (args) => {
|
|
3982
4326
|
let result;
|
|
3983
4327
|
try {
|
|
3984
|
-
result =
|
|
4328
|
+
result = spawnSync2("docker", args, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 2e4 });
|
|
3985
4329
|
} catch (err) {
|
|
3986
4330
|
return { unavailable: true, status: null, stdout: "", stderr: err instanceof Error ? err.message : String(err) };
|
|
3987
4331
|
}
|
|
@@ -4135,16 +4479,57 @@ async function defaultFetchText(ref, authToken) {
|
|
|
4135
4479
|
if (!res.ok) throw new Error(`Failed to fetch ${ref}: HTTP ${res.status}`);
|
|
4136
4480
|
return res.text();
|
|
4137
4481
|
}
|
|
4482
|
+
function assertCredentialSafeAuditUrl(url) {
|
|
4483
|
+
let parsed;
|
|
4484
|
+
try {
|
|
4485
|
+
parsed = new URL(url);
|
|
4486
|
+
} catch {
|
|
4487
|
+
throw new Error(`Refusing to post a deploy audit to an unparseable URL: ${url}`);
|
|
4488
|
+
}
|
|
4489
|
+
if (parsed.protocol === "https:") return;
|
|
4490
|
+
const host = parsed.hostname.toLowerCase();
|
|
4491
|
+
if (host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]") return;
|
|
4492
|
+
throw new Error(
|
|
4493
|
+
`Refusing to post a deploy audit over ${parsed.protocol}// to ${parsed.host}: the request carries the license key in its body and a bearer token in its headers, which plain HTTP exposes to anything on the network path. Use an https:// endpoint (the default is https://api.askexe.com), or point it at localhost.`
|
|
4494
|
+
);
|
|
4495
|
+
}
|
|
4496
|
+
var MAX_AUDIT_REDIRECTS = 5;
|
|
4138
4497
|
async function defaultPostJson(url, body, authToken) {
|
|
4139
|
-
const
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4498
|
+
const payload = JSON.stringify(body);
|
|
4499
|
+
let target = url;
|
|
4500
|
+
let originOrigin;
|
|
4501
|
+
for (let hop = 0; ; hop++) {
|
|
4502
|
+
assertCredentialSafeAuditUrl(target);
|
|
4503
|
+
const targetOrigin = new URL(target).origin;
|
|
4504
|
+
if (originOrigin === void 0) {
|
|
4505
|
+
originOrigin = targetOrigin;
|
|
4506
|
+
} else if (targetOrigin !== originOrigin) {
|
|
4507
|
+
throw new Error(
|
|
4508
|
+
`Refusing to follow a deploy-audit redirect from ${originOrigin} to ${targetOrigin}: this request carries the license key in its body and a bearer token in its Authorization header, and this loop re-attaches both to every hop itself, so the Fetch spec's cross-origin credential stripping never applies. A redirect to a different origin \u2014 even one that is independently https \u2014 is refused rather than forwarded with credentials attached.`
|
|
4509
|
+
);
|
|
4510
|
+
}
|
|
4511
|
+
const res = await fetch(target, {
|
|
4512
|
+
method: "POST",
|
|
4513
|
+
headers: {
|
|
4514
|
+
"content-type": "application/json",
|
|
4515
|
+
...authToken ? { authorization: `Bearer ${authToken}` } : {}
|
|
4516
|
+
},
|
|
4517
|
+
body: payload,
|
|
4518
|
+
redirect: "manual"
|
|
4519
|
+
});
|
|
4520
|
+
if (res.status < 300 || res.status > 399) {
|
|
4521
|
+
if (!res.ok) throw new Error(`Failed to POST ${target}: HTTP ${res.status}`);
|
|
4522
|
+
return;
|
|
4523
|
+
}
|
|
4524
|
+
if (hop >= MAX_AUDIT_REDIRECTS) {
|
|
4525
|
+
throw new Error(`Failed to POST ${url}: more than ${MAX_AUDIT_REDIRECTS} redirects (last: ${target})`);
|
|
4526
|
+
}
|
|
4527
|
+
const location = res.headers.get("location");
|
|
4528
|
+
if (!location) {
|
|
4529
|
+
throw new Error(`Failed to POST ${target}: HTTP ${res.status} redirect with no Location header`);
|
|
4530
|
+
}
|
|
4531
|
+
target = new URL(location, target).toString();
|
|
4532
|
+
}
|
|
4148
4533
|
}
|
|
4149
4534
|
function defaultStackPaths() {
|
|
4150
4535
|
const cwdCompose = path.resolve("docker-compose.yml");
|
|
@@ -4201,7 +4586,7 @@ function parseComposeVolumeNames(composeRaw) {
|
|
|
4201
4586
|
return names;
|
|
4202
4587
|
}
|
|
4203
4588
|
function volumeHasComposeProjectLabel(volumeName, projectName) {
|
|
4204
|
-
const res =
|
|
4589
|
+
const res = spawnSync2(
|
|
4205
4590
|
"docker",
|
|
4206
4591
|
["volume", "inspect", volumeName, "--format", '{{ index .Labels "com.docker.compose.project" }}'],
|
|
4207
4592
|
{ encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 1e4 }
|
|
@@ -4230,7 +4615,7 @@ function detectDanglingVolumes(scope) {
|
|
|
4230
4615
|
byName.set(name, { name, driver: driver ?? "local", size: "" });
|
|
4231
4616
|
}
|
|
4232
4617
|
};
|
|
4233
|
-
const labeled =
|
|
4618
|
+
const labeled = spawnSync2(
|
|
4234
4619
|
"docker",
|
|
4235
4620
|
[
|
|
4236
4621
|
"volume",
|
|
@@ -4245,7 +4630,7 @@ function detectDanglingVolumes(scope) {
|
|
|
4245
4630
|
{ encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
|
|
4246
4631
|
);
|
|
4247
4632
|
if (labeled.status === 0 && labeled.stdout?.trim()) ingest(labeled.stdout, false);
|
|
4248
|
-
const all =
|
|
4633
|
+
const all = spawnSync2(
|
|
4249
4634
|
"docker",
|
|
4250
4635
|
["volume", "ls", "--filter", "dangling=true", "--format", "{{.Name}} {{.Driver}}"],
|
|
4251
4636
|
{ encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
|
|
@@ -4260,14 +4645,14 @@ function detectDanglingVolumes(scope) {
|
|
|
4260
4645
|
}
|
|
4261
4646
|
function getVolumeSize(volumeName) {
|
|
4262
4647
|
try {
|
|
4263
|
-
const inspectResult =
|
|
4648
|
+
const inspectResult = spawnSync2(
|
|
4264
4649
|
"docker",
|
|
4265
4650
|
["volume", "inspect", volumeName, "--format", "{{.Mountpoint}}"],
|
|
4266
4651
|
{ encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 1e4 }
|
|
4267
4652
|
);
|
|
4268
4653
|
const mountpoint = inspectResult.stdout?.trim();
|
|
4269
4654
|
if (!mountpoint || inspectResult.status !== 0) return "unknown";
|
|
4270
|
-
const duResult =
|
|
4655
|
+
const duResult = spawnSync2(
|
|
4271
4656
|
"du",
|
|
4272
4657
|
["-sh", mountpoint],
|
|
4273
4658
|
{ encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 1e4 }
|
|
@@ -4296,7 +4681,7 @@ function removeDanglingVolumes(volumes, scope) {
|
|
|
4296
4681
|
);
|
|
4297
4682
|
continue;
|
|
4298
4683
|
}
|
|
4299
|
-
const checkResult =
|
|
4684
|
+
const checkResult = spawnSync2(
|
|
4300
4685
|
"docker",
|
|
4301
4686
|
["volume", "ls", "--filter", "dangling=true", "--filter", `name=^${vol.name}$`, "--format", "{{.Name}}"],
|
|
4302
4687
|
{ encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 1e4 }
|
|
@@ -4403,6 +4788,7 @@ export {
|
|
|
4403
4788
|
isExecFormMigration,
|
|
4404
4789
|
expandComposeServicesWithSidecars,
|
|
4405
4790
|
resolveOwningManifestService,
|
|
4791
|
+
reconcileStackLockFromContainers,
|
|
4406
4792
|
composeArgsForStack,
|
|
4407
4793
|
parseStackManifest,
|
|
4408
4794
|
loadStackManifest,
|
|
@@ -4444,6 +4830,7 @@ export {
|
|
|
4444
4830
|
assertRolloutStageAllowed,
|
|
4445
4831
|
assertBreakingChangesAllowed,
|
|
4446
4832
|
verifyManifestImagesAvailable,
|
|
4833
|
+
verifyPreDeployImages,
|
|
4447
4834
|
collectImageProvenanceIssues,
|
|
4448
4835
|
assertImageProvenance,
|
|
4449
4836
|
collectImageVersionLabelIssues,
|
|
@@ -4473,6 +4860,8 @@ export {
|
|
|
4473
4860
|
verifyIngressTargetsReachable,
|
|
4474
4861
|
waitForHttpOk,
|
|
4475
4862
|
httpStatus,
|
|
4863
|
+
assertCredentialSafeAuditUrl,
|
|
4864
|
+
defaultPostJson,
|
|
4476
4865
|
defaultStackPaths,
|
|
4477
4866
|
resolveComposeProjectName,
|
|
4478
4867
|
parseComposeVolumeNames,
|