@runeya/runeya 2.0.72 → 2.0.74
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/agent/index.js +1057 -977
- package/agent/index.js.map +1 -1
- package/agent-manager-L35E7FWI.js +7 -0
- package/{chunk-HPYBAUAH.js → chunk-JRXAQNAC.js} +119 -5
- package/chunk-JRXAQNAC.js.map +1 -0
- package/index.js +1 -1
- package/package.json +1 -1
- package/{src-53OQNM27.js → src-YG67XURV.js} +134 -64
- package/src-YG67XURV.js.map +1 -0
- package/web/assets/AgentScalarChatInterface.vue-CHi2dFEc.js +13 -0
- package/web/assets/AgentTerminalPage-BvdfOTep.js +1 -0
- package/web/assets/AiChatPage-DJ03I6Lb.js +1 -0
- package/web/assets/{AppLayout-Dj8VrBzz.css → AppLayout-Cvn5Nj7U.css} +1 -1
- package/web/assets/AppLayout-DLhk2bQj.js +1 -0
- package/web/assets/AuditPage-EqCcRjr9.js +1 -0
- package/web/assets/CloudAccountPage-BUjzLwjW.js +1 -0
- package/web/assets/CloudAccountPage-CNxUzrAO.js +1 -0
- package/web/assets/CloudMessagingPage-BrZRNxlZ.js +2 -0
- package/web/assets/DashboardPage-B6MhaCCj.js +1 -0
- package/web/assets/DirectoryPickerDialog-3m0wiBWG.js +1 -0
- package/web/assets/{EditorIcon-BbilRWLq.js → EditorIcon-DVd7Gn4R.js} +2 -2
- package/web/assets/{EnvironmentForm-BIHXK18r.js → EnvironmentForm-CbYQ53vB.js} +2 -2
- package/web/assets/EnvironmentFormPage-mnSwPbUr.js +1 -0
- package/web/assets/EnvironmentListPage-kFhmundZ.js +1 -0
- package/web/assets/KanbanBoardPage-CCl8dmwn.css +1 -0
- package/web/assets/KanbanBoardPage-cgbSqPnz.js +4 -0
- package/web/assets/KanbanListPage-D4xaJzdt.js +1 -0
- package/web/assets/LaunchProjectPage-Boxl4Dja.js +1 -0
- package/web/assets/LaunchServicesPage-D-FjI4AR.js +1 -0
- package/web/assets/LogViewer-Dy7SyJwf.js +3 -0
- package/web/assets/OrgKeyPrompt-Ctjsqp3s.js +1 -0
- package/web/assets/{ProcessControls-BzMrd-2c.js → ProcessControls-DMG-C-9V.js} +1 -1
- package/web/assets/ProcessDetailPage-CroZuFui.js +1 -0
- package/web/assets/{ProcessMetrics-hZWAa3gi.js → ProcessMetrics-QAK1AZsb.js} +2 -2
- package/web/assets/ProjectDetailPage-CvHH1DfL.js +1 -0
- package/web/assets/ProjectListPage-DAXodWJP.js +1 -0
- package/web/assets/RandomJobTestPage-DZ_xOlfL.js +2 -0
- package/web/assets/ScenarioEditorPage-CODJ_St4.js +14 -0
- package/web/assets/SendToChatDialog-DhVM2ESX.js +1 -0
- package/web/assets/ServiceControlsBar-DdvYd2xI.js +1 -0
- package/web/assets/ServiceDetailPage-BJRGB4fq.js +2 -0
- package/web/assets/{ServiceDetailPage-DDSyACSv.css → ServiceDetailPage-Di9SzpJw.css} +1 -1
- package/web/assets/ServiceFormPage-MDqY-U7o.js +1 -0
- package/web/assets/{SettingsPage-ClUsbLPy.css → SettingsPage-CKRCL18-.css} +1 -1
- package/web/assets/SettingsPage-CeUT68wE.js +2063 -0
- package/web/assets/UnlockPage-Blh0YpJC.js +1 -0
- package/web/assets/VariablesTable-BTAp4k6f.js +1 -0
- package/web/assets/VariablesTable-DNNf7eCt.css +1 -0
- package/web/assets/VaultMigrationPage-B7TK6Yjh.js +1 -0
- package/web/assets/VersionBadge-Buin8AuA.js +1 -0
- package/web/assets/WikiPage-CJ-rNfud.js +1 -0
- package/web/assets/WikiView-BgCUaLa6.js +1 -0
- package/web/assets/add-scalar-classes-CKwuR5ZQ.js +387 -0
- package/web/assets/auth-errors-BSQODFsD.js +1 -0
- package/web/assets/{autocomplete-wqj_ORBH.js → autocomplete-0aIbUwlr.js} +3 -3
- package/web/assets/{basic-shape-diamond.svg-CWwnQ30s.js → basic-shape-diamond.svg-BTTsBN8v.js} +1 -1
- package/web/assets/{basic-shape-hexagon.svg-C9JMDUIK.js → basic-shape-hexagon.svg-CbALgV8W.js} +1 -1
- package/web/assets/{basic-shape-primary-circle-ellipse-round.svg-Do0Ewbp-.js → basic-shape-primary-circle-ellipse-round.svg-CM2Rc-Vc.js} +1 -1
- package/web/assets/{basic-shape-primary-square-rectangle.svg-CRq767cD.js → basic-shape-primary-square-rectangle.svg-CQ1KoMjn.js} +1 -1
- package/web/assets/{basic-shape-shield.svg-BuxJBs70.js → basic-shape-shield.svg-1lqFtlO8.js} +1 -1
- package/web/assets/{browser-BhZAIVa8.js → browser-BhYmZa45.js} +1 -1
- package/web/assets/{browser-BEEW2obM.js → browser-W4YisEmh.js} +1 -1
- package/web/assets/{card-C1iS2wAN.js → card-CLPFpENW.js} +2 -2
- package/web/assets/{checkbox-CCU9xze9.js → checkbox-xXts-zyO.js} +2 -2
- package/web/assets/{chip-DsJBorBp.js → chip-BDaJibPj.js} +2 -2
- package/web/assets/{client-BFK39Zab.js → client-B0jAuhqn.js} +2 -2
- package/web/assets/cloud-chat.store-B4mu3u7F.js +1 -0
- package/web/assets/cloud-session-CPlXmpSe.js +1 -0
- package/web/assets/column-grBnjbWs.js +907 -0
- package/web/assets/{computer-device-desktop-monitor.svg-XWEWhL0y.js → computer-device-desktop-monitor.svg-BixhDvwl.js} +1 -1
- package/web/assets/{computer-device-desktop.svg-COkZClBv.js → computer-device-desktop.svg-ZmA0L2qL.js} +1 -1
- package/web/assets/{computer-device-laptop.svg-C4EfJUqO.js → computer-device-laptop.svg-BbdJBfg2.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-android-samsung-back.svg-Bb2_2tyI.js → computer-device-mobile-phone-android-samsung-back.svg-BzFWE61G.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-android-samsung.svg-CEUhXP7K.js → computer-device-mobile-phone-android-samsung.svg-BDtiMsFX.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-iphone-x-back.svg-B3rxizbE.js → computer-device-mobile-phone-iphone-x-back.svg-DM6YheEO.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-iphone-x.svg-BSKpZFCN.js → computer-device-mobile-phone-iphone-x.svg-Bp3jERFh.js} +1 -1
- package/web/assets/{computer-device-mobile-tablet-touch.svg-CZvb3YX2.js → computer-device-mobile-tablet-touch.svg-CFlGkb9z.js} +1 -1
- package/web/assets/{computer-device-mobile-tablet.svg-BM4_YZYi.js → computer-device-mobile-tablet.svg-BZBxeC6-.js} +1 -1
- package/web/assets/{computer-device-network-ethernet-cat6.svg-CK0v-Rjf.js → computer-device-network-ethernet-cat6.svg-Cx3VdpRS.js} +1 -1
- package/web/assets/{computer-device-network-lan-www.svg-DvhO71Lq.js → computer-device-network-lan-www.svg-kpYR7ArK.js} +1 -1
- package/web/assets/{computer-device-network-wifi-connection.svg--olUYsgv.js → computer-device-network-wifi-connection.svg-CWV3wPXN.js} +1 -1
- package/web/assets/{computer-device-network-wifi-router.svg-D5HKSWTi.js → computer-device-network-wifi-router.svg-CzE7DHvd.js} +1 -1
- package/web/assets/{cssMode-CTjKNOiX.js → cssMode-COP0Vc--.js} +1 -1
- package/web/assets/{divider-VFAPax5_.js → divider-BgzI-Lls.js} +2 -2
- package/web/assets/{docx-preview-gNYLz3FX.js → docx-preview-D9Nq99G-.js} +1 -1
- package/web/assets/{ecology-science-erlenmeyer-flask.svg-THkDG-tj.js → ecology-science-erlenmeyer-flask.svg-Dvg9Ooy-.js} +1 -1
- package/web/assets/{fieldset-DZGy449H.js → fieldset-DkMAzSHT.js} +2 -2
- package/web/assets/{freemarker2-CNSvFpVF.js → freemarker2-BF912KBd.js} +1 -1
- package/web/assets/{handlebars-BeRu48NI.js → handlebars-CDz6xiAj.js} +1 -1
- package/web/assets/{html-DrTiGPjE.js → html-DdlTee49.js} +1 -1
- package/web/assets/{htmlMode-DpbDpbjK.js → htmlMode-BKPtJJGG.js} +1 -1
- package/web/assets/{image-flash-lightning.svg-DrkyfdIV.js → image-flash-lightning.svg-_KHhUck_.js} +1 -1
- package/web/assets/{image-picture-flower.svg-BqFj1xcR.js → image-picture-flower.svg-xYdaJTim.js} +1 -1
- package/web/assets/{index-y5bguEQB.js → index-K7kdEsBo.js} +210 -210
- package/web/assets/{interface-alert-exclamation-diamond.svg-B40BfW6d.js → interface-alert-exclamation-diamond.svg-DfMcMOwb.js} +1 -1
- package/web/assets/{interface-alert-exclamation-triangle-warning.svg-DeIlksL4.js → interface-alert-exclamation-triangle-warning.svg-HFqVNBE9.js} +1 -1
- package/web/assets/{interface-alert-information-circle.svg-SwVdV-Z6.js → interface-alert-information-circle.svg-CUOqF7qS.js} +1 -1
- package/web/assets/{interface-award-crown.svg-DZHf0EHC.js → interface-award-crown.svg-6s7F0fMR.js} +1 -1
- package/web/assets/{interface-bookmark.svg-DBEqa-8W.js → interface-bookmark-tag.svg-BCyK266t.js} +1 -1
- package/web/assets/{interface-bookmark-tag.svg-CiaV2Cjo.js → interface-bookmark.svg-CFJIMfN-.js} +1 -1
- package/web/assets/{interface-calendar-date-one.svg-C_afKyyz.js → interface-calendar-date-one.svg-DZDWCn7W.js} +1 -1
- package/web/assets/{interface-content-book-open-pages.svg-D5d9ilSu.js → interface-content-book-open-pages.svg-DV_U01L-.js} +1 -1
- package/web/assets/{interface-content-book-page.svg-B6hlaLP5.js → interface-content-book-page.svg-DITAHjsW.js} +1 -1
- package/web/assets/{interface-content-file.svg-COWMwejF.js → interface-content-file.svg-CeQU8wpF.js} +1 -1
- package/web/assets/interface-content-folder.svg-BCjROcNE.js +1 -0
- package/web/assets/{interface-content-folder.svg-K7DTqQH-.js → interface-content-folder.svg-CUNjtwrk.js} +1 -1
- package/web/assets/{interface-copy-clipboard.svg-BFQ6eajI.js → interface-copy-clipboard.svg-Cpw5aWsC.js} +1 -1
- package/web/assets/{interface-edit-attachment.svg-B-LsB4cM.js → interface-edit-attachment.svg-CfC-IGjI.js} +1 -1
- package/web/assets/{interface-edit-binocular.svg-CnVjKyrn.js → interface-edit-binocular.svg-CjYGcQSJ.js} +1 -1
- package/web/assets/{interface-edit-magic-wand.svg-CUY6vVJT.js → interface-edit-magic-wand.svg-Wdc1CXnn.js} +1 -1
- package/web/assets/{interface-edit-tool-paint-roller.svg-B1tSdIxN.js → interface-edit-tool-paint-roller.svg-BfODeBzt.js} +1 -1
- package/web/assets/{interface-edit-tool-pencil.svg-BHFULT75.js → interface-edit-tool-pencil.svg-D4KkDVej.js} +1 -1
- package/web/assets/{interface-favorite-award.svg-CcOLoF8I.js → interface-favorite-award.svg-rFwxYUIH.js} +1 -1
- package/web/assets/{interface-favorite-flag.svg-CAW6LmLW.js → interface-favorite-flag.svg-B3aO74D4.js} +1 -1
- package/web/assets/{interface-favorite-heart.svg-BEz4zlNs.js → interface-favorite-heart.svg-DnLWhJhp.js} +1 -1
- package/web/assets/{interface-favorite-star.svg-DKFuvYge.js → interface-favorite-star.svg-B1bTAfnw.js} +1 -1
- package/web/assets/{interface-favorite-stars-sparkles.svg-BfzccoPz.js → interface-favorite-stars-sparkles.svg-Ze10JKoz.js} +1 -1
- package/web/assets/{interface-hierarchy-flowchart.svg-BT8QX161.js → interface-hierarchy-flowchart.svg-DvhnI7vM.js} +1 -1
- package/web/assets/{interface-home-house.svg-B264pTPi.js → interface-home-house.svg-TpFO9U15.js} +1 -1
- package/web/assets/{interface-hyperlink.svg-DhUgNKkr.js → interface-hyperlink.svg-B6PjuMyj.js} +1 -1
- package/web/assets/{interface-lighting-brightness.svg-CPKb40uB.js → interface-lighting-brightness.svg-CFNb3F8V.js} +1 -1
- package/web/assets/{interface-lock-closed.svg-CvXhgCtt.js → interface-lock-closed.svg-CRzdSCj5.js} +1 -1
- package/web/assets/{interface-lock-open-unlock.svg-B0PMKRhP.js → interface-lock-open-unlock.svg-o1dtCc6U.js} +1 -1
- package/web/assets/{interface-login-key.svg-DJUm3vhg.js → interface-login-key.svg-BCRY7fi7.js} +1 -1
- package/web/assets/{interface-search.svg-ByW98ez_.js → interface-search.svg-CSd_UAHp.js} +1 -1
- package/web/assets/{interface-setting-cog.svg-DYOmJ9It.js → interface-setting-cog.svg-BiAFMqpv.js} +1 -1
- package/web/assets/{interface-share-megaphone-bullhorn.svg-YOCUHa3i.js → interface-share-megaphone-bullhorn.svg-Bg6Nrrba.js} +1 -1
- package/web/assets/{interface-share-rocket.svg-C5kj5dSu.js → interface-share-rocket.svg-BueJTjIT.js} +1 -1
- package/web/assets/{interface-share-satellite.svg-C0svPxG6.js → interface-share-satellite.svg-BPXIZysE.js} +1 -1
- package/web/assets/{interface-share-space-ship.svg-8Nw02n1Q.js → interface-share-space-ship.svg-Tpmu2ZQs.js} +1 -1
- package/web/assets/{interface-share.svg-eDW294tn.js → interface-share.svg-DZ7feWlJ.js} +1 -1
- package/web/assets/{interface-signal-square.svg-CxB5mcJQ.js → interface-signal-square.svg-CHVwe1pi.js} +1 -1
- package/web/assets/{interface-time-clock-circle.svg-CEnlQi79.js → interface-time-clock-circle.svg-DtUcGfFi.js} +1 -1
- package/web/assets/{interface-time-hour-glass.svg-qL3_s19Q.js → interface-time-hour-glass.svg-BNWEgOHt.js} +1 -1
- package/web/assets/{interface-users-multiple.svg-Cz2iA33z.js → interface-users-multiple.svg-C1Pry5nR.js} +1 -1
- package/web/assets/{interface-weather-moon.svg-BoT9GUK_.js → interface-weather-moon.svg-DQx-1A-h.js} +1 -1
- package/web/assets/{javascript-DWdA0-HW.js → javascript-CsXL5DT8.js} +1 -1
- package/web/assets/{jsonMode-DxGrVlm0.js → jsonMode-DvB3zo30.js} +2 -2
- package/web/assets/{liquid-COqLk0mR.js → liquid-DI2z9alR.js} +1 -1
- package/web/assets/{lspLanguageFeatures--0hj1ZV4.js → lspLanguageFeatures-CMc4rLCM.js} +3 -3
- package/web/assets/{mail-chat-bubble-square.svg-eiKzTBOv.js → mail-chat-bubble-square.svg-DN92EruI.js} +1 -1
- package/web/assets/{mail-send-email-paper-airplane.svg-CCI77Gk8.js → mail-send-email-paper-airplane.svg-DOaMqGHu.js} +1 -1
- package/web/assets/{mail-send-envelope.svg-ChM5k_N7.js → mail-send-envelope.svg-Co6AFlQX.js} +1 -1
- package/web/assets/{mdx-CwXNREAO.js → mdx-CGWf38OI.js} +1 -1
- package/web/assets/{message-CSxReshg.js → message-VrL-0XTF.js} +2 -2
- package/web/assets/{minus-Cg0lH8Mn.js → minus-BjZ21L72.js} +2 -2
- package/web/assets/modal-8HVVBuyS.js +1 -0
- package/web/assets/modal-C6s7wXuj.js +5 -0
- package/web/assets/{money-cashier-receipt.svg-WMIW7vxg.js → money-cashier-receipt.svg-8Qup-ZSr.js} +1 -1
- package/web/assets/{money-currency-dollar-pay.svg-qTcGSVX2.js → money-currency-dollar-pay.svg-CIlSYSGr.js} +1 -1
- package/web/assets/{money-graph-arrow-increase.svg-B-TQKOW-.js → money-graph-arrow-increase.svg-CYJyq294.js} +1 -1
- package/web/assets/{money-graph-bar-chart-increase.svg-CWCIjQcI.js → money-graph-bar-chart-increase.svg-BV2pC3vV.js} +1 -1
- package/web/assets/multiselect-CTA4uR0f.js +251 -0
- package/web/assets/{nature-ecology-leaf.svg-CL26IBv2.js → nature-ecology-leaf.svg-Dqy1XkxJ.js} +1 -1
- package/web/assets/{password-ZOY0bqV1.js → password-IByxJqSm.js} +4 -4
- package/web/assets/{phone-telephone.svg-BhzxDLVX.js → phone-telephone.svg-QvU-I7Ej.js} +1 -1
- package/web/assets/{plus-DsBv8bgd.js → plus-TqzBK0F-.js} +6 -6
- package/web/assets/process.store-BvO7PchE.js +1 -0
- package/web/assets/{programming-bug.svg-CBNm3E3F.js → programming-bug.svg-DEh0hIKm.js} +1 -1
- package/web/assets/{programming-cloud.svg-BrVRbl9B.js → programming-cloud.svg-B8v1xLPM.js} +1 -1
- package/web/assets/{programming-computer-database-server.svg-LQp6n-du.js → programming-computer-database-server.svg-B38-gJMV.js} +1 -1
- package/web/assets/{programming-computer-database.svg-CSbhcIMU.js → programming-computer-database.svg-CSc_uTaq.js} +1 -1
- package/web/assets/{programming-module-four-layout.svg-DYEAcL2j.js → programming-module-four-layout.svg-Ct8e9N9z.js} +1 -1
- package/web/assets/{programming-module-three.svg-CCQXCU-e.js → programming-module-three.svg-Cramtamu.js} +1 -1
- package/web/assets/{programming-module.svg-Chrmf7k4.js → programming-module.svg-_oZsSiMg.js} +1 -1
- package/web/assets/{programming-script-code.svg-DPhhp3IW.js → programming-script-code.svg-B57Dfv3U.js} +1 -1
- package/web/assets/{python-B7ePhfsS.js → python-CIgmiyeD.js} +1 -1
- package/web/assets/{razor-ChpzroOv.js → razor-CwnddCBj.js} +1 -1
- package/web/assets/router-Bh1D7DgU.js +1 -0
- package/web/assets/settings-scope-Doez2KD1.js +1 -0
- package/web/assets/settings.store-CPMOmi7H.js +1 -0
- package/web/assets/{shopping-cart.svg-bmefzlOu.js → shopping-cart.svg-9Veqyy-9.js} +1 -1
- package/web/assets/{shopping-gift-present.svg-aUOleva0.js → shopping-gift-present.svg-Dlo3w3e8.js} +1 -1
- package/web/assets/{shopping-shipping-box-parcel-package.svg-BLsRP4dg.js → shopping-shipping-box-parcel-package.svg-BM0DDqiS.js} +1 -1
- package/web/assets/{src-BPSr9dU2.js → src-9tSFXHt7.js} +34 -34
- package/web/assets/src-C-LFb604.js +1 -0
- package/web/assets/{tabpanel-DZQ_g__B.js → tabpanel-BlB9Tamb.js} +3 -3
- package/web/assets/{tag-new-circle.svg-kTMMMv-0.js → tag-new-circle.svg-A1eYtb-i.js} +1 -1
- package/web/assets/{toggleswitch-BWXDXl37.js → toggleswitch-BNzkwtak.js} +2 -2
- package/web/assets/{travel-map-earth-globe.svg-BdQmz8_b.js → travel-map-earth-globe.svg-DrGjwD_E.js} +1 -1
- package/web/assets/trpc-sPb5TcJm.js +1 -0
- package/web/assets/{tsMode-arHIUQbZ.js → tsMode-D4XC6YIE.js} +6 -6
- package/web/assets/{typescript-Ds9kgbPd.js → typescript-Dk_am5Bh.js} +1 -1
- package/web/assets/useAiChatDrawer-CR-1uKnl.js +1 -0
- package/web/assets/useCloudOrg-CYZgY69j.css +1 -0
- package/web/assets/useCloudOrg-Dg-9Fo9B.js +97 -0
- package/web/assets/{useProjectCatalog-BbSaTBSS.js → useProjectCatalog-uQxqbSkg.js} +1 -1
- package/web/assets/{xml-CO56TgpZ.js → xml-CzMMYFkm.js} +1 -1
- package/web/assets/{yaml-DueFV2-x.js → yaml-U-6eR_c5.js} +1 -1
- package/web/index.html +1 -1
- package/agent-manager-YDLSYZE3.js +0 -7
- package/chunk-HPYBAUAH.js.map +0 -1
- package/src-53OQNM27.js.map +0 -1
- package/web/assets/AgentScalarChatInterface.vue-DdIfThmp.js +0 -13
- package/web/assets/AgentTerminalPage-v9fFc2Kd.js +0 -1
- package/web/assets/AiChatPage-BvrKlLxc.js +0 -1
- package/web/assets/AppLayout-CLzy-QOZ.js +0 -1
- package/web/assets/AuditPage-DgJIcr0c.js +0 -1
- package/web/assets/CloudAccountPage-CoJV3YCA.js +0 -1
- package/web/assets/CloudAccountPage-DGtKCmXL.js +0 -1
- package/web/assets/CloudMessagingPage-Bql34zJU.js +0 -2
- package/web/assets/DashboardPage-BSvJxrcT.js +0 -1
- package/web/assets/DirectoryPickerDialog-BfLLfUQy.js +0 -1
- package/web/assets/EnvironmentFormPage-oLAwLJ1b.js +0 -1
- package/web/assets/EnvironmentListPage-tJfB0q_E.js +0 -1
- package/web/assets/KanbanBoardPage-DpyYe6jx.js +0 -4
- package/web/assets/KanbanBoardPage-JjjS4BfO.css +0 -1
- package/web/assets/KanbanListPage-DjXWjWgU.js +0 -1
- package/web/assets/LaunchProjectPage-Bqgsa2z1.js +0 -1
- package/web/assets/LaunchServicesPage-BCNDSuuN.js +0 -1
- package/web/assets/LogViewer-gTNzyao0.js +0 -3
- package/web/assets/OrgKeyPrompt-BdNV_cve.js +0 -1
- package/web/assets/ProcessDetailPage-Rg5zyPYJ.js +0 -1
- package/web/assets/ProjectDetailPage-NbxG6AIr.js +0 -1
- package/web/assets/ProjectListPage-COMYMVbr.js +0 -1
- package/web/assets/RandomJobTestPage-DTK2RLln.js +0 -2
- package/web/assets/ScenarioEditorPage-DIx_Nzbh.js +0 -14
- package/web/assets/SendToChatDialog-BAalryU3.js +0 -1
- package/web/assets/ServiceControlsBar-CgR8yFZb.js +0 -1
- package/web/assets/ServiceDetailPage-Cvqftndf.js +0 -2
- package/web/assets/ServiceFormPage-CGgCwNM3.js +0 -1
- package/web/assets/SettingsPage-Dx5xoAS7.js +0 -2063
- package/web/assets/UnlockPage-Dlp8kXD-.js +0 -1
- package/web/assets/VariablesTable-B4h9eNC_.css +0 -1
- package/web/assets/VariablesTable-Dr1C6hg4.js +0 -1
- package/web/assets/VaultMigrationPage-1zZCTKgS.js +0 -1
- package/web/assets/VersionBadge-BiLjqi8I.js +0 -1
- package/web/assets/WikiPage-B51w0xOX.js +0 -1
- package/web/assets/WikiView-CGQrkGH4.js +0 -1
- package/web/assets/add-scalar-classes-ChVyhgpT.js +0 -387
- package/web/assets/auth-errors-BdfA61wA.js +0 -1
- package/web/assets/cloud-chat.store-D39vo5xT.js +0 -1
- package/web/assets/cloud-session-B7G8xhKC.js +0 -1
- package/web/assets/column-CPU5Jg0n.js +0 -907
- package/web/assets/interface-content-folder.svg-BCIUgpD4.js +0 -1
- package/web/assets/modal-D3dkRJqD.js +0 -1
- package/web/assets/modal-ix4Amfqv.js +0 -5
- package/web/assets/multiselect-C7U34xql.js +0 -251
- package/web/assets/process.store-DPp7dk63.js +0 -1
- package/web/assets/router-Df972Ysi.js +0 -1
- package/web/assets/settings-scope-CC3oHq2H.js +0 -1
- package/web/assets/settings.store-B31_cRNl.js +0 -1
- package/web/assets/src-Dt37H-VN.js +0 -1
- package/web/assets/trpc-aSS7b3jh.js +0 -1
- package/web/assets/useAiChatDrawer-C1xrMtLl.js +0 -1
- package/web/assets/useCloudOrg-BdpqnN19.css +0 -1
- package/web/assets/useCloudOrg-BexK510D.js +0 -97
- /package/{agent-manager-YDLSYZE3.js.map → agent-manager-L35E7FWI.js.map} +0 -0
package/agent/index.js
CHANGED
|
@@ -66,767 +66,54 @@ import { TRPCError as TRPCError2 } from "@trpc/server";
|
|
|
66
66
|
// src/services/process-manager.ts
|
|
67
67
|
import { EventEmitter as EventEmitter7 } from "events";
|
|
68
68
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
69
|
-
import { networkInterfaces } from "os";
|
|
69
|
+
import { networkInterfaces, homedir as homedir5, platform as platform2 } from "os";
|
|
70
70
|
import { join as join3, isAbsolute, resolve } from "path";
|
|
71
71
|
|
|
72
|
-
// ../../packages/
|
|
73
|
-
import {
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
// ../../packages/shared/src/schemas/user.schema.ts
|
|
73
|
+
import { z } from "zod";
|
|
74
|
+
var UserSchema = z.object({
|
|
75
|
+
id: z.string().max(128),
|
|
76
|
+
email: z.string().email().max(320),
|
|
77
|
+
name: z.string().min(1).max(500),
|
|
78
|
+
avatar: z.string().url().max(2048).nullable().optional()
|
|
79
|
+
});
|
|
76
80
|
|
|
77
|
-
// ../../
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
};
|
|
93
|
-
var split = (line = "") => {
|
|
94
|
-
const words = [];
|
|
95
|
-
let field = "";
|
|
96
|
-
scan(
|
|
97
|
-
line,
|
|
98
|
-
/\s*(?:([^\s\\'"]+)|'((?:[^'\\]|\\.)*)'|"((?:[^"\\]|\\.)*)"|(\\.?)|(\S))(\s|$)?/,
|
|
99
|
-
(match) => {
|
|
100
|
-
const [_raw, word, sq, dq, escape2, garbage, separator] = match;
|
|
101
|
-
if (garbage != null) {
|
|
102
|
-
throw new Error(`Unmatched quote: ${line}`);
|
|
103
|
-
}
|
|
104
|
-
if (word) {
|
|
105
|
-
field += word;
|
|
106
|
-
} else {
|
|
107
|
-
let addition;
|
|
108
|
-
if (sq) {
|
|
109
|
-
addition = sq;
|
|
110
|
-
} else if (dq) {
|
|
111
|
-
addition = dq;
|
|
112
|
-
} else if (escape2) {
|
|
113
|
-
addition = escape2;
|
|
114
|
-
}
|
|
115
|
-
if (addition) {
|
|
116
|
-
field += addition.replace(/\\(?=.)/, "");
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
if (separator != null) {
|
|
120
|
-
words.push(field);
|
|
121
|
-
field = "";
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
);
|
|
125
|
-
if (field) {
|
|
126
|
-
words.push(field);
|
|
127
|
-
}
|
|
128
|
-
return words;
|
|
129
|
-
};
|
|
81
|
+
// ../../packages/shared/src/schemas/org.schema.ts
|
|
82
|
+
import { z as z2 } from "zod";
|
|
83
|
+
var OrgSchema = z2.object({
|
|
84
|
+
id: z2.string().max(128),
|
|
85
|
+
name: z2.string().min(1).max(100),
|
|
86
|
+
slug: z2.string().min(1).max(100).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/),
|
|
87
|
+
ownerId: z2.string().max(128)
|
|
88
|
+
});
|
|
89
|
+
var OrgMemberSchema = z2.object({
|
|
90
|
+
id: z2.string().max(128),
|
|
91
|
+
orgId: z2.string().max(128),
|
|
92
|
+
userId: z2.string().max(128),
|
|
93
|
+
globalRole: z2.enum(["owner", "admin", "member"]),
|
|
94
|
+
invitedAt: z2.coerce.date(),
|
|
95
|
+
joinedAt: z2.coerce.date().nullable().optional()
|
|
96
|
+
});
|
|
130
97
|
|
|
131
|
-
// ../../packages/
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
return "";
|
|
152
|
-
});
|
|
153
|
-
return unresolved;
|
|
154
|
-
}
|
|
155
|
-
var SYSTEM_PATH_DIRS = ["/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", "/sbin", "/bin"];
|
|
156
|
-
function buildSafeEnv(configEnv = {}) {
|
|
157
|
-
const safeKeys = ["PATH", "HOME", "USER", "SHELL", "LANG", "TERM", "NODE_ENV", "TMPDIR", "TZ", "DBUS_SESSION_BUS_ADDRESS", "XDG_RUNTIME_DIR"];
|
|
158
|
-
const env2 = {};
|
|
159
|
-
for (const key of safeKeys) {
|
|
160
|
-
if (process.env[key]) {
|
|
161
|
-
env2[key] = process.env[key];
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
const existingPath = env2["PATH"] ?? "";
|
|
165
|
-
const existingDirs = new Set(existingPath.split(":").filter(Boolean));
|
|
166
|
-
const missingDirs = SYSTEM_PATH_DIRS.filter((d) => !existingDirs.has(d));
|
|
167
|
-
if (missingDirs.length > 0) {
|
|
168
|
-
env2["PATH"] = [existingPath, ...missingDirs].filter(Boolean).join(":");
|
|
169
|
-
}
|
|
170
|
-
return { ...env2, ...configEnv };
|
|
171
|
-
}
|
|
172
|
-
var NativeRunner = class {
|
|
173
|
-
type = "native";
|
|
174
|
-
start(config) {
|
|
175
|
-
let subprocess;
|
|
176
|
-
const cwd = resolveCwd(config.cwd, config.env);
|
|
177
|
-
const isWindows = process.platform === "win32";
|
|
178
|
-
if (config.shell) {
|
|
179
|
-
subprocess = execa(config.command, {
|
|
180
|
-
cwd,
|
|
181
|
-
env: buildSafeEnv(config.env),
|
|
182
|
-
shell: true,
|
|
183
|
-
detached: !isWindows,
|
|
184
|
-
// Create new process group for group kill (not supported on Windows)
|
|
185
|
-
windowsHide: true,
|
|
186
|
-
// Prevent terminal windows from appearing on Windows
|
|
187
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
188
|
-
reject: false,
|
|
189
|
-
// Don't throw on non-zero exit
|
|
190
|
-
buffer: false
|
|
191
|
-
// Don't accumulate stdout/stderr in memory — we stream via readline
|
|
192
|
-
});
|
|
193
|
-
} else {
|
|
194
|
-
const args = shellwordsSplit(config.command);
|
|
195
|
-
const cmd = args.shift();
|
|
196
|
-
if (!cmd) {
|
|
197
|
-
throw new Error("Invalid command: cannot parse empty or whitespace-only command");
|
|
198
|
-
}
|
|
199
|
-
subprocess = execa(cmd, args, {
|
|
200
|
-
cwd,
|
|
201
|
-
env: buildSafeEnv(config.env),
|
|
202
|
-
shell: false,
|
|
203
|
-
// SECURITY: shell:false prevents command injection
|
|
204
|
-
detached: !isWindows,
|
|
205
|
-
// Create new process group for group kill (not supported on Windows)
|
|
206
|
-
windowsHide: true,
|
|
207
|
-
// Prevent terminal windows from appearing on Windows
|
|
208
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
209
|
-
reject: false,
|
|
210
|
-
// Don't throw on non-zero exit
|
|
211
|
-
buffer: false
|
|
212
|
-
// Don't accumulate stdout/stderr in memory — we stream via readline
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
const exitPromise = new Promise((resolve2) => {
|
|
216
|
-
subprocess.then((result) => {
|
|
217
|
-
resolve2({
|
|
218
|
-
exitCode: result.exitCode ?? null,
|
|
219
|
-
signal: result.signal ?? null,
|
|
220
|
-
error: result.failed && result.shortMessage ? result.shortMessage : void 0
|
|
221
|
-
});
|
|
222
|
-
}).catch((err) => {
|
|
223
|
-
resolve2({ exitCode: 1, signal: null, error: err.message ?? "Unknown error" });
|
|
224
|
-
});
|
|
225
|
-
});
|
|
226
|
-
return {
|
|
227
|
-
pid: subprocess.pid,
|
|
228
|
-
kill(signal = "SIGTERM") {
|
|
229
|
-
try {
|
|
230
|
-
if (process.platform === "win32") {
|
|
231
|
-
if (!subprocess.pid) return false;
|
|
232
|
-
execSync(`taskkill /F /T /PID ${subprocess.pid}`, { stdio: "ignore" });
|
|
233
|
-
return true;
|
|
234
|
-
}
|
|
235
|
-
if (subprocess.pid) {
|
|
236
|
-
process.kill(-subprocess.pid, signal);
|
|
237
|
-
return true;
|
|
238
|
-
}
|
|
239
|
-
return subprocess.kill(signal);
|
|
240
|
-
} catch {
|
|
241
|
-
return false;
|
|
242
|
-
}
|
|
243
|
-
},
|
|
244
|
-
stdout: subprocess.stdout,
|
|
245
|
-
stderr: subprocess.stderr,
|
|
246
|
-
exitPromise
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
async isAvailable() {
|
|
250
|
-
return true;
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
// ../../packages/runner-docker/src/index.ts
|
|
255
|
-
import { execa as execa2 } from "execa";
|
|
256
|
-
import { PassThrough } from "stream";
|
|
257
|
-
import { randomUUID } from "crypto";
|
|
258
|
-
import { writeFile, unlink, mkdir } from "fs/promises";
|
|
259
|
-
import { tmpdir, homedir as homedir2, userInfo } from "os";
|
|
260
|
-
import { join } from "path";
|
|
261
|
-
function splitShellArgs(cmd) {
|
|
262
|
-
const args = [];
|
|
263
|
-
let current = "";
|
|
264
|
-
let inSingle = false;
|
|
265
|
-
let inDouble = false;
|
|
266
|
-
for (let i = 0; i < cmd.length; i++) {
|
|
267
|
-
const ch = cmd[i];
|
|
268
|
-
if (ch === "'" && !inDouble) {
|
|
269
|
-
inSingle = !inSingle;
|
|
270
|
-
} else if (ch === '"' && !inSingle) {
|
|
271
|
-
inDouble = !inDouble;
|
|
272
|
-
} else if (ch === "\\" && inDouble && i + 1 < cmd.length) {
|
|
273
|
-
current += cmd[++i];
|
|
274
|
-
} else if (/\s/.test(ch) && !inSingle && !inDouble) {
|
|
275
|
-
if (current) {
|
|
276
|
-
args.push(current);
|
|
277
|
-
current = "";
|
|
278
|
-
}
|
|
279
|
-
} else {
|
|
280
|
-
current += ch;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
if (current) args.push(current);
|
|
284
|
-
return args;
|
|
285
|
-
}
|
|
286
|
-
function sanitizeDockerName(name) {
|
|
287
|
-
return name.toLowerCase().replace(/[^a-z0-9._-]/g, "-").replace(/-{2,}/g, "-");
|
|
288
|
-
}
|
|
289
|
-
function expandEnvVars2(str, serviceEnv) {
|
|
290
|
-
const withHome = str.replace(/^~(\/|$)/, `${homedir2()}$1`);
|
|
291
|
-
return withHome.replace(/\$\{(\w+)\}|\$(\w+)/g, (_, braced, plain) => {
|
|
292
|
-
const name = braced ?? plain;
|
|
293
|
-
return serviceEnv?.[name] ?? "";
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
async function preMkdirVolumes(volumes, serviceEnv) {
|
|
297
|
-
for (const v of volumes) {
|
|
298
|
-
const expanded = expandEnvVars2(v, serviceEnv);
|
|
299
|
-
const parts = expanded.split(":");
|
|
300
|
-
if (parts.length < 2) continue;
|
|
301
|
-
const hostPath = parts[0];
|
|
302
|
-
if (!hostPath.startsWith("/") && !hostPath.startsWith(".")) continue;
|
|
303
|
-
await mkdir(hostPath, { recursive: true }).catch(() => {
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
var DockerRunner = class {
|
|
308
|
-
type = "docker";
|
|
309
|
-
start(config) {
|
|
310
|
-
const stdout = new PassThrough();
|
|
311
|
-
const stderr = new PassThrough();
|
|
312
|
-
const containerName = sanitizeDockerName(config.cmdId ? `runeya-${config.serviceId}-${config.cmdId}` : `runeya-${config.serviceId}`);
|
|
313
|
-
let killed = false;
|
|
314
|
-
const exitPromise = new Promise(
|
|
315
|
-
(resolve2) => {
|
|
316
|
-
void (async () => {
|
|
317
|
-
try {
|
|
318
|
-
await execa2("docker", ["rm", "-f", containerName], { reject: false });
|
|
319
|
-
const dc = config.dockerConfig;
|
|
320
|
-
let lastCardId = null;
|
|
321
|
-
const envFlags = Object.entries(config.env ?? {}).flatMap(
|
|
322
|
-
([k, v]) => ["-e", `${k}=${v}`]
|
|
323
|
-
);
|
|
324
|
-
await preMkdirVolumes(dc.volumes ?? [], config.env);
|
|
325
|
-
const volumeFlags = (dc.volumes ?? []).flatMap((v) => ["-v", expandEnvVars2(v, config.env)]);
|
|
326
|
-
if (dc.mountRootpath && config.cwd) {
|
|
327
|
-
volumeFlags.push("-v", `${config.cwd}:${config.cwd}`);
|
|
328
|
-
}
|
|
329
|
-
if (dc.image && !dc.dockerfile) {
|
|
330
|
-
lastCardId = randomUUID();
|
|
331
|
-
stdout.write(
|
|
332
|
-
"\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "pull", _cardId: lastCardId, _cardState: "open", message: `--- Docker Pull: ${dc.image} ---` }) + "\n"
|
|
333
|
-
);
|
|
334
|
-
const pull = execa2("docker", ["pull", dc.image], { reject: false });
|
|
335
|
-
pull.stdout?.pipe(stdout, { end: false });
|
|
336
|
-
pull.stderr?.pipe(stderr, { end: false });
|
|
337
|
-
await pull;
|
|
338
|
-
}
|
|
339
|
-
let imageName = dc.image ?? containerName + ":latest";
|
|
340
|
-
if (dc.dockerfile) {
|
|
341
|
-
lastCardId = randomUUID();
|
|
342
|
-
stdout.write(
|
|
343
|
-
"\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "build", _cardId: lastCardId, _cardState: "open", message: "--- Docker Build ---" }) + "\n"
|
|
344
|
-
);
|
|
345
|
-
const tmpFile = join(tmpdir(), `runeya-${config.serviceId}-${randomUUID()}.dockerfile`);
|
|
346
|
-
try {
|
|
347
|
-
await writeFile(tmpFile, dc.dockerfile, "utf8");
|
|
348
|
-
const buildArgs = Object.entries(dc.buildArgs ?? {}).flatMap(
|
|
349
|
-
([k, v]) => ["--build-arg", `${k}=${v}`]
|
|
350
|
-
);
|
|
351
|
-
const targetArgs = dc.targetStage ? ["--target", dc.targetStage] : [];
|
|
352
|
-
const buildContext = dc.buildContext ?? config.cwd ?? ".";
|
|
353
|
-
imageName = `${containerName}:latest`;
|
|
354
|
-
const build = execa2(
|
|
355
|
-
"docker",
|
|
356
|
-
["build", "-f", tmpFile, "-t", imageName, ...buildArgs, ...targetArgs, buildContext],
|
|
357
|
-
{ reject: false }
|
|
358
|
-
);
|
|
359
|
-
build.stdout?.pipe(stdout, { end: false });
|
|
360
|
-
build.stderr?.pipe(stderr, { end: false });
|
|
361
|
-
await build;
|
|
362
|
-
} finally {
|
|
363
|
-
await unlink(tmpFile).catch(() => {
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
if (killed) {
|
|
368
|
-
resolve2({ exitCode: null, signal: "SIGTERM" });
|
|
369
|
-
return;
|
|
370
|
-
}
|
|
371
|
-
if (lastCardId) {
|
|
372
|
-
stdout.write(
|
|
373
|
-
"\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "close", _cardId: lastCardId, _cardState: "close" }) + "\n"
|
|
374
|
-
);
|
|
375
|
-
}
|
|
376
|
-
const bootstrapCmds = config.skipBootstrap ? [] : (dc.bootstrapCommands ?? []).filter((c) => c.command.trim());
|
|
377
|
-
for (const bsCmd of bootstrapCmds) {
|
|
378
|
-
if (killed) {
|
|
379
|
-
resolve2({ exitCode: null, signal: "SIGTERM" });
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
const bsCardId = randomUUID();
|
|
383
|
-
const bsCmdName = bsCmd.label || bsCmd.command;
|
|
384
|
-
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "bootstrap", _cardId: bsCardId, _cardState: "open", message: `Bootstrap: ${bsCmdName}` })}
|
|
385
|
-
`);
|
|
386
|
-
const exitCode = await this.runBootstrap(bsCmd, imageName, config.env ?? {}, dc.volumes ?? [], stdout, stderr);
|
|
387
|
-
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: bsCardId, _cardState: "close" })}
|
|
388
|
-
`);
|
|
389
|
-
if (exitCode !== 0) {
|
|
390
|
-
stderr.write(`Bootstrap command "${bsCmdName}" failed with exit code ${exitCode}
|
|
391
|
-
`);
|
|
392
|
-
resolve2({ exitCode, signal: null, error: `Bootstrap "${bsCmdName}" failed (exit ${exitCode})` });
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
if (killed) {
|
|
397
|
-
resolve2({ exitCode: null, signal: "SIGTERM" });
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
const networkFlags = dc.networkMode === "host" ? ["--network", "host"] : (dc.ports ?? []).flatMap((p) => ["-p", p]);
|
|
401
|
-
let cmdArgs;
|
|
402
|
-
let entrypointFlags;
|
|
403
|
-
if (dc.useNativeCommand) {
|
|
404
|
-
const shell = dc.nativeShell || "sh";
|
|
405
|
-
entrypointFlags = [];
|
|
406
|
-
cmdArgs = config.command ? [shell, "-c", config.command] : [];
|
|
407
|
-
} else {
|
|
408
|
-
entrypointFlags = dc.entrypoint ? ["--entrypoint", dc.entrypoint] : [];
|
|
409
|
-
cmdArgs = dc.command ? splitShellArgs(dc.command) : [];
|
|
410
|
-
}
|
|
411
|
-
const { uid, gid } = userInfo();
|
|
412
|
-
const rmFlag = config.rm ? ["--rm"] : [];
|
|
413
|
-
const runArgs = [
|
|
414
|
-
"run",
|
|
415
|
-
...rmFlag,
|
|
416
|
-
"--init",
|
|
417
|
-
"--name",
|
|
418
|
-
containerName,
|
|
419
|
-
"--user",
|
|
420
|
-
dc.user || `${uid}:${gid}`,
|
|
421
|
-
...networkFlags,
|
|
422
|
-
...envFlags,
|
|
423
|
-
...volumeFlags,
|
|
424
|
-
...entrypointFlags,
|
|
425
|
-
imageName,
|
|
426
|
-
...cmdArgs
|
|
427
|
-
];
|
|
428
|
-
const debugCardId = randomUUID();
|
|
429
|
-
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "run", _cardId: debugCardId, _cardState: "open", message: "Docker Run" })}
|
|
430
|
-
`);
|
|
431
|
-
stdout.write(`docker ${runArgs.join(" ")}
|
|
432
|
-
`);
|
|
433
|
-
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: debugCardId, _cardState: "close" })}
|
|
434
|
-
`);
|
|
435
|
-
const runProc = execa2("docker", runArgs, { reject: false });
|
|
436
|
-
runProc.stdout?.pipe(stdout, { end: false });
|
|
437
|
-
runProc.stderr?.pipe(stderr, { end: false });
|
|
438
|
-
const result = await runProc;
|
|
439
|
-
resolve2({ exitCode: result.exitCode ?? null, signal: result.signal ?? null });
|
|
440
|
-
} catch (err) {
|
|
441
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
442
|
-
stderr.write(`Docker infrastructure error: ${msg}
|
|
443
|
-
`);
|
|
444
|
-
resolve2({ exitCode: 1, signal: null });
|
|
445
|
-
} finally {
|
|
446
|
-
stdout.end();
|
|
447
|
-
stderr.end();
|
|
448
|
-
}
|
|
449
|
-
})();
|
|
450
|
-
}
|
|
451
|
-
);
|
|
452
|
-
return {
|
|
453
|
-
pid: void 0,
|
|
454
|
-
containerName,
|
|
455
|
-
stdout,
|
|
456
|
-
stderr,
|
|
457
|
-
exitPromise,
|
|
458
|
-
kill(_signal = "SIGTERM") {
|
|
459
|
-
killed = true;
|
|
460
|
-
execa2("docker", ["stop", containerName]).catch(() => {
|
|
461
|
-
});
|
|
462
|
-
return true;
|
|
463
|
-
}
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
/** Start a long-lived container (sleep infinity) for shared mode.
|
|
467
|
-
* Returns the RunnerProcess (lifetime) plus a `containerReady` promise that resolves
|
|
468
|
-
* once `docker run --detach` has completed and the container is confirmed running.
|
|
469
|
-
* Callers must await `containerReady` before calling `execInContainer`. */
|
|
470
|
-
startSharedContainer(config) {
|
|
471
|
-
const stdout = new PassThrough();
|
|
472
|
-
const stderr = new PassThrough();
|
|
473
|
-
const containerName = sanitizeDockerName(`runeya-${config.serviceId}`);
|
|
474
|
-
let killed = false;
|
|
475
|
-
let resolveReady;
|
|
476
|
-
let rejectReady;
|
|
477
|
-
const containerReady = new Promise((res, rej) => {
|
|
478
|
-
resolveReady = res;
|
|
479
|
-
rejectReady = rej;
|
|
480
|
-
});
|
|
481
|
-
let exitResolve;
|
|
482
|
-
const exitPromise = new Promise(
|
|
483
|
-
(resolve2) => {
|
|
484
|
-
exitResolve = resolve2;
|
|
485
|
-
}
|
|
486
|
-
);
|
|
487
|
-
void (async () => {
|
|
488
|
-
try {
|
|
489
|
-
await execa2("docker", ["rm", "-f", containerName], { reject: false });
|
|
490
|
-
const dc = config.dockerConfig;
|
|
491
|
-
let lastCardId = null;
|
|
492
|
-
const envFlags = Object.entries(config.env ?? {}).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
|
|
493
|
-
await preMkdirVolumes(dc.volumes ?? [], config.env);
|
|
494
|
-
const volumeFlags = (dc.volumes ?? []).flatMap((v) => ["-v", expandEnvVars2(v, config.env)]);
|
|
495
|
-
if (dc.mountRootpath && config.cwd) {
|
|
496
|
-
volumeFlags.push("-v", `${config.cwd}:${config.cwd}`);
|
|
497
|
-
}
|
|
498
|
-
if (dc.image && !dc.dockerfile) {
|
|
499
|
-
lastCardId = randomUUID();
|
|
500
|
-
stdout.write("\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "pull", _cardId: lastCardId, _cardState: "open", message: `--- Docker Pull: ${dc.image} ---` }) + "\n");
|
|
501
|
-
const pull = execa2("docker", ["pull", dc.image], { reject: false });
|
|
502
|
-
pull.stdout?.pipe(stdout, { end: false });
|
|
503
|
-
pull.stderr?.pipe(stderr, { end: false });
|
|
504
|
-
await pull;
|
|
505
|
-
}
|
|
506
|
-
let imageName = dc.image ?? containerName + ":latest";
|
|
507
|
-
if (dc.dockerfile) {
|
|
508
|
-
lastCardId = randomUUID();
|
|
509
|
-
stdout.write("\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "build", _cardId: lastCardId, _cardState: "open", message: "--- Docker Build ---" }) + "\n");
|
|
510
|
-
const tmpFile = join(tmpdir(), `runeya-${config.serviceId}-${randomUUID()}.dockerfile`);
|
|
511
|
-
try {
|
|
512
|
-
await writeFile(tmpFile, dc.dockerfile, "utf8");
|
|
513
|
-
const buildArgs = Object.entries(dc.buildArgs ?? {}).flatMap(([k, v]) => ["--build-arg", `${k}=${v}`]);
|
|
514
|
-
const targetArgs = dc.targetStage ? ["--target", dc.targetStage] : [];
|
|
515
|
-
const buildContext = dc.buildContext ?? config.cwd ?? ".";
|
|
516
|
-
imageName = `${containerName}:latest`;
|
|
517
|
-
const build = execa2("docker", ["build", "-f", tmpFile, "-t", imageName, ...buildArgs, ...targetArgs, buildContext], { reject: false });
|
|
518
|
-
build.stdout?.pipe(stdout, { end: false });
|
|
519
|
-
build.stderr?.pipe(stderr, { end: false });
|
|
520
|
-
await build;
|
|
521
|
-
} finally {
|
|
522
|
-
await unlink(tmpFile).catch(() => {
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
if (killed) {
|
|
527
|
-
rejectReady(new Error("Killed before container started"));
|
|
528
|
-
exitResolve({ exitCode: null, signal: "SIGTERM" });
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
if (lastCardId) {
|
|
532
|
-
stdout.write("\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "close", _cardId: lastCardId, _cardState: "close" }) + "\n");
|
|
533
|
-
}
|
|
534
|
-
const networkFlags = dc.networkMode === "host" ? ["--network", "host"] : (dc.ports ?? []).flatMap((p) => ["-p", p]);
|
|
535
|
-
const { uid, gid } = userInfo();
|
|
536
|
-
const runArgs = [
|
|
537
|
-
"run",
|
|
538
|
-
"--detach",
|
|
539
|
-
"--init",
|
|
540
|
-
"--name",
|
|
541
|
-
containerName,
|
|
542
|
-
"--user",
|
|
543
|
-
dc.user || `${uid}:${gid}`,
|
|
544
|
-
...networkFlags,
|
|
545
|
-
...envFlags,
|
|
546
|
-
...volumeFlags,
|
|
547
|
-
imageName,
|
|
548
|
-
"sleep",
|
|
549
|
-
"infinity"
|
|
550
|
-
];
|
|
551
|
-
const debugCardId = randomUUID();
|
|
552
|
-
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "run", _cardId: debugCardId, _cardState: "open", message: "Docker Run (shared container)" })}
|
|
553
|
-
`);
|
|
554
|
-
stdout.write(`docker ${runArgs.join(" ")}
|
|
555
|
-
`);
|
|
556
|
-
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: debugCardId, _cardState: "close" })}
|
|
557
|
-
`);
|
|
558
|
-
const runProc = execa2("docker", runArgs, { reject: false });
|
|
559
|
-
runProc.stdout?.pipe(stdout, { end: false });
|
|
560
|
-
runProc.stderr?.pipe(stderr, { end: false });
|
|
561
|
-
const runResult = await runProc;
|
|
562
|
-
if (runResult.exitCode !== 0) {
|
|
563
|
-
rejectReady(new Error(`docker run exited with code ${runResult.exitCode}`));
|
|
564
|
-
exitResolve({ exitCode: runResult.exitCode ?? 1, signal: null });
|
|
565
|
-
return;
|
|
566
|
-
}
|
|
567
|
-
resolveReady();
|
|
568
|
-
const waitProc = execa2("docker", ["wait", containerName], { reject: false });
|
|
569
|
-
await waitProc;
|
|
570
|
-
exitResolve({ exitCode: 0, signal: null });
|
|
571
|
-
} catch (err) {
|
|
572
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
573
|
-
stderr.write(`Docker infrastructure error: ${msg}
|
|
574
|
-
`);
|
|
575
|
-
rejectReady(new Error(msg));
|
|
576
|
-
exitResolve({ exitCode: 1, signal: null });
|
|
577
|
-
} finally {
|
|
578
|
-
stdout.end();
|
|
579
|
-
stderr.end();
|
|
580
|
-
}
|
|
581
|
-
})();
|
|
582
|
-
return {
|
|
583
|
-
pid: void 0,
|
|
584
|
-
containerName,
|
|
585
|
-
stdout,
|
|
586
|
-
stderr,
|
|
587
|
-
exitPromise,
|
|
588
|
-
containerReady,
|
|
589
|
-
kill(_signal = "SIGTERM") {
|
|
590
|
-
killed = true;
|
|
591
|
-
execa2("docker", ["kill", containerName]).then(() => exitResolve({ exitCode: null, signal: "SIGKILL" })).catch(() => exitResolve({ exitCode: 1, signal: null }));
|
|
592
|
-
return true;
|
|
593
|
-
}
|
|
594
|
-
};
|
|
595
|
-
}
|
|
596
|
-
/** Run a command inside a running shared container via `docker exec`.
|
|
597
|
-
* Kill terminates the docker-exec process but does NOT stop the container. */
|
|
598
|
-
execInContainer(containerName, command, envVars = {}, shell = "sh") {
|
|
599
|
-
const stdout = new PassThrough();
|
|
600
|
-
const stderr = new PassThrough();
|
|
601
|
-
let dockerProc = null;
|
|
602
|
-
const exitPromise = new Promise(
|
|
603
|
-
(resolve2) => {
|
|
604
|
-
void (async () => {
|
|
605
|
-
try {
|
|
606
|
-
const envFlags = Object.entries(envVars).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
|
|
607
|
-
const shellCmd = command.length ? command : "true";
|
|
608
|
-
dockerProc = execa2(
|
|
609
|
-
"docker",
|
|
610
|
-
["exec", ...envFlags, containerName, shell, "-c", shellCmd],
|
|
611
|
-
{ reject: false }
|
|
612
|
-
);
|
|
613
|
-
dockerProc.stdout?.pipe(stdout, { end: false });
|
|
614
|
-
dockerProc.stderr?.pipe(stderr, { end: false });
|
|
615
|
-
const result = await dockerProc;
|
|
616
|
-
resolve2({ exitCode: result.exitCode ?? null, signal: result.signal ?? null });
|
|
617
|
-
} catch (err) {
|
|
618
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
619
|
-
stderr.write(`docker execInContainer error: ${msg}
|
|
620
|
-
`);
|
|
621
|
-
resolve2({ exitCode: 1, signal: null });
|
|
622
|
-
} finally {
|
|
623
|
-
stdout.end();
|
|
624
|
-
stderr.end();
|
|
625
|
-
}
|
|
626
|
-
})();
|
|
627
|
-
}
|
|
628
|
-
);
|
|
629
|
-
return {
|
|
630
|
-
pid: void 0,
|
|
631
|
-
containerName,
|
|
632
|
-
stdout,
|
|
633
|
-
stderr,
|
|
634
|
-
exitPromise,
|
|
635
|
-
kill(_signal = "SIGTERM") {
|
|
636
|
-
dockerProc?.kill("SIGTERM");
|
|
637
|
-
return true;
|
|
638
|
-
}
|
|
639
|
-
};
|
|
640
|
-
}
|
|
641
|
-
/** Run a shortcut command in the context of a Docker service.
|
|
642
|
-
* If a service container is running (shared or isolated), uses `docker exec`.
|
|
643
|
-
* If not running, reuses `start()` with `--rm` and `skipBootstrap`. */
|
|
644
|
-
runShortcut(config, shortcutCommand) {
|
|
645
|
-
const stdout = new PassThrough();
|
|
646
|
-
const stderr = new PassThrough();
|
|
647
|
-
let innerProcess = null;
|
|
648
|
-
let dockerProc = null;
|
|
649
|
-
const exitPromise = new Promise(
|
|
650
|
-
(resolve2) => {
|
|
651
|
-
void (async () => {
|
|
652
|
-
try {
|
|
653
|
-
const psResult = await execa2(
|
|
654
|
-
"docker",
|
|
655
|
-
["ps", "--filter", `name=runeya-${config.serviceId}`, "--format", "{{.Names}}"],
|
|
656
|
-
{ reject: false }
|
|
657
|
-
);
|
|
658
|
-
const runningContainer = psResult.stdout.trim().split("\n").find((n) => n.startsWith(`runeya-${config.serviceId}`));
|
|
659
|
-
if (runningContainer) {
|
|
660
|
-
const shell = config.dockerConfig.nativeShell || "sh";
|
|
661
|
-
const envFlags = Object.entries(config.env ?? {}).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
|
|
662
|
-
const args = ["exec", ...envFlags, runningContainer, shell, "-c", shortcutCommand || "true"];
|
|
663
|
-
const cardId = randomUUID();
|
|
664
|
-
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "exec", _cardId: cardId, _cardState: "open", message: "Docker Exec" })}
|
|
665
|
-
`);
|
|
666
|
-
stdout.write(`docker ${args.join(" ")}
|
|
667
|
-
`);
|
|
668
|
-
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: cardId, _cardState: "close" })}
|
|
669
|
-
`);
|
|
670
|
-
dockerProc = execa2("docker", args, { reject: false });
|
|
671
|
-
dockerProc.stdout?.pipe(stdout, { end: false });
|
|
672
|
-
dockerProc.stderr?.pipe(stderr, { end: false });
|
|
673
|
-
const result = await dockerProc;
|
|
674
|
-
resolve2({ exitCode: result.exitCode ?? null, signal: result.signal ?? null });
|
|
675
|
-
} else {
|
|
676
|
-
innerProcess = this.start({
|
|
677
|
-
...config,
|
|
678
|
-
command: shortcutCommand,
|
|
679
|
-
cmdId: `shortcut-${randomUUID()}`,
|
|
680
|
-
rm: true,
|
|
681
|
-
skipBootstrap: true,
|
|
682
|
-
dockerConfig: { ...config.dockerConfig, useNativeCommand: true }
|
|
683
|
-
});
|
|
684
|
-
innerProcess.stdout?.pipe(stdout, { end: false });
|
|
685
|
-
innerProcess.stderr?.pipe(stderr, { end: false });
|
|
686
|
-
const result = await innerProcess.exitPromise;
|
|
687
|
-
resolve2(result);
|
|
688
|
-
}
|
|
689
|
-
} catch (err) {
|
|
690
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
691
|
-
stderr.write(`docker shortcut error: ${msg}
|
|
692
|
-
`);
|
|
693
|
-
resolve2({ exitCode: 1, signal: null });
|
|
694
|
-
} finally {
|
|
695
|
-
stdout.end();
|
|
696
|
-
stderr.end();
|
|
697
|
-
}
|
|
698
|
-
})();
|
|
699
|
-
}
|
|
700
|
-
);
|
|
701
|
-
return {
|
|
702
|
-
pid: void 0,
|
|
703
|
-
stdout,
|
|
704
|
-
stderr,
|
|
705
|
-
exitPromise,
|
|
706
|
-
kill(signal = "SIGTERM") {
|
|
707
|
-
if (innerProcess) return innerProcess.kill(signal);
|
|
708
|
-
dockerProc?.kill("SIGTERM");
|
|
709
|
-
return true;
|
|
710
|
-
}
|
|
711
|
-
};
|
|
712
|
-
}
|
|
713
|
-
async isAvailable() {
|
|
714
|
-
const result = await execa2("docker", ["info"], { reject: false });
|
|
715
|
-
return result.exitCode === 0;
|
|
716
|
-
}
|
|
717
|
-
/** Run a single bootstrap command sequentially inside a temporary container (--rm).
|
|
718
|
-
* Streams stdout/stderr into the provided PassThrough streams.
|
|
719
|
-
* Resolves with the exit code when the container exits. */
|
|
720
|
-
async runBootstrap(cmd, imageName, env2, volumes, stdout, stderr) {
|
|
721
|
-
const containerName = sanitizeDockerName(`runeya-bootstrap-${randomUUID()}`);
|
|
722
|
-
const envFlags = Object.entries(env2).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
|
|
723
|
-
await preMkdirVolumes(volumes, env2);
|
|
724
|
-
const volumeFlags = volumes.map((v) => expandEnvVars2(v, env2)).flatMap((v) => ["-v", v]);
|
|
725
|
-
const entrypointFlags = cmd.entrypoint ? ["--entrypoint", cmd.entrypoint] : [];
|
|
726
|
-
const { uid, gid } = userInfo();
|
|
727
|
-
const defaultUser = `${uid}:${gid}`;
|
|
728
|
-
const userFlags = ["--user", cmd.user || defaultUser];
|
|
729
|
-
const cmdArgs = splitShellArgs(cmd.command);
|
|
730
|
-
const runArgs = [
|
|
731
|
-
"run",
|
|
732
|
-
"--rm",
|
|
733
|
-
"--init",
|
|
734
|
-
"--name",
|
|
735
|
-
containerName,
|
|
736
|
-
"--network",
|
|
737
|
-
"host",
|
|
738
|
-
...envFlags,
|
|
739
|
-
...volumeFlags,
|
|
740
|
-
...entrypointFlags,
|
|
741
|
-
...userFlags,
|
|
742
|
-
imageName,
|
|
743
|
-
...cmdArgs
|
|
744
|
-
];
|
|
745
|
-
const proc = execa2("docker", runArgs, { reject: false });
|
|
746
|
-
proc.stdout?.pipe(stdout, { end: false });
|
|
747
|
-
proc.stderr?.pipe(stderr, { end: false });
|
|
748
|
-
const result = await proc;
|
|
749
|
-
return result.exitCode ?? 1;
|
|
750
|
-
}
|
|
751
|
-
};
|
|
752
|
-
|
|
753
|
-
// src/services/process-store.ts
|
|
754
|
-
var ProcessStore = class {
|
|
755
|
-
processes = /* @__PURE__ */ new Map();
|
|
756
|
-
get(id) {
|
|
757
|
-
return this.processes.get(id);
|
|
758
|
-
}
|
|
759
|
-
getAll() {
|
|
760
|
-
return Array.from(this.processes.values());
|
|
761
|
-
}
|
|
762
|
-
set(id, process2) {
|
|
763
|
-
this.processes.set(id, process2);
|
|
764
|
-
}
|
|
765
|
-
delete(id) {
|
|
766
|
-
return this.processes.delete(id);
|
|
767
|
-
}
|
|
768
|
-
has(id) {
|
|
769
|
-
return this.processes.has(id);
|
|
770
|
-
}
|
|
771
|
-
clear() {
|
|
772
|
-
this.processes.clear();
|
|
773
|
-
}
|
|
774
|
-
getByServiceId(serviceId) {
|
|
775
|
-
return this.getAll().find((p) => p.serviceConfig.id === serviceId);
|
|
776
|
-
}
|
|
777
|
-
};
|
|
778
|
-
var processStore = new ProcessStore();
|
|
779
|
-
|
|
780
|
-
// src/services/log-sources/console-log-source.ts
|
|
781
|
-
import { createInterface } from "readline";
|
|
782
|
-
import { EventEmitter } from "events";
|
|
783
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
784
|
-
|
|
785
|
-
// ../../packages/shared/src/schemas/user.schema.ts
|
|
786
|
-
import { z } from "zod";
|
|
787
|
-
var UserSchema = z.object({
|
|
788
|
-
id: z.string().max(128),
|
|
789
|
-
email: z.string().email().max(320),
|
|
790
|
-
name: z.string().min(1).max(500),
|
|
791
|
-
avatar: z.string().url().max(2048).nullable().optional()
|
|
792
|
-
});
|
|
793
|
-
|
|
794
|
-
// ../../packages/shared/src/schemas/org.schema.ts
|
|
795
|
-
import { z as z2 } from "zod";
|
|
796
|
-
var OrgSchema = z2.object({
|
|
797
|
-
id: z2.string().max(128),
|
|
798
|
-
name: z2.string().min(1).max(100),
|
|
799
|
-
slug: z2.string().min(1).max(100).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/),
|
|
800
|
-
ownerId: z2.string().max(128)
|
|
801
|
-
});
|
|
802
|
-
var OrgMemberSchema = z2.object({
|
|
803
|
-
id: z2.string().max(128),
|
|
804
|
-
orgId: z2.string().max(128),
|
|
805
|
-
userId: z2.string().max(128),
|
|
806
|
-
globalRole: z2.enum(["owner", "admin", "member"]),
|
|
807
|
-
invitedAt: z2.coerce.date(),
|
|
808
|
-
joinedAt: z2.coerce.date().nullable().optional()
|
|
809
|
-
});
|
|
810
|
-
|
|
811
|
-
// ../../packages/shared/src/schemas/project.schema.ts
|
|
812
|
-
import { z as z3 } from "zod";
|
|
813
|
-
var ProjectSchema = z3.object({
|
|
814
|
-
id: z3.string().max(128),
|
|
815
|
-
orgId: z3.string().max(128).nullable().optional(),
|
|
816
|
-
name: z3.string().min(1).max(200),
|
|
817
|
-
description: z3.string().max(1e4).optional().default(""),
|
|
818
|
-
serviceIds: z3.array(z3.string().max(128)).max(1e4).default([]),
|
|
819
|
-
// Environment support
|
|
820
|
-
// NOTE: activeEnvironmentId is runtime-only (not persisted to JSON)
|
|
821
|
-
// It's initialized to 'local' by default at load time
|
|
822
|
-
activeEnvironmentId: z3.string().max(128).optional(),
|
|
823
|
-
environmentIds: z3.array(z3.string().max(128)).max(100).default([]),
|
|
824
|
-
// Ordre d'affichage des groupes de services dans la sidebar (noms de groupes).
|
|
825
|
-
// Les groupes absents de cette liste sont affichés après, par ordre alphabétique.
|
|
826
|
-
groupOrder: z3.array(z3.string().max(200)).max(100).default([])
|
|
827
|
-
});
|
|
828
|
-
var CreateProjectSchema = ProjectSchema.omit({ id: true }).partial().required({ name: true });
|
|
829
|
-
var UpdateProjectSchema = ProjectSchema.partial().required({ id: true });
|
|
98
|
+
// ../../packages/shared/src/schemas/project.schema.ts
|
|
99
|
+
import { z as z3 } from "zod";
|
|
100
|
+
var ProjectSchema = z3.object({
|
|
101
|
+
id: z3.string().max(128),
|
|
102
|
+
orgId: z3.string().max(128).nullable().optional(),
|
|
103
|
+
name: z3.string().min(1).max(200),
|
|
104
|
+
description: z3.string().max(1e4).optional().default(""),
|
|
105
|
+
serviceIds: z3.array(z3.string().max(128)).max(1e4).default([]),
|
|
106
|
+
// Environment support
|
|
107
|
+
// NOTE: activeEnvironmentId is runtime-only (not persisted to JSON)
|
|
108
|
+
// It's initialized to 'local' by default at load time
|
|
109
|
+
activeEnvironmentId: z3.string().max(128).optional(),
|
|
110
|
+
environmentIds: z3.array(z3.string().max(128)).max(100).default([]),
|
|
111
|
+
// Ordre d'affichage des groupes de services dans la sidebar (noms de groupes).
|
|
112
|
+
// Les groupes absents de cette liste sont affichés après, par ordre alphabétique.
|
|
113
|
+
groupOrder: z3.array(z3.string().max(200)).max(100).default([])
|
|
114
|
+
});
|
|
115
|
+
var CreateProjectSchema = ProjectSchema.omit({ id: true }).partial().required({ name: true });
|
|
116
|
+
var UpdateProjectSchema = ProjectSchema.partial().required({ id: true });
|
|
830
117
|
|
|
831
118
|
// ../../packages/shared/src/schemas/service.schema.ts
|
|
832
119
|
import { z as z7 } from "zod";
|
|
@@ -1309,7 +596,16 @@ var AgentStatusSchema = z10.object({
|
|
|
1309
596
|
lastSeen: z10.string().nullable().optional(),
|
|
1310
597
|
uptime: z10.number().nonnegative().default(0),
|
|
1311
598
|
runnersAvailable: z10.array(z10.enum(["native", "docker"])).default(["native"]),
|
|
1312
|
-
lanIp: z10.string().optional()
|
|
599
|
+
lanIp: z10.string().optional(),
|
|
600
|
+
/**
|
|
601
|
+
* Ce que la machine de l'agent vaut pour les builtins de portée `agent`.
|
|
602
|
+
* Sert à PRÉVISUALISER — la valeur injectée reste calculée au lancement, par
|
|
603
|
+
* l'agent lui-même : une IP change, un agent se déconnecte, et un statut
|
|
604
|
+
* n'est qu'un cliché.
|
|
605
|
+
*/
|
|
606
|
+
os: z10.string().max(64).optional(),
|
|
607
|
+
home: z10.string().max(4096).optional(),
|
|
608
|
+
cwd: z10.string().max(4096).optional()
|
|
1313
609
|
});
|
|
1314
610
|
|
|
1315
611
|
// ../../packages/shared/src/schemas/permission.schema.ts
|
|
@@ -1721,233 +1017,1000 @@ var KanbanCardRefSchema = z19.object({
|
|
|
1721
1017
|
commentCount: z19.number().int().nonnegative().default(0)
|
|
1722
1018
|
});
|
|
1723
1019
|
|
|
1724
|
-
// ../../packages/shared/src/schemas/cloud-api-key.schema.ts
|
|
1725
|
-
import { z as z20 } from "zod";
|
|
1726
|
-
var CloudApiScopeSchema = z20.enum([
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
*
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
secret
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1020
|
+
// ../../packages/shared/src/schemas/cloud-api-key.schema.ts
|
|
1021
|
+
import { z as z20 } from "zod";
|
|
1022
|
+
var CloudApiScopeSchema = z20.enum([
|
|
1023
|
+
"kanban:read",
|
|
1024
|
+
"kanban:write",
|
|
1025
|
+
"kanban:comment",
|
|
1026
|
+
"kanban:delete"
|
|
1027
|
+
]);
|
|
1028
|
+
var CloudApiKeySecretSchema = z20.string().regex(/^rk_[0-9a-f]{64}$/);
|
|
1029
|
+
var CloudApiKeySchema = z20.object({
|
|
1030
|
+
id: z20.string().max(128),
|
|
1031
|
+
organizationId: z20.string().max(128),
|
|
1032
|
+
name: z20.string().min(1).max(200),
|
|
1033
|
+
scopes: z20.array(CloudApiScopeSchema).min(1).max(10),
|
|
1034
|
+
/**
|
|
1035
|
+
* Les tableaux que la clé peut atteindre, ou `null` pour « tous ceux de
|
|
1036
|
+
* l'organisation ».
|
|
1037
|
+
*
|
|
1038
|
+
* `null` et `[]` ne sont pas la même chose : la liste vide n'ouvre rien, et
|
|
1039
|
+
* c'est délibéré — un tableau supprimé ne doit pas élargir une clé qui ne le
|
|
1040
|
+
* nommait plus que lui.
|
|
1041
|
+
*/
|
|
1042
|
+
boards: z20.array(z20.string().max(64)).max(200).nullable(),
|
|
1043
|
+
createdAt: z20.string().max(64),
|
|
1044
|
+
/** Dernier usage constaté, pour reconnaître une clé oubliée. */
|
|
1045
|
+
lastUsedAt: z20.string().max(64).nullable(),
|
|
1046
|
+
/** Qui l'a émise — une clé sans visage ne se révoque jamais sereinement. */
|
|
1047
|
+
createdBy: z20.object({ id: z20.string().max(128), name: z20.string().max(200) }),
|
|
1048
|
+
/** Les 4 derniers caractères du secret, pour reconnaître une clé dans une liste. */
|
|
1049
|
+
keyPreview: z20.string().max(8)
|
|
1050
|
+
});
|
|
1051
|
+
var CreatedCloudApiKeySchema = z20.object({
|
|
1052
|
+
key: CloudApiKeySchema,
|
|
1053
|
+
secret: CloudApiKeySecretSchema
|
|
1054
|
+
});
|
|
1055
|
+
var CreateCloudApiKeyInput = z20.object({
|
|
1056
|
+
organizationId: z20.string().min(1).max(128),
|
|
1057
|
+
name: z20.string().min(1).max(200),
|
|
1058
|
+
scopes: z20.array(CloudApiScopeSchema).min(1).max(10),
|
|
1059
|
+
boards: z20.array(z20.string().max(64)).max(200).nullable().default(null)
|
|
1060
|
+
});
|
|
1061
|
+
var UpdateCloudApiKeyInput = z20.object({
|
|
1062
|
+
id: z20.string().min(1).max(128),
|
|
1063
|
+
name: z20.string().min(1).max(200).optional(),
|
|
1064
|
+
scopes: z20.array(CloudApiScopeSchema).min(1).max(10).optional(),
|
|
1065
|
+
boards: z20.array(z20.string().max(64)).max(200).nullable().optional()
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
// ../../packages/shared/src/utils/crypto.ts
|
|
1069
|
+
import { createCipheriv, createDecipheriv, randomBytes, pbkdf2Sync } from "crypto";
|
|
1070
|
+
|
|
1071
|
+
// ../../packages/shared/src/js-log-parser.ts
|
|
1072
|
+
import vm from "vm";
|
|
1073
|
+
var VALID_LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error", "fatal"]);
|
|
1074
|
+
var PARSE_TIMEOUT_MS = 50;
|
|
1075
|
+
var MAX_CONSECUTIVE_TIMEOUTS = 10;
|
|
1076
|
+
var JSLogParser = class {
|
|
1077
|
+
parsers = [];
|
|
1078
|
+
constructor(definitions = []) {
|
|
1079
|
+
this.setParsers(definitions);
|
|
1080
|
+
}
|
|
1081
|
+
setParsers(definitions) {
|
|
1082
|
+
this.parsers = [];
|
|
1083
|
+
for (const def of definitions) {
|
|
1084
|
+
if (!def.enabled) continue;
|
|
1085
|
+
try {
|
|
1086
|
+
const compiled = this.compileParser(def);
|
|
1087
|
+
this.parsers.push({
|
|
1088
|
+
id: def.id,
|
|
1089
|
+
name: def.name,
|
|
1090
|
+
enabled: true,
|
|
1091
|
+
fn: compiled
|
|
1092
|
+
});
|
|
1093
|
+
} catch (err) {
|
|
1094
|
+
console.warn(
|
|
1095
|
+
`[js-log-parser] Failed to compile parser "${def.name}" (${def.id}): ${err instanceof Error ? err.message : String(err)}`
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
parse(line) {
|
|
1101
|
+
let current = line;
|
|
1102
|
+
for (const parser of this.parsers) {
|
|
1103
|
+
try {
|
|
1104
|
+
current = parser.fn(current);
|
|
1105
|
+
} catch (err) {
|
|
1106
|
+
console.warn(
|
|
1107
|
+
`[js-log-parser] Parser "${parser.name}" threw error: ${err instanceof Error ? err.message : String(err)}`
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
return this.sanitize(current);
|
|
1112
|
+
}
|
|
1113
|
+
/**
|
|
1114
|
+
* Compile le code utilisateur en une fonction bornée en temps.
|
|
1115
|
+
*
|
|
1116
|
+
* Le `timeout` de `runInNewContext` ne couvre que l'évaluation de la factory :
|
|
1117
|
+
* la closure retournée s'exécutait ensuite ligne par ligne directement sur
|
|
1118
|
+
* l'event loop, sans aucune borne. Une regex à backtracking exponentiel
|
|
1119
|
+
* fournie par l'utilisateur figeait donc l'agent entier — logs, statuts et
|
|
1120
|
+
* métriques de *tous* les services. Chaque invocation repasse maintenant par
|
|
1121
|
+
* la vm, avec son propre budget.
|
|
1122
|
+
*/
|
|
1123
|
+
compileParser(def) {
|
|
1124
|
+
const forbidden = ["require(", "import ", "eval("];
|
|
1125
|
+
for (const pat of forbidden) {
|
|
1126
|
+
if (def.code.includes(pat)) {
|
|
1127
|
+
throw new Error("Code contains forbidden patterns (require, import, eval)");
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
const sandbox = {
|
|
1131
|
+
RegExp,
|
|
1132
|
+
String,
|
|
1133
|
+
Object,
|
|
1134
|
+
Array,
|
|
1135
|
+
JSON,
|
|
1136
|
+
Math,
|
|
1137
|
+
Date,
|
|
1138
|
+
undefined: void 0,
|
|
1139
|
+
null: null
|
|
1140
|
+
};
|
|
1141
|
+
let script;
|
|
1142
|
+
try {
|
|
1143
|
+
script = new vm.Script(`(${def.code})`, { filename: `parser-${def.id}.js` });
|
|
1144
|
+
} catch (err) {
|
|
1145
|
+
throw new Error(`Compilation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1146
|
+
}
|
|
1147
|
+
const context = vm.createContext({ ...sandbox, __line: null, __result: null });
|
|
1148
|
+
let parserFn;
|
|
1149
|
+
try {
|
|
1150
|
+
parserFn = script.runInContext(context, { timeout: 100 });
|
|
1151
|
+
} catch (err) {
|
|
1152
|
+
throw new Error(`Execution failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1153
|
+
}
|
|
1154
|
+
if (typeof parserFn !== "function") {
|
|
1155
|
+
throw new Error("Parser code must export a function");
|
|
1156
|
+
}
|
|
1157
|
+
context["__parserFn"] = parserFn;
|
|
1158
|
+
const callScript = new vm.Script("__result = __parserFn(__line);", {
|
|
1159
|
+
filename: `parser-${def.id}-call.js`
|
|
1160
|
+
});
|
|
1161
|
+
let consecutiveTimeouts = 0;
|
|
1162
|
+
let disabled = false;
|
|
1163
|
+
return (line) => {
|
|
1164
|
+
if (disabled) return line;
|
|
1165
|
+
const ctx = context;
|
|
1166
|
+
ctx["__line"] = line;
|
|
1167
|
+
ctx["__result"] = null;
|
|
1168
|
+
try {
|
|
1169
|
+
callScript.runInContext(context, { timeout: PARSE_TIMEOUT_MS });
|
|
1170
|
+
consecutiveTimeouts = 0;
|
|
1171
|
+
} catch (err) {
|
|
1172
|
+
const e = err;
|
|
1173
|
+
const timedOut = !!e && (e.code === "ERR_SCRIPT_EXECUTION_TIMEOUT" || typeof e.message === "string" && /execution timed out/i.test(e.message));
|
|
1174
|
+
if (!timedOut) throw err;
|
|
1175
|
+
consecutiveTimeouts += 1;
|
|
1176
|
+
if (consecutiveTimeouts >= MAX_CONSECUTIVE_TIMEOUTS) {
|
|
1177
|
+
disabled = true;
|
|
1178
|
+
console.warn(
|
|
1179
|
+
`[js-log-parser] Parser "${def.name}" (${def.id}) disabled after ${MAX_CONSECUTIVE_TIMEOUTS} consecutive timeouts`
|
|
1180
|
+
);
|
|
1181
|
+
}
|
|
1182
|
+
return line;
|
|
1183
|
+
}
|
|
1184
|
+
const result = ctx["__result"];
|
|
1185
|
+
if (result === null || result === void 0 || typeof result !== "object") {
|
|
1186
|
+
return line;
|
|
1187
|
+
}
|
|
1188
|
+
return result;
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
/** Sanitize the final LogLine: truncate message, limit metadata, validate level */
|
|
1192
|
+
sanitize(line) {
|
|
1193
|
+
let { message, metadata, level } = line;
|
|
1194
|
+
if (message.length > 16384) {
|
|
1195
|
+
message = message.substring(0, 16384) + "...[truncated]";
|
|
1196
|
+
}
|
|
1197
|
+
metadata = metadata ?? {};
|
|
1198
|
+
const metaKeys = Object.keys(metadata);
|
|
1199
|
+
if (metaKeys.length > 100) {
|
|
1200
|
+
const limited = {};
|
|
1201
|
+
for (let i = 0; i < 100; i++) {
|
|
1202
|
+
limited[metaKeys[i]] = metadata[metaKeys[i]];
|
|
1203
|
+
}
|
|
1204
|
+
metadata = limited;
|
|
1205
|
+
}
|
|
1206
|
+
if (!VALID_LEVELS.has(level)) {
|
|
1207
|
+
level = "info";
|
|
1208
|
+
}
|
|
1209
|
+
if (message !== line.message || metadata !== line.metadata || level !== line.level) {
|
|
1210
|
+
return { ...line, message, metadata, level };
|
|
1211
|
+
}
|
|
1212
|
+
return line;
|
|
1213
|
+
}
|
|
1214
|
+
};
|
|
1215
|
+
|
|
1216
|
+
// ../../packages/shared/src/builtins.ts
|
|
1217
|
+
var BUILTIN_VARIABLES = [
|
|
1218
|
+
// ── Le service ───────────────────────────────────────────────────────────
|
|
1219
|
+
{ name: "service.NAME", scope: "server", descriptionKey: "serviceName" },
|
|
1220
|
+
{ name: "service.ID", scope: "server", descriptionKey: "serviceId" },
|
|
1221
|
+
{ name: "service.PORT", scope: "server", descriptionKey: "servicePort" },
|
|
1222
|
+
{ name: "service.URL", scope: "server", descriptionKey: "serviceUrl" },
|
|
1223
|
+
{ name: "service.BASE_URL", scope: "server", descriptionKey: "serviceBaseUrl" },
|
|
1224
|
+
{ name: "service.CWD", scope: "agent", descriptionKey: "serviceCwd" },
|
|
1225
|
+
// ── Le projet et l'environnement actif ───────────────────────────────────
|
|
1226
|
+
{ name: "project.NAME", scope: "server", descriptionKey: "projectName" },
|
|
1227
|
+
{ name: "runeya.ENV_NAME", scope: "server", descriptionKey: "envName" },
|
|
1228
|
+
// ── Le serveur Runeya ────────────────────────────────────────────────────
|
|
1229
|
+
// `service.HOST` a toujours désigné l'adresse d'écoute du SERVEUR, pas une
|
|
1230
|
+
// propriété du service : le nom trompait, il devient un alias.
|
|
1231
|
+
{ name: "runeya.HOST", scope: "server", descriptionKey: "runeyaHost", deprecatedAlias: "service.HOST" },
|
|
1232
|
+
// ── La machine qui exécute ───────────────────────────────────────────────
|
|
1233
|
+
{ name: "agent.HOST_LAN", scope: "agent", descriptionKey: "agentHostLan", deprecatedAlias: "service.HOST_LAN" },
|
|
1234
|
+
// Le NOM de l'agent est une étiquette de la configuration du serveur, pas
|
|
1235
|
+
// une propriété de la machine : c'est le serveur qui le connaît et le résout.
|
|
1236
|
+
{ name: "agent.NAME", scope: "server", descriptionKey: "agentName" },
|
|
1237
|
+
{ name: "agent.OS", scope: "agent", descriptionKey: "agentOs" },
|
|
1238
|
+
{ name: "agent.HOME", scope: "agent", descriptionKey: "agentHome" }
|
|
1239
|
+
];
|
|
1240
|
+
var BUILTIN_REFERENCE_RE = /\{\{([A-Za-z][A-Za-z0-9_.-]*)\}\}/g;
|
|
1241
|
+
var ENVIRONMENT_NAMESPACE = "environment.";
|
|
1242
|
+
function interpolateBuiltins(text, values) {
|
|
1243
|
+
return text.replace(BUILTIN_REFERENCE_RE, (match, name) => {
|
|
1244
|
+
if (name.startsWith(ENVIRONMENT_NAMESPACE)) return match;
|
|
1245
|
+
return values[name] ?? match;
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
function interpolateBuiltinsInEnv(env2, values) {
|
|
1249
|
+
const out = {};
|
|
1250
|
+
for (const [key, value] of Object.entries(env2)) {
|
|
1251
|
+
out[key] = interpolateBuiltins(value, values);
|
|
1252
|
+
}
|
|
1253
|
+
return out;
|
|
1254
|
+
}
|
|
1255
|
+
function withDeprecatedAliases(values) {
|
|
1256
|
+
const out = { ...values };
|
|
1257
|
+
for (const builtin of BUILTIN_VARIABLES) {
|
|
1258
|
+
if (builtin.deprecatedAlias && out[builtin.name] !== void 0) {
|
|
1259
|
+
out[builtin.deprecatedAlias] = out[builtin.name];
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
return out;
|
|
1263
|
+
}
|
|
1766
1264
|
|
|
1767
|
-
// ../../packages/shared/src/
|
|
1768
|
-
|
|
1265
|
+
// ../../packages/shared/src/constants/intervals.ts
|
|
1266
|
+
var HEALTH_CHECK_INTERVAL = 3e4;
|
|
1267
|
+
var METRICS_INTERVAL = 5e3;
|
|
1268
|
+
var HEALTH_CHECK_INITIAL_DELAY = 5e3;
|
|
1269
|
+
var HEALTH_WS_INTERVAL = 1e4;
|
|
1270
|
+
|
|
1271
|
+
// ../../packages/shared/src/constants/buffers.ts
|
|
1272
|
+
var LOG_BUFFER_SIZE = 5e3;
|
|
1273
|
+
|
|
1274
|
+
// ../../packages/shared/src/constants/timeouts.ts
|
|
1275
|
+
var GRACE_PERIOD = 1e4;
|
|
1276
|
+
var AGENT_STOP_FETCH_TIMEOUT = GRACE_PERIOD + 15e3;
|
|
1277
|
+
|
|
1278
|
+
// ../../packages/shared/src/constants/editors.ts
|
|
1279
|
+
var SUPPORTED_EDITORS = [
|
|
1280
|
+
{ key: "vscode", name: "Visual Studio Code", command: "code" },
|
|
1281
|
+
{ key: "cursor", name: "Cursor", command: "cursor" },
|
|
1282
|
+
{ key: "windsurf", name: "Windsurf", command: "windsurf" },
|
|
1283
|
+
{ key: "sublime", name: "Sublime Text", command: "subl" },
|
|
1284
|
+
{ key: "atom", name: "Atom", command: "atom" },
|
|
1285
|
+
{ key: "antigravity", name: "Antigravity", command: "antigravity" },
|
|
1286
|
+
{ key: "intellij", name: "IntelliJ IDEA", command: "idea" },
|
|
1287
|
+
{ key: "android-studio", name: "Android Studio", command: "studio" },
|
|
1288
|
+
{ key: "webstorm", name: "WebStorm", command: "webstorm" },
|
|
1289
|
+
{ key: "zed", name: "Zed", command: "zed" },
|
|
1290
|
+
{ key: "neovim", name: "Neovim", command: "nvim" },
|
|
1291
|
+
{ key: "vim", name: "Vim", command: "vim" },
|
|
1292
|
+
{ key: "emacs", name: "Emacs", command: "emacs" },
|
|
1293
|
+
{ key: "fleet", name: "Fleet", command: "fleet" }
|
|
1294
|
+
];
|
|
1295
|
+
var EDITOR_BY_KEY = new Map(
|
|
1296
|
+
SUPPORTED_EDITORS.map((e) => [e.key, e])
|
|
1297
|
+
);
|
|
1298
|
+
|
|
1299
|
+
// ../../packages/shared/src/sync/json-crdt.ts
|
|
1300
|
+
import * as Y from "yjs";
|
|
1301
|
+
|
|
1302
|
+
// ../../packages/runner-native/src/native-runner.ts
|
|
1303
|
+
import { execa } from "execa";
|
|
1304
|
+
import { execSync } from "child_process";
|
|
1305
|
+
import { homedir } from "os";
|
|
1306
|
+
|
|
1307
|
+
// ../../node_modules/shellwords/dist/esm/index.js
|
|
1308
|
+
var scan = (string, pattern, callback) => {
|
|
1309
|
+
let result = "";
|
|
1310
|
+
while (string.length > 0) {
|
|
1311
|
+
const match = string.match(pattern);
|
|
1312
|
+
if (match && match.index != null && match[0] != null) {
|
|
1313
|
+
result += string.slice(0, match.index);
|
|
1314
|
+
result += callback(match);
|
|
1315
|
+
string = string.slice(match.index + match[0].length);
|
|
1316
|
+
} else {
|
|
1317
|
+
result += string;
|
|
1318
|
+
string = "";
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
return result;
|
|
1322
|
+
};
|
|
1323
|
+
var split = (line = "") => {
|
|
1324
|
+
const words = [];
|
|
1325
|
+
let field = "";
|
|
1326
|
+
scan(
|
|
1327
|
+
line,
|
|
1328
|
+
/\s*(?:([^\s\\'"]+)|'((?:[^'\\]|\\.)*)'|"((?:[^"\\]|\\.)*)"|(\\.?)|(\S))(\s|$)?/,
|
|
1329
|
+
(match) => {
|
|
1330
|
+
const [_raw, word, sq, dq, escape2, garbage, separator] = match;
|
|
1331
|
+
if (garbage != null) {
|
|
1332
|
+
throw new Error(`Unmatched quote: ${line}`);
|
|
1333
|
+
}
|
|
1334
|
+
if (word) {
|
|
1335
|
+
field += word;
|
|
1336
|
+
} else {
|
|
1337
|
+
let addition;
|
|
1338
|
+
if (sq) {
|
|
1339
|
+
addition = sq;
|
|
1340
|
+
} else if (dq) {
|
|
1341
|
+
addition = dq;
|
|
1342
|
+
} else if (escape2) {
|
|
1343
|
+
addition = escape2;
|
|
1344
|
+
}
|
|
1345
|
+
if (addition) {
|
|
1346
|
+
field += addition.replace(/\\(?=.)/, "");
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
if (separator != null) {
|
|
1350
|
+
words.push(field);
|
|
1351
|
+
field = "";
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
);
|
|
1355
|
+
if (field) {
|
|
1356
|
+
words.push(field);
|
|
1357
|
+
}
|
|
1358
|
+
return words;
|
|
1359
|
+
};
|
|
1360
|
+
|
|
1361
|
+
// ../../packages/runner-native/src/native-runner.ts
|
|
1362
|
+
var shellwordsSplit = split;
|
|
1363
|
+
function expandEnvVars(str, serviceEnv) {
|
|
1364
|
+
const withHome = str.replace(/^~(\/|$)/, `${homedir()}$1`);
|
|
1365
|
+
return withHome.replace(/\$\{(\w+)\}|\$(\w+)/g, (_, braced, plain) => {
|
|
1366
|
+
const name = braced ?? plain;
|
|
1367
|
+
return serviceEnv?.[name] ?? "";
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
function resolveCwd(cwd, env2) {
|
|
1371
|
+
if (!cwd) return ".";
|
|
1372
|
+
return expandEnvVars(cwd, env2) || ".";
|
|
1373
|
+
}
|
|
1374
|
+
function findUnresolvedEnvVars(str, serviceEnv) {
|
|
1375
|
+
const unresolved = [];
|
|
1376
|
+
str.replace(/\$\{(\w+)\}|\$(\w+)/g, (_, braced, plain) => {
|
|
1377
|
+
const name = braced ?? plain;
|
|
1378
|
+
if (serviceEnv?.[name] === void 0) {
|
|
1379
|
+
unresolved.push(name);
|
|
1380
|
+
}
|
|
1381
|
+
return "";
|
|
1382
|
+
});
|
|
1383
|
+
return unresolved;
|
|
1384
|
+
}
|
|
1385
|
+
var SYSTEM_PATH_DIRS = ["/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", "/sbin", "/bin"];
|
|
1386
|
+
function buildSafeEnv(configEnv = {}) {
|
|
1387
|
+
const safeKeys = ["PATH", "HOME", "USER", "SHELL", "LANG", "TERM", "NODE_ENV", "TMPDIR", "TZ", "DBUS_SESSION_BUS_ADDRESS", "XDG_RUNTIME_DIR"];
|
|
1388
|
+
const env2 = {};
|
|
1389
|
+
for (const key of safeKeys) {
|
|
1390
|
+
if (process.env[key]) {
|
|
1391
|
+
env2[key] = process.env[key];
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
const existingPath = env2["PATH"] ?? "";
|
|
1395
|
+
const existingDirs = new Set(existingPath.split(":").filter(Boolean));
|
|
1396
|
+
const missingDirs = SYSTEM_PATH_DIRS.filter((d) => !existingDirs.has(d));
|
|
1397
|
+
if (missingDirs.length > 0) {
|
|
1398
|
+
env2["PATH"] = [existingPath, ...missingDirs].filter(Boolean).join(":");
|
|
1399
|
+
}
|
|
1400
|
+
return { ...env2, ...configEnv };
|
|
1401
|
+
}
|
|
1402
|
+
var NativeRunner = class {
|
|
1403
|
+
type = "native";
|
|
1404
|
+
start(config) {
|
|
1405
|
+
let subprocess;
|
|
1406
|
+
const cwd = resolveCwd(config.cwd, config.env);
|
|
1407
|
+
const isWindows = process.platform === "win32";
|
|
1408
|
+
if (config.shell) {
|
|
1409
|
+
subprocess = execa(config.command, {
|
|
1410
|
+
cwd,
|
|
1411
|
+
env: buildSafeEnv(config.env),
|
|
1412
|
+
shell: true,
|
|
1413
|
+
detached: !isWindows,
|
|
1414
|
+
// Create new process group for group kill (not supported on Windows)
|
|
1415
|
+
windowsHide: true,
|
|
1416
|
+
// Prevent terminal windows from appearing on Windows
|
|
1417
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1418
|
+
reject: false,
|
|
1419
|
+
// Don't throw on non-zero exit
|
|
1420
|
+
buffer: false
|
|
1421
|
+
// Don't accumulate stdout/stderr in memory — we stream via readline
|
|
1422
|
+
});
|
|
1423
|
+
} else {
|
|
1424
|
+
const args = shellwordsSplit(config.command);
|
|
1425
|
+
const cmd = args.shift();
|
|
1426
|
+
if (!cmd) {
|
|
1427
|
+
throw new Error("Invalid command: cannot parse empty or whitespace-only command");
|
|
1428
|
+
}
|
|
1429
|
+
subprocess = execa(cmd, args, {
|
|
1430
|
+
cwd,
|
|
1431
|
+
env: buildSafeEnv(config.env),
|
|
1432
|
+
shell: false,
|
|
1433
|
+
// SECURITY: shell:false prevents command injection
|
|
1434
|
+
detached: !isWindows,
|
|
1435
|
+
// Create new process group for group kill (not supported on Windows)
|
|
1436
|
+
windowsHide: true,
|
|
1437
|
+
// Prevent terminal windows from appearing on Windows
|
|
1438
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1439
|
+
reject: false,
|
|
1440
|
+
// Don't throw on non-zero exit
|
|
1441
|
+
buffer: false
|
|
1442
|
+
// Don't accumulate stdout/stderr in memory — we stream via readline
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
const exitPromise = new Promise((resolve2) => {
|
|
1446
|
+
subprocess.then((result) => {
|
|
1447
|
+
resolve2({
|
|
1448
|
+
exitCode: result.exitCode ?? null,
|
|
1449
|
+
signal: result.signal ?? null,
|
|
1450
|
+
error: result.failed && result.shortMessage ? result.shortMessage : void 0
|
|
1451
|
+
});
|
|
1452
|
+
}).catch((err) => {
|
|
1453
|
+
resolve2({ exitCode: 1, signal: null, error: err.message ?? "Unknown error" });
|
|
1454
|
+
});
|
|
1455
|
+
});
|
|
1456
|
+
return {
|
|
1457
|
+
pid: subprocess.pid,
|
|
1458
|
+
kill(signal = "SIGTERM") {
|
|
1459
|
+
try {
|
|
1460
|
+
if (process.platform === "win32") {
|
|
1461
|
+
if (!subprocess.pid) return false;
|
|
1462
|
+
execSync(`taskkill /F /T /PID ${subprocess.pid}`, { stdio: "ignore" });
|
|
1463
|
+
return true;
|
|
1464
|
+
}
|
|
1465
|
+
if (subprocess.pid) {
|
|
1466
|
+
process.kill(-subprocess.pid, signal);
|
|
1467
|
+
return true;
|
|
1468
|
+
}
|
|
1469
|
+
return subprocess.kill(signal);
|
|
1470
|
+
} catch {
|
|
1471
|
+
return false;
|
|
1472
|
+
}
|
|
1473
|
+
},
|
|
1474
|
+
stdout: subprocess.stdout,
|
|
1475
|
+
stderr: subprocess.stderr,
|
|
1476
|
+
exitPromise
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
async isAvailable() {
|
|
1480
|
+
return true;
|
|
1481
|
+
}
|
|
1482
|
+
};
|
|
1769
1483
|
|
|
1770
|
-
// ../../packages/
|
|
1771
|
-
import
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1484
|
+
// ../../packages/runner-docker/src/index.ts
|
|
1485
|
+
import { execa as execa2 } from "execa";
|
|
1486
|
+
import { PassThrough } from "stream";
|
|
1487
|
+
import { randomUUID } from "crypto";
|
|
1488
|
+
import { writeFile, unlink, mkdir } from "fs/promises";
|
|
1489
|
+
import { tmpdir, homedir as homedir2, userInfo } from "os";
|
|
1490
|
+
import { join } from "path";
|
|
1491
|
+
function splitShellArgs(cmd) {
|
|
1492
|
+
const args = [];
|
|
1493
|
+
let current = "";
|
|
1494
|
+
let inSingle = false;
|
|
1495
|
+
let inDouble = false;
|
|
1496
|
+
for (let i = 0; i < cmd.length; i++) {
|
|
1497
|
+
const ch = cmd[i];
|
|
1498
|
+
if (ch === "'" && !inDouble) {
|
|
1499
|
+
inSingle = !inSingle;
|
|
1500
|
+
} else if (ch === '"' && !inSingle) {
|
|
1501
|
+
inDouble = !inDouble;
|
|
1502
|
+
} else if (ch === "\\" && inDouble && i + 1 < cmd.length) {
|
|
1503
|
+
current += cmd[++i];
|
|
1504
|
+
} else if (/\s/.test(ch) && !inSingle && !inDouble) {
|
|
1505
|
+
if (current) {
|
|
1506
|
+
args.push(current);
|
|
1507
|
+
current = "";
|
|
1508
|
+
}
|
|
1509
|
+
} else {
|
|
1510
|
+
current += ch;
|
|
1511
|
+
}
|
|
1779
1512
|
}
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1513
|
+
if (current) args.push(current);
|
|
1514
|
+
return args;
|
|
1515
|
+
}
|
|
1516
|
+
function sanitizeDockerName(name) {
|
|
1517
|
+
return name.toLowerCase().replace(/[^a-z0-9._-]/g, "-").replace(/-{2,}/g, "-");
|
|
1518
|
+
}
|
|
1519
|
+
function expandEnvVars2(str, serviceEnv) {
|
|
1520
|
+
const withHome = str.replace(/^~(\/|$)/, `${homedir2()}$1`);
|
|
1521
|
+
return withHome.replace(/\$\{(\w+)\}|\$(\w+)/g, (_, braced, plain) => {
|
|
1522
|
+
const name = braced ?? plain;
|
|
1523
|
+
return serviceEnv?.[name] ?? "";
|
|
1524
|
+
});
|
|
1525
|
+
}
|
|
1526
|
+
async function preMkdirVolumes(volumes, serviceEnv) {
|
|
1527
|
+
for (const v of volumes) {
|
|
1528
|
+
const expanded = expandEnvVars2(v, serviceEnv);
|
|
1529
|
+
const parts = expanded.split(":");
|
|
1530
|
+
if (parts.length < 2) continue;
|
|
1531
|
+
const hostPath = parts[0];
|
|
1532
|
+
if (!hostPath.startsWith("/") && !hostPath.startsWith(".")) continue;
|
|
1533
|
+
await mkdir(hostPath, { recursive: true }).catch(() => {
|
|
1534
|
+
});
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
var DockerRunner = class {
|
|
1538
|
+
type = "docker";
|
|
1539
|
+
start(config) {
|
|
1540
|
+
const stdout = new PassThrough();
|
|
1541
|
+
const stderr = new PassThrough();
|
|
1542
|
+
const containerName = sanitizeDockerName(config.cmdId ? `runeya-${config.serviceId}-${config.cmdId}` : `runeya-${config.serviceId}`);
|
|
1543
|
+
let killed = false;
|
|
1544
|
+
const exitPromise = new Promise(
|
|
1545
|
+
(resolve2) => {
|
|
1546
|
+
void (async () => {
|
|
1547
|
+
try {
|
|
1548
|
+
await execa2("docker", ["rm", "-f", containerName], { reject: false });
|
|
1549
|
+
const dc = config.dockerConfig;
|
|
1550
|
+
let lastCardId = null;
|
|
1551
|
+
const envFlags = Object.entries(config.env ?? {}).flatMap(
|
|
1552
|
+
([k, v]) => ["-e", `${k}=${v}`]
|
|
1553
|
+
);
|
|
1554
|
+
await preMkdirVolumes(dc.volumes ?? [], config.env);
|
|
1555
|
+
const volumeFlags = (dc.volumes ?? []).flatMap((v) => ["-v", expandEnvVars2(v, config.env)]);
|
|
1556
|
+
if (dc.mountRootpath && config.cwd) {
|
|
1557
|
+
volumeFlags.push("-v", `${config.cwd}:${config.cwd}`);
|
|
1558
|
+
}
|
|
1559
|
+
if (dc.image && !dc.dockerfile) {
|
|
1560
|
+
lastCardId = randomUUID();
|
|
1561
|
+
stdout.write(
|
|
1562
|
+
"\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "pull", _cardId: lastCardId, _cardState: "open", message: `--- Docker Pull: ${dc.image} ---` }) + "\n"
|
|
1563
|
+
);
|
|
1564
|
+
const pull = execa2("docker", ["pull", dc.image], { reject: false });
|
|
1565
|
+
pull.stdout?.pipe(stdout, { end: false });
|
|
1566
|
+
pull.stderr?.pipe(stderr, { end: false });
|
|
1567
|
+
await pull;
|
|
1568
|
+
}
|
|
1569
|
+
let imageName = dc.image ?? containerName + ":latest";
|
|
1570
|
+
if (dc.dockerfile) {
|
|
1571
|
+
lastCardId = randomUUID();
|
|
1572
|
+
stdout.write(
|
|
1573
|
+
"\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "build", _cardId: lastCardId, _cardState: "open", message: "--- Docker Build ---" }) + "\n"
|
|
1574
|
+
);
|
|
1575
|
+
const tmpFile = join(tmpdir(), `runeya-${config.serviceId}-${randomUUID()}.dockerfile`);
|
|
1576
|
+
try {
|
|
1577
|
+
await writeFile(tmpFile, dc.dockerfile, "utf8");
|
|
1578
|
+
const buildArgs = Object.entries(dc.buildArgs ?? {}).flatMap(
|
|
1579
|
+
([k, v]) => ["--build-arg", `${k}=${v}`]
|
|
1580
|
+
);
|
|
1581
|
+
const targetArgs = dc.targetStage ? ["--target", dc.targetStage] : [];
|
|
1582
|
+
const buildContext = dc.buildContext ?? config.cwd ?? ".";
|
|
1583
|
+
imageName = `${containerName}:latest`;
|
|
1584
|
+
const build = execa2(
|
|
1585
|
+
"docker",
|
|
1586
|
+
["build", "-f", tmpFile, "-t", imageName, ...buildArgs, ...targetArgs, buildContext],
|
|
1587
|
+
{ reject: false }
|
|
1588
|
+
);
|
|
1589
|
+
build.stdout?.pipe(stdout, { end: false });
|
|
1590
|
+
build.stderr?.pipe(stderr, { end: false });
|
|
1591
|
+
await build;
|
|
1592
|
+
} finally {
|
|
1593
|
+
await unlink(tmpFile).catch(() => {
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
if (killed) {
|
|
1598
|
+
resolve2({ exitCode: null, signal: "SIGTERM" });
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
if (lastCardId) {
|
|
1602
|
+
stdout.write(
|
|
1603
|
+
"\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "close", _cardId: lastCardId, _cardState: "close" }) + "\n"
|
|
1604
|
+
);
|
|
1605
|
+
}
|
|
1606
|
+
const bootstrapCmds = config.skipBootstrap ? [] : (dc.bootstrapCommands ?? []).filter((c) => c.command.trim());
|
|
1607
|
+
for (const bsCmd of bootstrapCmds) {
|
|
1608
|
+
if (killed) {
|
|
1609
|
+
resolve2({ exitCode: null, signal: "SIGTERM" });
|
|
1610
|
+
return;
|
|
1611
|
+
}
|
|
1612
|
+
const bsCardId = randomUUID();
|
|
1613
|
+
const bsCmdName = bsCmd.label || bsCmd.command;
|
|
1614
|
+
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "bootstrap", _cardId: bsCardId, _cardState: "open", message: `Bootstrap: ${bsCmdName}` })}
|
|
1615
|
+
`);
|
|
1616
|
+
const exitCode = await this.runBootstrap(bsCmd, imageName, config.env ?? {}, dc.volumes ?? [], stdout, stderr);
|
|
1617
|
+
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: bsCardId, _cardState: "close" })}
|
|
1618
|
+
`);
|
|
1619
|
+
if (exitCode !== 0) {
|
|
1620
|
+
stderr.write(`Bootstrap command "${bsCmdName}" failed with exit code ${exitCode}
|
|
1621
|
+
`);
|
|
1622
|
+
resolve2({ exitCode, signal: null, error: `Bootstrap "${bsCmdName}" failed (exit ${exitCode})` });
|
|
1623
|
+
return;
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
if (killed) {
|
|
1627
|
+
resolve2({ exitCode: null, signal: "SIGTERM" });
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
const networkFlags = dc.networkMode === "host" ? ["--network", "host"] : (dc.ports ?? []).flatMap((p) => ["-p", p]);
|
|
1631
|
+
let cmdArgs;
|
|
1632
|
+
let entrypointFlags;
|
|
1633
|
+
if (dc.useNativeCommand) {
|
|
1634
|
+
const shell = dc.nativeShell || "sh";
|
|
1635
|
+
entrypointFlags = [];
|
|
1636
|
+
cmdArgs = config.command ? [shell, "-c", config.command] : [];
|
|
1637
|
+
} else {
|
|
1638
|
+
entrypointFlags = dc.entrypoint ? ["--entrypoint", dc.entrypoint] : [];
|
|
1639
|
+
cmdArgs = dc.command ? splitShellArgs(dc.command) : [];
|
|
1640
|
+
}
|
|
1641
|
+
const { uid, gid } = userInfo();
|
|
1642
|
+
const rmFlag = config.rm ? ["--rm"] : [];
|
|
1643
|
+
const runArgs = [
|
|
1644
|
+
"run",
|
|
1645
|
+
...rmFlag,
|
|
1646
|
+
"--init",
|
|
1647
|
+
"--name",
|
|
1648
|
+
containerName,
|
|
1649
|
+
"--user",
|
|
1650
|
+
dc.user || `${uid}:${gid}`,
|
|
1651
|
+
...networkFlags,
|
|
1652
|
+
...envFlags,
|
|
1653
|
+
...volumeFlags,
|
|
1654
|
+
...entrypointFlags,
|
|
1655
|
+
imageName,
|
|
1656
|
+
...cmdArgs
|
|
1657
|
+
];
|
|
1658
|
+
const debugCardId = randomUUID();
|
|
1659
|
+
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "run", _cardId: debugCardId, _cardState: "open", message: "Docker Run" })}
|
|
1660
|
+
`);
|
|
1661
|
+
stdout.write(`docker ${runArgs.join(" ")}
|
|
1662
|
+
`);
|
|
1663
|
+
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: debugCardId, _cardState: "close" })}
|
|
1664
|
+
`);
|
|
1665
|
+
const runProc = execa2("docker", runArgs, { reject: false });
|
|
1666
|
+
runProc.stdout?.pipe(stdout, { end: false });
|
|
1667
|
+
runProc.stderr?.pipe(stderr, { end: false });
|
|
1668
|
+
const result = await runProc;
|
|
1669
|
+
resolve2({ exitCode: result.exitCode ?? null, signal: result.signal ?? null });
|
|
1670
|
+
} catch (err) {
|
|
1671
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1672
|
+
stderr.write(`Docker infrastructure error: ${msg}
|
|
1673
|
+
`);
|
|
1674
|
+
resolve2({ exitCode: 1, signal: null });
|
|
1675
|
+
} finally {
|
|
1676
|
+
stdout.end();
|
|
1677
|
+
stderr.end();
|
|
1678
|
+
}
|
|
1679
|
+
})();
|
|
1680
|
+
}
|
|
1681
|
+
);
|
|
1682
|
+
return {
|
|
1683
|
+
pid: void 0,
|
|
1684
|
+
containerName,
|
|
1685
|
+
stdout,
|
|
1686
|
+
stderr,
|
|
1687
|
+
exitPromise,
|
|
1688
|
+
kill(_signal = "SIGTERM") {
|
|
1689
|
+
killed = true;
|
|
1690
|
+
execa2("docker", ["stop", containerName]).catch(() => {
|
|
1791
1691
|
});
|
|
1792
|
-
|
|
1793
|
-
console.warn(
|
|
1794
|
-
`[js-log-parser] Failed to compile parser "${def.name}" (${def.id}): ${err instanceof Error ? err.message : String(err)}`
|
|
1795
|
-
);
|
|
1692
|
+
return true;
|
|
1796
1693
|
}
|
|
1797
|
-
}
|
|
1694
|
+
};
|
|
1798
1695
|
}
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1696
|
+
/** Start a long-lived container (sleep infinity) for shared mode.
|
|
1697
|
+
* Returns the RunnerProcess (lifetime) plus a `containerReady` promise that resolves
|
|
1698
|
+
* once `docker run --detach` has completed and the container is confirmed running.
|
|
1699
|
+
* Callers must await `containerReady` before calling `execInContainer`. */
|
|
1700
|
+
startSharedContainer(config) {
|
|
1701
|
+
const stdout = new PassThrough();
|
|
1702
|
+
const stderr = new PassThrough();
|
|
1703
|
+
const containerName = sanitizeDockerName(`runeya-${config.serviceId}`);
|
|
1704
|
+
let killed = false;
|
|
1705
|
+
let resolveReady;
|
|
1706
|
+
let rejectReady;
|
|
1707
|
+
const containerReady = new Promise((res, rej) => {
|
|
1708
|
+
resolveReady = res;
|
|
1709
|
+
rejectReady = rej;
|
|
1710
|
+
});
|
|
1711
|
+
let exitResolve;
|
|
1712
|
+
const exitPromise = new Promise(
|
|
1713
|
+
(resolve2) => {
|
|
1714
|
+
exitResolve = resolve2;
|
|
1715
|
+
}
|
|
1716
|
+
);
|
|
1717
|
+
void (async () => {
|
|
1802
1718
|
try {
|
|
1803
|
-
|
|
1719
|
+
await execa2("docker", ["rm", "-f", containerName], { reject: false });
|
|
1720
|
+
const dc = config.dockerConfig;
|
|
1721
|
+
let lastCardId = null;
|
|
1722
|
+
const envFlags = Object.entries(config.env ?? {}).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
|
|
1723
|
+
await preMkdirVolumes(dc.volumes ?? [], config.env);
|
|
1724
|
+
const volumeFlags = (dc.volumes ?? []).flatMap((v) => ["-v", expandEnvVars2(v, config.env)]);
|
|
1725
|
+
if (dc.mountRootpath && config.cwd) {
|
|
1726
|
+
volumeFlags.push("-v", `${config.cwd}:${config.cwd}`);
|
|
1727
|
+
}
|
|
1728
|
+
if (dc.image && !dc.dockerfile) {
|
|
1729
|
+
lastCardId = randomUUID();
|
|
1730
|
+
stdout.write("\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "pull", _cardId: lastCardId, _cardState: "open", message: `--- Docker Pull: ${dc.image} ---` }) + "\n");
|
|
1731
|
+
const pull = execa2("docker", ["pull", dc.image], { reject: false });
|
|
1732
|
+
pull.stdout?.pipe(stdout, { end: false });
|
|
1733
|
+
pull.stderr?.pipe(stderr, { end: false });
|
|
1734
|
+
await pull;
|
|
1735
|
+
}
|
|
1736
|
+
let imageName = dc.image ?? containerName + ":latest";
|
|
1737
|
+
if (dc.dockerfile) {
|
|
1738
|
+
lastCardId = randomUUID();
|
|
1739
|
+
stdout.write("\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "build", _cardId: lastCardId, _cardState: "open", message: "--- Docker Build ---" }) + "\n");
|
|
1740
|
+
const tmpFile = join(tmpdir(), `runeya-${config.serviceId}-${randomUUID()}.dockerfile`);
|
|
1741
|
+
try {
|
|
1742
|
+
await writeFile(tmpFile, dc.dockerfile, "utf8");
|
|
1743
|
+
const buildArgs = Object.entries(dc.buildArgs ?? {}).flatMap(([k, v]) => ["--build-arg", `${k}=${v}`]);
|
|
1744
|
+
const targetArgs = dc.targetStage ? ["--target", dc.targetStage] : [];
|
|
1745
|
+
const buildContext = dc.buildContext ?? config.cwd ?? ".";
|
|
1746
|
+
imageName = `${containerName}:latest`;
|
|
1747
|
+
const build = execa2("docker", ["build", "-f", tmpFile, "-t", imageName, ...buildArgs, ...targetArgs, buildContext], { reject: false });
|
|
1748
|
+
build.stdout?.pipe(stdout, { end: false });
|
|
1749
|
+
build.stderr?.pipe(stderr, { end: false });
|
|
1750
|
+
await build;
|
|
1751
|
+
} finally {
|
|
1752
|
+
await unlink(tmpFile).catch(() => {
|
|
1753
|
+
});
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
if (killed) {
|
|
1757
|
+
rejectReady(new Error("Killed before container started"));
|
|
1758
|
+
exitResolve({ exitCode: null, signal: "SIGTERM" });
|
|
1759
|
+
return;
|
|
1760
|
+
}
|
|
1761
|
+
if (lastCardId) {
|
|
1762
|
+
stdout.write("\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "close", _cardId: lastCardId, _cardState: "close" }) + "\n");
|
|
1763
|
+
}
|
|
1764
|
+
const networkFlags = dc.networkMode === "host" ? ["--network", "host"] : (dc.ports ?? []).flatMap((p) => ["-p", p]);
|
|
1765
|
+
const { uid, gid } = userInfo();
|
|
1766
|
+
const runArgs = [
|
|
1767
|
+
"run",
|
|
1768
|
+
"--detach",
|
|
1769
|
+
"--init",
|
|
1770
|
+
"--name",
|
|
1771
|
+
containerName,
|
|
1772
|
+
"--user",
|
|
1773
|
+
dc.user || `${uid}:${gid}`,
|
|
1774
|
+
...networkFlags,
|
|
1775
|
+
...envFlags,
|
|
1776
|
+
...volumeFlags,
|
|
1777
|
+
imageName,
|
|
1778
|
+
"sleep",
|
|
1779
|
+
"infinity"
|
|
1780
|
+
];
|
|
1781
|
+
const debugCardId = randomUUID();
|
|
1782
|
+
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "run", _cardId: debugCardId, _cardState: "open", message: "Docker Run (shared container)" })}
|
|
1783
|
+
`);
|
|
1784
|
+
stdout.write(`docker ${runArgs.join(" ")}
|
|
1785
|
+
`);
|
|
1786
|
+
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: debugCardId, _cardState: "close" })}
|
|
1787
|
+
`);
|
|
1788
|
+
const runProc = execa2("docker", runArgs, { reject: false });
|
|
1789
|
+
runProc.stdout?.pipe(stdout, { end: false });
|
|
1790
|
+
runProc.stderr?.pipe(stderr, { end: false });
|
|
1791
|
+
const runResult = await runProc;
|
|
1792
|
+
if (runResult.exitCode !== 0) {
|
|
1793
|
+
rejectReady(new Error(`docker run exited with code ${runResult.exitCode}`));
|
|
1794
|
+
exitResolve({ exitCode: runResult.exitCode ?? 1, signal: null });
|
|
1795
|
+
return;
|
|
1796
|
+
}
|
|
1797
|
+
resolveReady();
|
|
1798
|
+
const waitProc = execa2("docker", ["wait", containerName], { reject: false });
|
|
1799
|
+
await waitProc;
|
|
1800
|
+
exitResolve({ exitCode: 0, signal: null });
|
|
1804
1801
|
} catch (err) {
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1802
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1803
|
+
stderr.write(`Docker infrastructure error: ${msg}
|
|
1804
|
+
`);
|
|
1805
|
+
rejectReady(new Error(msg));
|
|
1806
|
+
exitResolve({ exitCode: 1, signal: null });
|
|
1807
|
+
} finally {
|
|
1808
|
+
stdout.end();
|
|
1809
|
+
stderr.end();
|
|
1808
1810
|
}
|
|
1809
|
-
}
|
|
1810
|
-
return
|
|
1811
|
+
})();
|
|
1812
|
+
return {
|
|
1813
|
+
pid: void 0,
|
|
1814
|
+
containerName,
|
|
1815
|
+
stdout,
|
|
1816
|
+
stderr,
|
|
1817
|
+
exitPromise,
|
|
1818
|
+
containerReady,
|
|
1819
|
+
kill(_signal = "SIGTERM") {
|
|
1820
|
+
killed = true;
|
|
1821
|
+
execa2("docker", ["kill", containerName]).then(() => exitResolve({ exitCode: null, signal: "SIGKILL" })).catch(() => exitResolve({ exitCode: 1, signal: null }));
|
|
1822
|
+
return true;
|
|
1823
|
+
}
|
|
1824
|
+
};
|
|
1811
1825
|
}
|
|
1812
|
-
/**
|
|
1813
|
-
*
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1826
|
+
/** Run a command inside a running shared container via `docker exec`.
|
|
1827
|
+
* Kill terminates the docker-exec process but does NOT stop the container. */
|
|
1828
|
+
execInContainer(containerName, command, envVars = {}, shell = "sh") {
|
|
1829
|
+
const stdout = new PassThrough();
|
|
1830
|
+
const stderr = new PassThrough();
|
|
1831
|
+
let dockerProc = null;
|
|
1832
|
+
const exitPromise = new Promise(
|
|
1833
|
+
(resolve2) => {
|
|
1834
|
+
void (async () => {
|
|
1835
|
+
try {
|
|
1836
|
+
const envFlags = Object.entries(envVars).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
|
|
1837
|
+
const shellCmd = command.length ? command : "true";
|
|
1838
|
+
dockerProc = execa2(
|
|
1839
|
+
"docker",
|
|
1840
|
+
["exec", ...envFlags, containerName, shell, "-c", shellCmd],
|
|
1841
|
+
{ reject: false }
|
|
1842
|
+
);
|
|
1843
|
+
dockerProc.stdout?.pipe(stdout, { end: false });
|
|
1844
|
+
dockerProc.stderr?.pipe(stderr, { end: false });
|
|
1845
|
+
const result = await dockerProc;
|
|
1846
|
+
resolve2({ exitCode: result.exitCode ?? null, signal: result.signal ?? null });
|
|
1847
|
+
} catch (err) {
|
|
1848
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1849
|
+
stderr.write(`docker execInContainer error: ${msg}
|
|
1850
|
+
`);
|
|
1851
|
+
resolve2({ exitCode: 1, signal: null });
|
|
1852
|
+
} finally {
|
|
1853
|
+
stdout.end();
|
|
1854
|
+
stderr.end();
|
|
1855
|
+
}
|
|
1856
|
+
})();
|
|
1857
|
+
}
|
|
1858
|
+
);
|
|
1859
|
+
return {
|
|
1860
|
+
pid: void 0,
|
|
1861
|
+
containerName,
|
|
1862
|
+
stdout,
|
|
1863
|
+
stderr,
|
|
1864
|
+
exitPromise,
|
|
1865
|
+
kill(_signal = "SIGTERM") {
|
|
1866
|
+
dockerProc?.kill("SIGTERM");
|
|
1867
|
+
return true;
|
|
1827
1868
|
}
|
|
1828
|
-
}
|
|
1829
|
-
const sandbox = {
|
|
1830
|
-
RegExp,
|
|
1831
|
-
String,
|
|
1832
|
-
Object,
|
|
1833
|
-
Array,
|
|
1834
|
-
JSON,
|
|
1835
|
-
Math,
|
|
1836
|
-
Date,
|
|
1837
|
-
undefined: void 0,
|
|
1838
|
-
null: null
|
|
1839
1869
|
};
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
const
|
|
1847
|
-
let
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1870
|
+
}
|
|
1871
|
+
/** Run a shortcut command in the context of a Docker service.
|
|
1872
|
+
* If a service container is running (shared or isolated), uses `docker exec`.
|
|
1873
|
+
* If not running, reuses `start()` with `--rm` and `skipBootstrap`. */
|
|
1874
|
+
runShortcut(config, shortcutCommand) {
|
|
1875
|
+
const stdout = new PassThrough();
|
|
1876
|
+
const stderr = new PassThrough();
|
|
1877
|
+
let innerProcess = null;
|
|
1878
|
+
let dockerProc = null;
|
|
1879
|
+
const exitPromise = new Promise(
|
|
1880
|
+
(resolve2) => {
|
|
1881
|
+
void (async () => {
|
|
1882
|
+
try {
|
|
1883
|
+
const psResult = await execa2(
|
|
1884
|
+
"docker",
|
|
1885
|
+
["ps", "--filter", `name=runeya-${config.serviceId}`, "--format", "{{.Names}}"],
|
|
1886
|
+
{ reject: false }
|
|
1887
|
+
);
|
|
1888
|
+
const runningContainer = psResult.stdout.trim().split("\n").find((n) => n.startsWith(`runeya-${config.serviceId}`));
|
|
1889
|
+
if (runningContainer) {
|
|
1890
|
+
const shell = config.dockerConfig.nativeShell || "sh";
|
|
1891
|
+
const envFlags = Object.entries(config.env ?? {}).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
|
|
1892
|
+
const args = ["exec", ...envFlags, runningContainer, shell, "-c", shortcutCommand || "true"];
|
|
1893
|
+
const cardId = randomUUID();
|
|
1894
|
+
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "exec", _cardId: cardId, _cardState: "open", message: "Docker Exec" })}
|
|
1895
|
+
`);
|
|
1896
|
+
stdout.write(`docker ${args.join(" ")}
|
|
1897
|
+
`);
|
|
1898
|
+
stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: cardId, _cardState: "close" })}
|
|
1899
|
+
`);
|
|
1900
|
+
dockerProc = execa2("docker", args, { reject: false });
|
|
1901
|
+
dockerProc.stdout?.pipe(stdout, { end: false });
|
|
1902
|
+
dockerProc.stderr?.pipe(stderr, { end: false });
|
|
1903
|
+
const result = await dockerProc;
|
|
1904
|
+
resolve2({ exitCode: result.exitCode ?? null, signal: result.signal ?? null });
|
|
1905
|
+
} else {
|
|
1906
|
+
innerProcess = this.start({
|
|
1907
|
+
...config,
|
|
1908
|
+
command: shortcutCommand,
|
|
1909
|
+
cmdId: `shortcut-${randomUUID()}`,
|
|
1910
|
+
rm: true,
|
|
1911
|
+
skipBootstrap: true,
|
|
1912
|
+
dockerConfig: { ...config.dockerConfig, useNativeCommand: true }
|
|
1913
|
+
});
|
|
1914
|
+
innerProcess.stdout?.pipe(stdout, { end: false });
|
|
1915
|
+
innerProcess.stderr?.pipe(stderr, { end: false });
|
|
1916
|
+
const result = await innerProcess.exitPromise;
|
|
1917
|
+
resolve2(result);
|
|
1918
|
+
}
|
|
1919
|
+
} catch (err) {
|
|
1920
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1921
|
+
stderr.write(`docker shortcut error: ${msg}
|
|
1922
|
+
`);
|
|
1923
|
+
resolve2({ exitCode: 1, signal: null });
|
|
1924
|
+
} finally {
|
|
1925
|
+
stdout.end();
|
|
1926
|
+
stderr.end();
|
|
1927
|
+
}
|
|
1928
|
+
})();
|
|
1882
1929
|
}
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1930
|
+
);
|
|
1931
|
+
return {
|
|
1932
|
+
pid: void 0,
|
|
1933
|
+
stdout,
|
|
1934
|
+
stderr,
|
|
1935
|
+
exitPromise,
|
|
1936
|
+
kill(signal = "SIGTERM") {
|
|
1937
|
+
if (innerProcess) return innerProcess.kill(signal);
|
|
1938
|
+
dockerProc?.kill("SIGTERM");
|
|
1939
|
+
return true;
|
|
1886
1940
|
}
|
|
1887
|
-
return result;
|
|
1888
1941
|
};
|
|
1889
1942
|
}
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
}
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1943
|
+
async isAvailable() {
|
|
1944
|
+
const result = await execa2("docker", ["info"], { reject: false });
|
|
1945
|
+
return result.exitCode === 0;
|
|
1946
|
+
}
|
|
1947
|
+
/** Run a single bootstrap command sequentially inside a temporary container (--rm).
|
|
1948
|
+
* Streams stdout/stderr into the provided PassThrough streams.
|
|
1949
|
+
* Resolves with the exit code when the container exits. */
|
|
1950
|
+
async runBootstrap(cmd, imageName, env2, volumes, stdout, stderr) {
|
|
1951
|
+
const containerName = sanitizeDockerName(`runeya-bootstrap-${randomUUID()}`);
|
|
1952
|
+
const envFlags = Object.entries(env2).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
|
|
1953
|
+
await preMkdirVolumes(volumes, env2);
|
|
1954
|
+
const volumeFlags = volumes.map((v) => expandEnvVars2(v, env2)).flatMap((v) => ["-v", v]);
|
|
1955
|
+
const entrypointFlags = cmd.entrypoint ? ["--entrypoint", cmd.entrypoint] : [];
|
|
1956
|
+
const { uid, gid } = userInfo();
|
|
1957
|
+
const defaultUser = `${uid}:${gid}`;
|
|
1958
|
+
const userFlags = ["--user", cmd.user || defaultUser];
|
|
1959
|
+
const cmdArgs = splitShellArgs(cmd.command);
|
|
1960
|
+
const runArgs = [
|
|
1961
|
+
"run",
|
|
1962
|
+
"--rm",
|
|
1963
|
+
"--init",
|
|
1964
|
+
"--name",
|
|
1965
|
+
containerName,
|
|
1966
|
+
"--network",
|
|
1967
|
+
"host",
|
|
1968
|
+
...envFlags,
|
|
1969
|
+
...volumeFlags,
|
|
1970
|
+
...entrypointFlags,
|
|
1971
|
+
...userFlags,
|
|
1972
|
+
imageName,
|
|
1973
|
+
...cmdArgs
|
|
1974
|
+
];
|
|
1975
|
+
const proc = execa2("docker", runArgs, { reject: false });
|
|
1976
|
+
proc.stdout?.pipe(stdout, { end: false });
|
|
1977
|
+
proc.stderr?.pipe(stderr, { end: false });
|
|
1978
|
+
const result = await proc;
|
|
1979
|
+
return result.exitCode ?? 1;
|
|
1912
1980
|
}
|
|
1913
1981
|
};
|
|
1914
1982
|
|
|
1915
|
-
//
|
|
1916
|
-
var
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
{
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
{
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
{
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
{ key: "vim", name: "Vim", command: "vim" },
|
|
1942
|
-
{ key: "emacs", name: "Emacs", command: "emacs" },
|
|
1943
|
-
{ key: "fleet", name: "Fleet", command: "fleet" }
|
|
1944
|
-
];
|
|
1945
|
-
var EDITOR_BY_KEY = new Map(
|
|
1946
|
-
SUPPORTED_EDITORS.map((e) => [e.key, e])
|
|
1947
|
-
);
|
|
1983
|
+
// src/services/process-store.ts
|
|
1984
|
+
var ProcessStore = class {
|
|
1985
|
+
processes = /* @__PURE__ */ new Map();
|
|
1986
|
+
get(id) {
|
|
1987
|
+
return this.processes.get(id);
|
|
1988
|
+
}
|
|
1989
|
+
getAll() {
|
|
1990
|
+
return Array.from(this.processes.values());
|
|
1991
|
+
}
|
|
1992
|
+
set(id, process2) {
|
|
1993
|
+
this.processes.set(id, process2);
|
|
1994
|
+
}
|
|
1995
|
+
delete(id) {
|
|
1996
|
+
return this.processes.delete(id);
|
|
1997
|
+
}
|
|
1998
|
+
has(id) {
|
|
1999
|
+
return this.processes.has(id);
|
|
2000
|
+
}
|
|
2001
|
+
clear() {
|
|
2002
|
+
this.processes.clear();
|
|
2003
|
+
}
|
|
2004
|
+
getByServiceId(serviceId) {
|
|
2005
|
+
return this.getAll().find((p) => p.serviceConfig.id === serviceId);
|
|
2006
|
+
}
|
|
2007
|
+
};
|
|
2008
|
+
var processStore = new ProcessStore();
|
|
1948
2009
|
|
|
1949
|
-
//
|
|
1950
|
-
import
|
|
2010
|
+
// src/services/log-sources/console-log-source.ts
|
|
2011
|
+
import { createInterface } from "readline";
|
|
2012
|
+
import { EventEmitter } from "events";
|
|
2013
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
1951
2014
|
|
|
1952
2015
|
// src/services/log-parser.ts
|
|
1953
2016
|
var DEFAULT_LEVEL_PATTERNS = [
|
|
@@ -3591,13 +3654,20 @@ function getLanIp() {
|
|
|
3591
3654
|
}
|
|
3592
3655
|
return "127.0.0.1";
|
|
3593
3656
|
}
|
|
3594
|
-
function
|
|
3595
|
-
const
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3657
|
+
function resolveAgentBuiltins(serviceConfig) {
|
|
3658
|
+
const values = {
|
|
3659
|
+
"agent.HOST_LAN": getLanIp(),
|
|
3660
|
+
"agent.OS": platform2(),
|
|
3661
|
+
"agent.HOME": homedir5(),
|
|
3662
|
+
// Le cwd est calculé avec l'env AVANT substitution : une variable qui
|
|
3663
|
+
// référencerait `{{service.CWD}}` ne peut donc pas se boucler sur
|
|
3664
|
+
// elle-même — la substitution ne repasse jamais sur son propre résultat.
|
|
3665
|
+
"service.CWD": resolve(resolveCwd(
|
|
3666
|
+
serviceConfig.resolvedCwd ?? serviceConfig.cwd,
|
|
3667
|
+
resolveEnv(serviceConfig.env)
|
|
3668
|
+
))
|
|
3669
|
+
};
|
|
3670
|
+
return withDeprecatedAliases(values);
|
|
3601
3671
|
}
|
|
3602
3672
|
var ProcessManager = class extends EventEmitter7 {
|
|
3603
3673
|
runners = /* @__PURE__ */ new Map();
|
|
@@ -3696,7 +3766,10 @@ var ProcessManager = class extends EventEmitter7 {
|
|
|
3696
3766
|
throw new Error(`Process ${processId} is already ${proc.state}`);
|
|
3697
3767
|
}
|
|
3698
3768
|
if (proc.serviceConfig.env) {
|
|
3699
|
-
proc.serviceConfig = {
|
|
3769
|
+
proc.serviceConfig = {
|
|
3770
|
+
...proc.serviceConfig,
|
|
3771
|
+
env: interpolateBuiltinsInEnv(proc.serviceConfig.env, resolveAgentBuiltins(proc.serviceConfig))
|
|
3772
|
+
};
|
|
3700
3773
|
}
|
|
3701
3774
|
const commands = (proc.serviceConfig.commands ?? []).filter((c) => c.command.trim());
|
|
3702
3775
|
const isDocker = proc.serviceConfig.runner === "docker";
|
|
@@ -4544,7 +4617,7 @@ var processRouter = router({
|
|
|
4544
4617
|
});
|
|
4545
4618
|
|
|
4546
4619
|
// src/trpc/routers/health.ts
|
|
4547
|
-
import { networkInterfaces as networkInterfaces2 } from "os";
|
|
4620
|
+
import { networkInterfaces as networkInterfaces2, homedir as homedir6, platform as platform3 } from "os";
|
|
4548
4621
|
import { execFile as execFile3 } from "child_process";
|
|
4549
4622
|
import { promisify } from "util";
|
|
4550
4623
|
var execFileAsync = promisify(execFile3);
|
|
@@ -4569,7 +4642,14 @@ async function getHealthData() {
|
|
|
4569
4642
|
runnersAvailable: runners,
|
|
4570
4643
|
processCount: processes.length,
|
|
4571
4644
|
runningCount: processes.filter((p) => p.state === "running").length,
|
|
4572
|
-
lanIp: getLanIp2()
|
|
4645
|
+
lanIp: getLanIp2(),
|
|
4646
|
+
// Ce qui décrit la machine, pour que l'interface puisse montrer la valeur
|
|
4647
|
+
// qu'aura `{{agent.OS}}`, `{{agent.HOME}}`, `{{service.CWD}}` AVANT que le
|
|
4648
|
+
// service ne démarre. La résolution, elle, reste faite ici au lancement :
|
|
4649
|
+
// ce statut n'est qu'un cliché, et l'agent reste l'autorité sur sa machine.
|
|
4650
|
+
os: platform3(),
|
|
4651
|
+
home: homedir6(),
|
|
4652
|
+
cwd: process.cwd()
|
|
4573
4653
|
};
|
|
4574
4654
|
}
|
|
4575
4655
|
var healthRouter = router({
|
|
@@ -6464,7 +6544,7 @@ function appendToPath(dir, environment = process.env) {
|
|
|
6464
6544
|
// ../../packages/shared/src/node/user-path.ts
|
|
6465
6545
|
import { execFile as execFile5 } from "child_process";
|
|
6466
6546
|
import { promisify as promisify3 } from "util";
|
|
6467
|
-
import { homedir as
|
|
6547
|
+
import { homedir as homedir7 } from "os";
|
|
6468
6548
|
import { existsSync as existsSync4, statSync } from "fs";
|
|
6469
6549
|
import { join as join6, delimiter as delimiter2 } from "path";
|
|
6470
6550
|
var execFileAsync3 = promisify3(execFile5);
|
|
@@ -6501,7 +6581,7 @@ async function readLoginShellPath() {
|
|
|
6501
6581
|
return null;
|
|
6502
6582
|
}
|
|
6503
6583
|
}
|
|
6504
|
-
async function ensureUserBinsOnPath(environment = process.env, home =
|
|
6584
|
+
async function ensureUserBinsOnPath(environment = process.env, home = homedir7()) {
|
|
6505
6585
|
const shellPath = await readLoginShellPath();
|
|
6506
6586
|
if (shellPath) {
|
|
6507
6587
|
for (const entry of shellPath.split(delimiter2).filter(Boolean)) {
|