@runeya/runeya 2.0.101 → 2.0.103
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 +170 -161
- package/agent/index.js.map +1 -1
- package/agent-manager-OWHTBG46.js +9 -0
- package/assets/icon-alert.ico +0 -0
- package/assets/icon-alert.png +0 -0
- package/assets/icon-alert.svg +19 -0
- package/chat-JZ4UQDWV.js +20 -0
- package/{node-B4T3JMM3.js → chunk-B7MABGQN.js} +51 -4
- package/chunk-B7MABGQN.js.map +1 -0
- package/chunk-KY6KYSOU.js +279 -0
- package/chunk-KY6KYSOU.js.map +1 -0
- package/{chunk-TNBMCKQX.js → chunk-NZNIWJDT.js} +226 -23
- package/chunk-NZNIWJDT.js.map +1 -0
- package/chunk-PH4E5WDN.js +137 -0
- package/chunk-PH4E5WDN.js.map +1 -0
- package/{chunk-BHLCBARP.js → chunk-QIBUMYR6.js} +29 -11
- package/chunk-QIBUMYR6.js.map +1 -0
- package/{chunk-NDO5VFZY.js → chunk-QRMG6GMX.js} +694 -917
- package/chunk-QRMG6GMX.js.map +1 -0
- package/{chunk-SP3IC2TR.js → chunk-UYOWIH4R.js} +39 -221
- package/chunk-UYOWIH4R.js.map +1 -0
- package/{chunk-F3HKV5AU.js → chunk-Z67WBWKD.js} +7 -5
- package/{chunk-F3HKV5AU.js.map → chunk-Z67WBWKD.js.map} +1 -1
- package/{companion-QNW7XA6X.js → companion-6J6NK7H7.js} +7 -4
- package/{desktop-launcher-FHNURZA7.js → desktop-launcher-N7WRF3LC.js} +11 -17
- package/desktop-launcher-N7WRF3LC.js.map +1 -0
- package/index.js +65 -3
- package/index.js.map +1 -1
- package/instances-command-KZ5UGXOR.js +17 -0
- package/node-ILM6MV56.js +21 -0
- package/node-ILM6MV56.js.map +1 -0
- package/package.json +4 -1
- package/settings-manager-NZV26BC3.js +9 -0
- package/settings-manager-NZV26BC3.js.map +1 -0
- package/{src-PF23DMAB.js → src-V7DPPFCF.js} +454 -255
- package/src-V7DPPFCF.js.map +1 -0
- package/tray-TRWZNOUD.js +291 -0
- package/tray-TRWZNOUD.js.map +1 -0
- package/web/assets/AgentScalarChatInterface.vue-CvG5ha3R.js +13 -0
- package/web/assets/AgentTerminalPage-DcGppuzO.js +1 -0
- package/web/assets/AiChatPage-BDr5tG0A.js +1 -0
- package/web/assets/{AppLayout-DeWqCLuK.css → AppLayout-CYQBjQBU.css} +1 -1
- package/web/assets/AppLayout-Dv3ViAk2.js +1 -0
- package/web/assets/AuditPage-Bc2jlgZJ.js +1 -0
- package/web/assets/CloudAccountPage-4BLXSOix.js +1 -0
- package/web/assets/CloudAccountPage-B3MX6DNn.js +1 -0
- package/web/assets/CloudMessagingPage-CVzUalxx.js +2 -0
- package/web/assets/DashboardPage-Bo51pbzt.js +1 -0
- package/web/assets/DirectoryPickerDialog-CIVjWKUm.js +1 -0
- package/web/assets/{EditorIcon-BXS2-yX1.js → EditorIcon-BguaWtZg.js} +2 -2
- package/web/assets/{EnvironmentForm--y9zfCDt.js → EnvironmentForm-D8dq0ffR.js} +2 -2
- package/web/assets/EnvironmentFormPage-d8p3q8Yt.js +1 -0
- package/web/assets/EnvironmentListPage-DWo2lWjE.js +1 -0
- package/web/assets/KanbanBoardPage-DkwIz3J1.js +4 -0
- package/web/assets/KanbanListPage-xIQRLcrS.js +1 -0
- package/web/assets/LaunchProjectPage-CXWixUmf.js +1 -0
- package/web/assets/LaunchServicesPage-nv-chYgX.js +1 -0
- package/web/assets/LogViewer-DLupfjjf.js +3 -0
- package/web/assets/OrgKeyPrompt-DePcB-8f.js +1 -0
- package/web/assets/ProcessControls-D3zTnHb2.js +1 -0
- package/web/assets/ProcessDetailPage-CgVGzRoJ.js +1 -0
- package/web/assets/{ProcessMetrics-fCxhXJgd.js → ProcessMetrics-Dwd5lzqY.js} +2 -2
- package/web/assets/ProjectDetailPage-HR20KyJ3.js +1 -0
- package/web/assets/ProjectListPage-DcH4uTTX.js +1 -0
- package/web/assets/RandomJobTestPage-BYTkVcdE.js +2 -0
- package/web/assets/ScenarioEditorPage-zRxR03Ud.js +14 -0
- package/web/assets/SendToChatDialog-Cm5eKBOb.js +1 -0
- package/web/assets/ServiceControlsBar-oBpAP9yX.js +1 -0
- package/web/assets/ServiceDetailPage-CahBi-or.js +2 -0
- package/web/assets/ServiceFormPage-DfmPM_mI.js +1 -0
- package/web/assets/SettingsPage-CDMXFJ4k.js +2063 -0
- package/web/assets/SettingsPage-Dw6tbcbw.css +1 -0
- package/web/assets/UnlockPage-BUyBEPzQ.js +1 -0
- package/web/assets/VariablesTable-Dc6CyVQW.js +1 -0
- package/web/assets/VaultMigrationPage-BUmzyDXN.js +1 -0
- package/web/assets/VersionBadge-Dx_67FtC.js +1 -0
- package/web/assets/WikiPage-DEMJLDpD.js +1 -0
- package/web/assets/WikiView-CcrQ2ySx.js +1 -0
- package/web/assets/add-scalar-classes-M_EBdf4f.js +387 -0
- package/web/assets/{autocomplete-AALxfd-8.js → autocomplete-QtPLLzzV.js} +3 -3
- package/web/assets/{basic-shape-diamond.svg-C4c3Deqh.js → basic-shape-diamond.svg-Dyx8FJkS.js} +1 -1
- package/web/assets/{basic-shape-hexagon.svg-DrH21BpW.js → basic-shape-hexagon.svg-1RKdVP3_.js} +1 -1
- package/web/assets/{basic-shape-primary-circle-ellipse-round.svg-DqIU3Cmf.js → basic-shape-primary-circle-ellipse-round.svg-CSa69hok.js} +1 -1
- package/web/assets/{basic-shape-primary-square-rectangle.svg-B3gDug6x.js → basic-shape-primary-square-rectangle.svg-B9TXktd4.js} +1 -1
- package/web/assets/{basic-shape-shield.svg-DdNJhKim.js → basic-shape-shield.svg-BZvKXoiw.js} +1 -1
- package/web/assets/{browser-DlwaOVwW.js → browser-CYeKc8Uo.js} +1 -1
- package/web/assets/{browser-IqQiUipW.js → browser-VlhbsseI.js} +1 -1
- package/web/assets/card-tEWfv-Op.js +32 -0
- package/web/assets/{checkbox-BP6nucdt.js → checkbox-CyPqKR6H.js} +3 -3
- package/web/assets/{chip-zQCMXVbm.js → chip-wM0gJ_FI.js} +2 -2
- package/web/assets/client-B919VgbS.js +24 -0
- package/web/assets/cloud-chat.store-C-A9nIqG.js +1 -0
- package/web/assets/cloud-session-g6ewm0UI.js +1 -0
- package/web/assets/column-DihIO4Zd.js +907 -0
- package/web/assets/{computer-device-desktop-monitor.svg-D28gfKH3.js → computer-device-desktop-monitor.svg-ClbIVuot.js} +1 -1
- package/web/assets/{computer-device-desktop.svg-BierhytR.js → computer-device-desktop.svg-CXpOovTP.js} +1 -1
- package/web/assets/{computer-device-laptop.svg-Buh46ofO.js → computer-device-laptop.svg-C9sY1wZv.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-android-samsung-back.svg-DWgP259U.js → computer-device-mobile-phone-android-samsung-back.svg-CPWC2QHX.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-android-samsung.svg-BlulLqG-.js → computer-device-mobile-phone-android-samsung.svg-B0H-mnfh.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-iphone-x-back.svg-CwAgL_XU.js → computer-device-mobile-phone-iphone-x-back.svg-BbIunxoN.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-iphone-x.svg-CGZk25hI.js → computer-device-mobile-phone-iphone-x.svg-qLGK_oVA.js} +1 -1
- package/web/assets/{computer-device-mobile-tablet-touch.svg-BW41ZuCA.js → computer-device-mobile-tablet-touch.svg-BDpuB6SD.js} +1 -1
- package/web/assets/{computer-device-mobile-tablet.svg-BXG04cxV.js → computer-device-mobile-tablet.svg-44THWP9E.js} +1 -1
- package/web/assets/{computer-device-network-ethernet-cat6.svg-BKUwbZI3.js → computer-device-network-ethernet-cat6.svg-tlgWltl_.js} +1 -1
- package/web/assets/{computer-device-network-lan-www.svg-o3B9PLqQ.js → computer-device-network-lan-www.svg-Bd7Ch4QN.js} +1 -1
- package/web/assets/{computer-device-network-wifi-connection.svg-CWz616VA.js → computer-device-network-wifi-connection.svg-D_XjoY-a.js} +1 -1
- package/web/assets/{computer-device-network-wifi-router.svg-C_Uxv8x_.js → computer-device-network-wifi-router.svg-BRpuwgUx.js} +1 -1
- package/web/assets/{cssMode-trDHQWjr.js → cssMode-D0M5mbRd.js} +1 -1
- package/web/assets/{divider-ER7evOrG.js → divider-gPnMjjpJ.js} +2 -2
- package/web/assets/{docx-preview-DaBMrB0t.js → docx-preview-CBPtwrA0.js} +1 -1
- package/web/assets/{ecology-science-erlenmeyer-flask.svg-TilKtHh2.js → ecology-science-erlenmeyer-flask.svg-CZ3uUeBT.js} +1 -1
- package/web/assets/{fieldset-BK4Kpi7y.js → fieldset-BSGgRmpr.js} +2 -2
- package/web/assets/{freemarker2-CPBy2gHY.js → freemarker2-BWsK2SIi.js} +1 -1
- package/web/assets/{handlebars-sFv_MRko.js → handlebars-CHNB1gG0.js} +1 -1
- package/web/assets/{html-CvDf5B_n.js → html-COwA9Dtl.js} +1 -1
- package/web/assets/{htmlMode-CKhs4g6W.js → htmlMode-gZ2_PUDA.js} +1 -1
- package/web/assets/{image-flash-lightning.svg-CkgasY6E.js → image-flash-lightning.svg-Iiwm_7-K.js} +1 -1
- package/web/assets/{image-picture-flower.svg-Csk-7jkE.js → image-picture-flower.svg-BP9U6YP8.js} +1 -1
- package/web/assets/{index-BmdsyJ54.css → index-DWQLzWm4.css} +1 -1
- package/web/assets/{index-CdghDQiK.js → index-mBPGEldp.js} +285 -285
- package/web/assets/{interface-alert-exclamation-diamond.svg-rH1JAriw.js → interface-alert-exclamation-diamond.svg-BYWgnbUp.js} +1 -1
- package/web/assets/{interface-alert-exclamation-triangle-warning.svg-BuZLBc2z.js → interface-alert-exclamation-triangle-warning.svg-CWGfXHx_.js} +1 -1
- package/web/assets/{interface-alert-information-circle.svg-D6i0hGVN.js → interface-alert-information-circle.svg-88Bga8qr.js} +1 -1
- package/web/assets/{interface-award-crown.svg-7Wu9-VKO.js → interface-award-crown.svg-3hO77oiy.js} +1 -1
- package/web/assets/{interface-bookmark.svg-CkLVcfT6.js → interface-bookmark-tag.svg-DcHwQsr0.js} +1 -1
- package/web/assets/{interface-bookmark-tag.svg-CPiMqQ77.js → interface-bookmark.svg-SfHcE95h.js} +1 -1
- package/web/assets/{interface-calendar-date-one.svg-CFSXAk1b.js → interface-calendar-date-one.svg-DdXOM9VZ.js} +1 -1
- package/web/assets/{interface-content-book-open-pages.svg-CC4c9Opt.js → interface-content-book-open-pages.svg-DD7QTDn_.js} +1 -1
- package/web/assets/{interface-content-book-page.svg-DxpVNOOq.js → interface-content-book-page.svg-Dd45mFzB.js} +1 -1
- package/web/assets/{interface-content-file.svg-CTaWk4im.js → interface-content-file.svg-slPoMF5K.js} +1 -1
- package/web/assets/interface-content-folder.svg-D90zbTLh.js +1 -0
- package/web/assets/{interface-content-folder.svg-uVUoz9w-.js → interface-content-folder.svg-cSgXwhRh.js} +1 -1
- package/web/assets/{interface-copy-clipboard.svg-BZIxAN3r.js → interface-copy-clipboard.svg-DNy0VeWx.js} +1 -1
- package/web/assets/{interface-edit-attachment.svg-DDzPxeNm.js → interface-edit-attachment.svg-VyCAm1jc.js} +1 -1
- package/web/assets/{interface-edit-binocular.svg-CZsgbA--.js → interface-edit-binocular.svg-DA6QB2sn.js} +1 -1
- package/web/assets/{interface-edit-magic-wand.svg-qmz7k4l6.js → interface-edit-magic-wand.svg-D0uagBk7.js} +1 -1
- package/web/assets/{interface-edit-tool-paint-roller.svg-DWE25KT2.js → interface-edit-tool-paint-roller.svg-ConlubSG.js} +1 -1
- package/web/assets/{interface-edit-tool-pencil.svg-DpK1C2tO.js → interface-edit-tool-pencil.svg-BgNzCwXf.js} +1 -1
- package/web/assets/{interface-favorite-award.svg-CLHMWnh1.js → interface-favorite-award.svg-MLL88pIy.js} +1 -1
- package/web/assets/{interface-favorite-flag.svg-CHGIAa-e.js → interface-favorite-flag.svg-ZhM_9XJZ.js} +1 -1
- package/web/assets/{interface-favorite-heart.svg-ymL9Qidy.js → interface-favorite-heart.svg-Cqq1PV9O.js} +1 -1
- package/web/assets/{interface-favorite-star.svg-C4JDKdUr.js → interface-favorite-star.svg-YumblcRD.js} +1 -1
- package/web/assets/{interface-favorite-stars-sparkles.svg-DRixMNWJ.js → interface-favorite-stars-sparkles.svg-BH5BXXOe.js} +1 -1
- package/web/assets/{interface-hierarchy-flowchart.svg-DozpERYh.js → interface-hierarchy-flowchart.svg-CEfCPIyC.js} +1 -1
- package/web/assets/{interface-home-house.svg-DpUEVY7I.js → interface-home-house.svg-DJE_g94c.js} +1 -1
- package/web/assets/{interface-hyperlink.svg-BI9P67ny.js → interface-hyperlink.svg-BFhnDXDD.js} +1 -1
- package/web/assets/{interface-lighting-brightness.svg-B6WWS4kG.js → interface-lighting-brightness.svg-NwOV0KEv.js} +1 -1
- package/web/assets/{interface-lock-closed.svg-BBQ9XM_j.js → interface-lock-closed.svg-qVkplX0W.js} +1 -1
- package/web/assets/{interface-lock-open-unlock.svg-GkTO8GmV.js → interface-lock-open-unlock.svg-D18OlPEP.js} +1 -1
- package/web/assets/{interface-login-key.svg--v2ZJH3Q.js → interface-login-key.svg-CccXX7_b.js} +1 -1
- package/web/assets/{interface-search.svg-CidqkApV.js → interface-search.svg-C6ncELaU.js} +1 -1
- package/web/assets/{interface-setting-cog.svg-DVZePAV3.js → interface-setting-cog.svg-5LrIeBav.js} +1 -1
- package/web/assets/{interface-share-megaphone-bullhorn.svg-BFn_RMqc.js → interface-share-megaphone-bullhorn.svg-C-qB4VYi.js} +1 -1
- package/web/assets/{interface-share-rocket.svg-BvWSz0s2.js → interface-share-rocket.svg-Citzuyng.js} +1 -1
- package/web/assets/{interface-share-satellite.svg-tqNCB74Z.js → interface-share-satellite.svg-BldpdKdo.js} +1 -1
- package/web/assets/{interface-share-space-ship.svg-BmB824fS.js → interface-share-space-ship.svg-B_Ni34rB.js} +1 -1
- package/web/assets/{interface-share.svg-CBZLrrF9.js → interface-share.svg-FAt7Kgad.js} +1 -1
- package/web/assets/{interface-signal-square.svg-C088p9NZ.js → interface-signal-square.svg-DeBP6Pim.js} +1 -1
- package/web/assets/{interface-time-clock-circle.svg-DubKvXWQ.js → interface-time-clock-circle.svg-dQfNY8BC.js} +1 -1
- package/web/assets/{interface-time-hour-glass.svg-6GComyAL.js → interface-time-hour-glass.svg-ylbFnlwY.js} +1 -1
- package/web/assets/{interface-users-multiple.svg-ja6OEhK_.js → interface-users-multiple.svg-DXts3WMC.js} +1 -1
- package/web/assets/{interface-weather-moon.svg-BnfLL03K.js → interface-weather-moon.svg-BG6mjCih.js} +1 -1
- package/web/assets/{javascript-DMRS72rt.js → javascript-C_ENjImO.js} +1 -1
- package/web/assets/{jsonMode--8QdTWx_.js → jsonMode-Bt-LEknD.js} +2 -2
- package/web/assets/{liquid-OaGt-c-G.js → liquid-CVshgHmY.js} +1 -1
- package/web/assets/{lspLanguageFeatures-B6AaNVcR.js → lspLanguageFeatures-D1e-RcOs.js} +3 -3
- package/web/assets/{mail-chat-bubble-square.svg-D0WUmEWq.js → mail-chat-bubble-square.svg-RUMLqiUI.js} +1 -1
- package/web/assets/{mail-send-email-paper-airplane.svg--9oR8FgG.js → mail-send-email-paper-airplane.svg-JDe3yqOH.js} +1 -1
- package/web/assets/{mail-send-envelope.svg-D7zYusS0.js → mail-send-envelope.svg-CCzWaeO-.js} +1 -1
- package/web/assets/{mdx-ChDcRRYd.js → mdx-D9G2-Bj8.js} +1 -1
- package/web/assets/{minus-lcNwQ3xr.js → minus-BMxEQL_C.js} +2 -2
- package/web/assets/modal-CZ7zYg5t.js +1 -0
- package/web/assets/modal-CmpFIC5N.js +5 -0
- package/web/assets/{money-cashier-receipt.svg-DzX-iwUT.js → money-cashier-receipt.svg-DfbOr89U.js} +1 -1
- package/web/assets/{money-currency-dollar-pay.svg-BFX_YTDc.js → money-currency-dollar-pay.svg-DY7fQ7jz.js} +1 -1
- package/web/assets/{money-graph-arrow-increase.svg-C16MfYnR.js → money-graph-arrow-increase.svg-jewlEZEL.js} +1 -1
- package/web/assets/{money-graph-bar-chart-increase.svg-BGG0yv-f.js → money-graph-bar-chart-increase.svg-BChD8dZv.js} +1 -1
- package/web/assets/multiselect-CoRzeHvy.js +251 -0
- package/web/assets/{nature-ecology-leaf.svg-DiIaC6NX.js → nature-ecology-leaf.svg-AQimnw3F.js} +1 -1
- package/web/assets/{password-BZlCIV8S.js → password-4Ykb_Ejn.js} +4 -4
- package/web/assets/{phone-telephone.svg-udmmRh0q.js → phone-telephone.svg-BdkwIhmo.js} +1 -1
- package/web/assets/{plus-CwmVHUki.js → plus-CYVYZlQL.js} +6 -6
- package/web/assets/process.store-CtXpHndZ.js +1 -0
- package/web/assets/{programming-bug.svg-xc1RtL3c.js → programming-bug.svg-DzT817WD.js} +1 -1
- package/web/assets/{programming-cloud.svg-axQALbJB.js → programming-cloud.svg-eKZD46YP.js} +1 -1
- package/web/assets/{programming-computer-database-server.svg-BVTqxH42.js → programming-computer-database-server.svg-BXOhjcQy.js} +1 -1
- package/web/assets/{programming-computer-database.svg-B-CECn7V.js → programming-computer-database.svg-DUzhimFY.js} +1 -1
- package/web/assets/{programming-module-four-layout.svg-icO9mDmE.js → programming-module-four-layout.svg-CYGX7Rlj.js} +1 -1
- package/web/assets/{programming-module-three.svg-D2zllUcw.js → programming-module-three.svg-BhQr1m-R.js} +1 -1
- package/web/assets/{programming-module.svg-gs4eO8gC.js → programming-module.svg-Bik697Ne.js} +1 -1
- package/web/assets/{programming-script-code.svg-BGMrS9je.js → programming-script-code.svg-BaTanEvH.js} +1 -1
- package/web/assets/{python-C1ZGhTnT.js → python-wDvaXe-V.js} +1 -1
- package/web/assets/{razor-Dxwwpjwp.js → razor-C-cEFJP1.js} +1 -1
- package/web/assets/router-CqYmBKhe.js +1 -0
- package/web/assets/settings-scope-DD7SbjFz.js +1 -0
- package/web/assets/settings.store-DcQmvBBv.js +1 -0
- package/web/assets/{shopping-cart.svg-DajW_J8z.js → shopping-cart.svg-BwUFrGEq.js} +1 -1
- package/web/assets/{shopping-gift-present.svg-yAHWXZYl.js → shopping-gift-present.svg-Bs4b94QF.js} +1 -1
- package/web/assets/{shopping-shipping-box-parcel-package.svg-BmpCCkbe.js → shopping-shipping-box-parcel-package.svg-DhVaYapE.js} +1 -1
- package/web/assets/{src-CabNenEM.js → src-CpoqK21I.js} +13 -13
- package/web/assets/src-De5rZb3_.js +1 -0
- package/web/assets/src-NB2ZR0ON.js +572 -0
- package/web/assets/tabpanel-DMt8G5AA.js +150 -0
- package/web/assets/{tag-new-circle.svg-BHHc5iei.js → tag-new-circle.svg-B4Z8uL1_.js} +1 -1
- package/web/assets/{toggleswitch-CJCNFliH.js → toggleswitch-CawhRFb7.js} +2 -2
- package/web/assets/{travel-map-earth-globe.svg-CHj70cli.js → travel-map-earth-globe.svg-D0s5cc-W.js} +1 -1
- package/web/assets/trpc-B17uPEkC.js +1 -0
- package/web/assets/{tsMode-DHXchBsw.js → tsMode-NHDuTjcd.js} +5 -5
- package/web/assets/{typescript-BVTudzDT.js → typescript-DGkgFTtn.js} +1 -1
- package/web/assets/useAiChatDrawer-BxE6EYFc.js +1 -0
- package/web/assets/{useCloudOrg-BN-OgVim.js → useCloudOrg-BJTjZPZ9.js} +1 -1
- package/web/assets/useProjectCatalog-DifZyVY5.js +1 -0
- package/web/assets/useProjectCloudOrg-EvyyjH6E.js +1 -0
- package/web/assets/{xml-5T1ybYUZ.js → xml-CJaXEqLW.js} +1 -1
- package/web/assets/{yaml-w_H4D4RN.js → yaml-bl8i8xOf.js} +1 -1
- package/web/index.html +2 -2
- package/agent-manager-SNVPZNLC.js +0 -8
- package/chat-RWOZHXBX.js +0 -18
- package/chunk-BHLCBARP.js.map +0 -1
- package/chunk-NDO5VFZY.js.map +0 -1
- package/chunk-SP3IC2TR.js.map +0 -1
- package/chunk-TNBMCKQX.js.map +0 -1
- package/desktop-launcher-FHNURZA7.js.map +0 -1
- package/node-B4T3JMM3.js.map +0 -1
- package/settings-manager-YHQ5YHUH.js +0 -8
- package/src-PF23DMAB.js.map +0 -1
- package/web/assets/AgentScalarChatInterface.vue-CpCuXAXu.js +0 -13
- package/web/assets/AgentTerminalPage-D8nMHtlG.js +0 -1
- package/web/assets/AiChatPage-C1FbL-Tb.js +0 -1
- package/web/assets/AppLayout-Dq-1shm9.js +0 -1
- package/web/assets/AuditPage-BjeeYf1P.js +0 -1
- package/web/assets/CloudAccountPage-BWcXUmZ3.js +0 -1
- package/web/assets/CloudAccountPage-CsNnjZQN.js +0 -1
- package/web/assets/CloudMessagingPage-CN-Hkvzf.js +0 -2
- package/web/assets/DashboardPage-30yBzA9Y.js +0 -1
- package/web/assets/DirectoryPickerDialog-BsYJrTG4.js +0 -1
- package/web/assets/EnvironmentFormPage-BETc1RGi.js +0 -1
- package/web/assets/EnvironmentListPage-CC0Sj1bx.js +0 -1
- package/web/assets/KanbanBoardPage-BdM0Op1M.js +0 -4
- package/web/assets/KanbanListPage-DM7RJqhx.js +0 -1
- package/web/assets/LaunchProjectPage-DXqYYycZ.js +0 -1
- package/web/assets/LaunchServicesPage-DCgwv5Pt.js +0 -1
- package/web/assets/LogViewer-CFSU-CNC.js +0 -3
- package/web/assets/OrgKeyPrompt-DQGyKSjb.js +0 -1
- package/web/assets/ProcessControls-98bxX4aW.js +0 -1
- package/web/assets/ProcessDetailPage-Bb_3RScY.js +0 -1
- package/web/assets/ProjectDetailPage-BNmbecE0.js +0 -1
- package/web/assets/ProjectListPage-v0JqfkPz.js +0 -1
- package/web/assets/RandomJobTestPage-D8q-EREO.js +0 -2
- package/web/assets/ScenarioEditorPage-D3EuMMBn.js +0 -14
- package/web/assets/SendToChatDialog-D-x5Pn3F.js +0 -1
- package/web/assets/ServiceControlsBar-7zKkkVxM.js +0 -1
- package/web/assets/ServiceDetailPage-jzYoqD5E.js +0 -2
- package/web/assets/ServiceFormPage-DjvOpPyE.js +0 -1
- package/web/assets/SettingsPage-C-OfBHjn.css +0 -1
- package/web/assets/SettingsPage-DKCbzYvF.js +0 -2063
- package/web/assets/UnlockPage-Cb43bz4p.js +0 -1
- package/web/assets/VariablesTable-C3syeLAl.js +0 -1
- package/web/assets/VaultMigrationPage-Cp-au3d7.js +0 -1
- package/web/assets/VersionBadge-CXX3tlKI.js +0 -1
- package/web/assets/WikiPage-D1at3ltm.js +0 -1
- package/web/assets/WikiView-ClZwZbal.js +0 -1
- package/web/assets/add-scalar-classes-D3kr5_fn.js +0 -387
- package/web/assets/card-q6s0jc6V.js +0 -32
- package/web/assets/client-BC-o8Mr9.js +0 -24
- package/web/assets/cloud-chat.store-387arRb5.js +0 -1
- package/web/assets/cloud-session-yejC3TfS.js +0 -1
- package/web/assets/column-ClizzdF5.js +0 -907
- package/web/assets/interface-content-folder.svg-BYgaYshM.js +0 -1
- package/web/assets/modal-4qFfZ_TY.js +0 -1
- package/web/assets/modal-TVJrDDCj.js +0 -5
- package/web/assets/multiselect-DcAoSG6S.js +0 -251
- package/web/assets/process.store-C8qfdRYx.js +0 -1
- package/web/assets/router-HZS_HREn.js +0 -1
- package/web/assets/settings-scope-DUmfNusx.js +0 -1
- package/web/assets/settings.store-Da4jL17l.js +0 -1
- package/web/assets/src-C-5koINO.js +0 -1
- package/web/assets/src-LFVDgykP.js +0 -572
- package/web/assets/tabpanel-D8XwziwN.js +0 -150
- package/web/assets/trpc-BeVJWlZK.js +0 -1
- package/web/assets/useAiChatDrawer-CFqm3BZi.js +0 -1
- package/web/assets/useProjectCatalog-sUfCxDEh.js +0 -1
- package/web/assets/useProjectCloudOrg-D1GcLai_.js +0 -1
- /package/{agent-manager-SNVPZNLC.js.map → agent-manager-OWHTBG46.js.map} +0 -0
- /package/{chat-RWOZHXBX.js.map → chat-JZ4UQDWV.js.map} +0 -0
- /package/{companion-QNW7XA6X.js.map → companion-6J6NK7H7.js.map} +0 -0
- /package/{settings-manager-YHQ5YHUH.js.map → instances-command-KZ5UGXOR.js.map} +0 -0
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
-
SchemaVersionSchema,
|
|
3
|
-
SettingsPrivateSchema,
|
|
4
|
-
SettingsSchema,
|
|
5
2
|
env,
|
|
6
3
|
legacyMachineFilePath,
|
|
7
4
|
machineFilePath,
|
|
8
5
|
machineRoot,
|
|
9
6
|
orgVaultRoot
|
|
10
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-KY6KYSOU.js";
|
|
8
|
+
import {
|
|
9
|
+
SchemaVersionSchema,
|
|
10
|
+
SettingsPrivateSchema,
|
|
11
|
+
SettingsSchema
|
|
12
|
+
} from "./chunk-QRMG6GMX.js";
|
|
11
13
|
|
|
12
14
|
// ../server/src/services/settings-manager.ts
|
|
13
15
|
import { readFile, writeFile, rename, mkdir, chmod } from "fs/promises";
|
|
@@ -149,4 +151,4 @@ var settingsManager = new SettingsManager();
|
|
|
149
151
|
export {
|
|
150
152
|
settingsManager
|
|
151
153
|
};
|
|
152
|
-
//# sourceMappingURL=chunk-
|
|
154
|
+
//# sourceMappingURL=chunk-Z67WBWKD.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../server/src/services/settings-manager.ts"],"sourcesContent":["import { readFile, writeFile, rename, mkdir, chmod } from 'node:fs/promises';\nimport { env } from '../config/env.js';\nimport { join } from 'node:path';\nimport { machineFilePath, legacyMachineFilePath, machineRoot, orgVaultRoot } from './vault-resolver.js';\nimport { SettingsSchema, SchemaVersionSchema, SettingsPrivateSchema } from '@runeya/packages-shared';\nimport type { Settings, SchemaVersion, SettingsPrivate } from '@runeya/packages-shared';\n\nconst SETTINGS_FILE = 'settings.json';\nconst SETTINGS_PRIVATE_FILE = 'settings.private.json';\nconst SCHEMA_VERSION_FILE = 'schema-version.json';\nconst CURRENT_SCHEMA_VERSION = 4;\n\n/**\n * Les réglages vivent dans le coffre de ce qu'ils configurent.\n *\n * Ils étaient au niveau machine — un fichier pour tout le poste — alors qu'ils\n * décrivent des choses qui appartiennent à des organisations différentes : les\n * fournisseurs d'IA qui paient le travail d'une équipe, les scénarios qui\n * décrivent ses services. Un réglage global obligeait donc à partager la clé\n * machine pour partager un secret d'organisation.\n *\n * `vault` désigne le coffre : l'identifiant d'une organisation, ou l'absence\n * pour le répertoire de lancement — celui d'un projet local, qui n'appartient à\n * personne d'autre. Rien ne reste au niveau machine sinon la session cloud,\n * irréductible puisque c'est elle qui donne accès aux organisations.\n */\nclass SettingsManager {\n private settings = new Map<string, Settings>();\n private settingsPrivate = new Map<string, SettingsPrivate>();\n private schemaVersion: SchemaVersion | null = null;\n\n /**\n * Le coffre visé, sous forme de racine sur le disque.\n *\n * Sans organisation, la racine machine — pas le répertoire de lancement. Ce\n * n'est pas un reste de l'ancien monde : y écrire forcerait un `.runeya` à\n * exister chez quelqu'un qui ne travaille que sur des projets cloud, ce que\n * les coffres ont justement supprimé (et ce qu'un test garde).\n */\n private rootOf(vault?: string): string {\n return vault ? orgVaultRoot(vault) : machineRoot();\n }\n\n private cacheKey(vault?: string): string {\n return vault ?? '';\n }\n\n private async atomicWrite(filename: string, data: unknown, vault?: string): Promise<void> {\n const root = this.rootOf(vault);\n await mkdir(root, { recursive: true });\n const filePath = join(root, filename);\n const tmpPath = filePath + '.tmp';\n await writeFile(tmpPath, JSON.stringify(data, null, 2), 'utf-8');\n await rename(tmpPath, filePath);\n await chmod(filePath, 0o600);\n }\n\n /**\n * Lire le fichier de CE coffre, et rien d'autre.\n *\n * Pas de repli sur un autre emplacement : un réglage lu ailleurs que là où il\n * est écrit fait deux vérités pour un même fait, et l'accord entre les deux\n * devient une chose de plus à tenir. Ce que les versions précédentes ont\n * écrit ailleurs est déplacé une fois pour toutes par\n * `migrateSettingsIntoVaults`, pas relu indéfiniment.\n */\n private async readJson<T>(filename: string, vault?: string): Promise<T | null> {\n try {\n return JSON.parse(await readFile(join(this.rootOf(vault), filename), 'utf-8')) as T;\n } catch {\n return null;\n }\n }\n\n /** Vide les caches — après un déplacement de fichiers sous nos pieds. */\n forget(): void {\n this.settings.clear();\n this.settingsPrivate.clear();\n }\n\n /** Un fichier qui appartient au poste, pas à un coffre. */\n private async readMachineJson<T>(filename: string): Promise<T | null> {\n for (const path of [machineFilePath(filename), legacyMachineFilePath(filename)]) {\n try {\n return JSON.parse(await readFile(path, 'utf-8')) as T;\n } catch {\n // Try the next location.\n }\n }\n return null;\n }\n\n async getSettings(vault?: string): Promise<Settings> {\n const key = this.cacheKey(vault);\n let current = this.settings.get(key);\n if (!current) {\n const raw = await this.readJson<unknown>(SETTINGS_FILE, vault);\n const parsed = raw ? SettingsSchema.safeParse(raw) : null;\n if (parsed?.success) {\n current = parsed.data;\n this.settings.set(key, current);\n } else {\n current = SettingsSchema.parse({ mode: env.MODE, cloudUrl: env.CLOUD_URL ?? null });\n await this.saveSettings(current, vault);\n }\n }\n return current;\n }\n\n async saveSettings(settings: Settings, vault?: string): Promise<void> {\n this.settings.set(this.cacheKey(vault), settings);\n await this.atomicWrite(SETTINGS_FILE, settings, vault);\n }\n\n async getPrivateSettings(vault?: string): Promise<SettingsPrivate> {\n const key = this.cacheKey(vault);\n let current = this.settingsPrivate.get(key);\n if (!current) {\n const raw = await this.readJson<unknown>(SETTINGS_PRIVATE_FILE, vault);\n const parsed = raw ? SettingsPrivateSchema.safeParse(raw) : null;\n if (parsed?.success) {\n current = parsed.data;\n this.settingsPrivate.set(key, current);\n } else {\n current = SettingsPrivateSchema.parse({});\n await this.savePrivateSettings(current, vault);\n }\n }\n return current;\n }\n\n async savePrivateSettings(settings: SettingsPrivate, vault?: string): Promise<void> {\n this.settingsPrivate.set(this.cacheKey(vault), settings);\n await this.atomicWrite(SETTINGS_PRIVATE_FILE, settings, vault);\n }\n\n /**\n * La version de schéma reste au niveau machine, et ce n'est pas un oubli :\n * elle ne configure rien, elle date les migrations des données de ce poste.\n */\n async getSchemaVersion(): Promise<SchemaVersion> {\n if (!this.schemaVersion) {\n const raw = await this.readMachineJson<unknown>(SCHEMA_VERSION_FILE);\n const parsed = raw ? SchemaVersionSchema.safeParse(raw) : null;\n if (parsed?.success) {\n this.schemaVersion = parsed.data;\n } else {\n this.schemaVersion = { version: CURRENT_SCHEMA_VERSION, migratedAt: new Date() };\n await this.saveSchemaVersion(this.schemaVersion);\n }\n }\n return this.schemaVersion;\n }\n\n async saveSchemaVersion(sv: SchemaVersion): Promise<void> {\n this.schemaVersion = sv;\n await mkdir(machineRoot(), { recursive: true });\n const filePath = machineFilePath(SCHEMA_VERSION_FILE);\n const tmpPath = filePath + '.tmp';\n await writeFile(tmpPath, JSON.stringify(sv, null, 2), 'utf-8');\n await rename(tmpPath, filePath);\n await chmod(filePath, 0o600);\n }\n\n getCurrentSchemaVersion(): number {\n return CURRENT_SCHEMA_VERSION;\n }\n}\n\nexport const settingsManager = new SettingsManager();\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../server/src/services/settings-manager.ts"],"sourcesContent":["import { readFile, writeFile, rename, mkdir, chmod } from 'node:fs/promises';\nimport { env } from '../config/env.js';\nimport { join } from 'node:path';\nimport { machineFilePath, legacyMachineFilePath, machineRoot, orgVaultRoot } from './vault-resolver.js';\nimport { SettingsSchema, SchemaVersionSchema, SettingsPrivateSchema } from '@runeya/packages-shared';\nimport type { Settings, SchemaVersion, SettingsPrivate } from '@runeya/packages-shared';\n\nconst SETTINGS_FILE = 'settings.json';\nconst SETTINGS_PRIVATE_FILE = 'settings.private.json';\nconst SCHEMA_VERSION_FILE = 'schema-version.json';\nconst CURRENT_SCHEMA_VERSION = 4;\n\n/**\n * Les réglages vivent dans le coffre de ce qu'ils configurent.\n *\n * Ils étaient au niveau machine — un fichier pour tout le poste — alors qu'ils\n * décrivent des choses qui appartiennent à des organisations différentes : les\n * fournisseurs d'IA qui paient le travail d'une équipe, les scénarios qui\n * décrivent ses services. Un réglage global obligeait donc à partager la clé\n * machine pour partager un secret d'organisation.\n *\n * `vault` désigne le coffre : l'identifiant d'une organisation, ou l'absence\n * pour le répertoire de lancement — celui d'un projet local, qui n'appartient à\n * personne d'autre. Rien ne reste au niveau machine sinon la session cloud,\n * irréductible puisque c'est elle qui donne accès aux organisations.\n */\nclass SettingsManager {\n private settings = new Map<string, Settings>();\n private settingsPrivate = new Map<string, SettingsPrivate>();\n private schemaVersion: SchemaVersion | null = null;\n\n /**\n * Le coffre visé, sous forme de racine sur le disque.\n *\n * Sans organisation, la racine machine — pas le répertoire de lancement. Ce\n * n'est pas un reste de l'ancien monde : y écrire forcerait un `.runeya` à\n * exister chez quelqu'un qui ne travaille que sur des projets cloud, ce que\n * les coffres ont justement supprimé (et ce qu'un test garde).\n */\n private rootOf(vault?: string): string {\n return vault ? orgVaultRoot(vault) : machineRoot();\n }\n\n private cacheKey(vault?: string): string {\n return vault ?? '';\n }\n\n private async atomicWrite(filename: string, data: unknown, vault?: string): Promise<void> {\n const root = this.rootOf(vault);\n await mkdir(root, { recursive: true });\n const filePath = join(root, filename);\n const tmpPath = filePath + '.tmp';\n await writeFile(tmpPath, JSON.stringify(data, null, 2), 'utf-8');\n await rename(tmpPath, filePath);\n await chmod(filePath, 0o600);\n }\n\n /**\n * Lire le fichier de CE coffre, et rien d'autre.\n *\n * Pas de repli sur un autre emplacement : un réglage lu ailleurs que là où il\n * est écrit fait deux vérités pour un même fait, et l'accord entre les deux\n * devient une chose de plus à tenir. Ce que les versions précédentes ont\n * écrit ailleurs est déplacé une fois pour toutes par\n * `migrateSettingsIntoVaults`, pas relu indéfiniment.\n */\n private async readJson<T>(filename: string, vault?: string): Promise<T | null> {\n try {\n return JSON.parse(await readFile(join(this.rootOf(vault), filename), 'utf-8')) as T;\n } catch {\n return null;\n }\n }\n\n /** Vide les caches — après un déplacement de fichiers sous nos pieds. */\n forget(): void {\n this.settings.clear();\n this.settingsPrivate.clear();\n }\n\n /** Un fichier qui appartient au poste, pas à un coffre. */\n private async readMachineJson<T>(filename: string): Promise<T | null> {\n for (const path of [machineFilePath(filename), legacyMachineFilePath(filename)]) {\n try {\n return JSON.parse(await readFile(path, 'utf-8')) as T;\n } catch {\n // Try the next location.\n }\n }\n return null;\n }\n\n async getSettings(vault?: string): Promise<Settings> {\n const key = this.cacheKey(vault);\n let current = this.settings.get(key);\n if (!current) {\n const raw = await this.readJson<unknown>(SETTINGS_FILE, vault);\n const parsed = raw ? SettingsSchema.safeParse(raw) : null;\n if (parsed?.success) {\n current = parsed.data;\n this.settings.set(key, current);\n } else {\n current = SettingsSchema.parse({ mode: env.MODE, cloudUrl: env.CLOUD_URL ?? null });\n await this.saveSettings(current, vault);\n }\n }\n return current;\n }\n\n async saveSettings(settings: Settings, vault?: string): Promise<void> {\n this.settings.set(this.cacheKey(vault), settings);\n await this.atomicWrite(SETTINGS_FILE, settings, vault);\n }\n\n async getPrivateSettings(vault?: string): Promise<SettingsPrivate> {\n const key = this.cacheKey(vault);\n let current = this.settingsPrivate.get(key);\n if (!current) {\n const raw = await this.readJson<unknown>(SETTINGS_PRIVATE_FILE, vault);\n const parsed = raw ? SettingsPrivateSchema.safeParse(raw) : null;\n if (parsed?.success) {\n current = parsed.data;\n this.settingsPrivate.set(key, current);\n } else {\n current = SettingsPrivateSchema.parse({});\n await this.savePrivateSettings(current, vault);\n }\n }\n return current;\n }\n\n async savePrivateSettings(settings: SettingsPrivate, vault?: string): Promise<void> {\n this.settingsPrivate.set(this.cacheKey(vault), settings);\n await this.atomicWrite(SETTINGS_PRIVATE_FILE, settings, vault);\n }\n\n /**\n * La version de schéma reste au niveau machine, et ce n'est pas un oubli :\n * elle ne configure rien, elle date les migrations des données de ce poste.\n */\n async getSchemaVersion(): Promise<SchemaVersion> {\n if (!this.schemaVersion) {\n const raw = await this.readMachineJson<unknown>(SCHEMA_VERSION_FILE);\n const parsed = raw ? SchemaVersionSchema.safeParse(raw) : null;\n if (parsed?.success) {\n this.schemaVersion = parsed.data;\n } else {\n this.schemaVersion = { version: CURRENT_SCHEMA_VERSION, migratedAt: new Date() };\n await this.saveSchemaVersion(this.schemaVersion);\n }\n }\n return this.schemaVersion;\n }\n\n async saveSchemaVersion(sv: SchemaVersion): Promise<void> {\n this.schemaVersion = sv;\n await mkdir(machineRoot(), { recursive: true });\n const filePath = machineFilePath(SCHEMA_VERSION_FILE);\n const tmpPath = filePath + '.tmp';\n await writeFile(tmpPath, JSON.stringify(sv, null, 2), 'utf-8');\n await rename(tmpPath, filePath);\n await chmod(filePath, 0o600);\n }\n\n getCurrentSchemaVersion(): number {\n return CURRENT_SCHEMA_VERSION;\n }\n}\n\nexport const settingsManager = new SettingsManager();\n"],"mappings":"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","names":[]}
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
MAX_CONSECUTIVE_RELAUNCHES,
|
|
4
4
|
buildCompanionPrompt,
|
|
5
5
|
buildRelaunchMessage,
|
|
6
|
+
companionAgentId,
|
|
6
7
|
companionDefaultPrompt,
|
|
7
8
|
companionSettings,
|
|
8
9
|
companionSystemNote,
|
|
@@ -20,15 +21,17 @@ import {
|
|
|
20
21
|
resetRelaunches,
|
|
21
22
|
reviewWindow,
|
|
22
23
|
takeRelaunchSlot
|
|
23
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-NZNIWJDT.js";
|
|
25
|
+
import "./chunk-QIBUMYR6.js";
|
|
26
|
+
import "./chunk-KY6KYSOU.js";
|
|
27
|
+
import "./chunk-QRMG6GMX.js";
|
|
24
28
|
import "./chunk-MD3VW4HQ.js";
|
|
25
|
-
import "./chunk-BHLCBARP.js";
|
|
26
|
-
import "./chunk-NDO5VFZY.js";
|
|
27
29
|
export {
|
|
28
30
|
COMPANION_SIGNATURE,
|
|
29
31
|
MAX_CONSECUTIVE_RELAUNCHES,
|
|
30
32
|
buildCompanionPrompt,
|
|
31
33
|
buildRelaunchMessage,
|
|
34
|
+
companionAgentId,
|
|
32
35
|
companionDefaultPrompt,
|
|
33
36
|
companionSettings,
|
|
34
37
|
companionSystemNote,
|
|
@@ -47,4 +50,4 @@ export {
|
|
|
47
50
|
reviewWindow,
|
|
48
51
|
takeRelaunchSlot
|
|
49
52
|
};
|
|
50
|
-
//# sourceMappingURL=companion-
|
|
53
|
+
//# sourceMappingURL=companion-6J6NK7H7.js.map
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deriveLauncherIdentity,
|
|
3
|
+
launcherIdFromName,
|
|
4
|
+
slugifyLauncherName
|
|
5
|
+
} from "./chunk-QRMG6GMX.js";
|
|
6
|
+
|
|
1
7
|
// src/desktop-launcher.ts
|
|
2
8
|
import { mkdir, writeFile, rm, copyFile, access } from "fs/promises";
|
|
3
9
|
import { execFile } from "child_process";
|
|
4
10
|
import { promisify } from "util";
|
|
5
11
|
import { homedir } from "os";
|
|
6
|
-
import { join,
|
|
12
|
+
import { join, dirname } from "path";
|
|
7
13
|
var exec = promisify(execFile);
|
|
8
14
|
function launcherArgs(opts) {
|
|
9
15
|
const args = ["--from-desktop"];
|
|
@@ -13,21 +19,9 @@ function launcherArgs(opts) {
|
|
|
13
19
|
}
|
|
14
20
|
return args;
|
|
15
21
|
}
|
|
16
|
-
function slugify(name) {
|
|
17
|
-
const slug = name.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
18
|
-
return slug || "runeya";
|
|
19
|
-
}
|
|
20
|
-
function idFromName(name) {
|
|
21
|
-
const slug = slugify(name);
|
|
22
|
-
return slug.startsWith("runeya") ? slug : `runeya-${slug}`;
|
|
23
|
-
}
|
|
24
22
|
function launcherWorkingDir(workingDir) {
|
|
25
23
|
return workingDir ?? homedir();
|
|
26
24
|
}
|
|
27
|
-
function deriveIdentity(explicitName, workingDir) {
|
|
28
|
-
const name = explicitName ?? (workingDir ? `Runeya \u2014 ${basename(workingDir)}` : "Runeya");
|
|
29
|
-
return { name, id: idFromName(name) };
|
|
30
|
-
}
|
|
31
25
|
async function exists(path) {
|
|
32
26
|
try {
|
|
33
27
|
await access(path);
|
|
@@ -272,16 +266,16 @@ async function uninstallDesktopLauncher(name, id) {
|
|
|
272
266
|
}
|
|
273
267
|
}
|
|
274
268
|
export {
|
|
275
|
-
deriveIdentity,
|
|
269
|
+
deriveLauncherIdentity as deriveIdentity,
|
|
276
270
|
desktopExecQuote,
|
|
277
|
-
idFromName,
|
|
271
|
+
launcherIdFromName as idFromName,
|
|
278
272
|
installDesktopLauncher,
|
|
279
273
|
launcherArgs,
|
|
280
274
|
launcherWorkingDir,
|
|
281
275
|
psQuote,
|
|
282
|
-
slugify,
|
|
276
|
+
slugifyLauncherName as slugify,
|
|
283
277
|
uninstallDesktopLauncher,
|
|
284
278
|
vbsQuote,
|
|
285
279
|
windowsVbsScript
|
|
286
280
|
};
|
|
287
|
-
//# sourceMappingURL=desktop-launcher-
|
|
281
|
+
//# sourceMappingURL=desktop-launcher-N7WRF3LC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/desktop-launcher.ts"],"sourcesContent":["/**\n * Cross-platform desktop launcher (`runeya install-desktop`).\n *\n * Deliberately an explicit sub-command rather than a postinstall hook: npm 12\n * blocks lifecycle scripts by default, so a launcher created that way would be\n * silently missing. Here the user asks for it, and gets the paths back.\n *\n * Nothing is embedded — the launcher points at the Node binary and the CLI\n * entry point currently in use. If the user switches Node version manager,\n * re-running the command re-pins the paths.\n */\nimport { mkdir, writeFile, rm, copyFile, access } from 'node:fs/promises';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { homedir } from 'node:os';\nimport { join, dirname } from 'node:path';\n\nimport {\n slugifyLauncherName,\n launcherIdFromName,\n deriveLauncherIdentity,\n} from '@runeya/packages-shared';\n\nconst exec = promisify(execFile);\n\n/**\n * Le nommage d'un lanceur vit dans `packages/shared` : le serveur en a besoin\n * pour proposer le même nom depuis l'interface. Réexporté ici sous les noms\n * locaux, qui sont ceux que le reste du CLI appelle.\n */\nexport {\n slugifyLauncherName as slugify,\n launcherIdFromName as idFromName,\n deriveLauncherIdentity as deriveIdentity,\n};\n\nexport type InstallOptions = {\n /** Absolute path to the Node binary the launcher must use. */\n nodePath: string;\n /** Absolute path to the CLI entry point (dist/index.js). */\n cliEntry: string;\n /** Directory holding the CLI dist — used to find the bundled icons in assets/. */\n distDir: string;\n /** Working directory to pin, or null to let the desktop decide. */\n workingDir: string | null;\n /** Display name, e.g. \"Runeya\" or \"Runeya — my-stack\". */\n name: string;\n /** Filesystem-safe id derived from the name, e.g. \"runeya-my-stack\". */\n id: string;\n /** Port baked into the launcher, or null to follow Runeya's default. */\n port: number | null;\n /** Agent port, or null to let Runeya derive it from `port + 1`. */\n agentPort: number | null;\n};\n\n/**\n * Arguments the launcher passes to the CLI.\n *\n * `--agent-port` is omitted when it is exactly what Runeya would derive on its\n * own, so the command line stays readable and keeps following the derivation\n * if it ever changes.\n */\nexport function launcherArgs(opts: Pick<InstallOptions, 'port' | 'agentPort'>): string[] {\n const args = ['--from-desktop'];\n if (opts.port !== null) args.push('--port', String(opts.port));\n if (opts.agentPort !== null && opts.agentPort !== (opts.port ?? 4000) + 1) {\n args.push('--agent-port', String(opts.agentPort));\n }\n return args;\n}\n\nexport type LauncherResult = {\n /** Files created or removed, for reporting back to the user. */\n paths: string[];\n /** Non-fatal problems (missing icon, desktop database refresh failed…). */\n warnings: string[];\n};\n\n/**\n * Le dossier de travail d'un lanceur, avec un repli qui n'est jamais la racine.\n *\n * Sans dossier épinglé, un lanceur hérite du cwd du système — `/` pour le\n * Finder comme pour systemd — et Runeya y placerait son `.runeya`. La racine\n * est en lecture seule sous macOS et interdite d'écriture sous Linux : le home\n * est le seul repli toujours disponible. Le CLI applique la même garde à\n * l'exécution, pour les lanceurs posés avant ce correctif.\n */\nexport function launcherWorkingDir(workingDir: string | null): string {\n return workingDir ?? homedir();\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Best-effort command: never fails the install, just reports a warning. */\nasync function tryExec(file: string, args: string[], warnings: string[]): Promise<void> {\n try {\n await exec(file, args);\n } catch {\n warnings.push(`Commande optionnelle échouée : ${file} (le lanceur est créé, le menu peut mettre un instant à l'afficher)`);\n }\n}\n\n// ─── Linux ───────────────────────────────────────────────────────────────────\n\n/**\n * Quote a value for the `Exec=` key of a .desktop file.\n * Per the Desktop Entry spec, inside a quoted argument the characters\n * `\"`, backtick, `$` and `\\` must each be preceded by a backslash.\n */\nexport function desktopExecQuote(value: string): string {\n return `\"${value.replace(/[\"`$\\\\]/g, (c) => `\\\\${c}`)}\"`;\n}\n\n/** Escape a value for a non-Exec .desktop key (only backslashes are special). */\nfunction desktopValue(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\\n/g, ' ');\n}\n\nfunction xdgDataHome(): string {\n return process.env['XDG_DATA_HOME'] || join(homedir(), '.local/share');\n}\n\nfunction linuxPaths(id: string) {\n const dataHome = xdgDataHome();\n const appsDir = join(dataHome, 'applications');\n return {\n appsDir,\n entry: join(appsDir, `${id}.desktop`),\n iconDir: join(dataHome, 'icons/hicolor/scalable/apps'),\n icon: join(dataHome, `icons/hicolor/scalable/apps/${id}.svg`),\n };\n}\n\nasync function installLinux(opts: InstallOptions): Promise<LauncherResult> {\n const paths: string[] = [];\n const warnings: string[] = [];\n const p = linuxPaths(opts.id);\n\n // The icon is an SVG, which the scalable hicolor directory takes as-is.\n const sourceIcon = join(opts.distDir, 'assets/icon.svg');\n let iconName = 'application-x-executable';\n if (await exists(sourceIcon)) {\n await mkdir(p.iconDir, { recursive: true });\n await copyFile(sourceIcon, p.icon);\n paths.push(p.icon);\n iconName = opts.id;\n } else {\n warnings.push(`Icône introuvable (${sourceIcon}), icône générique utilisée`);\n }\n\n // --from-desktop: nobody is watching a terminal, so startup failures must be\n // reported in a browser window rather than written to a discarded stderr.\n const exec_ = [opts.nodePath, opts.cliEntry, ...launcherArgs(opts)]\n .map(desktopExecQuote)\n .join(' ');\n const lines = [\n '[Desktop Entry]',\n 'Type=Application',\n `Name=${desktopValue(opts.name)}`,\n 'Comment=Process and service manager',\n `Exec=${exec_}`,\n `Icon=${iconName}`,\n 'Terminal=false',\n 'Categories=Development;',\n 'StartupNotify=true',\n // Marker used by uninstall-desktop to refuse deleting a hand-written entry\n 'X-Runeya-Managed=true',\n ];\n lines.push(`Path=${desktopValue(launcherWorkingDir(opts.workingDir))}`);\n\n await mkdir(p.appsDir, { recursive: true });\n await writeFile(p.entry, lines.join('\\n') + '\\n', { mode: 0o755 });\n paths.push(p.entry);\n\n await tryExec('update-desktop-database', [p.appsDir], warnings);\n\n return { paths, warnings };\n}\n\nasync function uninstallLinux(id: string): Promise<LauncherResult> {\n const paths: string[] = [];\n const warnings: string[] = [];\n const p = linuxPaths(id);\n for (const target of [p.entry, p.icon]) {\n if (await exists(target)) {\n await rm(target, { force: true });\n paths.push(target);\n }\n }\n if (paths.length) await tryExec('update-desktop-database', [p.appsDir], warnings);\n return { paths, warnings };\n}\n\n// ─── macOS ───────────────────────────────────────────────────────────────────\n\n/** Escape a value destined for a <string> node of an Info.plist. */\nfunction plistString(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n}\n\n/** Single-quote a value for the POSIX shell inside the .app stub script. */\nfunction shQuote(value: string): string {\n return `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\nfunction macAppPath(name: string): string {\n return join(homedir(), 'Applications', `${name}.app`);\n}\n\nasync function installMac(opts: InstallOptions): Promise<LauncherResult> {\n const warnings: string[] = [];\n const appPath = macAppPath(opts.name);\n const macosDir = join(appPath, 'Contents/MacOS');\n const resourcesDir = join(appPath, 'Contents/Resources');\n const execName = opts.id;\n\n await mkdir(macosDir, { recursive: true });\n await mkdir(resourcesDir, { recursive: true });\n\n // The bundle executable is a shell stub: no compiled code, no signing needed.\n // A locally generated .app carries no quarantine attribute, so Gatekeeper\n // lets it run even unsigned.\n const stub = [\n '#!/bin/sh',\n '# Generated by `runeya install-desktop` — safe to delete.',\n `cd ${shQuote(launcherWorkingDir(opts.workingDir))} || exit 1`,\n `exec ${[opts.nodePath, opts.cliEntry, ...launcherArgs(opts)].map(shQuote).join(' ')} \"$@\"`,\n '',\n ].filter(Boolean).join('\\n');\n await writeFile(join(macosDir, execName), stub, { mode: 0o755 });\n\n // CFBundleIconFile is only emitted when the .icns actually made it into the\n // bundle — a key pointing at a missing file makes Finder fall back silently,\n // which is harder to diagnose than no key at all.\n const sourceIcns = join(opts.distDir, 'assets/icon.icns');\n let iconKey = '';\n if (await exists(sourceIcns)) {\n await copyFile(sourceIcns, join(resourcesDir, `${execName}.icns`));\n iconKey = `\\n <key>CFBundleIconFile</key><string>${plistString(execName)}</string>`;\n } else {\n warnings.push(`Icône introuvable (${sourceIcns}), icône générique utilisée`);\n }\n\n const plist = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>CFBundleName</key><string>${plistString(opts.name)}</string>\n <key>CFBundleDisplayName</key><string>${plistString(opts.name)}</string>\n <key>CFBundleExecutable</key><string>${plistString(execName)}</string>\n <key>CFBundleIdentifier</key><string>dev.runeya.launcher.${plistString(opts.id)}</string>\n <key>CFBundlePackageType</key><string>APPL</string>${iconKey}\n <key>CFBundleInfoDictionaryVersion</key><string>6.0</string>\n <key>CFBundleShortVersionString</key><string>1.0</string>\n <key>NSHighResolutionCapable</key><true/>\n</dict>\n</plist>\n`;\n await writeFile(join(appPath, 'Contents/Info.plist'), plist);\n\n // Ask LaunchServices to notice the new bundle so Spotlight finds it right away.\n await tryExec(\n '/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister',\n ['-f', appPath],\n warnings,\n );\n\n return { paths: [appPath], warnings };\n}\n\nasync function uninstallMac(name: string): Promise<LauncherResult> {\n const appPath = macAppPath(name);\n if (!(await exists(appPath))) return { paths: [], warnings: [] };\n await rm(appPath, { recursive: true, force: true });\n return { paths: [appPath], warnings: [] };\n}\n\n// ─── Windows ─────────────────────────────────────────────────────────────────\n\n/** Single-quote a value for a PowerShell literal string. */\nexport function psQuote(value: string): string {\n return `'${value.replace(/'/g, \"''\")}'`;\n}\n\nfunction windowsLnkPath(name: string): string {\n const appData = process.env['APPDATA'] || join(homedir(), 'AppData/Roaming');\n return join(appData, 'Microsoft/Windows/Start Menu/Programs', `${name}.lnk`);\n}\n\n/**\n * Où vit le script qui lance Runeya sans console.\n *\n * Hors du dossier du menu Démarrer — un `.vbs` posé là apparaîtrait dans la\n * recherche Windows à côté du raccourci — et hors du `dist` du paquet, qu'une\n * réinstallation npm remplace : le script y disparaîtrait sans que rien ne le\n * recrée, faute de postinstall (npm 12 les bloque).\n */\nfunction windowsVbsPath(id: string): string {\n const localAppData = process.env['LOCALAPPDATA'] || join(homedir(), 'AppData/Local');\n return join(localAppData, 'Runeya', `${id}.vbs`);\n}\n\n/** Double-quote a value for a VBScript string literal. */\nexport function vbsQuote(value: string): string {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n}\n\n/**\n * Le script qui lance Runeya **sans fenêtre**.\n *\n * `node.exe` est une application console : Windows lui alloue une console, et\n * un raccourci ne sait que la réduire (`WindowStyle = 7`) — d'où une fenêtre de\n * commande dans la barre des tâches pendant tout l'usage de l'application.\n *\n * `wscript.exe`, lui, est une application graphique : il n'ouvre aucune console\n * et lance sa cible en `SW_HIDE` (le `0` de `Run`). La console de Node existe\n * donc toujours — c'est ce qui compte : **elle est seulement cachée, pas\n * absente**, et tout ce que Runeya lance ensuite (l'agent, git, docker, les\n * services) l'hérite sans rien afficher. C'est la même intention que le\n * `windowsHide` des runners, posée une fois pour toute la descendance.\n *\n * Le `False` rend la main immédiatement : `wscript` sort, Runeya reste.\n */\nexport function windowsVbsScript(\n opts: Pick<InstallOptions, 'nodePath' | 'cliEntry' | 'port' | 'agentPort'> & { workingDir: string | null },\n): string {\n const command = [opts.nodePath, opts.cliEntry, ...launcherArgs(opts)]\n .map((part) => `\"${part}\"`)\n .join(' ');\n return [\n // Commentaires en ASCII : wscript lit un .vbs sans BOM comme de l'ANSI, et\n // des accents s'y afficheraient de travers à qui l'ouvre.\n \"' Runeya launcher - created by 'runeya install-desktop', do not edit.\",\n \"' wscript.exe opens no console; the 0 below starts Runeya hidden.\",\n 'Set sh = CreateObject(\"WScript.Shell\")',\n `sh.CurrentDirectory = ${vbsQuote(launcherWorkingDir(opts.workingDir))}`,\n `sh.Run ${vbsQuote(command)}, 0, False`,\n '',\n ].join('\\n');\n}\n\nasync function runPowerShell(script: string, warnings: string[]): Promise<void> {\n // -EncodedCommand avoids every layer of cmd.exe quoting.\n const encoded = Buffer.from(script, 'utf16le').toString('base64');\n try {\n await exec('powershell.exe', ['-NoProfile', '-NonInteractive', '-EncodedCommand', encoded]);\n } catch (err) {\n warnings.push(`PowerShell a échoué : ${(err as Error).message}`);\n throw err;\n }\n}\n\nasync function installWindows(opts: InstallOptions): Promise<LauncherResult> {\n const warnings: string[] = [];\n const lnk = windowsLnkPath(opts.name);\n\n // The .ico is referenced in place inside the installed dist rather than\n // copied: the shortcut already breaks if that dist moves, so a second copy\n // would only add a file to leave behind.\n const icoPath = join(opts.distDir, 'assets/icon.ico');\n const iconPath = (await exists(icoPath)) ? icoPath : null;\n if (!iconPath) warnings.push(`Icône introuvable (${icoPath}), icône de Node utilisée`);\n\n // Le raccourci ne lance pas Node : il lance `wscript.exe`, qui lance Node\n // sans console. Un raccourci pointant sur `node.exe` laissait une fenêtre de\n // commande dans la barre des tâches, `WindowStyle` ne sachant que la réduire.\n const vbs = windowsVbsPath(opts.id);\n await mkdir(dirname(vbs), { recursive: true });\n await writeFile(vbs, windowsVbsScript(opts), 'utf8');\n\n const wscript = join(process.env['SystemRoot'] || 'C:\\\\Windows', 'System32', 'wscript.exe');\n\n const script = [\n `$ws = New-Object -ComObject WScript.Shell`,\n `$sc = $ws.CreateShortcut(${psQuote(lnk)})`,\n `$sc.TargetPath = ${psQuote(wscript)}`,\n `$sc.Arguments = ${psQuote(`\"${vbs}\"`)}`,\n `$sc.WorkingDirectory = ${psQuote(launcherWorkingDir(opts.workingDir))}`,\n `$sc.Description = 'Runeya — process and service manager'`,\n // L'icône reste celle de Runeya : elle est déclarée à part de la cible.\n iconPath ? `$sc.IconLocation = ${psQuote(iconPath)}` : '',\n `$sc.Save()`,\n ].filter(Boolean).join('\\n');\n\n await mkdir(dirname(lnk), { recursive: true });\n await runPowerShell(script, warnings);\n\n return { paths: [lnk, vbs], warnings };\n}\n\nasync function uninstallWindows(name: string, id: string): Promise<LauncherResult> {\n // Les deux fichiers, et chacun pour lui-même : un raccourci posé avant que le\n // lanceur ne passe par `wscript` n'a pas de `.vbs` à côté de lui, et son\n // absence n'est pas une raison de laisser le raccourci en place.\n const removed: string[] = [];\n for (const path of [windowsLnkPath(name), windowsVbsPath(id)]) {\n if (!(await exists(path))) continue;\n await rm(path, { force: true });\n removed.push(path);\n }\n return { paths: removed, warnings: [] };\n}\n\n// ─── Entry points ────────────────────────────────────────────────────────────\n\nexport async function installDesktopLauncher(opts: InstallOptions): Promise<LauncherResult> {\n switch (process.platform) {\n case 'linux':\n case 'freebsd':\n case 'openbsd':\n return installLinux(opts);\n case 'darwin':\n return installMac(opts);\n case 'win32':\n return installWindows(opts);\n default:\n throw new Error(`Plateforme non supportée : ${process.platform}`);\n }\n}\n\nexport async function uninstallDesktopLauncher(name: string, id: string): Promise<LauncherResult> {\n switch (process.platform) {\n case 'linux':\n case 'freebsd':\n case 'openbsd':\n return uninstallLinux(id);\n case 'darwin':\n return uninstallMac(name);\n case 'win32':\n return uninstallWindows(name, id);\n default:\n throw new Error(`Plateforme non supportée : ${process.platform}`);\n }\n}\n"],"mappings":"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","names":[]}
|
package/index.js
CHANGED
|
@@ -84,7 +84,7 @@ for (const { flag, env: key } of ENV_FLAGS) {
|
|
|
84
84
|
if (args.includes("--debug")) process.env["RUNEYA_DEBUG"] = "1";
|
|
85
85
|
var subCommand = args[0];
|
|
86
86
|
if (subCommand === "install-desktop" || subCommand === "uninstall-desktop") {
|
|
87
|
-
const { installDesktopLauncher, uninstallDesktopLauncher, deriveIdentity } = await import("./desktop-launcher-
|
|
87
|
+
const { installDesktopLauncher, uninstallDesktopLauncher, deriveIdentity } = await import("./desktop-launcher-N7WRF3LC.js");
|
|
88
88
|
const { shouldRunWizard, runInstallWizard, printInstallReport, printUninstallReport } = await import("./desktop-wizard-4CYANX2O.js");
|
|
89
89
|
const { parsePort } = await import("./free-port-565NMFIZ.js");
|
|
90
90
|
const rest = args.slice(1);
|
|
@@ -134,6 +134,21 @@ if (subCommand === "install-desktop" || subCommand === "uninstall-desktop") {
|
|
|
134
134
|
process.exit(1);
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
|
+
if (subCommand === "instances") {
|
|
138
|
+
const { listInstances, killInstance, restartInstance } = await import("./src-V7DPPFCF.js");
|
|
139
|
+
const { runInstancesCommand } = await import("./instances-command-KZ5UGXOR.js");
|
|
140
|
+
process.exit(await runInstancesCommand(args.slice(1), {
|
|
141
|
+
listInstances,
|
|
142
|
+
stopInstance: killInstance,
|
|
143
|
+
restartInstance: async (pid) => {
|
|
144
|
+
const { pid: newPid, portReleased } = await restartInstance(pid);
|
|
145
|
+
return { pid: newPid, portReleased };
|
|
146
|
+
},
|
|
147
|
+
openUrl: (url) => open(url),
|
|
148
|
+
log: (message) => console.log(message),
|
|
149
|
+
warn: (message) => console.error(message)
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
137
152
|
var targetDir = args.find((a, i) => !a.startsWith("-") && !flagsWithValues.has(args[i - 1] ?? ""));
|
|
138
153
|
if (targetDir) {
|
|
139
154
|
const resolved = resolve(targetDir);
|
|
@@ -161,6 +176,9 @@ Commands:
|
|
|
161
176
|
--port <n> Port baked into the launcher (default: Runeya's own)
|
|
162
177
|
--agent-port <n> Agent port baked in (default: launcher port + 1)
|
|
163
178
|
-y, --yes Skip the wizard and take the defaults
|
|
179
|
+
instances [open|stop|restart <pid>]
|
|
180
|
+
List the Runeya running on this machine, and act on
|
|
181
|
+
one. --json for the raw records.
|
|
164
182
|
--from-desktop Set by desktop launchers: report startup failures
|
|
165
183
|
in a browser window instead of a silent exit
|
|
166
184
|
|
|
@@ -171,6 +189,7 @@ Options:
|
|
|
171
189
|
-s, --service <name> Service name or id
|
|
172
190
|
--lan Expose server on the local network (shortcut for --host 0.0.0.0)
|
|
173
191
|
--no-open Do not open browser on startup
|
|
192
|
+
--no-tray Do not put this instance in the system tray
|
|
174
193
|
--agent Run as agent only (no server, no UI) \u2014 for remote machines
|
|
175
194
|
-h, --help Show this help message
|
|
176
195
|
|
|
@@ -212,6 +231,7 @@ if (args.includes("--version")) {
|
|
|
212
231
|
console.log(version);
|
|
213
232
|
process.exit(0);
|
|
214
233
|
}
|
|
234
|
+
var noTray = args.includes("--no-tray");
|
|
215
235
|
var noOpen = args.includes("--no-open") || !!process.env["VITEST"] || !!process.env["CI"] || process.env["NODE_ENV"] === "test";
|
|
216
236
|
var isPullEnv = args.includes("--pull-env") || args.includes("--pe");
|
|
217
237
|
if (isPullEnv) {
|
|
@@ -275,11 +295,12 @@ function listenWithRetry(server, port, host, wss, maxRetries = 20, delay = 500)
|
|
|
275
295
|
});
|
|
276
296
|
}
|
|
277
297
|
async function main() {
|
|
278
|
-
const { ensureNodeBinOnPath, ensureUserBinsOnPath, stampConsole } = await import("./node-
|
|
298
|
+
const { ensureNodeBinOnPath, ensureUserBinsOnPath, stampConsole } = await import("./node-ILM6MV56.js");
|
|
279
299
|
ensureNodeBinOnPath();
|
|
280
300
|
await ensureUserBinsOnPath();
|
|
281
301
|
if (!isPullEnv) stampConsole();
|
|
282
|
-
const { createLocalServer, pullEnv, PullEnvError, registerInstance } = await import("./src-
|
|
302
|
+
const { createLocalServer, pullEnv, PullEnvError, registerInstance, registerCliLocation } = await import("./src-V7DPPFCF.js");
|
|
303
|
+
registerCliLocation({ execPath: process.execPath, cliEntry: fileURLToPath(import.meta.url) });
|
|
283
304
|
if (isPullEnv) {
|
|
284
305
|
if (!serviceArg) {
|
|
285
306
|
console.error("Error: --service (-s) is required with --pull-env");
|
|
@@ -353,6 +374,7 @@ async function main() {
|
|
|
353
374
|
}
|
|
354
375
|
printStartupTable(port, appUrl);
|
|
355
376
|
console.log("[cli] Press Ctrl+C to stop");
|
|
377
|
+
let tray = null;
|
|
356
378
|
let shuttingDown = false;
|
|
357
379
|
const gracefulShutdown = async (signal) => {
|
|
358
380
|
if (shuttingDown) {
|
|
@@ -362,6 +384,7 @@ async function main() {
|
|
|
362
384
|
shuttingDown = true;
|
|
363
385
|
console.log(`
|
|
364
386
|
[cli] Received ${signal}, shutting down gracefully...`);
|
|
387
|
+
await tray?.stop();
|
|
365
388
|
if (process.env.NODE_ENV === "development") {
|
|
366
389
|
process.exit(0);
|
|
367
390
|
}
|
|
@@ -371,6 +394,45 @@ async function main() {
|
|
|
371
394
|
};
|
|
372
395
|
process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
|
|
373
396
|
process.on("SIGINT", () => gracefulShutdown("SIGINT"));
|
|
397
|
+
if (!noTray) {
|
|
398
|
+
const { startInstanceTray } = await import("./tray-TRWZNOUD.js");
|
|
399
|
+
const {
|
|
400
|
+
scheduleSelfRestart,
|
|
401
|
+
listTrayServices,
|
|
402
|
+
onTrayServicesChanged,
|
|
403
|
+
startProcess,
|
|
404
|
+
stopProcess,
|
|
405
|
+
restartProcess,
|
|
406
|
+
networkInfo,
|
|
407
|
+
setLanMode
|
|
408
|
+
} = await import("./src-V7DPPFCF.js");
|
|
409
|
+
tray = await startInstanceTray({
|
|
410
|
+
info: { cwd: process.cwd(), port, version, url: appUrl },
|
|
411
|
+
assetsDir: join(__dirname, "assets"),
|
|
412
|
+
openUrl: (target) => open(target),
|
|
413
|
+
restart: () => scheduleSelfRestart(),
|
|
414
|
+
stop: () => void gracefulShutdown("tray"),
|
|
415
|
+
listServices: listTrayServices,
|
|
416
|
+
startService: (id) => startProcess(id),
|
|
417
|
+
// L'arrêt exige l'agent qui le fait tourner : il est dans la vue, et
|
|
418
|
+
// seul un service en cours propose ce geste.
|
|
419
|
+
stopService: async (id) => {
|
|
420
|
+
const service = (await listTrayServices()).find((s) => s.id === id);
|
|
421
|
+
if (!service?.agentId) throw new Error(`Aucun agent pour ${id}`);
|
|
422
|
+
return stopProcess(id, service.agentId);
|
|
423
|
+
},
|
|
424
|
+
restartService: (id) => restartProcess(id),
|
|
425
|
+
onServicesChanged: onTrayServicesChanged,
|
|
426
|
+
lan: {
|
|
427
|
+
read: () => {
|
|
428
|
+
const info = networkInfo();
|
|
429
|
+
return { enabled: info.lanEnabled, addresses: info.lanUrls };
|
|
430
|
+
},
|
|
431
|
+
toggle: (enabled) => setLanMode(enabled)
|
|
432
|
+
},
|
|
433
|
+
warn: (message) => console.log(message)
|
|
434
|
+
});
|
|
435
|
+
}
|
|
374
436
|
}
|
|
375
437
|
main().catch(async (err) => {
|
|
376
438
|
console.error("[cli] Fatal error:", err);
|
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/port-resolution.ts"],"sourcesContent":["#!/usr/bin/env node\nimport type { Server } from 'node:http';\nimport type { WebSocketServer } from 'ws';\nimport type { Request, Response } from 'express';\nimport { fileURLToPath, URL as NodeURL } from 'node:url';\nimport { dirname, join, resolve } from 'node:path';\nimport { readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport express from 'express';\nimport dotenv from 'dotenv'\nimport open from 'open';\nimport { resolvePort } from './port-resolution.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nconst { version } = JSON.parse(\n readFileSync(new NodeURL('./package.json', import.meta.url), 'utf8'),\n) as { version: string };\n\nfunction printStartupTable(port: number, appUrl: string): void {\n const rows: [string, string][] = [\n ['Version', version],\n ['Port', String(port)],\n ['Url', appUrl],\n ];\n\n const col0 = Math.max(...rows.map(([k]) => k.length));\n const col1 = Math.max(...rows.map(([, v]) => v.length));\n\n const pad = (s: string, n: number) => s.padEnd(n);\n const hr = (l: string, m: string, r: string, f: string) =>\n l + f.repeat(col0 + 2) + m + f.repeat(col1 + 2) + r;\n\n console.log('');\n console.log(hr('┌', '┬', '┐', '─'));\n for (const [key, value] of rows) {\n console.log(`│ ${pad(key, col0)} │ ${pad(value, col1)} │`);\n }\n console.log(hr('└', '┴', '┘', '─'));\n console.log('');\n}\n\n// Parse CLI flags\nconst args = process.argv.slice(2);\n\n/**\n * Set by the desktop launcher. It means nobody is watching a terminal, so a\n * startup failure has to be reported through a window of its own.\n */\nconst isFromDesktop = args.includes('--from-desktop');\n\n// Capture must start before anything logs, hence this early import.\nconst startupFailure = isFromDesktop ? await import('./startup-failure.js') : null;\nstartupFailure?.captureOutput();\n\nfunction getFlagValue(flags: string[]): string | undefined {\n for (const flag of flags) {\n const idx = args.indexOf(flag);\n if (idx !== -1 && idx + 1 < args.length) return args[idx + 1];\n }\n return undefined;\n}\n\n/**\n * Flags that mirror a RUNEYA_* environment variable. The flag always wins over\n * the variable, and both are equivalent otherwise.\n *\n * Secrets (RUNEYA_ENCRYPTION_KEY, RUNEYA_MASTER_PASSWORD) deliberately have no\n * flag: process arguments are world-readable through `ps` on most systems.\n */\nconst ENV_FLAGS: { flag: string; env: string }[] = [\n { flag: '--host', env: 'RUNEYA_HOST' },\n { flag: '--agent-port', env: 'RUNEYA_AGENT_PORT' },\n { flag: '--agent-host', env: 'RUNEYA_AGENT_HOST' },\n { flag: '--agent-binary-path', env: 'RUNEYA_AGENT_BINARY_PATH' },\n { flag: '--data-dir', env: 'RUNEYA_DATA_DIR' },\n { flag: '--mode', env: 'RUNEYA_MODE' },\n { flag: '--cloud-url', env: 'RUNEYA_CLOUD_URL' },\n { flag: '--cloud-app-url', env: 'RUNEYA_CLOUD_APP_URL' },\n { flag: '--cors-origin', env: 'RUNEYA_CORS_ORIGIN' },\n { flag: '--claude-pty', env: 'RUNEYA_CLAUDE_PTY' },\n];\n\n// Flags taking a value — needed so their value is not mistaken for the target directory\nconst flagsWithValues = new Set([\n '--port',\n '--name',\n '-e', '--environment',\n '-s', '--service',\n ...ENV_FLAGS.map((f) => f.flag),\n]);\n\n// Apply value flags to their env var (flag wins over an already-set variable).\n// Done before dotenv so a .env file can never override an explicit flag.\nfor (const { flag, env: key } of ENV_FLAGS) {\n const value = getFlagValue([flag]);\n if (value !== undefined) process.env[key] = value;\n}\n// --debug is a boolean shortcut for RUNEYA_DEBUG=1\nif (args.includes('--debug')) process.env['RUNEYA_DEBUG'] = '1';\n\n/**\n * `install-desktop` / `uninstall-desktop` — handled before anything else so the\n * sub-command name is never mistaken for a target directory, and so the current\n * working directory is still the user's when we capture it.\n *\n * Bare on a TTY it opens a wizard; any flag that pre-answers a question skips\n * straight to the action so scripts stay unattended.\n */\nconst subCommand = args[0];\nif (subCommand === 'install-desktop' || subCommand === 'uninstall-desktop') {\n const { installDesktopLauncher, uninstallDesktopLauncher, deriveIdentity } =\n await import('./desktop-launcher.js');\n const { shouldRunWizard, runInstallWizard, printInstallReport, printUninstallReport } =\n await import('./desktop-wizard.js');\n\n const { parsePort } = await import('./free-port.js');\n\n const rest = args.slice(1);\n // Every flag of this sub-command that takes a value: without this, the value\n // itself (a port number, a name) is mistaken for the target directory.\n const subFlagsWithValues = new Set(['--name', '--port', '--agent-port']);\n const positional = rest.find((a, i) => !a.startsWith('-') && !subFlagsWithValues.has(rest[i - 1] ?? ''));\n const nameFlag = getFlagValue(['--name']);\n\n // Ports baked into the shortcut. Null means \"follow Runeya's default\", so a\n // launcher created without them keeps tracking the default if it changes.\n const portFlagRaw = getFlagValue(['--port']);\n const agentPortFlagRaw = getFlagValue(['--agent-port']);\n for (const [flag, raw] of [['--port', portFlagRaw], ['--agent-port', agentPortFlagRaw]] as const) {\n if (raw !== undefined && parsePort(raw) === null) {\n console.error(`Erreur : ${flag} attend un entier entre 1 et 65535 (reçu ${JSON.stringify(raw)}).`);\n process.exit(1);\n }\n }\n let port = parsePort(portFlagRaw);\n let agentPort = parsePort(agentPortFlagRaw);\n\n // The data directory is resolved from the working directory, so a launcher\n // that does not pin one would start Runeya in the desktop's cwd (usually the\n // home directory) and create a stray .runeya there. Pin the cwd by default.\n let workingDir = rest.includes('--no-cwd') ? null : resolve(positional ?? process.cwd());\n let displayName = nameFlag;\n\n if (subCommand === 'install-desktop' && shouldRunWizard(rest, positional !== undefined)) {\n const answers = await runInstallWizard(process.cwd());\n if (!answers) process.exit(130); // aborted with Ctrl+C\n workingDir = answers.workingDir;\n displayName = answers.name;\n port = answers.port;\n agentPort = answers.agentPort;\n }\n\n const { name, id } = deriveIdentity(displayName, workingDir);\n\n try {\n if (subCommand === 'install-desktop') {\n const result = await installDesktopLauncher({\n nodePath: process.execPath,\n cliEntry: fileURLToPath(import.meta.url),\n distDir: __dirname,\n workingDir,\n name,\n id,\n port,\n agentPort,\n });\n printInstallReport({ name, workingDir, nodePath: process.execPath, port, agentPort, result });\n } else {\n printUninstallReport(name, await uninstallDesktopLauncher(name, id));\n }\n process.exit(0);\n } catch (err) {\n console.error(`Erreur : ${(err as Error).message}`);\n process.exit(1);\n }\n}\n\n// Resolve target directory (first positional arg, skipping flag values)\nconst targetDir = args.find((a, i) => !a.startsWith('-') && !flagsWithValues.has(args[i - 1] ?? ''));\nif (targetDir) {\n const resolved = resolve(targetDir);\n process.chdir(resolved);\n console.log(`[cli] Working directory: ${resolved}`);\n} else if (process.env['RUNEYA_DATA_DIR']) {\n const resolved = resolve(process.env['RUNEYA_DATA_DIR'], '..');\n process.chdir(resolved);\n console.log(`[cli] Working directory: ${resolved} (from RUNEYA_DATA_DIR)`);\n} else if (process.cwd() === '/') {\n /**\n * On n'écrit jamais à la racine.\n *\n * Un lanceur global — installé sans dossier épinglé — démarre avec le cwd que\n * lui donne le système, et le Finder comme les services systemd donnent `/`.\n * `DATA_DIR` y vaudrait `/.runeya` : sous macOS la racine est le volume\n * système signé, monté en lecture seule, et la première écriture locale\n * échouerait en EROFS — que même root ne peut pas lever sans\n * `/etc/synthetic.conf` et un redémarrage. Sous Linux elle demanderait les\n * droits du superutilisateur pour un dossier qui n'a rien à faire là.\n *\n * Le repli vaut aussi pour les lanceurs DÉJÀ installés, que corriger le stub\n * ne rattraperait pas.\n */\n const home = homedir();\n process.chdir(home);\n console.log(`[cli] Working directory: ${home} (lanceur sans dossier épinglé)`);\n}\n\ndotenv.config({ quiet: true });\n\nif (args.includes('--help') || args.includes('-h')) {\n console.log(`Usage: runeya [path-to-your-stack] [options]\n\nCommands:\n install-desktop [path] Create a desktop/menu launcher for this machine\n Bare on a terminal, this opens a short wizard.\n uninstall-desktop Remove a launcher created by install-desktop\n --name <label> Launcher name (default: \"Runeya — <folder>\")\n --no-cwd Global launcher — do not pin a working directory\n --port <n> Port baked into the launcher (default: Runeya's own)\n --agent-port <n> Agent port baked in (default: launcher port + 1)\n -y, --yes Skip the wizard and take the defaults\n --from-desktop Set by desktop launchers: report startup failures\n in a browser window instead of a silent exit\n\nOptions:\n --version Show version number\n --pe, --pull-env Print env vars for a service to stdout (requires -e and -s)\n -e, --environment <n> Environment name or id\n -s, --service <name> Service name or id\n --lan Expose server on the local network (shortcut for --host 0.0.0.0)\n --no-open Do not open browser on startup\n --agent Run as agent only (no server, no UI) — for remote machines\n -h, --help Show this help message\n\nConfiguration:\n Each setting has a flag and an equivalent RUNEYA_ environment variable; the\n flag wins. Variables are prefixed so they cannot collide with those of the\n services you manage. A .env file in the working directory is loaded\n automatically, but never overrides a flag.\n\n Flag Environment variable Default\n --port <n> RUNEYA_HTTP_PORT 4000\n (binds the agent instead when --agent is used)\n --host <address> RUNEYA_HOST 127.0.0.1\n --agent-port <n> RUNEYA_AGENT_PORT server port + 1\n --agent-host <address> RUNEYA_AGENT_HOST 127.0.0.1\n --agent-binary-path <path> RUNEYA_AGENT_BINARY_PATH bundled with the CLI\n --data-dir <path> RUNEYA_DATA_DIR <cwd>/.runeya\n --mode <mode> RUNEYA_MODE local-simple\n 'local-simple' | 'cloud'\n --cloud-url <url> RUNEYA_CLOUD_URL —\n --cloud-app-url <url> RUNEYA_CLOUD_APP_URL —\n --cors-origin <origin> RUNEYA_CORS_ORIGIN —\n --lan RUNEYA_LAN_PROXY false\n --debug RUNEYA_DEBUG false\n --claude-pty <0|1> RUNEYA_CLAUDE_PTY 1\n PTY mode for the Claude Code runner\n\n Secrets have no flag — process arguments are readable by other users via 'ps':\n RUNEYA_ENCRYPTION_KEY 64-char hex key for CI/CD — unlocks secrets without a\n master password AND disables tRPC authentication.\n Never set this on a machine reachable by others.\n RUNEYA_MASTER_PASSWORD Master password used by --pull-env instead of prompting\n\n Standard variables Runeya also honours: NODE_ENV, CI (skips opening the browser).\n`);\n process.exit(0);\n}\n\nif (args.includes('--version')) {\n console.log(version);\n process.exit(0);\n}\n\nconst noOpen =\n args.includes('--no-open') ||\n !!process.env['VITEST'] ||\n !!process.env['CI'] ||\n process.env['NODE_ENV'] === 'test';\n\n// --pull-env flag — detect early so we can silence stdout before any log\nconst isPullEnv = args.includes('--pull-env') || args.includes('--pe');\n\n// In pull-env mode, redirect console.log/info to stderr so only KEY=VALUE goes to stdout\nif (isPullEnv) {\n const toStderr = (...a: unknown[]) => process.stderr.write(a.join(' ') + '\\n');\n console.log = toStderr;\n console.info = toStderr;\n}\n\nconst serviceArg = getFlagValue(['-s', '--service']);\nconst environmentArg = getFlagValue(['-e', '--environment']);\n\n// Configure environment BEFORE importing server (env is parsed at module load)\n// --agent mode: run as standalone agent only (no server, no UI)\nconst isAgentOnly = args.includes('--agent');\n\n// --port targets the server, except in agent mode where it binds the agent\nconst portFlag = getFlagValue(['--port']);\nif (portFlag) {\n process.env[isAgentOnly ? 'RUNEYA_AGENT_PORT' : 'RUNEYA_HTTP_PORT'] = portFlag;\n}\n\n// --lan binds to 0.0.0.0. As an explicit flag it outranks RUNEYA_HOST; coming\n// from RUNEYA_LAN_PROXY it only fills in a host nobody else set.\nconst hostFlag = getFlagValue(['--host']);\nconst isLan = args.includes('--lan');\nconst isLanProxy = isLan || process.env.RUNEYA_LAN_PROXY === 'true' || process.env.RUNEYA_LAN_PROXY === '1';\nif (isLanProxy) {\n process.env.RUNEYA_LAN_PROXY = 'true';\n if (!hostFlag && isLan) process.env.RUNEYA_HOST = '0.0.0.0';\n else process.env.RUNEYA_HOST ??= '0.0.0.0';\n}\n\n// In agent mode --host binds the agent rather than the server\nif (isAgentOnly) {\n if (hostFlag) {\n process.env.RUNEYA_AGENT_HOST = hostFlag;\n } else if (isLan) {\n process.env.RUNEYA_AGENT_HOST = '0.0.0.0';\n } else if (isLanProxy) {\n process.env.RUNEYA_AGENT_HOST ??= '0.0.0.0';\n }\n}\n\n// Agent binary shipped inside the CLI dist — overridable via --agent-binary-path\nprocess.env.RUNEYA_AGENT_BINARY_PATH ??= join(__dirname, 'agent/index.js');\n// Expose CLI version to server\nprocess.env.RUNEYA_VERSION = version;\n// Tell the server it was launched from a shortcut, so the UI can say so\nif (isFromDesktop) process.env.RUNEYA_FROM_DESKTOP = '1';\n// Data directory defaults to CWD/.runeya (server env.ts default)\n// so Runeya data lives alongside the target project.\n\n/**\n * Listen with retry for EADDRINUSE — handles the race condition when the CLI\n * restarts the server before the old process has fully released the port.\n *\n * The `wss` parameter is needed because the `ws` library re-emits HTTP server\n * errors on the WebSocketServer — without a handler the error becomes unhandled.\n */\nfunction listenWithRetry(\n server: Server,\n port: number,\n host: string,\n wss?: WebSocketServer,\n maxRetries = 20,\n delay = 500,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n let attempts = 0;\n\n // Absorb EADDRINUSE errors re-emitted by the ws library on the WSS\n // during the retry window. Without this, Node.js crashes on unhandled error.\n const wssErrorHandler = () => { /* absorbed — handled via server 'error' */ };\n wss?.on('error', wssErrorHandler);\n\n const tryListen = () => {\n const onError = (err: NodeJS.ErrnoException) => {\n // Clean up the 'listening' callback that server.listen() registered\n server.removeAllListeners('listening');\n\n if (err.code === 'EADDRINUSE' && attempts < maxRetries) {\n attempts++;\n console.log(`[cli] Port ${port} in use, retrying in ${delay}ms (${attempts}/${maxRetries})...`);\n setTimeout(tryListen, delay);\n } else {\n wss?.removeListener('error', wssErrorHandler);\n reject(err);\n }\n };\n\n server.once('error', onError);\n server.listen(port, host, () => {\n server.removeListener('error', onError);\n wss?.removeListener('error', wssErrorHandler);\n resolve();\n });\n };\n\n tryListen();\n });\n}\n\nasync function main() {\n // Avant tout : ce que ce process hérite ici, le serveur, l'agent local et\n // chaque service lancé ensuite en héritent à leur tour. Un raccourci de bureau\n // reçoit le PATH de la session graphique, où ni les gestionnaires de version\n // ni les binaires installés par l'utilisateur (claude, codex) ne figurent.\n const { ensureNodeBinOnPath, ensureUserBinsOnPath, stampConsole } = await import('@runeya/packages-shared/node');\n ensureNodeBinOnPath();\n await ensureUserBinsOnPath();\n\n // Journaux datés du temps écoulé depuis le démarrage. Jamais en --pull-env :\n // sa sortie est lue par un script, pas par un humain.\n if (!isPullEnv) stampConsole();\n\n // Dynamic import ensures env is parsed AFTER we configure it\n const { createLocalServer, pullEnv, PullEnvError, registerInstance } = await import('@runeya/apps-server');\n\n // Handle --pull-env mode: resolve env vars and print, then exit\n if (isPullEnv) {\n if (!serviceArg) {\n console.error('Error: --service (-s) is required with --pull-env');\n process.exit(1);\n }\n if (!environmentArg) {\n console.error('Error: --environment (-e) is required with --pull-env');\n process.exit(1);\n }\n try {\n const output = await pullEnv({ service: serviceArg, environment: environmentArg });\n if (output) process.stdout.write(output + '\\n');\n process.exit(0);\n } catch (err: unknown) {\n if (err instanceof PullEnvError) {\n console.error(`Error: ${err.message}`);\n process.exit(err.exitCode);\n }\n throw err;\n }\n }\n\n // --agent mode: standalone agent, no server, no UI\n if (isAgentOnly) {\n const { spawn } = await import('node:child_process');\n const agentBin = join(__dirname, 'agent/index.js');\n const child = spawn(process.execPath, [agentBin], { stdio: 'inherit', windowsHide: true });\n child.on('exit', (code) => process.exit(code ?? 0));\n // SIGINT is already delivered to the child by the terminal (same process group).\n // Intercept it here only to suppress Node's default exit so we stay alive\n // until the child finishes its graceful shutdown.\n process.on('SIGINT', () => { /* wait for child to exit */ });\n process.on('SIGTERM', () => child.kill('SIGTERM'));\n return;\n }\n\n /**\n * A shortcut clicked twice must not fail.\n *\n * Starting a second instance on a port a Runeya already holds ends in\n * EADDRINUSE after ten seconds of retries — and from a launcher there is no\n * terminal to read that in. So the port is asked first: if Runeya answers,\n * the right move is to bring up the window that already exists.\n *\n * Only for launcher starts. From a terminal, `runeya` twice on one port is a\n * mistake worth reporting, not one worth papering over.\n */\n if (isFromDesktop) {\n const port = resolvePort();\n const { probeRuneya } = await import('./free-port.js');\n const existing = await probeRuneya(port);\n if (existing) {\n const url = `http://localhost:${port}`;\n console.log(`[cli] Runeya v${existing.version} déjà en cours sur le port ${port} — ouverture de ${url}`);\n if (!noOpen) await open(url);\n return;\n }\n }\n\n console.log('[cli] Starting Runeya...');\n\n // Create server (automatically spawns local agent)\n const { app, server, wss, shutdown } = await createLocalServer();\n\n // Serve static files from web frontend (embedded in CLI dist during build)\n const webDistPath = join(__dirname, 'web');\n\n /**\n * Les fichiers d'`assets/` portent un hash de leur contenu dans leur nom : une\n * mise à jour produit un NOUVEAU nom, jamais un contenu différent sous le même\n * nom. Ils peuvent donc être gardés indéfiniment, et `immutable` dit au\n * navigateur de ne même pas revalider.\n *\n * Sans cela, `express.static` répond `max-age=0` : chaque rechargement\n * redemande les 295 fichiers pour s'entendre répondre 304. Ce sont des\n * requêtes vides, mais elles occupent les six connexions qu'un navigateur\n * accorde par hôte — pour tous ses onglets à la fois. Avec plusieurs onglets\n * rechargés ensemble, l'ouverture du WebSocket attendait derrière cette file.\n */\n app.use('/assets', express.static(join(webDistPath, 'assets'), {\n immutable: true,\n maxAge: '1y',\n fallthrough: false,\n }));\n\n // Tout le reste (favicon…) : revalidation à chaque fois, ces noms ne changent\n // pas d'une version à l'autre.\n app.use(express.static(webDistPath, {\n index: false,\n setHeaders: (res) => res.setHeader('Cache-Control', 'no-cache'),\n }));\n\n // Fallback to index.html for client-side routing (Vue Router)\n // Express 5 requires explicit path patterns (not '*')\n //\n // JAMAIS mis en cache : c'est lui qui nomme les assets de la version courante.\n // Un index.html périmé rappellerait les fichiers de l'ancienne version — qui,\n // eux, ne sont plus là.\n //\n // `root` + nom relatif, jamais un chemin absolu : `sendFile` refuse tout\n // segment commençant par un point (`dotfiles: 'ignore'` par défaut) et\n // répond 404. Or l'installation la plus courante — `npx @runeya/runeya` —\n // vit sous `~/.npm/_npx/…`. Avec un chemin absolu, la page d'accueil était\n // donc introuvable sur toute machine lancée par npx (ou depuis `~/.nvm`),\n // alors que `/index.html` répondait : `express.static` ne teste, lui, que la\n // partie relative à sa racine.\n app.use((_req: Request, res: Response) => {\n res.setHeader('Cache-Control', 'no-cache');\n res.sendFile('index.html', { root: webDistPath });\n });\n\n const port = resolvePort();\n const host = process.env.RUNEYA_HOST ?? '127.0.0.1';\n\n await listenWithRetry(server, port, host, wss);\n\n // Announce this instance now that the port is really ours, so the settings\n // panel of any Runeya on this machine can list it.\n await registerInstance();\n\n /**\n * L'adresse d'écoute n'est pas une adresse de visite.\n *\n * `0.0.0.0` (et son équivalent IPv6 `::`) dit « toutes les interfaces » à\n * bind ; ce n'est pas une destination. Sous Linux une connexion vers elle\n * retombe sur la boucle locale, ce qui a longtemps masqué le problème — sous\n * Windows elle n'est pas routable du tout, et les navigateurs la bloquent\n * désormais ailleurs aussi. On écoute donc partout, mais on ouvre localhost.\n */\n const browseHost = host === '0.0.0.0' || host === '::' ? 'localhost' : host;\n const appUrl = `http://${browseHost}:${port}`;\n\n if (!noOpen) {\n await open(appUrl);\n }\n\n console.log('\\n🚀 Runeya is running!');\n if (isLanProxy) {\n console.log('🌐 LAN mode: server and service ports exposed on local network');\n }\n printStartupTable(port, appUrl);\n console.log('[cli] Press Ctrl+C to stop');\n\n let shuttingDown = false;\n const gracefulShutdown = async (signal: string) => {\n if (shuttingDown) {\n console.log(`[cli] Forced exit (second ${signal})`);\n process.exit(1);\n }\n shuttingDown = true;\n console.log(`\\n[cli] Received ${signal}, shutting down gracefully...`);\n\n // In dev, exit immediately — ports are freed on process death,\n // and the 'exit' handler in agent-spawner SIGKILLs the agent.\n if (process.env.NODE_ENV === 'development') {\n process.exit(0);\n }\n\n await shutdown();\n console.log('[cli] Shutdown complete');\n process.exit(0);\n };\n\n process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));\n process.on('SIGINT', () => gracefulShutdown('SIGINT'));\n}\n\nmain().catch(async (err) => {\n console.error('[cli] Fatal error:', err);\n\n // With a terminal, the message above is the report. Without one, it goes\n // nowhere: serve it as a page and open it in the browser instead.\n if (startupFailure) {\n try {\n const { diagnose, renderFailurePage, capturedLines, showStartupFailure } = startupFailure;\n const html = renderFailurePage(\n diagnose(err, resolvePort()),\n capturedLines(),\n {\n 'Version': version,\n 'Dossier de travail': process.cwd(),\n 'Node': process.execPath,\n 'Runeya': fileURLToPath(import.meta.url),\n },\n );\n await showStartupFailure(html);\n } catch (reportErr) {\n console.error('[cli] Impossible d\\'afficher le rapport d\\'erreur:', reportErr);\n }\n }\n\n process.exit(1);\n});\n","/**\n * Resolve the HTTP port Runeya should listen on.\n *\n * Only RUNEYA_HTTP_PORT is read (default 4000) — the generic PORT variable is\n * intentionally ignored so it can stay reserved for the user's own services.\n *\n * Throws if the resolved value is not an integer in [1, 65535].\n */\nexport function resolvePort(): number {\n const raw = process.env.RUNEYA_HTTP_PORT;\n if (raw === undefined) return 4000;\n\n const port = Number(raw);\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw new Error(\n `Invalid port: ${JSON.stringify(raw)}. Must be an integer between 1 and 65535.`,\n );\n }\n return port;\n}\n"],"mappings":"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","names":["resolve","port"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/port-resolution.ts"],"sourcesContent":["#!/usr/bin/env node\nimport type { Server } from 'node:http';\nimport type { WebSocketServer } from 'ws';\nimport type { Request, Response } from 'express';\nimport { fileURLToPath, URL as NodeURL } from 'node:url';\nimport { dirname, join, resolve } from 'node:path';\nimport { readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport express from 'express';\nimport dotenv from 'dotenv'\nimport open from 'open';\nimport { resolvePort } from './port-resolution.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nconst { version } = JSON.parse(\n readFileSync(new NodeURL('./package.json', import.meta.url), 'utf8'),\n) as { version: string };\n\nfunction printStartupTable(port: number, appUrl: string): void {\n const rows: [string, string][] = [\n ['Version', version],\n ['Port', String(port)],\n ['Url', appUrl],\n ];\n\n const col0 = Math.max(...rows.map(([k]) => k.length));\n const col1 = Math.max(...rows.map(([, v]) => v.length));\n\n const pad = (s: string, n: number) => s.padEnd(n);\n const hr = (l: string, m: string, r: string, f: string) =>\n l + f.repeat(col0 + 2) + m + f.repeat(col1 + 2) + r;\n\n console.log('');\n console.log(hr('┌', '┬', '┐', '─'));\n for (const [key, value] of rows) {\n console.log(`│ ${pad(key, col0)} │ ${pad(value, col1)} │`);\n }\n console.log(hr('└', '┴', '┘', '─'));\n console.log('');\n}\n\n// Parse CLI flags\nconst args = process.argv.slice(2);\n\n/**\n * Set by the desktop launcher. It means nobody is watching a terminal, so a\n * startup failure has to be reported through a window of its own.\n */\nconst isFromDesktop = args.includes('--from-desktop');\n\n// Capture must start before anything logs, hence this early import.\nconst startupFailure = isFromDesktop ? await import('./startup-failure.js') : null;\nstartupFailure?.captureOutput();\n\nfunction getFlagValue(flags: string[]): string | undefined {\n for (const flag of flags) {\n const idx = args.indexOf(flag);\n if (idx !== -1 && idx + 1 < args.length) return args[idx + 1];\n }\n return undefined;\n}\n\n/**\n * Flags that mirror a RUNEYA_* environment variable. The flag always wins over\n * the variable, and both are equivalent otherwise.\n *\n * Secrets (RUNEYA_ENCRYPTION_KEY, RUNEYA_MASTER_PASSWORD) deliberately have no\n * flag: process arguments are world-readable through `ps` on most systems.\n */\nconst ENV_FLAGS: { flag: string; env: string }[] = [\n { flag: '--host', env: 'RUNEYA_HOST' },\n { flag: '--agent-port', env: 'RUNEYA_AGENT_PORT' },\n { flag: '--agent-host', env: 'RUNEYA_AGENT_HOST' },\n { flag: '--agent-binary-path', env: 'RUNEYA_AGENT_BINARY_PATH' },\n { flag: '--data-dir', env: 'RUNEYA_DATA_DIR' },\n { flag: '--mode', env: 'RUNEYA_MODE' },\n { flag: '--cloud-url', env: 'RUNEYA_CLOUD_URL' },\n { flag: '--cloud-app-url', env: 'RUNEYA_CLOUD_APP_URL' },\n { flag: '--cors-origin', env: 'RUNEYA_CORS_ORIGIN' },\n { flag: '--claude-pty', env: 'RUNEYA_CLAUDE_PTY' },\n];\n\n// Flags taking a value — needed so their value is not mistaken for the target directory\nconst flagsWithValues = new Set([\n '--port',\n '--name',\n '-e', '--environment',\n '-s', '--service',\n ...ENV_FLAGS.map((f) => f.flag),\n]);\n\n// Apply value flags to their env var (flag wins over an already-set variable).\n// Done before dotenv so a .env file can never override an explicit flag.\nfor (const { flag, env: key } of ENV_FLAGS) {\n const value = getFlagValue([flag]);\n if (value !== undefined) process.env[key] = value;\n}\n// --debug is a boolean shortcut for RUNEYA_DEBUG=1\nif (args.includes('--debug')) process.env['RUNEYA_DEBUG'] = '1';\n\n/**\n * `install-desktop` / `uninstall-desktop` — handled before anything else so the\n * sub-command name is never mistaken for a target directory, and so the current\n * working directory is still the user's when we capture it.\n *\n * Bare on a TTY it opens a wizard; any flag that pre-answers a question skips\n * straight to the action so scripts stay unattended.\n */\nconst subCommand = args[0];\nif (subCommand === 'install-desktop' || subCommand === 'uninstall-desktop') {\n const { installDesktopLauncher, uninstallDesktopLauncher, deriveIdentity } =\n await import('./desktop-launcher.js');\n const { shouldRunWizard, runInstallWizard, printInstallReport, printUninstallReport } =\n await import('./desktop-wizard.js');\n\n const { parsePort } = await import('./free-port.js');\n\n const rest = args.slice(1);\n // Every flag of this sub-command that takes a value: without this, the value\n // itself (a port number, a name) is mistaken for the target directory.\n const subFlagsWithValues = new Set(['--name', '--port', '--agent-port']);\n const positional = rest.find((a, i) => !a.startsWith('-') && !subFlagsWithValues.has(rest[i - 1] ?? ''));\n const nameFlag = getFlagValue(['--name']);\n\n // Ports baked into the shortcut. Null means \"follow Runeya's default\", so a\n // launcher created without them keeps tracking the default if it changes.\n const portFlagRaw = getFlagValue(['--port']);\n const agentPortFlagRaw = getFlagValue(['--agent-port']);\n for (const [flag, raw] of [['--port', portFlagRaw], ['--agent-port', agentPortFlagRaw]] as const) {\n if (raw !== undefined && parsePort(raw) === null) {\n console.error(`Erreur : ${flag} attend un entier entre 1 et 65535 (reçu ${JSON.stringify(raw)}).`);\n process.exit(1);\n }\n }\n let port = parsePort(portFlagRaw);\n let agentPort = parsePort(agentPortFlagRaw);\n\n // The data directory is resolved from the working directory, so a launcher\n // that does not pin one would start Runeya in the desktop's cwd (usually the\n // home directory) and create a stray .runeya there. Pin the cwd by default.\n let workingDir = rest.includes('--no-cwd') ? null : resolve(positional ?? process.cwd());\n let displayName = nameFlag;\n\n if (subCommand === 'install-desktop' && shouldRunWizard(rest, positional !== undefined)) {\n const answers = await runInstallWizard(process.cwd());\n if (!answers) process.exit(130); // aborted with Ctrl+C\n workingDir = answers.workingDir;\n displayName = answers.name;\n port = answers.port;\n agentPort = answers.agentPort;\n }\n\n const { name, id } = deriveIdentity(displayName, workingDir);\n\n try {\n if (subCommand === 'install-desktop') {\n const result = await installDesktopLauncher({\n nodePath: process.execPath,\n cliEntry: fileURLToPath(import.meta.url),\n distDir: __dirname,\n workingDir,\n name,\n id,\n port,\n agentPort,\n });\n printInstallReport({ name, workingDir, nodePath: process.execPath, port, agentPort, result });\n } else {\n printUninstallReport(name, await uninstallDesktopLauncher(name, id));\n }\n process.exit(0);\n } catch (err) {\n console.error(`Erreur : ${(err as Error).message}`);\n process.exit(1);\n }\n}\n\n/**\n * `runeya instances` — voir et piloter les Runeya de cette machine depuis un\n * terminal. Traité ici, avec les autres sous-commandes, pour que le mot\n * « instances » ne soit jamais pris pour un répertoire cible.\n *\n * Le pendant de l'icône de barre système, qui ne montre qu'une instance — la\n * sienne — et n'existe pas partout. Celle-ci les montre toutes, partout.\n *\n * Aucun serveur n'est démarré : le registre machine est un dossier de fichiers,\n * et le lire ne demande rien d'autre que de le lire.\n */\nif (subCommand === 'instances') {\n // Importé ici et pas en tête de fichier : charger `@runeya/apps-server` a un\n // coût, et un `runeya` ordinaire n'a pas à le payer pour une sous-commande\n // qu'il n'utilise pas.\n const { listInstances, killInstance, restartInstance } = await import('@runeya/apps-server');\n const { runInstancesCommand } = await import('./instances-command.js');\n\n process.exit(await runInstancesCommand(args.slice(1), {\n listInstances,\n stopInstance: killInstance,\n restartInstance: async (pid: number) => {\n const { pid: newPid, portReleased } = await restartInstance(pid);\n return { pid: newPid, portReleased };\n },\n openUrl: (url: string) => open(url),\n log: (message: string) => console.log(message),\n warn: (message: string) => console.error(message),\n }));\n}\n\n// Resolve target directory (first positional arg, skipping flag values)\nconst targetDir = args.find((a, i) => !a.startsWith('-') && !flagsWithValues.has(args[i - 1] ?? ''));\nif (targetDir) {\n const resolved = resolve(targetDir);\n process.chdir(resolved);\n console.log(`[cli] Working directory: ${resolved}`);\n} else if (process.env['RUNEYA_DATA_DIR']) {\n const resolved = resolve(process.env['RUNEYA_DATA_DIR'], '..');\n process.chdir(resolved);\n console.log(`[cli] Working directory: ${resolved} (from RUNEYA_DATA_DIR)`);\n} else if (process.cwd() === '/') {\n /**\n * On n'écrit jamais à la racine.\n *\n * Un lanceur global — installé sans dossier épinglé — démarre avec le cwd que\n * lui donne le système, et le Finder comme les services systemd donnent `/`.\n * `DATA_DIR` y vaudrait `/.runeya` : sous macOS la racine est le volume\n * système signé, monté en lecture seule, et la première écriture locale\n * échouerait en EROFS — que même root ne peut pas lever sans\n * `/etc/synthetic.conf` et un redémarrage. Sous Linux elle demanderait les\n * droits du superutilisateur pour un dossier qui n'a rien à faire là.\n *\n * Le repli vaut aussi pour les lanceurs DÉJÀ installés, que corriger le stub\n * ne rattraperait pas.\n */\n const home = homedir();\n process.chdir(home);\n console.log(`[cli] Working directory: ${home} (lanceur sans dossier épinglé)`);\n}\n\ndotenv.config({ quiet: true });\n\nif (args.includes('--help') || args.includes('-h')) {\n console.log(`Usage: runeya [path-to-your-stack] [options]\n\nCommands:\n install-desktop [path] Create a desktop/menu launcher for this machine\n Bare on a terminal, this opens a short wizard.\n uninstall-desktop Remove a launcher created by install-desktop\n --name <label> Launcher name (default: \"Runeya — <folder>\")\n --no-cwd Global launcher — do not pin a working directory\n --port <n> Port baked into the launcher (default: Runeya's own)\n --agent-port <n> Agent port baked in (default: launcher port + 1)\n -y, --yes Skip the wizard and take the defaults\n instances [open|stop|restart <pid>]\n List the Runeya running on this machine, and act on\n one. --json for the raw records.\n --from-desktop Set by desktop launchers: report startup failures\n in a browser window instead of a silent exit\n\nOptions:\n --version Show version number\n --pe, --pull-env Print env vars for a service to stdout (requires -e and -s)\n -e, --environment <n> Environment name or id\n -s, --service <name> Service name or id\n --lan Expose server on the local network (shortcut for --host 0.0.0.0)\n --no-open Do not open browser on startup\n --no-tray Do not put this instance in the system tray\n --agent Run as agent only (no server, no UI) — for remote machines\n -h, --help Show this help message\n\nConfiguration:\n Each setting has a flag and an equivalent RUNEYA_ environment variable; the\n flag wins. Variables are prefixed so they cannot collide with those of the\n services you manage. A .env file in the working directory is loaded\n automatically, but never overrides a flag.\n\n Flag Environment variable Default\n --port <n> RUNEYA_HTTP_PORT 4000\n (binds the agent instead when --agent is used)\n --host <address> RUNEYA_HOST 127.0.0.1\n --agent-port <n> RUNEYA_AGENT_PORT server port + 1\n --agent-host <address> RUNEYA_AGENT_HOST 127.0.0.1\n --agent-binary-path <path> RUNEYA_AGENT_BINARY_PATH bundled with the CLI\n --data-dir <path> RUNEYA_DATA_DIR <cwd>/.runeya\n --mode <mode> RUNEYA_MODE local-simple\n 'local-simple' | 'cloud'\n --cloud-url <url> RUNEYA_CLOUD_URL —\n --cloud-app-url <url> RUNEYA_CLOUD_APP_URL —\n --cors-origin <origin> RUNEYA_CORS_ORIGIN —\n --lan RUNEYA_LAN_PROXY false\n --debug RUNEYA_DEBUG false\n --claude-pty <0|1> RUNEYA_CLAUDE_PTY 1\n PTY mode for the Claude Code runner\n\n Secrets have no flag — process arguments are readable by other users via 'ps':\n RUNEYA_ENCRYPTION_KEY 64-char hex key for CI/CD — unlocks secrets without a\n master password AND disables tRPC authentication.\n Never set this on a machine reachable by others.\n RUNEYA_MASTER_PASSWORD Master password used by --pull-env instead of prompting\n\n Standard variables Runeya also honours: NODE_ENV, CI (skips opening the browser).\n`);\n process.exit(0);\n}\n\nif (args.includes('--version')) {\n console.log(version);\n process.exit(0);\n}\n\n/**\n * L'icône de barre système, sauf `--no-tray`.\n *\n * Chaque Runeya pose la sienne au démarrage et la retire en s'arrêtant : une\n * icône par instance en cours. Là où la barre système n'existe pas (serveur\n * sans bureau, arm64, paquet optionnel absent), il n'y a rien à désactiver —\n * l'icône ne se pose pas, et Runeya démarre pareil.\n */\nconst noTray = args.includes('--no-tray');\n\nconst noOpen =\n args.includes('--no-open') ||\n !!process.env['VITEST'] ||\n !!process.env['CI'] ||\n process.env['NODE_ENV'] === 'test';\n\n// --pull-env flag — detect early so we can silence stdout before any log\nconst isPullEnv = args.includes('--pull-env') || args.includes('--pe');\n\n// In pull-env mode, redirect console.log/info to stderr so only KEY=VALUE goes to stdout\nif (isPullEnv) {\n const toStderr = (...a: unknown[]) => process.stderr.write(a.join(' ') + '\\n');\n console.log = toStderr;\n console.info = toStderr;\n}\n\nconst serviceArg = getFlagValue(['-s', '--service']);\nconst environmentArg = getFlagValue(['-e', '--environment']);\n\n// Configure environment BEFORE importing server (env is parsed at module load)\n// --agent mode: run as standalone agent only (no server, no UI)\nconst isAgentOnly = args.includes('--agent');\n\n// --port targets the server, except in agent mode where it binds the agent\nconst portFlag = getFlagValue(['--port']);\nif (portFlag) {\n process.env[isAgentOnly ? 'RUNEYA_AGENT_PORT' : 'RUNEYA_HTTP_PORT'] = portFlag;\n}\n\n// --lan binds to 0.0.0.0. As an explicit flag it outranks RUNEYA_HOST; coming\n// from RUNEYA_LAN_PROXY it only fills in a host nobody else set.\nconst hostFlag = getFlagValue(['--host']);\nconst isLan = args.includes('--lan');\nconst isLanProxy = isLan || process.env.RUNEYA_LAN_PROXY === 'true' || process.env.RUNEYA_LAN_PROXY === '1';\nif (isLanProxy) {\n process.env.RUNEYA_LAN_PROXY = 'true';\n if (!hostFlag && isLan) process.env.RUNEYA_HOST = '0.0.0.0';\n else process.env.RUNEYA_HOST ??= '0.0.0.0';\n}\n\n// In agent mode --host binds the agent rather than the server\nif (isAgentOnly) {\n if (hostFlag) {\n process.env.RUNEYA_AGENT_HOST = hostFlag;\n } else if (isLan) {\n process.env.RUNEYA_AGENT_HOST = '0.0.0.0';\n } else if (isLanProxy) {\n process.env.RUNEYA_AGENT_HOST ??= '0.0.0.0';\n }\n}\n\n// Agent binary shipped inside the CLI dist — overridable via --agent-binary-path\nprocess.env.RUNEYA_AGENT_BINARY_PATH ??= join(__dirname, 'agent/index.js');\n// Expose CLI version to server\nprocess.env.RUNEYA_VERSION = version;\n// Tell the server it was launched from a shortcut, so the UI can say so\nif (isFromDesktop) process.env.RUNEYA_FROM_DESKTOP = '1';\n// Data directory defaults to CWD/.runeya (server env.ts default)\n// so Runeya data lives alongside the target project.\n\n/**\n * Listen with retry for EADDRINUSE — handles the race condition when the CLI\n * restarts the server before the old process has fully released the port.\n *\n * The `wss` parameter is needed because the `ws` library re-emits HTTP server\n * errors on the WebSocketServer — without a handler the error becomes unhandled.\n */\nfunction listenWithRetry(\n server: Server,\n port: number,\n host: string,\n wss?: WebSocketServer,\n maxRetries = 20,\n delay = 500,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n let attempts = 0;\n\n // Absorb EADDRINUSE errors re-emitted by the ws library on the WSS\n // during the retry window. Without this, Node.js crashes on unhandled error.\n const wssErrorHandler = () => { /* absorbed — handled via server 'error' */ };\n wss?.on('error', wssErrorHandler);\n\n const tryListen = () => {\n const onError = (err: NodeJS.ErrnoException) => {\n // Clean up the 'listening' callback that server.listen() registered\n server.removeAllListeners('listening');\n\n if (err.code === 'EADDRINUSE' && attempts < maxRetries) {\n attempts++;\n console.log(`[cli] Port ${port} in use, retrying in ${delay}ms (${attempts}/${maxRetries})...`);\n setTimeout(tryListen, delay);\n } else {\n wss?.removeListener('error', wssErrorHandler);\n reject(err);\n }\n };\n\n server.once('error', onError);\n server.listen(port, host, () => {\n server.removeListener('error', onError);\n wss?.removeListener('error', wssErrorHandler);\n resolve();\n });\n };\n\n tryListen();\n });\n}\n\nasync function main() {\n // Avant tout : ce que ce process hérite ici, le serveur, l'agent local et\n // chaque service lancé ensuite en héritent à leur tour. Un raccourci de bureau\n // reçoit le PATH de la session graphique, où ni les gestionnaires de version\n // ni les binaires installés par l'utilisateur (claude, codex) ne figurent.\n const { ensureNodeBinOnPath, ensureUserBinsOnPath, stampConsole } = await import('@runeya/packages-shared/node');\n ensureNodeBinOnPath();\n await ensureUserBinsOnPath();\n\n // Journaux datés du temps écoulé depuis le démarrage. Jamais en --pull-env :\n // sa sortie est lue par un script, pas par un humain.\n if (!isPullEnv) stampConsole();\n\n // Dynamic import ensures env is parsed AFTER we configure it\n const { createLocalServer, pullEnv, PullEnvError, registerInstance, registerCliLocation } = await import('@runeya/apps-server');\n\n // D'où ce CLI a été lancé, pour que l'interface puisse proposer `install-desktop`\n // sans que le serveur ait à deviner un exécutable.\n registerCliLocation({ execPath: process.execPath, cliEntry: fileURLToPath(import.meta.url) });\n\n // Handle --pull-env mode: resolve env vars and print, then exit\n if (isPullEnv) {\n if (!serviceArg) {\n console.error('Error: --service (-s) is required with --pull-env');\n process.exit(1);\n }\n if (!environmentArg) {\n console.error('Error: --environment (-e) is required with --pull-env');\n process.exit(1);\n }\n try {\n const output = await pullEnv({ service: serviceArg, environment: environmentArg });\n if (output) process.stdout.write(output + '\\n');\n process.exit(0);\n } catch (err: unknown) {\n if (err instanceof PullEnvError) {\n console.error(`Error: ${err.message}`);\n process.exit(err.exitCode);\n }\n throw err;\n }\n }\n\n // --agent mode: standalone agent, no server, no UI\n if (isAgentOnly) {\n const { spawn } = await import('node:child_process');\n const agentBin = join(__dirname, 'agent/index.js');\n const child = spawn(process.execPath, [agentBin], { stdio: 'inherit', windowsHide: true });\n child.on('exit', (code) => process.exit(code ?? 0));\n // SIGINT is already delivered to the child by the terminal (same process group).\n // Intercept it here only to suppress Node's default exit so we stay alive\n // until the child finishes its graceful shutdown.\n process.on('SIGINT', () => { /* wait for child to exit */ });\n process.on('SIGTERM', () => child.kill('SIGTERM'));\n return;\n }\n\n /**\n * A shortcut clicked twice must not fail.\n *\n * Starting a second instance on a port a Runeya already holds ends in\n * EADDRINUSE after ten seconds of retries — and from a launcher there is no\n * terminal to read that in. So the port is asked first: if Runeya answers,\n * the right move is to bring up the window that already exists.\n *\n * Only for launcher starts. From a terminal, `runeya` twice on one port is a\n * mistake worth reporting, not one worth papering over.\n */\n if (isFromDesktop) {\n const port = resolvePort();\n const { probeRuneya } = await import('./free-port.js');\n const existing = await probeRuneya(port);\n if (existing) {\n const url = `http://localhost:${port}`;\n console.log(`[cli] Runeya v${existing.version} déjà en cours sur le port ${port} — ouverture de ${url}`);\n if (!noOpen) await open(url);\n return;\n }\n }\n\n console.log('[cli] Starting Runeya...');\n\n // Create server (automatically spawns local agent)\n const { app, server, wss, shutdown } = await createLocalServer();\n\n // Serve static files from web frontend (embedded in CLI dist during build)\n const webDistPath = join(__dirname, 'web');\n\n /**\n * Les fichiers d'`assets/` portent un hash de leur contenu dans leur nom : une\n * mise à jour produit un NOUVEAU nom, jamais un contenu différent sous le même\n * nom. Ils peuvent donc être gardés indéfiniment, et `immutable` dit au\n * navigateur de ne même pas revalider.\n *\n * Sans cela, `express.static` répond `max-age=0` : chaque rechargement\n * redemande les 295 fichiers pour s'entendre répondre 304. Ce sont des\n * requêtes vides, mais elles occupent les six connexions qu'un navigateur\n * accorde par hôte — pour tous ses onglets à la fois. Avec plusieurs onglets\n * rechargés ensemble, l'ouverture du WebSocket attendait derrière cette file.\n */\n app.use('/assets', express.static(join(webDistPath, 'assets'), {\n immutable: true,\n maxAge: '1y',\n fallthrough: false,\n }));\n\n // Tout le reste (favicon…) : revalidation à chaque fois, ces noms ne changent\n // pas d'une version à l'autre.\n app.use(express.static(webDistPath, {\n index: false,\n setHeaders: (res) => res.setHeader('Cache-Control', 'no-cache'),\n }));\n\n // Fallback to index.html for client-side routing (Vue Router)\n // Express 5 requires explicit path patterns (not '*')\n //\n // JAMAIS mis en cache : c'est lui qui nomme les assets de la version courante.\n // Un index.html périmé rappellerait les fichiers de l'ancienne version — qui,\n // eux, ne sont plus là.\n //\n // `root` + nom relatif, jamais un chemin absolu : `sendFile` refuse tout\n // segment commençant par un point (`dotfiles: 'ignore'` par défaut) et\n // répond 404. Or l'installation la plus courante — `npx @runeya/runeya` —\n // vit sous `~/.npm/_npx/…`. Avec un chemin absolu, la page d'accueil était\n // donc introuvable sur toute machine lancée par npx (ou depuis `~/.nvm`),\n // alors que `/index.html` répondait : `express.static` ne teste, lui, que la\n // partie relative à sa racine.\n app.use((_req: Request, res: Response) => {\n res.setHeader('Cache-Control', 'no-cache');\n res.sendFile('index.html', { root: webDistPath });\n });\n\n const port = resolvePort();\n const host = process.env.RUNEYA_HOST ?? '127.0.0.1';\n\n await listenWithRetry(server, port, host, wss);\n\n // Announce this instance now that the port is really ours, so the settings\n // panel of any Runeya on this machine can list it.\n await registerInstance();\n\n /**\n * L'adresse d'écoute n'est pas une adresse de visite.\n *\n * `0.0.0.0` (et son équivalent IPv6 `::`) dit « toutes les interfaces » à\n * bind ; ce n'est pas une destination. Sous Linux une connexion vers elle\n * retombe sur la boucle locale, ce qui a longtemps masqué le problème — sous\n * Windows elle n'est pas routable du tout, et les navigateurs la bloquent\n * désormais ailleurs aussi. On écoute donc partout, mais on ouvre localhost.\n */\n const browseHost = host === '0.0.0.0' || host === '::' ? 'localhost' : host;\n const appUrl = `http://${browseHost}:${port}`;\n\n if (!noOpen) {\n await open(appUrl);\n }\n\n console.log('\\n🚀 Runeya is running!');\n if (isLanProxy) {\n console.log('🌐 LAN mode: server and service ports exposed on local network');\n }\n printStartupTable(port, appUrl);\n console.log('[cli] Press Ctrl+C to stop');\n\n // Assignée plus bas : l'arrêt doit pouvoir la retirer, et la poser demande\n // de savoir arrêter — les deux se référencent.\n let tray: { stop: () => Promise<void> } | null = null;\n\n let shuttingDown = false;\n const gracefulShutdown = async (signal: string) => {\n if (shuttingDown) {\n console.log(`[cli] Forced exit (second ${signal})`);\n process.exit(1);\n }\n shuttingDown = true;\n console.log(`\\n[cli] Received ${signal}, shutting down gracefully...`);\n\n // L'icône part en premier : elle annonce une instance vivante, et la\n // laisser pendant l'extinction inviterait à cliquer dans le vide.\n await tray?.stop();\n\n // In dev, exit immediately — ports are freed on process death,\n // and the 'exit' handler in agent-spawner SIGKILLs the agent.\n if (process.env.NODE_ENV === 'development') {\n process.exit(0);\n }\n\n await shutdown();\n console.log('[cli] Shutdown complete');\n process.exit(0);\n };\n\n process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));\n process.on('SIGINT', () => gracefulShutdown('SIGINT'));\n\n if (!noTray) {\n const { startInstanceTray } = await import('./tray.js');\n const {\n scheduleSelfRestart,\n listTrayServices,\n onTrayServicesChanged,\n startProcess,\n stopProcess,\n restartProcess,\n networkInfo,\n setLanMode,\n } = await import('@runeya/apps-server');\n\n tray = await startInstanceTray({\n info: { cwd: process.cwd(), port, version, url: appUrl },\n assetsDir: join(__dirname, 'assets'),\n openUrl: (target) => open(target),\n restart: () => scheduleSelfRestart(),\n stop: () => void gracefulShutdown('tray'),\n\n listServices: listTrayServices,\n startService: (id) => startProcess(id),\n // L'arrêt exige l'agent qui le fait tourner : il est dans la vue, et\n // seul un service en cours propose ce geste.\n stopService: async (id) => {\n const service = (await listTrayServices()).find((s) => s.id === id);\n if (!service?.agentId) throw new Error(`Aucun agent pour ${id}`);\n return stopProcess(id, service.agentId);\n },\n restartService: (id) => restartProcess(id),\n onServicesChanged: onTrayServicesChanged,\n\n lan: {\n read: () => {\n const info = networkInfo();\n // `lanUrls` est déjà ce qu'on voudrait lire au survol : des adresses\n // joignables, pas des IP brutes. Vide hors mode réseau local.\n return { enabled: info.lanEnabled, addresses: info.lanUrls };\n },\n toggle: (enabled) => setLanMode(enabled),\n },\n\n warn: (message) => console.log(message),\n });\n }\n}\n\nmain().catch(async (err) => {\n console.error('[cli] Fatal error:', err);\n\n // With a terminal, the message above is the report. Without one, it goes\n // nowhere: serve it as a page and open it in the browser instead.\n if (startupFailure) {\n try {\n const { diagnose, renderFailurePage, capturedLines, showStartupFailure } = startupFailure;\n const html = renderFailurePage(\n diagnose(err, resolvePort()),\n capturedLines(),\n {\n 'Version': version,\n 'Dossier de travail': process.cwd(),\n 'Node': process.execPath,\n 'Runeya': fileURLToPath(import.meta.url),\n },\n );\n await showStartupFailure(html);\n } catch (reportErr) {\n console.error('[cli] Impossible d\\'afficher le rapport d\\'erreur:', reportErr);\n }\n }\n\n process.exit(1);\n});\n","/**\n * Resolve the HTTP port Runeya should listen on.\n *\n * Only RUNEYA_HTTP_PORT is read (default 4000) — the generic PORT variable is\n * intentionally ignored so it can stay reserved for the user's own services.\n *\n * Throws if the resolved value is not an integer in [1, 65535].\n */\nexport function resolvePort(): number {\n const raw = process.env.RUNEYA_HTTP_PORT;\n if (raw === undefined) return 4000;\n\n const port = Number(raw);\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw new Error(\n `Invalid port: ${JSON.stringify(raw)}. Must be an integer between 1 and 65535.`,\n );\n }\n return port;\n}\n"],"mappings":"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","names":["resolve","port"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatUptime,
|
|
3
|
+
instanceUrl,
|
|
4
|
+
parseInstancesArgs,
|
|
5
|
+
renderInstances,
|
|
6
|
+
runInstancesCommand,
|
|
7
|
+
shortenPath
|
|
8
|
+
} from "./chunk-PH4E5WDN.js";
|
|
9
|
+
export {
|
|
10
|
+
formatUptime,
|
|
11
|
+
instanceUrl,
|
|
12
|
+
parseInstancesArgs,
|
|
13
|
+
renderInstances,
|
|
14
|
+
runInstancesCommand,
|
|
15
|
+
shortenPath
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=instances-command-KZ5UGXOR.js.map
|
package/node-ILM6MV56.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appendToPath,
|
|
3
|
+
ensureNodeBinOnPath,
|
|
4
|
+
ensureUserBinsOnPath,
|
|
5
|
+
isCliAvailable,
|
|
6
|
+
readLoginShellPath,
|
|
7
|
+
resolveCliInvocation,
|
|
8
|
+
stampConsole,
|
|
9
|
+
whichCommand
|
|
10
|
+
} from "./chunk-B7MABGQN.js";
|
|
11
|
+
export {
|
|
12
|
+
appendToPath,
|
|
13
|
+
ensureNodeBinOnPath,
|
|
14
|
+
ensureUserBinsOnPath,
|
|
15
|
+
isCliAvailable,
|
|
16
|
+
readLoginShellPath,
|
|
17
|
+
resolveCliInvocation,
|
|
18
|
+
stampConsole,
|
|
19
|
+
whichCommand
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=node-ILM6MV56.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runeya/runeya",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.103",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"runeya": "./index.js"
|
|
@@ -34,5 +34,8 @@
|
|
|
34
34
|
"yjs": "^13.6.31",
|
|
35
35
|
"zod": "^4.4.3",
|
|
36
36
|
"zod-openapi": "^6.0.0"
|
|
37
|
+
},
|
|
38
|
+
"optionalDependencies": {
|
|
39
|
+
"systray2": "2.1.4"
|
|
37
40
|
}
|
|
38
41
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|