@askexenow/exe-os 0.9.346 → 0.9.348
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/cloudflared/config.yml.example +9 -6
- package/deploy/compose/docker-compose.yml +16 -9
- package/deploy/compose/sso-edge/default.conf.template +26 -0
- package/deploy/stack-manifests/v0.9.json +1 -1
- package/dist/{active-agent-Y7B6SUEV.js → active-agent-PX6KAEEQ.js} +4 -3
- package/dist/{active-agent-JXJFAZMM.js → active-agent-QVLZKWR2.js} +4 -3
- package/dist/{agentic-ontology-AUJAVTHS.js → agentic-ontology-6MEXY5L7.js} +1 -1
- package/dist/{backfill-metadata-3LUJK7D4.js → backfill-metadata-MCFBGWKX.js} +6 -5
- package/dist/{backup-verify-6UAZ5ETR.js → backup-verify-RGB3KKD4.js} +2 -1
- package/dist/{behaviors-BVOBYS73.js → behaviors-6GI6VND2.js} +7 -6
- package/dist/bin/agentic-ontology-backfill.js +7 -6
- package/dist/bin/agentic-reflection-backfill.js +8 -7
- package/dist/bin/agentic-semantic-label.js +7 -6
- package/dist/bin/backfill-conversations.js +6 -5
- package/dist/bin/backfill-responses.js +6 -5
- package/dist/bin/backfill-vectors.js +7 -6
- package/dist/bin/bulk-sync-postgres.js +11 -10
- package/dist/bin/cc-doctor.js +5 -4
- package/dist/bin/cleanup-stale-review-tasks.js +16 -15
- package/dist/bin/cli.js +16 -16
- package/dist/bin/deferred-daemon-restart.js +107 -94
- package/dist/bin/exe-agent-config.js +5 -4
- package/dist/bin/exe-agent.js +6 -5
- package/dist/bin/exe-assign.js +7 -6
- package/dist/bin/exe-boot.js +31 -30
- package/dist/bin/exe-call.js +6 -5
- package/dist/bin/exe-cloud.js +26 -15
- package/dist/bin/exe-config-dump.js +5 -4
- package/dist/bin/exe-dispatch.js +16 -15
- package/dist/bin/exe-doctor.js +5 -4
- package/dist/bin/exe-export-behaviors.js +9 -8
- package/dist/bin/exe-forget.js +8 -7
- package/dist/bin/exe-gateway.js +8 -7
- package/dist/bin/exe-healthcheck.js +5 -4
- package/dist/bin/exe-heartbeat.js +18 -17
- package/dist/bin/exe-kill.js +20 -19
- package/dist/bin/exe-launch-agent.js +26 -25
- package/dist/bin/exe-memory-reads.js +6 -5
- package/dist/bin/exe-new-employee.js +10 -9
- package/dist/bin/exe-os-mcp-proxy.js +4 -3
- package/dist/bin/exe-pending-messages.js +17 -16
- package/dist/bin/exe-pending-notifications.js +16 -15
- package/dist/bin/exe-pending-reviews.js +16 -15
- package/dist/bin/exe-rename.js +6 -5
- package/dist/bin/exe-review.js +19 -18
- package/dist/bin/exe-search.js +7 -6
- package/dist/bin/exe-session-cleanup.js +20 -19
- package/dist/bin/exe-settings.js +13 -12
- package/dist/bin/exe-start-codex.js +102 -21
- package/dist/bin/exe-start-opencode.js +11 -10
- package/dist/bin/exe-status.js +17 -16
- package/dist/bin/exe-support.js +3 -3
- package/dist/bin/exe-team.js +4 -3
- package/dist/bin/git-sweep.js +17 -16
- package/dist/bin/graph-backfill.js +7 -6
- package/dist/bin/graph-export.js +7 -6
- package/dist/bin/import-history.js +10 -9
- package/dist/bin/install.js +73 -73
- package/dist/bin/intercom-check.js +4 -4
- package/dist/bin/mcp-sessions.js +2 -2
- package/dist/bin/orchestration-metrics.js +5 -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 +1 -1
- package/dist/bin/reconcile-backlog.js +2 -2
- package/dist/bin/registry-proxy.js +1 -1
- package/dist/bin/scan-tasks.js +16 -15
- package/dist/bin/setup.js +2 -2
- package/dist/bin/shard-migrate.js +6 -5
- package/dist/bin/stack-update.js +7 -6
- package/dist/bin/vps-health-gate.js +1 -1
- package/dist/{boot-generation-IF4J6UEJ.js → boot-generation-FB2J53IG.js} +4 -3
- package/dist/{boot-review-sections-WEEFCSBX.js → boot-review-sections-QF5MZGJI.js} +15 -14
- package/dist/{capability-cards-C65NRVTL.js → capability-cards-YADEM2KN.js} +3 -2
- package/dist/{capacity-monitor-PGYDR35M.js → capacity-monitor-CG2IGONS.js} +17 -16
- package/dist/{catchup-brief-QB7M3OY7.js → catchup-brief-QFVNMTU5.js} +20 -19
- package/dist/{chunk-H5RS3XRJ.js → chunk-23O6LHII.js} +1 -1
- package/dist/{chunk-RLULWMUL.js → chunk-27REQ7KR.js} +1 -1
- package/dist/{chunk-GGPLVRYZ.js → chunk-2AD2GAPC.js} +1 -1
- package/dist/{chunk-25CXLXZQ.js → chunk-2WJYLXPF.js} +1 -1
- package/dist/{chunk-CFA4T2HP.js → chunk-43RTUMUT.js} +1 -1
- package/dist/{chunk-RYTY7KNZ.js → chunk-5C46Y4AK.js} +1 -1
- package/dist/{chunk-X7NSCRCD.js → chunk-5KCC26FB.js} +2 -2
- package/dist/{chunk-44ZGOBMU.js → chunk-5RPCWLXE.js} +1 -1
- package/dist/{chunk-ZASZQDAI.js → chunk-6GSYN262.js} +1 -1
- package/dist/{chunk-QS6KVXUN.js → chunk-6JQTSKDR.js} +263 -111
- package/dist/{chunk-QCM3YWL7.js → chunk-6QRS3IZF.js} +1 -1
- package/dist/{chunk-X2PLFBVG.js → chunk-6WFXNQDJ.js} +1 -1
- package/dist/{chunk-LUQ57SRM.js → chunk-7QRMFYOV.js} +23 -9
- package/dist/{chunk-HBJAMWHT.js → chunk-7WQ3WHPW.js} +195 -153
- package/dist/{chunk-OIF65HXR.js → chunk-A3YHWWE6.js} +10 -6
- package/dist/{chunk-OZLNCLS3.js → chunk-A42356G7.js} +1 -1
- package/dist/{chunk-24BHZNOP.js → chunk-A43SIGAO.js} +3 -3
- package/dist/{chunk-LSTIMHL4.js → chunk-AFY4V4N3.js} +1 -1
- package/dist/{chunk-Y7GJ6HXA.js → chunk-AJIXH5JF.js} +79 -25
- package/dist/{chunk-EU2GUT67.js → chunk-AMC2OPYP.js} +1 -1
- package/dist/{chunk-N4XVAP7Z.js → chunk-AQ24P2O7.js} +4 -4
- package/dist/{chunk-KQ3HRA6Q.js → chunk-AUILJKSM.js} +2 -2
- package/dist/{chunk-OQB5SKO4.js → chunk-AXNUMBLO.js} +3 -3
- package/dist/{chunk-SQIH3TDK.js → chunk-BOQUXG7N.js} +4 -4
- package/dist/{chunk-4A6RX2N6.js → chunk-BTP7BORU.js} +1 -1
- package/dist/{chunk-LYNELMA2.js → chunk-BUUGFQHL.js} +2 -2
- package/dist/{chunk-6OEMGMOV.js → chunk-CCOKYSJA.js} +3 -3
- package/dist/{chunk-6F3OMSZJ.js → chunk-DAODOSH4.js} +1 -1
- package/dist/{chunk-MWXXVXJL.js → chunk-DJYJDK53.js} +7 -7
- package/dist/{chunk-ZK6I3PUX.js → chunk-DXMTJJP3.js} +4 -4
- package/dist/{chunk-CMTS2MLG.js → chunk-E3BNUQHW.js} +2 -2
- package/dist/{chunk-YKIQF6EY.js → chunk-EFHGK6JP.js} +1 -1
- package/dist/{chunk-Q6ZQIX7L.js → chunk-FE6WBI2M.js} +5 -1
- package/dist/{chunk-6YABSGAW.js → chunk-FENYNW52.js} +1 -1
- package/dist/{chunk-4KLQ4GH5.js → chunk-FFCPSPNK.js} +1 -1
- package/dist/{chunk-FEIACXDV.js → chunk-FPK753IZ.js} +16 -16
- package/dist/{chunk-NCMFMJMZ.js → chunk-GA655CUD.js} +2 -2
- package/dist/{chunk-BDFRAQG5.js → chunk-GJ6KIHOM.js} +4 -4
- package/dist/{chunk-CR7XPLLC.js → chunk-GKNWKQFY.js} +1 -1
- package/dist/{chunk-VQLGFSML.js → chunk-GLOWJP5H.js} +2 -2
- package/dist/{chunk-XTGZDP2L.js → chunk-H3TA23PH.js} +4 -4
- package/dist/{chunk-GGHH54QD.js → chunk-H5QNVWU4.js} +18 -10
- package/dist/{chunk-WKUX5PFV.js → chunk-HL24OHHS.js} +9 -9
- package/dist/{chunk-3WELJGZN.js → chunk-HYZE3MNS.js} +1 -1
- package/dist/{chunk-HVZKJMJX.js → chunk-JORPYG4O.js} +1 -1
- package/dist/{chunk-JNEVNS5R.js → chunk-JW5XS35A.js} +9 -9
- package/dist/{chunk-OM2XM5HU.js → chunk-KIMAQNSM.js} +3 -3
- package/dist/{chunk-TIZE727O.js → chunk-KZUU6MNF.js} +1 -1
- package/dist/{chunk-OELDRRCZ.js → chunk-L36RX54F.js} +104 -11
- package/dist/{chunk-ZZQ4AEYB.js → chunk-M7PBRIRH.js} +1 -1
- package/dist/{chunk-4JDRUXQV.js → chunk-MGMXYI7Y.js} +2 -2
- package/dist/{chunk-4BQYN4IJ.js → chunk-MH5HWMVH.js} +1 -1
- package/dist/{chunk-BUDVHNV2.js → chunk-MMOONM6D.js} +1 -1
- package/dist/{chunk-CQN4IKRB.js → chunk-MMXIE6HV.js} +1 -1
- package/dist/{chunk-LNMTCTSH.js → chunk-MOZY4IQO.js} +1 -1
- package/dist/{chunk-EYGMCOTV.js → chunk-MVZLF27P.js} +2 -2
- package/dist/{chunk-HMVGXC4I.js → chunk-NY6DU5RB.js} +1 -1
- package/dist/{chunk-WMJK4GBF.js → chunk-O522M4YZ.js} +1 -1
- package/dist/{chunk-EDC57TDH.js → chunk-OBWIVRD6.js} +1 -1
- package/dist/{chunk-Q7UHMUCE.js → chunk-PAXAF2UY.js} +35 -15
- package/dist/{chunk-YLLUGK6J.js → chunk-PBLDPW4U.js} +2 -2
- package/dist/{chunk-D74XYSA3.js → chunk-QCQT5RXR.js} +5 -1
- package/dist/{chunk-3QYE5U6D.js → chunk-QNKR7WEL.js} +20 -6
- package/dist/{chunk-E6TLQG2T.js → chunk-RBRGSOK5.js} +1 -1
- package/dist/{chunk-6I6OMBYY.js → chunk-RFRUDXOI.js} +2 -2
- package/dist/{chunk-MHZAUM7G.js → chunk-SLH2743O.js} +3 -3
- package/dist/{chunk-LP6EJVVN.js → chunk-SMQ642D3.js} +4 -4
- package/dist/{chunk-BCFWDNH7.js → chunk-SQ4WACH4.js} +1 -1
- package/dist/{chunk-6LLDY7AL.js → chunk-TF5E6O5Q.js} +1 -1
- package/dist/{chunk-IXIQSWHV.js → chunk-TLWYOMSS.js} +3 -3
- package/dist/{chunk-2LC2ASCN.js → chunk-UAKGNQWE.js} +1 -1
- package/dist/{chunk-2WEUQWFQ.js → chunk-UTQWVRU6.js} +5 -5
- package/dist/{chunk-VPY4CMD6.js → chunk-WL3IQJKN.js} +3 -3
- package/dist/{chunk-NGP6LSV2.js → chunk-WNBZJSQT.js} +10 -1
- package/dist/{chunk-MCZWZEVE.js → chunk-WUMWXU6B.js} +1 -1
- package/dist/{chunk-R6C6UGVG.js → chunk-WWT3E7DO.js} +3 -3
- package/dist/{chunk-ACYZER3P.js → chunk-WZJ3VYRJ.js} +3 -3
- package/dist/{chunk-2KOQKLDF.js → chunk-X6VEQ7MC.js} +1 -1
- package/dist/{chunk-HXIBVZC3.js → chunk-Y3JXLIZV.js} +3 -3
- package/dist/{chunk-2UA263BM.js → chunk-YAIFZXOM.js} +5 -5
- package/dist/{chunk-YGTKGAWM.js → chunk-YM6GJM2F.js} +4 -4
- package/dist/chunk-YMUZWC33.js +8 -0
- package/dist/{chunk-DKKMBEU6.js → chunk-YTPCJLEL.js} +1 -1
- package/dist/{chunk-RPAMFCPP.js → chunk-Z52QQB4Z.js} +2 -2
- package/dist/{chunk-PJOHJ7Q4.js → chunk-ZXSFUR77.js} +172 -35
- package/dist/{cleanup-graph-garbage-INHZJESS.js → cleanup-graph-garbage-XTSBQXD6.js} +8 -7
- package/dist/{cloud-sync-shutdown-HNQ7T3LA.js → cloud-sync-shutdown-A2QB74YM.js} +3 -2
- package/dist/{co-activation-IMZM3IXG.js → co-activation-S2FVGMQP.js} +3 -2
- package/dist/{co-occurrence-PZAEUDAP.js → co-occurrence-VQB6U5ME.js} +6 -5
- package/dist/{conversation-entity-extractor-AU55E6YT.js → conversation-entity-extractor-YF3ZLTEJ.js} +3 -3
- package/dist/{crdt-sync-LI6FL3DG.js → crdt-sync-2SGCDWC3.js} +1 -1
- package/dist/{crm-webhook-NOLMWTAP.js → crm-webhook-P64SXEHD.js} +2 -2
- package/dist/{cto-delegation-gate-SZCLR4PI.js → cto-delegation-gate-6KLGT2LB.js} +15 -14
- package/dist/{daemon-orchestration-R5HT252K.js → daemon-orchestration-JQGKEWPD.js} +20 -20
- package/dist/{dispatch-ack-VUGMAGNL.js → dispatch-ack-AZL3WKCK.js} +1 -2
- package/dist/{doc-graph-extractor-E5SXO6NZ.js → doc-graph-extractor-DCJMATVZ.js} +6 -5
- package/dist/{documents-PYKWTZBA.js → documents-7EPH3VPE.js} +7 -6
- package/dist/{dreaming-JAHOTVRJ.js → dreaming-O4P2W5E5.js} +19 -18
- package/dist/{exe-drift-DGIY5YBT.js → exe-drift-ED7FBS2C.js} +4 -3
- package/dist/{exe-export-A6MC7LZ7.js → exe-export-YJI4USGZ.js} +9 -8
- package/dist/{exe-import-HKA6LKHC.js → exe-import-SUTAYKUW.js} +9 -8
- package/dist/{exe-key-6QXOAVR4.js → exe-key-CRSDAOZD.js} +71 -71
- package/dist/{exe-snapshot-BUPXYKMH.js → exe-snapshot-KB4YYDCA.js} +20 -19
- package/dist/{fast-db-init-BXLBA6II.js → fast-db-init-3K2PV6GJ.js} +1 -1
- package/dist/{founder-context-5KQR3ER3.js → founder-context-JHHFM4GF.js} +2 -2
- package/dist/gateway/index.js +9 -8
- package/dist/{git-main-guard-UZP3KXYI.js → git-main-guard-TGK3RQY3.js} +1 -1
- package/dist/{git-staleness-OTIXXNBN.js → git-staleness-YPHGWE3B.js} +3 -2
- package/dist/{global-procedures-ACYUMLIG.js → global-procedures-PEWDBSPJ.js} +5 -4
- package/dist/{graph-auto-extract-QWVENG4K.js → graph-auto-extract-7OJYYV4G.js} +6 -5
- package/dist/{graph-rag-2I24BQC2.js → graph-rag-YFITUAVO.js} +3 -3
- package/dist/{hook-prefetch-22IJRGX4.js → hook-prefetch-O6ZCZCTX.js} +16 -15
- package/dist/hooks/bug-report-worker.js +18 -18
- package/dist/hooks/codex-stop-task-finalizer.js +19 -19
- package/dist/hooks/commit-complete.js +18 -17
- package/dist/hooks/error-recall.js +8 -7
- package/dist/hooks/exe-heartbeat-hook.js +4 -3
- package/dist/hooks/ingest.js +7 -6
- package/dist/hooks/instructions-loaded.js +5 -4
- package/dist/hooks/manifest.json +19 -19
- package/dist/hooks/notification.js +5 -4
- package/dist/hooks/post-compact.js +17 -16
- package/dist/hooks/post-tool-combined.js +9 -9
- package/dist/hooks/pre-compact.js +18 -17
- package/dist/hooks/pre-tool-use.js +38 -40
- package/dist/hooks/prompt-submit.js +31 -30
- package/dist/hooks/session-end.js +22 -21
- package/dist/hooks/session-start.js +13 -13
- package/dist/hooks/stop.js +21 -20
- package/dist/hooks/subagent-stop.js +19 -18
- package/dist/hooks/summary-worker.js +22 -21
- package/dist/index.js +25 -24
- package/dist/{installer-QYXL3HBG.js → installer-3ONNP5JV.js} +6 -5
- package/dist/{installer-RWPVEBMJ.js → installer-CY5PN7TN.js} +6 -5
- package/dist/{installer-NZ76KPYJ.js → installer-N4QXGINR.js} +6 -5
- package/dist/{intercom-queue-TAARE4O7.js → intercom-queue-A52WQOCD.js} +15 -14
- package/dist/lib/agent-config.js +2 -2
- package/dist/lib/cloud-sync.js +15 -10
- package/dist/lib/consolidation.js +8 -7
- package/dist/lib/database.js +5 -2
- package/dist/lib/db-backup.js +2 -1
- package/dist/lib/db-checkpoint-worker.js +9 -0
- package/dist/lib/db-read-worker-client.js +21 -8
- package/dist/lib/db-read-worker.js +15 -0
- package/dist/lib/db-write-worker-client.js +4 -1
- package/dist/lib/db-write-worker.js +21 -6
- package/dist/lib/db.js +5 -2
- package/dist/lib/device-registry.js +1 -1
- package/dist/lib/employee-templates.js +6 -5
- package/dist/lib/employees.js +3 -2
- package/dist/lib/exe-daemon.js +344 -179
- package/dist/lib/hybrid-search.js +7 -6
- package/dist/lib/identity.js +3 -2
- package/dist/lib/license.js +2 -2
- package/dist/lib/messaging.js +16 -15
- package/dist/lib/registry-proxy.js +1 -1
- package/dist/lib/reminders.js +4 -3
- package/dist/lib/runtime-table.js +9 -3
- package/dist/lib/schedules.js +7 -6
- package/dist/lib/session-registry.js +5 -4
- package/dist/lib/skill-learning.js +8 -7
- package/dist/lib/store.js +6 -5
- package/dist/lib/task-router.js +4 -3
- package/dist/lib/tasks.js +17 -17
- package/dist/lib/tmux-routing.js +15 -14
- package/dist/lib/token-spend.js +4 -3
- package/dist/{license-gate-CVHDQZJV.js → license-gate-ZRORTAQ2.js} +3 -3
- package/dist/{license-sync-72S7BWQY.js → license-sync-CQHBDUQE.js} +2 -2
- package/dist/mcp/register-tools.js +70 -70
- package/dist/mcp/server.js +71 -71
- package/dist/mcp/tools/complete-reminder.js +5 -4
- package/dist/mcp/tools/create-reminder.js +5 -4
- package/dist/mcp/tools/create-task.js +19 -19
- package/dist/mcp/tools/deactivate-behavior.js +9 -8
- package/dist/mcp/tools/list-reminders.js +5 -4
- package/dist/mcp/tools/list-tasks.js +19 -19
- package/dist/mcp/tools/send-message.js +18 -17
- package/dist/mcp/tools/update-task.js +18 -18
- package/dist/{mcp-http-config-JP3XSY2X.js → mcp-http-config-2A6HKQP5.js} +4 -3
- package/dist/{mcp-session-identity-DDAM464U.js → mcp-session-identity-OPRX32H5.js} +15 -14
- package/dist/{memory-cards-XJ2JMF3V.js → memory-cards-GFO2CSPV.js} +6 -5
- package/dist/{memory-graph-extractor-FJVF7RTG.js → memory-graph-extractor-2Z72HN5P.js} +7 -6
- package/dist/{memory-poisoning-defense-GM3GQPRI.js → memory-poisoning-defense-WZJ52KXT.js} +3 -2
- package/dist/{memory-pressure-watchdog-HB572OZG.js → memory-pressure-watchdog-IG7VRFIX.js} +16 -15
- package/dist/{memory-reflection-WIMMTW7M.js → memory-reflection-LTRHDGUL.js} +3 -2
- package/dist/{notification-ledger-5TQXBYY2.js → notification-ledger-KSCPGLQG.js} +16 -15
- package/dist/{notifications-LA3X57YT.js → notifications-YKHZPCXU.js} +15 -14
- package/dist/{orchestration-events-KFZMGU3D.js → orchestration-events-HAFDPTLV.js} +4 -3
- package/dist/{orchestrator-MOJEAZ3K.js → orchestrator-4MZEQULR.js} +17 -16
- package/dist/{pipeline-router-2V5NFQ2O.js → pipeline-router-RSRJPZNI.js} +4 -3
- package/dist/{plan-limits-2LHFEYOT.js → plan-limits-5QYYPIPT.js} +6 -5
- package/dist/{platform-procedures-G44IYUM2.js → platform-procedures-DZ6YABEK.js} +1 -1
- package/dist/{projection-worker-ZMHVILPW.js → projection-worker-SKAMSZJF.js} +2 -2
- package/dist/{prospective-memory-JEWS5GFU.js → prospective-memory-V7LFCPU4.js} +3 -2
- package/dist/{reranker-TBQV76K4.js → reranker-HXMJ7SKW.js} +1 -1
- package/dist/{retrieval-health-HYXDUNFE.js → retrieval-health-4NCBHUUS.js} +1 -1
- package/dist/{review-polling-OFGP5Q7M.js → review-polling-KQUALBEU.js} +16 -15
- package/dist/runtime/index.js +19 -18
- package/dist/{session-events-ABAI2KE3.js → session-events-3KL735DZ.js} +16 -15
- package/dist/{session-kill-telemetry-2MHLK4Z4.js → session-kill-telemetry-KVRGLYVI.js} +16 -15
- package/dist/{session-scope-MRIE7ZKS.js → session-scope-LBG6DT5O.js} +15 -14
- package/dist/{setup-wizard-UQ3B2E6D.js → setup-wizard-UL3AKI6E.js} +2 -2
- package/dist/{skill-refinement-46QDGAGE.js → skill-refinement-6HPISXQC.js} +4 -3
- package/dist/{stack-update-5BPENFJK.js → stack-update-WBDTJJEF.js} +7 -3
- package/dist/{steward-gate-GXINMHNV.js → steward-gate-CWPD4HEK.js} +4 -3
- package/dist/{support-inbox-TCOASPLK.js → support-inbox-HRIHHKPU.js} +3 -3
- package/dist/{task-enforcement-OJAG2BGJ.js → task-enforcement-OAOL7XFL.js} +16 -15
- package/dist/{task-scope-5GKJTQL2.js → task-scope-PSVAE3EM.js} +15 -14
- package/dist/{tasks-crud-ZWKPTGPU.js → tasks-crud-TLELWWUL.js} +17 -14
- package/dist/{tasks-notify-IUDI6SYJ.js → tasks-notify-7Q2XTDZ7.js} +16 -16
- package/dist/{tasks-review-INJKVN63.js → tasks-review-S6QB5KGS.js} +15 -14
- package/dist/{telemetry-upload-LIC7M7AY.js → telemetry-upload-LTL5SW24.js} +8 -7
- package/dist/{token-budget-PABF5ZBO.js → token-budget-SK32GKFZ.js} +4 -3
- package/dist/{tool-telemetry-PDHE36YD.js → tool-telemetry-QJGJAHOC.js} +1 -1
- package/dist/tui/App.js +24 -23
- package/dist/{tui-data-Y6X7A4U4.js → tui-data-3JSV56ME.js} +15 -14
- package/dist/{update-support-COJYGU2V.js → update-support-LMPGWJVG.js} +10 -9
- package/dist/{work-state-heartbeat-YV3MAIQY.js → work-state-heartbeat-MQQOCU54.js} +1 -1
- package/dist/{worker-gate-BLJENHMV.js → worker-gate-P2O64XMH.js} +1 -1
- package/dist/{workflow-engine-AAPPPMFS.js → workflow-engine-BLLQKA3O.js} +2 -2
- package/dist/{worktree-MGYTWKCA.js → worktree-FJZXHDCJ.js} +5 -4
- package/dist/{worktree-sweep-HNNHNAXN.js → worktree-sweep-SW4AG6JR.js} +6 -5
- package/package.json +1 -1
- package/release-notes.json +56 -104
- package/dist/chunk-GSIJL4YA.js +0 -58
- /package/dist/{chunk-GH5YKFE7.js → chunk-AQ6ECPUP.js} +0 -0
- /package/dist/{chunk-O3XAKSKI.js → chunk-DRHXISWL.js} +0 -0
- /package/dist/{chunk-A3MGVYSP.js → chunk-E42D2E5F.js} +0 -0
- /package/dist/{chunk-PDN25UJU.js → chunk-FXZRJT3H.js} +0 -0
- /package/dist/{chunk-CHDPANT4.js → chunk-GFIWADEH.js} +0 -0
- /package/dist/{chunk-W7JPRQM2.js → chunk-GPZQZTJB.js} +0 -0
- /package/dist/{chunk-WPQ5LWMW.js → chunk-H4JKOLXU.js} +0 -0
- /package/dist/{chunk-RYWVPACG.js → chunk-HTJKAAHD.js} +0 -0
- /package/dist/{chunk-PDWIUSQH.js → chunk-PIUDQ7P2.js} +0 -0
- /package/dist/{chunk-HIN6X5QB.js → chunk-QUOMJKVF.js} +0 -0
- /package/dist/{chunk-DY7WDHMC.js → chunk-XF2D4CDA.js} +0 -0
- /package/dist/{core-memory-TBLZ2YQQ.js → core-memory-Z7LPR3RX.js} +0 -0
- /package/dist/{oauth-server-IB7OWY4H.js → oauth-server-FSKABATB.js} +0 -0
- /package/dist/{project-boot-TI3PUQNN.js → project-boot-FVSC4VQC.js} +0 -0
- /package/dist/{wiki-acl-V5IRECJ3.js → wiki-acl-CW2UALTJ.js} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadLicense
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-MMOONM6D.js";
|
|
4
4
|
|
|
5
5
|
// src/lib/stack-update.ts
|
|
6
6
|
import { execFileSync, spawnSync } from "child_process";
|
|
@@ -299,6 +299,8 @@ async function rollbackStackUpdate(options) {
|
|
|
299
299
|
} catch {
|
|
300
300
|
}
|
|
301
301
|
const backupComposeFile = lockData?.backupComposeFile;
|
|
302
|
+
const backupComposeOverrideFile = lockData?.backupComposeOverrideFile;
|
|
303
|
+
const composeOverrideFile = composeOverrideFileFor(options.composeFile);
|
|
302
304
|
if (!options.serviceName) {
|
|
303
305
|
try {
|
|
304
306
|
if (existsSync(options.composeFile)) {
|
|
@@ -307,27 +309,41 @@ async function rollbackStackUpdate(options) {
|
|
|
307
309
|
} catch {
|
|
308
310
|
}
|
|
309
311
|
if (backupComposeFile && existsSync(backupComposeFile)) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
);
|
|
312
|
+
copyFileSync(backupComposeFile, options.composeFile);
|
|
313
|
+
console.log(`[stack-update] Restored docker-compose.yml from ${backupComposeFile}`);
|
|
313
314
|
} else {
|
|
314
315
|
console.log("[stack-update] No backed-up docker-compose.yml in lock \u2014 rolling back image tags via .env on the current compose.");
|
|
315
316
|
}
|
|
317
|
+
try {
|
|
318
|
+
if (backupComposeOverrideFile && existsSync(backupComposeOverrideFile)) {
|
|
319
|
+
copyFileSync(backupComposeOverrideFile, composeOverrideFile);
|
|
320
|
+
console.log(`[stack-update] Restored docker-compose.override.yml from ${backupComposeOverrideFile}`);
|
|
321
|
+
} else if (lockData?.hadComposeOverrideFile === false && existsSync(composeOverrideFile)) {
|
|
322
|
+
rmSync(composeOverrideFile, { force: true });
|
|
323
|
+
console.log("[stack-update] Removed docker-compose.override.yml because it was absent from the pre-update snapshot.");
|
|
324
|
+
}
|
|
325
|
+
} catch (overrideErr) {
|
|
326
|
+
const reason = overrideErr instanceof Error ? overrideErr.message : String(overrideErr);
|
|
327
|
+
console.warn(`[stack-update] Could not restore docker-compose.override.yml (${reason}); continuing rollback.`);
|
|
328
|
+
}
|
|
316
329
|
}
|
|
317
330
|
const scopedServiceNames = options.serviceName ? Object.entries(lockData?.services ?? {}).filter(([name, service]) => name === options.serviceName || (service.composeService ?? name) === options.serviceName).map(([name]) => name) : [];
|
|
318
331
|
const rollbackEnvRaw = readFileSync(rollbackEnv, "utf8");
|
|
319
332
|
if (scopedServiceNames.length > 0 && lockData?.services) {
|
|
320
333
|
const rollbackEnvMap = parseEnv(rollbackEnvRaw);
|
|
334
|
+
const scopedEnvKeys = scopedServiceNames.map((serviceName) => lockData.services[serviceName].env).filter((key) => Boolean(key));
|
|
335
|
+
const mutatedEnvKeys = lockData.mutatedEnvKeys ?? [];
|
|
336
|
+
const restoreEnvKeys = [.../* @__PURE__ */ new Set([...scopedEnvKeys, ...mutatedEnvKeys])];
|
|
321
337
|
const scopedUpdates = Object.fromEntries(
|
|
322
|
-
|
|
338
|
+
restoreEnvKeys.map((key) => [key, rollbackEnvMap.get(key) ?? ""])
|
|
323
339
|
);
|
|
324
|
-
console.log(`[stack-update] Restoring env keys for service ${scopedServiceNames.join(", ")} from ${rollbackEnv}`);
|
|
340
|
+
console.log(`[stack-update] Restoring env keys for service ${scopedServiceNames.join(", ")} from ${rollbackEnv}: ${restoreEnvKeys.join(", ")}`);
|
|
325
341
|
writeSecretFile(options.envFile, patchEnv(readFileSync(options.envFile, "utf8"), scopedUpdates));
|
|
326
342
|
} else {
|
|
327
343
|
console.log(`[stack-update] Restoring env from ${rollbackEnv}`);
|
|
328
344
|
writeSecretFile(options.envFile, rollbackEnvRaw);
|
|
329
345
|
}
|
|
330
|
-
const composeArgs =
|
|
346
|
+
const composeArgs = composeArgsForStack(options.composeFile, options.envFile);
|
|
331
347
|
if (lockData?.services) {
|
|
332
348
|
for (const [serviceName, service] of Object.entries(lockData.services)) {
|
|
333
349
|
if (scopedServiceNames.length > 0 && !scopedServiceNames.includes(serviceName)) continue;
|
|
@@ -440,6 +456,22 @@ function manifestImagesForPull(release) {
|
|
|
440
456
|
Object.values(release.services).map((service) => imagePullRef(service.image.trim())).filter(Boolean)
|
|
441
457
|
));
|
|
442
458
|
}
|
|
459
|
+
var COMPOSE_SIDECARS = {
|
|
460
|
+
// exe-crm-worker uses the same CRM_IMAGE_TAG as exe-crm but is a distinct
|
|
461
|
+
// compose service. Pull/restart it whenever the CRM API image changes so the
|
|
462
|
+
// API and worker cannot drift to different versions. (bug 9e324fd2)
|
|
463
|
+
"exe-crm": ["exe-crm-worker"],
|
|
464
|
+
"exe-erp": ["exe-erp-nginx", "exe-erp-websocket", "exe-erp-queue", "exe-erp-scheduler"]
|
|
465
|
+
};
|
|
466
|
+
function expandComposeServicesWithSidecars(primaryComposeServices) {
|
|
467
|
+
const expanded = [...primaryComposeServices];
|
|
468
|
+
for (const primary of primaryComposeServices) {
|
|
469
|
+
for (const sidecar of COMPOSE_SIDECARS[primary] ?? []) {
|
|
470
|
+
if (!expanded.includes(sidecar)) expanded.push(sidecar);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return expanded;
|
|
474
|
+
}
|
|
443
475
|
function cloneReleaseWithServices(release, serviceNames) {
|
|
444
476
|
const wanted = new Set(serviceNames);
|
|
445
477
|
const services = {};
|
|
@@ -463,6 +495,18 @@ function readStackUpdateLock(lockFile) {
|
|
|
463
495
|
function writeStackUpdateLock(lockFile, data) {
|
|
464
496
|
writeFileSync(lockFile, JSON.stringify(data, null, 2) + "\n");
|
|
465
497
|
}
|
|
498
|
+
function composeOverrideFileFor(composeFile) {
|
|
499
|
+
return path.join(path.dirname(composeFile), "docker-compose.override.yml");
|
|
500
|
+
}
|
|
501
|
+
function composeArgsForStack(composeFile, envFile, includeOverride = true) {
|
|
502
|
+
const args = ["compose", "--file", composeFile];
|
|
503
|
+
const overrideFile = composeOverrideFileFor(composeFile);
|
|
504
|
+
if (includeOverride && existsSync(overrideFile)) {
|
|
505
|
+
args.push("--file", overrideFile);
|
|
506
|
+
}
|
|
507
|
+
args.push("--env-file", envFile);
|
|
508
|
+
return args;
|
|
509
|
+
}
|
|
466
510
|
function buildInitialServiceStatus(plan, envRaw, now, activeServices) {
|
|
467
511
|
const env = parseEnv(envRaw);
|
|
468
512
|
const at = now().toISOString();
|
|
@@ -991,26 +1035,64 @@ function parseManualRegistryCredentials(raw, sampleImage) {
|
|
|
991
1035
|
if (!username || !password) return void 0;
|
|
992
1036
|
return { registry: registryFromImage(sampleImage ?? ""), username, password };
|
|
993
1037
|
}
|
|
1038
|
+
async function resolveStackImageCredentials(options, release) {
|
|
1039
|
+
const images = release ? manifestImagesForPull(release) : [];
|
|
1040
|
+
const sampleImage = images.find((image) => image.startsWith("update.askexe.com/")) ?? images.find((image) => image.startsWith("ghcr.io/")) ?? images[0] ?? "";
|
|
1041
|
+
const fetched = await fetchImageCredentials(options);
|
|
1042
|
+
if (fetched) return fetched;
|
|
1043
|
+
const manual = parseManualRegistryCredentials(options.registryCredentials || process.env.EXE_REGISTRY_CREDENTIALS, sampleImage);
|
|
1044
|
+
if (manual) return manual;
|
|
1045
|
+
if (images.some((image) => image.startsWith("update.askexe.com/"))) {
|
|
1046
|
+
const stackEnvPullTokensRaw = process.env.EXE_REGISTRY_PROXY_PULL_TOKENS || (options.envFile && existsSync(options.envFile) ? (() => {
|
|
1047
|
+
const envMap = parseEnv(readFileSync(options.envFile, "utf8"));
|
|
1048
|
+
return envMap.get("EXE_REGISTRY_PROXY_PULL_TOKENS") ?? "";
|
|
1049
|
+
})() : "");
|
|
1050
|
+
const firstPullToken = stackEnvPullTokensRaw.split(/[\n,]/).map((s) => s.trim()).find(Boolean);
|
|
1051
|
+
if (firstPullToken) {
|
|
1052
|
+
return { registry: "update.askexe.com", username: "token", password: firstPullToken };
|
|
1053
|
+
}
|
|
1054
|
+
const licenseKey = options.manifestAuthToken || options.licenseKey || process.env.EXE_LICENSE_KEY;
|
|
1055
|
+
if (licenseKey) {
|
|
1056
|
+
return { registry: "update.askexe.com", username: "license", password: licenseKey };
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
return null;
|
|
1060
|
+
}
|
|
994
1061
|
async function verifyManifestImagesAvailable(plan, options) {
|
|
995
1062
|
const exec = options.exec ?? defaultExec;
|
|
996
1063
|
const images = manifestImagesForPull(plan.release);
|
|
997
|
-
const
|
|
1064
|
+
const maxAttempts = Math.max(1, Math.floor(options.verifyImageMaxAttempts ?? 3));
|
|
1065
|
+
const baseDelayMs = Math.max(0, Math.floor(options.verifyImageRetryBaseDelayMs ?? 1e3));
|
|
998
1066
|
let registryForLogout;
|
|
999
|
-
const creds = await
|
|
1067
|
+
const creds = await resolveStackImageCredentials(options, plan.release);
|
|
1000
1068
|
if (creds) {
|
|
1001
1069
|
(options.dockerLogin ?? defaultDockerLogin)(creds);
|
|
1002
1070
|
registryForLogout = creds.registry;
|
|
1003
1071
|
}
|
|
1004
1072
|
try {
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1073
|
+
const results = [];
|
|
1074
|
+
for (const image of images) {
|
|
1075
|
+
let lastError = "";
|
|
1076
|
+
let ok = false;
|
|
1077
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
1078
|
+
try {
|
|
1079
|
+
exec("docker", ["manifest", "inspect", image]);
|
|
1080
|
+
ok = true;
|
|
1081
|
+
break;
|
|
1082
|
+
} catch (err) {
|
|
1083
|
+
lastError = err instanceof Error ? err.message : String(err);
|
|
1084
|
+
if (attempt < maxAttempts) {
|
|
1085
|
+
const delayMs = baseDelayMs * Math.pow(2, attempt - 1);
|
|
1086
|
+
console.warn(
|
|
1087
|
+
`[stack-update] manifest inspect failed for ${image} (attempt ${attempt}/${maxAttempts}): ${lastError}. Retrying in ${delayMs}ms.`
|
|
1088
|
+
);
|
|
1089
|
+
if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1012
1092
|
}
|
|
1013
|
-
|
|
1093
|
+
results.push(ok ? { image, ok: true } : { image, ok: false, error: `manifest inspect failed after ${maxAttempts} attempt(s): ${lastError}` });
|
|
1094
|
+
}
|
|
1095
|
+
return results;
|
|
1014
1096
|
} finally {
|
|
1015
1097
|
if (registryForLogout) {
|
|
1016
1098
|
try {
|
|
@@ -1020,6 +1102,54 @@ async function verifyManifestImagesAvailable(plan, options) {
|
|
|
1020
1102
|
}
|
|
1021
1103
|
}
|
|
1022
1104
|
}
|
|
1105
|
+
function servicesForPullImage(release, image) {
|
|
1106
|
+
return Object.entries(release.services).filter(([, service]) => imagePullRef(service.image) === image).map(([serviceName, service]) => {
|
|
1107
|
+
const composeService = service.composeService ?? serviceName;
|
|
1108
|
+
return composeService === serviceName ? serviceName : `${serviceName} (${composeService})`;
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
function serviceListForPullImage(release, image) {
|
|
1112
|
+
const services = servicesForPullImage(release, image);
|
|
1113
|
+
return services.length > 0 ? services.join(", ") : "unknown service";
|
|
1114
|
+
}
|
|
1115
|
+
function allServiceList(release) {
|
|
1116
|
+
return Object.keys(release.services).join(", ") || "unknown service";
|
|
1117
|
+
}
|
|
1118
|
+
function errorMessage(err) {
|
|
1119
|
+
return err instanceof Error ? err.message : String(err);
|
|
1120
|
+
}
|
|
1121
|
+
function packagedComposeTemplatePath(options) {
|
|
1122
|
+
return options.composeTemplateFileForUpdate ?? path.join(resolvePackageRoot(), "deploy", "compose", "docker-compose.yml");
|
|
1123
|
+
}
|
|
1124
|
+
function readStagedComposeTemplate(options, currentComposeRaw) {
|
|
1125
|
+
const templatePath = packagedComposeTemplatePath(options);
|
|
1126
|
+
if (!existsSync(templatePath)) {
|
|
1127
|
+
return { raw: currentComposeRaw, templatePath, templateFound: false, shouldRefresh: false };
|
|
1128
|
+
}
|
|
1129
|
+
const raw = readFileSync(templatePath, "utf8");
|
|
1130
|
+
return { raw, templatePath, templateFound: true, shouldRefresh: raw !== currentComposeRaw };
|
|
1131
|
+
}
|
|
1132
|
+
async function assertPreDeployImagesPullable(plan, options) {
|
|
1133
|
+
let results;
|
|
1134
|
+
try {
|
|
1135
|
+
results = await verifyManifestImagesAvailable(plan, options);
|
|
1136
|
+
} catch (err) {
|
|
1137
|
+
throw new Error(
|
|
1138
|
+
`Pre-deploy registry authentication check failed before any production service was changed. Aborting stack update for service(s) ${allServiceList(plan.release)}: ${errorMessage(err)}`
|
|
1139
|
+
);
|
|
1140
|
+
}
|
|
1141
|
+
const failed = results.filter((r) => !r.ok);
|
|
1142
|
+
if (failed.length === 0) return;
|
|
1143
|
+
const details = failed.map((failure) => {
|
|
1144
|
+
const services = serviceListForPullImage(plan.release, failure.image);
|
|
1145
|
+
return ` - ${services}: ${failure.image}${failure.error ? ` \u2014 ${failure.error}` : ""}`;
|
|
1146
|
+
}).join("\n");
|
|
1147
|
+
throw new Error(
|
|
1148
|
+
`Pre-deploy image pullability check failed \u2014 aborting before any production service was changed.
|
|
1149
|
+
${details}
|
|
1150
|
+
Fix registry authentication or publish the missing image(s), then re-run stack-update.`
|
|
1151
|
+
);
|
|
1152
|
+
}
|
|
1023
1153
|
function commandSucceeds(cmd, args = []) {
|
|
1024
1154
|
const res = spawnSync(cmd, args, { stdio: "ignore" });
|
|
1025
1155
|
return res.status === 0;
|
|
@@ -1179,6 +1309,18 @@ function backupStackConfig(stackDir, composeFile, envRaw, now = () => /* @__PURE
|
|
|
1179
1309
|
} catch {
|
|
1180
1310
|
backupComposeFile = void 0;
|
|
1181
1311
|
}
|
|
1312
|
+
const composeOverrideFile = composeOverrideFileFor(composeFile);
|
|
1313
|
+
const hadComposeOverrideFile = existsSync(composeOverrideFile);
|
|
1314
|
+
let backupComposeOverrideFile;
|
|
1315
|
+
try {
|
|
1316
|
+
if (hadComposeOverrideFile) {
|
|
1317
|
+
backupComposeOverrideFile = path.join(updateBackupDir, "docker-compose.override.yml.bak");
|
|
1318
|
+
copyFileSync(composeOverrideFile, backupComposeOverrideFile);
|
|
1319
|
+
copyFileSync(composeOverrideFile, path.join(updateBackupDir, "docker-compose.override.yml"));
|
|
1320
|
+
}
|
|
1321
|
+
} catch {
|
|
1322
|
+
backupComposeOverrideFile = void 0;
|
|
1323
|
+
}
|
|
1182
1324
|
for (const f of [...PROTECTED_CONFIG_FILES, ...BOOTSTRAP_OVERWRITTEN_CONFIG_FILES]) {
|
|
1183
1325
|
const src = path.join(stackDir, f);
|
|
1184
1326
|
try {
|
|
@@ -1212,7 +1354,7 @@ function backupStackConfig(stackDir, composeFile, envRaw, now = () => /* @__PURE
|
|
|
1212
1354
|
} catch {
|
|
1213
1355
|
}
|
|
1214
1356
|
console.log(`[stack-update] Config backed up to ${updateBackupDir}`);
|
|
1215
|
-
return { updateBackupDir, backupEnvFile, backupComposeFile };
|
|
1357
|
+
return { updateBackupDir, backupEnvFile, backupComposeFile, backupComposeOverrideFile, hadComposeOverrideFile };
|
|
1216
1358
|
}
|
|
1217
1359
|
function installDockerUbuntu(exec) {
|
|
1218
1360
|
if (process.platform !== "linux") throw new Error("Docker auto-install is only supported on Linux. Install Docker manually, then retry.");
|
|
@@ -1584,7 +1726,7 @@ function hardenSsh(exec, result) {
|
|
|
1584
1726
|
}
|
|
1585
1727
|
function areStackContainersRunning(composeFile, envFile) {
|
|
1586
1728
|
try {
|
|
1587
|
-
const result = spawnSync("docker", [
|
|
1729
|
+
const result = spawnSync("docker", [...composeArgsForStack(composeFile, envFile), "ps", "-q"], {
|
|
1588
1730
|
stdio: ["pipe", "pipe", "pipe"],
|
|
1589
1731
|
timeout: 15e3
|
|
1590
1732
|
});
|
|
@@ -1795,6 +1937,7 @@ async function runStackUpdate(options) {
|
|
|
1795
1937
|
const scopedServiceNames = options.serviceName ? [options.serviceName] : resumeServices;
|
|
1796
1938
|
const effectiveTargetVersion = options.targetVersion ?? resumeLock?.stackVersion;
|
|
1797
1939
|
const composeRaw = readFileSync(options.composeFile, "utf8");
|
|
1940
|
+
const stagedCompose = readStagedComposeTemplate(options, composeRaw);
|
|
1798
1941
|
const plan = createStackUpdatePlan(manifest, envRaw, effectiveTargetVersion, scopedServiceNames, serviceSelection, composeRaw);
|
|
1799
1942
|
const fullTargetPlan = scopedServiceNames.length > 0 ? createStackUpdatePlan(manifest, envRaw, effectiveTargetVersion, void 0, serviceSelection, composeRaw) : plan;
|
|
1800
1943
|
assertRolloutStageAllowed(plan, {
|
|
@@ -1803,7 +1946,20 @@ async function runStackUpdate(options) {
|
|
|
1803
1946
|
});
|
|
1804
1947
|
assertBreakingChangesAllowed(plan, options.allowedBreakingChangeIds ?? []);
|
|
1805
1948
|
assertDeploymentScopeAllowed(plan, options.deploymentPersona ?? "customer");
|
|
1806
|
-
const
|
|
1949
|
+
const requiredEnvValidation = options.dryRun ? { derived: {}, unresolvable: [] } : detectMissingRequiredEnvVars(stagedCompose.raw, envRaw);
|
|
1950
|
+
const migratedEnvVars = requiredEnvValidation.derived;
|
|
1951
|
+
if (requiredEnvValidation.unresolvable.length > 0) {
|
|
1952
|
+
const lines = requiredEnvValidation.unresolvable.map((r) => ` - ${r.key}${r.message ? ` (${r.message})` : ""}`);
|
|
1953
|
+
throw new Error(
|
|
1954
|
+
`Stack update aborted before any changes: the updated compose template requires env vars that are missing from ${options.envFile} and cannot be derived automatically.
|
|
1955
|
+
Set these in ${options.envFile}, then re-run stack-update:
|
|
1956
|
+
${lines.join("\n")}`
|
|
1957
|
+
);
|
|
1958
|
+
}
|
|
1959
|
+
const plannedEnvRaw = patchEnv(envRaw, {
|
|
1960
|
+
...migratedEnvVars,
|
|
1961
|
+
...Object.fromEntries(plan.changes.map((c) => [c.key, c.after]))
|
|
1962
|
+
});
|
|
1807
1963
|
assertProductionDeployGate(plan, plannedEnvRaw, composeRaw, {
|
|
1808
1964
|
breakGlassReason: options.breakGlassReason,
|
|
1809
1965
|
breakGlassAuditFile: options.breakGlassAuditFile,
|
|
@@ -1830,6 +1986,11 @@ async function runStackUpdate(options) {
|
|
|
1830
1986
|
if (options.dryRun || !options.resume && plan.changes.length === 0 && containersRunning) {
|
|
1831
1987
|
return { status: "planned", targetVersion: plan.targetVersion, changes: plan.changes, lockFile };
|
|
1832
1988
|
}
|
|
1989
|
+
if (!options.skipImageAvailabilityCheck) {
|
|
1990
|
+
console.log("[stack-update] Pre-deploy image auth/pullability check started");
|
|
1991
|
+
await assertPreDeployImagesPullable(plan, options);
|
|
1992
|
+
console.log("[stack-update] \u2713 Pre-deploy image auth/pullability check passed");
|
|
1993
|
+
}
|
|
1833
1994
|
await postDeployAudit(options, "started", plan.targetVersion, previousVersion);
|
|
1834
1995
|
try {
|
|
1835
1996
|
if (!options.preDeployBackup) {
|
|
@@ -1843,13 +2004,13 @@ async function runStackUpdate(options) {
|
|
|
1843
2004
|
const updateBackupDir = configBackup.updateBackupDir;
|
|
1844
2005
|
const backupEnvFile = configBackup.backupEnvFile;
|
|
1845
2006
|
const backupComposeFile = configBackup.backupComposeFile;
|
|
2007
|
+
const backupComposeOverrideFile = configBackup.backupComposeOverrideFile;
|
|
2008
|
+
const hadComposeOverrideFile = configBackup.hadComposeOverrideFile;
|
|
1846
2009
|
try {
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
const templateRaw = readFileSync(templateCompose, "utf8");
|
|
1850
|
-
if (templateRaw !== composeRaw) {
|
|
2010
|
+
if (stagedCompose.templateFound) {
|
|
2011
|
+
if (stagedCompose.shouldRefresh) {
|
|
1851
2012
|
const tmpCompose = `${options.composeFile}.tmp-${process.pid}`;
|
|
1852
|
-
writeFileSync(tmpCompose,
|
|
2013
|
+
writeFileSync(tmpCompose, stagedCompose.raw, { mode: 420 });
|
|
1853
2014
|
renameSync(tmpCompose, options.composeFile);
|
|
1854
2015
|
console.log(
|
|
1855
2016
|
`[stack-update] Refreshed docker-compose.yml from packaged template (old saved to ${path.join(updateBackupDir, "docker-compose.yml")}). Customer overrides should live in docker-compose.override.yml.`
|
|
@@ -1857,44 +2018,19 @@ async function runStackUpdate(options) {
|
|
|
1857
2018
|
}
|
|
1858
2019
|
} else {
|
|
1859
2020
|
console.warn(
|
|
1860
|
-
`[stack-update] Packaged compose template not found at ${
|
|
2021
|
+
`[stack-update] Packaged compose template not found at ${stagedCompose.templatePath}; keeping existing docker-compose.yml. Shipped compose fixes will not apply.`
|
|
1861
2022
|
);
|
|
1862
2023
|
}
|
|
1863
2024
|
} catch (err) {
|
|
1864
2025
|
const reason = err instanceof Error ? err.message : String(err);
|
|
1865
2026
|
console.warn(`[stack-update] Could not refresh docker-compose.yml (${reason}); using existing compose.`);
|
|
1866
2027
|
}
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
if (unresolvable.length > 0) {
|
|
1872
|
-
const lines = unresolvable.map((r) => ` - ${r.key}${r.message ? ` (${r.message})` : ""}`);
|
|
1873
|
-
throw new Error(
|
|
1874
|
-
`Stack update aborted before any changes: the updated compose template requires env vars that are missing from ${options.envFile} and cannot be derived automatically.
|
|
1875
|
-
Set these in ${options.envFile}, then re-run stack-update:
|
|
1876
|
-
${lines.join("\n")}`
|
|
1877
|
-
);
|
|
1878
|
-
}
|
|
1879
|
-
migratedEnvVars = derived;
|
|
1880
|
-
if (Object.keys(derived).length > 0) {
|
|
1881
|
-
console.log(
|
|
1882
|
-
`[stack-update] Migrating ${Object.keys(derived).length} newly-required env var(s) into ${options.envFile} with derived defaults: ${Object.keys(derived).join(", ")}`
|
|
1883
|
-
);
|
|
1884
|
-
}
|
|
1885
|
-
} catch (err) {
|
|
1886
|
-
throw err instanceof Error ? err : new Error(String(err));
|
|
2028
|
+
if (Object.keys(migratedEnvVars).length > 0) {
|
|
2029
|
+
console.log(
|
|
2030
|
+
`[stack-update] Migrating ${Object.keys(migratedEnvVars).length} newly-required env var(s) into ${options.envFile} with derived defaults: ${Object.keys(migratedEnvVars).join(", ")}`
|
|
2031
|
+
);
|
|
1887
2032
|
}
|
|
1888
2033
|
const initialServiceStatus = options.resume && resumeLock?.serviceStatus ? resumeLock.serviceStatus : buildInitialServiceStatus(fullTargetPlan, envRaw, now, new Set(Object.keys(plan.release.services)));
|
|
1889
|
-
writeStackUpdateLock(lockFile, {
|
|
1890
|
-
stackVersion: plan.targetVersion,
|
|
1891
|
-
previousVersion,
|
|
1892
|
-
updatedAt: now().toISOString(),
|
|
1893
|
-
backupEnvFile: resumeLock?.backupEnvFile ?? backupEnvFile,
|
|
1894
|
-
backupComposeFile: resumeLock?.backupComposeFile ?? backupComposeFile,
|
|
1895
|
-
services: { ...fullTargetPlan.release.services, ...resumeLock?.services ?? {}, ...plan.release.services },
|
|
1896
|
-
serviceStatus: initialServiceStatus
|
|
1897
|
-
});
|
|
1898
2034
|
try {
|
|
1899
2035
|
const { spawnSync: sp } = await import("child_process");
|
|
1900
2036
|
const backupSh = path.join(stackDir, "backup.sh");
|
|
@@ -1939,6 +2075,19 @@ ${lines.join("\n")}`
|
|
|
1939
2075
|
if (overrideResolution.warn) console.warn(overrideResolution.notice);
|
|
1940
2076
|
else console.log(overrideResolution.notice);
|
|
1941
2077
|
}
|
|
2078
|
+
const mutatedEnvKeys = Object.keys(updates);
|
|
2079
|
+
writeStackUpdateLock(lockFile, {
|
|
2080
|
+
stackVersion: plan.targetVersion,
|
|
2081
|
+
previousVersion,
|
|
2082
|
+
updatedAt: now().toISOString(),
|
|
2083
|
+
backupEnvFile: resumeLock?.backupEnvFile ?? backupEnvFile,
|
|
2084
|
+
backupComposeFile: resumeLock?.backupComposeFile ?? backupComposeFile,
|
|
2085
|
+
backupComposeOverrideFile: resumeLock?.backupComposeOverrideFile ?? backupComposeOverrideFile,
|
|
2086
|
+
hadComposeOverrideFile: resumeLock?.hadComposeOverrideFile ?? hadComposeOverrideFile,
|
|
2087
|
+
mutatedEnvKeys: [.../* @__PURE__ */ new Set([...resumeLock?.mutatedEnvKeys ?? [], ...mutatedEnvKeys])],
|
|
2088
|
+
services: { ...fullTargetPlan.release.services, ...resumeLock?.services ?? {}, ...plan.release.services },
|
|
2089
|
+
serviceStatus: initialServiceStatus
|
|
2090
|
+
});
|
|
1942
2091
|
const patched = patchEnv(envRaw, updates);
|
|
1943
2092
|
const tmp = `${options.envFile}.tmp-${process.pid}`;
|
|
1944
2093
|
writeSecretFile(tmp, patched);
|
|
@@ -1946,47 +2095,19 @@ ${lines.join("\n")}`
|
|
|
1946
2095
|
for (const serviceName of Object.keys(plan.release.services)) {
|
|
1947
2096
|
updateServiceStatus(lockFile, serviceName, "env_patched", now);
|
|
1948
2097
|
}
|
|
1949
|
-
const composeArgs =
|
|
2098
|
+
const composeArgs = composeArgsForStack(options.composeFile, options.envFile);
|
|
1950
2099
|
let registryForLogout;
|
|
1951
2100
|
try {
|
|
1952
2101
|
let credsLogged = false;
|
|
1953
2102
|
const resolveRegistryCredentials = async () => {
|
|
1954
|
-
|
|
1955
|
-
if (!
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
const registry = sampleImage.startsWith("update.askexe.com") ? "update.askexe.com" : "ghcr.io";
|
|
1963
|
-
resolved = { registry, username, password };
|
|
1964
|
-
if (!credsLogged) console.log(`[stack-update] Using manual registry credentials for ${registry}.`);
|
|
1965
|
-
}
|
|
1966
|
-
}
|
|
1967
|
-
}
|
|
1968
|
-
if (!resolved) {
|
|
1969
|
-
const sampleImage = Object.values(plan.release.services)[0]?.image ?? "";
|
|
1970
|
-
if (sampleImage.startsWith("update.askexe.com")) {
|
|
1971
|
-
const stackEnvPullTokensRaw = process.env.EXE_REGISTRY_PROXY_PULL_TOKENS || (existsSync(options.envFile) ? (() => {
|
|
1972
|
-
const envMap = parseEnv(readFileSync(options.envFile, "utf8"));
|
|
1973
|
-
return envMap.get("EXE_REGISTRY_PROXY_PULL_TOKENS") ?? "";
|
|
1974
|
-
})() : "");
|
|
1975
|
-
const firstPullToken = stackEnvPullTokensRaw.split(/[\n,]/).map((s) => s.trim()).find(Boolean);
|
|
1976
|
-
if (firstPullToken) {
|
|
1977
|
-
resolved = { registry: "update.askexe.com", username: "token", password: firstPullToken };
|
|
1978
|
-
if (!credsLogged) console.log("[stack-update] Using EXE_REGISTRY_PROXY_PULL_TOKENS for update.askexe.com registry auth.");
|
|
1979
|
-
}
|
|
1980
|
-
}
|
|
1981
|
-
}
|
|
1982
|
-
if (!resolved) {
|
|
1983
|
-
const sampleImage = Object.values(plan.release.services)[0]?.image ?? "";
|
|
1984
|
-
if (sampleImage.startsWith("update.askexe.com")) {
|
|
1985
|
-
const licenseKey = options.manifestAuthToken || options.licenseKey || process.env.EXE_LICENSE_KEY;
|
|
1986
|
-
if (licenseKey) {
|
|
1987
|
-
resolved = { registry: "update.askexe.com", username: "license", password: licenseKey };
|
|
1988
|
-
if (!credsLogged) console.log("[stack-update] Using license key for update.askexe.com registry auth.");
|
|
1989
|
-
}
|
|
2103
|
+
const resolved = await resolveStackImageCredentials(options, plan.release);
|
|
2104
|
+
if (resolved && !credsLogged) {
|
|
2105
|
+
if (options.registryCredentials || process.env.EXE_REGISTRY_CREDENTIALS) {
|
|
2106
|
+
console.log(`[stack-update] Using manual registry credentials for ${resolved.registry}.`);
|
|
2107
|
+
} else if (resolved.registry === "update.askexe.com" && resolved.username === "token") {
|
|
2108
|
+
console.log("[stack-update] Using EXE_REGISTRY_PROXY_PULL_TOKENS for update.askexe.com registry auth.");
|
|
2109
|
+
} else if (resolved.registry === "update.askexe.com" && resolved.username === "license") {
|
|
2110
|
+
console.log("[stack-update] Using license key for update.askexe.com registry auth.");
|
|
1990
2111
|
}
|
|
1991
2112
|
}
|
|
1992
2113
|
if (resolved) credsLogged = true;
|
|
@@ -1994,7 +2115,13 @@ ${lines.join("\n")}`
|
|
|
1994
2115
|
};
|
|
1995
2116
|
let creds = await resolveRegistryCredentials();
|
|
1996
2117
|
if (creds) {
|
|
1997
|
-
|
|
2118
|
+
try {
|
|
2119
|
+
(options.dockerLogin ?? defaultDockerLogin)(creds);
|
|
2120
|
+
} catch (err) {
|
|
2121
|
+
throw new Error(
|
|
2122
|
+
`Docker registry login failed for ${creds.registry}; aborting before image pull for service(s) ${allServiceList(plan.release)}: ${errorMessage(err)}`
|
|
2123
|
+
);
|
|
2124
|
+
}
|
|
1998
2125
|
registryForLogout = creds.registry;
|
|
1999
2126
|
}
|
|
2000
2127
|
const runImageAvailabilityCheck = !options.skipImageAvailabilityCheck && !options.exec;
|
|
@@ -2029,10 +2156,19 @@ Push the missing image(s) to the registry, or re-run with --break-glass <reason>
|
|
|
2029
2156
|
(options.dockerLogin ?? defaultDockerLogin)(fresh);
|
|
2030
2157
|
creds = fresh;
|
|
2031
2158
|
registryForLogout = fresh.registry;
|
|
2032
|
-
} catch {
|
|
2159
|
+
} catch (err) {
|
|
2160
|
+
throw new Error(
|
|
2161
|
+
`Docker registry re-login failed before pulling ${image} for service(s) ${serviceListForPullImage(plan.release, image)}; aborting before container swap: ${errorMessage(err)}`
|
|
2162
|
+
);
|
|
2033
2163
|
}
|
|
2034
2164
|
}
|
|
2035
|
-
|
|
2165
|
+
try {
|
|
2166
|
+
exec("docker", ["pull", image]);
|
|
2167
|
+
} catch (err) {
|
|
2168
|
+
throw new Error(
|
|
2169
|
+
`Image pull failed before container swap for service(s) ${serviceListForPullImage(plan.release, image)} using ${image}: ${errorMessage(err)}`
|
|
2170
|
+
);
|
|
2171
|
+
}
|
|
2036
2172
|
for (const [serviceName, service] of Object.entries(plan.release.services)) {
|
|
2037
2173
|
if (imagePullRef(service.image) === image) updateServiceStatus(lockFile, serviceName, "pulled", now);
|
|
2038
2174
|
}
|
|
@@ -2045,14 +2181,25 @@ Push the missing image(s) to the registry, or re-run with --break-glass <reason>
|
|
|
2045
2181
|
(options.dockerLogin ?? defaultDockerLogin)(fresh);
|
|
2046
2182
|
creds = fresh;
|
|
2047
2183
|
registryForLogout = fresh.registry;
|
|
2048
|
-
} catch {
|
|
2184
|
+
} catch (err) {
|
|
2185
|
+
throw new Error(
|
|
2186
|
+
`Docker registry re-login failed before docker compose pull for service(s) ${allServiceList(plan.release)}; aborting before container swap: ${errorMessage(err)}`
|
|
2187
|
+
);
|
|
2049
2188
|
}
|
|
2050
2189
|
}
|
|
2051
|
-
const composePullTargets =
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2190
|
+
const composePullTargets = expandComposeServicesWithSidecars(
|
|
2191
|
+
Object.entries(plan.release.services).map(([name, svc]) => svc.composeService ?? name)
|
|
2192
|
+
);
|
|
2193
|
+
try {
|
|
2194
|
+
if (composePullTargets.length > 0) {
|
|
2195
|
+
exec("docker", [...composeArgs, "pull", ...composePullTargets]);
|
|
2196
|
+
} else {
|
|
2197
|
+
exec("docker", [...composeArgs, "pull"]);
|
|
2198
|
+
}
|
|
2199
|
+
} catch (err) {
|
|
2200
|
+
throw new Error(
|
|
2201
|
+
`Docker compose pull failed before container swap for service(s) ${allServiceList(plan.release)}: ${errorMessage(err)}`
|
|
2202
|
+
);
|
|
2056
2203
|
}
|
|
2057
2204
|
endComposePull();
|
|
2058
2205
|
progress.endPhase();
|
|
@@ -2154,16 +2301,8 @@ Push the missing image(s) to the registry, or re-run with --break-glass <reason>
|
|
|
2154
2301
|
"cloudflared"
|
|
2155
2302
|
// tunnel — restarted last so services are healthy before it connects
|
|
2156
2303
|
];
|
|
2157
|
-
const COMPOSE_SIDECARS = {
|
|
2158
|
-
"exe-erp": ["exe-erp-nginx", "exe-erp-websocket", "exe-erp-queue", "exe-erp-scheduler"]
|
|
2159
|
-
};
|
|
2160
2304
|
const primaryComposeServices = Object.entries(plan.release.services).map(([serviceName, service]) => service.composeService ?? serviceName);
|
|
2161
|
-
const scopedComposeServices =
|
|
2162
|
-
for (const primary of primaryComposeServices) {
|
|
2163
|
-
for (const sidecar of COMPOSE_SIDECARS[primary] ?? []) {
|
|
2164
|
-
if (!scopedComposeServices.includes(sidecar)) scopedComposeServices.push(sidecar);
|
|
2165
|
-
}
|
|
2166
|
-
}
|
|
2305
|
+
const scopedComposeServices = expandComposeServicesWithSidecars(primaryComposeServices);
|
|
2167
2306
|
const restartOrder = [
|
|
2168
2307
|
...RESTART_ORDER.filter((service) => scopedComposeServices.includes(service)),
|
|
2169
2308
|
...scopedComposeServices.filter((service) => !RESTART_ORDER.includes(service))
|
|
@@ -2329,7 +2468,18 @@ Fix these before the stack is safe to operate.`);
|
|
|
2329
2468
|
progress.logOverallSummary();
|
|
2330
2469
|
printPhaseSummary();
|
|
2331
2470
|
const finalLock = readStackUpdateLock(lockFile) ?? {};
|
|
2332
|
-
writeStackUpdateLock(lockFile, {
|
|
2471
|
+
writeStackUpdateLock(lockFile, {
|
|
2472
|
+
...finalLock,
|
|
2473
|
+
stackVersion: plan.targetVersion,
|
|
2474
|
+
previousVersion,
|
|
2475
|
+
updatedAt: now().toISOString(),
|
|
2476
|
+
backupEnvFile: finalLock.backupEnvFile ?? backupEnvFile,
|
|
2477
|
+
backupComposeFile: finalLock.backupComposeFile ?? backupComposeFile,
|
|
2478
|
+
backupComposeOverrideFile: finalLock.backupComposeOverrideFile ?? backupComposeOverrideFile,
|
|
2479
|
+
hadComposeOverrideFile: finalLock.hadComposeOverrideFile ?? hadComposeOverrideFile,
|
|
2480
|
+
mutatedEnvKeys: finalLock.mutatedEnvKeys ?? mutatedEnvKeys,
|
|
2481
|
+
services: { ...fullTargetPlan.release.services, ...finalLock.services ?? {}, ...plan.release.services }
|
|
2482
|
+
});
|
|
2333
2483
|
await postDeployAudit(options, "success", plan.targetVersion, previousVersion, void 0, { changes: plan.changes.length });
|
|
2334
2484
|
return { status: "updated", targetVersion: plan.targetVersion, changes: plan.changes, backupEnvFile, lockFile, serviceStatus: readStackUpdateLock(lockFile)?.serviceStatus };
|
|
2335
2485
|
} catch (err) {
|
|
@@ -2866,6 +3016,8 @@ export {
|
|
|
2866
3016
|
buildReleaseMigrationArgs,
|
|
2867
3017
|
runReleaseMigrations,
|
|
2868
3018
|
isExecFormMigration,
|
|
3019
|
+
expandComposeServicesWithSidecars,
|
|
3020
|
+
composeArgsForStack,
|
|
2869
3021
|
parseStackManifest,
|
|
2870
3022
|
loadStackManifest,
|
|
2871
3023
|
parseEnv,
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isPostgresBackendEnabled
|
|
3
|
+
} from "./chunk-YMUZWC33.js";
|
|
4
|
+
|
|
1
5
|
// src/lib/db-write-worker-client.ts
|
|
2
6
|
import { fork } from "child_process";
|
|
3
7
|
import { existsSync } from "fs";
|
|
@@ -10,6 +14,18 @@ var _spawnAttempts = 0;
|
|
|
10
14
|
var MAX_SPAWN_ATTEMPTS = 5;
|
|
11
15
|
var WRITE_TIMEOUT_MS = 6e4;
|
|
12
16
|
var _pending = /* @__PURE__ */ new Map();
|
|
17
|
+
function buildDbWriteWorkerEnv(dbPath, encryptionKey, source = process.env) {
|
|
18
|
+
const env = {
|
|
19
|
+
...source,
|
|
20
|
+
EXE_IS_DAEMON: "",
|
|
21
|
+
EXE_DB_DIRECT: "1",
|
|
22
|
+
EXE_BOOT_FAST: "1",
|
|
23
|
+
EXE_DB_NO_CHECKPOINT_TIMER: "1"
|
|
24
|
+
};
|
|
25
|
+
if (dbPath) env.EXE_DB_WRITE_WORKER_PATH = dbPath;
|
|
26
|
+
if (encryptionKey) env.EXE_DB_WRITE_WORKER_KEY = encryptionKey;
|
|
27
|
+
return env;
|
|
28
|
+
}
|
|
13
29
|
function rejectAllPending(reason) {
|
|
14
30
|
for (const [id, cb] of _pending) {
|
|
15
31
|
clearTimeout(cb.timer);
|
|
@@ -31,15 +47,12 @@ function spawnDbWriteWorker(dbPath, encryptionKey) {
|
|
|
31
47
|
`);
|
|
32
48
|
return;
|
|
33
49
|
}
|
|
34
|
-
const env =
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
EXE_DB_NO_CHECKPOINT_TIMER: "1"
|
|
41
|
-
};
|
|
42
|
-
if (encryptionKey) env.EXE_DB_WRITE_WORKER_KEY = encryptionKey;
|
|
50
|
+
const env = buildDbWriteWorkerEnv(dbPath, encryptionKey);
|
|
51
|
+
if (!isPostgresBackendEnabled(env) && !env.EXE_DB_WRITE_WORKER_PATH) {
|
|
52
|
+
process.stderr.write("[db-write-worker-client] no SQLite db path for write worker - memory writes will run on the event loop.\n");
|
|
53
|
+
_spawnAttempts = Math.max(0, _spawnAttempts - 1);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
43
56
|
try {
|
|
44
57
|
_worker = fork(workerPath, [], { stdio: ["ignore", "ignore", "inherit", "ipc"], env });
|
|
45
58
|
} catch (err) {
|
|
@@ -118,6 +131,7 @@ function disposeDbWriteWorker() {
|
|
|
118
131
|
}
|
|
119
132
|
|
|
120
133
|
export {
|
|
134
|
+
buildDbWriteWorkerEnv,
|
|
121
135
|
isWriteWorkerEnabled,
|
|
122
136
|
spawnDbWriteWorker,
|
|
123
137
|
isDbWriteWorkerReady,
|