@runeya/runeya 2.0.123 → 2.0.125
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-manager-2G55ZFCL.js → agent-manager-FZFFWISA.js} +2 -2
- package/{chat-MOAVENBI.js → chat-JIJQ7IJS.js} +4 -4
- package/{chunk-MSLFR2EN.js → chunk-4PN7QBNM.js} +57 -5
- package/chunk-4PN7QBNM.js.map +1 -0
- package/{chunk-DUHCY3JU.js → chunk-GKK3ACWB.js} +14 -9
- package/chunk-GKK3ACWB.js.map +1 -0
- package/{chunk-TNJFDWJX.js → chunk-H22YLVQE.js} +9 -4
- package/chunk-H22YLVQE.js.map +1 -0
- package/{companion-7VOV4W3T.js → companion-OZODV5BR.js} +3 -3
- package/index.js +3 -3
- package/package.json +1 -1
- package/{src-DN2IGASI.js → src-SGSG2RSF.js} +48 -12
- package/{src-DN2IGASI.js.map → src-SGSG2RSF.js.map} +1 -1
- package/web/assets/{AgentScalarChatInterface.vue-DrcrJYKe.js → AgentScalarChatInterface.vue-Bv7WQetq.js} +1 -1
- package/web/assets/{AgentTerminalPage-BonnuSSS.js → AgentTerminalPage-CMA5oI2T.js} +1 -1
- package/web/assets/AiChatPage-C0Ho1rG3.js +1 -0
- package/web/assets/{AppLayout-DRTTSl7g.js → AppLayout-DBKRAp0R.js} +1 -1
- package/web/assets/{AuditPage-CBWGaY0D.js → AuditPage-fZVhSJlE.js} +1 -1
- package/web/assets/CloudAccountPage-2LiTQCKr.js +1 -0
- package/web/assets/{CloudAccountPage-DvbOBtHJ.js → CloudAccountPage-CunPTy1b.js} +1 -1
- package/web/assets/{CloudMessagingPage-BB-_RdEk.js → CloudMessagingPage-DWciFn32.js} +1 -1
- package/web/assets/{DashboardPage-MdYRjTwv.js → DashboardPage-3psdQljM.js} +1 -1
- package/web/assets/{DirectoryPickerDialog-DROtNZ9T.js → DirectoryPickerDialog-DiiAUQKg.js} +1 -1
- package/web/assets/{EditorIcon-LCl9V_-a.js → EditorIcon-BZyy2C12.js} +1 -1
- package/web/assets/{EnvironmentForm-BUadxutb.js → EnvironmentForm-MRC8U5op.js} +1 -1
- package/web/assets/{EnvironmentFormPage-Do3NwXL5.js → EnvironmentFormPage-gd8fGS8P.js} +1 -1
- package/web/assets/{EnvironmentListPage-DiG8nF1p.js → EnvironmentListPage-DgbclvZs.js} +1 -1
- package/web/assets/{KanbanBoardPage-_QCZ2A2f.js → KanbanBoardPage-BBT0gqjT.js} +3 -3
- package/web/assets/{KanbanListPage-nyfKMn50.js → KanbanListPage-CidIQgAq.js} +1 -1
- package/web/assets/{LaunchProjectPage-VHAUZ-cq.js → LaunchProjectPage-DBtkrI-A.js} +1 -1
- package/web/assets/{LaunchServicesPage-CRv2zJxH.js → LaunchServicesPage-DdmfVxYL.js} +1 -1
- package/web/assets/{LogViewer-DcoQF_33.js → LogViewer-CvDPgFjq.js} +1 -1
- package/web/assets/{OrgKeyPrompt-X9hHtpi9.js → OrgKeyPrompt-D3RmJEtb.js} +1 -1
- package/web/assets/{ProcessControls-PKQWukd7.js → ProcessControls-neMxqIY_.js} +1 -1
- package/web/assets/{ProcessDetailPage-DhFoi4DT.js → ProcessDetailPage-Dj0L8Jz0.js} +1 -1
- package/web/assets/{ProcessMetrics-CMewzyxA.js → ProcessMetrics-Bb7yNIVd.js} +1 -1
- package/web/assets/{RandomJobTestPage-CErdKP1K.js → RandomJobTestPage-ohHAOaio.js} +1 -1
- package/web/assets/{ScenarioEditorPage-CpRlfU3g.js → ScenarioEditorPage-BIcmG3wo.js} +1 -1
- package/web/assets/{SendToChatDialog-DIp62wvw.js → SendToChatDialog-oi4KFAVq.js} +1 -1
- package/web/assets/{ServiceControlsBar-Bk4M-tKR.js → ServiceControlsBar-GgoPszoH.js} +1 -1
- package/web/assets/{ServiceDetailPage-BxAZTqFu.js → ServiceDetailPage-CIDlO0iu.js} +1 -1
- package/web/assets/ServiceFormPage-Q_M2GgKE.css +1 -0
- package/web/assets/ServiceFormPage-p3AUhHLN.js +1 -0
- package/web/assets/{SettingsPage-Dx1eYZKP.js → SettingsPage-B_heumvd.js} +4 -4
- package/web/assets/{UnlockPage-CgynzFN3.js → UnlockPage-nz_1VQWy.js} +1 -1
- package/web/assets/{VaultMigrationPage-Cw--n60U.js → VaultMigrationPage-B_nZC8Cc.js} +1 -1
- package/web/assets/{VersionBadge-Ct-qYNDF.js → VersionBadge-DJJK7bgD.js} +1 -1
- package/web/assets/WikiPage-DiCUjWEu.js +1 -0
- package/web/assets/{WikiView-Izg2SvGt.js → WikiView-vYMnLt41.js} +1 -1
- package/web/assets/{add-scalar-classes-BP_OZa5m.js → add-scalar-classes-_7NDhIUO.js} +3 -3
- package/web/assets/{autocomplete-DMfvn4sK.js → autocomplete-BTMTTAk9.js} +1 -1
- package/web/assets/{basic-shape-diamond.svg-B5H1r2bp.js → basic-shape-diamond.svg-CZQG7mdB.js} +1 -1
- package/web/assets/{basic-shape-hexagon.svg-CYAjKF0z.js → basic-shape-hexagon.svg-BnLoXUmj.js} +1 -1
- package/web/assets/{basic-shape-primary-circle-ellipse-round.svg-CgleCAf-.js → basic-shape-primary-circle-ellipse-round.svg-DDU6pRYe.js} +1 -1
- package/web/assets/{basic-shape-primary-square-rectangle.svg-1Oa48Hhs.js → basic-shape-primary-square-rectangle.svg-Dq_Zdck2.js} +1 -1
- package/web/assets/{basic-shape-shield.svg-F6dZwVUJ.js → basic-shape-shield.svg-DbFCxPmO.js} +1 -1
- package/web/assets/{browser-D3KJ0m2n.js → browser-CTYk99RA.js} +1 -1
- package/web/assets/{browser-CmPAWcJ7.js → browser-DowFjZcI.js} +1 -1
- package/web/assets/{card-Ciw7uU90.js → card-R4Q2Qr9t.js} +1 -1
- package/web/assets/{checkbox-BCCx0Nu6.js → checkbox-CfoV-T17.js} +1 -1
- package/web/assets/{chip-JRh6DXig.js → chip-V3vhLdcF.js} +1 -1
- package/web/assets/{client-BIlYBe0s.js → client-DHQNUKOx.js} +1 -1
- package/web/assets/{cloud-chat.store-BUYi4kYT.js → cloud-chat.store-CaSRn8Mg.js} +1 -1
- package/web/assets/cloud-client-CzGojtBl.js +1 -0
- package/web/assets/{cloud-session-CZWto5y3.js → cloud-session-D71P4F3g.js} +2 -2
- package/web/assets/cloud-session-DlLnrwVQ.js +1 -0
- package/web/assets/{column-DSBHw97f.js → column-CjJa3tsz.js} +1 -1
- package/web/assets/{computer-device-desktop-monitor.svg-D7wu2cQ4.js → computer-device-desktop-monitor.svg-CRLfD7-U.js} +1 -1
- package/web/assets/{computer-device-desktop.svg-BtVwjOEG.js → computer-device-desktop.svg-CGKq4iih.js} +1 -1
- package/web/assets/{computer-device-laptop.svg-f3tFeUHj.js → computer-device-laptop.svg-bmeM_RDO.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-android-samsung-back.svg-CmJcGkrL.js → computer-device-mobile-phone-android-samsung-back.svg-CFwMSjoP.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-android-samsung.svg-C2ke6Sbg.js → computer-device-mobile-phone-android-samsung.svg-iIOhGZVY.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-iphone-x-back.svg-DxMqUXKE.js → computer-device-mobile-phone-iphone-x-back.svg-CLqnsMnT.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-iphone-x.svg-DkbKlrh8.js → computer-device-mobile-phone-iphone-x.svg-XECS9ZDX.js} +1 -1
- package/web/assets/{computer-device-mobile-tablet-touch.svg-DP0uXMda.js → computer-device-mobile-tablet-touch.svg-CUR9IhGB.js} +1 -1
- package/web/assets/{computer-device-mobile-tablet.svg-C064ZFQm.js → computer-device-mobile-tablet.svg-BJGisjBt.js} +1 -1
- package/web/assets/{computer-device-network-ethernet-cat6.svg-Dwzl7zBN.js → computer-device-network-ethernet-cat6.svg-DzgiswAZ.js} +1 -1
- package/web/assets/{computer-device-network-lan-www.svg-BgErom5w.js → computer-device-network-lan-www.svg-Dr1frFpv.js} +1 -1
- package/web/assets/{computer-device-network-wifi-connection.svg-ByqNsV6y.js → computer-device-network-wifi-connection.svg-DSj6qxT1.js} +1 -1
- package/web/assets/{computer-device-network-wifi-router.svg-AySGITbi.js → computer-device-network-wifi-router.svg-8lGzw_-s.js} +1 -1
- package/web/assets/{cssMode-BqrZ4SB-.js → cssMode-sBjZEJAf.js} +1 -1
- package/web/assets/{divider-BswZTb8q.js → divider-p4BForJk.js} +1 -1
- package/web/assets/{docx-preview-t_oOha_C.js → docx-preview-D-bfEEBT.js} +1 -1
- package/web/assets/{ecology-science-erlenmeyer-flask.svg-Keg4ZY0z.js → ecology-science-erlenmeyer-flask.svg-DhxVJRJ1.js} +1 -1
- package/web/assets/{fieldset-DaWy9FsL.js → fieldset-CCZ1tJUm.js} +1 -1
- package/web/assets/{freemarker2-Br0kiufp.js → freemarker2-C8iPD1fo.js} +1 -1
- package/web/assets/{handlebars-BrATzKUL.js → handlebars-BbBZAhwL.js} +1 -1
- package/web/assets/{html-LWTJcTM2.js → html-BQ_SV3Jd.js} +1 -1
- package/web/assets/{htmlMode-A23pWfMP.js → htmlMode-DReHoZFB.js} +1 -1
- package/web/assets/{image-flash-lightning.svg-uQfoT6Ex.js → image-flash-lightning.svg-DbKHX2c2.js} +1 -1
- package/web/assets/{image-picture-flower.svg-XxD1bCHC.js → image-picture-flower.svg-CEpqP8le.js} +1 -1
- package/web/assets/{index-e5dmzMc-.js → index-PMr5ScNs.js} +4 -4
- package/web/assets/{interface-alert-exclamation-diamond.svg-gQAlkILu.js → interface-alert-exclamation-diamond.svg-CoNNtahD.js} +1 -1
- package/web/assets/{interface-alert-exclamation-triangle-warning.svg-Ga2rsl6o.js → interface-alert-exclamation-triangle-warning.svg-BHa7AW0u.js} +1 -1
- package/web/assets/{interface-alert-information-circle.svg-BS0N2R1M.js → interface-alert-information-circle.svg-CpRzO-l8.js} +1 -1
- package/web/assets/{interface-award-crown.svg-CtLbK4Gl.js → interface-award-crown.svg-BFOXAZFu.js} +1 -1
- package/web/assets/{interface-bookmark.svg-Clt6TTov.js → interface-bookmark-tag.svg-DpZGlSV4.js} +1 -1
- package/web/assets/{interface-bookmark-tag.svg-Dfd6eXAX.js → interface-bookmark.svg-DulnuoPg.js} +1 -1
- package/web/assets/{interface-calendar-date-one.svg-BmFNLrzR.js → interface-calendar-date-one.svg-CWQHbXWQ.js} +1 -1
- package/web/assets/{interface-content-book-open-pages.svg-u8kJbc3N.js → interface-content-book-open-pages.svg-BH97UDUJ.js} +1 -1
- package/web/assets/{interface-content-book-page.svg-Csk8d0R8.js → interface-content-book-page.svg-DmnJkpeN.js} +1 -1
- package/web/assets/{interface-content-file.svg-DIoD1UhJ.js → interface-content-file.svg-DkouOQzj.js} +1 -1
- package/web/assets/interface-content-folder.svg-BLBb2W1v.js +1 -0
- package/web/assets/{interface-content-folder.svg-ipO7hYM2.js → interface-content-folder.svg-DK2esxIw.js} +1 -1
- package/web/assets/{interface-copy-clipboard.svg-BaK2fHKS.js → interface-copy-clipboard.svg-DuwyZprv.js} +1 -1
- package/web/assets/{interface-edit-attachment.svg-CrpyP6c6.js → interface-edit-attachment.svg-C4lXPh7a.js} +1 -1
- package/web/assets/{interface-edit-binocular.svg-Cw-YeqUQ.js → interface-edit-binocular.svg-CuA4f4ED.js} +1 -1
- package/web/assets/{interface-edit-magic-wand.svg-BPa49t_4.js → interface-edit-magic-wand.svg-D-Cc4zpI.js} +1 -1
- package/web/assets/{interface-edit-tool-paint-roller.svg-Cfag7vxY.js → interface-edit-tool-paint-roller.svg-MtAeMQ6k.js} +1 -1
- package/web/assets/{interface-edit-tool-pencil.svg-BNAmX0d_.js → interface-edit-tool-pencil.svg-ZAP8C3Sw.js} +1 -1
- package/web/assets/{interface-favorite-award.svg-CIMvocAv.js → interface-favorite-award.svg-DRZh5var.js} +1 -1
- package/web/assets/{interface-favorite-flag.svg-8C3GXK06.js → interface-favorite-flag.svg-Dy0qBZak.js} +1 -1
- package/web/assets/{interface-favorite-heart.svg-CEU_IALn.js → interface-favorite-heart.svg-Cjxi5AEp.js} +1 -1
- package/web/assets/{interface-favorite-star.svg-Bs0RUtgk.js → interface-favorite-star.svg-B1OPbNTd.js} +1 -1
- package/web/assets/{interface-favorite-stars-sparkles.svg-CZYZ5qkH.js → interface-favorite-stars-sparkles.svg-CvnZTUkf.js} +1 -1
- package/web/assets/{interface-hierarchy-flowchart.svg-DOgEXHV2.js → interface-hierarchy-flowchart.svg-GGCH0pvQ.js} +1 -1
- package/web/assets/{interface-home-house.svg-lDERGk8q.js → interface-home-house.svg-DB_dC7eo.js} +1 -1
- package/web/assets/{interface-hyperlink.svg-CAZrs64U.js → interface-hyperlink.svg-LlMqAHmb.js} +1 -1
- package/web/assets/{interface-lighting-brightness.svg-CVANBB7i.js → interface-lighting-brightness.svg-DutEgNfQ.js} +1 -1
- package/web/assets/{interface-lock-closed.svg-qDLyceL-.js → interface-lock-closed.svg-DteyBWrL.js} +1 -1
- package/web/assets/{interface-lock-open-unlock.svg-Bc-cq6eU.js → interface-lock-open-unlock.svg-D2g-W1Mn.js} +1 -1
- package/web/assets/{interface-login-key.svg-D6wZBYEi.js → interface-login-key.svg-Dk1JjhYH.js} +1 -1
- package/web/assets/{interface-search.svg-BVM6kkvA.js → interface-search.svg-CDHAdhLc.js} +1 -1
- package/web/assets/{interface-setting-cog.svg-uJYqlmKx.js → interface-setting-cog.svg-BXKxgm-B.js} +1 -1
- package/web/assets/{interface-share-megaphone-bullhorn.svg-CgBVBu7Z.js → interface-share-megaphone-bullhorn.svg-Fq3c3_sE.js} +1 -1
- package/web/assets/{interface-share-rocket.svg-C1iCXMlX.js → interface-share-rocket.svg-BBIuiQ8_.js} +1 -1
- package/web/assets/{interface-share-satellite.svg-uH-Cvq9d.js → interface-share-satellite.svg-LZRzoY-Y.js} +1 -1
- package/web/assets/{interface-share-space-ship.svg-81lauyV5.js → interface-share-space-ship.svg-C6EewxDh.js} +1 -1
- package/web/assets/{interface-share.svg-DO85t-F0.js → interface-share.svg-Bj60UW_t.js} +1 -1
- package/web/assets/{interface-signal-square.svg-CFAni6lY.js → interface-signal-square.svg-wJGg3ZJ7.js} +1 -1
- package/web/assets/{interface-time-clock-circle.svg-BUQfluh7.js → interface-time-clock-circle.svg-C2Ki_bgh.js} +1 -1
- package/web/assets/{interface-time-hour-glass.svg-BAZDU-C5.js → interface-time-hour-glass.svg-BeaTe2YW.js} +1 -1
- package/web/assets/{interface-users-multiple.svg-Bj0AvF2-.js → interface-users-multiple.svg-ZNPhOLEJ.js} +1 -1
- package/web/assets/{interface-weather-moon.svg-Cxz-5thD.js → interface-weather-moon.svg-CzOxK1E2.js} +1 -1
- package/web/assets/{javascript-CuP68vN5.js → javascript-CV2jmATe.js} +1 -1
- package/web/assets/{jsonMode-CdGjze9r.js → jsonMode-BpNATOZn.js} +1 -1
- package/web/assets/{liquid-fJJZPdJb.js → liquid-Bkbhlfu6.js} +1 -1
- package/web/assets/{lspLanguageFeatures-YzzH9q9a.js → lspLanguageFeatures-BIiCr6WR.js} +1 -1
- package/web/assets/{mail-chat-bubble-square.svg-DY1-sN8v.js → mail-chat-bubble-square.svg-B-R9ItyG.js} +1 -1
- package/web/assets/{mail-send-email-paper-airplane.svg-6zVEUG2-.js → mail-send-email-paper-airplane.svg-F4sC3JuQ.js} +1 -1
- package/web/assets/{mail-send-envelope.svg-DNpA7Auy.js → mail-send-envelope.svg-BaE9bGol.js} +1 -1
- package/web/assets/{mdx-CphM-wvX.js → mdx-CsTzsRLc.js} +1 -1
- package/web/assets/{minus-DD84SZSh.js → minus-CsIPqtIl.js} +1 -1
- package/web/assets/modal-B_0-h4nC.js +1 -0
- package/web/assets/{modal-CKGM8Wb3.js → modal-KwmdNF_4.js} +1 -1
- package/web/assets/{money-cashier-receipt.svg-ChxLUMT0.js → money-cashier-receipt.svg-C8rqn3qa.js} +1 -1
- package/web/assets/{money-currency-dollar-pay.svg-CcPdfv1E.js → money-currency-dollar-pay.svg-BW5dnMxx.js} +1 -1
- package/web/assets/{money-graph-arrow-increase.svg-BsmXO8yM.js → money-graph-arrow-increase.svg-fHNc8kor.js} +1 -1
- package/web/assets/{money-graph-bar-chart-increase.svg-QVk3zD8i.js → money-graph-bar-chart-increase.svg-65H_xZ15.js} +1 -1
- package/web/assets/{multiselect-3cR58mLz.js → multiselect-Z0owdrkn.js} +1 -1
- package/web/assets/{nature-ecology-leaf.svg-nzup63P6.js → nature-ecology-leaf.svg-BIZVZEYz.js} +1 -1
- package/web/assets/{password-CCYLOu-C.js → password-Be5EVCzq.js} +1 -1
- package/web/assets/{phone-telephone.svg-BLtgdZw-.js → phone-telephone.svg-B1dHjXge.js} +1 -1
- package/web/assets/{plus-jk73RdzY.js → plus-BY4yX4ZS.js} +1 -1
- package/web/assets/process.store-B-PvNJQb.js +1 -0
- package/web/assets/{programming-bug.svg-BCN6lOn1.js → programming-bug.svg-DJHBIgCF.js} +1 -1
- package/web/assets/{programming-cloud.svg-DHNBRNkQ.js → programming-cloud.svg-26MWe8cC.js} +1 -1
- package/web/assets/{programming-computer-database-server.svg-C4DheEbm.js → programming-computer-database-server.svg-Dy7gdMab.js} +1 -1
- package/web/assets/{programming-computer-database.svg-cD2w2ZZ6.js → programming-computer-database.svg-3HsFit56.js} +1 -1
- package/web/assets/{programming-module-four-layout.svg-D6_P2rTG.js → programming-module-four-layout.svg-CLumiwsC.js} +1 -1
- package/web/assets/{programming-module-three.svg-Dc076Z_f.js → programming-module-three.svg-3DvVSvY_.js} +1 -1
- package/web/assets/{programming-module.svg-D0c9akII.js → programming-module.svg-CgtgW8TW.js} +1 -1
- package/web/assets/{programming-script-code.svg-BrT3KZQe.js → programming-script-code.svg-DdeXzy2-.js} +1 -1
- package/web/assets/project-launch.store-DtFeb4vv.js +1 -0
- package/web/assets/project.store-DcaBpnnB.js +1 -0
- package/web/assets/{python-DMw-TRDY.js → python-YqWM3LFr.js} +1 -1
- package/web/assets/{radiobutton-CnoEo0qc.js → radiobutton-Pm1c37Fw.js} +1 -1
- package/web/assets/{razor-BTS4Lk96.js → razor-BtNiyC__.js} +1 -1
- package/web/assets/router-DnVYXVMw.js +1 -0
- package/web/assets/settings-scope-DR8NUZr5.js +1 -0
- package/web/assets/{settings.store-DeGpnclr.js → settings.store-CniuNQ3t.js} +1 -1
- package/web/assets/{shopping-cart.svg-pvFNKXP_.js → shopping-cart.svg-ejbEU5yG.js} +1 -1
- package/web/assets/{shopping-gift-present.svg-PYJ4_vdS.js → shopping-gift-present.svg-RLuyvmga.js} +1 -1
- package/web/assets/{shopping-shipping-box-parcel-package.svg-KMRd9Rmg.js → shopping-shipping-box-parcel-package.svg-0GduEUbl.js} +1 -1
- package/web/assets/{src-NXursDRf.js → src-BS3JGGS_.js} +1 -1
- package/web/assets/{src-BsadAol0.js → src-BzZzroPd.js} +3 -3
- package/web/assets/{tabpanel-CKudNnqo.js → tabpanel-CssLXh-h.js} +1 -1
- package/web/assets/{tag-new-circle.svg-Bf83DYRq.js → tag-new-circle.svg-CEdgH15R.js} +1 -1
- package/web/assets/theme-C7HVmgEO.js +1 -0
- package/web/assets/{toggleswitch-Cv0supU2.js → toggleswitch-CEiGEBl3.js} +1 -1
- package/web/assets/{travel-map-earth-globe.svg-WxnFDzEH.js → travel-map-earth-globe.svg-Dmwx1Lus.js} +1 -1
- package/web/assets/trpc-C6zILEMh.js +1 -0
- package/web/assets/{tsMode-CfruLmor.js → tsMode-DpPT4F6s.js} +1 -1
- package/web/assets/{typescript-BvsjNfHT.js → typescript-DoO0syM1.js} +1 -1
- package/web/assets/useAiChatDrawer-CnrYG1GW.js +1 -0
- package/web/assets/{useCloudOrg-B0o8vN4e.js → useCloudOrg-DWmP9gqs.js} +1 -1
- package/web/assets/{useEnvVarAutocomplete-DJMTIim7.js → useEnvVarAutocomplete-Dkx7Cn9l.js} +1 -1
- package/web/assets/{useProjectCatalog-B6GXBDDA.js → useProjectCatalog-Cu3VZu2F.js} +1 -1
- package/web/assets/{useProjectCloudOrg-BwLsTiz0.js → useProjectCloudOrg-CG7seJKu.js} +1 -1
- package/web/assets/{useServiceUrlHost-CE4Qoy-J.js → useServiceUrlHost-ADKWqhx0.js} +1 -1
- package/web/assets/{xml-BTID20Kj.js → xml-FoCdWVvH.js} +1 -1
- package/web/assets/{yaml-BtOf_8je.js → yaml-CgRsanOy.js} +1 -1
- package/web/index.html +1 -1
- package/chunk-DUHCY3JU.js.map +0 -1
- package/chunk-MSLFR2EN.js.map +0 -1
- package/chunk-TNJFDWJX.js.map +0 -1
- package/web/assets/AiChatPage-DzTc9-iH.js +0 -1
- package/web/assets/CloudAccountPage-DTrPLz-p.js +0 -1
- package/web/assets/ServiceFormPage-B8jcMT3b.css +0 -1
- package/web/assets/ServiceFormPage-Dr_e9QMM.js +0 -1
- package/web/assets/WikiPage-D7N7nA2O.js +0 -1
- package/web/assets/cloud-client-CujRC6FF.js +0 -1
- package/web/assets/cloud-session-CSIV9Uvx.js +0 -1
- package/web/assets/interface-content-folder.svg-BPZbNQNK.js +0 -1
- package/web/assets/modal-Dd5rzDUd.js +0 -1
- package/web/assets/process.store-jsfEBwiA.js +0 -1
- package/web/assets/project-launch.store-Bp7vasUu.js +0 -1
- package/web/assets/project.store-DuZriz9o.js +0 -1
- package/web/assets/router-BU2tqcBm.js +0 -1
- package/web/assets/settings-scope-Bg_X1n_Y.js +0 -1
- package/web/assets/theme-D6M00FyZ.js +0 -1
- package/web/assets/trpc-mWVODCs2.js +0 -1
- package/web/assets/useAiChatDrawer-vNey6IKe.js +0 -1
- /package/{agent-manager-2G55ZFCL.js.map → agent-manager-FZFFWISA.js.map} +0 -0
- /package/{chat-MOAVENBI.js.map → chat-JIJQ7IJS.js.map} +0 -0
- /package/{companion-7VOV4W3T.js.map → companion-OZODV5BR.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../server/src/create-server.ts","../../server/src/trpc/routers/health.ts","../../server/src/trpc/routers/app-update.ts","../../server/src/trpc/routers/changelog.ts","../../server/src/trpc/routers/project.ts","../../server/src/services/current-project.ts","../../server/src/services/org-keys.ts","../../server/src/services/master-password.ts","../../server/src/services/service-graph.ts","../../server/src/trpc/routers/agent.ts","../../server/src/trpc/routers/process.ts","../../server/src/services/process-control.ts","../../server/src/trpc/routers/audit.ts","../../server/src/trpc/routers/setup.ts","../../server/src/trpc/routers/environment.ts","../../server/src/trpc/routers/settings.ts","../../server/src/trpc/routers/editor.ts","../../server/src/services/user-config-manager.ts","../../server/src/trpc/routers/api-keys.ts","../../server/src/trpc/routers/git.ts","../../server/src/trpc/routers/scenario.ts","../../server/src/trpc/crud-procedure-utils.ts","../../server/src/trpc/ai-generation-procedure-utils.ts","../../server/src/services/ai-generation.ts","../../server/src/services/scenario-runner.ts","../../server/src/services/scenario-presets.ts","../../server/src/trpc/routers/debug.ts","../../server/src/trpc/routers/diagnostics.ts","../../server/src/services/log-buffer.ts","../../server/src/trpc/routers/kanban-queue.ts","../../server/src/services/kanban-queue.ts","../../server/src/trpc/routers/kanban.ts","../../server/src/trpc/routers/terminal.ts","../../server/src/trpc/routers/utility.ts","../../server/src/trpc/routers/wiki.ts","../../server/src/trpc/routers/config.ts","../../server/src/trpc/routers/cloud-sync.ts","../../server/src/services/org-sync-scope.ts","../../server/src/services/org-canary.ts","../../server/src/services/cloud-sync-bridge.ts","../../server/src/services/sync-doc-cache.ts","../../server/src/services/key-adoption.ts","../../server/src/trpc/routers/filesystem.ts","../../server/src/trpc/routers/desktop.ts","../../server/src/services/desktop-launcher.ts","../../server/src/services/tray-accent.ts","../../server/src/trpc/router.ts","../../server/src/middleware/error-handler.ts","../../server/src/services/migration-engine.ts","../../server/src/services/file-security.ts","../../server/src/services/vault-migration.ts","../../server/src/services/settings-migration.ts","../../server/src/migrations/migrate-from-legacy.ts","../../server/src/services/server-state.ts","../../server/src/services/openapi.ts","../../server/src/services/image-cleanup.service.ts","../../server/src/index.ts","../../server/src/commands/pull-env.ts","../../server/src/services/tray-services.ts","../../server/src/services/tray-icon.ts","../../server/src/services/png-to-ico.ts","../../server/src/services/runeya-icon.ts"],"sourcesContent":["import express from 'express';\nimport cors from 'cors';\nimport { createServer, type Server } from 'node:http';\nimport { resolve } from 'node:path';\nimport { WebSocketServer, WebSocket } from 'ws';\nimport { createExpressMiddleware } from '@trpc/server/adapters/express';\nimport { applyWSSHandler } from '@trpc/server/adapters/ws';\nimport { appRouter } from './trpc/router.js';\nimport { createContext } from './trpc/trpc.js';\nimport { getCloudApiUrl, getDeviceName } from './trpc/routers/cloud-auth.js';\nimport { cloudSessionStore } from './services/cloud-session-store.js';\nimport { readCloudIdentity, accountForOrg, orgCloudUrl } from './services/cloud-api.js';\nimport { APP_VERSION_HEADER, appVersion } from './config/app-version.js';\nimport { errorHandler } from './middleware/error-handler.js';\nimport { agentManager } from './services/agent-manager.js';\nimport { agentSpawner } from './services/agent-spawner.js';\nimport { startClaudeTranscriptWatcher, stopClaudeTranscriptWatcher } from './services/claude-transcript-sync.js';\nimport { startCodexTranscriptWatcher, stopCodexTranscriptWatcher } from './services/codex-transcript-sync.js';\nimport { settingsManager } from './services/settings-manager.js';\nimport { applyPersistedLanMode, registerHttpServer } from './services/lan-mode.js';\nimport { installLogCapture } from './services/log-buffer.js';\nimport { unregisterInstance } from './services/instance-registry.js';\nimport { migrationEngine } from './services/migration-engine.js';\nimport { ensureFilePermissions } from './services/file-security.js';\nimport { auditService } from './services/audit-service.js';\nimport { environmentStore } from './services/environment-store.js';\nimport { ensureDataGitignore } from './utils/ensure-data-gitignore.js';\nimport { machineRoot, keyRoot, legacyVaultRoot, allVaultRoots, listOrgVaults, orgVaultRoot } from './services/vault-resolver.js';\nimport { sweepStaleTempFiles } from './services/run-store-utils.js';\nimport { openLegacyVault, migrateLegacyVault } from './services/vault-migration.js';\nimport { projectStore } from './services/project-store.js';\nimport { cloudSyncBridge } from './services/cloud-sync-bridge.js';\nimport { unlockOrgKeys, sealUnopenedOrgVaults } from './services/org-keys.js';\nimport { migrateSettingsIntoVaults } from './services/settings-migration.js';\nimport { serviceStore } from './services/service-store.js';\nimport { runLegacyMigration, runOverrideOnlyMigration, findLegacyKeyInBackup } from './migrations/migrate-from-legacy.js';\nimport { env } from './config/env.js';\nimport {\n setEncryptionKeyInMemory,\n getEncryptionKey,\n loadFromEnv,\n hasEncryptionKey,\n isCiMode,\n setPendingLegacyKey,\n getPendingLegacyKey,\n clearPendingLegacyKey,\n hasPendingLegacyKey,\n} from './utils/encryption-key.js';\nimport {\n generateJwtSecret,\n signJwt,\n verifyJwt,\n getJwtSecretGeneratedAt,\n} from './services/auth-token.js';\nimport {\n writeEncryptedKey,\n readEncryptedKey,\n writeVerifyFile,\n verifyEncryptionKey,\n hasEncryptedKeyFile,\n hasVerifyFile,\n} from './services/master-password.js';\nimport { getServerState } from './services/server-state.js';\nimport { apiKeyStore } from './services/api-key-store.js';\nimport { generateLlmsTxt } from './services/llms-txt-generator.js';\nimport { getOpenApiDocument } from './services/openapi.js';\nimport rateLimit from 'express-rate-limit';\nimport { existsSync, createReadStream } from 'node:fs';\nimport multer from 'multer';\nimport { imageStorageService, ALLOWED_MIME_TYPES, MAX_IMAGE_SIZE_BYTES } from './services/image-storage.service.js';\nimport { imageCleanupService } from './services/image-cleanup.service.js';\n\nexport interface ServerInstance {\n app: express.Express;\n server: Server;\n wss: WebSocketServer;\n shutdown: () => Promise<void>;\n}\n\nfunction csrfMiddleware(req: express.Request, res: express.Response, next: express.NextFunction): void {\n const contentType = req.headers['content-type'] ?? '';\n if (!contentType.includes('application/json')) {\n res.status(415).json({ error: 'Content-Type must be application/json' });\n return;\n }\n const origin = req.headers['origin'];\n if (origin) {\n const allowedOrigins = [\n `http://localhost:${env.PORT}`,\n `http://127.0.0.1:${env.PORT}`,\n 'http://localhost:5173', // dev Vite\n 'http://127.0.0.1:5173',\n ];\n // In LAN mode, allow any origin pointing to the server port (e.g. tablet on local network)\n if (env.RUNEYA_LAN_PROXY) {\n try {\n const parsed = new URL(origin);\n const originPort = parsed.port || (parsed.protocol === 'https:' ? '443' : '80');\n if (originPort === String(env.PORT) || originPort === '5173') {\n next();\n return;\n }\n } catch {\n // invalid origin URL — fall through to deny\n }\n }\n if (!allowedOrigins.includes(origin)) {\n res.status(403).json({ error: 'Forbidden origin' });\n return;\n }\n }\n next();\n}\n\nconst authLimiter = rateLimit({\n windowMs: 15 * 60 * 1000,\n max: 5,\n standardHeaders: true,\n legacyHeaders: false,\n message: { error: 'Trop de tentatives. Réessayez dans 15 minutes.' },\n});\n\nconst llmsLimiter = rateLimit({\n windowMs: 60 * 1000, // 1 minute\n max: 60,\n standardHeaders: true,\n legacyHeaders: false,\n message: { error: 'Rate limit exceeded. Retry in 1 minute.' },\n});\n\nexport async function createLocalServer(): Promise<ServerInstance> {\n // Before anything logs: the settings panel streams this buffer, and a boot\n // whose first lines are missing is the one you most want to read.\n installLogCapture();\n\n // Generate JWT signing secret first\n generateJwtSecret();\n\n // Load encryption key from env var (CI mode) or check state\n const ciMode = await loadFromEnv();\n\n // Run legacy migration FIRST — loads key temporarily, re-encrypts, then stores in pending holder\n await runLegacyMigration(env.DATA_DIR);\n\n // Handle server restart between migration and setup:\n // The pending key is in-memory only, so recover it from backup if needed.\n // Only attempt recovery if .runeya-verify doesn't exist — if it does, setup\n // was already completed at least once and we should not treat this as a migration.\n const keyDir = await keyRoot();\n if (!ciMode && !hasPendingLegacyKey() && !(await hasEncryptedKeyFile(keyDir)) && !(await hasVerifyFile(keyDir))) {\n const recoveredKey = await findLegacyKeyInBackup(env.DATA_DIR);\n if (recoveredKey) {\n setPendingLegacyKey(recoveredKey);\n console.log('[server] Legacy key recovered from backup — setup required to migrate');\n }\n }\n\n if (!ciMode) {\n const { state } = await getServerState();\n if (state === 'locked') {\n console.log('[server] Serveur verrouillé — master password requis');\n } else if (state === 'setup') {\n console.log('[server] Premier lancement — setup requis');\n }\n }\n\n // The local vault is NOT created here. It appears when a local project is\n // written into it (see `ensureLocalVault`), so working only on cloud projects\n // leaves the directories Runeya was started in untouched.\n const absoluteDataDir = resolve(env.DATA_DIR);\n console.log(`[server] Local project directory: ${absoluteDataDir}`);\n console.log(`[server] Machine directory: ${machineRoot()}`);\n if (existsSync(env.DATA_DIR)) {\n // Only meaningful once the directory exists: it guards files in it.\n await ensureDataGitignore(env.DATA_DIR);\n }\n\n // Initialize settings and run migrations\n await settingsManager.getSettings();\n // Avant toute écoute : le mode LAN mémorisé décide de l'adresse d'écoute.\n await applyPersistedLanMode();\n await migrationEngine.run();\n\n // Enforce secure file permissions on sensitive data files\n await ensureFilePermissions();\n\n // Clean up old audit log entries\n auditService.cleanup().catch((err) => console.error('[server] Audit cleanup failed:', err));\n\n const app = express();\n\n /**\n * Qui tient une connexion, et combien de temps.\n *\n * Un navigateur n'accorde que six connexions par hôte, partagées entre TOUS\n * ses onglets : une poignée de requêtes lentes suffit à faire attendre\n * l'ouverture d'un WebSocket, sans que rien ne le signale nulle part. On\n * journalise donc ce qui dépasse la seconde, et ce qui est encore en vol\n * pendant ce temps.\n */\n let inFlight = 0;\n app.use((req, res, next) => {\n const startedAt = Date.now();\n inFlight++;\n const label = `${req.method} ${req.originalUrl.split('?')[0]}`;\n const slow = setTimeout(() => {\n console.warn(`[http] LENTE (>1s, toujours en cours) ${label} — ${inFlight} requête(s) en vol`);\n }, 1000);\n res.on('close', () => {\n clearTimeout(slow);\n inFlight--;\n const ms = Date.now() - startedAt;\n if (ms >= 1000) console.warn(`[http] ${label} a tenu une connexion ${(ms / 1000).toFixed(1)}s`);\n });\n next();\n });\n\n // CORS: restrict to localhost in dev, configurable via env\n // In LAN mode, allow any origin pointing to the server port or Vite dev port\n const corsOrigin = env.CORS_ORIGIN ?? (env.RUNEYA_LAN_PROXY\n ? (origin: string | undefined, cb: (err: Error | null, allow?: boolean) => void) => {\n if (!origin) { cb(null, false); return; }\n try {\n const parsed = new URL(origin);\n const port = parsed.port || (parsed.protocol === 'https:' ? '443' : '80');\n cb(null, port === String(env.PORT) || port === '5173');\n } catch {\n cb(null, false);\n }\n }\n : 'http://localhost:5173');\n app.use(cors({\n origin: corsOrigin,\n credentials: true,\n }));\n\n // Called once after the encryption key is set in memory (unlock or setup).\n // Idempotent: safe to call even if already done.\n let postUnlockDone = false;\n async function runPostUnlock(masterPassword: string | null = null): Promise<void> {\n if (postUnlockDone) return;\n postUnlockDone = true;\n\n // Avant tout : sceller les coffres qui ont leur propre clé et que rien n'a\n // encore ouverts. Tant qu'ils ne le sont pas, ils héritent en silence de la\n // clé machine — ce qui ne les rend pas lisibles, seulement inscriptibles\n // sous la mauvaise clé.\n const sealed = await sealUnopenedOrgVaults();\n if (sealed.length > 0) {\n console.log(`[org-keys] ${sealed.length} coffre(s) scellé(s) le temps de l'ouverture`);\n }\n\n // Puis : chaque organisation présente sur ce disque reçoit sa clé — la\n // sienne si elle en a déjà une, sinon la clé machine, qui est de toute\n // façon celle sous laquelle ses données sont écrites. Rien n'est converti,\n // et une organisation dont la clé n'est pas la nôtre est simplement laissée\n // fermée plutôt que de bloquer la machine entière.\n const orgKeys = await unlockOrgKeys(masterPassword);\n if (orgKeys.seeded.length > 0) {\n console.log(`[org-keys] ${orgKeys.seeded.length} organisation(s) ont reçu leur propre clé de chiffrement`);\n }\n for (const orgId of orgKeys.locked) {\n console.error(`[org-keys] org ${orgId}: sa clé ne s'ouvre pas avec ce master password — ce coffre reste fermé.`);\n }\n\n // Les réglages descendent dans le coffre de leur organisation, une fois.\n const settingsMove = await migrateSettingsIntoVaults();\n if (settingsMove.movedTo) {\n console.log(`[settings] réglages déplacés vers l'organisation ${settingsMove.movedTo} : ${settingsMove.files.join(', ')}`);\n }\n if (settingsMove.ambiguous.length > 0) {\n console.warn(\n `[settings] réglages encore au niveau du poste : ${settingsMove.ambiguous.length} organisations sur cette machine,`\n + ' impossible de deviner à laquelle ils appartiennent — répartissez-les depuis les réglages.',\n );\n }\n\n await runOverrideOnlyMigration(env.DATA_DIR);\n\n if (env.MODE === 'local-simple') {\n const projects = await projectStore.list();\n if (projects.length === 0) {\n const project = await projectStore.create({\n name: 'My Local Project',\n description: 'Auto-generated default project for local development',\n });\n const localEnv = await environmentStore.create({\n projectId: project.id,\n name: 'Local',\n description: 'Default local environment (immutable)',\n variables: {},\n parentIds: [],\n color: '#22c55e',\n immutable: true,\n }, project.orgId);\n await projectStore.update({\n id: project.id,\n orgId: project.orgId,\n environmentIds: [localEnv.id],\n activeEnvironmentId: localEnv.id,\n });\n console.log('[server] Created default project with Local environment');\n }\n }\n\n // Initialize agent manager (loads persisted remote agents — requires encryption key)\n await agentManager.init();\n\n // Pas d'`await` : le spawn attend que l'agent ait démarré son propre\n // process Node et imprimé sa passphrase (~450 ms). Le retenir ici retardait\n // d'autant le `listen`, alors que rien de ce qui suit n'en dépend et que\n // l'interface sait déjà vivre avec un agent pas encore connecté.\n agentSpawner.spawnLocalAgent().catch((err) => {\n console.warn('[server] Failed to spawn the local agent:', err);\n });\n\n // Watch Claude Code's on-disk transcripts so PTY conversations stay\n // synced live with the non-PTY message view.\n startClaudeTranscriptWatcher().catch((err) => {\n console.warn('[server] Failed to start Claude transcript watcher:', err);\n });\n // Le pendant Codex : sans lui, une conversation Codex en terminal\n // n'annonce jamais la fin d'un tour, et le compagnon ne s'y déclenche pas.\n startCodexTranscriptWatcher();\n\n /**\n * Charger les services maintenant que la clé est là : le premier\n * chargement réussi prévient les abonnés — dont l'icône de barre système,\n * qui a pu lire à vide avant le déverrouillage.\n *\n * Volontairement non fatal. `load()` attrape déjà un `services.json`\n * illisible, mais pas `ensureProjectsLoaded()` ni `allVaultRoots()` : sans\n * cette garde, un coffre en mauvais état empêcherait le serveur de finir\n * son démarrage, là où la lecture paresseuse d'avant ne gênait que\n * l'appelant.\n */\n await serviceStore.list().catch((err) => {\n console.warn('[server] Failed to preload services:', err);\n });\n\n // Les fichiers temporaires d'écritures interrompues — voir sweepStaleTempFiles.\n // En arrière-plan : un balayage de répertoires n'a pas à retarder le démarrage.\n void (async () => {\n const orgRoots = (await listOrgVaults()).map((orgId) => orgVaultRoot(orgId));\n const removed = await sweepStaleTempFiles([machineRoot(), ...orgRoots, ...await allVaultRoots()]);\n if (removed > 0) console.log(`[server] ${removed} fichier(s) temporaire(s) orphelin(s) retiré(s)`);\n })().catch((err) => console.warn('[server] Temp file sweep failed:', err));\n\n // Start continuous project sync for every linked organization (requires the\n // encryption key, now loaded, to decrypt stored sync tokens).\n cloudSyncBridge.start().catch((err) => {\n console.warn('[server] Failed to start cloud sync bridge:', err);\n });\n }\n\n // If key is already available at startup (CI mode or legacy plaintext key), run now\n if (hasEncryptionKey()) {\n await runPostUnlock();\n }\n\n // GET /api/status — public\n app.get('/api/status', async (_req, res) => {\n try {\n const state = await getServerState();\n res.json({ ...state, ciMode: isCiMode() });\n } catch {\n res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n // GET /api/cloud/callback — lands here from the cloud authorization page,\n // carrying a single-use token. Exchanges it for a session token, which stays\n // on this server: the browser never receives a cloud credential.\n app.get('/api/cloud/callback', authLimiter, async (req, res) => {\n const token = typeof req.query['token'] === 'string' ? req.query['token'] : null;\n const state = typeof req.query['state'] === 'string' ? req.query['state'] : null;\n if (!token || !state) {\n res.status(400).send('Missing token or state.');\n return;\n }\n // Binds the callback to a login this server started; also stops a stray\n // redirect from installing someone else's token.\n const returnTo = cloudSessionStore.consumeState(state);\n if (!returnTo) {\n res.status(400).send('Unknown or expired login attempt. Please start again.');\n return;\n }\n try {\n // `/device/link`, not `/one-time-token/verify`: the latter hands back the\n // BROWSER's session, which made every linked machine share one session —\n // a sign-out in the web app unlinked them all, and two accounts could not\n // be linked from the same browser. This mints a session for this machine\n // alone, revocable on its own from the \"linked machines\" screens.\n const verifyRes = await fetch(`${getCloudApiUrl()}/api/auth/device/link`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', [APP_VERSION_HEADER]: appVersion },\n body: JSON.stringify({ token, name: getDeviceName() }),\n signal: AbortSignal.timeout(15_000),\n });\n if (!verifyRes.ok) {\n res.status(401).send('The cloud rejected this login token.');\n return;\n }\n // The bearer plugin exposes the SIGNED session token here. The JSON body\n // carries the raw, unsigned one, which `bearer({ requireSignature: true })`\n // would reject — so this header is the only usable source.\n const sessionToken = verifyRes.headers.get('set-auth-token');\n if (!sessionToken) {\n res.status(502).send('The cloud did not return a session token.');\n return;\n }\n // Qui vient de se connecter : c'est cette identité qui nomme le compte,\n // et sans elle deux liaisons du même utilisateur laisseraient deux tokens\n // côte à côte, dont un que plus rien ne rafraîchit.\n const identity = await readCloudIdentity(getCloudApiUrl(), sessionToken);\n if (!identity) {\n res.status(502).send('The cloud did not say who this session belongs to.');\n return;\n }\n await cloudSessionStore.add(getCloudApiUrl(), sessionToken, identity);\n // Sync authenticates with this session, so a fresh sign-in is exactly what\n // links paused on a rejected session were waiting for.\n void cloudSyncBridge.resumeAll();\n res.redirect(`${returnTo}?cloud=linked`);\n } catch {\n res.status(502).send('Could not reach the Runeya cloud.');\n }\n });\n\n // GET /api/cloud/{chat,kanban}/stream — proxies the cloud's SSE streams.\n // EventSource cannot send an Authorization header, so the local JWT travels\n // as a query param, exactly as the tRPC WebSocket already does. The cloud\n // token itself never leaves this process — it is attached here.\n function proxyCloudStream(localPath: string, upstreamPath: string): void {\n app.get(localPath, async (req, res) => {\n const jwt = typeof req.query['token'] === 'string' ? req.query['token'] : '';\n try {\n await verifyJwt(jwt);\n } catch {\n res.status(401).end();\n return;\n }\n const organizationId = typeof req.query['organizationId'] === 'string' ? req.query['organizationId'] : '';\n if (!organizationId) {\n res.status(400).end();\n return;\n }\n // Le flux appartient à une organisation : c'est elle qui dit sous quel\n // compte le relayer. Prendre « le » token du poste rouvrait le flux d'un\n // autre utilisateur dès qu'il y en a deux.\n const accountId = await accountForOrg(organizationId);\n const token = accountId ? await cloudSessionStore.getToken(accountId) : null;\n if (!accountId || !token) {\n res.status(401).end();\n return;\n }\n // Même règle que partout : l'adresse vient de l'organisation, le compte\n // ne fournit que le jeton.\n const streamBase = await orgCloudUrl(organizationId);\n // Long-lived stream: aborted when the browser disconnects, not on a timeout.\n const upstreamAbort = new AbortController();\n req.on('close', () => upstreamAbort.abort());\n try {\n const upstream = await fetch(\n `${streamBase.replace(/\\/+$/, '')}${upstreamPath}?organizationId=${encodeURIComponent(organizationId)}`,\n {\n headers: {\n Authorization: `Bearer ${token}`,\n [APP_VERSION_HEADER]: appVersion,\n Accept: 'text/event-stream',\n },\n signal: upstreamAbort.signal,\n },\n );\n if (!upstream.ok || !upstream.body) {\n res.status(upstream.status === 401 ? 401 : 502).end();\n return;\n }\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n 'X-Accel-Buffering': 'no',\n });\n const reader = upstream.body.getReader();\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n // nosemgrep: direct-response-write -- relais d'un flux SSE amont (text/event-stream), octets opaques, jamais du HTML\n res.write(value);\n }\n res.end();\n } catch {\n // Client disconnect or upstream failure — nothing left to send.\n if (!res.headersSent) res.status(502).end();\n else res.end();\n }\n });\n }\n\n // POST /api/cloud/kanban/image — relays a card attachment to the cloud, which\n // stores it in S3. The browser has no cloud credential, so the token is\n // attached here; the JWT in the query is what proves the local session, as on\n // the streams above.\n // The body limit here is only a memory guard, deliberately above the cloud's\n // own cap (55 MB, MAX_ATTACHMENT_BYTES): the cloud is the single authority on\n // what is too large, and it answers with a clear message. A tighter limit here\n // would reject the file first, with a bare 413 and no explanation.\n app.post(\n '/api/cloud/kanban/image',\n express.raw({ type: () => true, limit: '64mb' }),\n async (req, res) => {\n const jwt = typeof req.query['token'] === 'string' ? req.query['token'] : '';\n try {\n await verifyJwt(jwt);\n } catch {\n res.status(401).end();\n return;\n }\n const organizationId = typeof req.query['organizationId'] === 'string' ? req.query['organizationId'] : '';\n if (!organizationId) {\n res.status(400).end();\n return;\n }\n // Le flux appartient à une organisation : c'est elle qui dit sous quel\n // compte le relayer. Prendre « le » token du poste rouvrait le flux d'un\n // autre utilisateur dès qu'il y en a deux.\n const accountId = await accountForOrg(organizationId);\n const token = accountId ? await cloudSessionStore.getToken(accountId) : null;\n if (!accountId || !token) {\n res.status(401).end();\n return;\n }\n // Même règle que partout : l'adresse vient de l'organisation, le compte\n // ne fournit que le jeton.\n const streamBase = await orgCloudUrl(organizationId);\n // The original file name has to be forwarded too: the cloud stores it and\n // serves it back in Content-Disposition. Dropping it here is what made\n // every attachment land as \"file\".\n const upstreamQuery = new URLSearchParams({ organizationId });\n if (typeof req.query['name'] === 'string') upstreamQuery.set('name', req.query['name']);\n try {\n const upstream = await fetch(\n `${streamBase.replace(/\\/+$/, '')}/api/kanban/image?${upstreamQuery.toString()}`,\n {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n [APP_VERSION_HEADER]: appVersion,\n 'Content-Type': String(req.headers['content-type'] ?? 'application/octet-stream'),\n },\n body: req.body as Buffer,\n // A 55 MB body over a home upstream link takes minutes, not seconds.\n signal: AbortSignal.timeout(300_000),\n },\n );\n res.status(upstream.status).json(await upstream.json().catch(() => ({})));\n } catch {\n res.status(502).json({ error: 'upload-failed' });\n }\n },\n );\n\n // GET /api/cloud/kanban/file/:id — relays an attachment's bytes. Reading is\n // authenticated on the cloud side, and the browser holds no cloud credential,\n // so the local JWT proves the session here and the cloud token is added on\n // the way out.\n // DELETE goes through the same shape: the browser proves the local session\n // with its JWT, the cloud token is added here.\n app.delete('/api/cloud/kanban/file/:id', async (req, res) => {\n const jwt = typeof req.query['token'] === 'string' ? req.query['token'] : '';\n try {\n await verifyJwt(jwt);\n } catch {\n res.status(401).end();\n return;\n }\n // Comme les flux : la pièce jointe appartient à une organisation, et c'est\n // elle qui dit sous quel compte la demander. Absente — un appelant plus\n // ancien que le multicompte — le compte unique du poste répond, ce qui est\n // exactement ce qu'il attendait.\n const fileOrgId = typeof req.query['organizationId'] === 'string' ? req.query['organizationId'] : '';\n const fileAccountId = fileOrgId ? await accountForOrg(fileOrgId) : null;\n const token = await cloudSessionStore.getToken(fileAccountId ?? undefined);\n if (!token) {\n res.status(401).end();\n return;\n }\n try {\n const upstream = await fetch(\n `${fileOrgId ? await orgCloudUrl(fileOrgId) : ((await cloudSessionStore.getCloudUrl(fileAccountId ?? undefined)) ?? getCloudApiUrl())}`\n + `/api/kanban/file/${encodeURIComponent(req.params.id)}`,\n {\n method: 'DELETE',\n headers: { Authorization: `Bearer ${token}`, [APP_VERSION_HEADER]: appVersion },\n signal: AbortSignal.timeout(15_000),\n },\n );\n res.status(upstream.status).end();\n } catch {\n res.status(502).end();\n }\n });\n\n app.get('/api/cloud/kanban/file/:id', async (req, res) => {\n const jwt = typeof req.query['token'] === 'string' ? req.query['token'] : '';\n try {\n await verifyJwt(jwt);\n } catch {\n res.status(401).end();\n return;\n }\n // Comme les flux : la pièce jointe appartient à une organisation, et c'est\n // elle qui dit sous quel compte la demander. Absente — un appelant plus\n // ancien que le multicompte — le compte unique du poste répond, ce qui est\n // exactement ce qu'il attendait.\n const fileOrgId = typeof req.query['organizationId'] === 'string' ? req.query['organizationId'] : '';\n const fileAccountId = fileOrgId ? await accountForOrg(fileOrgId) : null;\n const token = await cloudSessionStore.getToken(fileAccountId ?? undefined);\n if (!token) {\n res.status(401).end();\n return;\n }\n try {\n const upstream = await fetch(\n `${fileOrgId ? await orgCloudUrl(fileOrgId) : ((await cloudSessionStore.getCloudUrl(fileAccountId ?? undefined)) ?? getCloudApiUrl())}`\n + `/api/kanban/file/${encodeURIComponent(req.params.id)}`,\n {\n headers: { Authorization: `Bearer ${token}`, [APP_VERSION_HEADER]: appVersion },\n signal: AbortSignal.timeout(300_000),\n },\n );\n if (!upstream.ok) {\n res.status(upstream.status).end();\n return;\n }\n res.set('Content-Type', upstream.headers.get('content-type') ?? 'application/octet-stream');\n const disposition = upstream.headers.get('content-disposition');\n if (disposition) res.set('Content-Disposition', disposition);\n res.set('X-Content-Type-Options', 'nosniff');\n res.set('Content-Security-Policy', \"default-src 'none'; sandbox\");\n // nosemgrep: direct-response-write -- relais d'octets de pièce jointe, en-têtes de durcissement conservés\n res.send(Buffer.from(await upstream.arrayBuffer()));\n } catch {\n res.status(502).end();\n }\n });\n\n /**\n * GET /api/cloud/avatar/:userId — relaie les octets d'un avatar.\n *\n * Le cloud sert les avatars publiquement, mais l'adresse de CE cloud est\n * figée dans la donnée : elle est recopiée dans `user.image` au téléversement\n * (`apps/cloud`, `${env.BASE_URL}/api/avatar/…`). Un cloud installé sur une\n * adresse privée — un `localhost:4100` de développement, un cloud d'équipe\n * derrière un VPN — écrit donc une URL que seuls les navigateurs de sa propre\n * machine savent résoudre. Depuis un autre appareil du réseau, l'image casse.\n *\n * Relayé ici, le navigateur ne demande plus qu'à l'origine dont il a chargé\n * l'application : la même en localhost, en LAN, et quand le cloud n'est pas\n * joignable publiquement.\n *\n * Sans jeton, comme la route amont : ces octets sont publics, et un `<img>`\n * ne pose pas d'en-tête. Rien de ce que la requête porte ne choisit l'hôte\n * appelé — il vient des tampons de ce poste — et l'identifiant est validé\n * avant d'entrer dans un chemin.\n */\n app.get('/api/cloud/avatar/:userId', async (req, res) => {\n const userId = req.params.userId;\n // Un identifiant vient du cloud et finit dans une URL : on le vérifie plutôt\n // que de l'assainir, un identifiant tordu désignerait quelqu'un d'autre.\n if (!/^[A-Za-z0-9._-]{1,128}$/.test(userId)) {\n res.status(400).end();\n return;\n }\n // Quel cloud : celui de l'organisation affichée, sinon celui du compte\n // nommé, sinon celui de ce poste. Les identifiants d'utilisateur de deux\n // clouds ne partagent aucun espace de noms.\n const orgId = typeof req.query['organizationId'] === 'string' ? req.query['organizationId'] : '';\n const accountId = typeof req.query['accountId'] === 'string' ? req.query['accountId'] : '';\n try {\n const base = orgId\n ? await orgCloudUrl(orgId)\n : ((await cloudSessionStore.getCloudUrl(accountId || undefined)) ?? getCloudApiUrl());\n const upstream = await fetch(`${base}/api/avatar/${encodeURIComponent(userId)}`, {\n headers: { [APP_VERSION_HEADER]: appVersion },\n signal: AbortSignal.timeout(15_000),\n });\n if (!upstream.ok) {\n res.status(upstream.status).end();\n return;\n }\n res.set('Content-Type', upstream.headers.get('content-type') ?? 'application/octet-stream');\n // Mêmes en-têtes de durcissement que la route amont : ces octets ne\n // doivent jamais être traités comme autre chose qu'une image inerte.\n res.set('X-Content-Type-Options', 'nosniff');\n res.set('Content-Security-Policy', \"default-src 'none'; sandbox\");\n res.set('Cache-Control', 'public, max-age=300');\n // nosemgrep: direct-response-write -- octets d'avatar, en-têtes de durcissement conservés\n res.send(Buffer.from(await upstream.arrayBuffer()));\n } catch {\n res.status(502).end();\n }\n });\n\n proxyCloudStream('/api/cloud/chat/stream', '/api/chat/stream');\n proxyCloudStream('/api/cloud/kanban/stream', '/api/kanban/stream');\n\n // POST /api/unlock — public, rate limited + CSRF\n app.post('/api/unlock', authLimiter, csrfMiddleware, express.json({ limit: '10kb' }), async (req, res) => {\n try {\n const body = req.body as { masterPassword?: unknown };\n const masterPassword = body.masterPassword;\n if (typeof masterPassword !== 'string' || masterPassword.length < 1 || masterPassword.length > 1024) {\n res.status(400).json({ error: 'masterPassword invalide' });\n return;\n }\n const encKey = await readEncryptedKey(await keyRoot(), masterPassword);\n setEncryptionKeyInMemory(encKey);\n await runPostUnlock(masterPassword);\n const token = await signJwt();\n res.json({ token });\n } catch (err) {\n console.error('[server] Unlock error:', err);\n res.status(401).json({ error: 'Master password incorrect' });\n }\n });\n\n // POST /api/setup — public, rate limited + CSRF\n app.post('/api/setup', authLimiter, csrfMiddleware, express.json({ limit: '10kb' }), async (req, res) => {\n try {\n const { state, hasVerifyFile: hasVerify, isLegacyMigration } = await getServerState();\n\n // Reject if already unlocked\n if (state === 'unlocked') {\n res.status(409).json({ error: 'Serveur déjà déverrouillé' });\n return;\n }\n\n const body = req.body as { masterPassword?: unknown; encryptionKey?: unknown };\n const masterPassword = body.masterPassword;\n if (typeof masterPassword !== 'string' || masterPassword.length < 1 || masterPassword.length > 1024) {\n res.status(400).json({ error: 'masterPassword invalide' });\n return;\n }\n\n let encKey: Buffer;\n\n if (isLegacyMigration) {\n // Read pending legacy key from in-memory holder\n const legacyKey = getPendingLegacyKey();\n if (!legacyKey) {\n res.status(500).json({ error: 'Clé legacy introuvable — redémarrez le serveur' });\n return;\n }\n encKey = legacyKey;\n } else if (hasVerify) {\n // New member: encryptionKey required\n const encryptionKeyHex = body.encryptionKey;\n if (typeof encryptionKeyHex !== 'string' || !/^[0-9a-f]{64}$/i.test(encryptionKeyHex)) {\n res.status(400).json({ error: 'encryptionKey invalide (attendu 64 hex)' });\n return;\n }\n encKey = Buffer.from(encryptionKeyHex, 'hex');\n // Verify against canary\n await verifyEncryptionKey(await keyRoot(), encKey);\n } else {\n // Fresh setup: generate new key or use provided key\n if (body.encryptionKey !== undefined) {\n const encryptionKeyHex = body.encryptionKey;\n if (typeof encryptionKeyHex !== 'string' || !/^[0-9a-f]{64}$/i.test(encryptionKeyHex)) {\n res.status(400).json({ error: 'encryptionKey invalide (attendu 64 hex)' });\n return;\n }\n encKey = Buffer.from(encryptionKeyHex, 'hex');\n } else {\n const { randomBytes } = await import('node:crypto');\n encKey = randomBytes(32);\n }\n }\n\n // Write .encryption.key.enc\n await writeEncryptedKey(await keyRoot(), masterPassword, encKey);\n\n // Verify round-trip (critical for legacy migration)\n const readBack = await readEncryptedKey(await keyRoot(), masterPassword);\n if (!readBack.equals(encKey)) {\n res.status(500).json({ error: 'Erreur de vérification round-trip — opération annulée' });\n return;\n }\n\n // Write .runeya-verify if not exists\n if (!hasVerify) {\n await writeVerifyFile(await keyRoot(), encKey);\n }\n\n setEncryptionKeyInMemory(encKey);\n if (isLegacyMigration) {\n clearPendingLegacyKey();\n }\n await runPostUnlock(masterPassword);\n const token = await signJwt();\n res.json({ token });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Erreur interne';\n if (message.includes('incorrecte')) {\n res.status(400).json({ error: message });\n } else {\n console.error('[server] Setup error:', err);\n res.status(500).json({ error: 'Erreur interne' });\n }\n }\n });\n\n /**\n * POST /api/migrate-vault — convert this directory's leftover vault.\n *\n * Authenticated: the caller must already hold the machine key, since that is\n * what the vault is being converted TO. Rate limited like the other\n * password-taking routes — it accepts the old master password, so it is an\n * oracle just as much as unlock is.\n */\n app.post('/api/migrate-vault', authLimiter, csrfMiddleware, express.json({ limit: '10kb' }), async (req, res) => {\n try {\n const jwt = typeof req.headers.authorization === 'string' && req.headers.authorization.startsWith('Bearer ')\n ? req.headers.authorization.slice(7)\n : '';\n if (!isCiMode()) {\n try {\n await verifyJwt(jwt);\n } catch {\n res.status(401).json({ error: 'Session invalide' });\n return;\n }\n }\n\n const machineKey = getEncryptionKey();\n if (!machineKey) {\n res.status(409).json({ error: 'Serveur verrouillé' });\n return;\n }\n\n const legacyRoot = await legacyVaultRoot();\n if (!legacyRoot) {\n res.status(409).json({ error: 'Aucun coffre à migrer dans ce répertoire' });\n return;\n }\n\n const body = req.body as { masterPassword?: unknown };\n const masterPassword = body.masterPassword;\n if (typeof masterPassword !== 'string' || masterPassword.length < 1 || masterPassword.length > 1024) {\n res.status(400).json({ error: 'masterPassword invalide' });\n return;\n }\n\n let legacyKey: Buffer;\n try {\n legacyKey = await openLegacyVault(legacyRoot, masterPassword);\n } catch {\n res.status(401).json({ error: 'Ancien master password incorrect' });\n return;\n }\n\n const report = await migrateLegacyVault(legacyRoot, machineRoot(), legacyKey, machineKey, new Date());\n console.log(`[vault-migration] ${legacyRoot} migré — sauvegarde : ${report.backupDir}`);\n res.json(report);\n } catch (err) {\n console.error('[server] Vault migration error:', err);\n res.status(500).json({ error: err instanceof Error ? err.message : 'Erreur interne' });\n }\n });\n\n // GET /:apikey/llms.txt — LLM API keys scopées\n app.get('/:apikey/llms.txt', llmsLimiter, async (req, res) => {\n const apikey = Array.isArray(req.params['apikey']) ? req.params['apikey'][0] : req.params['apikey'];\n // Validate format first — always 401 to avoid oracle\n if (!apikey || !/^[0-9a-f]{64}$/i.test(apikey)) {\n res.status(401).send('Unauthorized');\n return;\n }\n try {\n const key = await apiKeyStore.validateKey(apikey);\n if (!key) {\n res.status(401).send('Unauthorized');\n return;\n }\n if (!hasEncryptionKey()) {\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\n res.setHeader('Cache-Control', 'no-store');\n const uiUrl = process.env.NODE_ENV === 'development' ? 'http://localhost:5173' : `http://localhost:${env.PORT}`;\n res.status(503).send(`# Runeya — Service Management API\\n\\n> Server is locked. Unlock with your master password at ${uiUrl} to access the full service list.\\n`);\n return;\n }\n const allServices = await serviceStore.list();\n const services = allServices.filter(s =>\n key.scopes.services.some(p => p.serviceId === s.id),\n );\n\n const content = generateLlmsTxt(key, services);\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\n res.setHeader('Cache-Control', 'no-store');\n res.send(content);\n } catch (err) {\n console.error('[server] llms.txt error:', err);\n res.status(500).send('Internal server error');\n }\n });\n\n // GET /api/docs — Scalar API reference UI (standalone HTML, no auth required)\n app.get('/api/docs', (req, res) => {\n const dark = req.query['dark'] === '1';\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n res.setHeader('Cache-Control', 'no-store');\n res.send(`<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>Runeya API Docs</title>\n <meta name=\"description\" content=\"Runeya service management API reference\" />\n <style>\n body { margin: 0; }\n </style>\n</head>\n<body>\n <script src=\"https://cdn.jsdelivr.net/npm/@scalar/api-reference\"></script>\n <script>\n Scalar.createApiReference(document.body, {\n url: '/api/openapi.json',\n darkMode: ${dark},\n layout: 'modern',\n defaultHttpClient: { targetKey: 'shell', clientKey: 'curl' },\n defaultOpenAllTags: false,\n persistAuth: true,\n agent: { disabled: true },\n metaData: {\n title: 'Runeya API Docs',\n description: 'Runeya service management API reference',\n ogTitle: 'Runeya API Docs',\n ogDescription: 'Runeya service management API reference',\n },\n });\n </script>\n</body>\n</html>`);\n });\n\n // GET /api/openapi.json — OpenAPI specification (public, no auth required)\n app.get('/api/openapi.json', (_req, res) => {\n try {\n res.json(getOpenApiDocument());\n } catch (err) {\n console.error('[server] openapi.json error:', err instanceof Error ? err.stack : err);\n res.status(500).json({ error: 'Failed to generate OpenAPI document', detail: err instanceof Error ? err.message : String(err) });\n }\n });\n\n // ── Image upload & serve endpoints ──────────────────────────────────────\n const memStorage = multer.memoryStorage();\n const upload = multer({\n storage: memStorage,\n limits: { fileSize: MAX_IMAGE_SIZE_BYTES },\n fileFilter: (_req, file, cb) => {\n if (ALLOWED_MIME_TYPES.has(file.mimetype)) {\n cb(null, true);\n } else {\n cb(new Error(`Unsupported MIME type: ${file.mimetype}`));\n }\n },\n });\n\n const CONV_ID_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/;\n const IMAGE_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n // Les erreurs de multer (MIME refusé par fileFilter, dépassement de taille)\n // sont des erreurs client : sans ce wrapper elles remontent au gestionnaire\n // d'erreurs global, qui répond 500 « Internal server error ».\n const uploadSingleImage = (req: express.Request, res: express.Response, next: express.NextFunction) => {\n upload.single('image')(req, res, (err: unknown) => {\n if (err) {\n const isTooLarge = (err as { code?: string }).code === 'LIMIT_FILE_SIZE';\n const message = err instanceof Error ? err.message : 'Upload failed';\n res.status(isTooLarge ? 413 : 400).json({ error: message });\n return;\n }\n next();\n });\n };\n\n app.post('/api/images/upload', uploadSingleImage, async (req, res) => {\n try {\n if (!req.file) {\n res.status(400).json({ error: 'No image file provided' });\n return;\n }\n const conversationId = (req.query?.['conversationId'] ?? req.body?.conversationId) as string | undefined;\n if (!conversationId || !CONV_ID_RE.test(conversationId)) {\n res.status(400).json({ error: 'Missing or invalid conversationId' });\n return;\n }\n const stored = await imageStorageService.saveImage(\n req.file.buffer,\n req.file.originalname,\n req.file.mimetype,\n conversationId,\n );\n res.json({\n imageId: stored.imageId,\n url: `/api/images/${conversationId}/${stored.imageId}`,\n mimeType: stored.mimeType,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Upload failed';\n res.status(400).json({ error: message });\n }\n });\n\n app.get('/api/images/:conversationId/:imageId', async (req, res) => {\n try {\n const { conversationId, imageId } = req.params as { conversationId: string; imageId: string };\n if (!conversationId || !CONV_ID_RE.test(conversationId)) {\n res.status(400).json({ error: 'Invalid conversationId' });\n return;\n }\n if (!imageId || !IMAGE_ID_RE.test(imageId)) {\n res.status(400).json({ error: 'Invalid imageId' });\n return;\n }\n // Le conversationId de l'URL doit correspondre au contexte enregistré :\n // sans ça le scoping par conversation n'est que décoratif.\n const result = await imageStorageService.getImagePath(imageId, conversationId);\n if (!result) {\n res.status(404).json({ error: 'Image not found' });\n return;\n }\n res.setHeader('Content-Type', result.mimeType);\n res.setHeader('Cache-Control', 'no-store');\n createReadStream(result.filePath).pipe(res);\n } catch (err) {\n console.error('[server] image serve error:', err);\n res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n // tRPC HTTP handler\n app.use('/api/trpc', createExpressMiddleware({\n router: appRouter,\n createContext,\n }));\n\n // Global error handler\n app.use(errorHandler);\n\n const server = createServer(app);\n registerHttpServer(server);\n\n // tRPC WebSocket handler — noServer mode so we control the upgrade\n const wss = new WebSocketServer({ noServer: true });\n applyWSSHandler({\n wss,\n router: appRouter,\n createContext: ({ req }) => {\n const headerAuth = req.headers.authorization ?? null;\n // Browser WebSocket can't set headers — also accept token from query param\n const urlObj = new URL(req.url ?? '/', `http://localhost:${env.PORT}`);\n const queryToken = urlObj.searchParams.get('token');\n const queryAuth = queryToken ? `Bearer ${queryToken}` : null;\n return { authorization: headerAuth ?? queryAuth };\n },\n });\n\n // Registry of active WS connections (stores only exp + iat, never the JWT)\n interface WsConnMeta { exp: number; iat: number; }\n const wsConnRegistry = new Map<WebSocket, WsConnMeta>();\n\n // Intercept HTTP→WS upgrade: validate JWT BEFORE handleUpgrade (spec Point 3)\n // Mirror protectedProcedure: skip JWT check when encryption key is in memory\n // (covers both CI mode and normal mode after master-password unlock).\n server.on('upgrade', async (req, socket, head) => {\n // Daté à l'arrivée : c'est ce qui distingue « le navigateur n'a pas encore\n // demandé » de « on a refusé ». Un rejet ne laissait aucune trace, et une\n // demande qui n'arrive jamais encore moins.\n // Une par onglet : bruyante en usage normal, précieuse quand on cherche\n // pourquoi un WebSocket tarde. RUNEYA_DEBUG=1 la rallume.\n if (process.env['RUNEYA_DEBUG']) console.log('[ws-upgrade] demande reçue');\n const auth = req.headers['authorization'] as string | undefined;\n const headerToken = auth?.startsWith('Bearer ') ? auth.slice(7) : null;\n // Browser WebSocket API can't set headers — accept token from query param as fallback\n const urlObj = new URL(req.url ?? '/', `http://localhost:${env.PORT}`);\n const queryToken = urlObj.searchParams.get('token');\n const token = headerToken ?? queryToken;\n\n if (!hasEncryptionKey()) {\n // Encryption key not in memory — require JWT (not yet unlocked)\n if (!token) {\n console.warn('[ws-upgrade] refusée : serveur verrouillé et aucun jeton fourni');\n socket.write('HTTP/1.1 401 Unauthorized\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n try {\n await verifyJwt(token);\n } catch {\n console.warn('[ws-upgrade] refusée : jeton invalide ou expiré');\n socket.write('HTTP/1.1 401 Unauthorized\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n }\n\n wss.handleUpgrade(req, socket, head, (ws) => {\n if (process.env['RUNEYA_DEBUG']) console.log('[ws-upgrade] acceptée — WebSocket établi');\n wss.emit('connection', ws, req);\n });\n });\n\n // Register connection — JWT already verified at upgrade, safe to use verifyJwt for exp/iat\n wss.on('connection', (ws, req) => {\n const auth = req.headers['authorization'] as string | undefined;\n const headerToken = auth?.startsWith('Bearer ') ? auth.slice(7) : null;\n const urlObj2 = new URL(req.url ?? '/', `http://localhost:${env.PORT}`);\n const token = headerToken ?? urlObj2.searchParams.get('token');\n if (token) {\n verifyJwt(token).then(({ exp, iat }) => {\n wsConnRegistry.set(ws, { exp, iat });\n }).catch(() => {});\n }\n ws.on('close', () => wsConnRegistry.delete(ws));\n });\n\n // Tick every 30s — close expired connections\n const wsTickInterval = setInterval(() => {\n const now = Math.floor(Date.now() / 1000);\n const secretGeneratedAt = getJwtSecretGeneratedAt();\n for (const [ws, meta] of wsConnRegistry) {\n if (meta.exp <= now || meta.iat < secretGeneratedAt) {\n ws.close(4401, 'JWT expired or signing secret rotated');\n wsConnRegistry.delete(ws);\n }\n }\n }, 30_000);\n\n const shutdown = async () => {\n console.log('[server] Shutting down...');\n clearInterval(wsTickInterval);\n stopClaudeTranscriptWatcher();\n stopCodexTranscriptWatcher();\n imageCleanupService.stop();\n void cloudSyncBridge.stopAll();\n // Kill agent immediately (SIGKILL, stateless) and close WS bridges in parallel\n await Promise.all([\n unregisterInstance(),\n agentSpawner.shutdown(),\n agentManager.shutdown(),\n ]);\n // Force-close all active connections so the port is released instantly\n server.closeAllConnections();\n await Promise.race([\n new Promise<void>((resolve) => wss.close(() => resolve())),\n new Promise<void>((resolve) => setTimeout(resolve, 2_000)),\n ]);\n await Promise.race([\n new Promise<void>((resolve) => server.close(() => resolve())),\n new Promise<void>((resolve) => setTimeout(resolve, 2_000)),\n ]);\n console.log('[server] Shutdown complete');\n };\n\n // Le compagnon écoute les fins de tour.\n //\n // Ici, et pas dans le `main()` de ce paquet : celui-ci ne s'exécute que si\n // `index.ts` est lancé directement. Le CLI publié, lui, importe\n // `createLocalServer` et l'appelle — le compagnon n'aurait jamais été branché\n // pour un utilisateur installé, alors qu'il l'était en développement.\n const { initCompanion } = await import('./services/companion.js');\n initCompanion();\n\n return { app, server, wss, shutdown };\n}\n","import os from 'node:os';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { z } from 'zod';\nimport { appVersion } from '../../config/app-version.js';\nimport { router, publicProcedure, protectedProcedure } from '../trpc.js';\n\nconst execFileAsync = promisify(execFile);\n\n/** Récupère la version de Docker si le binaire est présent, sinon null. */\nasync function getDockerVersion(): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync('docker', ['--version'], {\n timeout: 3000,\n windowsHide: true,\n });\n // Format typique : \"Docker version 27.3.1, build ce12230\"\n const match = /Docker version\\s+([^,\\s]+)/i.exec(stdout);\n return match?.[1] ?? (stdout.trim() || null);\n } catch {\n return null;\n }\n}\n\nconst startedAt = Date.now();\n\nconst NPM_LATEST_URL = 'https://registry.npmjs.org/@runeya%2Fruneya/latest';\n\n/** Compare deux versions semver simples. Renvoie 1 si a>b, -1 si a<b, 0 si égales. */\nfunction compareSemver(a: string, b: string): number {\n const pa = a.split('.').map((n) => Number.parseInt(n, 10) || 0);\n const pb = b.split('.').map((n) => Number.parseInt(n, 10) || 0);\n for (let i = 0; i < 3; i++) {\n const da = pa[i] ?? 0;\n const db = pb[i] ?? 0;\n if (da > db) return 1;\n if (da < db) return -1;\n }\n return 0;\n}\n\n/**\n * Le client revérifie périodiquement et au retour au premier plan : sans ce\n * cache, chaque fenêtre rouverte irait interroger le registre npm. Volontairement\n * plus court que l'intervalle du client (5 min) : à durée égale, un tic arrivant\n * une fraction de seconde trop tôt se ferait servir l'entrée précédente et le\n * délai réel doublerait.\n */\nconst VERSION_CACHE_MS = 4 * 60 * 1000;\nlet versionCache: { at: number; latest: string | null } | null = null;\n\n/**\n * Plancher entre deux vérifications forcées.\n *\n * Le cache ci-dessus existe pour les vérifications automatiques ; un clic sur\n * « Revérifier » le court-circuite, sinon le bouton mentirait pendant quatre\n * minutes après une publication. Ce plancher-là ne protège pas le confort mais\n * le registre : la route est publique, et sans lui une boucle de clics — ou un\n * client qui redemande en rafale — irait taper npm à chaque appel.\n */\nconst FORCED_CHECK_FLOOR_MS = 2_000;\nlet lastForcedAt = 0;\n\n/**\n * Version publiée la plus récente, ou null si le registre est injoignable.\n *\n * `force` ignore le cache ET le remplace : la réponse fraîche est donc aussi\n * celle que verront les autres écrans à leur prochaine question — c'est ce qui\n * fait apparaître le bandeau de mise à jour dans la foulée du clic.\n */\nasync function fetchLatestVersion(force = false): Promise<string | null> {\n const now = Date.now();\n const forcing = force && now - lastForcedAt >= FORCED_CHECK_FLOOR_MS;\n if (forcing) lastForcedAt = now;\n if (!forcing && versionCache && now - versionCache.at < VERSION_CACHE_MS) {\n return versionCache.latest;\n }\n let latest: string | null = null;\n try {\n const res = await fetch(NPM_LATEST_URL, {\n headers: { accept: 'application/json' },\n signal: AbortSignal.timeout(5000),\n });\n if (res.ok) {\n const parsed = z.object({ version: z.string().max(64) }).safeParse(await res.json());\n if (parsed.success) latest = parsed.data.version;\n }\n } catch {\n latest = null;\n }\n versionCache = { at: Date.now(), latest };\n return latest;\n}\n\nexport const healthRouter = router({\n check: publicProcedure\n .meta({ openapi: { method: 'GET', path: '/health', tags: ['health'], summary: 'Health check' } })\n .output(z.object({ status: z.literal('ok'), uptime: z.number(), version: z.string() }))\n .query(() => {\n return {\n status: 'ok' as const,\n uptime: Date.now() - startedAt,\n version: appVersion,\n };\n }),\n versionInfo: publicProcedure\n // `force` : le bouton « Revérifier » des réglages, qui n'a de sens que s'il\n // interroge vraiment le registre.\n .input(z.object({ force: z.boolean().optional() }).optional())\n .output(\n z.object({\n current: z.string(),\n latest: z.string().nullable(),\n status: z.enum(['up-to-date', 'outdated', 'ahead', 'dev', 'unknown']),\n }),\n )\n .query(async ({ input }) => {\n // En mode dev, pas de version publiée à comparer.\n if (appVersion === 'dev') {\n return { current: appVersion, latest: null, status: 'dev' as const };\n }\n\n const latest = await fetchLatestVersion(input?.force ?? false);\n if (latest === null) {\n return { current: appVersion, latest: null, status: 'unknown' as const };\n }\n const cmp = compareSemver(appVersion, latest);\n const status = cmp === 0 ? 'up-to-date' : cmp < 0 ? 'outdated' : 'ahead';\n return { current: appVersion, latest, status };\n }),\n systemInfo: protectedProcedure\n .output(\n z.object({\n version: z.string(),\n nodeVersion: z.string(),\n platform: z.string(),\n arch: z.string(),\n osType: z.string(),\n osRelease: z.string(),\n hostname: z.string(),\n cpuModel: z.string(),\n cpuCount: z.number(),\n totalMemoryBytes: z.number(),\n freeMemoryBytes: z.number(),\n serverUptimeMs: z.number(),\n osUptimeSec: z.number(),\n dockerVersion: z.string().nullable(),\n }),\n )\n .query(async () => {\n const cpus = os.cpus();\n const dockerVersion = await getDockerVersion();\n return {\n version: appVersion,\n nodeVersion: process.version,\n platform: process.platform,\n arch: process.arch,\n osType: os.type(),\n osRelease: os.release(),\n hostname: os.hostname(),\n cpuModel: cpus[0]?.model.trim() ?? 'unknown',\n cpuCount: cpus.length,\n totalMemoryBytes: os.totalmem(),\n freeMemoryBytes: os.freemem(),\n serverUptimeMs: Date.now() - startedAt,\n osUptimeSec: os.uptime(),\n dockerVersion,\n };\n }),\n});\n","import { spawn, execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { router, publicProcedure, requireLoopbackOrToken } from '../trpc.js';\nimport { env } from '../../config/env.js';\nimport { appVersion } from '../../config/app-version.js';\n\nconst execFileAsync = promisify(execFile);\n\n/** Le paquet publié, seul nom que cette route accepte d'installer. */\nconst PACKAGE_NAME = '@runeya/runeya';\n\n/** `npm install -g` télécharge, compile parfois, et n'est pas pressé. */\nconst INSTALL_TIMEOUT_MS = 10 * 60_000;\n\n/**\n * Mettre à jour Runeya depuis Runeya, pour les installations de bureau.\n *\n * Lancé depuis un terminal, on met à jour comme on a installé : un `npm i -g`\n * dans le terminal qu'on a déjà sous la main. Lancé depuis un raccourci, il n'y\n * a pas de terminal — et la version qui tourne peut vieillir indéfiniment sans\n * que rien ne le dise. D'où ces routes, réservées à ce cas.\n *\n * Elles répondent SANS jeton à la boucle locale : le bandeau s'affiche aussi\n * avant l'entrée dans l'application (déverrouillage, migration de coffre), là\n * où aucun jeton n'existe encore et où rester bloqué sur une version trop\n * ancienne est justement le cas à traiter.\n *\n * Elles répondent aussi à un appelant muni du jeton d'application, d'où qu'il\n * vienne. Sans quoi une Runeya pilotée depuis une tablette — tout l'objet du\n * mode LAN — ne pouvait plus se mettre à jour du tout : la seule machine\n * autorisée était celle devant laquelle personne n'était assis. Le jeton dit ce\n * que la boucle locale disait, et il le dit à distance.\n */\n\n/**\n * Comment lancer `npm` sans passer par un shell.\n *\n * Une session graphique n'a pas le `PATH` d'un shell de connexion : les\n * gestionnaires de version (n, nvm, fnm, volta) n'y figurent pas, et `npm` est\n * introuvable alors même qu'il est installé, juste à côté du `node` qui exécute\n * ce code.\n *\n * D'où le script JS de npm, lancé par le `node` courant : c'est la seule forme\n * qui marche partout **sans shell**. Sur Windows, `npm` n'est qu'un `npm.cmd`,\n * et depuis le correctif de CVE-2024-27980 Node refuse de lancer un `.cmd` sans\n * `shell: true` — le nommer en entier ne suffit donc plus. C'est ce qui faisait\n * répondre « npm est introuvable » sur une machine où npm est parfaitement\n * installé, à côté du node qui tourne.\n */\ntype NpmCommand = { command: string; args: string[]; shell: boolean };\n\nfunction resolveNpm(): NpmCommand {\n const nodeDir = dirname(process.execPath);\n const candidates = [\n // Windows (installateur officiel, nvm-windows, volta) : npm est un dossier\n // frère de node.exe.\n join(nodeDir, 'node_modules', 'npm', 'bin', 'npm-cli.js'),\n // Unix : node est dans `bin/`, npm sous `lib/node_modules/`.\n join(nodeDir, '..', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'),\n ];\n for (const cli of candidates) {\n if (existsSync(cli)) return { command: process.execPath, args: [cli], shell: false };\n }\n // Repli sur le PATH. Sur Windows il n'y a que le `.cmd`, qui exige un shell —\n // les arguments sont tous des constantes de ce fichier, rien de ce que\n // l'appelant envoie n'y entre.\n return process.platform === 'win32'\n ? { command: 'npm.cmd', args: [], shell: true }\n : { command: 'npm', args: [], shell: false };\n}\n\n/** Ce qu'on affiche pour dire quel npm a été retenu. */\nfunction npmLabel(npm: NpmCommand): string {\n return [npm.command, ...npm.args].join(' ');\n}\n\n/** Version d'un exécutable, ou `null` s'il ne répond pas. */\nasync function probeVersion(npm: NpmCommand, args: string[]): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(npm.command, [...npm.args, ...args], {\n timeout: 10_000,\n windowsHide: true,\n shell: npm.shell,\n });\n return stdout.trim().split('\\n')[0]?.trim() || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Refuse tout ce qui ne vient pas d'un lancement par raccourci.\n *\n * Ces routes installent du code et redémarrent le process : les ouvrir à une\n * instance lancée en terminal n'apporterait rien — l'utilisateur y a déjà son\n * shell — et élargirait la surface d'attaque pour rien.\n */\nfunction requireDesktop(): void {\n if (!env.FROM_DESKTOP) {\n throw new TRPCError({\n code: 'PRECONDITION_FAILED',\n message: 'Update from the app is only available for desktop launches.',\n });\n }\n}\n\nexport const appUpdateRouter = router({\n /** De quoi la mise à jour a besoin, et ce que la machine en offre. */\n prerequisites: publicProcedure\n .output(\n z.object({\n fromDesktop: z.boolean(),\n nodeVersion: z.string(),\n npmVersion: z.string().nullable(),\n npmPath: z.string(),\n globalPrefix: z.string().nullable(),\n ready: z.boolean(),\n }),\n )\n .query(async ({ ctx }) => {\n await requireLoopbackOrToken(ctx);\n const npm = resolveNpm();\n const npmVersion = await probeVersion(npm, ['--version']);\n // Le préfixe dit OÙ l'installation atterrira : utile à afficher quand\n // Runeya a été installé par un autre gestionnaire, où la mise à jour\n // réussirait sans jamais remplacer la version qui tourne.\n const globalPrefix = npmVersion ? await probeVersion(npm, ['prefix', '-g']) : null;\n\n return {\n fromDesktop: env.FROM_DESKTOP,\n nodeVersion: process.version,\n npmVersion,\n npmPath: npmLabel(npm),\n globalPrefix,\n ready: env.FROM_DESKTOP && npmVersion !== null,\n };\n }),\n\n /**\n * Installe la dernière version publiée, globalement.\n *\n * La sortie complète est renvoyée telle quelle, succès comme échec : quand\n * `npm` refuse (droits sur le préfixe, réseau, registre privé), son message\n * est la seule chose qui dit à l'utilisateur quoi faire.\n */\n install: publicProcedure\n .output(\n z.object({\n ok: z.boolean(),\n output: z.string(),\n installedVersion: z.string().nullable(),\n }),\n )\n .mutation(async ({ ctx }) => {\n await requireLoopbackOrToken(ctx);\n requireDesktop();\n\n const npm = resolveNpm();\n try {\n const { stdout, stderr } = await execFileAsync(\n npm.command,\n [...npm.args, 'install', '-g', `${PACKAGE_NAME}@latest`],\n { timeout: INSTALL_TIMEOUT_MS, windowsHide: true, shell: npm.shell, maxBuffer: 10 * 1024 * 1024 },\n );\n const installedVersion = await probeVersion(npm, ['view', `${PACKAGE_NAME}`, 'version']);\n return { ok: true, output: [stdout, stderr].filter(Boolean).join('\\n').trim(), installedVersion };\n } catch (err) {\n const e = err as { stdout?: string; stderr?: string; message: string };\n const output = [e.stdout, e.stderr, e.message].filter(Boolean).join('\\n').trim();\n return { ok: false, output, installedVersion: null };\n }\n }),\n\n /**\n * Relance Runeya, puis rend la main au nouveau process.\n *\n * Le remplaçant est détaché et démarre avec les mêmes arguments : il rouvre\n * donc la fenêtre lui-même. Le port est encore tenu par l'ancien pendant\n * quelques instants — le démarrage réessaie déjà sur EADDRINUSE, c'est ce qui\n * rend ce relais possible sans temporisation ici.\n */\n restart: publicProcedure\n .output(z.object({ restarting: z.literal(true), version: z.string() }))\n .mutation(async ({ ctx }) => {\n await requireLoopbackOrToken(ctx);\n requireDesktop();\n\n const child = spawn(process.execPath, process.argv.slice(1), {\n detached: true,\n stdio: 'ignore',\n // `detached` demande une console neuve à Windows, et une console neuve\n // est une fenêtre de commande à l'écran : le lanceur de bureau cache la\n // sienne, la mise à jour n'a pas à en rouvrir une.\n windowsHide: true,\n cwd: process.cwd(),\n // Le relais s'annonce comme tel : sans cela le CLI, relancé avec\n // `--from-desktop`, sonde le port, y trouve l'ancien process encore\n // vivant pendant sa demi-seconde de sursis, en conclut qu'une Runeya\n // tourne déjà et se contente de rouvrir la fenêtre. L'ancien mourait\n // juste après, et « Redémarrer » ne redémarrait rien.\n env: { ...process.env, RUNEYA_RESTART_HANDOFF: '1' },\n });\n child.unref();\n\n // Laisse la réponse partir avant de couper : sans ce délai, le client voit\n // une socket fermée et non un redémarrage.\n setTimeout(() => process.exit(0), 500);\n\n return { restarting: true as const, version: appVersion };\n }),\n});\n","import { z } from 'zod';\nimport {\n ChangelogIndexItemSchema,\n ChangelogReleaseSchema,\n ChangelogSurfaceSchema,\n} from '@runeya/packages-shared';\nimport { router, publicProcedure } from '../trpc.js';\nimport { appVersion } from '../../config/app-version.js';\nimport { getCloudApiUrl } from '../../services/cloud-api.js';\n\n/**\n * Le journal des nouveautés, relayé depuis le cloud.\n *\n * Relayé, et non appelé directement par l'interface : le cloud n'autorise en\n * CORS que ses propres origines, et une Runeya locale n'en est pas une — elle\n * répond sur un port choisi au lancement, et sur une IP de LAN dès que le mode\n * réseau est actif. Le relais évite aussi de dépendre d'une session cloud :\n * le journal est public, une machine jamais reliée doit le lire.\n *\n * Les routes sont publiques pour la même raison que le bandeau de mise à jour :\n * elles servent aussi avant l'entrée dans l'application (déverrouillage,\n * migration de coffre), là où aucun jeton n'existe encore.\n */\n\n/** Le registre bouge à l'échelle du déploiement ; cinq minutes suffisent, et bornent les allers-retours. */\nconst CACHE_MS = 5 * 60 * 1000;\nconst cache = new Map<string, { at: number; value: unknown }>();\n\nasync function cloudChangelog(path: string, params: Record<string, string | null>): Promise<unknown> {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) if (value) search.set(key, value);\n const url = `${getCloudApiUrl()}${path}?${search.toString()}`;\n\n const hit = cache.get(url);\n if (hit && Date.now() - hit.at < CACHE_MS) return hit.value;\n\n const res = await fetch(url, {\n headers: { accept: 'application/json' },\n signal: AbortSignal.timeout(8000),\n });\n if (!res.ok) throw new Error(`changelog: HTTP ${res.status}`);\n const value: unknown = await res.json();\n cache.set(url, { at: Date.now(), value });\n return value;\n}\n\n/**\n * La version qui borne ce que l'app peut annoncer.\n *\n * En développement il n'y a pas de version publiée : rien n'est borné, sinon un\n * poste de développement ne verrait jamais l'entrée qu'il vient d'écrire.\n */\nfunction appCeiling(): string | null {\n return appVersion === 'dev' ? null : appVersion;\n}\n\nconst inputSchema = z.object({\n surface: ChangelogSurfaceSchema,\n /** Dernière version déjà vue par ce navigateur, exclue du résultat. */\n since: z.string().max(32).nullish(),\n});\n\nexport const changelogRouter = router({\n /** Ce qu'il y a à lire, sans les corps. */\n index: publicProcedure\n .input(inputSchema)\n .output(z.object({ releases: z.array(ChangelogIndexItemSchema), currentAppVersion: z.string() }))\n .query(async ({ input }) => {\n const data = await cloudChangelog('/api/changelog', {\n surface: input.surface,\n since: input.since ?? null,\n until: input.surface === 'app' ? appCeiling() : null,\n });\n const parsed = z.object({ releases: z.array(ChangelogIndexItemSchema) }).parse(data);\n return { releases: parsed.releases, currentAppVersion: appVersion };\n }),\n\n /** Les entrées complètes. */\n releases: publicProcedure\n .input(inputSchema)\n .output(z.object({ releases: z.array(ChangelogReleaseSchema), currentAppVersion: z.string() }))\n .query(async ({ input }) => {\n const data = await cloudChangelog('/api/changelog/releases', {\n surface: input.surface,\n since: input.since ?? null,\n until: input.surface === 'app' ? appCeiling() : null,\n });\n const parsed = z.object({ releases: z.array(ChangelogReleaseSchema) }).parse(data);\n return { releases: parsed.releases, currentAppVersion: appVersion };\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { router, protectedProcedure, getAllowedServiceIds } from '../trpc.js';\nimport { projectStore, LocalProjectExistsError } from '../../services/project-store.js';\nimport { setCurrentProject } from '../../services/current-project.js';\nimport { serviceStore } from '../../services/service-store.js';\nimport { environmentStore } from '../../services/environment-store.js';\nimport { environmentResolver } from '../../services/environment-resolver.js';\nimport { agentManager } from '../../services/agent-manager.js';\nimport { auditService } from '../../services/audit-service.js';\nimport { projectPathStore, holdsRuneyaProject } from '../../services/project-path-store.js';\nimport { assertOrgVaultReadable, OrgVaultUnreadableError } from '../../services/org-keys.js';\nimport { buildServiceGraph } from '../../services/service-graph.js';\n\n/**\n * Le dernier verrou avant de servir un projet d'organisation.\n *\n * `cloud-sync` garde l'ouverture initiale, mais un projet déjà matérialisé se\n * relit à chaque démarrage sans repasser par lui — et un poste qui a perdu la\n * clé de l'organisation, ou qui ne l'a jamais eue, le rouvrirait comme si de\n * rien n'était. La lecture y mène l'écriture : ce qui s'affiche se sauvegarde.\n */\nasync function assertReadable(orgId: string | null | undefined): Promise<void> {\n if (!orgId) return;\n try {\n await assertOrgVaultReadable(orgId);\n } catch (err) {\n if (err instanceof OrgVaultUnreadableError) {\n throw new TRPCError({ code: 'FORBIDDEN', message: err.message });\n }\n throw err;\n }\n}\n\nexport const projectRouter = router({\n list: protectedProcedure.query(async () => {\n return projectStore.list();\n }),\n\n /**\n * `orgId` names which project — the same id can exist in several\n * organizations. Left out, the id must answer for exactly one project.\n */\n get: protectedProcedure\n .input(z.object({ id: z.string().max(128), orgId: z.string().max(128).nullable().optional() }))\n .query(async ({ input }) => {\n const project = await projectStore.get(input);\n if (!project) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.id} not found` });\n }\n await assertReadable(project.orgId);\n return project;\n }),\n\n /**\n * Build a portable snapshot of a project for cloud storage: the project\n * record plus its services in sanitized (secret-free) on-disk form.\n * Environments are intentionally excluded — they carry secret values that\n * stay local.\n */\n export: protectedProcedure\n .input(z.object({ id: z.string().max(128), orgId: z.string().max(128).nullable().optional() }))\n .query(async ({ input }) => {\n const project = await projectStore.get(input);\n if (!project) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.id} not found` });\n }\n await assertReadable(project.orgId);\n const services = (\n await Promise.all(project.serviceIds.map((sid) => serviceStore.getSanitized(sid)))\n ).filter((s): s is NonNullable<typeof s> => s !== null);\n return { project, services };\n }),\n\n create: protectedProcedure\n .input(\n z.object({\n name: z.string().min(1).max(200),\n description: z.string().max(10000).optional(),\n orgId: z.string().max(128).nullable().optional(),\n serviceIds: z.array(z.string().max(128)).max(10000).optional(),\n }),\n )\n .mutation(async ({ input }) => {\n // Create the project first (with empty environmentIds, will be updated after creating local env)\n let project;\n try {\n project = await projectStore.create({\n ...input,\n description: input.description ?? '',\n serviceIds: input.serviceIds ?? [],\n environmentIds: [],\n });\n } catch (err) {\n // A directory holds a single local project. That is a conflict the user\n // can act on, not a server fault: surfaced as such, and carrying the\n // machine-readable code so the UI can say it in the user's language.\n if (err instanceof LocalProjectExistsError) {\n throw new TRPCError({ code: 'CONFLICT', message: err.code, cause: err });\n }\n throw new TRPCError({ code: 'CONFLICT', message: (err as Error).message });\n }\n\n // Create the default 'local' immutable environment for this project\n const localEnv = await environmentStore.create({\n projectId: project.id,\n name: 'local',\n description: 'Default local environment (immutable)',\n parentIds: [],\n immutable: true,\n }, project.orgId);\n\n // Update the project with the local environment\n const result = await projectStore.update({\n id: project.id,\n orgId: project.orgId,\n environmentIds: [localEnv.id],\n activeEnvironmentId: localEnv.id,\n });\n\n await auditService.log({ userId: 'local', action: 'create', entityType: 'project', entityId: project.id, metadata: { name: input.name } });\n return result!;\n }),\n\n update: protectedProcedure\n .input(\n z.object({\n id: z.string().max(128),\n name: z.string().min(1).max(200).optional(),\n description: z.string().max(10000).optional(),\n orgId: z.string().max(128).nullable().optional(),\n serviceIds: z.array(z.string().max(128)).max(10000).optional(),\n groupOrder: z.array(z.string().max(200)).max(100).optional(),\n }),\n )\n .mutation(async ({ input }) => {\n const project = await projectStore.update(input);\n if (!project) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.id} not found` });\n }\n await auditService.log({ userId: 'local', action: 'update', entityType: 'project', entityId: input.id });\n return project;\n }),\n\n delete: protectedProcedure\n .input(z.object({ id: z.string().max(128), orgId: z.string().max(128).nullable().optional() }))\n .mutation(async ({ input }) => {\n const deleted = await projectStore.delete(input);\n if (!deleted) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.id} not found` });\n }\n await auditService.log({ userId: 'local', action: 'delete', entityType: 'project', entityId: input.id });\n return { success: true as const };\n }),\n\n addService: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n serviceId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n const target = { id: input.projectId, orgId: input.orgId };\n const project = await projectStore.addService(target, input.serviceId);\n if (!project) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.projectId} not found` });\n }\n\n // Auto-create service-scoped environments for each global env in the project\n const service = await serviceStore.get(input.serviceId);\n if (service) {\n const globalEnvs = await environmentStore.listByScope(input.projectId, 'global', input.orgId);\n for (const globalEnv of globalEnvs) {\n const svcEnv = await environmentStore.create({\n projectId: input.projectId,\n name: `${service.name} (${globalEnv.name})`,\n scope: 'service',\n reference: input.serviceId,\n activateOn: globalEnv.id,\n parentIds: [globalEnv.id],\n variables: {},\n }, input.orgId);\n await projectStore.addEnvironment(target, svcEnv.id);\n }\n }\n\n await auditService.log({\n userId: 'local',\n action: 'update',\n entityType: 'project',\n entityId: input.projectId,\n metadata: { operation: 'addService', serviceId: input.serviceId },\n });\n return project;\n }),\n\n removeService: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n serviceId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n const project = await projectStore.removeService(\n { id: input.projectId, orgId: input.orgId }, input.serviceId,\n );\n if (!project) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.projectId} not found` });\n }\n await auditService.log({\n userId: 'local',\n action: 'update',\n entityType: 'project',\n entityId: input.projectId,\n metadata: { operation: 'removeService', serviceId: input.serviceId },\n });\n return project;\n }),\n\n setActiveEnvironment: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n environmentId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n const project = await projectStore.get({ id: input.projectId, orgId: input.orgId });\n if (!project) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.projectId} not found` });\n }\n\n // Validate environment exists\n const environment = await environmentStore.get(input.environmentId);\n if (!environment) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.environmentId} not found` });\n }\n if (environment.projectId !== input.projectId) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Environment does not belong to this project' });\n }\n\n // Collect running services before changing environment\n const runningServices: { serviceId: string; agentId: string }[] = [];\n\n for (const serviceId of project.serviceIds) {\n const service = await serviceStore.get(serviceId);\n if (!service || !service.agentId) continue;\n\n const agentStatus = agentManager.getStatus(service.agentId);\n if (!agentStatus?.connected) continue;\n\n try {\n const processStatus = await agentManager.agentQuery<{ status: string }>(\n service.agentId,\n 'process.get',\n { id: serviceId }\n );\n\n if (processStatus?.status === 'running' || processStatus?.status === 'starting') {\n runningServices.push({ serviceId, agentId: service.agentId });\n }\n } catch {\n // Agent unreachable or process not deployed — skip\n }\n }\n\n // Update environment\n const updated = await projectStore.setActiveEnvironment(\n { id: input.projectId, orgId: input.orgId }, input.environmentId,\n );\n\n if (!updated) {\n throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Failed to set active environment' });\n }\n\n // Push resolved config to ALL assigned services (running or not)\n for (const serviceId of project.serviceIds) {\n const service = await serviceStore.get(serviceId);\n if (!service || !service.agentId) continue;\n\n const agentStatus = agentManager.getStatus(service.agentId);\n if (!agentStatus?.connected) continue;\n\n // Always resolve — the resolver handles empty service variables\n let resolvedService = service;\n try {\n const resolved = await environmentResolver.resolveForService({\n serviceId: service.id,\n activeEnvironmentId: input.environmentId,\n });\n\n resolvedService = {\n ...service,\n env: { ...resolved.env },\n envSecrets: [...resolved.envSecrets],\n };\n } catch (err) {\n console.error('[project-router] Failed to resolve variables for service', serviceId + ':', (err as Error).message);\n }\n\n const wasRunning = runningServices.some(rs => rs.serviceId === serviceId);\n\n if (wasRunning) {\n // Stop → deploy (with new env) → start\n // Uses deploy instead of updateConfig for consistency with the lazy deploy pattern\n try {\n await agentManager.agentMutation(service.agentId, 'process.stop', { id: serviceId });\n await agentManager.agentMutation(service.agentId, 'process.deploy', resolvedService);\n await agentManager.agentMutation(service.agentId, 'process.start', { id: serviceId });\n } catch (err) {\n console.error('[project-router] Failed to restart service', serviceId + ':', (err as Error).message);\n }\n }\n // Stopped services: no need to push config — the next start will\n // lazy-deploy with the freshly resolved environment anyway.\n }\n\n return updated;\n }),\n\n /**\n * Where this project lives on this machine, for every project at once.\n *\n * Machine-local by design: a directory of mine means nothing on a teammate's\n * machine, and the cloud sync pushes projects wholesale — a path stored on the\n * project itself would travel with it.\n */\n /**\n * Le projet que cet onglet regarde.\n *\n * Le choix vit dans le navigateur ; le serveur ne le connaîtrait pas sans\n * cette annonce. Il n'en fait rien de persistant — seule l'icône de barre\n * système s'en sert, pour montrer les services du projet ouvert plutôt que\n * ceux de toute la machine.\n */\n setCurrent: protectedProcedure\n .input(z.object({ id: z.string().max(128), orgId: z.string().max(128).nullable().default(null) }).nullable())\n .mutation(({ input }) => {\n setCurrentProject(input ? { id: input.id, orgId: input.orgId } : null);\n return { ok: true as const };\n }),\n\n /**\n * Le graphe des dépendances du projet : qui a besoin de qui.\n *\n * Les arêtes ne sont pas déclarées, elles se lisent — une variable de A qui\n * cite `{{services.<slug-de-B>.PORT}}` EST la dépendance, celle-là même que\n * l'interpolation résout au déploiement. Rien à tenir à jour à côté, donc\n * rien qui puisse mentir.\n *\n * Seules les CLÉS des variables sortent d'ici. Les valeurs résolues portent\n * des secrets déchiffrés : elles servent à détecter la référence, et\n * s'arrêtent là.\n */\n graph: protectedProcedure\n .input(z.object({\n id: z.string().min(1).max(128),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .query(async ({ ctx, input }) => {\n const project = await projectStore.get(input);\n if (!project) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.id} not found` });\n }\n await assertReadable(project.orgId);\n\n const allowed = getAllowedServiceIds(ctx);\n const services = (await Promise.all(project.serviceIds.map((sid) => serviceStore.get(sid))))\n .filter((s) => s !== null);\n\n // Sans environnement actif, aucune variable n'est résolue : le graphe\n // rend alors ses nœuds et aucune arête, ce qui est la vérité.\n const envByServiceId: Record<string, Record<string, string>> = {};\n if (project.activeEnvironmentId) {\n const activeEnvironmentId = project.activeEnvironmentId;\n await Promise.all(services.map(async (service) => {\n try {\n const resolved = await environmentResolver.resolveForService({\n serviceId: service.id,\n activeEnvironmentId,\n });\n envByServiceId[service.id] = resolved.env;\n } catch (err) {\n // Un environnement illisible ne doit pas emporter le graphe\n // entier : ce service perd ses arêtes, les autres gardent les\n // leurs.\n console.error('[project-router] Failed to resolve variables for graph, service', service.id + ':', (err as Error).message);\n }\n }));\n }\n\n const graph = buildServiceGraph({\n services: services.map((s) => ({ id: s.id, name: s.name })),\n envByServiceId,\n });\n\n // Une clé d'API ne voit que les services qu'elle porte. Le filtre vient\n // APRÈS le calcul, jamais avant : bâtir le graphe sur une liste amputée\n // ferait passer les services retirés pour des références mortes, et\n // publierait leurs slugs dans `dangling` — soit exactement le nom qu'on\n // voulait taire.\n if (allowed === null) return graph;\n return {\n nodes: graph.nodes.filter((n) => allowed.has(n.id)),\n edges: graph.edges.filter((e) => allowed.has(e.from) && allowed.has(e.to)),\n dangling: graph.dangling.filter((d) => allowed.has(d.from)),\n };\n }),\n\n localPaths: protectedProcedure.query(async () => {\n return projectPathStore.all();\n }),\n\n getLocalPath: protectedProcedure\n .input(z.object({\n id: z.string().min(1).max(128),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .query(async ({ input }) => {\n return { path: await projectPathStore.get(input) };\n }),\n\n /**\n * Place a project in a directory of this machine.\n *\n * Refuses a directory that already holds a Runeya project, or one another\n * project was already placed in: two projects sharing a directory is what\n * makes services run against the wrong code.\n */\n setLocalPath: protectedProcedure\n .input(z.object({\n id: z.string().min(1).max(128),\n orgId: z.string().max(128).nullable().optional(),\n path: z.string().min(1).max(4096),\n }))\n .mutation(async ({ input }) => {\n const project = await projectStore.get(input);\n if (!project) throw new TRPCError({ code: 'NOT_FOUND', message: 'Projet introuvable' });\n\n if (await holdsRuneyaProject(input.path)) {\n throw new TRPCError({\n code: 'CONFLICT',\n message: 'Ce répertoire contient déjà un projet Runeya',\n });\n }\n const taken = await projectPathStore.projectAt(input.path, project);\n if (taken) {\n throw new TRPCError({\n code: 'CONFLICT',\n message: 'Un autre projet est déjà rattaché à ce répertoire',\n });\n }\n\n await projectPathStore.set(project, input.path);\n await auditService.log({ userId: 'local', action: 'update', entityType: 'project', entityId: input.id, metadata: { localPath: input.path } });\n return { path: input.path };\n }),\n /**\n * Ce qui a changé dans les stores, à mesure que ça change.\n *\n * Un projet, un service ou un environnement n'arrive pas toujours de\n * l'utilisateur assis devant : il descend du cloud quand un collègue le\n * pousse, ou d'une autre Runeya de cette machine. Les stores étaient déjà\n * prévenus — la synchronisation s'appuie sur les mêmes signaux — mais rien ne\n * portait l'information jusqu'à l'écran, qui gardait donc ce qu'il avait\n * chargé à l'ouverture de la vue.\n *\n * Ce flux annonce les collections touchées, pas leur contenu. Chacune a déjà\n * sa route, avec ses règles — un service ne sort jamais d'ici sans être\n * expurgé de ses secrets — et les redire ici en ferait une seconde version à\n * tenir d'accord avec la première.\n *\n * Les réveils sont groupés : une synchronisation qui descend un projet touche\n * ses trois collections coup sur coup, et trois annonces feraient trois\n * rechargements là où un seul suffit.\n */\n onDataChanged: protectedProcedure.subscription(async function* ({ signal }) {\n const touched = new Set<'projects' | 'services' | 'environments'>();\n let wake: (() => void) | null = null;\n\n const mark = (collection: 'projects' | 'services' | 'environments') => () => {\n touched.add(collection);\n if (wake) { wake(); wake = null; }\n };\n const onProjects = mark('projects');\n projectStore.events.on('saved', onProjects);\n const offs = [serviceStore.onChange(mark('services')), environmentStore.onChange(mark('environments'))];\n\n // Sans ce réveil, un client parti pendant l'attente laisserait le\n // générateur suspendu pour toujours — l'abandon ne franchit pas un `await`,\n // donc le désabonnement ci-dessous n'arriverait jamais.\n const onAbort = () => { if (wake) { wake(); wake = null; } };\n signal?.addEventListener('abort', onAbort);\n\n try {\n while (!signal?.aborted) {\n if (touched.size > 0) {\n const collections = Array.from(touched);\n touched.clear();\n yield { collections };\n } else {\n await new Promise<void>((resolve) => { wake = resolve; });\n }\n }\n } finally {\n projectStore.events.off('saved', onProjects);\n for (const off of offs) off();\n signal?.removeEventListener('abort', onAbort);\n }\n }),\n});\n","/**\n * Le projet que l'utilisateur regarde, connu du serveur.\n *\n * Ce choix vit dans le `localStorage` du navigateur : c'est l'onglet qui sait\n * quel projet est ouvert, et rien ne le disait au serveur. L'icône de barre\n * système, elle, n'a pas d'onglet — sans cette annonce, elle listerait les\n * services de tous les projets de la machine alors que l'écran n'en montre\n * qu'un.\n *\n * Gardé en mémoire, jamais sur le disque : c'est l'état d'une session\n * d'affichage, pas une configuration. Un redémarrage repart sans projet\n * courant, et l'onglet le redit en se rouvrant.\n */\nimport type { ProjectRef } from './project-key.js';\n\nlet current: ProjectRef | null = null;\nconst listeners = new Set<() => void>();\n\n/** Le projet regardé, ou `null` tant qu'aucun onglet ne l'a annoncé. */\nexport function getCurrentProject(): ProjectRef | null {\n return current;\n}\n\n/**\n * Annonce le projet regardé.\n *\n * Ne prévient que si le projet change vraiment : un onglet qui répète son\n * choix — au rechargement, ou à chaque reconnexion — ne doit pas faire\n * redessiner ce qui n'a pas bougé.\n */\nexport function setCurrentProject(next: ProjectRef | null): void {\n if (current?.id === next?.id && current?.orgId === next?.orgId) return;\n current = next;\n for (const listener of listeners) {\n try {\n listener();\n } catch {\n // Un abonné qui échoue ne doit pas empêcher les autres d'être prévenus.\n }\n }\n}\n\nexport function onCurrentProjectChanged(listener: () => void): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n","import { mkdir } from 'node:fs/promises';\nimport {\n readEncryptedKey,\n writeEncryptedKey,\n writeVerifyFile,\n readVerifyFile,\n matchesCanary,\n hasEncryptedKeyFile,\n} from './master-password.js';\nimport { setEncryptionKeyInMemory, getEncryptionKey, markVaultLocked, isVaultLocked, hasEncryptionKey } from '../utils/encryption-key.js';\nimport { orgVaultRoot, listOrgVaults, keyRoot } from './vault-resolver.js';\n\n/**\n * Une clé de chiffrement par organisation.\n *\n * La clé protégeait tout le poste, alors que ce qu'elle protège appartient à\n * des organisations différentes : une clé qui change — ou une organisation dont\n * la clé n'est pas la nôtre — emportait donc la machine entière. Chaque\n * organisation a désormais la sienne, rangée dans son coffre et scellée par le\n * même master password, si bien que déverrouiller la machine les ouvre toutes\n * d'un geste.\n *\n * La bascule est gratuite, et c'est voulu : une organisation sans clé propre\n * reçoit **la clé machine actuelle**. Ses données sont déjà chiffrées sous\n * elle, il n'y a donc rien à convertir, rien à perdre, et rien à demander à\n * l'utilisateur. Le jour où une organisation adopte une autre clé, seul son\n * coffre est re-chiffré — le reste de la machine ne bouge pas.\n */\n\nexport interface OrgKeyReport {\n /** Organisations dont la clé a été ouverte depuis leur coffre. */\n opened: string[];\n /** Organisations qui viennent de recevoir la clé machine comme clé propre. */\n seeded: string[];\n /**\n * Organisations dont la clé existe mais que ce master password n'ouvre pas.\n *\n * Le poste reste utilisable : ces coffres-là ne se déchiffrent pas, et la\n * synchronisation les écartera en le disant, plutôt que de rendre toute la\n * machine inaccessible pour une organisation.\n */\n locked: string[];\n}\n\n/**\n * Ouvrir — ou amorcer — la clé de chaque organisation présente sur ce disque.\n *\n * Appelé au déverrouillage, une fois la clé machine chargée. `masterPassword`\n * peut manquer (mode CI, où la clé vient de l'environnement) : on charge alors\n * la clé machine en mémoire pour chaque organisation sans rien écrire, ce qui\n * reproduit exactement le comportement d'avant les clés par organisation.\n */\nexport async function unlockOrgKeys(masterPassword: string | null): Promise<OrgKeyReport> {\n const machineKey = getEncryptionKey();\n const report: OrgKeyReport = { opened: [], seeded: [], locked: [] };\n if (!machineKey) return report;\n\n for (const orgId of await listOrgVaults()) {\n const root = orgVaultRoot(orgId);\n\n // Sans master password, rien ne peut être ni ouvert ni scellé. La clé\n // machine sert alors pour les organisations qui n'ont pas la leur — mais\n // JAMAIS pour celles qui en ont une : leur donner la clé machine ne les\n // rend pas lisibles, ça les rend inscriptibles sous la mauvaise clé, et\n // c'est ainsi qu'un coffre finit à moitié dans un chiffrement et à moitié\n // dans l'autre.\n if (!masterPassword) {\n if (await hasEncryptedKeyFile(root)) {\n markVaultLocked(orgId);\n report.locked.push(orgId);\n continue;\n }\n setEncryptionKeyInMemory(machineKey, orgId);\n continue;\n }\n\n const canary = await readVerifyFile(root);\n if (canary) {\n try {\n const key = await readEncryptedKey(root, masterPassword, await keyRoot());\n // Le canari du coffre tranche : le mot de passe peut ouvrir le fichier\n // et rendre une clé qui n'est pas celle sous laquelle ce coffre a été\n // écrit — auquel cas s'en servir écrirait du charabia par-dessus.\n if (!matchesCanary(canary, key)) {\n markVaultLocked(orgId);\n report.locked.push(orgId);\n continue;\n }\n setEncryptionKeyInMemory(key, orgId);\n report.opened.push(orgId);\n } catch {\n markVaultLocked(orgId);\n report.locked.push(orgId);\n }\n continue;\n }\n\n // Première rencontre : l'organisation adopte la clé machine, qui est déjà\n // celle de ses données. Écrit avant d'être chargé — une clé en mémoire que\n // le disque ignore disparaîtrait au redémarrage en laissant le coffre\n // chiffré sous une clé que plus rien ne nomme.\n await mkdir(root, { recursive: true });\n await writeEncryptedKey(root, masterPassword, machineKey, await keyRoot());\n await writeVerifyFile(root, machineKey);\n setEncryptionKeyInMemory(machineKey, orgId);\n report.seeded.push(orgId);\n }\n\n return report;\n}\n\n/**\n * Installer une clé donnée comme clé d'une organisation.\n *\n * Ne convertit rien : c'est à l'appelant d'avoir re-chiffré le coffre au\n * préalable, faute de quoi son contenu deviendrait illisible. Utilisé par\n * l'adoption, qui fait les deux dans le bon ordre.\n */\nexport async function installOrgKey(\n orgId: string,\n key: Buffer,\n masterPassword: string,\n): Promise<void> {\n const root = orgVaultRoot(orgId);\n await mkdir(root, { recursive: true });\n const pepperDir = await keyRoot();\n await writeEncryptedKey(root, masterPassword, key, pepperDir);\n const readBack = await readEncryptedKey(root, masterPassword, pepperDir);\n if (!readBack.equals(key)) {\n throw new Error(\"Vérification du fichier de clé de l'organisation échouée.\");\n }\n await writeVerifyFile(root, key);\n setEncryptionKeyInMemory(key, orgId);\n}\n\n/**\n * Le coffre d'une organisation est illisible depuis ce poste.\n *\n * Distinct d'une panne : la donnée est là, intacte, mais sous une clé que cette\n * machine n'a pas. Le geste qui répare est l'adoption de la clé, pas une\n * nouvelle tentative.\n */\nexport class OrgVaultUnreadableError extends Error {\n readonly code = 'ORG_VAULT_UNREADABLE';\n constructor(readonly orgId: string) {\n // Le code, pas la phrase : c'est l'interface qui sait dire où adopter.\n super('ORG_VAULT_UNREADABLE');\n this.name = 'OrgVaultUnreadableError';\n }\n}\n\n/**\n * Refuser d'ouvrir ce qu'on ne saura pas lire.\n *\n * Purement local, et c'est le point : `reconcileOrgCanary` interroge le cloud et\n * n'est éprouvé qu'à la première connexion d'une organisation, si bien qu'une\n * machine déjà connectée ouvrait ensuite n'importe quel projet sans que rien ne\n * revérifie la clé. Or ouvrir un projet, c'est charger ses environnements, ses\n * services et ses conversations — puis les réécrire à la première sauvegarde.\n * Sous la mauvaise clé, cette écriture passe par-dessus des secrets qu'on n'a\n * pas su lire : mieux vaut ne pas ouvrir du tout.\n *\n * Deux cas refusent :\n * - le coffre est verrouillé — sa clé existe, ce master password ne l'ouvre pas ;\n * - il a un canari que la clé en usage ici n'ouvre pas — c'est exactement la\n * situation où `getEncryptionKey` retombe en silence sur la clé machine.\n *\n * Une organisation sans canari local n'a pas encore de clé à elle : ses données\n * sont sous la clé machine, et l'ouvrir est sans risque.\n */\nexport async function assertOrgVaultReadable(orgId: string): Promise<void> {\n if (isVaultLocked(orgId)) throw new OrgVaultUnreadableError(orgId);\n\n const canary = await readVerifyFile(orgVaultRoot(orgId));\n if (!canary) return;\n\n const key = getEncryptionKey(orgId);\n if (!key || !matchesCanary(canary, key)) throw new OrgVaultUnreadableError(orgId);\n}\n\n/**\n * Fermer d'avance tout coffre qui a sa propre clé et qu'on n'a pas ouverte.\n *\n * Sans ça, `getEncryptionKey(orgId)` retombe en silence sur la clé machine pour\n * un coffre absent du trousseau. Le repli est juste pour une organisation qui\n * n'a pas encore de clé — ses données SONT sous la clé machine — et faux pour\n * une organisation qui en a une : la lecture échoue, et surtout l'écriture\n * réussit, sous une clé que ce coffre n'emploie pas. C'est ainsi qu'un fichier\n * se retrouve chiffré autrement que ses voisins, sans que rien ne le signale.\n *\n * Appelé avant que le moindre store ne lise le disque : à partir de là, un\n * coffre non ouvert refuse au lieu de se tromper. `setEncryptionKeyInMemory`\n * lève le verrou dès que la vraie clé arrive.\n */\nexport async function sealUnopenedOrgVaults(): Promise<string[]> {\n const sealed: string[] = [];\n for (const orgId of await listOrgVaults()) {\n if (hasEncryptionKey(orgId)) continue;\n if (!(await hasEncryptedKeyFile(orgVaultRoot(orgId)))) continue;\n markVaultLocked(orgId);\n sealed.push(orgId);\n }\n return sealed;\n}\n","import { randomBytes, createCipheriv, createDecipheriv } from 'node:crypto';\nimport { readFile, writeFile, chmod, stat, rename } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { Entry } from '@napi-rs/keyring';\nimport { hashRaw as argon2HashRaw } from '@node-rs/argon2';\n\nconst KEYRING_SERVICE = 'runeya';\nconst KEYRING_ACCOUNT = 'pepper';\nconst VERIFY_FILENAME = '.runeya-verify';\nconst ENCRYPTED_KEY_FILENAME = '.encryption.key.enc';\nconst PEPPER_FILENAME = '.pepper.private';\nconst CANARY_PLAINTEXT = 'runeya:v1:key-verification';\nconst MAX_KEY_FILE_SIZE = 1024; // 1 KB\nconst ARGON2_OPTIONS = { memoryCost: 65536, timeCost: 3, parallelism: 4, outputLen: 32 };\n\n// Helper: validate file size before reading\nasync function readKeyFile(filePath: string): Promise<Buffer> {\n const s = await stat(filePath);\n if (s.size > MAX_KEY_FILE_SIZE) throw new Error(`Fichier suspect : ${filePath} (${s.size} octets)`);\n return readFile(filePath);\n}\n\n// AES-256-GCM encrypt\nfunction aesEncrypt(key: Buffer, plaintext: Buffer): Buffer {\n const iv = randomBytes(12);\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);\n const authTag = cipher.getAuthTag();\n return Buffer.concat([iv, authTag, encrypted]); // 12 + 16 + N bytes\n}\n\n// AES-256-GCM decrypt — throws if authTag invalid\nfunction aesDecrypt(key: Buffer, data: Buffer): Buffer {\n const iv = data.subarray(0, 12);\n const authTag = data.subarray(12, 28);\n const ciphertext = data.subarray(28);\n const decipher = createDecipheriv('aes-256-gcm', key, iv, { authTagLength: 16 });\n decipher.setAuthTag(authTag);\n return Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n}\n\n// Fallback: store pepper as a file in dataDir (chmod 600)\nasync function getPepperFromFile(dataDir: string): Promise<Buffer | null> {\n try {\n const raw = await readKeyFile(join(dataDir, PEPPER_FILENAME));\n const hex = raw.toString('utf-8').trim();\n if (/^[0-9a-f]{64}$/i.test(hex)) return Buffer.from(hex, 'hex');\n } catch { /* not found */ }\n return null;\n}\n\nasync function writePepperToFile(dataDir: string, pepper: Buffer): Promise<void> {\n const filePath = join(dataDir, PEPPER_FILENAME);\n const tmpPath = filePath + '.tmp';\n await writeFile(tmpPath, pepper.toString('hex'), 'utf-8');\n await chmod(tmpPath, 0o600);\n await rename(tmpPath, filePath);\n}\n\nfunction tryKeyringGet(): string | null {\n try { return new Entry(KEYRING_SERVICE, KEYRING_ACCOUNT).getPassword(); } catch { return null; }\n}\n\nfunction tryKeyringSet(value: string): boolean {\n try { new Entry(KEYRING_SERVICE, KEYRING_ACCOUNT).setPassword(value); return true; } catch { return false; }\n}\n\n// Get or generate pepper — keyring first, file fallback\nasync function getOrCreatePepper(dataDir: string): Promise<Buffer> {\n // Try keyring read\n const pepperHex = tryKeyringGet();\n if (pepperHex && /^[0-9a-f]{64}$/i.test(pepperHex)) {\n return Buffer.from(pepperHex, 'hex');\n }\n // Keyring failed or empty — try file fallback\n const filePepper = await getPepperFromFile(dataDir);\n if (filePepper) return filePepper;\n // Generate new pepper, persist in keyring if possible, else file\n const pepper = randomBytes(32);\n const saved = tryKeyringSet(pepper.toString('hex'));\n if (!saved) {\n console.warn('[master-password] Keyring unavailable, storing pepper in dataDir (fallback)');\n await writePepperToFile(dataDir, pepper);\n }\n return pepper;\n}\n\n// Derive key from master password + pepper using Argon2id\n// Returns 32-byte derived key (never stored)\nasync function deriveKey(masterPassword: string, pepper: Buffer, salt: Buffer): Promise<Buffer> {\n const combined = masterPassword + pepper.toString('hex');\n const derived = await argon2HashRaw(combined, {\n ...ARGON2_OPTIONS,\n salt,\n });\n return Buffer.from(derived);\n}\n\n// Encrypt encryption key and write to .encryption.key.enc\n// Format: base64(salt_16 + iv_12 + authTag_16 + ciphertext_32)\n/**\n * `pepperDir` dit où trouver le poivre quand le trousseau de l'OS est\n * indisponible. Il vaut le répertoire de la clé par défaut, mais un coffre\n * d'organisation le fait pointer vers la racine machine : le poivre décrit le\n * poste, pas l'organisation, et en semer une copie par coffre en ferait un\n * secret de plus à tenir en accord avec les autres.\n */\nexport async function writeEncryptedKey(\n dataDir: string,\n masterPassword: string,\n encryptionKey: Buffer,\n pepperDir: string = dataDir,\n): Promise<void> {\n const pepper = await getOrCreatePepper(pepperDir);\n const salt = randomBytes(16);\n const derivedKey = await deriveKey(masterPassword, pepper, salt);\n const payload = aesEncrypt(derivedKey, encryptionKey); // iv(12) + authTag(16) + ciphertext(32)\n const fileContent = Buffer.concat([salt, payload]);\n const encoded = fileContent.toString('base64');\n const filePath = join(dataDir, ENCRYPTED_KEY_FILENAME);\n const tmpPath = filePath + '.tmp';\n await writeFile(tmpPath, encoded, 'utf-8');\n await chmod(tmpPath, 0o600);\n await rename(tmpPath, filePath);\n}\n\n// Read and decrypt .encryption.key.enc — throws on wrong password\nexport async function readEncryptedKey(\n dataDir: string,\n masterPassword: string,\n pepperDir: string = dataDir,\n): Promise<Buffer> {\n const filePath = join(dataDir, ENCRYPTED_KEY_FILENAME);\n const raw = await readKeyFile(filePath);\n const fileContent = Buffer.from(raw.toString('utf-8').trim(), 'base64');\n const salt = fileContent.subarray(0, 16);\n const payload = fileContent.subarray(16); // iv(12) + authTag(16) + ciphertext(32)\n const pepper = await getPepperFromKeychain(pepperDir);\n const derivedKey = await deriveKey(masterPassword, pepper, salt);\n // throws if authTag invalid → wrong password\n return aesDecrypt(derivedKey, payload);\n}\n\n// Get pepper from keychain, file fallback (must exist — throws if not found anywhere)\nasync function getPepperFromKeychain(dataDir: string): Promise<Buffer> {\n const pepperHex = tryKeyringGet();\n if (pepperHex && /^[0-9a-f]{64}$/i.test(pepperHex)) {\n return Buffer.from(pepperHex, 'hex');\n }\n // Fallback to file\n const filePepper = await getPepperFromFile(dataDir);\n if (filePepper) return filePepper;\n throw new Error('Pepper introuvable (keyring et fichier). Re-setup requis.');\n}\n\n// Write canary file .runeya-verify\nexport async function writeVerifyFile(dataDir: string, encryptionKey: Buffer): Promise<void> {\n const payload = aesEncrypt(encryptionKey, Buffer.from(CANARY_PLAINTEXT, 'utf-8'));\n const filePath = join(dataDir, VERIFY_FILENAME);\n const tmpPath = filePath + '.tmp';\n await writeFile(tmpPath, payload.toString('base64'), 'utf-8');\n await rename(tmpPath, filePath);\n}\n\n// Verify encryption key against .runeya-verify — throws if wrong key\nexport async function verifyEncryptionKey(dataDir: string, encryptionKey: Buffer): Promise<void> {\n const filePath = join(dataDir, VERIFY_FILENAME);\n const raw = await readKeyFile(filePath);\n if (!matchesCanary(raw.toString('utf-8'), encryptionKey)) {\n throw new Error('Clé d\\'encryption incorrecte');\n }\n}\n\n/**\n * Whether a canary was produced by this key.\n *\n * Canaries cannot be compared to each other: `aesEncrypt` uses a random IV, so\n * the same key yields a different canary every time. The only test is to\n * decrypt — which is also why holding a canary reveals nothing about the key.\n *\n * Takes the canary value rather than a path, so the same check works on the\n * local `.runeya-verify` and on the one an organization publishes to the cloud.\n */\nexport function matchesCanary(canaryBase64: string, encryptionKey: Buffer): boolean {\n try {\n const payload = Buffer.from(canaryBase64.trim(), 'base64');\n return aesDecrypt(encryptionKey, payload).toString('utf-8') === CANARY_PLAINTEXT;\n } catch {\n // Wrong key => GCM auth failure. Indistinguishable from a corrupt canary,\n // and both mean the same thing here: this key does not open it.\n return false;\n }\n}\n\n/** This machine's canary, or null when setup has not written one yet. */\nexport async function readVerifyFile(dataDir: string): Promise<string | null> {\n try {\n return (await readKeyFile(join(dataDir, VERIFY_FILENAME))).toString('utf-8').trim();\n } catch {\n return null;\n }\n}\n\n// Check if .runeya-verify exists\nexport async function hasVerifyFile(dataDir: string): Promise<boolean> {\n try {\n await stat(join(dataDir, VERIFY_FILENAME));\n return true;\n } catch {\n return false;\n }\n}\n\n// Check if .encryption.key.enc exists\nexport async function hasEncryptedKeyFile(dataDir: string): Promise<boolean> {\n try {\n await stat(join(dataDir, ENCRYPTED_KEY_FILENAME));\n return true;\n } catch {\n return false;\n }\n}\n\n","import { ambiguousServiceSlugs, crossServiceSlugsIn, serviceSlug } from '@runeya/packages-shared';\n\n/**\n * Le graphe des dépendances entre services d'un projet, tel qu'il se lit dans\n * les variables d'environnement.\n *\n * Rien de nouveau n'est déclaré pour le construire : une arête `A → B` existe\n * parce qu'une variable de A cite `{{services.<slug-de-B>.PORT}}` — la même\n * référence que l'interpolation remplace au déploiement (voir\n * `buildServerBuiltins`). Le graphe décrit donc ce qui se passe vraiment, et\n * ne peut pas se désynchroniser d'une configuration tenue à part.\n */\n\ninterface ServiceGraphNode {\n id: string;\n name: string;\n slug: string;\n /**\n * Deux services du projet portent ce slug : aucun des deux n'est adressable\n * (`buildServerBuiltins` les exclut tous les deux). Les références qui les\n * nomment restent donc sans effet — et l'interface a de quoi le dire.\n */\n ambiguousSlug: boolean;\n}\n\ninterface ServiceGraphEdge {\n /** Le service qui a besoin de l'autre. */\n from: string;\n /** Celui dont il lit le port, l'URL ou le nom. */\n to: string;\n /** Les variables qui portent la référence — leurs clés, jamais leurs valeurs. */\n keys: string[];\n}\n\n/** Une référence qui ne mène à aucun service : faute de frappe, ou service retiré. */\ninterface ServiceGraphDanglingRef {\n from: string;\n slug: string;\n keys: string[];\n}\n\nexport interface ServiceGraph {\n nodes: ServiceGraphNode[];\n edges: ServiceGraphEdge[];\n dangling: ServiceGraphDanglingRef[];\n}\n\nexport interface ServiceGraphInput {\n services: { id: string; name: string }[];\n /**\n * Pour chaque service, ses variables résolues AVANT interpolation des\n * builtins : les `{{services.*}}` y sont donc encore lisibles. C'est ce que\n * rend `environmentResolver.resolveForService`.\n *\n * Seules les CLÉS ressortent d'ici : une valeur peut être un secret déchiffré.\n */\n envByServiceId: Record<string, Record<string, string>>;\n}\n\n/** Accumule les clés par couple (source, cible), sans jamais garder de valeur. */\nfunction addKey(\n buckets: Map<string, { from: string; target: string; keys: Set<string> }>,\n from: string,\n target: string,\n key: string,\n): void {\n // Le couple sert d'identité ; les deux moitiés sont conservées à part pour\n // n'avoir aucune chaîne à ré-analyser ensuite. Le séparateur est écrit en\n // séquence d'échappement, jamais en caractère brut : un octet nul dans le\n // source ferait classer ce fichier comme binaire par git, et il n'aurait\n // plus ni diff ni fusion.\n const id = `${from}\\u0000${target}`;\n const bucket = buckets.get(id) ?? { from, target, keys: new Set<string>() };\n bucket.keys.add(key);\n buckets.set(id, bucket);\n}\n\n/**\n * Volontairement pur — aucun store, aucun accès disque : la règle qui compte\n * ici (quelle référence fait quelle arête) se teste sans monter un serveur.\n */\nexport function buildServiceGraph(input: ServiceGraphInput): ServiceGraph {\n const ambiguous = ambiguousServiceSlugs(input.services.map((s) => s.name));\n\n const nodes: ServiceGraphNode[] = input.services.map((service) => {\n const slug = serviceSlug(service.name);\n return {\n id: service.id,\n name: service.name,\n slug,\n ambiguousSlug: ambiguous.has(slug),\n };\n });\n\n // Un slug ambigu n'entre pas dans la table : le résoudre vers l'un des deux\n // services dépendrait de l'ordre de chargement — exactement ce que\n // `buildServerBuiltins` refuse de faire au moment d'interpoler.\n const bySlug = new Map<string, string>();\n for (const node of nodes) {\n if (node.slug && !node.ambiguousSlug) bySlug.set(node.slug, node.id);\n }\n\n const edgeBuckets = new Map<string, { from: string; target: string; keys: Set<string> }>();\n const danglingBuckets = new Map<string, { from: string; target: string; keys: Set<string> }>();\n\n for (const service of input.services) {\n const env = input.envByServiceId[service.id] ?? {};\n for (const [key, value] of Object.entries(env)) {\n for (const slug of crossServiceSlugsIn(value)) {\n const target = bySlug.get(slug);\n // Une auto-référence n'est pas une dépendance : `{{services.a.PORT}}`\n // écrit depuis A redit ce que `{{service.PORT}}` dit déjà. Ni arête,\n // ni signalement.\n if (target === service.id) continue;\n if (target) addKey(edgeBuckets, service.id, target, key);\n else addKey(danglingBuckets, service.id, slug, key);\n }\n }\n }\n\n const edges: ServiceGraphEdge[] = [...edgeBuckets.values()].map((b) => ({\n from: b.from,\n to: b.target,\n keys: [...b.keys].sort(),\n }));\n const dangling: ServiceGraphDanglingRef[] = [...danglingBuckets.values()].map((b) => ({\n from: b.from,\n slug: b.target,\n keys: [...b.keys].sort(),\n }));\n\n return { nodes, edges, dangling };\n}\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { LOG_BUFFER_SIZE } from '@runeya/packages-shared';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { agentManager } from '../../services/agent-manager.js';\nimport type { AgentStatus } from '@runeya/packages-shared';\n\nconst SUBSCRIPTION_QUEUE_MAX = LOG_BUFFER_SIZE;\n\nexport const agentRouter = router({\n /** List all registered agents with their connection status */\n list: protectedProcedure.query(() => {\n return agentManager.listAgents();\n }),\n\n /** Get a single agent's config and status */\n get: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .query(({ input }) => {\n const agent = agentManager.getAgent(input.id);\n if (!agent) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Agent ${input.id} not found` });\n }\n return {\n config: { ...agent.config, passphrase: '***' },\n status: agent.status,\n };\n }),\n\n /** Test connectivity to an agent given url + passphrase */\n testConnection: protectedProcedure\n .input(\n z.object({\n url: z.string().url().max(2048),\n passphrase: z.string().min(1).max(1024).optional(),\n agentId: z.string().max(128).optional(),\n }),\n )\n .mutation(async ({ input }) => {\n let passphrase = input.passphrase;\n let targetUrl = input.url;\n if (!passphrase && input.agentId) {\n const agent = agentManager.getAgentConfig(input.agentId);\n if (!agent) {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'Agent not found' });\n }\n passphrase = agent.passphrase;\n // SECURITY: When using a stored passphrase, always use the stored agent URL\n // to prevent exfiltration of the passphrase to an attacker-controlled URL\n targetUrl = agent.url;\n }\n if (!passphrase) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Passphrase is required' });\n }\n\n const url = new URL('/api/trpc/health.check', targetUrl);\n try {\n const res = await fetch(url.toString(), {\n headers: { 'Authorization': `Bearer ${passphrase}`, 'Content-Type': 'application/json' },\n signal: AbortSignal.timeout(5000),\n });\n if (!res.ok) {\n return { success: false as const, error: `HTTP ${res.status} ${res.statusText}` };\n }\n const json = await res.json() as { error?: { message?: string }; result?: { data?: { uptime?: number } } };\n if (json.error) {\n return { success: false as const, error: json.error.message ?? 'Agent returned an error' };\n }\n return { success: true as const, uptime: json.result?.data?.uptime };\n } catch (err) {\n const msg = err instanceof Error ? err.message : 'Unknown error';\n return { success: false as const, error: msg };\n }\n }),\n\n /** Register a new agent */\n register: protectedProcedure\n .input(\n z.object({\n name: z.string().min(1).max(100),\n url: z.string().url().max(2048),\n passphrase: z.string().min(1).max(1024),\n // À quelle organisation rattacher l'agent. Absent = la machine, ce que\n // font l'agent local et tout client antérieur à ce champ.\n orgId: z.string().min(1).max(128).nullable().optional(),\n }),\n )\n .mutation(async ({ input }) => {\n const config = await agentManager.register(\n input.name, input.url, input.passphrase, input.orgId ?? null,\n );\n return { ...config, passphrase: '***' };\n }),\n\n /** Update an existing agent */\n update: protectedProcedure\n .input(\n z.object({\n id: z.string().max(128),\n name: z.string().min(1).max(100).optional(),\n url: z.string().url().max(2048).optional(),\n passphrase: z.string().min(1).max(1024).optional(),\n passthroughEnv: z.array(\n z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/).max(256),\n ).max(100).optional(),\n }),\n )\n .mutation(async ({ input }) => {\n try {\n const { id, ...fields } = input;\n const config = await agentManager.update(id, fields);\n return { ...config, passphrase: '***' };\n } catch (err) {\n if (err instanceof Error) {\n if (err.message.includes('not found')) {\n throw new TRPCError({ code: 'NOT_FOUND', message: err.message });\n }\n if (err.message.includes('Cannot modify')) {\n throw new TRPCError({ code: 'FORBIDDEN', message: err.message });\n }\n }\n throw err;\n }\n }),\n\n /** Get resolved passthrough env values from an agent */\n getPassthroughEnv: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .query(async ({ input }) => {\n try {\n return await agentManager.agentQuery<Record<string, string>>(input.id, 'config.getPassthroughEnv');\n } catch {\n return {};\n }\n }),\n\n /** Remove a registered agent */\n remove: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .mutation(async ({ input }) => {\n try {\n const removed = await agentManager.remove(input.id);\n if (!removed) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Agent ${input.id} not found` });\n }\n return { success: true as const };\n } catch (err) {\n if (err instanceof Error && err.message === 'Cannot remove the local agent') {\n throw new TRPCError({ code: 'FORBIDDEN', message: err.message });\n }\n throw err;\n }\n }),\n\n /** Subscribe to real-time agent status changes */\n onStatus: protectedProcedure.subscription(async function* () {\n // Yield current state of all agents immediately so the client\n // doesn't have to wait for the next health tick.\n for (const agent of agentManager.listAgents()) {\n yield { agentId: agent.config.id, status: agent.status };\n }\n\n const queue: Array<{ agentId: string; status: AgentStatus }> = [];\n let resolve: (() => void) | null = null;\n\n const handler = (event: { agentId: string; status: AgentStatus }) => {\n if (queue.length >= SUBSCRIPTION_QUEUE_MAX) queue.shift();\n queue.push(event);\n if (resolve) {\n resolve();\n resolve = null;\n }\n };\n\n agentManager.on('status', handler);\n\n try {\n while (true) {\n if (queue.length > 0) {\n yield queue.shift()!;\n } else {\n await new Promise<void>((r) => { resolve = r; });\n }\n }\n } finally {\n agentManager.off('status', handler);\n }\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { LOG_BUFFER_SIZE, ServiceShortcutSchema, AGENT_LONG_FETCH_TIMEOUT } from '@runeya/packages-shared';\nimport type { ProcessStatus, ProcessMetrics } from '@runeya/packages-shared';\nimport { router, protectedProcedure, requireServiceAction, getAllowedServiceIds } from '../trpc.js';\nimport type { AuthContext } from '../trpc.js';\nimport { agentManager } from '../../services/agent-manager.js';\nimport { auditService } from '../../services/audit-service.js';\nimport { serviceStore } from '../../services/service-store.js';\nimport { startProcess, stopProcess, restartProcess, listAllProcesses } from '../../services/process-control.js';\nimport { resolveServiceVariables } from './service.js';\nimport { resolveAgentCwd } from '../../services/workspace-cwd.js';\n\n/** Max items in a subscription queue before dropping oldest */\nconst SUBSCRIPTION_QUEUE_MAX = LOG_BUFFER_SIZE;\n\n/**\n * Helper that creates a queued async generator forwarding events from agentManager.\n * Deduplicates the queue+handler pattern used by all process subscriptions.\n */\nasync function* forwardEvents<T = Record<string, unknown>>(\n eventName: string,\n filter?: (data: Record<string, unknown>) => boolean,\n): AsyncGenerator<T> {\n const queue: T[] = [];\n let resolve: (() => void) | null = null;\n\n const handler = (data: Record<string, unknown>) => {\n if (filter && !filter(data)) return;\n if (queue.length >= SUBSCRIPTION_QUEUE_MAX) queue.shift();\n queue.push(data as T);\n if (resolve) { resolve(); resolve = null; }\n };\n\n agentManager.on(eventName, handler);\n\n try {\n while (true) {\n if (queue.length > 0) {\n yield queue.shift()!;\n } else {\n await new Promise<void>((r) => { resolve = r; });\n }\n }\n } finally {\n agentManager.off(eventName, handler);\n }\n}\n\n/**\n * Helper for log batch forwarding. The AgentWSBridge wraps array data as\n * `{ batch: ParsedLog[], agentId }`. We filter by agentId + processId,\n * then yield the filtered batch to the frontend.\n */\nasync function* forwardLogBatches(\n agentId: string,\n processId: string,\n): AsyncGenerator<unknown[]> {\n const queue: unknown[][] = [];\n let resolve: (() => void) | null = null;\n\n const handler = (data: Record<string, unknown>) => {\n if (data.agentId !== agentId) return;\n const batch = data.batch as Array<Record<string, unknown>>;\n if (!Array.isArray(batch)) return;\n const filtered = batch.filter((log) => log.processId === processId);\n if (filtered.length === 0) return;\n if (queue.length >= SUBSCRIPTION_QUEUE_MAX) queue.shift();\n queue.push(filtered);\n if (resolve) { resolve(); resolve = null; }\n };\n\n agentManager.on('process:log', handler);\n\n try {\n while (true) {\n if (queue.length > 0) {\n yield queue.shift()!;\n } else {\n await new Promise<void>((r) => { resolve = r; });\n }\n }\n } finally {\n agentManager.off('process:log', handler);\n }\n}\n\nexport const processRouter = router({\n /** List all processes across all connected agents */\n list: protectedProcedure\n .meta({ openapi: { method: 'GET', path: '/processes', tags: ['processes'], summary: 'List all processes', protect: true } })\n .output(z.any())\n .query(() => listAllProcesses()),\n\n\n /** Get a single process from a specific agent */\n get: protectedProcedure\n .meta({ openapi: { method: 'GET', path: '/processes/{agentId}/{id}', tags: ['processes'], summary: 'Get a process by agent and ID', protect: true } })\n .input(z.object({ agentId: z.string().max(128), id: z.string().max(128) }))\n .output(z.any())\n .query(async ({ input, ctx }) => {\n requireServiceAction(ctx as AuthContext, input.id, 'service:read');\n const status = agentManager.getStatus(input.agentId);\n if (!status) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Agent ${input.agentId} not found` });\n }\n\n const proc = await agentManager.agentQuery<ProcessStatus>(input.agentId, 'process.get', { id: input.id });\n return { ...proc, agentId: input.agentId };\n }),\n\n\n /** Start a process on an agent.\n * Lazy deploy: the agent only learns about a service when it is first started\n * (or restarted). This avoids pushing configs for every service at agent boot,\n * which would be wasteful when many services are never started.\n * The deploy call is idempotent — creates the process if missing, updates config if it exists. */\n start: protectedProcedure\n .meta({ openapi: { method: 'POST', path: '/processes/{agentId}/{processId}/start', tags: ['processes'], summary: 'Start a process', protect: true } })\n .input(z.object({ agentId: z.string().max(128).optional(), processId: z.string().max(128) }))\n .output(z.any())\n .mutation(async ({ input, ctx }) => {\n requireServiceAction(ctx as AuthContext, input.processId, 'service:start');\n return startProcess(input.processId, input.agentId);\n }),\n\n /** Stop a process on an agent */\n stop: protectedProcedure\n .meta({ openapi: { method: 'POST', path: '/processes/{agentId}/{processId}/stop', tags: ['processes'], summary: 'Stop a process', protect: true } })\n .input(z.object({ agentId: z.string().max(128), processId: z.string().max(128) }))\n .output(z.any())\n .mutation(async ({ input, ctx }) => {\n requireServiceAction(ctx as AuthContext, input.processId, 'service:stop');\n return stopProcess(input.processId, input.agentId);\n }),\n\n /** Restart a process on an agent.\n * Sends stop → deploy (latest resolved config) → start so that\n * config/variable changes take effect. Same lazy deploy pattern as start. */\n restart: protectedProcedure\n .meta({ openapi: { method: 'POST', path: '/processes/{agentId}/{processId}/restart', tags: ['processes'], summary: 'Restart a process', protect: true } })\n .input(z.object({ agentId: z.string().max(128).optional(), processId: z.string().max(128) }))\n .output(z.any())\n .mutation(async ({ input, ctx }) => {\n requireServiceAction(ctx as AuthContext, input.processId, 'service:restart');\n return restartProcess(input.processId, input.agentId);\n }),\n\n /** Get buffered logs for a process from an agent */\n logs: protectedProcedure\n .meta({ openapi: { method: 'GET', path: '/processes/{agentId}/{processId}/logs', tags: ['processes'], summary: 'Get buffered logs for a process', protect: true } })\n .input(z.object({ agentId: z.string().max(128), processId: z.string().max(128) }))\n .output(z.any())\n .query(async ({ input, ctx }) => {\n requireServiceAction(ctx as AuthContext, input.processId, 'logs:read');\n return agentManager.agentQuery(input.agentId, 'process.logs', { id: input.processId });\n }),\n\n /** Clear buffered logs for a process on an agent */\n clearLogBuffer: protectedProcedure\n .input(z.object({ agentId: z.string().max(128), processId: z.string().max(128) }))\n .mutation(async ({ input }) => {\n await agentManager.agentMutation(input.agentId, 'process.clearLogBuffer', { id: input.processId });\n await auditService.log({ userId: 'local', action: 'clearLogBuffer', entityType: 'process', entityId: input.processId, metadata: { agentId: input.agentId } });\n return { success: true };\n }),\n\n /** Execute a shortcut command on an agent, streaming output into the process log */\n executeShortcut: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n processId: z.string().max(128),\n shortcut: ServiceShortcutSchema,\n }))\n .mutation(async ({ input }) => {\n // Lazy deploy: ensure the agent knows about this service (same pattern as start/restart)\n const service = await serviceStore.get(input.processId);\n if (service) {\n try {\n const resolved = await resolveServiceVariables(service);\n await agentManager.agentMutation(input.agentId, 'process.deploy', resolved);\n } catch (err) {\n console.debug('[process-router] Failed to deploy before executeShortcut for', input.processId + ':', (err as Error).message);\n }\n }\n\n const result = await agentManager.agentMutation<{ exitCode: number | null }>(\n input.agentId, 'process.executeShortcut',\n { id: input.processId, shortcut: input.shortcut },\n AGENT_LONG_FETCH_TIMEOUT,\n );\n await auditService.log({\n userId: 'local',\n action: 'executeShortcut',\n entityType: 'process',\n entityId: input.processId,\n metadata: { agentId: input.agentId, shortcutId: input.shortcut.id, shortcutLabel: input.shortcut.label },\n });\n return result;\n }),\n\n /** Execute an ad-hoc command on an agent, streaming output into the process log */\n executeAdHocCommand: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n processId: z.string().max(128),\n command: z.string().min(1).max(4096),\n cwd: z.string().max(4096).optional(),\n commandId: z.string().max(128).optional(),\n }))\n .mutation(async ({ input }) => {\n // Lazy deploy: ensure the agent knows about this service (same pattern as start/restart)\n const service = await serviceStore.get(input.processId);\n if (service) {\n try {\n const resolved = await resolveServiceVariables(service);\n await agentManager.agentMutation(input.agentId, 'process.deploy', resolved);\n } catch (err) {\n console.debug('[process-router] Failed to deploy before executeAdHocCommand for', input.processId + ':', (err as Error).message);\n }\n }\n\n const result = await agentManager.agentMutation<{ exitCode: number | null }>(\n input.agentId, 'process.executeAdHocCommand',\n {\n id: input.processId,\n command: input.command,\n // An explicit cwd wins; otherwise the service's directory, anchored on\n // its project rather than on the server's launch directory.\n cwd: input.cwd ?? await resolveAgentCwd({ serviceId: input.processId }),\n commandId: input.commandId,\n },\n AGENT_LONG_FETCH_TIMEOUT,\n );\n await auditService.log({\n userId: 'local',\n action: 'executeAdHocCommand',\n entityType: 'process',\n entityId: input.processId,\n metadata: { agentId: input.agentId, command: input.command },\n });\n return result;\n }),\n\n /** Cancel a running shortcut command on an agent */\n cancelShortcut: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n processId: z.string().max(128),\n shortcutId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n await agentManager.agentMutation(input.agentId, 'process.cancelShortcut', { id: input.processId, shortcutId: input.shortcutId });\n return { success: true };\n }),\n\n /** Cancel a running ad-hoc command on an agent */\n cancelAdHocCommand: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n processId: z.string().max(128),\n commandId: z.string().max(128).optional(),\n }))\n .mutation(async ({ input }) => {\n await agentManager.agentMutation(input.agentId, 'process.cancelAdHocCommand', { id: input.processId, commandId: input.commandId });\n return { success: true };\n }),\n\n /** Get current metrics for a process from an agent */\n metrics: protectedProcedure\n .input(z.object({ agentId: z.string().max(128), processId: z.string().max(128) }))\n .query(async ({ input }) => {\n return agentManager.agentQuery<ProcessMetrics>(input.agentId, 'process.metrics', { id: input.processId });\n }),\n\n /**\n * Subscribe to real-time log stream for a process.\n * Forwards batched events from the AgentWSBridge in real-time.\n * Historical logs are fetched separately via process.logs query.\n */\n onLog: protectedProcedure\n .input(z.object({ agentId: z.string().max(128), processId: z.string().max(128) }))\n .subscription(async function* ({ input, ctx }) {\n requireServiceAction(ctx as AuthContext, input.processId, 'logs:read');\n yield* forwardLogBatches(input.agentId, input.processId);\n }),\n\n /**\n * Subscribe to real-time status changes for processes.\n * Input is optional — omit agentId/processId for global monitoring (dashboard).\n * Forwards events from the AgentWSBridge in real-time.\n */\n onStatus: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128).optional(),\n processId: z.string().max(128).optional(),\n }).optional())\n .subscription(async function* ({ input, ctx }) {\n const allowedIds = getAllowedServiceIds(ctx as AuthContext);\n if (input?.processId) requireServiceAction(ctx as AuthContext, input.processId, 'service:status');\n\n // Yield initial state\n try {\n const agents = agentManager.listAgents();\n for (const agent of agents.filter(a => a.status.connected)) {\n if (input?.agentId && agent.config.id !== input.agentId) continue;\n try {\n const processes = await agentManager.agentQuery<any[]>(agent.config.id, 'process.list');\n for (const proc of processes) {\n if (input?.processId && proc.id !== input.processId) continue;\n if (allowedIds && !allowedIds.has(proc.id)) continue;\n yield { ...proc, agentId: agent.config.id };\n }\n } catch {\n // Agent unreachable, skip\n }\n }\n } catch {\n // Ignore errors during initial load\n }\n\n yield* forwardEvents('process:status', (d) => {\n if (input?.agentId && d.agentId !== input.agentId) return false;\n if (input?.processId && d.processId !== input.processId) return false;\n if (allowedIds && !allowedIds.has(d.processId as string)) return false;\n return true;\n });\n }),\n\n /** Subscribe to real-time metrics for a process. */\n onMetrics: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128).optional(),\n processId: z.string().max(128).optional(),\n }).optional())\n .subscription(async function* ({ input, ctx }) {\n const allowedIds = getAllowedServiceIds(ctx as AuthContext);\n if (input?.processId) requireServiceAction(ctx as AuthContext, input.processId, 'service:status');\n\n yield* forwardEvents<ProcessMetrics>('process:metrics', (d) => {\n if (input?.agentId && d.agentId !== input.agentId) return false;\n if (input?.processId && d.processId !== input.processId) return false;\n if (allowedIds && !allowedIds.has(d.processId as string)) return false;\n return true;\n });\n }),\n\n /** Subscribe to real-time health status changes. */\n onHealth: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128).optional(),\n processId: z.string().max(128).optional(),\n }).optional())\n .subscription(async function* ({ input, ctx }) {\n const allowedIds = getAllowedServiceIds(ctx as AuthContext);\n if (input?.processId) requireServiceAction(ctx as AuthContext, input.processId, 'service:healthcheck');\n\n yield* forwardEvents('process:health', (d) => {\n if (input?.agentId && d.agentId !== input.agentId) return false;\n if (input?.processId && d.processId !== input.processId) return false;\n if (allowedIds && !allowedIds.has(d.processId as string)) return false;\n return true;\n });\n }),\n});\n","/**\n * Démarrer, arrêter, redémarrer un service — la logique, sans le transport.\n *\n * Extrait du routeur tRPC `process` parce qu'il n'en est plus le seul appelant :\n * l'icône de barre système pilote les mêmes services, et elle tourne DANS le\n * processus du serveur. Sans cette extraction, elle aurait dû soit recopier ces\n * enchaînements — déploiement paresseux, purge des logs, résolution de l'agent\n * effectif —, soit se forger un jeton pour s'appeler elle-même par tRPC. Le\n * premier duplique un comportement délicat ; le second ouvre une porte dans\n * l'authentification pour un appelant qui n'en a pas besoin.\n *\n * Ce qui reste au routeur : le contrôle des droits (`requireServiceAction`),\n * qui dépend de l'appelant et n'a aucun sens ici.\n */\nimport { TRPCError } from '@trpc/server';\nimport { AGENT_STOP_FETCH_TIMEOUT } from '@runeya/packages-shared';\nimport type { ProcessStatus, ServiceConfig } from '@runeya/packages-shared';\nimport { agentManager } from './agent-manager.js';\nimport { auditService } from './audit-service.js';\nimport { serviceStore } from './service-store.js';\nimport { projectStore } from './project-store.js';\nimport { environmentResolver } from './environment-resolver.js';\n// Dette connue, antérieure à ce fichier : ces deux aides vivent dans un\n// routeur alors qu'elles n'ont rien de transport. Les déplacer touche bien\n// plus que le sujet du jour ; l'import reste donc dirigé comme il l'était.\nimport { resolveServiceVariables, resolveEffectiveAgentId } from '../trpc/routers/service.js';\n\n/** Le résultat d'un geste : l'état rendu par l'agent, et lequel a répondu. */\nexport type ProcessControlResult = ProcessStatus & { agentId: string };\n\n/**\n * L'agent qui doit exécuter le geste.\n *\n * La configuration du service ou de l'environnement l'emporte toujours sur\n * l'agent passé par l'appelant, pour qu'un changement d'agent prenne effet\n * immédiatement.\n */\nasync function resolveTarget(\n processId: string,\n fallbackAgentId?: string | null,\n): Promise<{ agentId: string; service: ServiceConfig | null }> {\n // Lu une seule fois et transporté : le service sert ici ET au déploiement.\n const service = (await serviceStore.get(processId)) ?? null;\n const agentId = (service ? await resolveEffectiveAgentId(service) : null) ?? fallbackAgentId ?? null;\n if (!agentId) {\n throw new TRPCError({\n code: 'BAD_REQUEST',\n message: 'No agent assigned to this service. Set an agent on the service or on the active environment.',\n });\n }\n return { agentId, service };\n}\n\n/**\n * Un service ne démarre pas tant que son environnement a des trous.\n *\n * Le contrôle est fatal, contrairement au déploiement paresseux qui le suit :\n * une variable obligatoire vide ne produit pas un service dégradé mais un\n * service qui tombe plus loin, avec un message qui ne nomme jamais la variable.\n * Autant refuser ici, en la nommant.\n *\n * Un service hors projet, ou dans un projet sans environnement actif, n'a rien\n * à vérifier : il n'y a pas d'environnement pour porter une exigence.\n */\nasync function assertEnvironmentComplete(service: ServiceConfig | null): Promise<void> {\n if (!service) return;\n\n const project = await projectStore.ofService(service.id);\n if (!project?.activeEnvironmentId) return;\n\n const missing = await environmentResolver.findMissingForService({\n serviceId: service.id,\n activeEnvironmentId: project.activeEnvironmentId,\n });\n if (missing.length === 0) return;\n\n throw new TRPCError({\n code: 'PRECONDITION_FAILED',\n message: `Missing environment variables: ${missing.map((m) => m.key).join(', ')}`,\n cause: { missingVariables: missing, environmentId: project.activeEnvironmentId },\n });\n}\n\n/**\n * Déploiement paresseux : l'agent n'apprend un service qu'à son premier\n * démarrage. Idempotent, et volontairement non bloquant — un déploiement raté\n * ne doit pas empêcher d'essayer de démarrer.\n */\nasync function deployBefore(\n processId: string,\n agentId: string,\n service: ServiceConfig | null,\n step: 'start' | 'restart',\n): Promise<void> {\n if (service) {\n try {\n const resolved = await resolveServiceVariables(service);\n await agentManager.agentMutation(agentId, 'process.deploy', resolved);\n } catch (err) {\n console.debug(`[process-control] Failed to deploy before ${step} for`, processId + ':', (err as Error).message);\n }\n }\n\n if (service?.clearLogsOnStart) {\n try {\n await agentManager.agentMutation(agentId, 'process.clearLogBuffer', { id: processId });\n agentManager.emit('process:log', { agentId, batch: [{ processId, __clearLogBuffer: true }] });\n } catch (err) {\n console.debug(`[process-control] Failed to clear logs before ${step} for`, processId + ':', (err as Error).message);\n }\n }\n}\n\nexport async function startProcess(processId: string, fallbackAgentId?: string | null): Promise<ProcessControlResult> {\n const { agentId, service } = await resolveTarget(processId, fallbackAgentId);\n\n await assertEnvironmentComplete(service);\n\n await deployBefore(processId, agentId, service, 'start');\n\n let result: ProcessStatus;\n try {\n result = await agentManager.agentMutation<ProcessStatus>(agentId, 'process.start', { id: processId });\n } catch (err: unknown) {\n const err_ = err as { cause?: { code?: string }; message?: string; name?: string };\n const isFetchError = err_?.cause?.code === 'ECONNREFUSED' || err_?.message === 'fetch failed' || err_?.name === 'TypeError';\n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message: isFetchError ? `Cannot reach agent — make sure the agent is running` : (err_?.message ?? 'Failed to start process'),\n });\n }\n\n await auditService.log({ userId: 'local', action: 'start', entityType: 'process', entityId: processId, metadata: { agentId } });\n return { ...result, agentId };\n}\n\nexport async function stopProcess(processId: string, agentId: string): Promise<ProcessControlResult> {\n const result = await agentManager.agentMutation<ProcessStatus>(\n agentId,\n 'process.stop',\n { id: processId },\n AGENT_STOP_FETCH_TIMEOUT,\n );\n await auditService.log({ userId: 'local', action: 'stop', entityType: 'process', entityId: processId, metadata: { agentId } });\n return { ...result, agentId };\n}\n\n/**\n * Arrêt → redéploiement de la configuration à jour → démarrage, pour qu'un\n * changement de configuration ou de variable prenne effet.\n */\nexport async function restartProcess(processId: string, fallbackAgentId?: string | null): Promise<ProcessControlResult> {\n const { agentId, service } = await resolveTarget(processId, fallbackAgentId);\n\n await assertEnvironmentComplete(service);\n\n // L'arrêt est permissif : le process peut ne pas encore exister sur l'agent.\n try {\n await agentManager.agentMutation<{ success: true }>(agentId, 'process.stop', { id: processId }, AGENT_STOP_FETCH_TIMEOUT);\n } catch (err) {\n console.debug('[process-control] Stop before restart ignored (process not found on agent?):', (err as Error).message);\n }\n\n await deployBefore(processId, agentId, service, 'restart');\n\n const result = await agentManager.agentMutation<ProcessStatus>(agentId, 'process.start', { id: processId });\n await auditService.log({ userId: 'local', action: 'restart', entityType: 'process', entityId: processId, metadata: { agentId } });\n return { ...result, agentId };\n}\n\n/**\n * L'état de tous les process, tous agents connectés confondus.\n *\n * Les agents injoignables sont ignorés plutôt que fatals : un agent distant\n * éteint ne doit pas priver l'appelant de l'état des autres.\n */\nexport async function listAllProcesses(): Promise<ProcessControlResult[]> {\n const results: ProcessControlResult[] = [];\n\n await Promise.allSettled(\n agentManager\n .listAgents()\n .filter((a) => a.status.connected)\n .map(async (a) => {\n try {\n const processes = await agentManager.agentQuery<ProcessStatus[]>(a.config.id, 'process.list');\n for (const proc of processes) results.push({ ...proc, agentId: a.config.id });\n } catch {\n // Agent unreachable, skip\n }\n }),\n );\n\n return results;\n}\n","import { z } from 'zod';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { auditService } from '../../services/audit-service.js';\n\nexport const auditRouter = router({\n list: protectedProcedure\n .input(z.object({\n action: z.string().max(50).optional(),\n entityType: z.string().max(50).optional(),\n entityId: z.string().max(100).optional(),\n limit: z.number().int().positive().max(100).default(50),\n offset: z.number().int().nonnegative().default(0),\n }).optional())\n .query(async ({ input }) => {\n return auditService.list(input ?? {});\n }),\n});\n","import { z } from 'zod';\nimport { router, publicProcedure, protectedProcedure } from '../trpc.js';\nimport { hasEncryptionKey, setEncryptionKey, getEncryptionKey, isVaultLocked } from '../../utils/encryption-key.js';\nimport { listOrgVaults, readOrgNames, readOrgClouds, orgVaultRoot } from '../../services/vault-resolver.js';\nimport { readVerifyFile, matchesCanary } from '../../services/master-password.js';\nimport { getCloudApiUrl } from '../../services/cloud-api.js';\nimport { agentStore } from '../../services/agent-store.js';\nimport { apiKeyStore } from '../../services/api-key-store.js';\nimport { conversationStore } from '../../services/conversation-store.js';\nimport { environmentStore } from '../../services/environment-store.js';\nimport { agentSpawner } from '../../services/agent-spawner.js';\nimport { env } from '../../config/env.js';\nimport { cloudSessionStore } from '../../services/cloud-session-store.js';\n\nexport const setupRouter = router({\n /**\n * Check if encryption key is required (project initialized but no key).\n */\n needsEncryptionKey: publicProcedure.query(async () => {\n return {\n needsKey: !hasEncryptionKey(),\n };\n }),\n\n /**\n * Get current encryption key in hex format (for sharing with team).\n * Only available in local-simple mode for security.\n */\n getEncryptionKeyHex: protectedProcedure.query(async () => {\n if (env.MODE !== 'local-simple') {\n throw new Error('Encryption key export only available in local-simple mode');\n }\n\n const key = getEncryptionKey();\n if (!key) {\n throw new Error('No encryption key loaded');\n }\n\n return {\n keyHex: key.toString('hex'),\n };\n }),\n\n /**\n * Les clés des organisations suivies sur ce poste.\n *\n * Le pendant de l'adoption : celle-ci demande une clé, celle-là la donne. Sans\n * elle, un membre qui doit transmettre la clé de son organisation à un\n * collègue n'a nulle part où la lire — l'onglet Sécurité ne montrant que la\n * clé machine, qui n'est pas la même dès qu'une organisation a la sienne.\n *\n * `source` n'est pas décoratif. `getEncryptionKey(orgId)` retombe en silence\n * sur la clé machine pour un coffre sans clé propre ; rendre ce hex sans le\n * dire afficherait la clé machine sous l'étiquette « clé de l'organisation »,\n * soit exactement la confusion que cette route existe pour lever.\n */\n getOrgKeys: protectedProcedure.query(async () => {\n if (env.MODE !== 'local-simple') {\n throw new Error('Encryption key export only available in local-simple mode');\n }\n\n const machineKey = getEncryptionKey();\n const orgs = await listOrgVaults();\n // Le nom vient du tampon du coffre, pas du cloud : c'est ce qui le rend\n // lisible hors ligne, quand l'id seul ne dit plus rien.\n const names = await readOrgNames();\n // Le cloud d'où vient chaque coffre. `~/.runeya/orgs/` est global à la\n // machine : un poste qui a parlé à deux clouds — l'hébergé et un local de\n // développement — y mélange leurs organisations, et rien ne les distingue\n // sans ce tampon. Sans lui, le panneau présentait la clé d'une organisation\n // d'un autre cloud comme une clé à transmettre à un collègue.\n const clouds = await readOrgClouds();\n const currentCloud = getCloudApiUrl();\n // Les clouds où ce poste a un compte. « Étranger » veut dire « d'un cloud\n // dont je ne suis membre nulle part » : avec deux comptes sur deux clouds,\n // comparer au seul cloud configuré rangeait toutes les organisations du\n // second sous « un autre cloud », clé comprise.\n const ownCloudUrls = new Set([\n currentCloud,\n ...(await cloudSessionStore.list()).map((a) => a.cloudUrl.replace(/\\/+$/, '')),\n ]);\n // Ce que chaque coffre garde sans savoir le lire. Les stores le préservent\n // déjà sur le disque ; le compter ici est ce qui le rend visible, au lieu\n // d'un silence qui se lit comme « il n'y a rien ».\n const [unreadableConversations, unreadableSecrets] = await Promise.all([\n conversationStore.unreadableByVault(),\n environmentStore.unreadableByVault(),\n ]);\n\n return {\n // Le cloud de cette instance, dit explicitement : c'est l'étalon contre\n // lequel `foreign` est mesuré, et sans lui « un autre cloud » ne veut\n // rien dire pour qui lit.\n currentCloud,\n orgs: await Promise.all(orgs.map(async (orgId) => {\n const name = names[orgId] ?? null;\n // Un coffre sans tampon vient forcément d'ici : il a été écrit avant\n // que le tampon existe, donc par ce cloud-là.\n const cloudUrl = clouds[orgId] ?? currentCloud;\n const foreign = !ownCloudUrls.has(cloudUrl.replace(/\\/+$/, ''));\n const unreadable = {\n apiKeys: await apiKeyStore.unreadableCount(orgId),\n conversations: unreadableConversations.get(orgId) ?? 0,\n secrets: unreadableSecrets.get(orgId) ?? 0,\n };\n // Un coffre verrouillé a une clé propre que ce master password n'ouvre\n // pas : il n'y a rien à montrer, et le repli sur la clé machine serait\n // un mensonge.\n if (isVaultLocked(orgId)) {\n return { orgId, name, cloudUrl, foreign, keyHex: null, source: 'locked' as const, unreadable };\n }\n const key = getEncryptionKey(orgId);\n if (!key) return { orgId, name, cloudUrl, foreign, keyHex: null, source: 'locked' as const, unreadable };\n const isMachineKey = machineKey !== null && key.equals(machineKey);\n return {\n orgId,\n name,\n cloudUrl,\n foreign,\n keyHex: key.toString('hex'),\n source: isMachineKey ? ('machine' as const) : ('own' as const),\n unreadable,\n };\n })),\n };\n }),\n\n /**\n * Éprouver une clé contre le canari du coffre, sans passer par le cloud.\n *\n * `cloudSync.checkOrgKey` interroge le canari publié par l'organisation :\n * il prouve « cette clé est celle de l'organisation », mais il exige que le\n * cloud réponde et que l'organisation y existe encore. Un poste hors ligne —\n * ou qui reprend un coffre dont l'organisation a disparu côté cloud — n'avait\n * alors plus aucun moyen de vérifier une clé avant de l'adopter.\n *\n * Le coffre porte pourtant son propre canari, écrit en même temps que sa clé.\n * Attention à ce qu'il dit : il éprouve la clé COURANTE du coffre, donc il ne\n * répond « oui » que pour celle déjà en place — c'est-à-dire exactement le\n * cas où l'adoption n'a rien à faire, et qu'elle refuse. Le confondre avec\n * une validation de la clé à adopter rendait le parcours impossible : vert\n * quand le geste est inutile, rouge sinon.\n */\n checkOrgKeyLocal: protectedProcedure\n .input(z.object({\n orgId: z.string().min(1).max(128),\n keyHex: z.string().length(64).regex(/^[0-9a-f]+$/i, 'Invalid hex format'),\n }))\n .query(async ({ input }) => {\n const canary = await readVerifyFile(orgVaultRoot(input.orgId));\n // Sans canari local, rien à comparer : l'adoption reste possible, mais\n // elle ne peut pas être confirmée d'avance, et le dire vaut mieux que\n // laisser croire à une vérification qui n'a pas eu lieu.\n if (!canary) return { isCurrentKey: false, hasCanary: false };\n return {\n isCurrentKey: matchesCanary(canary, Buffer.from(input.keyHex, 'hex')),\n hasCanary: true,\n };\n }),\n\n /**\n * Submit and validate encryption key.\n * Attempts to decrypt existing data to validate the key.\n * Spawns the local agent if in local-simple mode.\n */\n submitEncryptionKey: publicProcedure\n .input(\n z.object({\n keyHex: z.string().length(64).regex(/^[0-9a-f]+$/i, 'Invalid hex format'),\n }),\n )\n .mutation(async ({ input }) => {\n try {\n // Set the key\n await setEncryptionKey(input.keyHex);\n\n // Validate by attempting to read encrypted data\n // If agents.json exists with encrypted data, this will decrypt it\n await agentStore.list();\n\n // Spawn the local agent now that the encryption key is available\n // (in local-simple mode, the agent couldn't spawn during server startup\n // because the key wasn't available yet)\n if (env.MODE === 'local-simple') {\n console.log('[setup] Encryption key validated, spawning local agent...');\n await agentSpawner.spawnLocalAgent();\n }\n\n return { success: true };\n } catch (err: unknown) {\n // If decryption fails, the key is invalid\n const message = err instanceof Error ? err.message : 'Unknown error';\n throw new Error(`Invalid encryption key: ${message}`);\n }\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { protectedProcedure, router, requireEnvAction, canEnvAction } from '../trpc.js';\nimport type { AuthContext } from '../trpc.js';\nimport { environmentStore } from '../../services/environment-store.js';\nimport { environmentOverridesStore } from '../../services/environment-overrides-store.js';\nimport { environmentResolver } from '../../services/environment-resolver.js';\nimport { projectStore } from '../../services/project-store.js';\nimport { serviceStore } from '../../services/service-store.js';\nimport { CreateEnvironmentSchema, UpdateEnvironmentSchema, VariableSchema, VariableOverrideSchema, MissingVariableReasonSchema } from '@runeya/packages-shared';\n\nexport const environmentRouter = router({\n list: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .query(async ({ input }) => {\n return await environmentStore.list(input.projectId, input.orgId);\n }),\n\n get: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .query(async ({ input }) => {\n const env = await environmentStore.get(input.id);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.id} not found` });\n return env;\n }),\n\n listByScope: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n scope: z.enum(['global', 'service']),\n }))\n .query(async ({ input }) => {\n return await environmentStore.listByScope(input.projectId, input.scope, input.orgId);\n }),\n\n findServiceEnvironment: protectedProcedure\n .input(z.object({ serviceId: z.string().max(128), globalEnvId: z.string().max(128) }))\n .query(async ({ input }) => {\n return await environmentStore.findServiceEnvironment(input.serviceId, input.globalEnvId);\n }),\n\n create: protectedProcedure\n // `orgId` accompagne le projet sans faire partie de l'environnement : il\n // dit dans quel coffre le poser quand l'id du projet répond pour plusieurs\n // organisations.\n .input(CreateEnvironmentSchema.extend({\n orgId: z.string().max(128).nullable().optional(),\n }))\n .mutation(async ({ input }) => {\n const { orgId, ...environment } = input;\n const target = { id: input.projectId, orgId };\n const env = await environmentStore.create(environment, orgId);\n\n // Add environment to project's environmentIds list\n const project = await projectStore.get(target);\n if (project && !project.environmentIds?.includes(env.id)) {\n await projectStore.addEnvironment(target, env.id);\n }\n\n // If creating a global env, auto-create service-scoped envs for each service in the project\n if (env.scope === 'global' && project) {\n for (const serviceId of project.serviceIds) {\n const service = await serviceStore.get(serviceId);\n if (!service) continue;\n // Include service-scoped envs from parent globals so inheritance chains work correctly\n const parentServiceEnvIds: string[] = [];\n for (const parentGlobalId of env.parentIds) {\n const parentServiceEnv = await environmentStore.findServiceEnvironment(serviceId, parentGlobalId);\n if (parentServiceEnv) {\n parentServiceEnvIds.push(parentServiceEnv.id);\n }\n }\n const svcEnv = await environmentStore.create({\n projectId: input.projectId,\n name: `${service.name} (${env.name})`,\n scope: 'service',\n reference: serviceId,\n activateOn: env.id,\n parentIds: [env.id, ...parentServiceEnvIds],\n variables: {},\n }, orgId);\n await projectStore.addEnvironment(target, svcEnv.id);\n }\n }\n\n return env;\n }),\n\n update: protectedProcedure\n .input(UpdateEnvironmentSchema)\n .mutation(async ({ input }) => {\n const existing = await environmentStore.get(input.id);\n if (!existing) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.id} not found` });\n\n const env = await environmentStore.update(input);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.id} not found` });\n\n // If a global environment was renamed, cascade to service-scoped environment names\n if (env.scope === 'global' && input.name && input.name !== existing.name) {\n // Le couple, déduit du coffre de l'environnement.\n const project = await projectStore.get(environmentStore.projectRefOf(env) ?? env.projectId);\n if (project) {\n const serviceNames = new Map<string, string>();\n for (const serviceId of project.serviceIds) {\n const service = await serviceStore.get(serviceId);\n if (service) serviceNames.set(serviceId, service.name);\n }\n await environmentStore.renameByActivateOn(env.id, input.name, serviceNames);\n }\n }\n\n return env;\n }),\n\n delete: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .mutation(async ({ input }) => {\n const env = await environmentStore.get(input.id);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.id} not found` });\n\n if (env.immutable) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Cannot delete immutable environment' });\n }\n\n // If deleting a global env, also delete all service-scoped envs that activateOn it\n if (env.scope === 'global') {\n await environmentStore.deleteByActivateOn(input.id);\n }\n\n const deleted = await environmentStore.delete(input.id);\n if (!deleted) throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Failed to delete environment' });\n\n // Remove environment from project\n await projectStore.removeEnvironment(environmentStore.projectRefOf(env) ?? env.projectId, input.id);\n\n return { success: true };\n }),\n\n resolve: protectedProcedure\n .input(z.object({ environmentId: z.string().max(128) }))\n .query(async ({ input, ctx }) => {\n const { includeSecrets } = requireEnvAction(ctx as AuthContext, input.environmentId, 'env:read');\n const env = await environmentStore.get(input.environmentId);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.environmentId} not found` });\n\n const resolved = await environmentResolver.resolveEnvironmentWithSources(input.environmentId);\n\n if (!includeSecrets) {\n // Strip secret values — replace with empty string to preserve variable shape\n const sanitized = { ...resolved };\n if (sanitized.variables) {\n sanitized.variables = Object.fromEntries(\n Object.entries(sanitized.variables).map(([id, v]) => [\n id,\n v.value?.isSecret ? { ...v, value: { ...v.value, value: '' } } : v,\n ]),\n );\n }\n return sanitized;\n }\n\n return resolved;\n }),\n\n resolveFlat: protectedProcedure\n .meta({ openapi: { method: 'GET', path: '/environments/{environmentId}/resolve-flat', tags: ['environments'], summary: 'Resolve environment variables as a flat key-value map', protect: true } })\n .input(z.object({ environmentId: z.string().max(128) }))\n .output(z.record(z.string(), z.string()))\n .query(async ({ input, ctx }) => {\n const { includeSecrets } = requireEnvAction(ctx as AuthContext, input.environmentId, 'env:read');\n const env = await environmentStore.get(input.environmentId);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.environmentId} not found` });\n\n const { env: resolved, envSecrets } = await environmentResolver.resolveEnvironment(input.environmentId);\n\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(resolved)) {\n if (!includeSecrets && envSecrets.includes(key)) {\n result[key] = '*****';\n } else {\n result[key] = value;\n }\n }\n return result;\n }),\n\n // --- Overrides (flat, by variableId) ---\n\n /**\n * Les variables qu'il reste à remplir sous un environnement : les siennes,\n * celles dont il hérite, et celles des environnements de service qui\n * s'activent avec lui.\n *\n * Aucune valeur n'en sort : uniquement les clés, leur description et le\n * motif. C'est ce que l'assistant de complétion affiche, et il n'a pas\n * besoin de connaître ce qui est déjà rempli ailleurs.\n */\n missingVariables: protectedProcedure\n .input(z.object({ environmentId: z.string().max(128) }))\n .query(async ({ input, ctx }) => {\n requireEnvAction(ctx as AuthContext, input.environmentId, 'env:read');\n const env = await environmentStore.get(input.environmentId);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.environmentId} not found` });\n\n const missing = await environmentResolver.findMissingForActiveEnvironment(input.environmentId);\n // Le contrôle d'entrée ne couvre que l'environnement demandé, alors que\n // le balayage remonte ses parents et descend dans ses environnements de\n // service. Chaque entrée est donc repassée au crible de son propre\n // environnement : pour l'app locale c'est toujours oui, pour une clé\n // bornée cela retire ce qu'elle n'a pas le droit de lire.\n return missing.filter((item) => canEnvAction(ctx as AuthContext, item.environmentId, 'env:read'));\n }),\n\n /**\n * Remplir une variable réclamée par l'assistant de complétion, sans toucher\n * au reste de sa définition.\n *\n * La destination dépend du motif, et c'est le serveur qui tranche parce que\n * lui seul a la définition sous les yeux :\n *\n * - `required` écrit une valeur **partagée** dans l'environnement qui définit\n * la variable, en préservant `pre`, `post` et tous ses drapeaux. Passer par\n * `upsertVariable` reviendrait à réécrire le slot entier depuis un client\n * qui n'en connaît qu'un morceau — un préfixe `postgres://` disparaîtrait.\n * - `overrideOnly` écrit une **surcharge machine**, qui ne quitte jamais ce\n * poste, en recopiant depuis la définition la forme (`pre`, `post`) et le\n * caractère secret que la surcharge ne porte pas d'elle-même.\n */\n fillVariable: protectedProcedure\n .input(z.object({\n environmentId: z.string().max(128),\n variableId: z.string().max(128),\n value: z.string().max(8192),\n reason: MissingVariableReasonSchema,\n }))\n .mutation(async ({ input, ctx }) => {\n requireEnvAction(ctx as AuthContext, input.environmentId, 'env:write');\n const env = await environmentStore.get(input.environmentId);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.environmentId} not found` });\n\n const variable = env.variables[input.variableId];\n if (!variable) throw new TRPCError({ code: 'NOT_FOUND', message: `Variable ${input.variableId} not found` });\n\n const slot = variable.value;\n if (input.reason === 'overrideOnly') {\n await environmentOverridesStore.setOverride(input.variableId, {\n value: { ...slot, value: input.value, required: false, overrideOnly: false },\n });\n return { success: true };\n }\n\n const result = await environmentStore.upsertVariable(input.environmentId, input.variableId, {\n ...variable,\n value: { ...slot, value: input.value },\n });\n if (!result) throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Failed to fill variable' });\n return { success: true };\n }),\n\n setOverride: protectedProcedure\n .input(z.object({\n variableId: z.string().max(128),\n // Only the value slot: the env var name comes from the variable\n // definition (a `key` sent by an older client is stripped here).\n variable: VariableOverrideSchema,\n }))\n .mutation(async ({ input }) => {\n await environmentOverridesStore.setOverride(input.variableId, input.variable);\n return { success: true };\n }),\n\n removeOverride: protectedProcedure\n .input(z.object({\n variableId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n await environmentOverridesStore.removeOverride(input.variableId);\n return { success: true };\n }),\n\n getOverrides: protectedProcedure\n .query(async () => {\n return await environmentOverridesStore.getAll();\n }),\n\n upsertVariable: protectedProcedure\n .meta({ openapi: { method: 'PUT', path: '/environments/{environmentId}/variables/{variableId}', tags: ['environments'], summary: 'Upsert a variable in an environment', protect: true } })\n .output(z.any())\n .input(z.object({\n environmentId: z.string().max(128),\n variableId: z.string().max(128),\n variable: VariableSchema,\n }))\n .mutation(async ({ input, ctx }) => {\n requireEnvAction(ctx as AuthContext, input.environmentId, 'env:write');\n const env = await environmentStore.get(input.environmentId);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.environmentId} not found` });\n const result = await environmentStore.upsertVariable(input.environmentId, input.variableId, input.variable);\n if (!result) throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Failed to update variable' });\n return result;\n }),\n\n /**\n * List everywhere a variable key is used inside a project: environments that\n * define it, and variables that reference it through {{environment.KEY}}.\n * Used by the UI to warn before editing a shared variable from a resolved view.\n */\n keyUsages: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n key: z.string().min(1).max(256),\n /** Environment holding the variable about to be edited — enables inherited-impact detection */\n environmentId: z.string().max(128).optional(),\n }))\n .query(async ({ input }) => {\n const environments = await environmentStore.list(input.projectId, input.orgId);\n const services = await serviceStore.list();\n const serviceName = (id?: string) => services.find(s => s.id === id)?.name;\n\n // Escape the key before embedding it in a regexp — it is user input.\n const escaped = input.key.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n // nosemgrep: detect-non-literal-regexp -- la clé est échappée juste au-dessus ; le motif reste linéaire (pas de quantificateur imbriqué)\n const refPattern = new RegExp(`\\\\{\\\\{environment\\\\.${escaped}\\\\}\\\\}`);\n\n const definedIn: Array<{ environmentId: string; environmentName: string; scope: string; serviceName?: string }> = [];\n const referencedBy: Array<{ environmentId: string; environmentName: string; scope: string; serviceName?: string; key: string }> = [];\n\n for (const env of environments) {\n const name = serviceName(env.reference);\n for (const variable of Object.values(env.variables ?? {})) {\n if (variable.key === input.key) {\n definedIn.push({\n environmentId: env.id,\n environmentName: env.name,\n scope: env.scope ?? 'global',\n ...(name ? { serviceName: name } : {}),\n });\n continue;\n }\n const slot = variable.value;\n if (refPattern.test(`${slot.pre}${slot.value}${slot.post}`)) {\n referencedBy.push({\n environmentId: env.id,\n environmentName: env.name,\n scope: env.scope ?? 'global',\n ...(name ? { serviceName: name } : {}),\n key: variable.key,\n });\n }\n }\n }\n\n // Indirect impact: environments that receive the variable through the\n // inheritance chain. We ask the resolver rather than re-deriving the\n // rules, so explicit parents, implicit service-ancestor inheritance and\n // dedup-by-key shadowing are all accounted for by construction.\n const inheritedBy: Array<{ environmentId: string; environmentName: string; scope: string; serviceName?: string }> = [];\n if (input.environmentId) {\n for (const env of environments) {\n if (env.id === input.environmentId) continue;\n try {\n const resolved = await environmentResolver.resolveEnvironmentWithSources(env.id);\n const inherits = Object.entries(resolved.variables).some(\n ([varId, variable]) =>\n variable.key === input.key\n && resolved.sources[varId]?.environmentId === input.environmentId,\n );\n if (inherits) {\n const name = serviceName(env.reference);\n inheritedBy.push({\n environmentId: env.id,\n environmentName: env.name,\n scope: env.scope ?? 'global',\n ...(name ? { serviceName: name } : {}),\n });\n }\n } catch {\n // Unresolvable environment (e.g. circular chain) — skip it\n }\n }\n }\n\n return { definedIn, referencedBy, inheritedBy };\n }),\n\n removeVariable: protectedProcedure\n .input(z.object({\n environmentId: z.string().max(128),\n variableId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n const env = await environmentStore.get(input.environmentId);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.environmentId} not found` });\n const result = await environmentStore.removeVariable(input.environmentId, input.variableId);\n if (!result) throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Failed to remove variable' });\n return result;\n }),\n});\n","import { promises as dns } from 'node:dns';\nimport { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { JSLogParserSchema, type JSLogParserDef, NotificationPreferencesSchema, SettingsSchema, nativeParsers, AIProviderSchema, type AIProvider, JSLogParser } from '@runeya/packages-shared';\nimport { settingsManager } from '../../services/settings-manager.js';\nimport { logParserStore } from '../../services/log-parser-store.js';\nimport { vaultOfProject } from '../../services/settings-scope.js';\nimport { env } from '../../config/env.js';\nimport { machineRoot } from '../../services/vault-resolver.js';\nimport { encryptValue, decryptValue, stableEncryptValue } from '../../services/crypto-helpers.js';\nimport { traefikManager } from '../../services/traefik-manager.js';\nimport { agentStore } from '../../services/agent-store.js';\nimport { agentManager } from '../../services/agent-manager.js';\nimport { TraefikConfigSchema } from '@runeya/packages-shared';\nimport { resolveWorkspaceCwd } from '../../services/workspace-cwd.js';\nimport { networkInfo, setLanMode } from '../../services/lan-mode.js';\nimport { companionDefaultPrompt } from '../../services/companion.js';\n\nconst NotificationPreferencesPatchSchema = NotificationPreferencesSchema.partial().strict();\n\n/**\n * Les parseurs tels qu'un écran les reçoit : les natifs de l'application, puis\n * ceux du coffre, chacun disant d'où il vient.\n *\n * L'origine n'est pas stockée — elle se déduit de l'endroit d'où la liste a été\n * lue — mais elle voyage, parce que modifier un parseur d'organisation change\n * le code qui tourne chez tous ses membres, et que l'écran doit pouvoir le dire.\n */\nfunction listWithOrigin(parsers: JSLogParserDef[], vault: string | undefined) {\n return [\n ...nativeParsers.map((p) => ({ ...p, origin: 'native' as const })),\n ...parsers.map((p) => ({ ...p, origin: vault ? ('org' as const) : ('machine' as const) })),\n ];\n}\n\nfunction maskApiKey(plaintext: string): string {\n if (plaintext.length <= 8) return '****';\n return plaintext.slice(0, 4) + '****' + plaintext.slice(-4);\n}\n\n/**\n * De quelle organisation on lit — ou écrit — les réglages.\n *\n * Les fournisseurs d'IA et les préférences de notification appartiennent à\n * l'organisation dont ils décrivent le travail, pas au poste. L'appelant dit\n * laquelle : soit directement, soit par le projet concerné, dont l'organisation\n * se déduit. Absent des deux, ce sont les réglages du poste — ceux d'une\n * machine qui ne travaille pour aucune organisation.\n */\nconst ScopeShape = {\n orgId: z.string().max(128).nullable().optional(),\n projectId: z.string().max(128).optional(),\n};\n\nasync function scopeOf(input?: { orgId?: string | null; projectId?: string }): Promise<string | undefined> {\n return input?.orgId ?? await vaultOfProject(input?.projectId);\n}\n\nexport const settingsRouter = router({\n /**\n * Get all settings\n */\n get: protectedProcedure.query(async () => {\n const settings = await settingsManager.getSettings();\n return settings;\n }),\n\n /**\n * Paths the server is running from (working directory + data directory).\n * Read-only, purely informational for the settings UI.\n */\n getPaths: protectedProcedure.query(async () => ({\n // The launch directory, not the process's current one — they are the same\n // today only because nothing calls chdir, which is exactly what must not be\n // relied on.\n cwd: await resolveWorkspaceCwd({}),\n dataDir: env.DATA_DIR,\n // Where cloud projects live: their vaults belong to the machine, not to\n // whichever directory the server happened to be started in.\n machineDir: machineRoot(),\n })),\n\n /**\n * Où le serveur écoute, et s'il est joignable depuis le réseau local.\n */\n getNetwork: protectedProcedure.query(() => networkInfo()),\n\n /**\n * Exposer — ou retirer — Runeya du réseau local, sans redémarrage.\n *\n * La socket d'écoute est rouverte sur place : les connexions en cours, dont\n * celle de l'onglet qui bascule, ne sont pas coupées. Le choix est mémorisé\n * dans les réglages, donc conservé au prochain démarrage.\n */\n setLanMode: protectedProcedure\n .input(z.object({ enabled: z.boolean() }))\n .mutation(async ({ input }) => {\n try {\n return await setLanMode(input.enabled);\n } catch (err) {\n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message: `Impossible de changer l'adresse d'écoute : ${(err as Error).message}`,\n });\n }\n }),\n\n /**\n * Update settings (mode, cloudUrl)\n */\n update: protectedProcedure\n .input(SettingsSchema.pick({ mode: true, cloudUrl: true, globalDocsPath: true }).partial())\n .mutation(async ({ input }) => {\n const current = await settingsManager.getSettings();\n const updated = {\n ...current,\n ...input,\n };\n await settingsManager.saveSettings(updated);\n return updated;\n }),\n\n /**\n * Get notification preferences\n */\n getNotificationPreferences: protectedProcedure\n .input(z.object(ScopeShape).optional())\n .query(async ({ input }) => {\n const priv = await settingsManager.getPrivateSettings(await scopeOf(input));\n return NotificationPreferencesSchema.parse(priv.notifications ?? {});\n }),\n\n /**\n * Update notification preferences (granular mute)\n */\n updateNotificationPreferences: protectedProcedure\n .input(NotificationPreferencesPatchSchema.extend(ScopeShape))\n .mutation(async ({ input }) => {\n const vault = await scopeOf(input);\n const priv = await settingsManager.getPrivateSettings(vault);\n const currentPrefs = NotificationPreferencesSchema.parse(priv.notifications ?? {});\n const updatedPrefs = {\n ...currentPrefs,\n ...input,\n };\n await settingsManager.savePrivateSettings({\n ...priv,\n notifications: updatedPrefs,\n }, vault);\n return updatedPrefs;\n }),\n\n /**\n * List all parsers\n *\n * Les natifs, puis ceux du coffre visé. L'origine accompagne chacun : un\n * parseur d'organisation se modifie pour toute l'équipe, et l'interface doit\n * pouvoir le dire avant que quelqu'un le change sans le savoir.\n */\n listParsers: protectedProcedure\n .input(z.object(ScopeShape).optional())\n .query(async ({ input }) => {\n const vault = await scopeOf(input);\n return listWithOrigin(await logParserStore.list(vault), vault);\n }),\n\n /**\n * Les parseurs du coffre visé, à chaque fois qu'ils changent.\n *\n * Les services arrivent en temps réel, et un parseur écrit par un collègue\n * atteint le disque tout aussi vite ; sans ce flux, seul l'écran resterait en\n * retard — affichant une liste dans laquelle le parseur qu'un service vient\n * de référencer n'existe pas encore.\n */\n onParsersChanged: protectedProcedure\n .input(z.object(ScopeShape).optional())\n .subscription(async function* ({ input, signal }) {\n const vault = await scopeOf(input);\n let pending = true;\n let wake: (() => void) | null = null;\n\n const off = logParserStore.onChanged((touched) => {\n // Un autre coffre ne regarde pas cet écran.\n if (touched !== vault) return;\n pending = true;\n if (wake) { wake(); wake = null; }\n });\n\n // Sans ce réveil, un client parti pendant l'attente laisserait le\n // générateur suspendu pour toujours — l'abandon ne franchit pas un\n // `await`, donc le désabonnement ci-dessous n'arriverait jamais.\n const onAbort = () => { if (wake) { wake(); wake = null; } };\n signal?.addEventListener('abort', onAbort);\n\n try {\n while (!signal?.aborted) {\n if (pending) {\n pending = false;\n // La même liste que `listParsers`, natifs compris : un abonné\n // remplace ce qu'il a reçu, et rendre moins ici ferait disparaître\n // les natifs de l'écran au premier changement.\n yield listWithOrigin(await logParserStore.list(vault), vault);\n } else {\n await new Promise<void>((resolve) => { wake = resolve; });\n }\n }\n } finally {\n off();\n signal?.removeEventListener('abort', onAbort);\n }\n }),\n\n /**\n * Get single parser by ID\n */\n getParser: protectedProcedure\n .input(z.object({ id: z.string().max(128), ...ScopeShape }))\n .query(async ({ input }) => {\n const parser = await logParserStore.get(input.id, await scopeOf(input));\n if (!parser) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Parser not found: ${input.id}` });\n }\n return parser;\n }),\n\n /**\n * Create new parser\n */\n createParser: protectedProcedure\n .input(\n JSLogParserSchema.omit({\n id: true,\n createdAt: true,\n updatedAt: true,\n }).extend(ScopeShape)\n )\n .mutation(async ({ input }) => {\n const { orgId, projectId, ...fields } = input;\n // Basic code validation (schema already validated forbiden patterns)\n if (!fields.code.trim()) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Parser code cannot be empty' });\n }\n return logParserStore.create(fields, await scopeOf({ orgId, projectId }));\n }),\n\n /**\n * Update existing parser\n */\n updateParser: protectedProcedure\n .input(\n JSLogParserSchema.omit({\n createdAt: true,\n updatedAt: true,\n }).partial()\n .required({ id: true })\n .extend(ScopeShape)\n )\n .mutation(async ({ input }) => {\n const { id, orgId, projectId, ...patch } = input;\n if (id.startsWith('native:')) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Cannot modify built-in parsers' });\n }\n if (patch.code !== undefined && !patch.code.trim()) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Parser code cannot be empty' });\n }\n const updated = await logParserStore.update(id, patch, await scopeOf({ orgId, projectId }));\n if (!updated) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Parser not found: ${id}` });\n }\n return updated;\n }),\n\n /**\n * Delete parser by ID\n */\n deleteParser: protectedProcedure\n .input(z.object({ id: z.string().max(128), ...ScopeShape }))\n .mutation(async ({ input }) => {\n if (input.id.startsWith('native:')) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Cannot delete built-in parsers' });\n }\n const deleted = await logParserStore.delete(input.id, await scopeOf(input));\n if (!deleted) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Parser not found: ${input.id}` });\n }\n return { deleted: true };\n }),\n\n // ---------------------------------------------------------------------------\n // AI Providers\n // ---------------------------------------------------------------------------\n\n // ---------------------------------------------------------------------------\n // Compagnon de relecture\n // ---------------------------------------------------------------------------\n\n /*\n * Réglages du POSTE, sans portée d'organisation (§9).\n *\n * Ils décrivent comment cette machine fait travailler ses agents. Rangés dans\n * un coffre d'organisation, un même poste aurait autant de compagnons que\n * d'organisations regardées — et le réglage changerait sous les yeux de\n * l'utilisateur au gré du projet ouvert.\n */\n getCompanionSettings: protectedProcedure\n .query(async () => {\n const settings = await settingsManager.getSettings();\n const c = settings.companion ?? { enabledByDefault: false };\n return {\n enabledByDefault: c.enabledByDefault ?? false,\n prompt: c.prompt ?? '',\n /**\n * Conservé dans la réponse pour ne pas casser un client déjà construit,\n * mais l'écran n'en fait plus un texte à modifier : le réglage ajoute\n * seulement des spécificités aux consignes Runeya.\n */\n defaultPrompt: companionDefaultPrompt(),\n };\n }),\n\n setCompanionSettings: protectedProcedure\n .input(z.object({\n enabledByDefault: z.boolean().optional(),\n // Rejeté au-delà, jamais tronqué : un prompt coupé produirait des\n // relectures incohérentes sans rien signaler.\n prompt: z.string().max(20_000).optional(),\n }))\n .mutation(async ({ input }) => {\n const settings = await settingsManager.getSettings();\n const current = settings.companion ?? { enabledByDefault: false };\n const prompt = input.prompt?.trim();\n await settingsManager.saveSettings({\n ...settings,\n companion: {\n enabledByDefault: input.enabledByDefault ?? current.enabledByDefault ?? false,\n // Vide = « celles de Runeya » : on efface le réglage plutôt que d'y\n // ranger une chaîne vide qui signifierait « aucune consigne ».\n ...(input.prompt === undefined\n ? (current.prompt ? { prompt: current.prompt } : {})\n : (prompt ? { prompt } : {})),\n },\n });\n return { ok: true };\n }),\n\n /**\n * List AI providers (API keys are masked)\n */\n listAIProviders: protectedProcedure\n .input(z.object(ScopeShape).optional())\n .query(async ({ input }) => {\n const vault = await scopeOf(input);\n const priv = await settingsManager.getPrivateSettings(vault);\n return (priv.aiProviders ?? []).map((p: AIProvider) => {\n let maskedKey = '(aucune)';\n if (p.encryptedApiKey) {\n try {\n maskedKey = maskApiKey(decryptValue(p.encryptedApiKey, vault));\n } catch { maskedKey = '(clé invalide)'; }\n }\n return { id: p.id, name: p.name, provider: p.provider, model: p.model, active: p.active, maskedKey, createdAt: p.createdAt, updatedAt: p.updatedAt };\n });\n }),\n\n /**\n * Create AI provider\n */\n createAIProvider: protectedProcedure\n .input(z.object({\n name: z.string().min(1).max(200),\n provider: AIProviderSchema.shape.provider,\n apiKey: z.string().max(500).optional(), // optional for providers like Ollama\n model: z.string().max(200).optional(),\n ...ScopeShape,\n }))\n .mutation(async ({ input }) => {\n if (input.provider !== 'ollama' && !input.apiKey?.trim()) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Une clé API est requise pour ce provider.' });\n }\n const vault = await scopeOf(input);\n const priv = await settingsManager.getPrivateSettings(vault);\n const id = `aiprovider-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;\n const now = new Date();\n const plainKey = input.apiKey ?? '';\n const newProvider: AIProvider = {\n id,\n name: input.name,\n provider: input.provider,\n // Chiffrée par la clé de l'organisation : c'est ce qui permet de\n // partager le fournisseur qu'elle paie sans partager la clé du poste.\n encryptedApiKey: plainKey ? encryptValue(plainKey, vault) : '',\n model: input.model,\n active: (priv.aiProviders ?? []).length === 0, // first one is active by default\n createdAt: now,\n updatedAt: now,\n };\n await settingsManager.savePrivateSettings({\n ...priv,\n aiProviders: [...(priv.aiProviders ?? []), newProvider],\n }, vault);\n return { ...newProvider, maskedKey: plainKey ? maskApiKey(plainKey) : '(aucune)', encryptedApiKey: undefined };\n }),\n\n /**\n * Update AI provider (apiKey optional — omit to keep existing)\n */\n updateAIProvider: protectedProcedure\n .input(z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200).optional(),\n provider: AIProviderSchema.shape.provider.optional(),\n apiKey: z.string().min(1).max(500).optional(),\n model: z.string().max(200).optional(),\n ...ScopeShape,\n }))\n .mutation(async ({ input }) => {\n const vault = await scopeOf(input);\n const priv = await settingsManager.getPrivateSettings(vault);\n const providers = priv.aiProviders ?? [];\n const idx = providers.findIndex((p: AIProvider) => p.id === input.id);\n if (idx === -1) throw new TRPCError({ code: 'NOT_FOUND', message: `AI provider not found: ${input.id}` });\n const existing = providers[idx];\n const encryptedApiKey = input.apiKey\n ? stableEncryptValue(input.apiKey, existing.encryptedApiKey, vault)\n : existing.encryptedApiKey;\n const updated: AIProvider = {\n ...existing,\n ...(input.name ? { name: input.name } : {}),\n ...(input.provider ? { provider: input.provider } : {}),\n ...(input.model !== undefined ? { model: input.model || undefined } : {}),\n encryptedApiKey,\n updatedAt: new Date(),\n };\n const newProviders = [...providers];\n newProviders[idx] = updated;\n await settingsManager.savePrivateSettings({ ...priv, aiProviders: newProviders }, vault);\n let maskedKey = '(aucune)';\n if (updated.encryptedApiKey) {\n try { maskedKey = maskApiKey(decryptValue(updated.encryptedApiKey, vault)); } catch { /* */ }\n }\n return { ...updated, maskedKey, encryptedApiKey: undefined };\n }),\n\n /**\n * Delete AI provider\n */\n deleteAIProvider: protectedProcedure\n .input(z.object({ id: z.string().min(1).max(128), ...ScopeShape }))\n .mutation(async ({ input }) => {\n const vault = await scopeOf(input);\n const priv = await settingsManager.getPrivateSettings(vault);\n const providers = priv.aiProviders ?? [];\n const filtered = providers.filter((p: AIProvider) => p.id !== input.id);\n if (filtered.length === providers.length) throw new TRPCError({ code: 'NOT_FOUND', message: `AI provider not found: ${input.id}` });\n // If deleted was active, promote first remaining to active\n const deletedWasActive = providers.find((p: AIProvider) => p.id === input.id)?.active ?? false;\n if (deletedWasActive && filtered.length > 0) filtered[0].active = true;\n await settingsManager.savePrivateSettings({ ...priv, aiProviders: filtered }, vault);\n return { deleted: true };\n }),\n\n /**\n * Set one provider as active (clears active flag on all others)\n */\n setActiveAIProvider: protectedProcedure\n .input(z.object({ id: z.string().min(1).max(128), ...ScopeShape }))\n .mutation(async ({ input }) => {\n const vault = await scopeOf(input);\n const priv = await settingsManager.getPrivateSettings(vault);\n const providers = priv.aiProviders ?? [];\n const idx = providers.findIndex((p: AIProvider) => p.id === input.id);\n if (idx === -1) throw new TRPCError({ code: 'NOT_FOUND', message: `AI provider not found: ${input.id}` });\n const updated = providers.map((p: AIProvider) => ({ ...p, active: p.id === input.id }));\n await settingsManager.savePrivateSettings({ ...priv, aiProviders: updated }, vault);\n return { id: input.id, active: true };\n }),\n\n // ---------------------------------------------------------------------------\n // Traefik config\n // ---------------------------------------------------------------------------\n\n /**\n * Get Traefik config for a specific agent (never returns credentials or cert key in plain text)\n */\n getAgentTraefikConfig: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .query(async ({ input }) => {\n const raw = agentStore.getTraefikConfig(input.agentId);\n const parsed = raw ? TraefikConfigSchema.safeParse(raw) : null;\n const config = parsed?.success ? parsed.data : null;\n return {\n enabled: config?.enabled ?? false,\n acmeEmail: config?.acmeEmail,\n wildcardDomain: config?.wildcardDomain,\n httpPort: config?.httpPort ?? 80,\n httpsPort: config?.httpsPort ?? 443,\n dnsProvider: config?.dnsProvider,\n hasDnsCredentials: Object.keys(config?.dnsCredentials ?? {}).length > 0,\n dnsCredentialKeys: Object.keys(config?.dnsCredentials ?? {}),\n hasCert: !!config?.encryptedCert,\n acmeStaging: config?.acmeStaging ?? false,\n };\n }),\n\n /**\n * Update Traefik config for a specific agent (credentials are encrypted before saving)\n */\n updateAgentTraefikConfig: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n enabled: z.boolean().optional(),\n acmeEmail: z.string().email().max(256).optional(),\n wildcardDomain: z.string().max(253).optional(),\n httpPort: z.number().int().min(1).max(65535).optional(),\n httpsPort: z.number().int().min(1).max(65535).optional(),\n dnsProvider: z.string().max(64).optional(),\n dnsCredentials: z.record(z.string().max(64), z.string().max(2048)).optional(),\n acmeStaging: z.boolean().optional(),\n }))\n .mutation(async ({ input }) => {\n const { agentId, ...fields } = input;\n const raw = agentStore.getTraefikConfig(agentId);\n const parsed = raw ? TraefikConfigSchema.safeParse(raw) : null;\n const existing = parsed?.success ? parsed.data : { enabled: false, dnsCredentials: {}, httpPort: 80, httpsPort: 443 };\n\n const encryptedCredentials = fields.dnsCredentials\n ? traefikManager.encryptDnsCredentials(fields.dnsCredentials)\n : existing.dnsCredentials;\n\n const updated = {\n ...existing,\n ...(fields.enabled !== undefined && { enabled: fields.enabled }),\n ...(fields.acmeEmail !== undefined && { acmeEmail: fields.acmeEmail }),\n ...(fields.wildcardDomain !== undefined && { wildcardDomain: fields.wildcardDomain }),\n ...(fields.httpPort !== undefined && { httpPort: fields.httpPort }),\n ...(fields.httpsPort !== undefined && { httpsPort: fields.httpsPort }),\n ...(fields.dnsProvider !== undefined && { dnsProvider: fields.dnsProvider }),\n ...(fields.acmeStaging !== undefined && { acmeStaging: fields.acmeStaging }),\n dnsCredentials: encryptedCredentials,\n };\n\n await agentStore.saveTraefikConfig(agentId, updated);\n\n // Déchiffrer les credentials avant push à l'agent\n const configToPush = {\n ...updated,\n dnsCredentials: traefikManager.decryptDnsCredentials(updated.dnsCredentials ?? {}),\n };\n // Push to connected agent\n await agentManager.pushTraefikConfig(agentId, configToPush);\n\n return { success: true };\n }),\n\n /**\n * Get Traefik config files content for a specific agent\n */\n getAgentTraefikConfigFiles: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .query(async ({ input }) => {\n return agentManager.agentQuery<{ static: string; dynamic: string }>(\n input.agentId,\n 'config.getTraefikConfigFiles',\n );\n }),\n\n getAgentTraefikFileTree: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .query(async ({ input }) => {\n return agentManager.agentQuery<Array<{ path: string; content: string }>>(\n input.agentId,\n 'config.getTraefikFileTree',\n );\n }),\n\n /**\n * Get Traefik container logs for a specific agent (snapshot)\n */\n getAgentTraefikLogs: protectedProcedure\n .input(z.object({ agentId: z.string().max(128), lines: z.number().int().min(1).max(500).default(100) }))\n .query(async ({ input }) => {\n const result = await agentManager.agentQuery<{ logs: string }>(\n input.agentId,\n 'config.getTraefikLogs',\n { lines: input.lines },\n );\n return result;\n }),\n\n /**\n * Stream Traefik logs in real-time (subscription, yields new lines every 500ms)\n */\n streamAgentTraefikLogs: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .subscription(async function* ({ input, signal }) {\n let seen = 0;\n while (!signal?.aborted) {\n try {\n const result = await agentManager.agentQuery<{ logs: string }>(\n input.agentId,\n 'config.getTraefikLogs',\n { lines: 500 },\n );\n const lines = result.logs?.trim() ? result.logs.split('\\n') : [];\n if (lines.length > seen) {\n const newLines = lines.slice(seen);\n seen = lines.length;\n yield { lines: newLines };\n }\n } catch {\n // agent not reachable yet — wait and retry\n }\n await new Promise(resolve => setTimeout(resolve, 500));\n }\n }),\n\n /**\n * Restart Traefik container on a specific agent (re-pushes config first to handle agent restarts)\n */\n restartAgentTraefik: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .mutation(async ({ input }) => {\n const raw = agentStore.getTraefikConfig(input.agentId);\n const parsed = raw ? TraefikConfigSchema.safeParse(raw) : null;\n const config = parsed?.success ? parsed.data : null;\n if (!config?.enabled) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Traefik non activé sur cet agent' });\n const decrypted = { ...config, dnsCredentials: traefikManager.decryptDnsCredentials(config.dnsCredentials ?? {}) };\n await agentManager.agentMutation(input.agentId, 'config.initTraefikConfig', decrypted, 5000);\n await agentManager.agentMutation(input.agentId, 'config.restartTraefik', undefined, 30000);\n return { success: true };\n }),\n\n /**\n * Force certificate renewal for a specific agent (wipes acme.json + restarts container)\n */\n renewAgentTraefikCert: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .mutation(async ({ input }) => {\n const raw = agentStore.getTraefikConfig(input.agentId);\n const parsed = raw ? TraefikConfigSchema.safeParse(raw) : null;\n const config = parsed?.success ? parsed.data : null;\n if (!config?.enabled) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Traefik non activé sur cet agent' });\n const decrypted = { ...config, dnsCredentials: traefikManager.decryptDnsCredentials(config.dnsCredentials ?? {}) };\n await agentManager.agentMutation(input.agentId, 'config.initTraefikConfig', decrypted, 5000);\n await agentManager.agentMutation(input.agentId, 'config.renewTraefikCert', undefined, 30000);\n return { success: true };\n }),\n\n /**\n * Validate Traefik configuration for a specific agent\n */\n validateAgentTraefikConfig: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .query(async ({ input }) => {\n const raw = agentStore.getTraefikConfig(input.agentId);\n const parsed = raw ? TraefikConfigSchema.safeParse(raw) : null;\n const config = parsed?.success ? parsed.data : null;\n\n const checks: Array<{ id: string; ok: boolean; message: string }> = [];\n\n // Config completeness checks (server-side)\n checks.push({\n id: 'enabled',\n ok: config?.enabled === true,\n message: config?.enabled ? 'Traefik activé' : 'Traefik non activé',\n });\n checks.push({\n id: 'domain',\n ok: !!config?.wildcardDomain?.trim(),\n message: config?.wildcardDomain ? `Domaine : ${config.wildcardDomain}` : 'Domaine wildcard non configuré',\n });\n checks.push({\n id: 'email',\n ok: !!config?.acmeEmail?.trim(),\n message: config?.acmeEmail ? `Email ACME : ${config.acmeEmail}` : 'Email ACME non configuré',\n });\n checks.push({\n id: 'dns_provider',\n ok: !!config?.dnsProvider?.trim(),\n message: config?.dnsProvider ? `Provider DNS : ${config.dnsProvider}` : 'Provider DNS non configuré',\n });\n checks.push({\n id: 'credentials',\n ok: Object.keys(config?.dnsCredentials ?? {}).length > 0,\n message: Object.keys(config?.dnsCredentials ?? {}).length > 0\n ? `${Object.keys(config!.dnsCredentials!).length} variable(s) configurée(s)`\n : 'Variables d\\'environnement DNS manquantes',\n });\n\n // DNS resolution check — only proceed if domain contains valid hostname characters.\n if (config?.wildcardDomain?.trim()) {\n const sanitisedDomain = config.wildcardDomain.replace(/^\\*\\./, '').replace(/[^a-z0-9.-]/gi, '');\n const probe = `probe.${sanitisedDomain}`;\n try {\n const addresses = await dns.resolve4(probe);\n const pointsToLocalhost = addresses.some(a => a === '127.0.0.1');\n checks.push({\n id: 'dns_resolution',\n ok: pointsToLocalhost,\n message: pointsToLocalhost\n ? `${probe} → 127.0.0.1 ✓`\n : `${probe} résout vers ${addresses.join(', ')} (attendu : 127.0.0.1)`,\n });\n } catch {\n checks.push({\n id: 'dns_resolution',\n ok: false,\n message: `${probe} ne résout pas — vérifiez le DNS wildcard`,\n });\n }\n }\n\n // Agent-side checks (Docker, container status)\n let agentChecks: Array<{ id: string; ok: boolean; message: string }> = [];\n try {\n const status = await agentManager.agentQuery<{\n containerRunning: boolean;\n dockerAvailable: boolean;\n configFileExists: boolean;\n cert: { hasCert: boolean; domain: string | null; expiresAt: string | null; daysLeft: number | null; expired: boolean };\n }>(input.agentId, 'config.getTraefikStatus');\n agentChecks.push({\n id: 'docker',\n ok: status.dockerAvailable,\n message: status.dockerAvailable ? 'Docker disponible' : 'Docker non trouvé dans PATH',\n });\n agentChecks.push({\n id: 'container',\n ok: status.containerRunning,\n message: status.containerRunning ? 'Container Traefik en cours d\\'exécution' : 'Container Traefik arrêté',\n });\n agentChecks.push({\n id: 'config_file',\n ok: status.configFileExists,\n message: status.configFileExists ? 'Fichier de configuration présent' : 'Fichier traefik.yml absent (enregistrez la config)',\n });\n const c = status.cert;\n if (c.hasCert && !c.expired) {\n agentChecks.push({\n id: 'ssl_cert',\n ok: true,\n message: `Certificat SSL valide pour ${c.domain} — expire dans ${c.daysLeft} jour(s) (${c.expiresAt})`,\n });\n } else if (c.hasCert && c.expired) {\n agentChecks.push({\n id: 'ssl_cert',\n ok: false,\n message: `Certificat SSL expiré pour ${c.domain} (depuis ${c.expiresAt})`,\n });\n } else {\n agentChecks.push({\n id: 'ssl_cert',\n ok: false,\n message: c.domain\n ? `Aucun certificat SSL pour ${c.domain} — Traefik doit être actif pour déclencher le challenge DNS-01`\n : 'Aucun certificat SSL trouvé dans acme.json',\n });\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const isNotFound = msg.includes('not found') || msg.includes('not connected');\n agentChecks.push({\n id: 'agent_reachable',\n ok: false,\n message: isNotFound\n ? `Agent non connecté au serveur (id: ${input.agentId})`\n : `Agent non joignable — ${msg}`,\n });\n }\n\n return { checks: [...checks, ...agentChecks] };\n }),\n\n /**\n * Test parser code: compile and run it against sample logs, return per-line results\n */\n testParser: protectedProcedure\n .input(\n z.object({\n code: z.string().max(50000),\n sampleLogs: z\n .array(\n z.object({\n raw: z.string().max(16384),\n stream: z.enum(['stdout', 'stderr']),\n })\n )\n .max(100)\n .default([]),\n })\n )\n .mutation(async ({ input }) => {\n // Compile via shared JSLogParser (same implementation as the agent)\n let jsParser: JSLogParser;\n try {\n jsParser = new JSLogParser([{\n id: 'preview',\n name: 'preview',\n code: input.code,\n enabled: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n }]);\n } catch (err) {\n throw new TRPCError({\n code: 'BAD_REQUEST',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n\n let idCounter = 0;\n const results = input.sampleLogs.map((log) => {\n const inputLine = {\n raw: log.raw,\n stream: log.stream as 'stdout' | 'stderr',\n level: 'info' as const,\n message: log.raw,\n hidden: false,\n metadata: {} as Record<string, unknown>,\n };\n\n try {\n const output = jsParser.parse({ ...inputLine });\n const logCard = output.json\n ? { id: `sim-${++idCounter}`, type: 'json', header: output.jsonHeader ?? 'JSON', state: 'self' as const, collapsable: true }\n : undefined;\n return { input: inputLine, output: { ...output, logCard }, error: null };\n } catch (err) {\n return { input: inputLine, output: null, error: err instanceof Error ? err.message : String(err) };\n }\n });\n\n return { validated: true, results };\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { execFile, spawn } from 'node:child_process';\nimport { stat } from 'node:fs/promises';\nimport { resolve, join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { SUPPORTED_EDITORS, EDITOR_BY_KEY } from '@runeya/packages-shared';\nimport { resolveCliInvocation, whichCommand } from '@runeya/packages-shared/node';\nimport { userConfigManager } from '../../services/user-config-manager.js';\nimport { serviceStore } from '../../services/service-store.js';\nimport { resolveWorkspaceCwd } from '../../services/workspace-cwd.js';\n\nfunction resolveCwd(cwd: string): string {\n const withHome = cwd.replace(/^~(\\/|$)/, `${homedir()}$1`);\n return withHome.replace(/\\$\\{(\\w+)\\}|\\$(\\w+)/g, (match, braced, plain) => {\n const name = braced ?? plain;\n return process.env[name] ?? match;\n });\n}\n\nasync function getServiceCwd(serviceId: string): Promise<string> {\n const services = await serviceStore.list();\n const service = services.find((s) => s.id === serviceId);\n if (!service) {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'Service not found' });\n }\n // Anchored on the project the service belongs to, rather than on whatever\n // directory the server was launched in.\n return resolveCwd(await resolveWorkspaceCwd({ serviceId }));\n}\n\nasync function isCommandAvailable(command: string): Promise<boolean> {\n return new Promise((resolve) => {\n execFile(whichCommand(), [command], { timeout: 5_000, windowsHide: true }, (err) => {\n resolve(!err);\n });\n });\n}\n\nexport const editorRouter = router({\n listAvailable: protectedProcedure.query(async () => {\n const results = await Promise.all(\n SUPPORTED_EDITORS.map(async (editor) => ({\n ...editor,\n installed: await isCommandAvailable(editor.command),\n })),\n );\n return results;\n }),\n\n getPreferences: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .query(async ({ input }) => {\n return userConfigManager.getEditorPreferences({ id: input.projectId, orgId: input.orgId });\n }),\n\n setDefault: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n editorKey: z.string().max(64),\n }))\n .mutation(async ({ input }) => {\n if (!EDITOR_BY_KEY.has(input.editorKey)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: `Unknown editor: ${input.editorKey}` });\n }\n await userConfigManager.setEditorPreference(\n { id: input.projectId, orgId: input.orgId }, 'default', input.editorKey,\n );\n return { success: true };\n }),\n\n setServiceEditor: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n serviceId: z.string().max(128),\n editorKey: z.string().max(64),\n }))\n .mutation(async ({ input }) => {\n if (!EDITOR_BY_KEY.has(input.editorKey)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: `Unknown editor: ${input.editorKey}` });\n }\n await userConfigManager.setEditorPreference(\n { id: input.projectId, orgId: input.orgId }, input.serviceId, input.editorKey,\n );\n return { success: true };\n }),\n\n removeServiceEditor: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n serviceId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n await userConfigManager.removeEditorPreference(\n { id: input.projectId, orgId: input.orgId }, input.serviceId,\n );\n return { success: true };\n }),\n\n open: protectedProcedure\n .input(z.object({\n editorKey: z.string().max(64),\n path: z.string().max(4096),\n }))\n .mutation(async ({ input }) => {\n const editor = EDITOR_BY_KEY.get(input.editorKey);\n if (!editor) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: `Unknown editor: ${input.editorKey}` });\n }\n\n // Expand ~ and $VAR/${VAR} from process.env, then resolve relative paths\n const expanded = input.path\n .replace(/^~(\\/|$)/, `${process.env['HOME'] ?? '/tmp'}$1`)\n .replace(/\\$\\{(\\w+)\\}|\\$(\\w+)/g, (_, a, b) => process.env[a || b] ?? '');\n const resolvedPath = resolve(expanded || '.');\n\n // Validate path exists (directory or file)\n try {\n await stat(resolvedPath);\n } catch (err) {\n if (err instanceof TRPCError) throw err;\n throw new TRPCError({ code: 'BAD_REQUEST', message: `Path does not exist: ${resolvedPath}` });\n }\n\n // Windows : `code`, `cursor` & co sont des shims `.cmd` — inchangé sur POSIX.\n const invocation = resolveCliInvocation(editor.command, [resolvedPath]);\n const child = spawn(invocation.command, invocation.args, {\n shell: false,\n detached: true,\n stdio: 'ignore',\n windowsHide: true,\n });\n child.unref();\n\n return { success: true };\n }),\n\n openFile: protectedProcedure\n .input(z.object({\n editorKey: z.string().max(64),\n serviceId: z.string().max(128),\n relativePath: z.string().max(4096),\n }))\n .mutation(async ({ input }) => {\n const editor = EDITOR_BY_KEY.get(input.editorKey);\n if (!editor) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: `Unknown editor: ${input.editorKey}` });\n }\n\n const cwd = await getServiceCwd(input.serviceId);\n const filePath = join(cwd, input.relativePath);\n\n // Prevent path traversal\n if (!filePath.startsWith(cwd)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Path traversal not allowed' });\n }\n\n try {\n await stat(filePath);\n } catch {\n throw new TRPCError({ code: 'BAD_REQUEST', message: `File does not exist: ${filePath}` });\n }\n\n // Windows : `code`, `cursor` & co sont des shims `.cmd` — inchangé sur POSIX.\n const invocation = resolveCliInvocation(editor.command, [filePath]);\n const child = spawn(invocation.command, invocation.args, {\n shell: false,\n detached: true,\n stdio: 'ignore',\n windowsHide: true,\n });\n child.unref();\n\n return { success: true };\n }),\n});\n","import { readFile, writeFile, rename, mkdir, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { z } from 'zod';\nimport { projectKey, type ProjectRef } from './project-key.js';\n\nconst CONFIG_DIR = join(homedir(), '.runeya');\nconst CONFIG_FILE = 'runeya.conf';\n\nconst EditorPreferencesSchema = z.object({\n default: z.string().max(64).optional(),\n}).catchall(z.string().max(64))\n .refine((obj) => Object.keys(obj).length <= 500, 'Too many editor preferences');\n\nconst ProjectSettingsSchema = z.object({\n settings: z.object({\n editors: EditorPreferencesSchema.optional(),\n }).optional(),\n});\n\nconst UserConfigSchema = z.record(\n z.string().max(128),\n ProjectSettingsSchema,\n).refine((obj) => Object.keys(obj).length <= 100, 'Too many projects in config');\n\ntype UserConfig = z.infer<typeof UserConfigSchema>;\n\n/**\n * Les préférences sont rangées par projet, et un projet est désigné par le\n * couple (organisation, projet) : deux projets de même id, dans deux\n * organisations, partageaient sinon les mêmes préférences d'éditeur. Les\n * entrées écrites par une version antérieure (id nu) sont encore lues.\n */\nfunction configKey(ref: ProjectRef): string {\n return projectKey(ref);\n}\n\nclass UserConfigManager {\n private config: UserConfig | null = null;\n\n private async ensureDir(): Promise<void> {\n await mkdir(CONFIG_DIR, { recursive: true });\n }\n\n private async atomicWrite(data: unknown): Promise<void> {\n await this.ensureDir();\n const filePath = join(CONFIG_DIR, CONFIG_FILE);\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 async getConfig(): Promise<UserConfig> {\n if (!this.config) {\n try {\n const raw = await readFile(join(CONFIG_DIR, CONFIG_FILE), 'utf-8');\n const parsed = UserConfigSchema.safeParse(JSON.parse(raw));\n this.config = parsed.success ? parsed.data : {};\n } catch {\n this.config = {};\n }\n }\n return this.config;\n }\n\n async saveConfig(config: UserConfig): Promise<void> {\n this.config = config;\n await this.atomicWrite(config);\n }\n\n async getEditorPreferences(ref: ProjectRef): Promise<Record<string, string>> {\n const config = await this.getConfig();\n return config[configKey(ref)]?.settings?.editors ?? config[ref.id]?.settings?.editors ?? {};\n }\n\n async setEditorPreference(ref: ProjectRef, target: string, editorKey: string): Promise<void> {\n const config = await this.getConfig();\n const key = configKey(ref);\n if (!config[key]) config[key] = { settings: config[ref.id]?.settings };\n if (!config[key].settings) config[key].settings = {};\n if (!config[key].settings!.editors) config[key].settings!.editors = {};\n config[key].settings!.editors![target] = editorKey;\n await this.saveConfig(config);\n }\n\n async removeEditorPreference(ref: ProjectRef, target: string): Promise<void> {\n const config = await this.getConfig();\n const editors = config[configKey(ref)]?.settings?.editors;\n if (editors && target in editors) {\n delete editors[target];\n await this.saveConfig(config);\n }\n }\n}\n\nexport const userConfigManager = new UserConfigManager();\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport { protectedProcedure, router } from '../trpc.js';\nimport { apiKeyStore, maskApiKey } from '../../services/api-key-store.js';\nimport { ApiKeyScopeSchema } from '@runeya/packages-shared';\nimport { resolveWorkspaceCwd } from '../../services/workspace-cwd.js';\n\nconst ALLOWED_SKILL_PATHS = new Set([\n '.claude/skills/runeya/SKILL.md',\n '.cursor/rules/runeya.mdc',\n '.windsurf/rules/runeya.md',\n]);\n\nconst KeyInputSchema = z.object({\n name: z.string().min(1).max(200),\n scopes: ApiKeyScopeSchema,\n isPublic: z.boolean().default(false),\n});\n\nexport const apiKeysRouter = router({\n list: protectedProcedure\n .query(() => apiKeyStore.list()),\n\n create: protectedProcedure\n // `orgId` n'est ajouté qu'à la création : changer de propriétaire déplace la\n // clé d'un coffre à l'autre, ce qui n'est pas une modification comme une\n // autre et mérite sa propre opération.\n .input(KeyInputSchema.extend({ orgId: z.string().min(1).max(128).nullable().optional() }))\n .mutation(({ input }) =>\n apiKeyStore.create(input.name, input.scopes, input.isPublic, input.orgId ?? null),\n ),\n\n /**\n * Renvoie le secret d'une seule clé, sur demande explicite. `list` ne le\n * contient pas : une clé ne doit jamais être re-servie en masse.\n */\n reveal: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .query(async ({ input }) => {\n const key = await apiKeyStore.reveal(input.id);\n if (!key) throw new TRPCError({ code: 'NOT_FOUND', message: 'API key not found' });\n return { key };\n }),\n\n update: protectedProcedure\n .input(KeyInputSchema.extend({ id: z.string().max(128) }))\n .mutation(async ({ input }) => {\n const updated = await apiKeyStore.update(input.id, input.name, input.scopes, input.isPublic);\n if (!updated) throw new TRPCError({ code: 'NOT_FOUND', message: 'API key not found' });\n // Un renommage n'est pas une raison de re-révéler le secret.\n return maskApiKey(updated);\n }),\n\n remove: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .mutation(async ({ input }) => {\n const removed = await apiKeyStore.remove(input.id);\n if (!removed) throw new TRPCError({ code: 'NOT_FOUND', message: 'API key not found' });\n return { success: true };\n }),\n\n renewKey: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .mutation(async ({ input }) => {\n const renewed = await apiKeyStore.renewKey(input.id);\n if (!renewed) throw new TRPCError({ code: 'NOT_FOUND', message: 'API key not found' });\n return renewed;\n }),\n\n writeSkillFile: protectedProcedure\n .input(z.object({\n relativePath: z.string().max(256),\n content: z.string().max(32768),\n }))\n .mutation(async ({ input }) => {\n if (!ALLOWED_SKILL_PATHS.has(input.relativePath)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Chemin non autorisé' });\n }\n // The launch directory, taken from the vault rather than from the process:\n // a skill file must land where Runeya was started, whatever the process's\n // own directory happens to be.\n const abs = join(await resolveWorkspaceCwd({}), input.relativePath);\n await mkdir(dirname(abs), { recursive: true });\n await writeFile(abs, input.content, { encoding: 'utf-8', mode: 0o644 });\n return { path: input.relativePath };\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport Anthropic from '@anthropic-ai/sdk';\nimport OpenAI from 'openai';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { serviceStore } from '../../services/service-store.js';\nimport { resolveWorkspaceCwd, resolveAgentCwd } from '../../services/workspace-cwd.js';\nimport { agentManager } from '../../services/agent-manager.js';\nimport { getActiveProvider, DEFAULT_MODELS, OPENAI_COMPAT_BASE_URLS } from '../../services/ai-provider-utils.js';\nimport { vaultOfProject } from '../../services/settings-scope.js';\nimport { resolveEffectiveAgentId } from './service.js';\nimport { OptionalProviderIdSchema } from '../shared-schemas.js';\n\nconst SERVICE_ID_SCHEMA = z.string().max(128);\nconst SAFE_PATH_SCHEMA = z\n .string()\n .min(1)\n .max(4096)\n .refine((p) => !p.startsWith('/') && !p.includes('../'), {\n message: 'Path must be relative and not traverse up',\n });\nconst REMOTE_SCHEMA = z.string().min(1).max(128).regex(/^[a-zA-Z0-9_\\-.]+$/);\nconst BRANCH_SCHEMA = z.string().min(1).max(256).regex(/^[a-zA-Z0-9._\\-/]+$/);\n\n/**\n * Resolve the effective agentId and absolute cwd for a service.\n * Throws if service not found or no agent is configured.\n */\nasync function resolveServiceContext(serviceId: string): Promise<{ agentId: string; cwd: string }> {\n const service = await serviceStore.get(serviceId);\n if (!service) {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'Service not found' });\n }\n const agentId = await resolveEffectiveAgentId(service);\n if (!agentId) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'No agent configured for this service' });\n }\n // Anchored on the project when the service's cwd is relative; a `~`/`$VAR`\n // cwd comes back untouched, since only the agent can expand it.\n return { agentId, cwd: await resolveWorkspaceCwd({ serviceId }) };\n}\n\n// Shared input shape: a git target is EITHER a service (serviceId) OR an agent's\n// own repository (agentId → cwd '.'). The latter lets the AI chat reuse this\n// view against the agent's working directory when no service is attached.\nconst gitTargetShape = {\n serviceId: SERVICE_ID_SCHEMA.optional(),\n agentId: z.string().max(128).optional(),\n /** Anchors on a project when no service is targeted (e.g. from the AI chat). */\n projectId: z.string().max(128).optional(),\n /** Son organisation : un id de projet seul peut en nommer un par organisation. */\n orgId: z.string().max(128).nullable().optional(),\n};\n\n/**\n * Resolve the effective agentId + cwd from a git target. Prefers serviceId when\n * present; otherwise targets the agent's own working directory (cwd '.').\n */\nasync function resolveGitContext(input: {\n serviceId?: string; agentId?: string; projectId?: string; orgId?: string | null;\n}): Promise<{ agentId: string; cwd: string }> {\n if (input.serviceId) return resolveServiceContext(input.serviceId);\n // No service: target an agent's own working directory (cwd '.'). Fall back to\n // the default agent when no explicit agentId is given (e.g. a chat conversation\n // that let the server pick the agent).\n const agentId = input.agentId ?? agentManager.getDefaultAgentId();\n if (!agentId) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'No agent available' });\n }\n // A project anchors the target. Without one, '.' — the AGENT's own directory,\n // which it resolves itself and which may not be on this machine at all.\n const cwd = await resolveAgentCwd({ projectId: input.projectId, orgId: input.orgId }) ?? '.';\n return { agentId, cwd };\n}\n\nexport const gitRouter = router({\n /** Get full git status */\n status: protectedProcedure\n .input(z.object({ ...gitTargetShape }))\n .query(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentQuery(agentId, 'git.status', { cwd });\n }),\n\n /** Get commit log */\n log: protectedProcedure\n .input(z.object({ ...gitTargetShape,limit: z.number().int().min(1).max(200).default(50) }))\n .query(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentQuery(agentId, 'git.log', { cwd, limit: input.limit });\n }),\n\n /** List local and remote branches */\n branches: protectedProcedure\n .input(z.object({ ...gitTargetShape }))\n .query(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentQuery(agentId, 'git.branches', { cwd });\n }),\n\n /** Checkout a branch */\n checkout: protectedProcedure\n .input(z.object({ ...gitTargetShape,branch: BRANCH_SCHEMA, create: z.boolean().default(false) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.checkout', { cwd, branch: input.branch, create: input.create });\n }),\n\n /** Stage files */\n stage: protectedProcedure\n .input(z.object({ ...gitTargetShape,paths: z.array(SAFE_PATH_SCHEMA).min(1).max(500) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.stage', { cwd, paths: input.paths });\n }),\n\n /** Stage all files */\n stageAll: protectedProcedure\n .input(z.object({ ...gitTargetShape }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.stageAll', { cwd });\n }),\n\n /** Unstage files */\n unstage: protectedProcedure\n .input(z.object({ ...gitTargetShape,paths: z.array(SAFE_PATH_SCHEMA).min(1).max(500) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.unstage', { cwd, paths: input.paths });\n }),\n\n /** Unstage all files */\n unstageAll: protectedProcedure\n .input(z.object({ ...gitTargetShape }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.unstageAll', { cwd });\n }),\n\n /** Commit staged changes */\n commit: protectedProcedure\n .input(z.object({ ...gitTargetShape,message: z.string().min(1).max(4096) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.commit', { cwd, message: input.message });\n }),\n\n /** Push to remote */\n push: protectedProcedure\n .input(z.object({ ...gitTargetShape,remote: REMOTE_SCHEMA.default('origin'), setUpstream: z.boolean().default(false) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.push', { cwd, remote: input.remote, setUpstream: input.setUpstream });\n }),\n\n /** Pull from remote */\n pull: protectedProcedure\n .input(z.object({ ...gitTargetShape,remote: REMOTE_SCHEMA.default('origin') }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.pull', { cwd, remote: input.remote });\n }),\n\n /** Fetch from remote */\n fetch: protectedProcedure\n .input(z.object({ ...gitTargetShape,remote: REMOTE_SCHEMA.default('origin') }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.fetch', { cwd, remote: input.remote });\n }),\n\n /** Get diff for a file or the whole index */\n diff: protectedProcedure\n .input(z.object({\n ...gitTargetShape,\n path: z.string().max(4096).optional(),\n staged: z.boolean().default(false),\n untracked: z.boolean().default(false),\n }))\n .query(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentQuery(agentId, 'git.diff', { cwd, path: input.path, staged: input.staged, untracked: input.untracked });\n }),\n\n /** Discard changes to working tree files */\n discard: protectedProcedure\n .input(z.object({ ...gitTargetShape,paths: z.array(SAFE_PATH_SCHEMA).min(1).max(500) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.discard', { cwd, paths: input.paths });\n }),\n\n /** Generate a commit message from staged diffs using AI (diff fetched from agent, AI runs on server) */\n generateCommitMessage: protectedProcedure\n .input(z.object({ ...gitTargetShape, providerId: OptionalProviderIdSchema, model: z.string().max(200).optional() }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n const { diff } = await agentManager.agentQuery<{ diff: string }>(agentId, 'git.stagedDiff', { cwd });\n\n if (!diff.trim()) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'No staged changes to generate a commit message from' });\n }\n\n // Falls back to the default (active) provider when the caller doesn't pick one.\n // Les fournisseurs sont ceux de l'organisation du projet visé : l'appel\n // porte déjà le couple, il n'y a rien à deviner.\n const active = await getActiveProvider(\n input.providerId,\n input.orgId ?? await vaultOfProject(input.projectId),\n );\n if (!active) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'No AI provider configured' });\n }\n\n const systemPrompt = `You are a git commit message generator. Given a git diff, write a concise and meaningful conventional commit message (e.g. feat:, fix:, refactor:, chore:, docs:, style:, test:).\nRules:\n- First line: type(optional scope): short summary (max 72 chars)\n- Optionally add a blank line and a brief body if the changes are complex\n- Write in English\n- Return ONLY the commit message, nothing else`;\n\n const { provider, plaintextKey } = active;\n const model = input.model || provider.model || DEFAULT_MODELS[provider.provider] || 'claude-opus-4-6';\n\n if (provider.provider === 'anthropic') {\n const client = new Anthropic({ apiKey: plaintextKey });\n const res = await client.messages.create({\n model,\n max_tokens: 512,\n system: systemPrompt,\n messages: [{ role: 'user', content: diff }],\n });\n const block = res.content[0];\n return { message: block?.type === 'text' ? block.text.trim() : '' };\n }\n\n if (provider.provider in OPENAI_COMPAT_BASE_URLS) {\n const baseURL = OPENAI_COMPAT_BASE_URLS[provider.provider]!;\n const client = new OpenAI({ apiKey: plaintextKey || 'ollama', baseURL });\n const res = await client.chat.completions.create({\n model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: diff },\n ],\n });\n return { message: res.choices[0]?.message?.content?.trim() ?? '' };\n }\n\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Unsupported AI provider' });\n }),\n\n /** Merge a branch into the current branch */\n merge: protectedProcedure\n .input(z.object({ ...gitTargetShape,branch: BRANCH_SCHEMA, noFf: z.boolean().default(false) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.merge', { cwd, branch: input.branch, noFf: input.noFf });\n }),\n\n /** Rebase current branch onto another branch */\n rebase: protectedProcedure\n .input(z.object({ ...gitTargetShape,branch: BRANCH_SCHEMA }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.rebase', { cwd, branch: input.branch });\n }),\n\n /** List stash entries */\n stashList: protectedProcedure\n .input(z.object({ ...gitTargetShape }))\n .query(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentQuery(agentId, 'git.stashList', { cwd });\n }),\n\n /** Stash current changes */\n stashPush: protectedProcedure\n .input(z.object({ ...gitTargetShape,message: z.string().max(4096).optional(), includeUntracked: z.boolean().default(true) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.stashPush', { cwd, message: input.message, includeUntracked: input.includeUntracked });\n }),\n\n /** Pop a stash entry */\n stashPop: protectedProcedure\n .input(z.object({ ...gitTargetShape,index: z.number().int().min(0).max(1000).default(0) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.stashPop', { cwd, index: input.index });\n }),\n\n /** Apply a stash entry without dropping it */\n stashApply: protectedProcedure\n .input(z.object({ ...gitTargetShape,index: z.number().int().min(0).max(1000).default(0) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.stashApply', { cwd, index: input.index });\n }),\n\n /** Drop a stash entry */\n stashDrop: protectedProcedure\n .input(z.object({ ...gitTargetShape,index: z.number().int().min(0).max(1000).default(0) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.stashDrop', { cwd, index: input.index });\n }),\n\n /** Watch .git/ for changes and stream updated status */\n onStatusChange: protectedProcedure\n .input(z.object({ ...gitTargetShape }))\n .subscription(async function* ({ input }) {\n const { agentId, cwd } = await resolveGitContext(input);\n\n const queue: unknown[] = [];\n let resolve: (() => void) | null = null;\n let done = false;\n\n let unsubscribe: (() => void) | undefined;\n try {\n unsubscribe = agentManager.agentSubscribe(\n agentId,\n 'git.onStatusChange',\n { cwd },\n (data) => {\n queue.push(data);\n if (resolve) { resolve(); resolve = null; }\n },\n () => {\n done = true;\n if (resolve) { resolve(); resolve = null; }\n },\n );\n } catch (err) {\n throw new TRPCError({\n code: 'BAD_REQUEST',\n message: `Cannot subscribe to git status: ${(err as Error).message}`,\n });\n }\n\n try {\n while (!done || queue.length > 0) {\n if (queue.length > 0) {\n yield queue.shift()!;\n } else {\n await new Promise<void>((r) => { resolve = r; });\n }\n }\n } finally {\n unsubscribe?.();\n }\n }),\n\n /** List remotes */\n remotes: protectedProcedure\n .input(z.object({ ...gitTargetShape }))\n .query(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentQuery(agentId, 'git.remotes', { cwd });\n }),\n});\n","import { randomUUID } from 'node:crypto';\nimport { TRPCError } from '@trpc/server';\nimport { z } from 'zod';\nimport { ScenarioNodeSchema, ScenarioGroupSchema } from '@runeya/packages-shared';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { createOrBadRequest, deleteOrNotFound, getOrNotFound, updateOrThrow } from '../crud-procedure-utils.js';\nimport { streamWithActiveProvider } from '../ai-generation-procedure-utils.js';\nimport {\n ConversationIdSchema,\n DescriptionSchema,\n Id128Schema,\n NameSchema,\n OptionalProviderIdSchema,\n} from '../shared-schemas.js';\nimport { vaultOfProject } from '../../services/settings-scope.js';\nimport { scenarioStore } from '../../services/scenario-store.js';\nimport { scenarioRunStore } from '../../services/scenario-run-store.js';\nimport { runScenario, tapBus, isScenarioRunning, abortScenario, resolveNodeInput } from '../../services/scenario-runner.js';\nimport { listPresets, getPreset } from '../../services/scenario-presets.js';\n\n// ─── AI generation helpers ────────────────────────────────────────────────────\n\nconst SCENARIO_SYSTEM_PROMPT = `You are an scenario org-chart builder assistant. You generate JSON structures representing an scenario hierarchy.\n\nIMPORTANT: Respond with ONLY a valid JSON object. No markdown, no code fences, no explanation. Pure JSON only.\n\nOutput schema:\n{\n \"leaderId\": \"string — id of the leader node\",\n \"groups\": [{ \"id\": \"string\", \"name\": \"string\", \"position\": { \"x\": number, \"y\": number }, \"width\": number, \"height\": number }],\n \"nodes\": [{ \"id\": \"string\", \"label\": \"string\", \"role\": \"manager|engineer|designer|analyst|qa|devops|product|writer|researcher|other\", \"groupId\": \"string (must match a group id)\", \"parentId\": \"string|null (null only for the leader)\", \"prompt\": \"string — detailed role description and instructions for this AI agent\", \"autoGenerated\": true, \"canAddNode\": false, \"position\": { \"x\": number, \"y\": number } }]\n}\n\nRules:\n- Every node MUST have a groupId that references an existing group id.\n- Exactly one node is the leader: parentId=null, their id = leaderId.\n- All other nodes MUST have parentId set to their manager's id.\n- The leader MUST always be in the group with id \"group-management\" and name \"Management\".\n- The leader MUST always have role \"manager\".\n- Use role to reflect each node's actual function: managers coordinate and delegate (never implement), engineers write code, etc.\n- Use short readable ids: \"group-engineering\", \"node-alice\", etc.\n- Groups: position spaced 400px apart (e.g. x=0, x=400, x=800). width >= 300, height >= 200.\n- Nodes positions are relative to their group: x/y in 30-260 range.\n- The \"prompt\" field must be detailed: role, responsibilities, communication style, expected outputs.`;\n\nfunction buildScenarioUserMessage(\n userPrompt: string,\n current?: { leaderId: string; groups: unknown[]; nodes: unknown[] },\n): string {\n if (current && (current.groups.length > 0 || current.nodes.length > 0)) {\n return `Current scenario:\\n${JSON.stringify(current, null, 2)}\\n\\nUser request: ${userPrompt}\\n\\nModify the scenario. Keep existing ids when possible.`;\n }\n return `Generate an scenario org-chart based on: ${userPrompt}`;\n}\n\n/**\n * L'organisation dont on lit — ou écrit — les scénarios : ils décrivent ses\n * services. Donnée directement, ou déduite du projet concerné. Absente des\n * deux, ce sont ceux du poste.\n */\nconst ScopeShape = {\n orgId: z.string().max(128).nullable().optional(),\n projectId: Id128Schema.optional(),\n};\n\nasync function scopeOf(input?: { orgId?: string | null; projectId?: string }): Promise<string | undefined> {\n return input?.orgId ?? await vaultOfProject(input?.projectId);\n}\n\nexport const scenarioRouter = router({\n list: protectedProcedure\n .input(z.object(ScopeShape).optional())\n .query(async ({ input }) => scenarioStore.list(await scopeOf(input))),\n\n get: protectedProcedure\n .input(z.object({ id: Id128Schema, ...ScopeShape }))\n .query(async ({ input }) => getOrNotFound(\n async () => scenarioStore.get(input.id, await scopeOf(input)),\n 'Scenario not found',\n )),\n\n create: protectedProcedure\n .input(z.object({\n name: NameSchema,\n icon: z.string().max(64).optional(),\n description: DescriptionSchema.optional(),\n leaderId: Id128Schema,\n groups: z.array(ScenarioGroupSchema).max(100).optional(),\n nodes: z.array(ScenarioNodeSchema).min(1).max(500),\n traversalMode: z.enum(['hierarchical', 'topological']).optional(),\n presetId: z.string().max(128).optional(),\n isPublished: z.boolean().optional(),\n ...ScopeShape,\n }))\n .mutation(({ input }) => {\n const now = Date.now();\n return createOrBadRequest(async () => scenarioStore.create({\n id: randomUUID(),\n name: input.name,\n icon: input.icon,\n description: input.description,\n leaderId: input.leaderId,\n groups: input.groups ?? [],\n nodes: input.nodes,\n traversalMode: input.traversalMode ?? 'hierarchical',\n presetId: input.presetId,\n isPublished: input.isPublished ?? false,\n createdAt: now,\n updatedAt: now,\n }));\n }),\n\n update: protectedProcedure\n .input(z.object({\n id: Id128Schema,\n name: NameSchema.optional(),\n icon: z.string().max(64).optional(),\n description: DescriptionSchema.optional(),\n leaderId: Id128Schema.optional(),\n groups: z.array(ScenarioGroupSchema).max(100).optional(),\n nodes: z.array(ScenarioNodeSchema).min(1).max(500).optional(),\n traversalMode: z.enum(['hierarchical', 'topological']).optional(),\n presetId: z.string().max(128).optional(),\n isPublished: z.boolean().optional(),\n ...ScopeShape,\n }))\n .mutation(({ input }) => updateOrThrow(\n async () => scenarioStore.update(input.id, {\n name: input.name,\n icon: input.icon,\n description: input.description,\n leaderId: input.leaderId,\n groups: input.groups,\n nodes: input.nodes,\n traversalMode: input.traversalMode,\n presetId: input.presetId,\n isPublished: input.isPublished,\n updatedAt: Date.now(),\n }, await scopeOf(input)),\n 'Scenario not found',\n )),\n\n delete: protectedProcedure\n .input(z.object({ id: Id128Schema, ...ScopeShape }))\n .mutation(({ input }) => deleteOrNotFound(\n async () => scenarioStore.delete(input.id, await scopeOf(input)),\n 'Scenario not found',\n )),\n\n run: protectedProcedure\n .input(z.object({\n conversationId: ConversationIdSchema,\n scenarioId: Id128Schema,\n userRequest: z.string().max(100_000),\n runnerOverride: z.enum(['claude-code', 'codex']).optional(),\n modelOverride: Id128Schema.optional(),\n agentId: Id128Schema.optional(),\n /** Anchors the run's working directory on the project it belongs to. */\n projectId: Id128Schema.optional(),\n /** Son organisation : sans elle, un id partagé désignerait un projet au hasard. */\n orgId: z.string().max(128).nullable().optional(),\n resume: z.boolean().optional(),\n }))\n .subscription(async function* ({ input, signal }) {\n const scenario = await scenarioStore.get(input.scenarioId, await scopeOf(input));\n if (!scenario) throw new TRPCError({ code: 'NOT_FOUND', message: 'Scenario not found' });\n\n // Start only on explicit user request or resume.\n // Reconnect/resubscribe paths pass an empty request and must never restart runs.\n const canStart = input.userRequest.trim().length > 0 || !!input.resume;\n if (!isScenarioRunning(input.conversationId) && canStart) {\n // On resume, load original user request from workspace if not provided\n let userRequest = input.userRequest;\n if (input.resume && !userRequest.trim()) {\n userRequest = await scenarioRunStore.readUserRequest(input.conversationId) ?? '';\n }\n void runScenario(input.conversationId, input.scenarioId, userRequest, {\n runnerOverride: input.runnerOverride,\n modelOverride: input.modelOverride,\n agentId: input.agentId,\n orgId: input.orgId,\n }, !!input.resume);\n // Small yield to let the bus be created before tapping\n await new Promise(r => setTimeout(r, 10));\n }\n\n // Tap into the live event bus (replays buffer for late subscribers)\n yield* tapBus(input.conversationId, signal ?? new AbortController().signal);\n }),\n\n stop: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .mutation(({ input }) => {\n abortScenario(input.conversationId);\n return { ok: true };\n }),\n\n sendNodeInput: protectedProcedure\n .input(z.object({\n conversationId: ConversationIdSchema,\n nodeId: Id128Schema,\n text: z.string().min(1).max(100_000),\n }))\n .mutation(({ input }) => {\n const resolved = resolveNodeInput(input.conversationId, input.nodeId, input.text);\n if (!resolved) throw new TRPCError({ code: 'NOT_FOUND', message: 'No pending input request for this node' });\n return { ok: true };\n }),\n\n isRunning: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .query(({ input }) => ({ running: isScenarioRunning(input.conversationId) })),\n\n runState: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .query(({ input }) => {\n const runState = scenarioRunStore.getRunState(input.conversationId);\n return runState ?? { nodeStates: {}, nodeOutputs: {}, activeNodeId: undefined };\n }),\n\n getPersistedRunState: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .query(async ({ input }) => {\n return await scenarioRunStore.loadPersistedRunState(input.conversationId);\n }),\n\n getReadme: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .query(async ({ input }) => {\n return await scenarioRunStore.readReadme(input.conversationId);\n }),\n\n getSnapshot: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .query(async ({ input }) => {\n return await scenarioRunStore.loadScenarioSnapshot(input.conversationId);\n }),\n\n streamGenerateWithAI: protectedProcedure\n .input(z.object({\n prompt: z.string().min(1).max(10_000),\n providerId: OptionalProviderIdSchema,\n model: z.string().max(200).optional(),\n current: z.object({\n leaderId: Id128Schema,\n groups: z.array(ScenarioGroupSchema).max(100),\n nodes: z.array(ScenarioNodeSchema).max(500),\n }).optional(),\n }))\n .subscription(async function* ({ input, signal }) {\n const userMessage = buildScenarioUserMessage(input.prompt, input.current);\n yield* streamWithActiveProvider({\n providerId: input.providerId,\n model: input.model,\n systemPrompt: SCENARIO_SYSTEM_PROMPT,\n userMessage,\n maxTokens: 8192,\n signal: signal ?? undefined,\n });\n }),\n\n streamRunEvents: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .subscription(async function* ({ input }) {\n const convId = input.conversationId;\n // For now, yield the current state once\n // In a real implementation, this would track state changes over time\n const runState = scenarioRunStore.getRunState(convId);\n if (runState) {\n for (const [nodeId, state] of Object.entries(runState.nodeStates)) {\n yield { type: 'node_state' as const, nodeId, state };\n }\n }\n }),\n\n /**\n * Returns the Claude Code session-id + agent-id for a node, so the UI can\n * open a debug PTY with `claude --resume <sessionId>` on the right agent.\n * Falls back to the persisted run-state for past nodes.\n */\n getNodeSession: protectedProcedure\n .input(z.object({\n conversationId: ConversationIdSchema,\n nodeId: Id128Schema,\n }))\n .query(async ({ input }) => {\n return await scenarioRunStore.getNodeSessionPersistent(input.conversationId, input.nodeId);\n }),\n\n listPresets: protectedProcedure.query(() => listPresets()),\n\n getPreset: protectedProcedure\n .input(z.object({ id: Id128Schema }))\n .query(({ input }) => {\n const preset = getPreset(input.id);\n if (!preset) throw new TRPCError({ code: 'NOT_FOUND', message: 'Preset not found' });\n return preset;\n }),\n});\n","import { TRPCError } from '@trpc/server';\n\nexport async function getOrNotFound<T>(\n getter: () => Promise<T | null>,\n notFoundMessage: string,\n): Promise<T> {\n const entity = await getter();\n if (!entity) throw new TRPCError({ code: 'NOT_FOUND', message: notFoundMessage });\n return entity;\n}\n\nexport async function createOrBadRequest<T>(creator: () => Promise<T>): Promise<T> {\n try {\n return await creator();\n } catch (err) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: (err as Error).message });\n }\n}\n\nexport async function updateOrThrow<T>(\n updater: () => Promise<T | null>,\n notFoundMessage: string,\n): Promise<T> {\n try {\n const entity = await updater();\n if (!entity) throw new TRPCError({ code: 'NOT_FOUND', message: notFoundMessage });\n return entity;\n } catch (err) {\n if (err instanceof TRPCError) throw err;\n throw new TRPCError({ code: 'BAD_REQUEST', message: (err as Error).message });\n }\n}\n\nexport async function deleteOrNotFound(\n deleter: () => Promise<boolean>,\n notFoundMessage: string,\n): Promise<{ ok: true }> {\n const deleted = await deleter();\n if (!deleted) throw new TRPCError({ code: 'NOT_FOUND', message: notFoundMessage });\n return { ok: true };\n}\n","import { TRPCError } from '@trpc/server';\nimport { streamProviderText } from '../services/ai-generation.js';\nimport { DEFAULT_MODELS, getActiveProvider } from '../services/ai-provider-utils.js';\n\ninterface ActiveProviderGenerationOptions {\n providerId?: string;\n /** L'organisation dont on lit les fournisseurs ; absente = les réglages du poste. */\n vault?: string;\n /** Overrides the provider's configured model when the caller picked one. */\n model?: string;\n systemPrompt: string;\n userMessage: string;\n maxTokens?: number;\n signal?: AbortSignal;\n}\n\nexport async function* streamWithActiveProvider(\n opts: ActiveProviderGenerationOptions,\n): AsyncGenerator<{ type: 'delta' | 'done'; text: string }> {\n const active = await getActiveProvider(opts.providerId, opts.vault);\n if (!active) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Aucun fournisseur IA configuré' });\n\n const { provider, plaintextKey } = active;\n const model = opts.model || provider.model || DEFAULT_MODELS[provider.provider] || '';\n\n try {\n for await (const text of streamProviderText({\n provider,\n plaintextKey,\n model,\n systemPrompt: opts.systemPrompt,\n userMessage: opts.userMessage,\n maxTokens: opts.maxTokens,\n signal: opts.signal,\n })) {\n yield { type: 'delta', text };\n }\n yield { type: 'done', text: '' };\n } catch (err) {\n if (String((err as Error)?.message ?? '').startsWith('Unsupported provider:')) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: `Fournisseur non supporté: ${provider.provider}` });\n }\n throw err;\n }\n}\n","import Anthropic from '@anthropic-ai/sdk';\nimport OpenAI from 'openai';\nimport type { AIProvider } from '@runeya/packages-shared';\nimport { OPENAI_COMPAT_BASE_URLS } from './ai-provider-utils.js';\n\nexport interface ProviderGenerationInput {\n provider: AIProvider;\n plaintextKey: string;\n model: string;\n systemPrompt: string;\n userMessage: string;\n maxTokens?: number;\n signal?: AbortSignal;\n}\n\nexport async function* streamProviderText(input: ProviderGenerationInput): AsyncGenerator<string> {\n const {\n provider,\n plaintextKey,\n model,\n systemPrompt,\n userMessage,\n maxTokens = 8192,\n signal,\n } = input;\n\n if (provider.provider === 'anthropic') {\n const client = new Anthropic({ apiKey: plaintextKey });\n const stream = client.messages.stream({\n model,\n max_tokens: maxTokens,\n system: systemPrompt,\n messages: [{ role: 'user', content: userMessage }],\n });\n for await (const event of stream) {\n if (signal?.aborted) return;\n if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {\n yield event.delta.text;\n }\n }\n return;\n }\n\n if (provider.provider in OPENAI_COMPAT_BASE_URLS) {\n const baseURL = OPENAI_COMPAT_BASE_URLS[provider.provider]!;\n const client = new OpenAI({ apiKey: plaintextKey || 'ollama', baseURL });\n const stream = await client.chat.completions.create({\n model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userMessage },\n ],\n stream: true,\n max_tokens: maxTokens,\n }, { signal: signal ?? undefined });\n for await (const chunk of stream) {\n if (signal?.aborted) return;\n const text = chunk.choices[0]?.delta?.content;\n if (text) yield text;\n }\n return;\n }\n\n throw new Error(`Unsupported provider: ${provider.provider}`);\n}\n","import { mkdir } from 'node:fs/promises';\nimport { randomUUID } from 'node:crypto';\nimport { join } from 'node:path';\nimport { scenarioStore } from './scenario-store.js';\nimport { scenarioRunStore, type NodeState } from './scenario-run-store.js';\nimport type { Scenario, ScenarioNode } from '@runeya/packages-shared';\nimport { getPreset } from './scenario-presets.js';\nimport { atomicWriteSecure, resolveConversationRunDir } from './run-store-utils.js';\nimport { ClaudeCodeRunner } from './ai-runners/claude-code-runner.js';\nimport { CodexRunner } from './ai-runners/codex-runner.js';\nimport type { AiRunner } from './ai-runners/ai-runner.js';\nimport { agentManager } from './agent-manager.js';\nimport { resolveConversationCwd } from './workspace-cwd.js';\n\nconst DEFAULT_NODE_MODELS: Record<'claude-code' | 'codex', string> = {\n 'claude-code': 'sonnet',\n codex: '',\n};\n\nexport interface ScenarioRunOverrides {\n runnerOverride?: 'claude-code' | 'codex';\n modelOverride?: string;\n agentId?: string;\n /**\n * L'organisation qui possède le scénario — celle dont le coffre le contient.\n *\n * Le répertoire de travail, lui, ne se transmet plus ici : il se lit de la\n * conversation au moment de lancer le CLI (`resolveConversationCwd`).\n */\n orgId?: string | null;\n}\n\n// ─── Event types ──────────────────────────────────────────────────────────────\n\nexport type ScenarioEvent =\n | { type: 'node_started'; nodeId: string }\n | { type: 'node_delta'; nodeId: string; text: string }\n | { type: 'node_status'; nodeId: string; text: string }\n | { type: 'node_tool_call'; nodeId: string; id: string; name: string; input: Record<string, unknown>; rawInput?: string }\n | { type: 'node_tool_result'; nodeId: string; id: string; result: string; isError: boolean }\n | { type: 'node_thinking'; nodeId: string; text: string }\n | { type: 'node_command'; nodeId: string; command: string }\n | { type: 'node_duration'; nodeId: string; durationMs: number }\n | { type: 'node_done'; nodeId: string; output: string; state: string }\n | { type: 'node_state_change'; nodeId: string; state: string }\n | { type: 'node_error'; nodeId: string; error: string }\n | { type: 'node_waiting_input'; nodeId: string; question: string }\n | { type: 'node_prompt'; nodeId: string; label: string; systemContext: string; userMessage: string }\n | { type: 'readme_append'; text: string }\n | { type: 'scenario_complete'; summary: string }\n | { type: 'scenario_error'; error: string };\n\n// ─── Event bus ────────────────────────────────────────────────────────────────\n\nconst MAX_BUFFER = 500;\n\ninterface RunBus {\n buffer: ScenarioEvent[];\n /** Absolute index of buffer[0] in the full event stream */\n baseIndex: number;\n listeners: Set<(evt: ScenarioEvent | null) => void>;\n done: boolean;\n}\n\nconst activeBuses = new Map<string, RunBus>();\nconst activeAbortControllers = new Map<string, AbortController>();\n\nfunction formatTs(): string {\n const d = new Date();\n const off = -d.getTimezoneOffset();\n const sign = off >= 0 ? '+' : '-';\n const pad2 = (n: number) => String(n).padStart(2, '0');\n return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())} ${pad2(d.getHours())}:${pad2(d.getMinutes())}:${pad2(d.getSeconds())} ${sign}${pad2(Math.floor(Math.abs(off) / 60))}:${pad2(Math.abs(off) % 60)}`;\n}\n\n// ─── Pending user-input requests (keyed by conversationId:nodeId) ──────────\n\nconst pendingNodeInputs = new Map<string, (text: string) => void>();\n\nfunction pendingNodeKey(conversationId: string, nodeId: string) {\n return `${conversationId}:${nodeId}`;\n}\n\n/** Called by scenario.sendNodeInput tRPC mutation when the user submits their reply. */\nexport function resolveNodeInput(conversationId: string, nodeId: string, text: string): boolean {\n const key = pendingNodeKey(conversationId, nodeId);\n const resolver = pendingNodeInputs.get(key);\n if (!resolver) return false;\n pendingNodeInputs.delete(key);\n resolver(text);\n return true;\n}\n\nfunction createBus(conversationId: string): RunBus {\n const bus: RunBus = { buffer: [], baseIndex: 0, listeners: new Set(), done: false };\n activeBuses.set(conversationId, bus);\n return bus;\n}\n\n// Events that are only useful in real-time and should not be replayed to late subscribers\nconst NO_BUFFER_EVENTS = new Set<ScenarioEvent['type']>(['node_status', 'node_thinking']);\n\nfunction publishToBus(bus: RunBus, evt: ScenarioEvent | null): void {\n if (evt !== null) {\n if (!NO_BUFFER_EVENTS.has(evt.type)) {\n bus.buffer.push(evt);\n while (bus.buffer.length > MAX_BUFFER) {\n const idx = bus.buffer.findIndex(e => e.type === 'node_delta');\n bus.buffer.splice(idx >= 0 ? idx : 0, 1);\n bus.baseIndex += 1;\n }\n }\n } else {\n bus.done = true;\n }\n for (const listener of bus.listeners) listener(evt);\n bus.listeners.clear();\n}\n\nexport async function* tapBus(conversationId: string, signal: AbortSignal): AsyncGenerator<ScenarioEvent> {\n const bus = activeBuses.get(conversationId);\n if (!bus) return;\n\n let cursor = bus.baseIndex;\n\n while (true) {\n if (cursor < bus.baseIndex) {\n // Buffer rotated (old events dropped). Jump forward to oldest still available.\n cursor = bus.baseIndex;\n }\n while (cursor < bus.baseIndex + bus.buffer.length) {\n const evt = bus.buffer[cursor - bus.baseIndex]!;\n cursor += 1;\n yield evt;\n }\n if (bus.done) return;\n if (signal.aborted) return;\n\n await new Promise<void>((resolve) => {\n const onAbort = () => {\n bus.listeners.delete(notify);\n resolve();\n };\n const notify = () => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n };\n bus.listeners.add(notify);\n signal.addEventListener('abort', onAbort, { once: true });\n // Race guard: if an event was published between the last buffer drain and\n // listener registration, wake immediately instead of waiting forever.\n if (cursor < bus.baseIndex + bus.buffer.length || bus.done || signal.aborted) {\n bus.listeners.delete(notify);\n signal.removeEventListener('abort', onAbort);\n resolve();\n }\n });\n }\n}\n\nexport function isScenarioRunning(conversationId: string): boolean {\n const bus = activeBuses.get(conversationId);\n return bus !== undefined && !bus.done;\n}\n\nexport function abortScenario(conversationId: string): boolean {\n const ctrl = activeAbortControllers.get(conversationId);\n if (!ctrl) return false;\n ctrl.abort();\n return true;\n}\n\n// ─── Hierarchy helpers ────────────────────────────────────────────────────────\n\nconst FINISHED_STATES = new Set(['done', 'error', 'synthesized']);\nconst MAX_MANAGER_REVIEW_ROUNDS = Infinity;\n\n/**\n * After a BFS level completes, promote any 'waiting' ancestor to 'done'\n * if all their descendants (recursively) are now in a finished state.\n */\nfunction resolveWaitingStates(\n nodes: ScenarioNode[],\n conversationId: string,\n byParent: Map<string, ScenarioNode[]>,\n publish: (evt: ScenarioEvent) => void,\n skipNodeIds: Set<string> = new Set(),\n): void {\n function allDescendantsDone(nodeId: string): boolean {\n for (const child of byParent.get(nodeId) ?? []) {\n const s = scenarioRunStore.getRunState(conversationId)?.nodeStates[child.id];\n if (!s || !FINISHED_STATES.has(s)) return false;\n if (!allDescendantsDone(child.id)) return false;\n }\n return true;\n }\n\n for (const node of nodes) {\n if (skipNodeIds.has(node.id)) continue;\n const s = scenarioRunStore.getRunState(conversationId)?.nodeStates[node.id];\n if (s === 'waiting' && allDescendantsDone(node.id)) {\n scenarioRunStore.setNodeState(conversationId, node.id, 'done');\n publish({ type: 'node_state_change', nodeId: node.id, state: 'done' });\n }\n }\n}\n\nfunction normalizeForMatch(value: string): string {\n return value\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, ' ')\n .trim();\n}\n\nfunction getDirectReports(nodes: ScenarioNode[], managerId: string): ScenarioNode[] {\n return nodes.filter((p) => p.parentIds[0] === managerId);\n}\n\n/**\n * Parse <next_person> directives from AI output.\n *\n * Supported forms:\n * <next_person name=\"Alice Martin\">specific instruction (multiline ok)</next_person>\n * <next_person name=\"STOP\" />\n */\nfunction parseRuneyaNextNodeDirectives(output: string): { name: string; instruction: string | null }[] {\n const results: { name: string; instruction: string | null }[] = [];\n // Self-closing form: <next_person name=\"STOP\" />\n for (const m of output.matchAll(/<next_person\\s+name=\"([^\"]*?)\"\\s*\\/>/g)) {\n results.push({ name: m[1].trim(), instruction: null });\n }\n // Content form: <next_person name=\"Alice\">instruction</next_person>\n for (const m of output.matchAll(/<next_person\\s+name=\"([^\"]*?)\">([\\s\\S]*?)<\\/next_person>/g)) {\n results.push({ name: m[1].trim(), instruction: m[2].trim() || null });\n }\n return results;\n}\n\ninterface HireDirectivePayload {\n label: string;\n role: string;\n prompt: string;\n}\n\n/**\n * Parse <hire_person> directives from AI output.\n *\n * <hire_person label=\"Jane Doe\" role=\"engineer\">Task focus prompt</hire_person>\n */\nfunction parseRuneyaHireDirectives(output: string): HireDirectivePayload[] {\n const results: HireDirectivePayload[] = [];\n for (const m of output.matchAll(/<hire_person\\s+label=\"([^\"]*?)\"\\s+role=\"([^\"]*?)\">([\\s\\S]*?)<\\/hire_person>/g)) {\n const label = m[1].trim();\n const role = m[2].trim();\n const prompt = m[3].trim();\n if (label && role && prompt) results.push({ label, role, prompt });\n }\n return results;\n}\n\nconst HIRE_LAYOUT = {\n startY: 88,\n siblingGap: 24,\n minXInTeam: 20,\n minYInTeam: 36,\n nodeWidthEstimate: 180,\n nodeHeightEstimate: 50,\n groupRightPadding: 24,\n groupBottomPadding: 28,\n minGroupWidth: 300,\n minGroupHeight: 200,\n} as const;\n\nfunction computeHirePosition(manager: ScenarioNode, nodes: ScenarioNode[]): { x: number; y: number } {\n const sameTeamReports = nodes.filter((p) => p.parentIds[0] === manager.id && p.groupId === (manager.groupId ?? null));\n const managerX = Number.isFinite(manager.position?.x) ? manager.position.x : 140;\n const managerY = Number.isFinite(manager.position?.y) ? manager.position.y : 40;\n const baseY = managerY + HIRE_LAYOUT.startY;\n const rightMost = sameTeamReports\n .filter((p) => Number.isFinite(p.position?.x))\n .sort((a, b) => (a.position?.x ?? 0) - (b.position?.x ?? 0))\n .at(-1);\n\n let x = managerX;\n let y = baseY;\n if (rightMost) {\n x = (rightMost.position?.x ?? managerX) + HIRE_LAYOUT.nodeWidthEstimate + HIRE_LAYOUT.siblingGap;\n y = Math.max(baseY, rightMost.position?.y ?? baseY);\n }\n\n if (manager.groupId) {\n x = Math.max(HIRE_LAYOUT.minXInTeam, x);\n y = Math.max(HIRE_LAYOUT.minYInTeam, y);\n } else {\n x = Math.max(0, x);\n y = Math.max(0, y);\n }\n\n return { x, y };\n}\n\nfunction ensureGroupCanContainNode(scenario: Scenario, groupId: string | null, position: { x: number; y: number }): void {\n if (!groupId) return;\n const group = scenario.groups.find((t) => t.id === groupId);\n if (!group) return;\n\n const width = Number.isFinite(group.width) ? group.width : HIRE_LAYOUT.minGroupWidth;\n const height = Number.isFinite(group.height) ? group.height : HIRE_LAYOUT.minGroupHeight;\n\n const neededWidth = position.x + HIRE_LAYOUT.nodeWidthEstimate + HIRE_LAYOUT.groupRightPadding;\n const neededHeight = position.y + HIRE_LAYOUT.nodeHeightEstimate + HIRE_LAYOUT.groupBottomPadding;\n\n group.width = Math.max(width, HIRE_LAYOUT.minGroupWidth, neededWidth);\n group.height = Math.max(height, HIRE_LAYOUT.minGroupHeight, neededHeight);\n}\n\nfunction applyHireDirectivesFromOutput(\n manager: ScenarioNode,\n scenario: Scenario,\n output: string,\n): ScenarioNode[] {\n const hireDirectives = parseRuneyaHireDirectives(output);\n if (hireDirectives.length === 0) return [];\n if (!manager.canAddNode) {\n throw new Error(`${manager.label} attempted to hire without permission`);\n }\n\n const hired: ScenarioNode[] = [];\n for (const payload of hireDirectives) {\n const id = `hire-${randomUUID().slice(0, 8)}`;\n const position = computeHirePosition(manager, scenario.nodes);\n ensureGroupCanContainNode(scenario, manager.groupId ?? null, position);\n const node: ScenarioNode = {\n id,\n type: 'ai',\n parentIds: [manager.id],\n groupId: manager.groupId ?? null,\n label: payload.label,\n role: payload.role,\n prompt: payload.prompt,\n question: '',\n autoGenerated: true,\n canAddNode: false,\n aiCli: manager.aiCli ?? 'claude-code',\n model: '',\n position,\n injectParentOutputs: false,\n injectedAncestorIds: [],\n };\n scenario.nodes.push(node);\n hired.push(node);\n }\n return hired;\n}\n\nfunction selectExplicitDirectReportsFromOutput(\n manager: ScenarioNode,\n nodes: ScenarioNode[],\n managerOutput: string,\n): { selected: ScenarioNode[]; unknownNames: string[]; assignments: Map<string, string>; missingAssignments: string[] } {\n const directReports = getDirectReports(nodes, manager.id);\n\n const directives = parseRuneyaNextNodeDirectives(managerOutput);\n const normalizedDirectives = directives.map((d) => ({ norm: normalizeForMatch(d.name), instruction: d.instruction }));\n const stopDirective = normalizedDirectives.length === 1 && normalizedDirectives[0]!.norm === 'stop';\n if (normalizedDirectives.length === 0 || stopDirective) return { selected: [], unknownNames: [], assignments: new Map(), missingAssignments: [] };\n\n const selected: ScenarioNode[] = [];\n const assignments = new Map<string, string>();\n const matchedDirectives = new Set<string>();\n for (const report of directReports) {\n const fullName = normalizeForMatch(report.label);\n const reverseName = normalizeForMatch(`${report.label}`);\n const matched = normalizedDirectives.find((d) => d.norm === fullName || d.norm === reverseName);\n if (matched) {\n selected.push(report);\n matchedDirectives.add(matched.norm);\n if (matched.instruction) assignments.set(report.id, matched.instruction);\n }\n }\n const unknownNames = normalizedDirectives.filter((d) => d.norm !== 'stop' && !matchedDirectives.has(d.norm)).map((d) => d.norm);\n const missingAssignments = selected.filter((r) => !assignments.has(r.id)).map((r) => r.label);\n return { selected, unknownNames, assignments, missingAssignments };\n}\n\n\n\nfunction hasExplicitNoDelegationDecision(output: string): boolean {\n const nextDirectives = parseRuneyaNextNodeDirectives(output);\n // STOP is only valid when it is the single NEXT_PERSON directive.\n return nextDirectives.length === 1 && normalizeForMatch(nextDirectives[0]?.name ?? '') === 'stop';\n}\n\nfunction buildDelegationRetryMessage(\n manager: ScenarioNode,\n directReports: ScenarioNode[],\n userRequest: string,\n previousOutput: string,\n): string {\n const reportsList = directReports\n .map((r) => `- ${r.label} | role: ${r.role ?? 'other'} | profile: ${r.prompt || 'no description'}`)\n .join('\\n');\n\n return [\n `## Original Request`,\n userRequest,\n ``,\n `## Your Previous Output`,\n `<previous_output>`,\n previousOutput,\n `</previous_output>`,\n ``,\n `## Delegation Retry (mandatory)`,\n `You must explicitly choose which direct reports to contact now.`,\n `Use the exact full names from the allowed list below.`,\n `If you still do not provide explicit names, your run will fail.`,\n ``,\n `## Allowed Direct Reports`,\n reportsList || '(none)',\n ``,\n ...(manager.canAddNode ? [\n `## Optional Hire Command`,\n `You may hire temporary contractors with:`,\n `<hire_person label=\"Jane Doe\" role=\"engineer\">Task focus prompt</hire_person>`,\n `If you hire someone and want them to run now, also include: <next_person name=\"Jane Doe\">their task</next_person>`,\n ``,\n ] : []),\n `## Output Format`,\n `Write one XML tag per selected node including their specific instruction:`,\n `<next_person name=\"FirstName LastName\">their specific task (multiline ok)</next_person>`,\n `Or explicitly choose no delegation with: <next_person name=\"STOP\" />`,\n ].join('\\n');\n}\n\nfunction buildMissingAssignmentsRetryMessage(\n _manager: ScenarioNode,\n missingNames: string[],\n previousOutput: string,\n): string {\n return [\n `## Missing Assignments`,\n `You selected the following nodes but did not provide a specific instruction for each:`,\n missingNames.map((n) => `- ${n}`).join('\\n'),\n ``,\n `## Your Previous Output`,\n `<previous_output>`,\n previousOutput,\n `</previous_output>`,\n ``,\n `## Required Format`,\n `For each node listed above, output one XML tag with their instruction:`,\n `<next_person name=\"FirstName LastName\">their specific task instruction (multiline ok)</next_person>`,\n `The instruction content is mandatory. Be concise and actionable.`,\n ].join('\\n');\n}\n\nfunction buildManagerReviewMessage(\n manager: ScenarioNode,\n directReports: ScenarioNode[],\n userRequest: string,\n previousOutput: string,\n childReportsSection: string,\n): string {\n const reportsList = directReports\n .map((r) => `- ${r.label} | role: ${r.role ?? 'other'} | profile: ${r.prompt || 'no description'}`)\n .join('\\n');\n\n return [\n `## Original Request`,\n userRequest,\n ``,\n `## Your Previous Output`,\n `<previous_output>`,\n previousOutput,\n `</previous_output>`,\n ``,\n `## Children Reports Collected`,\n childReportsSection || '(none)',\n ``,\n `## Parent Review Decision (mandatory)`,\n `You are now in review mode after collecting child reports.`,\n `Your decision rule is simple:`,\n `- If the deliverable is complete and satisfies the original request → output <next_person name=\"STOP\" /> immediately. Do NOT re-run for process reasons (wrong node assigned, style preferences, etc.).`,\n `- If something is factually missing or incorrect in the deliverable → request a targeted re-run with precise instructions.`,\n `Use the exact full names from your direct reports list below.`,\n ``,\n `## Allowed Direct Reports`,\n reportsList || '(none)',\n ``,\n ...(manager.canAddNode ? [\n `## Optional Hire Command`,\n `You may hire temporary contractors with:`,\n `<hire_person label=\"Jane Doe\" role=\"engineer\">Task focus prompt</hire_person>`,\n `If you hire someone and want them to run now, also include: <next_person name=\"Jane Doe\">their task</next_person>`,\n ``,\n ] : []),\n `## Output Format`,\n `If no more child work is needed: output <next_person name=\"STOP\" /> first, then immediately write a complete synthesis of all children's deliverables so your parent can evaluate the result. Do NOT summarize — include the full content (scripts, outputs, data, etc.).`,\n `If refinement is needed, output one XML tag per selected node with their specific instruction:`,\n `<next_person name=\"FirstName LastName\">precise refinement instruction (multiline ok)</next_person>`,\n ].join('\\n');\n}\n\n// ─── Prompt builders ──────────────────────────────────────────────────────────\n\n\nfunction buildSystemPrompt(\n node: ScenarioNode,\n scenario: Scenario,\n): string {\n const group = scenario.groups.find(t => t.id === node.groupId);\n const manager = node.parentIds[0] ? scenario.nodes.find(p => p.id === node.parentIds[0]) : null;\n const reports = getDirectReports(scenario.nodes, node.id);\n\n const preset = scenario.presetId ? getPreset(scenario.presetId) : undefined;\n const presetRole = preset?.roles.find(r => r.id === (node.role ?? 'other'));\n const roleBehavior = presetRole?.systemPrompt ?? '';\n const rolePrompt = presetRole?.prompt ?? '';\n\n const lines = [\n `You are ${node.label}${group ? `, member of the ${group.name} group` : ''}.`,\n `Your role type: **${(node.role ?? 'other').toUpperCase()}**.`,\n '',\n ];\n\n if (roleBehavior) {\n lines.push('## Role Behavior (strictly enforce)', roleBehavior, '');\n }\n\n const profileSection = [node.prompt, rolePrompt].filter(Boolean).join('\\n\\n');\n lines.push('## Your Profile & Instructions', profileSection || '(No profile provided)', '');\n\n if (manager) {\n lines.push(`## Reporting Line`, `You report to ${manager.label} (${manager.role ?? 'other'}).`, '');\n } else {\n lines.push(`## Position`, `You are the leader of this scenario. You coordinate all groups.`, '');\n }\n\n if (reports.length > 0) {\n lines.push(\n `## Your Direct Reports`,\n ...reports.map(r => {\n const rGroup = scenario.groups.find(g => g.id === r.groupId);\n const groupInfo = rGroup\n ? ` | group: ${rGroup.name}${rGroup.description ? ` (${rGroup.description})` : ''}`\n : '';\n return `- ${r.label} (${r.role ?? 'other'})${groupInfo}: ${r.prompt || '(No profile provided)'}`;\n }),\n '',\n );\n }\n\n if (node.canAddNode) {\n lines.push(\n '## Hiring Capability',\n 'You are allowed to hire temporary contractors for this run.',\n 'Use exactly: <hire_person label=\"Jane Doe\" role=\"engineer\">Task focus prompt</hire_person>',\n 'Any hired node will automatically be placed in your own group.',\n 'To execute the hired node in this run, also output: <next_person name=\"Jane Doe\">their task</next_person>',\n '',\n );\n }\n\n lines.push(\n '## Output Instructions',\n 'Write your output clearly and in a structured format.',\n 'Stay strictly within your role — do not produce deliverables that belong to a different role.',\n 'Be concise and actionable.',\n 'Only use <ask_user>...</ask_user> when you are genuinely blocked by missing information that no one in the group can provide (e.g. a secret, a business decision, an external credential). NEVER use it to ask for confirmation, approval, or readiness (e.g. \"are you ready?\", \"shall I proceed?\"). Always proceed autonomously unless truly blocked.',\n );\n\n // Inject RUNEYA_AI_* environment variables\n const runeya_ai_vars = Object.entries(process.env)\n .filter(([k]) => k.startsWith('RUNEYA_AI_'))\n .map(([k, v]) => `${k}=${v}`)\n .join('\\n');\n if (runeya_ai_vars) {\n lines.push('', '## Environment', '', runeya_ai_vars);\n }\n\n return lines.join('\\n');\n}\n\nfunction buildUserMessage(\n node: ScenarioNode,\n scenario: Scenario,\n userRequest: string,\n managerOutput: string | null,\n isLeaderSynthesis: boolean,\n isLeaderDispatch: boolean,\n allOutputs?: Map<string, string>,\n): string {\n const parts: string[] = [];\n\n if (node.prompt) {\n parts.push(`## Your Profile & Instructions (reminder)\\n\\n${node.prompt}`);\n }\n\n parts.push(`## Original Request\\n\\n${userRequest}`);\n\n if (isLeaderSynthesis && allOutputs) {\n // Leader's final synthesis pass: receive all group outputs\n const teamSection = scenario.nodes\n .filter(p => p.id !== scenario.leaderId && allOutputs.has(p.id))\n .map(p => {\n const name = p.label.trim() || p.id;\n const output = allOutputs.get(p.id) ?? '';\n return `<team_member id=\"${p.id}\" name=\"${name}\">\\n${output}\\n</team_member>`;\n })\n .join('\\n\\n');\n\n if (teamSection) {\n parts.push(`## Your Group's Outputs\\n\\n${teamSection}`);\n }\n\n parts.push(\n `## Your Task`,\n `Synthesize all group outputs above and deliver a final, comprehensive answer to the original request.`,\n `Highlight key results, decisions, and any remaining open points.`,\n );\n } else if (isLeaderDispatch) {\n // Leader's dispatch pass: break down the request and assign sub-tasks\n const directReports = getDirectReports(scenario.nodes, node.id);\n const reportsList = directReports\n .map(r => {\n const group = scenario.groups.find(t => t.id === r.groupId);\n return `- ${r.label} | role: ${r.role ?? 'other'}${group ? ` | group: ${group.name}${group.description ? ` (${group.description})` : ''}` : ''} | profile: ${r.prompt || 'no description'}`;\n })\n .join('\\n');\n\n parts.push(\n `## Your Direct Reports\\n\\n${reportsList || '(none)'}`,\n `## Your Task`,\n `As the leader, your role here is STRICTLY to delegate — NEVER to solve the request yourself.`,\n `Do NOT ask yourself whether you should answer directly or delegate. You ALWAYS delegate.`,\n `⚠️ IMPORTANT: Before selecting anyone, re-read your Profile & Instructions above. Any constraint written there (e.g. \"do not contact X\", \"must hire someone\") is MANDATORY and overrides everything else.`,\n `Instead, analyze the request and produce a clear **delegation plan**:`,\n `1. Break down the request into concrete sub-tasks, one per direct report (or group of reports if relevant).`,\n `2. For each node, write a specific, actionable assignment that fits their role and expertise.`,\n `3. Provide any strategic context, constraints, or success criteria they need.`,\n `4. Do NOT produce the final answer — your group will do that. You coordinate.`,\n `5. IMPORTANT: explicitly mention the exact full name of each direct report you want to contact. Only explicitly mentioned nodes will be executed.`,\n `6. For each node you assign, output one XML tag with their name AND specific instruction: <next_person name=\"FirstName LastName\">their specific instruction (multiline ok)</next_person>`,\n `7. If you intentionally decide to contact nobody, write exactly: <next_person name=\"STOP\" />`,\n ...(node.canAddNode ? [\n `8. You may hire temporary contractors with: <hire_person label=\"Jane Doe\" role=\"engineer\">Task focus prompt</hire_person>`,\n `9. Hired nodes are always placed in your own group (no group field needed).`,\n `10. If you hire someone and want them to execute now, also include: <next_person name=\"Jane Doe\">their task</next_person>`,\n ] : []),\n ``,\n `Format your output as a brief intro followed by one clearly labeled section per direct report.`,\n );\n } else {\n if (managerOutput) {\n const manager = scenario.nodes.find(p => p.id === node.parentIds[0]);\n const managerName = manager ? manager.label.trim() : 'your manager';\n parts.push(\n `## Assignment from ${managerName}\\n\\n<manager_output>\\n${managerOutput}\\n</manager_output>`,\n );\n }\n\n // Inject outputs from explicitly selected ancestor nodes\n if (allOutputs && !isLeaderSynthesis) {\n const injectedIds = new Set<string>();\n // Always inject all parent outputs when the node has multiple parents (aggregation node),\n // or when explicitly requested via injectParentOutputs.\n if (node.injectParentOutputs || node.parentIds.length > 1) {\n for (const pid of node.parentIds) injectedIds.add(pid);\n }\n for (const aid of (node.injectedAncestorIds ?? [])) injectedIds.add(aid);\n // Remove first parent since its output is already shown as \"Assignment from manager\" (avoid duplicate)\n injectedIds.delete(node.parentIds[0] ?? '');\n\n const prevOutputs = scenario.nodes\n .filter(p => injectedIds.has(p.id) && allOutputs.has(p.id))\n .map(p => {\n const name = p.label.trim() || p.id;\n const output = allOutputs.get(p.id) ?? '';\n return `<context_node id=\"${p.id}\" name=\"${name}\">\\n${output}\\n</context_node>`;\n })\n .join('\\n\\n');\n if (prevOutputs) {\n parts.push(`## Context from Related Nodes\\n\\n${prevOutputs}`);\n }\n }\n\n parts.push(\n `## Your Task`,\n `Based on the original request${managerOutput ? ' and your manager\\'s assignment above' : ''}${allOutputs && !isLeaderSynthesis && ((node.parentIds.length > 1 || node.injectParentOutputs) || (node.injectedAncestorIds ?? []).length > 0) ? ' and the context from related nodes above' : ''}, ` +\n `complete your specific part according to your role and expertise. ` +\n `Be thorough and actionable. Report your output clearly — your manager will use it for the final synthesis.`,\n );\n\n const directReports = getDirectReports(scenario.nodes, node.id);\n if (directReports.length > 0) {\n const reportsList = directReports\n .map((r) => `- ${r.label} | role: ${r.role ?? 'other'} | profile: ${r.prompt || 'no description'}`)\n .join('\\n');\n parts.push(\n ...(node.canAddNode ? [\n `## Hiring (available to you)`,\n `You may hire a temporary contractor for this run: <hire_person label=\"Jane Doe\" role=\"engineer\">Task focus prompt</hire_person>`,\n `If you hire someone and want them to execute immediately, also add: <next_person name=\"Jane Doe\">their task</next_person>`,\n `Hired nodes join your group automatically — no group field needed.`,\n ] : []),\n `## Direct Reports You Can Also Contact\\n\\n${reportsList}`,\n `⚠️ MANDATORY: Re-read your Profile & Instructions above before selecting anyone. Any constraint there (e.g. \"do not contact X\", \"must hire\") overrides everything.`,\n `For each node you assign, output one XML tag with their name AND specific instruction: <next_person name=\"FirstName LastName\">their specific instruction (multiline ok)</next_person>`,\n `Only names declared with <next_person> will run.`,\n `If you intentionally choose to delegate to nobody, write: <next_person name=\"STOP\" />`,\n );\n }\n }\n\n return parts.join('\\n\\n');\n}\n\n// ─── Single-node AI call (streaming) ───────────────────────────────────────\n\nfunction resolveNodeExecutionConfig(\n node: ScenarioNode,\n runOverrides?: ScenarioRunOverrides,\n): { aiCli: 'claude-code' | 'codex'; model: string } {\n const baseCli = node.aiCli ?? 'claude-code';\n const aiCli = runOverrides?.runnerOverride ?? baseCli;\n const crossFamily = !!runOverrides?.runnerOverride && runOverrides.runnerOverride !== baseCli;\n const modelOverride = runOverrides?.modelOverride?.trim() ?? '';\n const nodeModel = node.model?.trim() ?? '';\n const model = modelOverride || (crossFamily ? DEFAULT_NODE_MODELS[aiCli] : (nodeModel || DEFAULT_NODE_MODELS[aiCli]));\n return { aiCli, model };\n}\n\n// ─── Per-node runner state (session continuity across ASK_USER loops) ───────\n\ninterface NodeRunnerState {\n runner: AiRunner;\n sessionId: string;\n isResume: boolean;\n}\n\nfunction createNodeRunnerState(aiCli: 'claude-code' | 'codex'): NodeRunnerState {\n return {\n runner: aiCli === 'codex' ? new CodexRunner() : new ClaudeCodeRunner(),\n sessionId: '',\n isResume: false,\n };\n}\n\nasync function runNodeCall(\n conversationId: string,\n node: ScenarioNode,\n systemContext: string,\n userMessage: string,\n runOverrides: ScenarioRunOverrides | undefined,\n signal: AbortSignal,\n publish: (evt: ScenarioEvent) => void,\n onDelta: (text: string) => void,\n runnerStates: Map<string, NodeRunnerState>,\n label = 'call',\n readme?: (text: string) => Promise<void>,\n): Promise<string> {\n publish({ type: 'node_prompt', nodeId: node.id, label, systemContext, userMessage });\n const { aiCli, model } = resolveNodeExecutionConfig(node, runOverrides);\n\n if (!runnerStates.has(node.id)) {\n runnerStates.set(node.id, createNodeRunnerState(aiCli));\n }\n const state = runnerStates.get(node.id)!;\n\n let currentPrompt = userMessage;\n let accumulated = '';\n let persistTimer: ReturnType<typeof setTimeout> | null = null;\n\n const schedulePersist = () => {\n if (persistTimer) return;\n persistTimer = setTimeout(() => {\n persistTimer = null;\n appendNodeOutput(conversationId, node, accumulated).catch(() => {});\n }, 500);\n };\n\n const flushPersist = () => {\n if (persistTimer) { clearTimeout(persistTimer); persistTimer = null; }\n };\n\n while (true) {\n const turnStart = Date.now();\n\n const result = await state.runner.run({\n agentId: runOverrides?.agentId ?? agentManager.getDefaultAgentId() ?? undefined,\n // Without this the CLI would run wherever the server was launched, whatever\n // project the scenario belongs to. Read from the conversation, so un lancement\n // sans requête HTTP — la file kanban — est ancré comme les autres. No project:\n // left unset, so the runner keeps its own default rather than being sent to\n // this machine's path.\n cwd: await resolveConversationCwd(conversationId),\n sessionId: state.sessionId,\n prompt: currentPrompt,\n isResume: state.isResume,\n systemContext,\n apiBaseUrl: '',\n apiToken: '',\n model,\n effort: 'normal',\n signal,\n onDelta: (text) => {\n accumulated += text;\n onDelta(text);\n schedulePersist();\n },\n onStatus: (text) => publish({ type: 'node_status', nodeId: node.id, text }),\n onToolCall: (id, name, input, rawInput) => publish({ type: 'node_tool_call', nodeId: node.id, id, name, input, rawInput }),\n onToolResult: (id, result, isError) => publish({ type: 'node_tool_result', nodeId: node.id, id, result, isError }),\n onThinking: (text) => publish({ type: 'node_thinking', nodeId: node.id, text }),\n onCommand: (cmd) => publish({ type: 'node_command', nodeId: node.id, command: cmd }),\n });\n\n flushPersist();\n // Update to the actual session ID reported by claude (may differ from our initial UUID)\n if (result.actualSessionId) state.sessionId = result.actualSessionId;\n state.isResume = true;\n\n // Persist the claude session-id per node so the user can later open a\n // `claude --resume <sessionId>` PTY from the debug button.\n const agentForNode = runOverrides?.agentId ?? agentManager.getDefaultAgentId() ?? null;\n if (state.sessionId && agentForNode) {\n scenarioRunStore.setNodeSession(conversationId, node.id, state.sessionId, agentForNode);\n void scenarioRunStore.persistRunState(conversationId);\n }\n\n if (result.tokenStatus === 'ask_user') {\n publish({ type: 'node_duration', nodeId: node.id, durationMs: Date.now() - turnStart });\n scenarioRunStore.setNodeState(conversationId, node.id, 'waiting_input');\n scenarioRunStore.setWaitingInput(conversationId, node.id, result.tokenMessage);\n flushPersist();\n publish({ type: 'node_waiting_input', nodeId: node.id, question: result.tokenMessage });\n await readme?.(`- ❓ [${formatTs()}] **${node.label}** — waiting for user input\\n`);\n\n const answer = await new Promise<string>((resolve, reject) => {\n const key = pendingNodeKey(conversationId, node.id);\n pendingNodeInputs.set(key, resolve);\n signal.addEventListener('abort', () => {\n pendingNodeInputs.delete(key);\n reject(new Error('Aborted'));\n }, { once: true });\n });\n\n scenarioRunStore.clearWaitingInput(conversationId, node.id);\n await readme?.(`- 💬 [${formatTs()}] **User replied** to ${node.label}\\n`);\n const qaBlock = `\\n\\n---\\n**Question:** ${result.tokenMessage}\\n\\n**Your answer:** ${answer}\\n`;\n await appendNodeOutput(conversationId, node, qaBlock);\n publish({ type: 'node_delta', nodeId: node.id, text: qaBlock });\n accumulated = '';\n scenarioRunStore.setNodeState(conversationId, node.id, 'running');\n publish({ type: 'node_started', nodeId: node.id });\n currentPrompt = `L'utilisateur a répondu : ${answer}`;\n continue;\n }\n\n publish({ type: 'node_duration', nodeId: node.id, durationMs: Date.now() - turnStart });\n return result.output;\n }\n}\n\n// ─── Persist output to workspace file ────────────────────────────────────────\n\nfunction getScenarioRunDir(conversationId: string): string | null {\n try {\n return resolveConversationRunDir('scenario-runs', conversationId);\n } catch {\n return null;\n }\n}\n\nasync function appendNodeOutput(conversationId: string, node: ScenarioNode, output: string): Promise<void> {\n const dir = getScenarioRunDir(conversationId);\n if (!dir) return;\n\n const slug = node.label.toLowerCase().replace(/[^a-z0-9]+/g, '-').slice(0, 60) || 'member';\n const safeId = node.id.replace(/[^a-z0-9_-]/gi, '-').slice(0, 80);\n const filePath = join(dir, `${slug}_${safeId}.md`);\n\n const content = `## Output\\n\\n${output}\\n`;\n await atomicWriteSecure(filePath, content);\n}\n\nasync function appendToReadme(\n conversationId: string,\n bus: RunBus,\n text: string,\n): Promise<void> {\n const dir = getScenarioRunDir(conversationId);\n if (!dir) return;\n\n const line = `${text}\\n`;\n try {\n await mkdir(dir, { recursive: true });\n const { appendFile } = await import('node:fs/promises');\n await appendFile(join(dir, 'README.md'), line, 'utf-8');\n } catch {\n // Non-fatal — still publish the event even if disk write fails\n }\n publishToBus(bus, { type: 'readme_append', text: line });\n}\n\nasync function writeFinalMd(\n conversationId: string,\n bus: RunBus,\n userRequest: string,\n content: string,\n): Promise<void> {\n const dir = getScenarioRunDir(conversationId);\n if (!dir) return;\n\n const fullContent = `# Final Report\\n\\n## User Request\\n\\n> ${userRequest.replaceAll('\\n', '\\n> ')}\\n\\n---\\n\\n## Result\\n\\n${content}\\n`;\n\n const filePath = join(dir, 'FINAL.md');\n await atomicWriteSecure(filePath, fullContent);\n\n // Stream FINAL.md content as readme_append so UI sees it inline\n await appendToReadme(conversationId, bus,\n `\\n---\\n\\n## ✅ FINAL REPORT\\n\\n**User request:**\\n\\n> ${userRequest.replaceAll('\\n', '\\n> ')}\\n\\n${content}\\n`,\n );\n}\n\n// ─── Main orchestration ───────────────────────────────────────────────────────\n\n/**\n * Runs the scenario multi-agent workflow for a given conversation.\n * Execution order: BFS level by level (leader → direct reports → their reports, …).\n * Nodes at the same level run in parallel.\n * After all agents complete, the leader runs a synthesis pass.\n * All events are published to the run bus so late subscribers can reconnect.\n */\nfunction applyRunOverridesToScenario(\n scenario: Scenario,\n runOverrides?: ScenarioRunOverrides,\n): Scenario {\n if (!runOverrides?.runnerOverride && !runOverrides?.modelOverride?.trim()) return scenario;\n return {\n ...scenario,\n nodes: scenario.nodes.map((node) => {\n const { aiCli, model } = resolveNodeExecutionConfig(node, runOverrides);\n return { ...node, aiCli, model };\n }),\n };\n}\n\nexport async function runScenario(\n conversationId: string,\n scenarioId: string,\n userRequest: string,\n runOverrides?: ScenarioRunOverrides,\n resume?: boolean,\n): Promise<void> {\n if (isScenarioRunning(conversationId)) return;\n\n const bus = createBus(conversationId);\n const ctrl = new AbortController();\n activeAbortControllers.set(conversationId, ctrl);\n const signal = ctrl.signal;\n\n const publish = (evt: ScenarioEvent) => publishToBus(bus, evt);\n const readme = (text: string) => appendToReadme(conversationId, bus, text);\n // Bullet list item with automatic timestamp prefix: `- emoji [ts] rest`\n const li = (emoji: string, content: string) => readme(`- ${emoji} [${formatTs()}] ${content}\\n`);\n\n const ts = () => formatTs();\n const fmtDuration = (startMs: number) => {\n const ms = Math.max(0, Date.now() - startMs);\n const sec = ms / 1000;\n return sec < 10 ? `${sec.toFixed(1)}s` : `${Math.round(sec)}s`;\n };\n\n let finalWritten = false;\n\n async function execute() {\n try {\n const scenario: Scenario = await (async () => {\n const base = await scenarioRunStore.loadScenarioSnapshot(conversationId)\n // Les surcharges de run portent le projet visé, donc l'organisation\n // dont ce scénario relève.\n ?? await scenarioStore.get(scenarioId, runOverrides?.orgId ?? undefined);\n if (!base) throw new Error(`Scenario ${scenarioId} not found`);\n // Apply overrides in memory only — snapshot on disk stays clean\n return applyRunOverridesToScenario(base, runOverrides);\n })();\n const leader = scenario.nodes.find((p) => p.id === scenario.leaderId);\n if (!leader) throw new Error('Scenario has no leader');\n\n // Build parent→children map for hierarchy lookups\n const byParent = new Map<string, ScenarioNode[]>();\n const nodesById = new Map(scenario.nodes.map((p) => [p.id, p]));\n\n // outputs[nodeId] = full text output of that node\n const outputs = new Map<string, string>();\n let leaderDispatchOutput: string | null = null;\n let leaderDispatchAssignments: Map<string, string> = new Map();\n\n // Runner state per node — preserves session for ASK_USER continuations\n const runnerStates = new Map<string, NodeRunnerState>();\n\n // ── Resume: load persisted state and pre-populate outputs for done persons ──\n const persistedState = resume\n ? await scenarioRunStore.loadPersistedRunState(conversationId)\n : null;\n\n function isSubtreeComplete(nodeId: string): boolean {\n if (!persistedState) return false;\n const state = persistedState.nodeStates[nodeId];\n if (state !== 'done' && state !== 'synthesized') return false;\n for (const child of getDirectReports(scenario.nodes, nodeId)) {\n if (!isSubtreeComplete(child.id)) return false;\n }\n return true;\n }\n\n if (persistedState) {\n for (const [nodeId, output] of Object.entries(persistedState.nodeOutputs)) {\n const state = persistedState.nodeStates[nodeId];\n if (state === 'done' || state === 'synthesized') {\n outputs.set(nodeId, output);\n scenarioRunStore.setNodeState(conversationId, nodeId, state as NodeState);\n scenarioRunStore.setNodeOutput(conversationId, nodeId, output);\n }\n }\n }\n\n if (resume) {\n await readme(`\\n---\\n\\n## ♻️ Run resumed — ${ts()}\\n`);\n } else {\n await readme(`\\n## Run started — ${ts()}\\n\\n**User request:**\\n\\n> ${userRequest.replaceAll('\\n', '\\n> ')}\\n`);\n }\n\n // Resume: restore leader dispatch from cache if available\n let leaderDispatchHandled = false;\n if (persistedState && outputs.has(leader.id)) {\n const cachedOut = outputs.get(leader.id)!;\n leaderDispatchOutput = cachedOut;\n const leaderResult = selectExplicitDirectReportsFromOutput(leader, scenario.nodes, cachedOut);\n byParent.set(leader.id, leaderResult.selected);\n leaderDispatchAssignments = leaderResult.assignments;\n const leaderState = leaderResult.selected.length > 0 ? 'waiting' : 'done';\n scenarioRunStore.setNodeState(conversationId, leader.id, leaderState);\n publish({ type: 'node_state_change', nodeId: leader.id, state: leaderState });\n publish({ type: 'node_done', nodeId: leader.id, output: cachedOut, state: leaderState });\n await li('♻️', `**${leader.label}** (Leader) — restored from previous run`);\n leaderDispatchHandled = true;\n }\n\n // Leader dispatch phase — hierarchical mode only\n if (scenario.traversalMode !== 'topological' && !leaderDispatchHandled) {\n const startedAt = Date.now();\n publish({ type: 'node_started', nodeId: leader.id });\n scenarioRunStore.setNodeState(conversationId, leader.id, 'running');\n await readme(`### [${ts()}] 📋 ${leader.label} (Leader) — dispatching assignments\\n`);\n await li('▶️', `**${leader.label}** — started`);\n\n try {\n const systemPrompt = buildSystemPrompt(leader, scenario);\n const userMsg = buildUserMessage(leader, scenario, userRequest, null, false, true);\n const out = await runNodeCall(conversationId, leader, systemPrompt, userMsg, runOverrides, signal, publish, (delta) => {\n publish({ type: 'node_delta', nodeId: leader.id, text: delta });\n }, runnerStates, 'dispatch', readme);\n\n outputs.set(leader.id, out);\n leaderDispatchOutput = out;\n const hiredByLeader = applyHireDirectivesFromOutput(leader, scenario, out);\n if (hiredByLeader.length > 0) {\n await scenarioRunStore.saveScenarioSnapshot(conversationId, scenario);\n await li('🆕', `${leader.label} hired: ${hiredByLeader.map((p) => `${p.label} (${p.role})`).join(', ')}`);\n }\n const directReports = getDirectReports(scenario.nodes, leader.id);\n const leaderResult = selectExplicitDirectReportsFromOutput(leader, scenario.nodes, out);\n // Auto-include hired nodes not already named in NEXT_PERSON\n const seenIds = new Set(leaderResult.selected.map((r) => r.id));\n for (const h of hiredByLeader) { if (!seenIds.has(h.id)) { leaderResult.selected.push(h); seenIds.add(h.id); } }\n let assignedReports = leaderResult.selected;\n let leaderAssignments = leaderResult.assignments;\n let explicitStop = hasExplicitNoDelegationDecision(out);\n let finalLeaderOutput = out;\n const needsRetry = directReports.length > 0 && assignedReports.length === 0 && !explicitStop;\n const hasUnknown = leaderResult.unknownNames.length > 0;\n const hasMissingAssignments = leaderResult.missingAssignments.length > 0;\n if (needsRetry || hasUnknown || hasMissingAssignments) {\n if (hasUnknown) await li('⚠️', `Unknown node(s) named by ${leader.label}: ${leaderResult.unknownNames.join(', ')}. Retrying.`);\n else if (hasMissingAssignments) await li('⚠️', `Missing assignments for ${leaderResult.missingAssignments.join(', ')} from ${leader.label}. Retrying.`);\n else await li('⚠️', `No explicit assignees parsed for ${leader.label}. Retrying once to force explicit selection.`);\n const retryUserMsg = hasMissingAssignments\n ? buildMissingAssignmentsRetryMessage(leader, leaderResult.missingAssignments, out)\n : buildDelegationRetryMessage(leader, directReports, userRequest, out);\n // Fresh session for retry — --resume on a killed/early-exited process is unreliable\n runnerStates.delete(leader.id);\n const retryOut = await runNodeCall(conversationId, leader, systemPrompt, retryUserMsg, runOverrides, signal, publish, (delta) => {\n publish({ type: 'node_delta', nodeId: leader.id, text: delta });\n }, runnerStates, 'dispatch-retry', readme);\n const hiredOnRetry = applyHireDirectivesFromOutput(leader, scenario, retryOut);\n if (hiredOnRetry.length > 0) {\n await scenarioRunStore.saveScenarioSnapshot(conversationId, scenario);\n await li('🆕', `${leader.label} hired on retry: ${hiredOnRetry.map((p) => `${p.label} (${p.role})`).join(', ')}`);\n }\n const retryResult = selectExplicitDirectReportsFromOutput(leader, scenario.nodes, retryOut);\n const seenRetryIds = new Set(retryResult.selected.map((r) => r.id));\n for (const h of hiredOnRetry) { if (!seenRetryIds.has(h.id)) { retryResult.selected.push(h); seenRetryIds.add(h.id); } }\n assignedReports = retryResult.selected;\n leaderAssignments = new Map([...leaderAssignments, ...retryResult.assignments]);\n explicitStop = hasExplicitNoDelegationDecision(retryOut);\n finalLeaderOutput = `${out}\\n\\n## Delegation Retry Output\\n${retryOut}`;\n if (assignedReports.length === 0 && !explicitStop) {\n throw new Error(`No explicit assignees parsed for ${leader.label} after retry`);\n }\n if (assignedReports.length > 0) {\n await li('✅', `Explicit assignees parsed for ${leader.label} after retry.`);\n }\n }\n if (assignedReports.length === 0 && explicitStop) {\n await li('⏹️', `${leader.label} explicitly chose to delegate to nobody (STOP).`);\n }\n\n outputs.set(leader.id, finalLeaderOutput);\n leaderDispatchOutput = finalLeaderOutput;\n await appendNodeOutput(conversationId, leader, finalLeaderOutput);\n\n byParent.set(leader.id, assignedReports);\n scenarioRunStore.setNodeState(conversationId, leader.id, assignedReports.length > 0 ? 'waiting' : 'done');\n scenarioRunStore.setNodeOutput(conversationId, leader.id, finalLeaderOutput);\n await scenarioRunStore.persistRunState(conversationId);\n\n for (const report of assignedReports) {\n await li('→', `**${report.label}** assigned by ${leader.label}`);\n }\n leaderDispatchAssignments = leaderAssignments;\n await li('✅', `**${leader.label}** (Leader) — done in ${fmtDuration(startedAt)}`);\n publish({ type: 'node_done', nodeId: leader.id, output: finalLeaderOutput, state: scenarioRunStore.getRunState(conversationId)?.nodeStates[leader.id] ?? 'done' });\n } catch (err) {\n if (signal.aborted) throw err;\n const msg = (err as Error).message;\n scenarioRunStore.setNodeState(conversationId, leader.id, 'error');\n await readme(`### [${ts()}] ❌ ${leader.label} (Leader) — FAILED after ${fmtDuration(startedAt)}: ${msg}\\n`);\n publish({ type: 'node_error', nodeId: leader.id, error: msg });\n runnerStates.delete(leader.id);\n const leaderErrorOutput = `❌ Leader failed: ${msg}`;\n scenarioRunStore.setNodeOutput(conversationId, leader.id, leaderErrorOutput);\n await appendNodeOutput(conversationId, leader, leaderErrorOutput);\n publish({ type: 'node_delta', nodeId: leader.id, text: `\\n\\n${leaderErrorOutput}` });\n throw new Error(`Leader failed: ${msg}`);\n }\n }\n\n // Group execution with parent review loops:\n // manager executes -> children execute -> manager reviews and decides STOP or targeted re-run.\n async function runDelegationPass(\n node: ScenarioNode,\n userMsg: string,\n modeLabel: string,\n ): Promise<{ finalOutput: string; assignedReports: ScenarioNode[]; assignments: Map<string, string> }> {\n const startedAt = Date.now();\n publish({ type: 'node_started', nodeId: node.id });\n scenarioRunStore.setNodeState(conversationId, node.id, 'running');\n await li('▶️', `**${node.label}** — started`);\n try {\n const manager = node.parentIds[0] ? nodesById.get(node.parentIds[0]) ?? null : null;\n const systemPrompt = buildSystemPrompt(node, scenario);\n const out = await runNodeCall(conversationId, node, systemPrompt, userMsg, runOverrides, signal, publish, (delta) => {\n publish({ type: 'node_delta', nodeId: node.id, text: delta });\n }, runnerStates, modeLabel, readme);\n const hiredByNode = applyHireDirectivesFromOutput(node, scenario, out);\n if (hiredByNode.length > 0) {\n await scenarioRunStore.saveScenarioSnapshot(conversationId, scenario);\n await li('🆕', `${node.label} hired: ${hiredByNode.map((p) => `${p.label} (${p.role})`).join(', ')}`);\n }\n\n const directReports = getDirectReports(scenario.nodes, node.id);\n let nodeResult = selectExplicitDirectReportsFromOutput(node, scenario.nodes, out);\n const seenIds = new Set(nodeResult.selected.map((r) => r.id));\n for (const h of hiredByNode) { if (!seenIds.has(h.id)) { nodeResult.selected.push(h); seenIds.add(h.id); } }\n let assignedReports = nodeResult.selected;\n let assignments = nodeResult.assignments;\n let explicitStop = hasExplicitNoDelegationDecision(out);\n let finalOutput = out;\n const needsRetry = directReports.length > 0 && assignedReports.length === 0 && !explicitStop;\n const hasUnknown = nodeResult.unknownNames.length > 0;\n const hasMissingAssignments = nodeResult.missingAssignments.length > 0;\n if (needsRetry || hasUnknown || hasMissingAssignments) {\n if (hasUnknown) await li('⚠️', `Unknown node(s) named by ${node.label}: ${nodeResult.unknownNames.join(', ')}. Retrying.`);\n else if (hasMissingAssignments) await li('⚠️', `Missing assignments for ${nodeResult.missingAssignments.join(', ')} from ${node.label}. Retrying.`);\n else await li('⚠️', `No explicit assignees parsed for ${node.label}. Retrying once to force explicit selection.`);\n const retryUserMsg = hasMissingAssignments\n ? buildMissingAssignmentsRetryMessage(node, nodeResult.missingAssignments, out)\n : buildDelegationRetryMessage(node, directReports, userRequest, out);\n // Fresh session for retry — --resume on a killed/early-exited process is unreliable\n runnerStates.delete(node.id);\n const retryOut = await runNodeCall(conversationId, node, systemPrompt, retryUserMsg, runOverrides, signal, publish, (delta) => {\n publish({ type: 'node_delta', nodeId: node.id, text: delta });\n }, runnerStates, `${modeLabel}-retry`, readme);\n const hiredOnRetry = applyHireDirectivesFromOutput(node, scenario, retryOut);\n if (hiredOnRetry.length > 0) {\n await scenarioRunStore.saveScenarioSnapshot(conversationId, scenario);\n await li('🆕', `${node.label} hired on retry: ${hiredOnRetry.map((p) => `${p.label} (${p.role})`).join(', ')}`);\n }\n const retryResult = selectExplicitDirectReportsFromOutput(node, scenario.nodes, retryOut);\n const seenRetryIds = new Set(retryResult.selected.map((r) => r.id));\n for (const h of hiredOnRetry) { if (!seenRetryIds.has(h.id)) { retryResult.selected.push(h); seenRetryIds.add(h.id); } }\n assignedReports = retryResult.selected;\n assignments = new Map([...assignments, ...retryResult.assignments]);\n explicitStop = hasExplicitNoDelegationDecision(retryOut);\n finalOutput = `${out}\\n\\n## Delegation Retry Output\\n${retryOut}`;\n if (assignedReports.length === 0 && !explicitStop) {\n throw new Error(`No explicit assignees parsed for ${node.label} after retry`);\n }\n if (assignedReports.length > 0) {\n await li('✅', `Explicit assignees parsed for ${node.label} after retry.`);\n }\n }\n if (assignedReports.length === 0 && explicitStop) {\n await li('⏹️', `${node.label} explicitly chose to delegate to nobody (STOP).`);\n }\n\n outputs.set(node.id, finalOutput);\n await appendNodeOutput(conversationId, node, finalOutput);\n byParent.set(node.id, assignedReports);\n\n scenarioRunStore.setNodeState(conversationId, node.id, assignedReports.length > 0 ? 'waiting' : 'done');\n scenarioRunStore.setNodeOutput(conversationId, node.id, finalOutput);\n await scenarioRunStore.persistRunState(conversationId);\n\n if (assignedReports.length > 0) {\n for (const report of assignedReports) {\n await li('→', `**${report.label}** assigned by ${node.label}`);\n }\n }\n const reportTo = manager ? manager.label : 'Leader';\n await li('✅', `**${node.label}** (${node.role ?? 'other'}) — done in ${fmtDuration(startedAt)}, reporting to ${reportTo}`);\n publish({ type: 'node_done', nodeId: node.id, output: finalOutput, state: scenarioRunStore.getRunState(conversationId)?.nodeStates[node.id] ?? 'done' });\n return { finalOutput, assignedReports, assignments };\n } catch (err) {\n if (signal.aborted) throw err;\n const msg = (err as Error).message;\n scenarioRunStore.setNodeState(conversationId, node.id, 'error');\n await li('❌', `**${node.label}** — error after ${fmtDuration(startedAt)}: ${msg}`);\n publish({ type: 'node_error', nodeId: node.id, error: msg });\n // Reset runner state so next retry starts a fresh session\n runnerStates.delete(node.id);\n const errorOutput = `[ERROR: ${node.label} failed — ${msg}]\\n\\n${outputs.get(node.id) ?? ''}`.trim();\n outputs.set(node.id, errorOutput);\n scenarioRunStore.setNodeOutput(conversationId, node.id, errorOutput);\n await appendNodeOutput(conversationId, node, `\\n\\n❌ Error: ${msg}`);\n publish({ type: 'node_delta', nodeId: node.id, text: `\\n\\n❌ Error: ${msg}` });\n return { finalOutput: errorOutput, assignedReports: [], assignments: new Map() };\n }\n }\n\n async function runAskNode(node: ScenarioNode): Promise<string> {\n const question = node.question?.trim() || node.label || node.id;\n publish({ type: 'node_started', nodeId: node.id });\n scenarioRunStore.setNodeState(conversationId, node.id, 'waiting_input');\n scenarioRunStore.setWaitingInput(conversationId, node.id, question);\n publish({ type: 'node_waiting_input', nodeId: node.id, question });\n await readme(`- ❓ [${ts()}] **${node.label || node.id}** — waiting for user input\\n`);\n\n const answer = await new Promise<string>((resolve, reject) => {\n const key = pendingNodeKey(conversationId, node.id);\n pendingNodeInputs.set(key, resolve);\n signal.addEventListener('abort', () => {\n pendingNodeInputs.delete(key);\n reject(new Error('Aborted'));\n }, { once: true });\n });\n\n scenarioRunStore.clearWaitingInput(conversationId, node.id);\n await readme(`- 💬 [${ts()}] **User replied** to ${node.label || node.id}\\n`);\n const output = `**Question:** ${question}\\n\\n**Answer:** ${answer}`;\n scenarioRunStore.setNodeOutput(conversationId, node.id, output);\n outputs.set(node.id, output);\n scenarioRunStore.setNodeState(conversationId, node.id, 'done');\n publish({ type: 'node_done', nodeId: node.id, output, state: 'done' });\n return output;\n }\n\n async function runNodeSubtree(node: ScenarioNode, managerOutput: string | null): Promise<void> {\n // Ask node: skip AI entirely, wait for human input\n if (node.type === 'ask') {\n if (!isSubtreeComplete(node.id)) await runAskNode(node);\n else {\n publish({ type: 'node_state_change', nodeId: node.id, state: 'done' });\n publish({ type: 'node_done', nodeId: node.id, output: outputs.get(node.id) ?? '', state: 'done' });\n }\n return;\n }\n\n // Resume: skip entire subtree if all persons in it are done\n if (isSubtreeComplete(node.id)) {\n publish({ type: 'node_state_change', nodeId: node.id, state: 'done' });\n publish({ type: 'node_done', nodeId: node.id, output: outputs.get(node.id) ?? '', state: 'done' });\n return;\n }\n\n // Resume: if this node's own execution is cached but children aren't all done,\n // use cached output to derive delegation (skip the AI call for this node only)\n let firstPassResult: { finalOutput: string; assignedReports: ScenarioNode[]; assignments: Map<string, string> };\n if (persistedState && outputs.has(node.id)) {\n const cachedOut = outputs.get(node.id)!;\n const result = selectExplicitDirectReportsFromOutput(node, scenario.nodes, cachedOut);\n byParent.set(node.id, result.selected);\n const newState = result.selected.length > 0 ? 'waiting' : 'done';\n scenarioRunStore.setNodeState(conversationId, node.id, newState);\n scenarioRunStore.setNodeOutput(conversationId, node.id, cachedOut);\n publish({ type: 'node_state_change', nodeId: node.id, state: newState });\n publish({ type: 'node_done', nodeId: node.id, output: cachedOut, state: newState });\n await li('♻️', `**${node.label}** — restored from previous run`);\n firstPassResult = { finalOutput: cachedOut, assignedReports: result.selected, assignments: result.assignments };\n } else {\n const initialUserMsg = buildUserMessage(node, scenario, userRequest, managerOutput, false, false);\n firstPassResult = await runDelegationPass(node, initialUserMsg, '(execution)');\n }\n\n let { finalOutput, assignedReports, assignments } = firstPassResult;\n\n let reviewRound = 0;\n while (assignedReports.length > 0) {\n if (signal.aborted) throw new Error('Aborted');\n reviewRound += 1;\n if (reviewRound > MAX_MANAGER_REVIEW_ROUNDS) {\n throw new Error(`${node.label} exceeded review loop limit (${MAX_MANAGER_REVIEW_ROUNDS})`);\n }\n\n await readme(`\\n### [${ts()}] Review loop ${reviewRound} for ${node.label} — collecting child reports\\n`);\n await Promise.all(assignedReports.map((report) => {\n const instruction = assignments.get(report.id) ?? null;\n return runNodeSubtree(report, instruction ?? finalOutput);\n }));\n\n const childReportsSection = assignedReports\n .map((report) => {\n const reportOut = outputs.get(report.id) ?? '';\n return `<child_report node=\"${report.label}\" id=\"${report.id}\">\\n${reportOut}\\n</child_report>`;\n })\n .join('\\n\\n');\n\n const reviewUserMsg = buildManagerReviewMessage(\n node,\n getDirectReports(scenario.nodes, node.id),\n userRequest,\n finalOutput,\n childReportsSection,\n );\n const pass = await runDelegationPass(node, reviewUserMsg, `(review round ${reviewRound})`);\n finalOutput = pass.finalOutput;\n assignedReports = pass.assignedReports;\n assignments = pass.assignments;\n }\n }\n\n if (scenario.traversalMode === 'topological') {\n // ── Topological mode: level-by-level, siblings run in parallel ──\n // Helper: get all parent IDs of a node (parentId + parentIds)\n const allParentIds = (n: ScenarioNode): string[] => n.parentIds ?? [];\n // Helper: get all children of a node (nodes that list it as any parent)\n const allChildren = (nodeId: string): ScenarioNode[] =>\n scenario.nodes.filter((n) => allParentIds(n).includes(nodeId));\n\n // Build levels: a node's level = max(parent levels) + 1\n const nodeLevelMap = new Map<string, number>();\n nodeLevelMap.set(leader.id, 0);\n // BFS to assign levels\n const bfsQueue: ScenarioNode[] = [leader];\n while (bfsQueue.length > 0) {\n const cur = bfsQueue.shift()!;\n const curLevel = nodeLevelMap.get(cur.id) ?? 0;\n for (const child of allChildren(cur.id)) {\n const newLevel = curLevel + 1;\n const existing = nodeLevelMap.get(child.id) ?? -1;\n if (newLevel > existing) {\n nodeLevelMap.set(child.id, newLevel);\n bfsQueue.push(child);\n }\n }\n }\n // Group nodes by level\n const maxLevel = Math.max(...nodeLevelMap.values());\n const levels: ScenarioNode[][] = Array.from({ length: maxLevel + 1 }, () => []);\n for (const node of scenario.nodes) {\n const lvl = nodeLevelMap.get(node.id);\n if (lvl !== undefined) levels[lvl].push(node);\n }\n\n const runTopoNode = async (node: ScenarioNode) => {\n if (signal.aborted) throw new Error('Aborted');\n\n // Ask node: skip AI entirely, wait for human input\n if (node.type === 'ask') {\n if (persistedState && outputs.has(node.id)) {\n scenarioRunStore.setNodeState(conversationId, node.id, 'done');\n scenarioRunStore.setNodeOutput(conversationId, node.id, outputs.get(node.id)!);\n publish({ type: 'node_state_change', nodeId: node.id, state: 'done' });\n publish({ type: 'node_done', nodeId: node.id, output: outputs.get(node.id)!, state: 'done' });\n await li('♻️', `**${node.label}** — restored from previous run`);\n } else {\n await runAskNode(node);\n }\n return;\n }\n\n // Resume: skip already-done nodes\n if (persistedState && outputs.has(node.id)) {\n const cached = outputs.get(node.id)!;\n scenarioRunStore.setNodeState(conversationId, node.id, 'done');\n scenarioRunStore.setNodeOutput(conversationId, node.id, cached);\n publish({ type: 'node_state_change', nodeId: node.id, state: 'done' });\n publish({ type: 'node_done', nodeId: node.id, output: cached, state: 'done' });\n await li('♻️', `**${node.label}** — restored from previous run`);\n return;\n }\n\n const startedAt = Date.now();\n publish({ type: 'node_started', nodeId: node.id });\n scenarioRunStore.setNodeState(conversationId, node.id, 'running');\n await readme(`### [${ts()}] ▶️ ${node.label} — started\\n`);\n await li('▶️', `**${node.label}** — started`);\n\n try {\n const parentOutput = node.parentIds[0] ? outputs.get(node.parentIds[0]) ?? null : null;\n const systemPrompt = buildSystemPrompt(node, scenario);\n const userMsg = buildUserMessage(node, scenario, userRequest, parentOutput, false, false, new Map(outputs));\n const out = await runNodeCall(conversationId, node, systemPrompt, userMsg, runOverrides, signal, publish, (delta) => {\n publish({ type: 'node_delta', nodeId: node.id, text: delta });\n }, runnerStates, '(topological)', readme);\n\n outputs.set(node.id, out);\n scenarioRunStore.setNodeState(conversationId, node.id, 'done');\n scenarioRunStore.setNodeOutput(conversationId, node.id, out);\n await scenarioRunStore.persistRunState(conversationId);\n await appendNodeOutput(conversationId, node, out);\n await li('✅', `**${node.label}** — done in ${fmtDuration(startedAt)}`);\n publish({ type: 'node_done', nodeId: node.id, output: out, state: 'done' });\n } catch (err) {\n if (signal.aborted) throw err;\n const msg = (err as Error).message;\n scenarioRunStore.setNodeState(conversationId, node.id, 'error');\n await readme(`### [${ts()}] ❌ ${node.label} — FAILED after ${fmtDuration(startedAt)}: ${msg}\\n`);\n publish({ type: 'node_error', nodeId: node.id, error: msg });\n runnerStates.delete(node.id);\n throw new Error(`${node.label} failed: ${msg}`);\n }\n };\n\n for (const level of levels) {\n // Run all nodes in the same level in parallel, wait before next level\n await Promise.all(level.map(runTopoNode));\n }\n } else {\n // ── Hierarchical mode: leader review loops + recursive subtree runs ──\n let leaderAssignedReports = byParent.get(leader.id) ?? [];\n let leaderCurrentOutput = leaderDispatchOutput ?? outputs.get(leader.id) ?? '';\n let leaderAssignments: Map<string, string> = leaderDispatchAssignments;\n let leaderReviewRound = 0;\n\n while (leaderAssignedReports.length > 0) {\n if (signal.aborted) throw new Error('Aborted');\n leaderReviewRound += 1;\n if (leaderReviewRound > MAX_MANAGER_REVIEW_ROUNDS) {\n throw new Error(`${leader.label} exceeded review loop limit (${MAX_MANAGER_REVIEW_ROUNDS})`);\n }\n\n await readme(`\\n### [${ts()}] Leader review loop ${leaderReviewRound} — running assigned children in parallel\\n`);\n await Promise.all(leaderAssignedReports.map((report) => {\n const instruction = leaderAssignments.get(report.id) ?? null;\n return runNodeSubtree(report, instruction ?? leaderCurrentOutput);\n }));\n\n const leaderChildReportsSection = leaderAssignedReports\n .map((report) => {\n const reportOut = outputs.get(report.id) ?? '';\n return `<child_report node=\"${report.label}\" id=\"${report.id}\">\\n${reportOut}\\n</child_report>`;\n })\n .join('\\n\\n');\n\n const leaderReviewMsg = buildManagerReviewMessage(\n leader,\n getDirectReports(scenario.nodes, leader.id),\n userRequest,\n leaderCurrentOutput,\n leaderChildReportsSection,\n );\n const leaderPass = await runDelegationPass(leader, leaderReviewMsg, `(leader review round ${leaderReviewRound})`);\n leaderCurrentOutput = leaderPass.finalOutput;\n leaderDispatchOutput = leaderCurrentOutput;\n leaderAssignedReports = leaderPass.assignedReports;\n leaderAssignments = leaderPass.assignments;\n }\n\n resolveWaitingStates(scenario.nodes, conversationId, byParent, publish, new Set([scenario.leaderId]));\n }\n\n // ── Phase 2: Leader synthesis → writes FINAL.md ────────────────────────\n const synthesisKey = `${leader.id}:synthesis`;\n const synthesisAlreadyDone = persistedState?.nodeStates[synthesisKey] === 'synthesized'\n && !!persistedState?.nodeOutputs[synthesisKey];\n\n if (synthesisAlreadyDone) {\n const summary = persistedState!.nodeOutputs[synthesisKey]!;\n await writeFinalMd(conversationId, bus, userRequest, summary);\n finalWritten = true;\n scenarioRunStore.setNodeState(conversationId, leader.id, 'done');\n publish({ type: 'node_state_change', nodeId: leader.id, state: 'done' });\n scenarioRunStore.setNodeState(conversationId, synthesisKey, 'synthesized');\n publish({ type: 'node_state_change', nodeId: synthesisKey, state: 'synthesized' });\n publish({ type: 'scenario_complete', summary });\n await li('♻️', `Synthesis restored from previous run`);\n } else if (scenario.nodes.length > 1) {\n const startedAt = Date.now();\n publish({ type: 'node_started', nodeId: `${leader.id}:synthesis` });\n await readme(`\\n### [${ts()}] 🔄 ${leader.label} (Leader) — synthesizing all outputs\\n`);\n await li('▶️', `**${leader.label}** synthesis — started`);\n\n try {\n const systemPrompt = buildSystemPrompt(leader, scenario);\n const userMsg = buildUserMessage(leader, scenario, userRequest, null, true, false, outputs);\n\n let summary = '';\n summary = await runNodeCall(conversationId, leader, systemPrompt, userMsg, runOverrides, signal, publish, (delta) => {\n publish({ type: 'node_delta', nodeId: `${leader.id}:synthesis`, text: delta });\n }, runnerStates, 'synthesis', readme);\n\n await writeFinalMd(conversationId, bus, userRequest, summary);\n finalWritten = true;\n\n // Leader completion condition: FINAL.md has been written.\n scenarioRunStore.setNodeState(conversationId, leader.id, 'done');\n publish({ type: 'node_state_change', nodeId: leader.id, state: 'done' });\n\n scenarioRunStore.setNodeState(conversationId, `${leader.id}:synthesis`, 'synthesized');\n scenarioRunStore.setNodeOutput(conversationId, `${leader.id}:synthesis`, summary);\n await scenarioRunStore.persistRunState(conversationId);\n\n await li('✅', `**${leader.label}** synthesis — done in ${fmtDuration(startedAt)}`);\n publish({ type: 'node_done', nodeId: `${leader.id}:synthesis`, output: summary, state: 'synthesized' });\n publish({ type: 'scenario_complete', summary });\n } catch (err) {\n if (signal.aborted) throw err;\n // Synthesis failed — write FINAL.md with what we have as fallback\n const fallback = [...outputs.entries()]\n .map(([id, out]) => {\n const p = scenario.nodes.find(x => x.id === id);\n const name = p ? p.label.trim() : id;\n return `### ${name}\\n\\n${out}`;\n })\n .join('\\n\\n---\\n\\n');\n await readme(`\\n⚠️ Leader synthesis failed — writing partial FINAL.md\\n`);\n await li('❌', `**${leader.label}** synthesis — failed after ${fmtDuration(startedAt)}`);\n await writeFinalMd(conversationId, bus, userRequest, fallback);\n finalWritten = true;\n // Leader completion condition: FINAL.md has been written.\n scenarioRunStore.setNodeState(conversationId, leader.id, 'done');\n publish({ type: 'node_state_change', nodeId: leader.id, state: 'done' });\n publish({ type: 'scenario_complete', summary: fallback });\n }\n } else {\n // Solo leader — their output IS the final\n const summary = leaderDispatchOutput ?? outputs.get(leader.id) ?? '';\n await writeFinalMd(conversationId, bus, userRequest, summary);\n finalWritten = true;\n // Leader completion condition: FINAL.md has been written.\n scenarioRunStore.setNodeState(conversationId, leader.id, 'done');\n publish({ type: 'node_state_change', nodeId: leader.id, state: 'done' });\n publish({ type: 'scenario_complete', summary });\n }\n } catch (err) {\n if (!signal.aborted) {\n const msg = (err as Error).message;\n // Guard: if we exit without FINAL.md, report it explicitly\n if (!finalWritten) {\n await appendToReadme(conversationId, bus,\n `\\n### [${ts()}] 🚨 GUARD: Run ended without FINAL.md — ${msg}\\n`,\n ).catch(() => {/* non-fatal */});\n }\n publish({ type: 'scenario_error', error: msg });\n }\n } finally {\n if (!finalWritten && !signal.aborted) {\n // Secondary guard: bus closing without FINAL.md written\n await appendToReadme(conversationId, bus,\n `\\n### [${ts()}] 🚨 GUARD: No FINAL.md detected at end of run. Check individual agent outputs.\\n`,\n ).catch(() => {/* non-fatal */});\n }\n // Final persist: capture any state changes (solo-leader done, synthesis\n // fallback, last-second updates) so a reload after completion shows the\n // finished scenario instead of a fresh-looking one.\n await scenarioRunStore.persistRunState(conversationId).catch(() => {/* non-fatal */});\n publishToBus(bus, null); // signal end-of-stream\n activeAbortControllers.delete(conversationId);\n }\n }\n\n // Fire-and-forget — run asynchronously so callers can subscribe immediately\n execute().catch(() => {/* errors published to bus */});\n}\n","import type { ScenarioPreset } from '@runeya/packages-shared';\n\nconst BUILT_IN_PRESETS: ScenarioPreset[] = [\n {\n id: 'enterprise',\n name: 'Enterprise',\n icon: 'pi-building',\n labels: {\n group: { en: 'Department', fr: 'Département' },\n node: { en: 'Employee', fr: 'Employé' },\n role: { en: 'Position', fr: 'Poste' },\n leader: { en: 'Director', fr: 'Directeur' },\n },\n defaultTraversalMode: 'hierarchical',\n canChangeTraversalMode: false,\n initialData: {\n leaderId: 'leader',\n groups: [\n { id: 'group-management', name: 'Management', position: { x: 0, y: 0 }, width: 300, height: 200 },\n ],\n nodes: [\n {\n id: 'leader',\n type: 'ai' as const,\n parentIds: [],\n groupId: 'group-management',\n label: 'Leader One',\n role: 'manager',\n prompt: 'Analyze the objective. Break it into concrete tasks and assign each to the right team member with a clear expected output. Do not do the technical work yourself.',\n question: '',\n autoGenerated: false,\n canAddNode: false,\n aiCli: 'claude-code',\n model: 'sonnet',\n position: { x: 50, y: 50 },\n },\n ],\n },\n roles: [\n {\n id: 'manager',\n name: 'Manager',\n systemPrompt: [\n 'You are a MANAGER. Your only job is to coordinate, plan, and delegate.',\n 'NEVER write code, scripts, or any technical artifact — not even as an example.',\n 'NEVER answer a technical question directly — always assign it to the right person.',\n 'Output only: task breakdowns, assignments, decisions, and synthesis.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'engineer',\n name: 'Engineer',\n systemPrompt: [\n 'You are an ENGINEER. Write working, production-ready code.',\n 'Always prefer real implementation over pseudocode or high-level descriptions.',\n 'Be concise in prose; let the code speak.',\n 'Output: source files, architecture decisions, technical specifications.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'designer',\n name: 'Designer',\n systemPrompt: [\n 'You are a DESIGNER. Define UX flows, visual hierarchy, and interaction patterns.',\n 'NEVER write code or CSS.',\n 'Describe interfaces in structured text: component name, layout, states, behavior.',\n 'Output: text wireframes, design decisions, component specs, UX guidelines.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'analyst',\n name: 'Analyst',\n systemPrompt: [\n 'You are an ANALYST. Investigate data, identify patterns, and surface actionable insights.',\n 'NEVER write code or scripts — if you need data processed, request it from an Engineer.',\n 'Output: structured analysis, metrics, findings, and evidence-based recommendations.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'qa',\n name: 'QA',\n systemPrompt: [\n 'You are a QA ENGINEER. Define what must be tested and how.',\n 'NEVER write implementation code.',\n 'You may write Gherkin / BDD scenarios or structured test cases as plain text.',\n 'Output: test plans, test cases, edge cases, risk assessments, acceptance criteria.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'devops',\n name: 'DevOps',\n systemPrompt: [\n 'You are a DEVOPS ENGINEER. Own infrastructure, deployment, and operations.',\n 'Write actual scripts and configuration files (shell, YAML, HCL, Dockerfile…) — no pseudocode.',\n 'Output: scripts, CI/CD pipelines, infrastructure-as-code, runbooks.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'product',\n name: 'Product',\n systemPrompt: [\n 'You are a PRODUCT MANAGER. Own requirements and priorities.',\n 'NEVER write code or technical specifications.',\n 'Output: PRDs, user stories with acceptance criteria, prioritization decisions, roadmap items.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'writer',\n name: 'Writer',\n systemPrompt: [\n 'You are a TECHNICAL WRITER. Produce clear, accurate, well-structured written content.',\n 'NEVER write code. If a code example is needed, flag it for an Engineer.',\n 'Output: documentation, guides, release notes, changelogs, communication drafts.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'researcher',\n name: 'Researcher',\n systemPrompt: [\n 'You are a RESEARCHER. Gather information, compare options, and synthesize knowledge into actionable insights.',\n 'NEVER write code.',\n 'Output: research summaries, comparisons, pros/cons analyses, evidence-based recommendations.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'other',\n name: 'Other',\n systemPrompt: '',\n prompt: '',\n },\n ],\n },\n];\n\nexport function listPresets(): ScenarioPreset[] {\n return BUILT_IN_PRESETS;\n}\n\nexport function getPreset(id: string): ScenarioPreset | undefined {\n return BUILT_IN_PRESETS.find(p => p.id === id);\n}\n","import { randomUUID } from 'node:crypto';\nimport { TRPCError } from '@trpc/server';\nimport { z } from 'zod';\nimport { protectedProcedure, router } from '../trpc.js';\n\ntype RandomTickEvent = {\n type: 'tick';\n jobId: string;\n index: number;\n value: number;\n at: number;\n};\n\ntype RandomDoneEvent = {\n type: 'done';\n jobId: string;\n reason: 'stopped' | 'max_ticks';\n at: number;\n};\n\ntype RandomJobEvent = RandomTickEvent | RandomDoneEvent;\n\ninterface RandomJob {\n id: string;\n startedAt: number;\n intervalMs: number;\n maxTicks: number;\n tick: number;\n done: boolean;\n timer: ReturnType<typeof setInterval>;\n buffer: RandomJobEvent[];\n baseIndex: number;\n listeners: Set<(event: RandomJobEvent | null) => void>;\n}\n\nconst MAX_BUFFER = 300;\nconst jobs = new Map<string, RandomJob>();\n\nfunction publish(job: RandomJob, event: RandomJobEvent | null): void {\n if (event) {\n job.buffer.push(event);\n if (job.buffer.length > MAX_BUFFER) {\n job.buffer.shift();\n job.baseIndex += 1;\n }\n } else {\n job.done = true;\n }\n\n for (const listener of job.listeners) listener(event);\n job.listeners.clear();\n}\n\nfunction stopJob(jobId: string, reason: 'stopped' | 'max_ticks'): boolean {\n const job = jobs.get(jobId);\n if (!job) return false;\n if (job.done) return true;\n\n clearInterval(job.timer);\n publish(job, { type: 'done', jobId, reason, at: Date.now() });\n publish(job, null);\n jobs.delete(jobId);\n return true;\n}\n\nasync function* tapJob(job: RandomJob, signal: AbortSignal): AsyncGenerator<RandomJobEvent> {\n let cursor = job.baseIndex;\n\n while (true) {\n if (cursor < job.baseIndex) cursor = job.baseIndex;\n while (cursor < job.baseIndex + job.buffer.length) {\n const evt = job.buffer[cursor - job.baseIndex];\n cursor += 1;\n if (!evt) continue;\n yield evt;\n }\n\n if (job.done || signal.aborted) return;\n\n await new Promise<void>((resolve) => {\n const onAbort = () => {\n job.listeners.delete(notify);\n resolve();\n };\n\n const notify = () => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n };\n\n job.listeners.add(notify);\n signal.addEventListener('abort', onAbort, { once: true });\n if (cursor < job.baseIndex + job.buffer.length || job.done || signal.aborted) {\n job.listeners.delete(notify);\n signal.removeEventListener('abort', onAbort);\n resolve();\n }\n });\n }\n}\n\nexport const debugRouter = router({\n startRandomJob: protectedProcedure\n .input(z.object({\n intervalMs: z.number().int().min(100).max(5000).optional(),\n maxTicks: z.number().int().min(1).max(10000).optional(),\n }).optional())\n .mutation(({ input }) => {\n const jobId = randomUUID();\n const intervalMs = input?.intervalMs ?? 400;\n const maxTicks = input?.maxTicks ?? 500;\n\n const job: RandomJob = {\n id: jobId,\n startedAt: Date.now(),\n intervalMs,\n maxTicks,\n tick: 0,\n done: false,\n timer: setInterval(() => {\n const current = jobs.get(jobId);\n if (!current || current.done) return;\n\n current.tick += 1;\n publish(current, {\n type: 'tick',\n jobId,\n index: current.tick,\n value: Math.random(),\n at: Date.now(),\n });\n\n if (current.tick >= current.maxTicks) {\n stopJob(jobId, 'max_ticks');\n }\n }, intervalMs),\n buffer: [],\n baseIndex: 0,\n listeners: new Set(),\n };\n\n jobs.set(jobId, job);\n return { jobId, intervalMs, maxTicks, startedAt: job.startedAt };\n }),\n\n streamRandomJob: protectedProcedure\n .input(z.object({ jobId: z.string().max(128) }))\n .subscription(async function* ({ input, signal }) {\n const job = jobs.get(input.jobId);\n if (!job) {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'Random job not found' });\n }\n\n yield* tapJob(job, signal ?? new AbortController().signal);\n }),\n\n stopRandomJob: protectedProcedure\n .input(z.object({ jobId: z.string().max(128) }))\n .mutation(({ input }) => ({ ok: stopJob(input.jobId, 'stopped') })),\n\n randomJobStatus: protectedProcedure\n .input(z.object({ jobId: z.string().max(128) }))\n .query(({ input }) => {\n const job = jobs.get(input.jobId);\n return {\n running: !!job && !job.done,\n tick: job?.tick ?? 0,\n };\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { protectedProcedure, router } from '../trpc.js';\nimport { recentEntries, entriesSince, onEntry, type LogEntry } from '../../services/log-buffer.js';\nimport { listInstances, killInstance, restartInstance, scheduleSelfRestart } from '../../services/instance-registry.js';\n\n/**\n * Live view of what this Runeya is doing, and of the other Runeya instances\n * sharing the machine.\n *\n * Everything here is `protectedProcedure`: the log stream carries whatever the\n * server and agent print, which routinely includes paths, project names and\n * command lines. It is diagnostic data, not public data.\n */\nexport const diagnosticsRouter = router({\n /** Backlog for a client that just opened the panel. */\n recentLogs: protectedProcedure\n .input(z.object({ limit: z.number().int().min(1).max(2000).default(500) }).optional())\n .query(({ input }) => recentEntries(input?.limit ?? 500)),\n\n /**\n * Live log stream.\n *\n * `afterSeq` lets a reconnecting client ask for what it missed instead of\n * restarting from an arbitrary window — without it, a dropped WebSocket\n * silently loses lines, which is precisely what someone watching a boot\n * failure cannot afford.\n */\n streamLogs: protectedProcedure\n .input(z.object({ afterSeq: z.number().int().nonnegative().default(0) }).optional())\n .subscription(async function* ({ input, signal }) {\n // Replay first, so nothing between the query and the subscription is lost.\n for (const entry of entriesSince(input?.afterSeq ?? 0)) yield entry;\n\n const queue: LogEntry[] = [];\n let wake: (() => void) | null = null;\n\n const off = onEntry((entry) => {\n queue.push(entry);\n wake?.();\n });\n\n try {\n while (!signal?.aborted) {\n if (queue.length === 0) {\n await new Promise<void>((resolve) => {\n wake = resolve;\n // Wake on abort too, otherwise an idle stream would hold the\n // generator open until the next line — which may never come.\n signal?.addEventListener('abort', () => resolve(), { once: true });\n });\n wake = null;\n continue;\n }\n yield queue.shift()!;\n }\n } finally {\n off();\n }\n }),\n\n /** Every Runeya answering on this machine, this one included. */\n instances: protectedProcedure.query(() => listInstances()),\n\n /**\n * Stop another Runeya on this machine — its agent first, then its server.\n *\n * The pid is a *selector*, not an instruction: it is looked up in the list\n * `listInstances()` has just vouched for, and anything absent from it is\n * refused. That is what keeps this from being a way to signal arbitrary\n * processes with the server's privileges.\n */\n killInstance: protectedProcedure\n .input(z.object({ pid: z.number().int().positive() }))\n .mutation(async ({ input }) => {\n try {\n return await killInstance(input.pid);\n } catch (err) {\n const reason = (err as Error).message;\n if (reason === 'instance-not-found') {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'No live Runeya instance with this pid.' });\n }\n if (reason === 'instance-is-current') {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'This instance cannot stop itself.' });\n }\n throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: reason });\n }\n }),\n\n /**\n * Redémarrer une Runeya de cette machine : même exécutable, mêmes arguments,\n * même répertoire, mêmes `RUNEYA_*`.\n *\n * Deux chemins pour une même promesse. Une autre instance est arrêtée puis\n * relancée d'ici, et la réponse dit ce qui s'est passé. Celle-ci ne peut pas :\n * elle répond d'abord, pose un relanceur détaché, et part — d'où un résultat\n * qui annonce un redémarrage à venir plutôt qu'un redémarrage fait.\n *\n * Mêmes garde-fous que `killInstance` — le pid est un sélecteur cherché dans\n * la liste validée — plus un refus propre quand le lancement n'est pas\n * reproductible : instance trop ancienne pour avoir publié sa ligne de\n * commande, ou lancée avec un secret que le registre ne conserve pas.\n */\n restartInstance: protectedProcedure\n .input(z.object({ pid: z.number().int().positive() }))\n .mutation(async ({ input }) => {\n try {\n if (input.pid === process.pid) {\n const { relauncherPid, port } = await scheduleSelfRestart();\n return { self: true as const, relauncherPid, port };\n }\n return { self: false as const, ...await restartInstance(input.pid) };\n } catch (err) {\n const reason = (err as Error).message;\n if (reason === 'instance-not-found') {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'No live Runeya instance with this pid.' });\n }\n if (reason.startsWith('instance-not-restartable:')) {\n throw new TRPCError({\n code: 'BAD_REQUEST',\n message: `This instance cannot be restarted (${reason.split(':')[1]}).`,\n });\n }\n throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: reason });\n }\n }),\n});\n","import { EventEmitter } from 'node:events';\n\n/**\n * In-memory ring buffer of everything this Runeya instance writes.\n *\n * The agent does not log to a file or a socket of its own: `agent-spawner`\n * reads its stdout line by line and re-emits it through the server's console\n * with an `[agent]` prefix. So capturing the server process's own output\n * captures both, and there is exactly one place to tap.\n *\n * The capture is a tee, never a filter: whatever was going to the terminal\n * still goes there. A developer running `runeya` in a shell must see exactly\n * what they saw before this existed.\n */\n\nexport type LogSource = 'server' | 'agent';\nexport type LogLevel = 'info' | 'warn' | 'error';\n\nexport type LogEntry = {\n /** Monotonic within a process; used by clients to de-duplicate on reconnect. */\n seq: number;\n at: number;\n source: LogSource;\n level: LogLevel;\n text: string;\n};\n\n/**\n * Roughly a full boot plus a long tail of activity. Bounded because this is a\n * diagnostic convenience, not a log store — anyone who needs history should be\n * redirecting the process output to a file.\n */\nconst MAX_ENTRIES = 2_000;\nconst MAX_TEXT_LENGTH = 4_000;\n\nconst entries: LogEntry[] = [];\nconst emitter = new EventEmitter();\n// Every open subscription attaches a listener; the default cap of 10 would warn\n// as soon as a few tabs watch the stream.\nemitter.setMaxListeners(0);\n\nlet seq = 0;\nlet installed = false;\n\n/** Lines the agent-spawner re-emits carry this prefix. */\nconst AGENT_PREFIX = '[agent] ';\n\n/**\n * Classify a line without pretending to parse it.\n *\n * stderr is not evidence of an error — plenty of tools write progress there —\n * so the stream only sets the floor, and the content can raise it.\n */\nexport function classify(line: string, stream: 'stdout' | 'stderr'): { source: LogSource; level: LogLevel; text: string } {\n const isAgent = line.startsWith(AGENT_PREFIX);\n const text = isAgent ? line.slice(AGENT_PREFIX.length) : line;\n\n let level: LogLevel = stream === 'stderr' ? 'warn' : 'info';\n // Word boundaries matter on the ASCII words: \"terrorism\" contains \"error\",\n // and a service with that in its name should not glow red. `\\b` is\n // ASCII-based though, so it never matches before an accented letter —\n // the French words are therefore matched without it.\n if (/\\b(error|fatal|failed|exception)\\b/i.test(text)\n || /(échec|erreur)/i.test(text)\n || text.includes('❌')) {\n level = 'error';\n } else if (/\\bwarn(ing)?\\b/i.test(text) || text.includes('⚠')) {\n level = 'warn';\n }\n\n return { source: isAgent ? 'agent' : 'server', level, text };\n}\n\nfunction push(line: string, stream: 'stdout' | 'stderr'): void {\n const { source, level, text } = classify(line, stream);\n const entry: LogEntry = {\n seq: ++seq,\n at: Date.now(),\n source,\n level,\n text: text.length > MAX_TEXT_LENGTH ? `${text.slice(0, MAX_TEXT_LENGTH)}…` : text,\n };\n\n entries.push(entry);\n if (entries.length > MAX_ENTRIES) entries.splice(0, entries.length - MAX_ENTRIES);\n emitter.emit('entry', entry);\n}\n\n/**\n * Start capturing. Idempotent: calling it twice would otherwise wrap the\n * already-wrapped `write` and record every line as many times as it was\n * installed.\n */\nexport function installLogCapture(): void {\n if (installed) return;\n installed = true;\n\n for (const [stream, name] of [\n [process.stdout, 'stdout'],\n [process.stderr, 'stderr'],\n ] as const) {\n const original = stream.write.bind(stream);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stream.write = ((chunk: any, encoding?: any, callback?: any) => {\n try {\n const text = typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf8');\n // Split on \\n and drop a trailing \\r: Windows tools emit CRLF, and the\n // stray carriage return would otherwise ride along into the UI.\n for (const raw of text.split('\\n')) {\n const line = raw.endsWith('\\r') ? raw.slice(0, -1) : raw;\n if (line.trim() !== '') push(line, name);\n }\n } catch {\n // Capturing must never be the reason a write fails\n }\n return original(chunk, encoding, callback);\n }) as typeof stream.write;\n }\n}\n\n/** The last `limit` entries, oldest first. */\nexport function recentEntries(limit = 500): LogEntry[] {\n return entries.slice(-Math.max(1, Math.min(limit, MAX_ENTRIES)));\n}\n\n/** Entries recorded after `afterSeq`, for a client catching up after a reconnect. */\nexport function entriesSince(afterSeq: number): LogEntry[] {\n return entries.filter((e) => e.seq > afterSeq);\n}\n\nexport function onEntry(listener: (entry: LogEntry) => void): () => void {\n emitter.on('entry', listener);\n return () => emitter.off('entry', listener);\n}\n","import { z } from 'zod';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { kanbanQueue } from '../../services/kanban-queue.js';\nimport type { KanbanQueueState } from '../../services/kanban-queue.js';\n\nexport const kanbanQueueRouter = router({\n getState: protectedProcedure.query(() => kanbanQueue.getState()),\n\n add: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n cardId: z.string().max(128),\n runner: z.enum(['claude-code', 'codex']).optional(),\n model: z.string().max(128).optional(),\n scenarioId: z.string().max(128).optional(),\n // Le projet ouvert quand la carte a été mise en file : la conversation\n // qui en naîtra lui appartient, plutôt que de rester orpheline et de\n // s'afficher dans tous les projets.\n projectId: z.string().max(128).optional(),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .mutation(({ input }) => kanbanQueue.add(input)),\n\n addColumn: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n columnId: z.string().max(128),\n // Les cartes visibles côté écran : une colonne filtrée n'envoie qu'elles.\n cardIds: z.array(z.string().max(128)).max(5000).optional(),\n runner: z.enum(['claude-code', 'codex']).optional(),\n model: z.string().max(128).optional(),\n scenarioId: z.string().max(128).optional(),\n projectId: z.string().max(128).optional(),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .mutation(async ({ input }) => {\n const { boardId, columnId, ...options } = input;\n return kanbanQueue.addColumn(boardId, columnId, options);\n }),\n\n remove: protectedProcedure\n .input(z.object({ itemId: z.string().max(128) }))\n .mutation(({ input }) => ({ removed: kanbanQueue.remove(input.itemId) })),\n\n stopAll: protectedProcedure\n .mutation(() => { kanbanQueue.stopAll(); return { ok: true }; }),\n\n setMaxConcurrent: protectedProcedure\n .input(z.object({ max: z.number().int().min(1).max(20) }))\n .mutation(({ input }) => { kanbanQueue.setMaxConcurrent(input.max); return kanbanQueue.getState(); }),\n\n onChanged: protectedProcedure.subscription(async function* () {\n const queue: KanbanQueueState[] = [];\n let resolve: (() => void) | null = null;\n\n const handler = () => {\n if (queue.length >= 50) queue.shift();\n queue.push(kanbanQueue.getState());\n if (resolve) { resolve(); resolve = null; }\n };\n\n kanbanQueue.on('changed', handler);\n // Emit initial state\n queue.push(kanbanQueue.getState());\n\n try {\n while (true) {\n if (queue.length > 0) {\n yield queue.shift()!;\n } else {\n await new Promise<void>((r) => { resolve = r; });\n }\n }\n } finally {\n kanbanQueue.off('changed', handler);\n }\n }),\n});\n","import { randomUUID } from 'node:crypto';\nimport { EventEmitter } from 'node:events';\nimport { kanbanStore } from './kanban-store.js';\nimport { conversationStore } from './conversation-store.js';\nimport { scenarioRunStore } from './scenario-run-store.js';\nimport { scenarioStore } from './scenario-store.js';\nimport { runScenario, tapBus, abortScenario } from './scenario-runner.js';\nimport { activeSessionRegistry } from './active-session-registry.js';\nimport { startCliSession } from '../trpc/routers/chat.js';\nimport { signJwt } from './auth-token.js';\nimport { companionSettings } from './companion.js';\n\nexport interface KanbanQueueItem {\n id: string;\n boardId: string;\n cardId: string;\n runner?: 'claude-code' | 'codex';\n model?: string;\n scenarioId?: string;\n /** Le projet depuis lequel la carte a été mise en file — celui de la conversation. */\n projectId?: string;\n /** Son organisation : avec l'id, c'est le couple qui désigne le coffre. */\n orgId?: string | null;\n addedAt: string;\n}\n\ninterface KanbanRunningItem {\n id: string;\n boardId: string;\n cardId: string;\n conversationId: string;\n startedAt: string;\n}\n\nexport interface KanbanQueueState {\n items: KanbanQueueItem[];\n running: KanbanRunningItem[];\n maxConcurrent: number;\n}\n\nclass KanbanQueueService extends EventEmitter {\n private items: KanbanQueueItem[] = [];\n private running: KanbanRunningItem[] = [];\n private maxConcurrent = 1;\n private startingCount = 0; // items whose startItem() is in-flight but not yet in this.running\n\n constructor() {\n super();\n // Un listener 'changed' par abonnement WS (onglet ouvert) : la limite par défaut de 10 est trop basse.\n this.setMaxListeners(0);\n }\n\n getState(): KanbanQueueState {\n return {\n items: [...this.items],\n running: [...this.running],\n maxConcurrent: this.maxConcurrent,\n };\n }\n\n add(rawItem: Omit<KanbanQueueItem, 'id' | 'addedAt'>): KanbanQueueItem {\n // Sans scénario ni runner, startItem() n'avait rien à lancer : la carte\n // entrait en file et en ressortait aussitôt, sans un mot. C'est ce que\n // faisait l'icône d'une carte, et le choix « Auto » d'une colonne.\n const item = rawItem.scenarioId || rawItem.runner\n ? rawItem\n : { ...rawItem, runner: 'claude-code' as const };\n const alreadyQueued = this.items.find(i => i.boardId === item.boardId && i.cardId === item.cardId);\n if (alreadyQueued) return alreadyQueued;\n const alreadyRunning = this.running.find(r => r.boardId === item.boardId && r.cardId === item.cardId);\n if (alreadyRunning) {\n // Return a fake item representing the running entry\n return { id: alreadyRunning.id, addedAt: alreadyRunning.startedAt, ...item };\n }\n\n const queueItem: KanbanQueueItem = {\n id: randomUUID(),\n ...item,\n addedAt: new Date().toISOString(),\n };\n this.items.push(queueItem);\n this.emit('changed');\n this.tick();\n return queueItem;\n }\n\n async addColumn(\n boardId: string,\n columnId: string,\n options: {\n runner?: 'claude-code' | 'codex';\n model?: string;\n scenarioId?: string;\n /**\n * Les cartes que l'écran montrait au moment du geste. L'utilisateur met en\n * file ce qu'il voit : une colonne filtrée n'envoie que ses cartes filtrées.\n * Absent = toute la colonne (aucun filtre actif).\n */\n cardIds?: string[];\n },\n ): Promise<KanbanQueueItem[]> {\n const board = await kanbanStore.get(boardId);\n if (!board) return [];\n const col = board.columns.find(c => c.id === columnId);\n if (!col) return [];\n const { cardIds, ...itemOptions } = options;\n const wanted = cardIds ? new Set(cardIds) : null;\n const cards = wanted ? col.cards.filter(card => wanted.has(card.id)) : col.cards;\n return cards.map(card => this.add({ boardId, cardId: card.id, ...itemOptions }));\n }\n\n remove(itemId: string): boolean {\n const idx = this.items.findIndex(i => i.id === itemId);\n if (idx >= 0) {\n this.items.splice(idx, 1);\n this.emit('changed');\n return true;\n }\n const runIdx = this.running.findIndex(r => r.id === itemId);\n if (runIdx >= 0) {\n const run = this.running[runIdx];\n abortScenario(run.conversationId);\n activeSessionRegistry.kill(run.conversationId);\n this.running.splice(runIdx, 1);\n this.emit('changed');\n this.tick();\n return true;\n }\n return false;\n }\n\n stopAll(): void {\n this.items = [];\n for (const run of this.running) {\n abortScenario(run.conversationId);\n activeSessionRegistry.kill(run.conversationId);\n }\n this.running = [];\n this.emit('changed');\n }\n\n setMaxConcurrent(max: number): void {\n this.maxConcurrent = Math.max(1, max);\n this.emit('changed');\n this.tick();\n }\n\n private tick(): void {\n while (this.running.length + this.startingCount < this.maxConcurrent && this.items.length > 0) {\n const item = this.items.shift()!;\n this.startingCount++;\n this.startItem(item).catch(err => {\n console.error('[kanban-queue] startItem error:', err);\n }).finally(() => {\n this.startingCount--;\n });\n }\n }\n\n private async startItem(item: KanbanQueueItem): Promise<void> {\n const board = await kanbanStore.get(item.boardId);\n if (!board) { this.tick(); return; }\n\n let card = null;\n for (const col of board.columns) {\n card = col.cards.find(c => c.id === item.cardId) ?? null;\n if (card) break;\n }\n if (!card) { this.tick(); return; }\n\n // Même règle que `chat.create` : le compagnon d'office suit le réglage du\n // poste, y compris pour les cartes lancées depuis la file.\n const companionByDefault = (await companionSettings()).enabledByDefault;\n\n const conv = await conversationStore.create(\n `Queue: ${card.title}`,\n !!item.runner,\n item.scenarioId,\n item.scenarioId ? 'scenario' : undefined,\n item.runner,\n item.boardId,\n item.cardId,\n undefined,\n item.projectId,\n item.orgId,\n companionByDefault ? { companionEnabled: true } : undefined,\n );\n\n const cardContent = card.title + (card.markdown ? '\\n\\n' + card.markdown : '');\n\n if (item.scenarioId) {\n // La file porte déjà le couple projet + organisation : les scénarios lus\n // sont ceux de l'organisation à qui appartient la carte.\n const scenario = await scenarioStore.get(item.scenarioId, item.orgId ?? undefined);\n if (scenario) {\n await scenarioRunStore.initializeConversationWorkspace(conv.id, scenario, cardContent);\n }\n }\n\n const runItem: KanbanRunningItem = {\n id: item.id,\n boardId: item.boardId,\n cardId: item.cardId,\n conversationId: conv.id,\n startedAt: new Date().toISOString(),\n };\n this.running.push(runItem);\n this.emit('changed');\n\n // Une ligne de journal pour que le tableau montre qu'une IA travaille ici.\n // Route ciblée : elle ne fait pas repasser le graphe de cartes par le réseau.\n const eventType = item.scenarioId ? 'scenario_started' : 'conversation_started';\n kanbanStore.addCardEvent(board.id, item.cardId, eventType, conv.id).catch(() => {});\n\n if (item.scenarioId) {\n void runScenario(conv.id, item.scenarioId, cardContent, {\n runnerOverride: item.runner,\n modelOverride: item.model,\n });\n this.monitorCompletion(runItem).catch(() => {});\n } else if (item.runner) {\n this.runWithRunner(runItem, item, cardContent).catch(err => {\n console.error('[kanban-queue] runWithRunner error:', err);\n this.finishItem(item.id);\n });\n } else {\n this.finishItem(item.id);\n }\n }\n\n private async runWithRunner(\n runItem: KanbanRunningItem,\n item: KanbanQueueItem,\n cardContent: string,\n ): Promise<void> {\n try {\n // Aucun modèle imposé : chaque CLI utilise celui que l'utilisateur a configuré.\n const model = item.model || '';\n // La file tourne hors requête HTTP : aucun `ctx.authorization` d'où tirer le\n // JWT. Sans lui, le serveur MCP est lancé sans RUNEYA_API_TOKEN et toutes\n // ses tools répondent « No auth token available ». On en signe un ici.\n const jwt = await signJwt();\n const { done } = await startCliSession(item.runner, runItem.conversationId, cardContent, { model, jwt });\n await done;\n } finally {\n this.finishItem(runItem.id);\n }\n }\n\n private async monitorCompletion(runItem: KanbanRunningItem): Promise<void> {\n // Wait a bit for the scenario bus to be created\n await new Promise(r => setTimeout(r, 100));\n const abortCtrl = new AbortController();\n try {\n for await (const event of tapBus(runItem.conversationId, abortCtrl.signal)) {\n if (event.type === 'scenario_complete') break;\n }\n } catch {\n // Aborted or ended\n } finally {\n this.finishItem(runItem.id);\n }\n }\n\n private finishItem(itemId: string): void {\n const idx = this.running.findIndex(r => r.id === itemId);\n if (idx >= 0) this.running.splice(idx, 1);\n this.emit('changed');\n this.tick();\n }\n}\n\nexport const kanbanQueue = new KanbanQueueService();\n","import { mkdir, readdir, rm, stat, writeFile } from 'node:fs/promises';\nimport { createHash } from 'node:crypto';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { z } from 'zod';\nimport { machineRoot } from '../../services/vault-resolver.js';\nimport { TRPCError } from '@trpc/server';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { cloudFetch, accountForOrgScope, soleAccountScope } from './cloud-auth.js';\nimport { executeKanbanCommands, executeKanbanBoardCommands } from '../../services/kanban-commands.js';\nimport { kanbanStore } from '../../services/kanban-store.js';\nimport type { KanbanBoard, KanbanCard } from '@runeya/packages-shared';\n\n/**\n * A card as the read routes expose it.\n *\n * Deliberately not the stored card: the history and the attachments are the\n * bulk of a board, and an agent listing cards has no use for either. The body\n * is kept — it is what the card *says* — and the rest is reduced to counts.\n *\n * Le journal n'arrive même plus jusqu'ici : le cloud le laisse en base et\n * envoie le décompte. Le fil d'une carte se lit par `kanbanStore.cardHistory`,\n * pour la seule carte qui intéresse l'agent.\n */\nfunction summarizeCard(card: KanbanCard, boardId: string, columnTitle: string): Record<string, unknown> {\n return {\n boardId,\n column: columnTitle,\n id: card.id,\n title: card.title,\n markdown: card.markdown ?? '',\n assignees: (card.assignees ?? []).map((a) => a.name),\n commentCount: card.commentCount ?? (card.history ?? []).filter((e) => e.type === 'comment').length,\n attachmentCount: (card.attachments ?? []).length,\n // Metadata only — the bytes are fetched on demand by `downloadAttachment`.\n attachments: (card.attachments ?? []).map((f) => ({\n id: f.id,\n name: f.name,\n contentType: f.contentType,\n size: f.size,\n })),\n createdAt: card.createdAt,\n updatedAt: card.updatedAt,\n };\n}\n\n/**\n * The cloud's board *list* omits `columns` (a board carries its whole card\n * graph, so listing them in full would be megabytes) and sends counts instead.\n * The shared type describes the full board, hence this narrow read.\n */\nfunction boardCounts(board: KanbanBoard): { columnCount: number; cardCount: number; columns: string[] } {\n const summary = board as unknown as { columnCount?: number; cardCount?: number };\n const columns = board.columns ?? [];\n return {\n columnCount: summary.columnCount ?? columns.length,\n cardCount: summary.cardCount ?? columns.reduce((sum, c) => sum + c.cards.length, 0),\n columns: columns.map((c) => c.title),\n };\n}\n\n/**\n * Attachment ids are server-issued base64url (see the cloud's `putAttachment`).\n * Validated before it reaches a URL or a file path: the id is both.\n */\nconst ATTACHMENT_ID_REGEX = /^[A-Za-z0-9_-]{1,128}$/;\n\n/** A malformed `filename*` must lose the name, not blow up the download. */\nfunction safeDecode(value: string): string {\n try {\n return decodeURIComponent(value);\n } catch {\n return '';\n }\n}\n\n/** Mirrors the cloud's own upload ceiling — nothing larger can exist. */\nconst MAX_ATTACHMENT_BYTES = 55 * 1024 * 1024;\n\n/**\n * Où atterrissent les pièces jointes téléchargées, un fichier par id.\n *\n * Le dossier temporaire de la machine, et non le `DATA_DIR` du projet : ces\n * fichiers sont un cache, pas des données. L'original vit dans le cloud, tout\n * est re-téléchargeable, et rien ici ne mérite d'être sauvegardé, synchronisé\n * ni versionné. Le système fait déjà le ménage de ce dossier ; la purge\n * ci-dessous s'occupe du reste, pour ne pas dépendre de sa politique.\n */\nexport function attachmentCacheDir(): string {\n return join(tmpdir(), 'runeya-kanban-attachments');\n}\n\n/** Au-delà, un fichier du cache ne sert plus personne. */\nconst ATTACHMENT_CACHE_TTL_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Oublier les fichiers que plus aucune conversation ne lit.\n *\n * Sans cela le cache ne fait que grossir — une pièce jointe pèse jusqu'à 55 Mo\n * et chaque agent qui en ouvre une en dépose une copie. Au mieux et silencieux :\n * un fichier qu'on n'arrive pas à supprimer n'a aucune raison de faire échouer\n * le téléchargement qui vient d'aboutir.\n */\nexport async function purgeStaleAttachments(\n dir: string,\n ttlMs: number = ATTACHMENT_CACHE_TTL_MS,\n): Promise<void> {\n try {\n const cutoff = Date.now() - ttlMs;\n for (const name of await readdir(dir)) {\n const path = join(dir, name);\n const info = await stat(path).catch(() => null);\n if (info && info.mtimeMs < cutoff) await rm(path, { force: true });\n }\n } catch {\n /* le cache est jetable : un ménage raté n'est pas une erreur */\n }\n}\n\n/**\n * Les emplacements du cache, du plus souhaitable au plus sûr.\n *\n * Le dossier temporaire d'abord : ces fichiers sont jetables et n'ont rien à\n * faire dans le projet. Le `DATA_DIR` ensuite, comme filet — un `/tmp` monté\n * en lecture seule, plein, ou hors de portée d'un agent au bac à sable ne doit\n * pas priver l'IA d'une pièce jointe qu'elle a le droit de lire.\n */\nfunction attachmentCacheDirs(): string[] {\n return [attachmentCacheDir(), join(machineRoot(), 'kanban-attachments')];\n}\n\n/**\n * Poser les octets sur le disque, et dire clairement si c'est impossible.\n *\n * Sans cela, un `/tmp` non inscriptible remontait à l'agent en 500 brut —\n * après un téléchargement déjà payé — sans qu'il puisse distinguer une panne\n * du cloud d'un problème de sa propre machine, ni savoir quoi faire. Ici, le\n * repli est tenté, puis l'échec est nommé, avec tous les chemins essayés.\n */\nexport async function storeAttachment(\n id: string,\n name: string,\n body: Buffer,\n dirs: string[] = attachmentCacheDirs(),\n): Promise<string> {\n const refusals: string[] = [];\n for (const dir of dirs) {\n try {\n // `recursive` couvre le cas du dossier absent : il est créé, parents compris.\n await mkdir(dir, { recursive: true });\n const path = join(dir, safeLocalName(id, name));\n await writeFile(path, body);\n // Après l'écriture, jamais avant : le ménage ne doit pas retarder ce\n // pour quoi l'agent attend, ni s'exécuter dans un dossier condamné.\n void purgeStaleAttachments(dir);\n return path;\n } catch (err) {\n refusals.push(`${dir} (${err instanceof Error ? err.message : String(err)})`);\n }\n }\n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message:\n `Impossible d'écrire la pièce jointe sur cette machine. Emplacements essayés : ${refusals.join(' ; ')}.`\n + ' Vérifiez les droits d\\'écriture, ou l\\'espace disque.',\n });\n}\n\n/**\n * Keep the extension the uploader gave the file (agents pick their reader from\n * it) but never let the name escape the cache directory.\n *\n * Le nom vient d'une empreinte de l'id, jamais de l'id lui-même : les\n * identifiants sont du base64url, donc sensibles à la casse, alors que les\n * systèmes de fichiers de Windows et de macOS ne le sont pas par défaut. Deux\n * pièces jointes ne différant que par la casse s'y écraseraient l'une l'autre,\n * et un agent lirait les octets d'un autre fichier que celui demandé.\n */\nexport function safeLocalName(id: string, name: string): string {\n const base = createHash('sha256').update(id).digest('hex').slice(0, 32);\n const ext = /\\.([A-Za-z0-9]{1,12})$/.exec(name)?.[1];\n return ext ? `${base}.${ext.toLowerCase()}` : base;\n}\n\nexport const kanbanRouter = router({\n /**\n * The organization's boards, without their cards — a board carries its whole\n * card graph, so listing them in full would be megabytes to answer \"which\n * boards exist?\". Use `getBoard` for the cards of one.\n */\n listBoards: protectedProcedure\n .input(z.object({\n includeArchived: z.boolean().optional(),\n organizationId: z.string().max(128).optional(),\n }).optional())\n .query(async ({ input }) => {\n const { organizationId, boards } = await kanbanStore.list(\n input?.includeArchived ?? false,\n input?.organizationId,\n );\n return {\n // Répondue explicitement : une liste vide doit dire à QUI la question\n // a été posée, sinon on ne peut pas distinguer « rien ici » de\n // « mauvaise organisation ».\n organizationId,\n boards: boards.map((b) => {\n const counts = boardCounts(b);\n return {\n id: b.id,\n name: b.name,\n description: b.description,\n archived: b.archived,\n columnCount: counts.columnCount,\n cardCount: counts.cardCount,\n updatedAt: b.updatedAt,\n };\n }),\n };\n }),\n\n /** One board: its columns, and the cards in each. */\n getBoard: protectedProcedure\n .input(z.object({ boardId: z.string().max(128) }))\n .query(async ({ input }) => {\n const board = await kanbanStore.get(input.boardId);\n if (!board) return { board: null };\n // La filiation vit hors du tableau, donc elle se demande à part — et elle\n // vaut d'être jointe ici : un agent qui lit un tableau doit voir qu'une\n // carte en attend une autre, sans avoir à le deviner du texte.\n const { links } = await kanbanStore.cardLinks(input.boardId);\n const parentOf = new Map(links.map((l) => [l.childCardId, l.parentCardId]));\n const childrenOf = new Map<string, string[]>();\n for (const link of links) {\n childrenOf.set(link.parentCardId, [...(childrenOf.get(link.parentCardId) ?? []), link.childCardId]);\n }\n const withLinks = (card: Record<string, unknown>): Record<string, unknown> => {\n const id = String(card['id']);\n const parent = parentOf.get(id);\n const children = childrenOf.get(id) ?? [];\n return {\n ...card,\n ...(parent ? { parentCardId: parent } : {}),\n ...(children.length ? { childCardIds: children } : {}),\n };\n };\n return {\n board: {\n id: board.id,\n name: board.name,\n description: board.description,\n instructions: board.instructions ?? '',\n archived: board.archived,\n columns: [...board.columns]\n .sort((a, b) => a.order - b.order)\n .map((col) => ({\n id: col.id,\n title: col.title,\n cards: [...col.cards]\n .sort((a, b) => a.order - b.order)\n .map((card) => withLinks(summarizeCard(card, board.id, col.title))),\n })),\n },\n };\n }),\n\n /**\n * Free-text search over card titles and bodies, across every board of the\n * organization — or one board when `boardId` is given. Archived boards are\n * left out: they are what the team decided to stop looking at.\n */\n searchCards: protectedProcedure\n .input(z.object({\n query: z.string().min(1).max(256),\n boardId: z.string().max(128).optional(),\n limit: z.number().int().min(1).max(100).optional(),\n organizationId: z.string().max(128).optional(),\n }))\n .query(async ({ input }) => {\n // La recherche se fait dans le cloud, avec le prédicat de ses propres\n // écrans : titre, corps et commentaires, sans casse ni accents. Filtrer\n // ici obligeait à rapatrier tous les tableaux entiers, et laissait de\n // côté ce que le tableau ne porte plus — les commentaires et l'archive.\n return kanbanStore.searchCards(input);\n }),\n\n /**\n * Le fil de commentaires d'une carte, relu à la demande.\n *\n * Le contexte d'un agent embarque les commentaires tels qu'ils étaient au\n * lancement de la tâche — un instantané. Le support qui répond dix minutes\n * plus tard écrit dans un fil que l'agent ne voit plus : `getBoard` ne rend\n * qu'un `commentCount`, et rien n'en donnait le texte. Cette route est la\n * relecture, pour une seule carte : c'est le journal qui pèse, pas le reste.\n */\n getCardComments: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n cardId: z.string().max(128),\n limit: z.number().int().min(1).max(200).optional(),\n }))\n .query(async ({ input }) => {\n const history = await kanbanStore.cardHistory(input.boardId, input.cardId);\n const comments = history.filter((e) => e.type === 'comment');\n // Les derniers, pas les premiers : un fil se lit par la fin.\n const slice = comments.slice(-(input.limit ?? 50));\n return {\n total: comments.length,\n comments: slice.map((c) => ({\n id: c.id,\n timestamp: c.timestamp,\n author: c.author ?? 'user',\n authorName: c.authorUser?.name,\n editedAt: c.editedAt,\n text: c.detail ?? '',\n attachments: (c.attachments ?? []).map((f) => ({\n id: f.id,\n name: f.name,\n contentType: f.contentType,\n size: f.size,\n })),\n })),\n };\n }),\n\n /**\n * La filiation des cartes d'un tableau : qui dépend de qui.\n *\n * `getBoard` en donne déjà l'essentiel carte par carte ; cette route sert\n * quand c'est l'arbre lui-même qu'on veut, dates et auteurs compris.\n */\n getCardLinks: protectedProcedure\n .input(z.object({ boardId: z.string().max(128) }))\n .query(async ({ input }) => kanbanStore.cardLinks(input.boardId)),\n\n /**\n * Rattacher une carte à une carte parente, ou l'en détacher.\n *\n * Sans `parentCardId`, le lien est retiré. Le parent peut vivre sur un autre\n * tableau : `parentBoardId` le désigne alors, sinon c'est celui de la carte.\n */\n setCardParent: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n cardId: z.string().max(128),\n parentCardId: z.string().max(128).optional(),\n parentBoardId: z.string().max(128).optional(),\n }))\n .mutation(async ({ input }) => {\n const ok = await kanbanStore.setCardParent(\n input.boardId,\n input.cardId,\n input.parentCardId\n ? { boardId: input.parentBoardId ?? input.boardId, cardId: input.parentCardId }\n : null,\n );\n if (!ok) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'The cloud refused the link (unknown card, or a cycle).' });\n }\n return { ok: true };\n }),\n\n moveCard: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n cardId: z.string().max(128),\n targetColumn: z.string().max(256),\n }))\n .mutation(async ({ input }) => {\n await executeKanbanCommands(input.boardId, input.cardId, [\n { type: 'move_card', columnTitle: input.targetColumn },\n ]);\n return { ok: true };\n }),\n\n addComment: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n cardId: z.string().max(128),\n comment: z.string().max(100_000),\n }))\n .mutation(async ({ input }) => {\n await executeKanbanCommands(input.boardId, input.cardId, [\n { type: 'add_comment', comment: input.comment },\n ]);\n return { ok: true };\n }),\n\n addCard: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n column: z.string().max(256),\n title: z.string().max(512),\n content: z.string().max(20000).optional(),\n }))\n .mutation(async ({ input }) => {\n await executeKanbanBoardCommands(input.boardId, [\n { type: 'add_card', columnTitle: input.column, cardTitle: input.title, cardContent: input.content },\n ]);\n return { ok: true };\n }),\n\n /**\n * Lire une carte, seule.\n *\n * `getBoard` rapatrie le tableau entier pour n'en regarder qu'une ; et il ne\n * porte pas les cartes rangées. Une carte s'adresse par son identifiant.\n */\n getCard: protectedProcedure\n .input(z.object({ boardId: z.string().max(128), cardId: z.string().max(128) }))\n .query(async ({ input }) => {\n const found = await kanbanStore.card(input.boardId, input.cardId);\n if (!found) throw new Error(`Carte ${input.cardId} introuvable sur le tableau ${input.boardId}.`);\n return { ...summarizeCard(found.card, input.boardId, ''), columnId: found.columnId };\n }),\n\n /**\n * Modifier une carte.\n *\n * Le manque le plus coûteux du kanban vu par un agent : sans lui, il ne\n * pouvait qu'ajouter. Face à une carte à corriger, il en créait une seconde.\n *\n * Un champ absent n'est pas touché ; `null` l'efface. La distinction compte —\n * changer un titre ne doit pas vider une couleur.\n */\n updateCard: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n cardId: z.string().max(128),\n title: z.string().min(1).max(512).optional(),\n content: z.string().max(100000).optional(),\n priority: z.number().int().min(1).max(10).nullable().optional(),\n color: z.string().max(32).nullable().optional(),\n groups: z.array(z.string().min(1).max(60)).max(30).optional(),\n deadline: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).nullable().optional(),\n assignees: z.array(z.string().max(128)).max(50).optional(),\n }))\n .mutation(async ({ input }) => {\n const { boardId, cardId, content, ...rest } = input;\n const patch: Record<string, unknown> = { ...rest };\n // Le cloud nomme `markdown` ce que l'outil appelle `content`, comme\n // `kanban_add_card` : un agent n'a pas à connaître deux noms.\n if (content !== undefined) patch.markdown = content;\n if (!Object.keys(patch).length) throw new Error('Rien à modifier : précisez au moins un champ.');\n const card = await kanbanStore.updateCard(boardId, cardId, patch);\n if (!card) throw new Error(`La carte ${cardId} n'a pas pu être modifiée.`);\n return summarizeCard(card, boardId, '');\n }),\n\n /** Ranger une carte, ou la reprendre. */\n setCardArchived: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n cardId: z.string().max(128),\n archived: z.boolean(),\n }))\n .mutation(async ({ input }) => {\n const ok = await kanbanStore.setCardArchived(input.boardId, input.cardId, input.archived);\n if (!ok) throw new Error(`La carte ${input.cardId} n'a pas pu être ${input.archived ? 'archivée' : 'reprise'}.`);\n return { ok: true };\n }),\n\n /**\n * Qui peut se voir assigner une carte.\n *\n * Sans cette liste, assigner revient à deviner un identifiant — et l'agent\n * n'a aucun moyen de le trouver.\n */\n listMembers: protectedProcedure\n .input(z.object({ organizationId: z.string().max(128).optional() }))\n .query(async ({ input }) => ({ members: await kanbanStore.members(input.organizationId) })),\n\n /**\n * Fetch one card attachment from the cloud and drop it on this machine, so an\n * agent can open it with its own file tools. The bytes never go through the\n * prompt: the card context lists the attachments, this returns a path.\n */\n downloadAttachment: protectedProcedure\n .input(z.object({\n attachmentId: z.string().max(128),\n // La pièce jointe appartient à une organisation : la nommer dit sous quel\n // compte la demander. C'est le SEUL appel qui tolère de ne pas l'avoir —\n // un agent n'a qu'un identifiant de fichier — et il échoue alors en le\n // disant dès que ce poste a plusieurs comptes.\n orgId: z.string().max(128).optional(),\n }))\n .mutation(async ({ input }) => {\n const id = input.attachmentId;\n if (!ATTACHMENT_ID_REGEX.test(id)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Invalid attachment id' });\n }\n\n // The cloud authorizes this: it checks the machine's session against the\n // organization owning the file before serving a single byte.\n const res = await cloudFetch(`/api/kanban/file/${id}`, {\n timeoutMs: 120_000,\n accountId: input.orgId\n ? await accountForOrgScope(input.orgId)\n : await soleAccountScope(),\n });\n if (res.status === 404) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Attachment ${id} not found` });\n }\n if (!res.ok) {\n throw new TRPCError({\n code: res.status === 403 ? 'FORBIDDEN' : 'INTERNAL_SERVER_ERROR',\n message: `Cloud refused the attachment (HTTP ${res.status})`,\n });\n }\n\n // Trust the header only to fail early; the real check is on the bytes.\n const declared = Number(res.headers.get('content-length') ?? 0);\n if (declared > MAX_ATTACHMENT_BYTES) {\n throw new TRPCError({ code: 'PAYLOAD_TOO_LARGE', message: 'Attachment too large to download' });\n }\n const body = Buffer.from(await res.arrayBuffer());\n if (body.length > MAX_ATTACHMENT_BYTES) {\n throw new TRPCError({ code: 'PAYLOAD_TOO_LARGE', message: 'Attachment too large to download' });\n }\n\n const contentType = res.headers.get('content-type') ?? 'application/octet-stream';\n const disposition = res.headers.get('content-disposition') ?? '';\n // `filename*` first: it carries the real, non-ASCII name (RFC 6266). The\n // quoted `filename` is only the transliterated fallback for old clients,\n // so reading it first would write \"Analyse d_un projet.docx\" to disk.\n const encoded = /filename\\*=UTF-8''([^;]+)/i.exec(disposition)?.[1];\n const name = (encoded ? safeDecode(encoded) : '')\n || /filename=\"([^\"]*)\"/.exec(disposition)?.[1]\n || id;\n\n const path = await storeAttachment(id, name, body);\n return { path, name, contentType, size: body.length };\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { agentManager } from '../../services/agent-manager.js';\nimport { resolveAgentCwd } from '../../services/workspace-cwd.js';\n\nexport interface TerminalSessionInfo {\n sessionId: string;\n title: string;\n cwd: string;\n cols: number;\n rows: number;\n createdAt: number;\n}\n\nexport const terminalRouter = router({\n /** Create a PTY shell session on the target agent */\n create: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n cwd: z.string().max(512).optional(),\n /** Anchors the terminal when no explicit cwd is given. */\n serviceId: z.string().max(128).optional(),\n projectId: z.string().max(128).optional(),\n /** L'organisation du projet : un id seul peut en nommer un par organisation. */\n orgId: z.string().max(128).nullable().optional(),\n cols: z.number().int().min(1).max(512).optional(),\n rows: z.number().int().min(1).max(256).optional(),\n title: z.string().max(128).optional(),\n }))\n .mutation(async ({ input }) => {\n const result = await agentManager.agentMutation<{ sessionId: string }>(\n input.agentId,\n 'terminal.create',\n {\n // An explicit cwd wins; otherwise the service's directory, then the\n // project's — never the directory the server was launched in.\n cwd: input.cwd ?? await resolveAgentCwd({\n serviceId: input.serviceId, projectId: input.projectId, orgId: input.orgId,\n }),\n cols: input.cols,\n rows: input.rows,\n title: input.title,\n },\n );\n return result;\n }),\n\n /** Les sessions PTY encore vivantes sur l'agent (onglets à retrouver) */\n list: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .query(async ({ input }) => {\n return agentManager.agentQuery<{ sessions: TerminalSessionInfo[] }>(\n input.agentId,\n 'terminal.list',\n );\n }),\n\n /** Renommer un onglet */\n rename: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n sessionId: z.string().max(128),\n title: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n await agentManager.agentMutation(\n input.agentId,\n 'terminal.rename',\n { sessionId: input.sessionId, title: input.title },\n );\n return { ok: true as const };\n }),\n\n /** Send keystrokes / data to a PTY session */\n write: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n sessionId: z.string().max(128),\n data: z.string().max(65536),\n }))\n .mutation(async ({ input }) => {\n await agentManager.agentMutation(\n input.agentId,\n 'terminal.write',\n { sessionId: input.sessionId, data: input.data },\n );\n return { ok: true as const };\n }),\n\n /** Resize the PTY */\n resize: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n sessionId: z.string().max(128),\n cols: z.number().int().min(1).max(512),\n rows: z.number().int().min(1).max(256),\n }))\n .mutation(async ({ input }) => {\n await agentManager.agentMutation(\n input.agentId,\n 'terminal.resize',\n { sessionId: input.sessionId, cols: input.cols, rows: input.rows },\n );\n return { ok: true as const };\n }),\n\n /** Destroy a PTY session */\n destroy: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n sessionId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n await agentManager.agentMutation(\n input.agentId,\n 'terminal.destroy',\n { sessionId: input.sessionId },\n );\n return { ok: true as const };\n }),\n\n /** Stream PTY output — proxied via AgentWSBridge dynamic subscription */\n onData: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n sessionId: z.string().max(128),\n /** Rejouer l'historique de la session avant le flux temps réel. */\n replay: z.boolean().optional(),\n }))\n .subscription(async function* ({ input }) {\n const queue: string[] = [];\n let resolve: (() => void) | null = null;\n let done = false;\n\n let unsubscribe: (() => void) | undefined;\n try {\n unsubscribe = agentManager.agentSubscribe(\n input.agentId,\n 'terminal.onData',\n { sessionId: input.sessionId, replay: input.replay },\n (data) => {\n if (typeof data === 'string') queue.push(data);\n if (resolve) { resolve(); resolve = null; }\n },\n () => {\n done = true;\n if (resolve) { resolve(); resolve = null; }\n },\n );\n } catch (err) {\n throw new TRPCError({\n code: 'BAD_REQUEST',\n message: `Cannot subscribe to terminal: ${(err as Error).message}`,\n });\n }\n\n try {\n while (!done || queue.length > 0) {\n if (queue.length > 0) {\n yield queue.shift()!;\n } else {\n await new Promise<void>((r) => { resolve = r; });\n }\n }\n } finally {\n unsubscribe?.();\n }\n }),\n});\n","import { z } from 'zod';\nimport { router, protectedProcedure } from '../trpc.js';\n\nconst MAX_WAIT_MS = 5 * 60 * 1000; // 5 minutes max\n\nexport const utilityRouter = router({\n wait: protectedProcedure\n .input(z.object({\n ms: z.number().int().min(0).max(MAX_WAIT_MS),\n }))\n .mutation(async ({ input }) => {\n await new Promise(resolve => setTimeout(resolve, input.ms));\n return { waited: input.ms };\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { readFile, readdir, stat, realpath, writeFile, mkdir, rename, rm } from 'node:fs/promises';\nimport type { Dirent } from 'node:fs';\nimport { resolve as resolvePath, join, relative, sep, dirname } from 'node:path';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { env } from '../../config/env.js';\nimport { serviceStore } from '../../services/service-store.js';\nimport { resolveWorkspaceCwd } from '../../services/workspace-cwd.js';\nimport { settingsManager } from '../../services/settings-manager.js';\nimport { agentManager } from '../../services/agent-manager.js';\nimport { resolveEffectiveAgentId } from './service.js';\n\nconst SCOPE_SCHEMA = z.union([\n z.literal('global'),\n z.string().regex(/^service:[A-Za-z0-9_-]{1,128}$/, 'Invalid service scope'),\n]);\nconst REL_PATH_SCHEMA = z\n .string()\n .min(1)\n .max(512)\n .regex(/^[A-Za-z0-9_./-]+$/)\n .refine((p) => !p.includes('..') && !p.startsWith('/'), {\n message: 'Path must be a relative path without traversal',\n });\n\nconst MAX_FILES = 500;\nconst MAX_DEPTH = 8;\nconst MAX_FILE_BYTES = 2_000_000;\nconst IGNORED_DIRS = new Set([\n 'node_modules', '.git', 'dist', 'build', '.next', '.turbo',\n '.cache', 'coverage', '.yarn', '.pnpm-store', 'target', 'out',\n]);\n\ntype DocsFileEntry = { type: 'file'; name: string; path: string };\ntype DocsDirEntry = { type: 'dir'; name: string; path: string; children: DocsEntry[] };\nexport type DocsEntry = DocsFileEntry | DocsDirEntry;\n\nconst DocsEntrySchema: z.ZodType<DocsEntry> = z.lazy(() => z.union([\n z.object({ type: z.literal('file'), name: z.string(), path: z.string() }),\n z.object({ type: z.literal('dir'), name: z.string(), path: z.string(), children: z.array(DocsEntrySchema) }),\n]));\n\n/**\n * For service scope: resolve via agent (agent expands $VAR and ~).\n * Returns { mode: 'agent', agentId, cwd } to call agent endpoints.\n *\n * For global scope: resolve locally on the server using the absolute globalDocsPath.\n * Returns { mode: 'local', root }.\n */\nasync function resolveScope(scope: string): Promise<\n | { mode: 'agent'; agentId: string; cwd: string }\n | { mode: 'local'; root: string }\n> {\n if (scope === 'global') {\n const settings = await settingsManager.getSettings();\n const sub = (settings.globalDocsPath?.trim() || 'wiki').replace(/^[\\\\/]+|[\\\\/]+$/g, '');\n if (sub.includes('..') || sub.includes('\\0')) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Sous-chemin invalide' });\n }\n // Base = parent of DATA_DIR (docs live alongside the data dir, not inside it)\n const dataDirAbs = resolvePath(env.DATA_DIR);\n await mkdir(dataDirAbs, { recursive: true });\n const base = dirname(await realpath(dataDirAbs));\n const target = resolvePath(base, sub);\n // Pre-check (defense-in-depth): the resolved target path must already live under base.\n if (target !== base && !(target + sep).startsWith(base + sep)) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Hors du dossier de données du serveur' });\n }\n await mkdir(target, { recursive: true });\n const root = await realpath(target);\n // Post-realpath check: a pre-existing symlink at `target` could resolve outside base.\n if (root !== base && !(root + sep).startsWith(base + sep)) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Le dossier wiki résout hors du dossier de données' });\n }\n return { mode: 'local', root };\n }\n // service:<id>\n const serviceId = scope.slice('service:'.length);\n const service = await serviceStore.get(serviceId);\n if (!service) throw new TRPCError({ code: 'NOT_FOUND', message: 'Service introuvable' });\n const agentId = await resolveEffectiveAgentId(service);\n if (!agentId) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Aucun agent configuré pour ce service' });\n // docsPath when defined, else the service's cwd — both anchored on the\n // project's directory rather than on wherever the server was launched.\n const cwd = await resolveWorkspaceCwd({ serviceId, override: service.docsPath?.trim() || undefined });\n return { mode: 'agent', agentId, cwd };\n}\n\n// ─── Local FS helpers (for global scope) ──────────────────────────────\n\nasync function walkLocal(root: string, dir: string, depth: number, counter: { n: number }): Promise<DocsEntry[]> {\n if (depth > MAX_DEPTH || counter.n >= MAX_FILES) return [];\n let entries: Dirent[];\n try { entries = await readdir(dir, { withFileTypes: true }); } catch { return []; }\n const out: DocsEntry[] = [];\n for (const e of entries) {\n if (counter.n >= MAX_FILES) break;\n if (e.name.startsWith('.') && e.name !== '.') continue;\n const abs = join(dir, e.name);\n const rel = relative(root, abs).split(sep).join('/');\n if (e.isDirectory()) {\n if (IGNORED_DIRS.has(e.name)) continue;\n const children = await walkLocal(root, abs, depth + 1, counter);\n out.push({ type: 'dir', name: e.name, path: rel, children });\n } else if (e.isFile() && /\\.(md|markdown)$/i.test(e.name)) {\n counter.n += 1;\n out.push({ type: 'file', name: e.name, path: rel });\n }\n }\n out.sort((a, b) => {\n if (a.type !== b.type) return a.type === 'dir' ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n return out;\n}\n\nasync function resolveSafeLocal(root: string, relPath: string, requireExist: boolean): Promise<string> {\n if (relPath.includes('..') || relPath.startsWith('/')) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Chemin invalide' });\n }\n const target = resolvePath(root, relPath);\n if (requireExist) {\n let real: string;\n try { real = await realpath(target); } catch {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'Chemin introuvable' });\n }\n if (real !== root && !(real + sep).startsWith(root + sep)) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Hors du dossier autorisé' });\n }\n return real;\n }\n const parent = dirname(target);\n let realParent: string;\n try { realParent = await realpath(parent); } catch { realParent = parent; }\n if (realParent !== root && !(realParent + sep).startsWith(root + sep)) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Hors du dossier autorisé' });\n }\n return resolvePath(realParent, target.slice(parent.length).replace(/^[\\\\/]+/, ''));\n}\n\n// ─── Router ───────────────────────────────────────────────────────────\n\nexport const wikiRouter = router({\n list: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA }))\n .output(z.object({ root: z.string(), entries: z.array(DocsEntrySchema), truncated: z.boolean() }))\n .query(async ({ input }) => {\n const target = await resolveScope(input.scope);\n if (target.mode === 'agent') {\n return agentManager.agentQuery(target.agentId, 'wiki.listRepoMarkdown', { cwd: target.cwd }) as Promise<{ root: string; entries: DocsEntry[]; truncated: boolean }>;\n }\n const counter = { n: 0 };\n const entries = await walkLocal(target.root, target.root, 0, counter);\n return { root: target.root, entries, truncated: counter.n >= MAX_FILES };\n }),\n\n read: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA, path: REL_PATH_SCHEMA }))\n .output(z.object({ path: z.string(), content: z.string() }))\n .query(async ({ input }) => {\n if (!/\\.(md|markdown)$/i.test(input.path)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Seuls les .md/.markdown sont autorisés' });\n }\n const target = await resolveScope(input.scope);\n if (target.mode === 'agent') {\n return agentManager.agentQuery(target.agentId, 'wiki.readRepoMarkdown', { cwd: target.cwd, path: input.path }) as Promise<{ path: string; content: string }>;\n }\n const file = await resolveSafeLocal(target.root, input.path, true);\n const s = await stat(file);\n if (!s.isFile()) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Pas un fichier' });\n if (s.size > MAX_FILE_BYTES) throw new TRPCError({ code: 'PAYLOAD_TOO_LARGE', message: 'Fichier trop volumineux' });\n const content = await readFile(file, 'utf-8');\n return { path: input.path, content };\n }),\n\n write: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA, path: REL_PATH_SCHEMA, content: z.string().max(5_000_000) }))\n .mutation(async ({ input }) => {\n if (!/\\.(md|markdown)$/i.test(input.path)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Seuls les .md/.markdown sont autorisés' });\n }\n const target = await resolveScope(input.scope);\n if (target.mode === 'agent') {\n return agentManager.agentMutation(target.agentId, 'wiki.writeMarkdown', { cwd: target.cwd, path: input.path, content: input.content }) as Promise<{ path: string; ok: boolean }>;\n }\n const file = await resolveSafeLocal(target.root, input.path, false);\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, input.content, 'utf-8');\n return { path: input.path, ok: true };\n }),\n\n createFile: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA, path: REL_PATH_SCHEMA }))\n .mutation(async ({ input }) => {\n if (!/\\.(md|markdown)$/i.test(input.path)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Seuls les .md/.markdown sont autorisés' });\n }\n const target = await resolveScope(input.scope);\n if (target.mode === 'agent') {\n return agentManager.agentMutation(target.agentId, 'wiki.createFile', { cwd: target.cwd, path: input.path }) as Promise<{ path: string; ok: boolean }>;\n }\n const file = await resolveSafeLocal(target.root, input.path, false);\n try { await stat(file); throw new TRPCError({ code: 'CONFLICT', message: 'Fichier déjà existant' }); }\n catch (err) { if (err instanceof TRPCError) throw err; }\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, '', 'utf-8');\n return { path: input.path, ok: true };\n }),\n\n createDir: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA, path: REL_PATH_SCHEMA }))\n .mutation(async ({ input }) => {\n const target = await resolveScope(input.scope);\n if (target.mode === 'agent') {\n return agentManager.agentMutation(target.agentId, 'wiki.createDir', { cwd: target.cwd, path: input.path }) as Promise<{ path: string; ok: boolean }>;\n }\n const dir = await resolveSafeLocal(target.root, input.path, false);\n await mkdir(dir, { recursive: true });\n return { path: input.path, ok: true };\n }),\n\n rename: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA, fromPath: REL_PATH_SCHEMA, toPath: REL_PATH_SCHEMA }))\n .mutation(async ({ input }) => {\n const target = await resolveScope(input.scope);\n if (target.mode === 'agent') {\n return agentManager.agentMutation(target.agentId, 'wiki.renamePath', { cwd: target.cwd, fromPath: input.fromPath, toPath: input.toPath }) as Promise<{ fromPath: string; toPath: string; ok: boolean }>;\n }\n const from = await resolveSafeLocal(target.root, input.fromPath, true);\n const to = await resolveSafeLocal(target.root, input.toPath, false);\n try { await stat(to); throw new TRPCError({ code: 'CONFLICT', message: 'La cible existe déjà' }); }\n catch (err) { if (err instanceof TRPCError) throw err; }\n await mkdir(dirname(to), { recursive: true });\n await rename(from, to);\n return { fromPath: input.fromPath, toPath: input.toPath, ok: true };\n }),\n\n ensureRoot: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA }))\n .mutation(async ({ input }) => {\n if (input.scope === 'global') {\n // Already created by resolveScope for global — call it once to materialise\n await resolveScope('global');\n return { ok: true };\n }\n // Service scope: ask the agent to mkdir its resolved docsPath\n const serviceId = input.scope.slice('service:'.length);\n const service = await serviceStore.get(serviceId);\n if (!service) throw new TRPCError({ code: 'NOT_FOUND', message: 'Service introuvable' });\n const agentId = await resolveEffectiveAgentId(service);\n if (!agentId) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Aucun agent configuré' });\n const cwd = await resolveWorkspaceCwd({ serviceId, override: service.docsPath?.trim() || undefined });\n return agentManager.agentMutation(agentId, 'wiki.ensureRoot', { cwd }) as Promise<{ root: string; ok: boolean }>;\n }),\n\n delete: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA, path: REL_PATH_SCHEMA }))\n .mutation(async ({ input }) => {\n const target = await resolveScope(input.scope);\n if (target.mode === 'agent') {\n return agentManager.agentMutation(target.agentId, 'wiki.deletePath', { cwd: target.cwd, path: input.path }) as Promise<{ path: string; ok: boolean }>;\n }\n const fp = await resolveSafeLocal(target.root, input.path, true);\n if (fp === target.root) throw new TRPCError({ code: 'FORBIDDEN', message: 'Impossible de supprimer la racine' });\n await rm(fp, { recursive: true, force: true });\n return { path: input.path, ok: true };\n }),\n});\n","import { router, publicProcedure } from '../trpc.js';\nimport { env } from '../../config/env.js';\n\n/**\n * Runtime configuration the web app needs before/without authentication.\n * The cloud endpoints are set on the server at launch (env vars) and fetched\n * by the web — never configured in the browser.\n */\nexport const configRouter = router({\n cloud: publicProcedure.query(() => ({\n apiUrl: env.CLOUD_URL,\n appUrl: env.CLOUD_APP_URL,\n })),\n\n /** How this instance was launched, and where it answers. */\n app: publicProcedure.query(() => ({\n fromDesktop: env.FROM_DESKTOP,\n port: env.PORT,\n })),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { readOrgClouds, readOrgAccounts, stampOrgCloud, rememberOrgName, rememberOrgAccount, readOrgNames, rememberOrgLogo, forgetOrgLogo, readOrgLogos, keyRoot, orgVaultRoot } from '../../services/vault-resolver.js';\nimport { assertOrgVaultReadable, OrgVaultUnreadableError } from '../../services/org-keys.js';\nimport { readVerifyFile, matchesCanary } from '../../services/master-password.js';\nimport { orgsToSync } from '../../services/org-sync-scope.js';\nimport { getCloudApiUrl, orgCloudUrl, accountForOrg } from '../../services/cloud-api.js';\nimport {\n reconcileOrgCanary,\n OrgKeyMismatchError,\n CanaryUnavailableError,\n} from '../../services/org-canary.js';\nimport { cloudSyncBridge, ProjectHeldElsewhereError } from '../../services/cloud-sync-bridge.js';\nimport { projectStore } from '../../services/project-store.js';\nimport { conversationStore } from '../../services/conversation-store.js';\nimport { projectPathStore } from '../../services/project-path-store.js';\nimport { cloudFetch, accountForOrgScope } from './cloud-auth.js';\nimport { adoptOrgKey } from '../../services/key-adoption.js';\nimport { getEncryptionKey } from '../../utils/encryption-key.js';\n\n/** Ce que le cloud a répondu, en clair : son `message` s'il en donne un. */\nasync function cloudMessage(res: Response): Promise<string> {\n try {\n const body = await res.text();\n if (!body) return '';\n try {\n const parsed = JSON.parse(body) as { message?: unknown };\n if (typeof parsed.message === 'string') return parsed.message;\n } catch {\n // Pas du JSON : le corps brut reste plus parlant que rien.\n }\n return body.slice(0, 300);\n } catch {\n return '';\n }\n}\n\n/**\n * Prove this machine's key is the org's, in the router's language.\n *\n * The check itself is a service — the sync bridge runs it too — so its refusals\n * come back as plain errors and are turned into tRPC codes here.\n */\n/**\n * Ce que ce poste sait lire, avant tout ce qu'il ira chercher.\n *\n * Éprouvé à CHAQUE ouverture, connexion en cours ou non : `assertOrgKey` ne\n * l'était qu'au premier projet d'une organisation, ce qui laissait les suivants\n * s'ouvrir sans que rien ne revérifie la clé.\n */\n/**\n * Le compte d'une organisation, sous la forme que `connect` attend.\n *\n * Rendu vide plutôt que `{ accountId: undefined }` : le lien est comparé\n * ailleurs, et un champ présent mais vide n'est pas la même chose qu'absent.\n */\nasync function accountScope(orgId: string): Promise<{ accountId?: string }> {\n const accountId = await accountForOrg(orgId);\n return accountId ? { accountId } : {};\n}\n\n/** Combien attendre l'état d'ouverture du cloud avant de suivre un projet. */\nconst OPENING_TIMEOUT_MS = 10_000;\n\nasync function assertOrgReadable(orgId: string): Promise<void> {\n try {\n await assertOrgVaultReadable(orgId);\n } catch (err) {\n if (err instanceof OrgVaultUnreadableError) {\n throw new TRPCError({ code: 'FORBIDDEN', message: err.message });\n }\n throw err;\n }\n}\n\nasync function assertOrgKey(orgId: string): Promise<void> {\n try {\n await reconcileOrgCanary(orgId);\n } catch (err) {\n if (err instanceof OrgKeyMismatchError) {\n throw new TRPCError({ code: 'FORBIDDEN', message: err.message });\n }\n if (err instanceof CanaryUnavailableError) {\n throw new TRPCError({ code: 'PRECONDITION_FAILED', message: err.message });\n }\n throw err;\n }\n}\n\n/**\n * Manages what this local server continuously syncs with the cloud.\n *\n * Nothing here records which organizations to sync: opening a project pulls its\n * vault, and that vault on disk IS the decision (see `org-sync-scope.ts`). The\n * transport authenticates with this machine's cloud session, so no credential\n * is stored either.\n */\n/**\n * Live sync state of an org, or 'stopped' when nothing is connected.\n *\n * Returned alongside the mutations the switcher calls, so the UI can tell a\n * paused session (a rejected sign-in, an app the cloud considers too old) from\n * a pull that is merely slow.\n */\nfunction syncState(orgId: string): string {\n return cloudSyncBridge.states().find((s) => s.orgId === orgId)?.state ?? 'stopped';\n}\n\nexport const cloudSyncRouter = router({\n /**\n * Follow one more project of an org, and pull it now.\n *\n * This is what opening a project in the switcher calls. It links the org on\n * first use, so the UI never has to know whether a link already exists —\n * \"open this project\" is the whole gesture.\n */\n trackProject: protectedProcedure\n .input(\n z.object({\n orgId: z.string().min(1).max(128),\n cloudUrl: z.string().url().max(2048),\n projectId: z.string().min(1).max(128),\n // Le compte sous lequel cette organisation a été listée. Tamponné avec\n // elle : c'est ce qui permettra à tout appel ultérieur de retrouver le\n // bon token sans qu'on ait à le lui redire.\n accountId: z.string().max(64).optional(),\n }),\n )\n .mutation(async ({ input }) => {\n // Avant toute chose : ce coffre s'ouvre-t-il ici ? Ouvrir un projet sous\n // la mauvaise clé ne rate pas — ça écrit par-dessus.\n await assertOrgReadable(input.orgId);\n const connected = cloudSyncBridge.states().some((s) => s.orgId === input.orgId);\n if (!connected) {\n // First project of this org on this machine. The stamp is written\n // BEFORE anything is pulled: it is what tells a later boot which cloud\n // this org's vault came from, and a vault without one would be taken\n // for an org of whatever cloud is configured then.\n await assertOrgKey(input.orgId);\n await stampOrgCloud(input.orgId, input.cloudUrl, undefined, input.accountId);\n await cloudSyncBridge.connect({\n orgId: input.orgId,\n cloudUrl: input.cloudUrl,\n ...(await accountScope(input.orgId)),\n });\n } else if (input.accountId) {\n // L'organisation synchronise déjà — connectée au démarrage, sans passer\n // par ici. Son coffre peut donc n'avoir jamais appris de quel compte il\n // relève, et rien d'autre ne le lui dira : le tampon n'était écrit qu'à\n // la toute première liaison, si bien qu'un poste redémarré une fois ne\n // le recevait plus jamais. Ouvrir un projet est le seul geste où le\n // compte est connu de façon certaine.\n await stampOrgCloud(input.orgId, input.cloudUrl, undefined, input.accountId);\n }\n // Le projet ne se trouve dans le document qu'une fois l'état d'ouverture du\n // cloud reçu : le suivre avant ne trouvait rien, sur un poste qui ouvre le\n // premier projet d'une organisation.\n await cloudSyncBridge.whenOpened(input.orgId, OPENING_TIMEOUT_MS);\n // Idempotent: following a project it already holds re-pulls it, which is\n // what makes re-opening a project fix a pull that never landed.\n try {\n const pulled = await cloudSyncBridge.followProject(input.orgId, input.projectId);\n return { pulled, state: syncState(input.orgId) };\n } catch (err) {\n // Un conflit que l'utilisateur peut lever lui-même, pas une panne : le\n // code voyage, l'interface le dit dans sa langue.\n if (err instanceof ProjectHeldElsewhereError) {\n throw new TRPCError({ code: 'CONFLICT', message: err.code, cause: err });\n }\n throw err;\n }\n }),\n\n /**\n * Faire passer le projet local de cette machine dans une organisation.\n *\n * Le projet n'est pas copié : il déménage. Son coffre quitte\n * `<cwd>/.runeya` pour celui de l'organisation, en gardant son identifiant,\n * puis il est suivi comme n'importe quel projet cloud — la réconciliation le\n * pousse alors dans le doc, services et environnements compris.\n *\n * Le déménagement est ce qui rend le geste sûr : il ne peut jamais y avoir\n * deux copies du même projet, donc rien à écraser. Un projet que\n * l'organisation porte déjà sous le même identifiant est refusé plutôt que\n * fusionné.\n */\n publishProject: protectedProcedure\n .input(\n z.object({\n orgId: z.string().min(1).max(128),\n cloudUrl: z.string().url().max(2048),\n projectId: z.string().min(1).max(128),\n // Le compte sous lequel cette organisation a été listée. Tamponné avec\n // elle : c'est ce qui permettra à tout appel ultérieur de retrouver le\n // bon token sans qu'on ait à le lui redire.\n accountId: z.string().max(64).optional(),\n }),\n )\n .mutation(async ({ input }) => {\n const local = await projectStore.get({ id: input.projectId, orgId: null });\n if (!local) {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'PROJECT_NOT_LOCAL' });\n }\n if (await projectStore.get({ id: input.projectId, orgId: input.orgId })) {\n throw new TRPCError({ code: 'CONFLICT', message: 'PROJECT_ALREADY_IN_ORG' });\n }\n\n // L'organisation doit synchroniser AVANT le déménagement : si sa clé ne\n // convient pas, ou si le lien échoue, le projet doit rester local plutôt\n // que d'atterrir dans un coffre que rien ne pousse.\n await assertOrgReadable(input.orgId);\n const connected = cloudSyncBridge.states().some((s) => s.orgId === input.orgId);\n if (!connected) {\n await assertOrgKey(input.orgId);\n await stampOrgCloud(input.orgId, input.cloudUrl, undefined, input.accountId);\n await cloudSyncBridge.connect({\n orgId: input.orgId,\n cloudUrl: input.cloudUrl,\n ...(await accountScope(input.orgId)),\n });\n } else if (input.accountId) {\n // L'organisation synchronise déjà — connectée au démarrage, sans passer\n // par ici. Son coffre peut donc n'avoir jamais appris de quel compte il\n // relève, et rien d'autre ne le lui dira : le tampon n'était écrit qu'à\n // la toute première liaison, si bien qu'un poste redémarré une fois ne\n // le recevait plus jamais. Ouvrir un projet est le seul geste où le\n // compte est connu de façon certaine.\n await stampOrgCloud(input.orgId, input.cloudUrl, undefined, input.accountId);\n }\n\n await projectStore.moveToOrg(input.projectId, input.orgId);\n // Le répertoire des sources suit le projet : il n'a pas bougé sur le\n // disque, seule la clé qui le désigne a changé d'organisation.\n await projectPathStore.relocate(\n { id: input.projectId, orgId: null },\n { id: input.projectId, orgId: input.orgId },\n );\n // Les conversations suivent leur projet ; leur store n'est pas atteignable\n // depuis celui des projets (il en dépend), d'où l'appel ici.\n await conversationStore.relocateAll();\n\n try {\n await cloudSyncBridge.followProject(input.orgId, input.projectId);\n } catch (err) {\n if (err instanceof ProjectHeldElsewhereError) {\n throw new TRPCError({ code: 'CONFLICT', message: err.code, cause: err });\n }\n throw err;\n }\n return { state: syncState(input.orgId) };\n }),\n\n /**\n * Cette clé est-elle celle de l'organisation ? Rien n'est écrit.\n *\n * L'étape à faire avant tout le reste : on ne re-chiffre pas une machine\n * entière sur une clé dont on n'a pas la preuve qu'elle ouvre le canari\n * publié. Le cloud, lui, ne peut pas répondre — il n'a que du chiffré sous\n * les yeux — donc le canari est rapatrié et jugé ici.\n */\n checkOrgKey: protectedProcedure\n .input(z.object({\n orgId: z.string().min(1).max(128),\n keyHex: z.string().length(64).regex(/^[0-9a-f]+$/i),\n }))\n .query(async ({ input }) => {\n const res = await cloudFetch(\n `/api/auth/organization/canary?organizationId=${encodeURIComponent(input.orgId)}`,\n { method: 'GET', accountId: await accountForOrgScope(input.orgId) },\n );\n if (!res.ok) {\n throw new TRPCError({ code: 'BAD_GATEWAY', message: await cloudMessage(res) || `CANARY_READ_FAILED (${res.status})` });\n }\n const { canary } = (await res.json()) as { canary?: unknown };\n // Pas encore de canari : la première machine à synchroniser publiera le\n // sien. N'importe quelle clé conviendrait, donc aucune n'est confirmée.\n if (typeof canary !== 'string') return { matches: false, published: false };\n return { matches: matchesCanary(canary, Buffer.from(input.keyHex, 'hex')), published: true };\n }),\n\n /**\n * Le canari de cette organisation s'ouvre-t-il avec la clé d'ici ?\n *\n * Le pendant sans synchronisation de `isKeyMismatch` : l'état `key-mismatch`\n * n'existe que pour une organisation dont la synchronisation tourne, or une\n * organisation vide n'en a aucune. Elle refusait donc toute publication sans\n * que l'interface puisse proposer ni l'adoption ni la remise à zéro — le seul\n * chemin qui la répare. Rien n'est écrit ici, ni sur le disque ni sur le cloud.\n */\n orgKeyStatus: protectedProcedure\n .input(z.object({ orgId: z.string().min(1).max(128) }))\n .query(async ({ input }) => {\n const key = getEncryptionKey(input.orgId);\n if (!key) return { status: 'unknown' as const };\n const res = await cloudFetch(\n `/api/auth/organization/canary?organizationId=${encodeURIComponent(input.orgId)}`,\n { method: 'GET', accountId: await accountForOrgScope(input.orgId) },\n );\n if (!res.ok) return { status: 'unknown' as const };\n const { canary } = (await res.json()) as { canary?: unknown };\n // Pas encore de canari : la première machine à synchroniser publiera le\n // sien, et ce sera celui d'ici. Rien à réparer.\n if (typeof canary !== 'string') return { status: 'unpublished' as const };\n return { status: matchesCanary(canary, key) ? ('ok' as const) : ('mismatch' as const) };\n }),\n\n /**\n * Faire adopter à cette machine la clé d'une organisation.\n *\n * Le pendant de `resetOrgKey` : là où celle-ci fait plier l'organisation à la\n * clé d'ici, celle-là fait plier cette machine à la sienne — et c'est la\n * seule des deux qui rend lisible ce qui avait déjà été chiffré sous elle.\n *\n * Bornée au coffre de l'organisation et à ceux de ses projets : les autres\n * organisations et la machine gardent leur clé.\n */\n adoptOrgKey: protectedProcedure\n .input(z.object({\n orgId: z.string().min(1).max(128),\n keyHex: z.string().length(64).regex(/^[0-9a-f]+$/i),\n masterPassword: z.string().min(1).max(1024),\n }))\n .mutation(async ({ input }) => {\n const report = await adoptOrgKey(\n input.orgId,\n Buffer.from(input.keyHex, 'hex'),\n input.masterPassword,\n new Date(),\n );\n // La reconnexion refait le contrôle du canari : c'est elle, et non le\n // succès de la conversion, qui prouve que l'organisation synchronise.\n await cloudSyncBridge.restartAll();\n return { converted: report.converted.length, backups: report.backups, state: syncState(input.orgId) };\n }),\n\n /**\n * Réinitialiser la clé de référence d'une organisation avec celle de cette\n * machine, puis relancer sa synchronisation.\n *\n * Le canari publié par le cloud est write-once : c'est ce qui empêche un\n * membre tenant la mauvaise clé d'enfermer les autres dehors. Le revers, c'est\n * qu'une clé machine qui change — réinstallation, `~/.runeya` perdu, migration\n * d'un ancien coffre — laisse l'organisation insynchronisable pour toujours.\n * Cette route est la sortie de secours, réservée au propriétaire côté cloud.\n *\n * Elle ne re-chiffre rien : ce qui a déjà été synchronisé sous l'ancienne clé\n * reste illisible. L'interface le dit avant de la déclencher.\n */\n resetOrgKey: protectedProcedure\n .input(z.object({ orgId: z.string().min(1).max(128) }))\n .mutation(async ({ input }) => {\n // Le canari du coffre de l'organisation d'abord : c'est LUI que la\n // publication éprouvera (`reconcileOrgCanary` lit `getEncryptionKey(orgId)`).\n // Publier celui de la machine sur une organisation qui a sa clé propre\n // laissait la référence fausse, et le mismatch entier.\n const canary = (await readVerifyFile(orgVaultRoot(input.orgId)))\n ?? (await readVerifyFile(await keyRoot()));\n // Publier un canari qu'on n'a pas remplacerait la référence de l'org par\n // rien du tout : mieux vaut refuser que verrouiller tout le monde dehors.\n if (!canary) {\n throw new TRPCError({\n code: 'PRECONDITION_FAILED',\n message: \"Cette machine n'a pas encore de clé de chiffrement.\",\n });\n }\n const res = await cloudFetch('/api/auth/organization/canary/reset', {\n method: 'POST',\n body: { organizationId: input.orgId, canary },\n accountId: await accountForOrgScope(input.orgId),\n });\n if (!res.ok) {\n const detail = await cloudMessage(res);\n throw new TRPCError({\n code: res.status === 403 ? 'FORBIDDEN' : 'BAD_GATEWAY',\n message: detail || `ORG_KEY_RESET_FAILED (${res.status})`,\n });\n }\n // La reconnexion refait le contrôle du canari : c'est elle, et non le\n // succès de l'appel, qui prouve que l'organisation synchronise à nouveau.\n const cloudUrl = (await orgsToSync()).find((l) => l.orgId === input.orgId)?.cloudUrl\n ?? getCloudApiUrl();\n await cloudSyncBridge.connect({ orgId: input.orgId, cloudUrl, ...(await accountScope(input.orgId)) });\n return { state: syncState(input.orgId) };\n }),\n\n /**\n * Stop materializing one project of an org on this machine.\n *\n * Removes its vault, and nothing else: the project stays in the org, for\n * every other member and for this one on another machine.\n */\n untrackProject: protectedProcedure\n .input(\n z.object({\n orgId: z.string().min(1).max(128),\n projectId: z.string().min(1).max(128),\n }),\n )\n .mutation(async ({ input }) => {\n await cloudSyncBridge.unfollowProject(input.orgId, input.projectId);\n return { success: true as const };\n }),\n\n /**\n * Retirer un projet de l'organisation — pour tous ses membres.\n *\n * À ne pas confondre avec `untrackProject`, qui ne concerne que cette\n * machine. Ici le projet quitte l'organisation : il disparaît pour chaque\n * membre, et le cloud rend son identifiant. La suppression locale n'est pas\n * faite ici : elle arrive par la synchronisation, comme pour tout autre\n * membre, ce qui évite d'effacer les fichiers si le cloud a refusé l'ordre.\n */\n deleteProjectFromOrg: protectedProcedure\n .input(\n z.object({\n orgId: z.string().min(1).max(128),\n projectId: z.string().min(1).max(128),\n }),\n )\n .mutation(async ({ input }) => {\n let res: Response;\n try {\n res = await cloudFetch('/api/auth/project/delete', {\n method: 'POST',\n body: { organizationId: input.orgId, projectId: input.projectId },\n // Dans le `try` : ne rien avoir à quoi rattacher l'organisation doit\n // ressortir comme CLOUD_NOT_LINKED, pas comme une erreur interne.\n accountId: await accountForOrgScope(input.orgId),\n });\n } catch (err) {\n // Pas de session cloud : un état de cette machine, dit avec un code que\n // l'interface traduit — la phrase anglaise de `cloudFetch` finissait\n // telle quelle sous les yeux de l'utilisateur.\n if (err instanceof TRPCError && err.code === 'PRECONDITION_FAILED') {\n throw new TRPCError({ code: 'PRECONDITION_FAILED', message: 'CLOUD_NOT_LINKED' });\n }\n throw err;\n }\n if (res.ok) return { success: true as const };\n\n // Le cloud dit précisément ce qui bloque — pas membre, rôle insuffisant,\n // projet absent. Écraser tout cela derrière un seul code laissait\n // l'utilisateur devant un message faux : « il faut être administrateur »\n // alors qu'il l'est, et que la cause était ailleurs.\n const detail = await cloudMessage(res);\n if (res.status === 403) {\n const code = /not a member/i.test(detail) ? 'PROJECT_NOT_MEMBER' : 'PROJECT_DELETE_FORBIDDEN';\n throw new TRPCError({ code: 'FORBIDDEN', message: code, cause: new Error(detail) });\n }\n if (res.status === 404) {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'PROJECT_NOT_IN_ORG', cause: new Error(detail) });\n }\n // Tout le reste voyage tel quel : un statut inattendu (426 version, 401\n // session expirée, panne réseau) mérite d'être lu, pas maquillé.\n throw new TRPCError({\n code: 'BAD_GATEWAY',\n message: detail || `PROJECT_DELETE_FAILED (${res.status})`,\n });\n }),\n\n /**\n * List the orgs this machine syncs, with their live sync state so the UI can\n * surface one whose sync is paused awaiting a fresh cloud sign-in.\n *\n * Derived from the vaults on disk, so it says what is actually synced rather\n * than what someone once asked for.\n */\n /**\n * Retenir localement le nom des organisations que le cloud vient de nommer.\n *\n * Les coffres sont rangés par identifiant, et l'identifiant est un hash : une\n * fois la session cloud éteinte, l'interface n'avait plus rien d'humain à\n * afficher. Le nom est donc recopié dans le tampon du coffre au passage, là\n * où il est déjà lu au démarrage suivant.\n */\n /**\n * Retenir à quel compte appartient chaque organisation.\n *\n * Poussé par l'interface avec ce que le cloud vient de répondre : une\n * organisation appartient au compte qui la LISTE. Le poste ne peut pas le\n * déduire — il l'a tenté, et il a rangé sous un compte les organisations\n * d'un autre. Même forme que `rememberOrgNames`, et pour la même raison :\n * ce que seul le cloud sait, on le recopie quand il le dit.\n */\n rememberOrgAccounts: protectedProcedure\n .input(z.object({\n orgs: z.array(z.object({\n orgId: z.string().min(1).max(128),\n accountId: z.string().min(1).max(64),\n })).max(200),\n }))\n .mutation(async ({ input }) => {\n // Une organisation peut être listée par PLUSIEURS comptes : deux\n // utilisateurs de ce poste en sont membres tous les deux. N'importe\n // lequel conviendrait, mais en écrire un au hasard le ferait changer à\n // chaque démarrage — le compte affiché sauterait sans raison visible. Le\n // tampon en place l'emporte donc tant qu'il reste un membre légitime.\n const candidates = new Map<string, string[]>();\n for (const { orgId, accountId } of input.orgs) {\n candidates.set(orgId, [...(candidates.get(orgId) ?? []), accountId]);\n }\n const current = await readOrgAccounts();\n let remembered = 0;\n for (const [orgId, accountIds] of candidates) {\n const kept = current[orgId];\n if (kept && accountIds.includes(kept)) continue;\n await rememberOrgAccount(orgId, accountIds[0]!);\n remembered++;\n }\n return { remembered };\n }),\n\n rememberOrgNames: protectedProcedure\n .input(z.object({\n orgs: z.array(z.object({\n orgId: z.string().min(1).max(128),\n name: z.string().min(1).max(100),\n })).max(200),\n }))\n .mutation(async ({ input }) => {\n for (const { orgId, name } of input.orgs) await rememberOrgName(orgId, name);\n return { remembered: input.orgs.length };\n }),\n\n /**\n * Les noms retenus dans les coffres de ce poste.\n *\n * Le pendant en lecture de `rememberOrgNames`, qui n'en avait pas : le nom\n * était recopié sur le disque au passage du cloud, puis n'était relu que par\n * le panneau des clés. L'écran de lancement, lui, ne connaissait que le cloud\n * — hors ligne, ou avant que la session ne réponde, il n'affichait donc qu'un\n * hash pour des organisations dont le nom était pourtant là, à côté.\n */\n orgNames: protectedProcedure.query(async () => readOrgNames()),\n\n /**\n * Rapatrier le logo des organisations données, pour que l'interface les\n * reconnaisse hors ligne comme elle les nomme hors ligne.\n *\n * C'est le serveur qui va le chercher, et non le navigateur : la route\n * d'image du cloud ne pose aucun en-tête CORS — un `fetch` depuis l'interface\n * serait refusé, et un `<img>` ne rend pas ses octets. Chaque organisation est\n * interrogée sur SON cloud (le tampon de son coffre), jamais sur celui\n * configuré à l'instant : un poste qui a connu deux clouds ramènerait sinon\n * l'image du mauvais.\n *\n * Un 404 efface le logo retenu — l'organisation en a retiré un — tandis qu'un\n * réseau muet laisse en place ce qui est déjà là : hors ligne, on garde.\n */\n cacheOrgLogos: protectedProcedure\n .input(z.object({ orgIds: z.array(z.string().min(1).max(128)).max(200) }))\n .mutation(async ({ input }) => {\n let cached = 0;\n for (const orgId of input.orgIds) {\n const base = await orgCloudUrl(orgId);\n try {\n // `format=png` : ce qui est rangé ici est relu par l'interface, mais\n // aussi posé dans la barre système, qui ne lit que le PNG. Le\n // demander au rapatriement évite d'avoir à convertir à chaque\n // affichage — et fait tenir l'icône hors ligne. Un cloud trop ancien\n // ignore le paramètre et rend l'original : c'est ce qui était rangé\n // jusqu'ici, rien n'est perdu.\n const res = await fetch(`${base}/api/org-logo/${encodeURIComponent(orgId)}?format=png`, {\n signal: AbortSignal.timeout(10_000),\n });\n if (res.status === 404) {\n await forgetOrgLogo(orgId);\n continue;\n }\n if (!res.ok) continue;\n const contentType = (res.headers.get('content-type') ?? '').split(';')[0]!.trim().toLowerCase();\n const bytes = Buffer.from(await res.arrayBuffer());\n // Même plafond que celui posé à l'envoi côté cloud : ce qui dépasse\n // ne vient pas de notre route, et n'a rien à faire dans un coffre.\n if (bytes.length === 0 || bytes.length > 512 * 1024) continue;\n await rememberOrgLogo(orgId, contentType, bytes.toString('base64'));\n cached += 1;\n } catch {\n // Cloud injoignable : on garde ce qui est déjà retenu.\n }\n }\n return { cached };\n }),\n\n /** Les logos retenus dans les coffres de ce poste, en data URL. */\n orgLogos: protectedProcedure.query(async () => readOrgLogos()),\n\n list: protectedProcedure.query(async () => {\n const links = await orgsToSync();\n const states = new Map(cloudSyncBridge.states().map((s) => [s.orgId, s]));\n return links.map((l) => {\n const found = states.get(l.orgId);\n return {\n orgId: l.orgId,\n cloudUrl: l.cloudUrl,\n state: found?.state ?? 'stopped',\n // Renseigné seulement quand le cloud a refusé cette app comme trop\n // ancienne : c'est lui qui publie le plancher, on ne le devine pas. La\n // borne est exclusive — il faut strictement plus récent que ce numéro.\n lastIncompatibleVersion: found?.lastIncompatibleVersion ?? null,\n };\n });\n }),\n\n /**\n * The cloud instance behind every org vault on this machine.\n *\n * Wider than `list`, which only reports the orgs actually synced here: a vault\n * may come from another cloud entirely, and saying so is how the UI explains\n * an org it can see but not reach.\n */\n orgClouds: protectedProcedure.query(async () => {\n const clouds = await readOrgClouds();\n // An org synced here without a stamp (a vault written before stamping\n // existed) belongs to the cloud this installation talks to.\n for (const { orgId } of await orgsToSync()) clouds[orgId] ??= getCloudApiUrl();\n return clouds;\n }),\n});\n","import { access } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { listCloudVaults, readOrgClouds, readOrgAccounts } from './vault-resolver.js';\nimport { cloudSessionStore } from './cloud-session-store.js';\nimport { getCloudApiUrl } from './cloud-api.js';\n\n/**\n * Which organizations this machine syncs — read from the disk, never stored.\n *\n * Syncing follows the projects you open: opening one materializes its vault\n * under `~/.runeya/orgs/<org>/projects/<id>`, and dropping it removes that\n * vault. The set of organizations worth connecting to is therefore already\n * written down, by the layout itself.\n *\n * It used to be a file of its own (`cloud-sync.json`), which had to be kept in\n * agreement with what was actually on disk — and did not: the UI stopped\n * offering link/unlink long ago, so the file recorded a decision nobody made\n * any more, while its disappearance silently stopped all syncing.\n */\n\nexport interface OrgSyncTarget {\n orgId: string;\n cloudUrl: string;\n /**\n * Le compte au nom duquel synchroniser cette organisation.\n *\n * Résolu ici, une fois, plutôt qu'à chaque requête : la question se tranche\n * en lisant le disque, et la poser à chaque push mettait une lecture de\n * fichier sur le chemin le plus chaud de l'application. Absent : le poste\n * n'en a qu'un, ou n'en a pas — `undefined` laisse le magasin retomber sur\n * son compte unique, ce qui est exactement la situation d'avant.\n */\n accountId?: string;\n}\n\n/**\n * A directory alone does not make a project: the stores create one as soon as\n * they write anything under it, so an org whose only trace is an empty\n * `environments.json` would otherwise be connected forever. `project.json` is\n * the file that says \"this project is materialized here\".\n */\nasync function isMaterialized(root: string): Promise<boolean> {\n return access(join(root, 'project.json')).then(() => true, () => false);\n}\n\n/**\n * Organizations with at least one materialized project on this machine.\n *\n * An org stamped with a cloud no account of this machine is signed into is left\n * out: its vault came from another instance, and connecting it here would ask a\n * cloud about an organization it knows nothing of. An unstamped org is assumed\n * to belong to the single account — that is how vaults written before the stamp\n * read, and with several accounts there is nothing to assume, so it waits for a\n * stamp rather than being offered to whoever happens to be first.\n *\n * L'adresse rendue est celle du tampon, plus celle configurée : deux comptes\n * peuvent vivre sur deux clouds, et l'adresse configurée n'est celle d'aucun\n * des deux en particulier.\n */\nexport async function orgsToSync(): Promise<OrgSyncTarget[]> {\n const [stamps, stampedAccounts, accounts] = await Promise.all([\n readOrgClouds(), readOrgAccounts(), cloudSessionStore.list(),\n ]);\n // Le cloud configuré compte parmi les connus même sans compte lié : une\n // session expirée ne doit pas faire disparaître l'organisation de la liste,\n // elle doit l'y laisser en « non authentifiée » — c'est cet état qui dit à\n // l'utilisateur qu'il a une connexion à refaire.\n const known = new Set([\n getCloudApiUrl(),\n ...accounts.map((a) => a.cloudUrl.replace(/\\/+$/, '')),\n ]);\n const fallback = accounts.length <= 1\n ? (accounts[0]?.cloudUrl.replace(/\\/+$/, '') ?? getCloudApiUrl())\n : null;\n const targets = new Map<string, OrgSyncTarget>();\n\n for (const vault of await listCloudVaults()) {\n if (targets.has(vault.orgId)) continue;\n const stamped = stamps[vault.orgId]?.replace(/\\/+$/, '');\n if (stamped ? !known.has(stamped) : fallback === null) continue;\n const cloudUrl = stamped ?? fallback;\n if (!cloudUrl) continue;\n const accountId = stampedAccounts[vault.orgId]\n ?? (accounts.length === 1 ? accounts[0]!.id : undefined);\n if (await isMaterialized(vault.root)) {\n targets.set(vault.orgId, { orgId: vault.orgId, cloudUrl, ...(accountId ? { accountId } : {}) });\n }\n }\n\n return Array.from(targets.values());\n}\n","import { cloudFetch, accountForOrgOrThrow } from './cloud-api.js';\nimport { matchesCanary, readVerifyFile } from './master-password.js';\nimport { getEncryptionKey } from '../utils/encryption-key.js';\nimport { keyRoot, orgVaultRoot } from './vault-resolver.js';\n\n/**\n * Reconcile this machine's encryption key with an organization's.\n *\n * Members share one key, out of band — the cloud never carries it. What the org\n * does publish is a canary: a blob only the right key can open. So before\n * syncing, this machine proves its key opens the org's canary; otherwise it\n * would happily receive everyone's data and be unable to read any secret in it,\n * with no explanation.\n *\n * The first machine to sync an org publishes its own canary and becomes the\n * reference for the others.\n *\n * Lives here rather than in the cloud-sync router because it is now also\n * checked when the sync starts on its own — an org is synced because its vault\n * is on disk, and nobody re-affirms the decision on boot, so the key that was\n * right when the project was pulled must be proven right again.\n */\n\n/** The check could not be carried out — no key, no canary, or no cloud. */\nexport class CanaryUnavailableError extends Error {\n readonly code = 'CANARY_UNAVAILABLE';\n /** `detail` reste pour les journaux ; le message est le code, pour l'interface. */\n constructor(readonly detail: string) {\n super('CANARY_UNAVAILABLE');\n this.name = 'CanaryUnavailableError';\n }\n}\n\n/** This machine's key is not the organization's — syncing would yield gibberish. */\nexport class OrgKeyMismatchError extends Error {\n readonly code = 'ORG_KEY_MISMATCH';\n /**\n * Le message EST le code, comme partout ailleurs sur ces routes.\n *\n * Une phrase écrite ici traverse le serveur telle quelle et s'affiche dans\n * l'interface sans passer par la traduction : une interface en français\n * annonçait donc l'échec en anglais, et le texte ne pouvait renvoyer nulle\n * part puisque le serveur ignore où se trouve l'écran qui répare. Le client\n * traduit `serverErrors.ORG_KEY_MISMATCH` et nomme le chemin.\n */\n constructor() {\n super('ORG_KEY_MISMATCH');\n this.name = 'OrgKeyMismatchError';\n }\n}\n\nexport async function reconcileOrgCanary(orgId: string): Promise<void> {\n // La clé de CETTE organisation, pas celle du poste : c'est tout l'intérêt\n // d'une clé par organisation — appartenir à deux organisations aux clés\n // différentes ne doit plus obliger à en sacrifier une.\n const key = getEncryptionKey(orgId);\n if (!key) throw new CanaryUnavailableError(\"Clé de l'organisation non chargée.\");\n\n // Le canari publié est celui de cette clé-là. Le coffre de l'organisation a\n // le sien dès qu'elle a reçu sa clé ; sinon c'est encore celui de la machine,\n // ce qui est exact puisque la clé l'est aussi.\n const local = (await readVerifyFile(orgVaultRoot(orgId))) ?? (await readVerifyFile(await keyRoot()));\n if (!local) throw new CanaryUnavailableError('This machine has no key canary yet.');\n\n // Publishing is write-once server-side: the value that comes back is the org's\n // reference, whether we just set it or someone else already had.\n const res = await cloudFetch('/api/auth/organization/canary', {\n method: 'POST',\n body: { organizationId: orgId, canary: local },\n accountId: await accountForOrgOrThrow(orgId),\n });\n if (!res.ok) {\n throw new CanaryUnavailableError('Could not reach the organization on the cloud.');\n }\n const { canary } = (await res.json()) as { canary?: unknown };\n if (typeof canary !== 'string') {\n throw new CanaryUnavailableError('The cloud returned no key canary.');\n }\n if (!matchesCanary(canary, key)) throw new OrgKeyMismatchError();\n}\n","import { randomUUID } from 'node:crypto';\nimport { mkdir, rm } from 'node:fs/promises';\nimport * as Y from 'yjs';\nimport { projectStore } from './project-store.js';\nimport { serviceStore } from './service-store.js';\nimport { environmentStore } from './environment-store.js';\nimport { logParserStore, isShareableParser } from './log-parser-store.js';\nimport { orgsToSync, type OrgSyncTarget as CloudSyncLink } from './org-sync-scope.js';\nimport { reconcileOrgCanary, OrgKeyMismatchError } from './org-canary.js';\nimport { cloudSessionStore } from './cloud-session-store.js';\nimport { APP_VERSION_HEADER, appVersion } from '../config/app-version.js';\nimport { getCollection, readEntity, writeEntity } from '@runeya/packages-shared';\nimport { listCloudVaults, projectVaultRoot } from './vault-resolver.js';\nimport { readSyncDoc, writeSyncDoc, writeSyncDocSync } from './sync-doc-cache.js';\n\n/**\n * Continuous, bidirectional synchronization between this local server and the\n * cloud, for every organization this server is linked to.\n *\n * Scope follows the hierarchy — org → project → services/environments — and\n * mirrors what git already shares: each entity's *on-disk* form, whatever\n * fields it happens to carry. Runtime-only state (a project's active\n * environment, a service's resolved env) is not persisted, so it is not synced\n * either; no allowlist decides this, \"is it on disk?\" does.\n *\n * Local-first is preserved: the `.runeya` JSON files stay the source of truth.\n * A per-org `Y.Doc` (CRDT) mirrors them and is relayed through the cloud over an\n * HTTP + SSE transport, so concurrent edits from different members merge instead\n * of overwriting each other.\n *\n * Loop prevention relies on Yjs transaction origins:\n * - local mutation → reconcile into doc under origin `local-bridge` → the\n * resulting incremental update is POSTed to the cloud.\n * - remote update → applied to the doc under origin `remote` → the observer\n * writes it back into the stores.\n * The stores then save and notify, which re-enters reconciliation — harmless\n * only because every write here is diff-guarded down to the field.\n */\n\nconst LOCAL_ORIGIN = 'local-bridge';\nconst REMOTE_ORIGIN = 'remote';\n/** History reloaded from this machine's cache: already on disk, not re-applied. */\nconst CACHE_ORIGIN = 'cache';\n/** Les projets recréés par une restauration du cloud — voir `apps/cloud/src/lib/sync-docs.ts`. */\nconst RESTORED_PROJECTS = 'projectRestores';\nconst PERSIST_DEBOUNCE_MS = 1_000;\nconst RECONNECT_DELAY_MS = 3_000;\n\n/**\n * How long to wait before retrying once the cloud rejected our session.\n *\n * A rejection usually needs a human (sign in again), so retrying on the normal\n * 3s cadence would just spam the logs forever. But it is not always terminal —\n * a cloud-side bug or a deploy rejects perfectly good sessions too, and those\n * heal on their own. Retrying slowly keeps the sync self-healing without the\n * noise; a fresh sign-in still resumes immediately via `resumeAll()`.\n */\nconst UNAUTHENTICATED_RETRY_MS = 5 * 60_000;\n\n/**\n * How long to wait before retrying once the cloud declared this app too old.\n *\n * Longer than a session rejection, because nothing heals here without a human\n * updating the app — but not never: the cloud may lower its floor again, or the\n * user may update without restarting anything we can observe.\n */\nconst OUTDATED_RETRY_MS = 30 * 60_000;\n\ntype CollectionName = 'projects' | 'services' | 'environments';\nconst COLLECTIONS: CollectionName[] = ['projects', 'services', 'environments'];\n\n/**\n * Les parseurs de logs, tenus à part des trois autres collections.\n *\n * Celles-ci descendent toutes d'un projet, et leur logique en dépend : ce que\n * cette machine « suit », ce qu'elle a le droit de supprimer, ce qu'un projet\n * jamais téléchargé lui interdit de toucher. Un parseur n'a pas de projet\n * parent — il appartient à l'organisation entière, et chaque membre en tient le\n * jeu complet. Le faire passer par `isTracked` reviendrait à lui inventer un\n * projet ; il a donc son observateur et sa réconciliation, plus courts parce\n * que la question « m'appartient-il ? » ne se pose pas.\n */\nconst PARSERS = 'logParsers';\n\n/** What the sync of one organization is currently doing, for the UI. */\nexport type SyncState =\n | 'connecting' | 'live' | 'unauthenticated' | 'outdated' | 'stopped' | 'key-mismatch';\n\nexport interface SyncStateReport {\n orgId: string;\n state: SyncState;\n lastIncompatibleVersion: string | null;\n}\n\n/** The cloud rejected our session (expired, signed out, or membership revoked). */\nclass SyncAuthError extends Error {\n constructor(status: number) {\n super(`cloud rejected the session (HTTP ${status})`);\n }\n}\n\n/**\n * The cloud refuses this app's version (HTTP 426).\n *\n * Distinct from an auth rejection because the cure is different: no amount of\n * retrying or signing back in fixes it, only updating the app — so it gets its\n * own state, its own cadence, and its own message.\n */\nclass SyncOutdatedError extends Error {\n /** Dernière version que le cloud refuse — la borne est exclusive. */\n public readonly lastIncompatibleVersion: string | null;\n\n constructor(lastIncompatibleVersion: string | null) {\n super(\n `this app (${appVersion}) is too old for this cloud`\n + `${lastIncompatibleVersion ? ` (needs newer than ${lastIncompatibleVersion})` : ''}`,\n );\n this.lastIncompatibleVersion = lastIncompatibleVersion;\n }\n}\n\n/** One live sync connection for a single organization. */\n/**\n * Le projet est déjà tenu ici pour une autre organisation — ou en local.\n *\n * Porte un code stable plutôt qu'une phrase : le message affiché est traduit\n * côté interface, celui-ci part dans les journaux.\n */\nexport class ProjectHeldElsewhereError extends Error {\n readonly code = 'PROJECT_HELD_ELSEWHERE';\n\n constructor(readonly projectId: string, readonly heldByOrgId: string | null) {\n super(\n `Project ${projectId} is already held here for ${heldByOrgId ? `organization ${heldByOrgId}` : 'this directory'}. ` +\n 'Two copies of one project share every entity id — stop following the other one first.',\n );\n this.name = 'ProjectHeldElsewhereError';\n }\n}\n\nclass OrgSyncConnection {\n private readonly doc = new Y.Doc();\n private readonly projects = getCollection(this.doc, 'projects');\n private readonly services = getCollection(this.doc, 'services');\n private readonly environments = getCollection(this.doc, 'environments');\n private readonly logParsers = getCollection(this.doc, PARSERS);\n private readonly conn = randomUUID();\n private link: CloudSyncLink;\n private stopped = false;\n private initializing = true;\n private abort: AbortController | null = null;\n private state: SyncState = 'connecting';\n /** Last version the cloud refuses, as it told us when rejecting this app. */\n private lastIncompatibleVersion: string | null = null;\n /** Local state still owed to the cloud (initial sync, or a rejected episode). */\n private needsPush = false;\n /**\n * Set while a newly followed project is being materialized.\n *\n * Reconciliation reads \"absent locally\" as \"removed from the project\", which\n * is true for an edit and catastrophically false mid-pull: a project whose\n * files have not landed yet would have its services and environments wiped\n * from the doc — for every member of the org, not just here.\n */\n private pulling = false;\n /**\n * Projects of this org materialized on this machine — the ones whose vault\n * exists. Refreshed from disk rather than held in a saved list: a list is one\n * more thing that can disagree with what is actually there, and a project on\n * disk but missing from it is the \"already here, still offered as a download\"\n * bug this replaces.\n */\n private tracked: Set<string> = new Set();\n /**\n * Whether the doc's opening state has been applied.\n *\n * It separates \"the org already had these projects\" from \"someone just\n * created one\". The first must not land here — joining a fifty-project org\n * would drop all fifty on the disk — while the second should, so a colleague\n * creating a project sees it appear on their teammates' machines.\n */\n private initialDocApplied = false;\n /**\n * Whether local state has been written into the doc.\n *\n * Never before the doc holds the known history — reloaded from disk, or\n * received from the cloud. Written into an empty doc, local state is\n * concurrent with every past write and loses to some of them at random: an\n * offline edit reverted, a service on disk erased by an older deletion.\n */\n private seeded = false;\n private markOpened!: () => void;\n /**\n * Réglée quand le document tient l'état d'ouverture du cloud — ou quand il ne\n * l'aura pas : session refusée, app trop ancienne, connexion arrêtée.\n */\n readonly opened = new Promise<void>((resolve) => { this.markOpened = resolve; });\n /** Store applications started by remote events and not finished yet. */\n private readonly applying = new Set<Promise<void>>();\n /**\n * When each entity was last changed by a remote update (`collection:id` → tick).\n *\n * Reconciliation reads the stores, waits, then writes what it read. A remote\n * change landing in between makes that read stale, and writing it would erase\n * the value that just arrived — for every member. Entities touched since the\n * read began are left alone: their application brings the disk up to date,\n * and the reconciliation it triggers starts from there.\n */\n private readonly remoteTouch = new Map<string, number>();\n private remoteClock = 0;\n private persistTimer: ReturnType<typeof setTimeout> | null = null;\n /** The cache write under way, so stopping can wait for it to land. */\n private persisting: Promise<void> = Promise.resolve();\n private readonly unsubscribes: (() => void)[] = [];\n private readonly onSaved = () => void this.reconcileLocalToDoc();\n\n constructor(link: CloudSyncLink) {\n this.link = link;\n }\n\n private collection(name: CollectionName): Y.Map<unknown> {\n return this[name];\n }\n\n getState(): SyncState {\n return this.state;\n }\n\n /** The cloud's version floor, known only once it has rejected us for it. */\n getLastIncompatibleVersion(): string | null {\n return this.lastIncompatibleVersion;\n }\n\n getLink(): CloudSyncLink {\n return this.link;\n }\n\n async start(): Promise<void> {\n // What this machine already holds decides what the doc may write here, so\n // it has to be known before the first remote event is applied.\n await this.refreshTracked();\n\n // Outbound: relay local-origin doc updates to the cloud (skipped while the\n // initial full push is being assembled).\n this.doc.on('update', (update: Uint8Array, origin: unknown) => {\n if (this.stopped || this.initializing) return;\n if (origin === LOCAL_ORIGIN) void this.pushUpdate(update);\n });\n\n // Inbound: apply remote-origin doc changes back into the local stores.\n for (const name of COLLECTIONS) {\n this.collection(name).observeDeep((events, txn) => {\n if (txn.origin !== REMOTE_ORIGIN) return;\n // Read before the flag is raised below: within one transaction every\n // observer runs synchronously, so all of them must see the same answer\n // for \"is this the opening state?\".\n const isInitial = !this.initialDocApplied;\n if (name === 'projects') this.initialDocApplied = true;\n this.track(this.applyDocEventsToStore(name, events, isInitial));\n });\n }\n\n // Les parseurs n'ont pas de projet parent : tout ce qui arrive est pour\n // cette machine, et il n'y a rien à filtrer.\n this.logParsers.observeDeep((events, txn) => {\n if (txn.origin !== REMOTE_ORIGIN) return;\n this.track(this.applyParserEventsToStore(events));\n });\n\n projectStore.events.on('saved', this.onSaved);\n this.unsubscribes.push(serviceStore.onChange(this.onSaved));\n this.unsubscribes.push(environmentStore.onChange(this.onSaved));\n this.unsubscribes.push(logParserStore.onLocalChange(this.onSaved));\n\n // The history this machine already knew, applied without touching the\n // stores: the disk already reflects it. Local state then goes on top.\n const cached = await readSyncDoc(this.link.orgId);\n let cacheLoaded = false;\n if (cached) {\n try {\n Y.applyUpdate(this.doc, cached, CACHE_ORIGIN);\n cacheLoaded = true;\n } catch (err) {\n console.error('[cloud-sync] unreadable sync cache for org %s, ignored:', this.link.orgId, (err as Error).message);\n }\n }\n this.doc.on('update', () => this.schedulePersist());\n // `initialDocApplied` reste faux : la première trame du cloud rattrape ce que\n // l'organisation a fait pendant que la machine était fermée. C'est un état\n // d'ouverture, pas des créations en direct — un projet apparu entre-temps\n // reste proposé, pas installé d'office.\n if (cacheLoaded) await this.seed();\n\n // Without a cache, seeding waits for the cloud's opening state (see\n // `streamOnce`). A rejected session does not abort the start — the loop\n // retries slowly and recovers on its own.\n void this.streamLoop();\n }\n\n /** Write local state on top of the known history, then owe it to the cloud. */\n private async seed(): Promise<void> {\n this.seeded = true;\n await this.reconcileLocalToDoc();\n this.initializing = false;\n this.needsPush = true;\n }\n\n private track(work: Promise<void>): void {\n this.applying.add(work);\n void work.finally(() => this.applying.delete(work));\n }\n\n private async settleApplying(): Promise<void> {\n while (this.applying.size > 0) await Promise.allSettled(this.applying);\n }\n\n private schedulePersist(): void {\n if (this.stopped || this.persistTimer) return;\n this.persistTimer = setTimeout(() => {\n this.persistTimer = null;\n this.persisting = this.persisting.then(() => this.persist());\n }, PERSIST_DEBOUNCE_MS);\n }\n\n private async persist(): Promise<void> {\n // Stopping already wrote the latest state; a write queued behind it has nothing to add.\n if (this.stopped) return;\n try {\n await writeSyncDoc(this.link.orgId, Y.encodeStateAsUpdate(this.doc));\n } catch (err) {\n console.error('[cloud-sync] could not save sync cache for org %s:', this.link.orgId, (err as Error).message);\n }\n }\n\n /** Resolves once any cache write already under way has landed. */\n stop(): Promise<void> {\n this.stopped = true;\n this.markOpened();\n this.state = 'stopped';\n projectStore.events.off('saved', this.onSaved);\n for (const off of this.unsubscribes.splice(0)) off();\n this.abort?.abort();\n if (this.persistTimer) {\n clearTimeout(this.persistTimer);\n this.persistTimer = null;\n }\n // Only once seeded: before that the doc is not yet a history worth keeping.\n if (this.seeded) {\n try {\n writeSyncDocSync(this.link.orgId, Y.encodeStateAsUpdate(this.doc));\n } catch (err) {\n console.error('[cloud-sync] could not save sync cache for org %s:', this.link.orgId, (err as Error).message);\n }\n }\n this.doc.destroy();\n return this.persisting;\n }\n\n // ---- Transport -------------------------------------------------------\n\n /**\n * Read the cloud session token fresh on every request, so signing back in\n * resumes sync without a restart. Throws when signed out, which the callers\n * treat as terminal exactly like a rejection from the cloud.\n */\n private async authHeader(): Promise<string> {\n // Le compte suit l'organisation, jamais « le » compte du poste : deux\n // organisations d'utilisateurs différents se synchronisent en même temps,\n // et un token unique en condamnait une des deux à un 403 perpétuel. Il est\n // porté par le lien, résolu une fois à la connexion — le relire ici\n // mettrait une lecture disque sur chaque push.\n const token = await cloudSessionStore.getToken(this.link.accountId);\n if (!token) throw new SyncAuthError(401);\n return `Bearer ${token}`;\n }\n\n private async headers(): Promise<Record<string, string>> {\n return {\n Authorization: await this.authHeader(),\n [APP_VERSION_HEADER]: appVersion,\n 'Content-Type': 'application/json',\n };\n }\n\n /**\n * Turn a 426 into a typed error, reading the floor the cloud published in the\n * body. The body is advisory: a missing or malformed one still blocks, it just\n * makes for a vaguer message.\n */\n private async outdatedError(res: Response): Promise<SyncOutdatedError> {\n try {\n const body = (await res.json()) as { lastIncompatibleVersion?: unknown };\n return new SyncOutdatedError(\n typeof body.lastIncompatibleVersion === 'string' ? body.lastIncompatibleVersion : null,\n );\n } catch {\n return new SyncOutdatedError(null);\n }\n }\n\n /** Remember the floor and stop pretending sync will resume on its own. */\n private markOutdated(err: SyncOutdatedError): void {\n this.markOpened();\n const alreadyReported = this.state === 'outdated';\n this.state = 'outdated';\n this.lastIncompatibleVersion = err.lastIncompatibleVersion;\n // Everything written while we were refused still has to reach the cloud\n // once the app is updated.\n this.needsPush = true;\n if (alreadyReported) return;\n console.error(`[cloud-sync] org ${this.link.orgId}: ${err.message} — sync paused until the app is updated.`);\n }\n\n /**\n * Mark this org as needing a fresh sign-in. Logged once per episode, not on\n * every slow retry: the point of retrying is to recover quietly.\n */\n private markUnauthenticated(err: SyncAuthError): void {\n this.markOpened();\n const alreadyReported = this.state === 'unauthenticated';\n this.state = 'unauthenticated';\n // Anything local was written while we were rejected: push it again once the\n // session works, or those changes would never reach the cloud.\n this.needsPush = true;\n if (alreadyReported) return;\n console.error(\n `[cloud-sync] org ${this.link.orgId}: ${err.message} — sync paused; retrying every`\n + ` ${UNAUTHENTICATED_RETRY_MS / 60_000} min, or immediately when you sign in to the cloud again.`,\n );\n }\n\n /** Sleep that gives up as soon as the connection is stopped. */\n private async delay(ms: number): Promise<void> {\n const step = 250;\n for (let waited = 0; waited < ms && !this.stopped; waited += step) {\n await new Promise((r) => setTimeout(r, Math.min(step, ms - waited)));\n }\n }\n\n private url(path: string): string {\n return `${this.link.cloudUrl.replace(/\\/$/, '')}/api/sync/${encodeURIComponent(this.link.orgId)}${path}`;\n }\n\n private async initialPush(): Promise<void> {\n try {\n const svRes = await fetch(this.url('/state-vector'), {\n headers: await this.headers(),\n signal: AbortSignal.timeout(15_000),\n });\n if (svRes.status === 426) throw await this.outdatedError(svRes);\n if (svRes.status === 401 || svRes.status === 403) throw new SyncAuthError(svRes.status);\n if (!svRes.ok) return;\n const { sv } = (await svRes.json()) as { sv: string };\n const cloudSv = new Uint8Array(Buffer.from(sv, 'base64'));\n const diff = Y.encodeStateAsUpdate(this.doc, cloudSv);\n await this.pushUpdate(diff);\n } catch (err) {\n if (err instanceof SyncAuthError || err instanceof SyncOutdatedError) throw err;\n console.error('[cloud-sync] initial push failed for org %s:', this.link.orgId, (err as Error).message);\n }\n }\n\n private async pushUpdate(update: Uint8Array): Promise<void> {\n try {\n const res = await fetch(this.url('/update'), {\n method: 'POST',\n headers: await this.headers(),\n body: JSON.stringify({ update: Buffer.from(update).toString('base64'), conn: this.conn }),\n signal: AbortSignal.timeout(15_000),\n });\n if (res.status === 426) throw await this.outdatedError(res);\n if (res.status === 401 || res.status === 403) throw new SyncAuthError(res.status);\n } catch (err) {\n if (err instanceof SyncOutdatedError) {\n this.markOutdated(err);\n this.abort?.abort();\n return;\n }\n if (err instanceof SyncAuthError) {\n this.markUnauthenticated(err);\n this.abort?.abort();\n return;\n }\n if (!this.stopped) console.error('[cloud-sync] push failed for org %s:', this.link.orgId, (err as Error).message);\n }\n }\n\n /**\n * Long-lived SSE connection; reconnects on drop, and backs off to a slow\n * cadence while the cloud is rejecting our session.\n */\n private async streamLoop(): Promise<void> {\n while (!this.stopped) {\n try {\n // Catches up whatever changed locally while we were disconnected.\n if (this.needsPush) {\n await this.initialPush();\n this.needsPush = false;\n }\n this.state = 'connecting';\n await this.streamOnce();\n } catch (err) {\n if (err instanceof SyncOutdatedError) {\n this.markOutdated(err);\n await this.delay(OUTDATED_RETRY_MS);\n continue;\n }\n if (err instanceof SyncAuthError) {\n this.markUnauthenticated(err);\n await this.delay(UNAUTHENTICATED_RETRY_MS);\n continue;\n }\n if (!this.stopped) console.error('[cloud-sync] stream error for org %s:', this.link.orgId, (err as Error).message);\n }\n await this.delay(RECONNECT_DELAY_MS);\n }\n }\n\n private async streamOnce(): Promise<void> {\n this.abort = new AbortController();\n const since = Buffer.from(Y.encodeStateVector(this.doc)).toString('base64');\n const res = await fetch(this.url(`/stream?conn=${this.conn}&since=${encodeURIComponent(since)}`), {\n headers: { Authorization: await this.authHeader(), [APP_VERSION_HEADER]: appVersion },\n signal: this.abort.signal,\n });\n if (res.status === 426) throw await this.outdatedError(res);\n if (res.status === 401 || res.status === 403) throw new SyncAuthError(res.status);\n if (!res.ok || !res.body) throw new Error(`stream HTTP ${res.status}`);\n this.state = 'live';\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n for (;;) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const frames = buffer.split('\\n\\n');\n buffer = frames.pop() ?? '';\n for (const frame of frames) {\n const line = frame.split('\\n').find((l) => l.startsWith('data: '));\n if (!line) continue;\n try {\n const payload = JSON.parse(line.slice(6)) as { type: string; update: string };\n const update = new Uint8Array(Buffer.from(payload.update, 'base64'));\n Y.applyUpdate(this.doc, update, REMOTE_ORIGIN);\n } catch {\n // Ignore malformed frames (comments/pings never carry `data:`).\n continue;\n }\n // Posé après la première trame, qu'elle ait touché aux projets ou non :\n // tout ce qui arrive ensuite est du direct.\n this.initialDocApplied = true;\n this.markOpened();\n if (!this.seeded) {\n // The opening state is in: let it reach the disk first, so what\n // reconciliation reads there already includes it, then put local\n // state on top and send it.\n await this.settleApplying();\n if (this.stopped) return;\n await this.seed();\n await this.initialPush();\n this.needsPush = false;\n }\n }\n }\n }\n\n // ---- Project selection ------------------------------------------------\n\n /**\n * Whether a doc entity is one this machine holds.\n *\n * The org is the unit of transport — the doc carries every project a member\n * can see — but not the unit of storage: a machine materializes only the\n * projects its user opened. Without this filter, opening one project of a\n * fifty-project org would drop the other forty-nine onto this disk.\n *\n * Having a vault is what \"followed\" means. Opening a project creates its\n * directory, dropping it removes the directory, and nothing else has to be\n * kept in agreement with the disk.\n */\n private isTracked(name: CollectionName, id: string): boolean {\n if (name === 'projects') return this.tracked.has(id);\n\n const fields = readEntity(this.collection(name), id);\n if (!fields) return false;\n if (name === 'environments') {\n const projectId = fields['projectId'];\n return typeof projectId === 'string' && this.tracked.has(projectId);\n }\n // A service is tracked when a tracked project lists it.\n const projects = this.collection('projects');\n for (const projectId of this.tracked) {\n const project = readEntity(projects, projectId);\n const serviceIds = project?.['serviceIds'];\n if (Array.isArray(serviceIds) && serviceIds.includes(id)) return true;\n }\n return false;\n }\n\n /** Re-read which projects of this org have a vault on this machine. */\n private async refreshTracked(): Promise<void> {\n const vaults = await listCloudVaults();\n this.tracked = new Set(\n vaults.filter((v) => v.orgId === this.link.orgId).map((v) => v.projectId),\n );\n }\n\n /**\n * Whether a *removal* announced by the doc concerns this machine.\n *\n * Deletions cannot go through `isTracked`: the entity is already gone from\n * the doc, so there is nothing left to read its `projectId` from. Projects\n * still answer from the selection; for their contents we lean on\n * `deleteLocally` being a no-op for anything this machine never pulled, which\n * is precisely the untracked case.\n */\n private isTrackedForDeletion(name: CollectionName, id: string): boolean {\n if (name === 'projects') return this.tracked.has(id);\n return true;\n }\n\n /**\n * Follow a project: give it a vault, then fill it from the doc.\n *\n * Idempotent on purpose. Widening a selection is not the only way a project\n * comes to be missing — a first pull can fail on a rejected session, or land\n * before the doc arrived — and re-opening the project has to be able to retry\n * it. Returns whether the doc actually held the project.\n */\n public async followProject(projectId: string): Promise<boolean> {\n const inDoc = readEntity(this.collection('projects'), projectId) !== null;\n // Asked for by couple: the same id can name a project of another org held\n // here too, and following would otherwise inspect that one's state.\n const existing = await projectStore.get({ id: projectId, orgId: this.link.orgId })\n ?? await projectStore.get({ id: projectId, orgId: null });\n // The same id already held as a local project: following it would give one\n // project two vaults, each overwriting the other's view of it. Refused\n // rather than merged — the two histories are not ours to reconcile.\n if (existing && !existing.orgId) {\n console.error(\n '[cloud-sync] project %s is already a local project here — not following it for org %s',\n projectId, this.link.orgId,\n );\n throw new ProjectHeldElsewhereError(projectId, null);\n }\n // Le même id déjà suivi pour une AUTRE organisation. Les deux copies portent\n // les mêmes ids de services, d'environnements et de conversations : les\n // tenir ensemble ferait écrire le contenu de l'une dans le coffre de\n // l'autre. Refusé, en nommant l'organisation qui le détient déjà — c'est\n // elle qu'il faut cesser de suivre pour prendre celle-ci.\n const heldBy = await projectStore.list().then((all) => all.find(\n (p) => p.id === projectId && p.orgId && p.orgId !== this.link.orgId,\n ));\n if (heldBy?.orgId) {\n throw new ProjectHeldElsewhereError(projectId, heldBy.orgId);\n }\n // A project just created here is not in the doc yet — it gets there through\n // reconciliation — but it is already ours to follow.\n const isLocal = existing?.orgId === this.link.orgId;\n if (!inDoc && !isLocal) return false;\n\n await mkdir(projectVaultRoot(this.link.orgId, projectId), { recursive: true });\n this.tracked.add(projectId);\n if (inDoc) await this.pullFromDoc([projectId]);\n else await this.reconcileLocalToDoc();\n return true;\n }\n\n /**\n * Stop following a project on this machine.\n *\n * Its vault goes with it — the directory *is* the selection — but the doc is\n * left untouched: the user stops following the project here, they do not ask\n * for it to be deleted for the whole organization.\n */\n public async unfollowProject(projectId: string): Promise<void> {\n this.tracked.delete(projectId);\n await projectStore.forgetLocally({ id: projectId, orgId: this.link.orgId });\n await rm(projectVaultRoot(this.link.orgId, projectId), { recursive: true, force: true })\n .catch(() => {});\n }\n\n /**\n * Materialize locally everything the doc holds for these projects.\n *\n * Contents land before their project, so that the moment the project becomes\n * local — and therefore \"owned\" by reconciliation — its services and\n * environments are already on disk. The guard covers the rest of the window,\n * including the saves this very method triggers.\n */\n private async pullFromDoc(projectIds: string[]): Promise<void> {\n this.pulling = true;\n try {\n for (const name of ['services', 'environments', 'projects'] as CollectionName[]) {\n const collection = this.collection(name);\n for (const id of Array.from(collection.keys())) {\n if (name === 'projects' ? !projectIds.includes(id) : !this.isTracked(name, id)) continue;\n const fields = readEntity(collection, id);\n if (fields) await this.upsertLocally(name, id, fields);\n }\n }\n } finally {\n this.pulling = false;\n }\n // Les contenus ont atterri avant leur projet — c'est voulu — donc dans le\n // coffre de lancement, faute de savoir encore à qui ils appartiennent. Le\n // projet est là maintenant : les remettre dans son coffre, ce qui les\n // retire du précédent. Sans ce passage ils y restaient, invisibles jusqu'au\n // redémarrage suivant, qui les relisait comme des contenus locaux orphelins —\n // services comme environnements.\n await serviceStore.relocateAll();\n await environmentStore.relocateAll();\n // Everything is on disk now, so reconciliation sees a coherent picture.\n await this.reconcileLocalToDoc();\n }\n\n // ---- Local ↔ Doc reconciliation --------------------------------------\n\n private async applyDocEventsToStore(\n name: CollectionName,\n events: Y.YEvent<Y.AbstractType<unknown>>[],\n isInitial = false,\n ): Promise<void> {\n const collection = this.collection(name);\n const deleted = new Set<string>();\n const affected = new Set<string>();\n // Kept apart from `affected`: an entity appearing is not the same event as\n // an entity changing, and only the first can mean \"a project was created\".\n const added = new Set<string>();\n for (const event of events) {\n if (event.target === collection) {\n for (const [key, change] of event.changes.keys) {\n if (change.action === 'delete') deleted.add(key);\n else {\n affected.add(key);\n if (change.action === 'add') added.add(key);\n }\n }\n } else {\n // A nested change (a field, an array element): the entity is the first\n // path segment.\n const topKey = event.path[0];\n if (typeof topKey === 'string') affected.add(topKey);\n }\n }\n\n // Still synchronous here — the observer's own call — so a reconciliation\n // already under way sees these ticks before it writes.\n for (const id of [...deleted, ...affected]) this.remoteTouch.set(`${name}:${id}`, ++this.remoteClock);\n\n // A deletion is applied for tracked entities only. `isTracked` reads the\n // doc, where the entity is already gone, so projects fall back to the\n // selection and contents to what we hold locally — never to \"unknown means\n // delete it\".\n for (const id of deleted) {\n if (!this.isTrackedForDeletion(name, id)) continue;\n await this.deleteLocally(name, id);\n }\n // A project created in the org after this machine caught up is followed on\n // its own. Doing so during the opening state would materialize the whole\n // org, which is exactly what per-project vaults exist to avoid.\n // Only on creation. An edit to a project this machine deliberately dropped\n // must not bring it back — the user stopped following it, a colleague\n // renaming it does not undo that.\n if (name === 'projects' && !isInitial) {\n for (const id of added) {\n if (deleted.has(id) || this.tracked.has(id)) continue;\n // Recréé par une restauration du cloud, pas créé : rien ne dit que ce\n // poste le voulait. Il reste proposé dans la liste des projets.\n if (this.doc.getMap(RESTORED_PROJECTS).has(id)) continue;\n try {\n await this.followProject(id);\n } catch (err) {\n // Un id que cette machine tient déjà ailleurs (projet local, ou autre\n // organisation). C'est un refus légitime quand quelqu'un demande de\n // suivre ce projet ; ici personne n'a rien demandé — le projet est\n // simplement apparu chez un collègue. Le laisser remonter couperait\n // l'application du reste de l'évènement et finirait en rejet non\n // capturé, puisque l'observateur Yjs n'attend pas cette promesse.\n if (!(err instanceof ProjectHeldElsewhereError)) throw err;\n console.warn(\n '[cloud-sync] project %s appeared in org %s but is already held here — not followed',\n id, this.link.orgId,\n );\n }\n }\n }\n\n for (const id of affected) {\n if (deleted.has(id)) continue;\n if (!this.isTracked(name, id)) continue;\n const fields = readEntity(collection, id);\n if (!fields) continue;\n await this.upsertLocally(name, id, fields);\n }\n }\n\n /**\n * Nombre d'applications distantes de parseurs en cours.\n *\n * La réconciliation lit le coffre et supprime du document ce qu'elle n'y\n * trouve pas ; déclenchée par un service enregistré au même instant, elle\n * lirait un coffre où le parseur qui arrive n'est pas encore écrit — et\n * l'effacerait pour toute l'organisation. Un compteur plutôt qu'un booléen :\n * plusieurs évènements peuvent se chevaucher, et le premier terminé ne doit\n * pas rouvrir la porte pour les autres.\n */\n private applyingParsers = 0;\n\n /**\n * Porter au disque les parseurs que le document vient de changer.\n *\n * Une suppression est appliquée telle quelle, sans l'équivalent du garde qui\n * protège les contenus d'un projet non téléchargé : chaque membre tient le\n * jeu complet de l'organisation, donc un parseur retiré du document l'a bien\n * été pour tout le monde.\n */\n private async applyParserEventsToStore(\n events: Y.YEvent<Y.AbstractType<unknown>>[],\n ): Promise<void> {\n const deleted = new Set<string>();\n const affected = new Set<string>();\n for (const event of events) {\n if (event.target === this.logParsers) {\n for (const [key, change] of event.changes.keys) {\n if (change.action === 'delete') deleted.add(key);\n else affected.add(key);\n }\n } else {\n const topKey = event.path[0];\n if (typeof topKey === 'string') affected.add(topKey);\n }\n }\n\n this.applyingParsers += 1;\n try {\n for (const id of deleted) {\n await logParserStore.applyRemoteDelete(id, this.link.orgId);\n }\n for (const id of affected) {\n if (deleted.has(id)) continue;\n const fields = readEntity(this.logParsers, id);\n if (!fields) continue;\n await logParserStore.applyRemoteUpsert(id, fields, this.link.orgId);\n }\n } finally {\n this.applyingParsers -= 1;\n }\n }\n\n private async upsertLocally(name: CollectionName, id: string, fields: unknown): Promise<void> {\n // L'organisation est passée explicitement : les secrets qui arrivent sont\n // chiffrés par SA clé, et le coffre de destination ne peut pas encore être\n // déduit — les contenus atterrissent avant leur projet, exprès, donc rien\n // ne relie encore ce service à une organisation. Sans elle, ils seraient\n // ouverts avec la clé machine, échoueraient en silence, et un chiffré\n // pourrait repartir chiffré une seconde fois.\n if (name === 'services') {\n await serviceStore.applyRemoteUpsert(id, fields, this.link.orgId);\n return;\n }\n if (name === 'environments') {\n await environmentStore.applyRemoteUpsert(id, fields, this.link.orgId);\n return;\n }\n // The org is decided by the connection that carried the project, not by the\n // field: a doc claiming `orgId: null` would otherwise turn a synced project\n // into a local one — and have it overwrite the launch directory's own.\n const result = await projectStore.applyRemoteUpsert(id, {\n ...(fields as object),\n orgId: this.link.orgId,\n });\n // A project created from a remote peer has no local environment yet;\n // bootstrap a default immutable \"local\" env so the UI is usable. Its own\n // environments may still be in flight, hence the check inside.\n if (result?.created) await this.bootstrapEnvironment(id);\n }\n\n private async deleteLocally(name: CollectionName, id: string): Promise<void> {\n if (name === 'services') { await serviceStore.applyRemoteDelete(id); return; }\n if (name === 'environments') { await environmentStore.applyRemoteDelete(id); return; }\n\n // Un projet que le cloud a refusé de stocker n'a pas été supprimé par\n // l'organisation : il n'a jamais été accepté. Ses fichiers restent ici —\n // les effacer perdrait un travail que personne n'a demandé à jeter — et la\n // machine cesse simplement de le pousser.\n const refusal = this.refusalFor(id);\n if (refusal) {\n console.error(\n '[cloud-sync] project %s refused by the cloud for org %s (%s) — kept on disk, no longer pushed',\n id, this.link.orgId, refusal,\n );\n this.tracked.delete(id);\n return;\n }\n await projectStore.applyRemoteDelete({ id, orgId: this.link.orgId });\n }\n\n /** Le motif du refus du cloud pour ce projet, s'il en a écrit un. */\n private refusalFor(projectId: string): string | null {\n const entry = this.doc.getMap('projectRefusals').get(projectId);\n if (!entry || typeof entry !== 'object') return null;\n const reason = (entry as { reason?: unknown }).reason;\n return typeof reason === 'string' ? reason : 'refused';\n }\n\n private async bootstrapEnvironment(projectId: string): Promise<void> {\n try {\n const existing = await environmentStore.getByProjectId(projectId).catch(() => []);\n if (existing.length > 0) return;\n const localEnv = await environmentStore.create({\n projectId,\n name: 'local',\n description: 'Default local environment (immutable)',\n parentIds: [],\n immutable: true,\n }, this.link.orgId);\n await projectStore.addEnvironment({ id: projectId, orgId: this.link.orgId }, localEnv.id);\n } catch (err) {\n console.error('[cloud-sync] env bootstrap failed for project %s:', projectId, (err as Error).message);\n }\n }\n\n /**\n * Mirror the org's local on-disk state into the doc.\n *\n * Membership follows the hierarchy: the org's projects, then their services\n * and environments.\n *\n * Deliberately additive for projects: a project that vanished locally is NOT\n * removed from the doc. Deleting files on one machine — or simply not having\n * pulled a project — must never wipe it for the whole organization. Removing a\n * project from the org is an explicit, admin-only action taken on the cloud,\n * which reaches every member as a remote deletion.\n *\n * Services and environments are different: they are the *contents* of a\n * project, so dropping one locally is an edit to that project and does\n * propagate — otherwise a service could never be removed.\n */\n private async reconcileLocalToDoc(): Promise<void> {\n if (this.stopped || this.pulling || !this.seeded) return;\n const readAt = this.remoteClock;\n const touchedSinceRead = (name: CollectionName, id: string): boolean =>\n (this.remoteTouch.get(`${name}:${id}`) ?? 0) > readAt;\n // Un projet que le cloud a refusé n'est pas repoussé : il reviendrait se\n // faire retirer à chaque réconciliation, indéfiniment.\n const projects = (await projectStore.listDiskFormByOrg(this.link.orgId))\n .filter((p) => !this.refusalFor(p.id));\n const projectIds = projects.map((p) => p.id);\n const serviceIds = [...new Set(projects.flatMap((p) => p.serviceIds ?? []))];\n const [services, environments] = await Promise.all([\n serviceStore.listSanitizedByIds(serviceIds),\n environmentStore.listEncryptedByProjectIds(projectIds),\n ]);\n if (this.stopped) return;\n\n // Les natifs ne partent pas : chaque poste a déjà les siens, et une copie\n // dans le document vieillirait à côté de l'original (voir `isShareable`).\n const parsers = (await logParserStore.list(this.link.orgId)).filter(isShareableParser);\n if (this.stopped) return;\n\n const local: Record<CollectionName, { id: string }[]> = { projects, services, environments };\n // Contents of projects this machine actually holds: anything belonging to a\n // project we never pulled is none of our business to delete.\n const ownedProjectIds = new Set(projectIds);\n\n this.doc.transact(() => {\n for (const name of COLLECTIONS) {\n const collection = this.collection(name);\n const entities = local[name];\n const ids = new Set(entities.map((e) => e.id));\n for (const entity of entities) {\n if (!touchedSinceRead(name, entity.id)) writeEntity(collection, entity.id, entity);\n }\n if (name === 'projects') continue;\n for (const id of Array.from(collection.keys())) {\n if (ids.has(id) || touchedSinceRead(name, id)) continue;\n if (this.belongsToOwnedProject(name, id, ownedProjectIds)) collection.delete(id);\n }\n }\n\n // Les parseurs se réconcilient dans les deux sens sans réserve : cette\n // machine tient le jeu complet de l'organisation, donc un parseur absent\n // ici a été supprimé, pas simplement jamais téléchargé.\n const parserIds = new Set(parsers.map((p) => p.id));\n for (const parser of parsers) writeEntity(this.logParsers, parser.id, parser);\n if (this.applyingParsers === 0) {\n for (const id of Array.from(this.logParsers.keys())) {\n if (!parserIds.has(id)) this.logParsers.delete(id);\n }\n }\n }, LOCAL_ORIGIN);\n }\n\n /**\n * Whether a doc entity belongs to a project this machine holds — i.e. whether\n * its absence locally is a real removal rather than a project we never pulled.\n */\n private belongsToOwnedProject(\n name: CollectionName,\n id: string,\n ownedProjectIds: Set<string>,\n ): boolean {\n const fields = readEntity(this.collection(name), id);\n if (!fields) return false;\n if (name === 'environments') {\n const projectId = fields['projectId'];\n return typeof projectId === 'string' && ownedProjectIds.has(projectId);\n }\n // A service belongs to whichever projects list it in `serviceIds`.\n const projects = this.collection('projects');\n for (const projectId of projects.keys()) {\n const project = readEntity(projects, projectId);\n const serviceIds = project?.['serviceIds'];\n if (!Array.isArray(serviceIds) || !serviceIds.includes(id)) continue;\n if (!ownedProjectIds.has(projectId)) return false; // still used elsewhere\n }\n return true;\n }\n}\n\n/** Manages one sync connection per linked organization for the whole server. */\nclass CloudSyncBridge {\n private connections = new Map<string, OrgSyncConnection>();\n /**\n * Orgs whose key this machine does not have.\n *\n * Tenues à part : la connexion n'est jamais ouverte, donc il n'y a rien à qui\n * demander son état — et une organisation qui ne peut pas synchroniser tant\n * qu'un humain n'a pas fourni de clé ne doit pas se lire « arrêtée ».\n */\n private keyMismatch = new Set<string>();\n private started = false;\n\n /**\n * Start syncing every organization this machine holds a project of.\n *\n * The scope is read from the disk (see `org-sync-scope.ts`) rather than from\n * a list of links: opening a project is what makes its org worth syncing, and\n * dropping the last one is what ends it.\n */\n async start(): Promise<void> {\n if (this.started) return;\n this.started = true;\n let links: CloudSyncLink[] = [];\n try {\n links = await orgsToSync();\n } catch (err) {\n console.error('[cloud-sync] could not read which organizations to sync:', (err as Error).message);\n return;\n }\n await this.migrateMachineParsers(links);\n for (const link of links) await this.connect(link);\n // Compté sur les connexions réellement ouvertes, pas sur les liens trouvés :\n // une organisation écartée (clé absente, verrou tenu ailleurs) annonçait une\n // synchro qui n'existait pas, juste après la ligne d'erreur qui le disait.\n const connected = this.connections.size;\n if (links.length > 0) {\n const skipped = links.length - connected;\n console.log(\n `[cloud-sync] syncing ${connected}/${links.length} organization(s)`\n + (skipped > 0 ? ` — ${skipped} not syncing (see the errors above)` : ''),\n );\n }\n }\n\n /**\n * Reconnect every link whose session had been rejected. Called after a cloud\n * sign-in, so sync resumes without restarting the server.\n */\n async resumeAll(): Promise<void> {\n const paused = Array.from(this.connections.values())\n .filter((c) => c.getState() === 'unauthenticated')\n .map((c) => c.getLink());\n for (const link of paused) await this.connect(link);\n }\n\n /**\n * Tout reconnecter, quel que soit l'état où chaque organisation s'était\n * arrêtée.\n *\n * `resumeAll` ne reprend que les sessions rejetées ; après un changement de\n * clé, ce sont justement les organisations écartées pour clé différente qu'il\n * faut retenter — et elles n'ont pas de connexion à reprendre, seulement un\n * lien sur le disque.\n */\n async restartAll(): Promise<void> {\n this.keyMismatch.clear();\n let links: CloudSyncLink[] = [];\n try {\n links = await orgsToSync();\n } catch (err) {\n console.error('[cloud-sync] could not read which organizations to sync:', (err as Error).message);\n return;\n }\n await this.migrateMachineParsers(links);\n for (const link of links) await this.connect(link);\n }\n\n /**\n * Déplacer les parseurs du poste dans les organisations de cette machine.\n *\n * Avant d'ouvrir les connexions, pour que la première réconciliation parte\n * d'un coffre déjà complet — sinon les parseurs partiraient au document au\n * coup d'après, ce qui marche mais laisse une fenêtre où l'équipe voit une\n * liste vide.\n *\n * Fait ici plutôt que dans chaque connexion : la liste du poste est vidée à\n * la fin, et deux connexions qui migreraient en parallèle se la\n * disputeraient — la seconde trouverait une machine déjà vide.\n */\n private async migrateMachineParsers(links: CloudSyncLink[]): Promise<void> {\n try {\n await logParserStore.migrateMachineParsersInto(links.map((l) => l.orgId));\n } catch (err) {\n // Un parseur non remonté se rattrape à la prochaine ouverture ; il ne\n // vaut pas d'empêcher la synchronisation de démarrer.\n console.error('[cloud-sync] could not move machine parsers into organizations:', (err as Error).message);\n }\n }\n\n /** Per-org sync state, for the UI. */\n states(): SyncStateReport[] {\n const live = Array.from(this.connections.entries()).map(([orgId, conn]) => ({\n orgId,\n state: conn.getState(),\n lastIncompatibleVersion: conn.getLastIncompatibleVersion(),\n }));\n // Sans cette entrée, une organisation dont la clé ne correspond pas se\n // lisait « arrêtée », et l'utilisateur n'avait qu'une ligne de journal —\n // vue par personne — pour l'apprendre.\n const mismatched = Array.from(this.keyMismatch)\n .filter((orgId) => !this.connections.has(orgId))\n .map((orgId) => ({\n orgId,\n state: 'key-mismatch' as SyncState,\n lastIncompatibleVersion: null,\n }));\n return [...live, ...mismatched];\n }\n\n /**\n * Follow one project of an org on this machine, pulling it now.\n *\n * Returns false when the org is not connected or the doc does not hold the\n * project — both mean \"not on this machine yet\", and the caller reports the\n * sync state rather than a bare timeout.\n */\n public async followProject(orgId: string, projectId: string): Promise<boolean> {\n const conn = this.connections.get(orgId);\n if (!conn) return false;\n return conn.followProject(projectId);\n }\n\n /** Stop following one project of an org on this machine. */\n public async unfollowProject(orgId: string, projectId: string): Promise<void> {\n await this.connections.get(orgId)?.unfollowProject(projectId);\n }\n\n /**\n * Begin (or restart) syncing a single organization.\n *\n * Takes the org's lock first. An org's vaults are shared by every Runeya on\n * this machine, so a second instance syncing the same org would write the\n * same files from its own copy of the doc — silently overwriting the first.\n * Refusing to sync is the safe answer: the instance keeps running, that org\n * simply does not sync here.\n */\n async connect(link: CloudSyncLink): Promise<void> {\n this.disconnect(link.orgId);\n\n // Nobody re-affirms this org on boot — its vault on disk is the whole\n // decision — so the key that was right when the project was pulled has to\n // be proven right again before anything is received under it.\n try {\n await reconcileOrgCanary(link.orgId);\n } catch (err) {\n if (err instanceof OrgKeyMismatchError) {\n console.error('[cloud-sync] org %s: %s', link.orgId, err.message);\n this.keyMismatch.add(link.orgId);\n return;\n }\n // Anything else — offline, signed out, no canary yet — is transient and\n // must not cost the org its sync: the transport already retries, and its\n // own auth failures are what pause it.\n console.warn(\n '[cloud-sync] org %s: could not check the organization key (%s) — syncing anyway.',\n // Le message porte désormais le code, destiné à l'interface ; le détail\n // lisible reste sur l'erreur, et c'est lui qui a sa place dans un log.\n link.orgId, (err as { detail?: string; message: string }).detail ?? (err as Error).message,\n );\n }\n // Le contrôle vient de passer : si la clé manquait, ce n'est plus le cas.\n this.keyMismatch.delete(link.orgId);\n\n // Rien n'interdit plus qu'une autre Runeya de ce poste synchronise la même\n // organisation. Un verrou l'empêchait, au motif que deux instances\n // écriraient les mêmes fichiers sans que la perdante l'apprenne — mais elle\n // l'apprend : les stores relisent leur coffre dès qu'il a bougé, et le\n // document leur porte ce que l'autre pousse, exactement comme entre deux\n // machines. Le verrou ne protégeait plus rien et privait de synchronisation\n // l'instance qui n'avait pas démarré la première.\n const conn = new OrgSyncConnection(link);\n this.connections.set(link.orgId, conn);\n try {\n await conn.start();\n } catch (err) {\n console.error('[cloud-sync] failed to start org %s:', link.orgId, (err as Error).message);\n }\n }\n\n disconnect(orgId: string): void {\n const existing = this.connections.get(orgId);\n if (existing) {\n void existing.stop();\n this.connections.delete(orgId);\n }\n }\n\n /**\n * Attendre que le document d'une organisation tienne l'état du cloud.\n *\n * Suivre un projet juste après avoir ouvert la connexion ne trouvait rien : la\n * trame d'ouverture n'était pas arrivée, et l'app concluait à un échec. Rend la\n * main au plus tard après `timeoutMs` — l'appelant lit alors l'état.\n */\n async whenOpened(orgId: string, timeoutMs: number): Promise<void> {\n const conn = this.connections.get(orgId);\n if (!conn) return;\n let timer: ReturnType<typeof setTimeout> | undefined;\n await Promise.race([\n conn.opened,\n new Promise<void>((resolve) => { timer = setTimeout(resolve, timeoutMs); }),\n ]);\n clearTimeout(timer);\n }\n\n /** Stops at once; the promise only says when pending cache writes have landed. */\n stopAll(): Promise<void> {\n const stopping = [...this.connections.values()].map((conn) => conn.stop());\n this.connections.clear();\n this.keyMismatch.clear();\n return Promise.all(stopping).then(() => {});\n }\n}\n\nexport const cloudSyncBridge = new CloudSyncBridge();\n","import { readFileSync, renameSync, rmSync, writeFileSync, mkdirSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport * as Y from 'yjs';\nimport { orgVaultRoot } from './vault-resolver.js';\nimport { atomicWriteSecure } from './run-store-utils.js';\n\n/**\n * Le document de synchronisation d'une organisation, gardé d'un lancement à\n * l'autre.\n *\n * Sans lui, chaque démarrage repartait d'un document vide et y écrivait le\n * disque avant d'avoir reçu l'historique du cloud : Yjs tenait alors ces\n * écritures pour concurrentes de tout ce que les autres avaient déjà écrit, et\n * les départageait par identifiant de client — une modification faite hors\n * ligne pouvait perdre, et un service supprimé plus tôt dans le document\n * effaçait celui que le disque venait de rendre. Rechargé, l'historique connu\n * précède ce que le disque y ajoute, et ce qui est ajouté l'emporte.\n */\nconst FILE = 'sync-doc.bin';\n\nfunction cachePath(orgId: string): string {\n return join(orgVaultRoot(orgId), FILE);\n}\n\nexport async function readSyncDoc(orgId: string): Promise<Uint8Array | null> {\n try {\n return new Uint8Array(await readFile(cachePath(orgId)));\n } catch {\n return null;\n }\n}\n\n/**\n * Fusionner plutôt que remplacer : deux Runeya d'un même poste partagent le\n * fichier, et chacune y apporte ce que l'autre n'a peut-être pas encore reçu.\n */\nfunction mergeWith(existing: Uint8Array | null, state: Uint8Array): Uint8Array {\n if (!existing) return state;\n try {\n return Y.mergeUpdates([existing, state]);\n } catch {\n // Un fichier illisible ne vaut rien à garder : l'état en mémoire le remplace.\n return state;\n }\n}\n\nexport async function writeSyncDoc(orgId: string, state: Uint8Array): Promise<void> {\n await atomicWriteSecure(cachePath(orgId), mergeWith(await readSyncDoc(orgId), state));\n}\n\n/** À l'arrêt : un processus qui se termine n'attend pas les promesses. */\nexport function writeSyncDocSync(orgId: string, state: Uint8Array): void {\n const path = cachePath(orgId);\n let existing: Uint8Array | null = null;\n try {\n existing = new Uint8Array(readFileSync(path));\n } catch {\n // Pas encore de document gardé.\n }\n mkdirSync(dirname(path), { recursive: true });\n const tmp = `${path}.${process.pid}.${randomUUID()}.tmp`;\n try {\n writeFileSync(tmp, mergeWith(existing, state), { mode: 0o600 });\n renameSync(tmp, path);\n } catch (err) {\n rmSync(tmp, { force: true });\n throw err;\n }\n}\n","import { readdir, readFile, writeFile, mkdir, copyFile, rename, stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';\nimport { decryptValueWith, encryptValueWith, isEncryptedValue } from './crypto-helpers.js';\nimport { readEncryptedKey } from './master-password.js';\nimport { getEncryptionKey, clearVaultLock } from '../utils/encryption-key.js';\nimport { installOrgKey } from './org-keys.js';\nimport { environmentStore } from './environment-store.js';\nimport { serviceStore } from './service-store.js';\nimport { conversationStore } from './conversation-store.js';\nimport { apiKeyStore } from './api-key-store.js';\nimport { keyRoot, orgVaultRoot, listCloudVaults } from './vault-resolver.js';\n\n/**\n * Adopter la clé d'une organisation.\n *\n * Distinct de la réinitialisation de son canari, qui la fait repartir sous la\n * clé d'ici en laissant illisible tout ce qui a déjà été chiffré sous l'autre.\n * Ici c'est l'inverse : c'est nous qui rejoignons la clé — ce qui rend lisible\n * ce qui existait déjà sous elle, et c'est la seule des deux voies qui répare\n * vraiment.\n *\n * Depuis que chaque organisation a sa clé, l'opération est bornée à son coffre\n * et à ceux de ses projets : le reste du poste ne bouge pas.\n */\n\nconst ALGORITHM = 'aes-256-gcm';\n\n/** Un secret d'agent, chiffré à part : un triplet hex, pas la forme `iv:tag:ct`. */\ninterface AgentTriplet {\n encrypted: string;\n iv: string;\n authTag: string;\n}\n\n/**\n * Reconnaît le triplet des agents.\n *\n * `agents.json` n'utilise pas `encryptValue` mais son propre format, hérité :\n * trois champs hex côte à côte. `isEncryptedValue` ne le voit donc pas, et une\n * conversion qui ne regarderait que les chaînes laisserait chaque passphrase\n * d'agent chiffrée sous l'ancienne clé — muette, sans rien pour le signaler.\n */\nfunction isAgentTriplet(value: Record<string, unknown>): boolean {\n const hex = (v: unknown): boolean => typeof v === 'string' && /^[0-9a-f]+$/i.test(v);\n return hex(value['encrypted']) && hex(value['iv']) && hex(value['authTag']);\n}\n\nfunction decryptTriplet(key: Buffer, t: AgentTriplet): string {\n const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(t.iv, 'hex'), { authTagLength: 16 });\n decipher.setAuthTag(Buffer.from(t.authTag, 'hex'));\n return decipher.update(t.encrypted, 'hex', 'utf-8') + decipher.final('utf-8');\n}\n\nfunction encryptTriplet(key: Buffer, plaintext: string): AgentTriplet {\n const iv = randomBytes(16);\n const cipher = createCipheriv(ALGORITHM, key, iv);\n const encrypted = cipher.update(plaintext, 'utf-8', 'hex') + cipher.final('hex');\n return { encrypted, iv: iv.toString('hex'), authTag: cipher.getAuthTag().toString('hex') };\n}\n\n/**\n * Re-chiffre récursivement tout ce qu'une valeur JSON porte de chiffré.\n *\n * Les valeurs sont trouvées par leur forme, jamais par un schéma : c'est ce qui\n * fait qu'un champ ajouté par une version ultérieure est converti lui aussi.\n * Ce qui ne s'ouvre pas sous l'ancienne clé est laissé tel quel — re-chiffrer\n * du charabia détruirait la seule copie de ce qu'il était.\n */\nexport function rekeyJsonValue(\n value: unknown,\n from: Buffer,\n to: Buffer,\n counter: { n: number },\n): unknown {\n if (typeof value === 'string') {\n if (!isEncryptedValue(value)) return value;\n let plaintext: string;\n try {\n plaintext = decryptValueWith(from, value);\n } catch {\n return value;\n }\n counter.n += 1;\n return encryptValueWith(to, plaintext);\n }\n if (Array.isArray(value)) return value.map((v) => rekeyJsonValue(v, from, to, counter));\n if (value && typeof value === 'object') {\n const record = value as Record<string, unknown>;\n if (isAgentTriplet(record)) {\n try {\n const plaintext = decryptTriplet(from, record as unknown as AgentTriplet);\n counter.n += 1;\n return { ...record, ...encryptTriplet(to, plaintext) };\n } catch {\n return record;\n }\n }\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(record)) out[k] = rekeyJsonValue(v, from, to, counter);\n return out;\n }\n return value;\n}\n\nexport interface KeyAdoptionReport {\n /** Chaque fichier converti, avec le nombre de secrets qu'il portait. */\n converted: { file: string; values: number }[];\n /** Les sauvegardes déposées avant écriture, une par coffre touché. */\n backups: string[];\n}\n\n/**\n * Les coffres d'une organisation : le sien, et celui de chacun de ses projets.\n *\n * Rien d'autre. C'est la différence que fait une clé par organisation :\n * adopter celle d'une organisation ne demande plus de re-chiffrer le poste\n * entier — les autres organisations, et la machine, gardent la leur.\n */\nasync function rootsOfOrg(orgId: string): Promise<string[]> {\n const roots = new Set<string>([orgVaultRoot(orgId)]);\n for (const vault of await listCloudVaults()) {\n if (vault.orgId === orgId) roots.add(vault.root);\n }\n return Array.from(roots);\n}\n\n/** Les JSON directement dans un coffre — jamais ses sauvegardes ni ses sous-dossiers. */\nasync function jsonFilesIn(root: string): Promise<string[]> {\n try {\n const entries = await readdir(root, { withFileTypes: true });\n return entries.filter((e) => e.isFile() && e.name.endsWith('.json')).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nasync function exists(path: string): Promise<boolean> {\n return stat(path).then(() => true, () => false);\n}\n\n/**\n * Faire adopter une autre clé à UNE organisation.\n *\n * Tout est lu et converti **en mémoire d'abord**, et rien n'est écrit avant que\n * la dernière conversion ait réussi. Une panne au milieu laisserait sinon\n * certains coffres sous la nouvelle clé et d'autres sous l'ancienne — un état\n * qu'aucune clé n'ouvre en entier, et dont on ne sait pas revenir.\n *\n * `masterPassword` est exigé parce que c'est lui qui scelle le fichier de clé\n * de l'organisation : l'adopter sans pouvoir l'écrire donnerait un coffre que\n * plus rien n'ouvrirait au redémarrage.\n */\nexport async function adoptOrgKey(\n orgId: string,\n newKey: Buffer,\n masterPassword: string,\n now: Date,\n): Promise<KeyAdoptionReport> {\n const currentKey = getEncryptionKey(orgId);\n if (!currentKey) {\n throw new Error(\"La clé actuelle de cette organisation n'est pas chargée.\");\n }\n if (newKey.equals(currentKey)) {\n // Un code : l'interface le traduit, et sait dire que rien n'est à faire.\n throw new Error('ORG_KEY_ALREADY_CURRENT');\n }\n // Le mot de passe doit ouvrir le fichier de clé du poste : c'est lui qui\n // scellera la nouvelle clé, et on ne réécrit pas un sésame sur la foi d'une\n // saisie non vérifiée.\n const machineRootDir = await keyRoot();\n await readEncryptedKey(machineRootDir, masterPassword);\n\n // 1. Lire et convertir, sans rien écrire.\n const pending: { path: string; content: string; values: number }[] = [];\n const touchedRoots = new Set<string>();\n for (const vaultRoot of await rootsOfOrg(orgId)) {\n for (const name of await jsonFilesIn(vaultRoot)) {\n const path = join(vaultRoot, name);\n let parsed: unknown;\n try {\n parsed = JSON.parse(await readFile(path, 'utf-8'));\n } catch {\n // Pas du JSON malgré l'extension : rien de nous à convertir.\n continue;\n }\n const counter = { n: 0 };\n const converted = rekeyJsonValue(parsed, currentKey, newKey, counter);\n if (counter.n === 0) continue;\n pending.push({ path, content: JSON.stringify(converted, null, 2), values: counter.n });\n touchedRoots.add(vaultRoot);\n }\n }\n\n // 2. Sauvegarder chaque coffre touché, entièrement, avant la première écriture.\n const stamp = now.toISOString().replace(/[:.]/g, '-').substring(0, 19);\n const backups: string[] = [];\n for (const vaultRoot of touchedRoots) {\n const backupDir = join(vaultRoot, `backup-key-${stamp}`);\n await mkdir(backupDir, { recursive: true });\n for (const name of await jsonFilesIn(vaultRoot)) {\n await copyFile(join(vaultRoot, name), join(backupDir, name));\n }\n // La clé d'origine part avec : sans elle, la sauvegarde ne s'ouvrirait plus.\n for (const name of ['.encryption.key.enc', '.runeya-verify']) {\n if (await exists(join(vaultRoot, name))) {\n await copyFile(join(vaultRoot, name), join(backupDir, name));\n }\n }\n backups.push(backupDir);\n }\n\n // 3. Écrire, atomiquement comme partout ailleurs dans les coffres.\n for (const item of pending) {\n const tmp = item.path + '.tmp';\n await writeFile(tmp, item.content, 'utf-8');\n await rename(tmp, item.path);\n }\n\n // 4. La clé de l'organisation en dernier : tant qu'elle n'a pas basculé, les\n // données converties sont inaccessibles, et c'est le bon sens de l'échec.\n await installOrgKey(orgId, newKey, masterPassword);\n clearVaultLock(orgId);\n\n // 5. Les stores ont lu le disque d'avant : leur mémoire décrit un coffre qui\n // n'existe plus. Sans cet oubli, l'interface continuerait d'annoncer des\n // données illisibles alors qu'elles viennent d'être réparées — et, plus\n // grave, la première sauvegarde réécrirait l'ancien chiffré par-dessus le\n // nouveau, défaisant en silence ce que les étapes 1 à 4 ont fait.\n environmentStore.resetCache();\n serviceStore.resetCache();\n conversationStore.resetCache();\n apiKeyStore.resetCache();\n\n return { converted: pending.map(({ path, values }) => ({ file: path, values })), backups };\n}\n","import { readdir, stat } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { isAbsolute, join, resolve, dirname, basename } from 'node:path';\nimport { z } from 'zod';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { holdsRuneyaProject, projectPathStore } from '../../services/project-path-store.js';\nimport { resolveWorkspaceCwd } from '../../services/workspace-cwd.js';\n\n/**\n * Directory browsing, for choosing where a cloud project lives on this machine.\n *\n * The browser cannot produce an absolute path — `showDirectoryPicker` yields an\n * opaque handle and `webkitdirectory` only relative names — so the machine has\n * to offer the tree itself.\n *\n * Deliberately narrow: directories only, never file contents, never file names.\n * Listing a tree is already more than the rest of the API exposes, so it gives\n * away as little as it can while still being usable. It stays behind\n * `protectedProcedure` like everything else, and the server only ever binds to\n * localhost.\n */\n\n/** Entries returned for one directory. Enough for deep trees, bounded for /nix and friends. */\nconst MAX_ENTRIES = 500;\n\nconst PATH_SCHEMA = z.string().min(1).max(4096);\n\nexport interface DirectoryEntry {\n name: string;\n path: string;\n /** A directory already holding a Runeya project cannot receive another one. */\n hasRuneyaProject: boolean;\n}\n\n/** Reject anything that is not a plain absolute path before touching the disk. */\nfunction safeResolve(input: string): string {\n if (input.includes('\\0')) throw new Error('Chemin invalide');\n const expanded = input.startsWith('~') ? join(homedir(), input.slice(1)) : input;\n if (!isAbsolute(expanded)) throw new Error('Le chemin doit être absolu');\n return resolve(expanded);\n}\n\nexport const filesystemRouter = router({\n /** Where a picker should open when the user has chosen nothing yet. */\n suggestedRoots: protectedProcedure.query(async () => {\n const roots = [\n { label: 'home', path: homedir() },\n // The launch directory, taken from the vault rather than the process.\n { label: 'cwd', path: await resolveWorkspaceCwd({}) },\n ];\n // De-duplicated: launching from home would otherwise offer the same row twice.\n const seen = new Set<string>();\n return roots.filter((r) => !seen.has(r.path) && seen.add(r.path));\n }),\n\n /**\n * The sub-directories of one directory.\n *\n * Hidden entries are skipped: they are noise for choosing a workspace, and\n * `.runeya` itself would invite placing a project inside another's data.\n */\n listDirectories: protectedProcedure\n .input(z.object({ path: PATH_SCHEMA }))\n .query(async ({ input }) => {\n const dir = safeResolve(input.path);\n\n const info = await stat(dir).catch(() => null);\n if (!info?.isDirectory()) {\n throw new Error(`Ce n'est pas un répertoire : ${dir}`);\n }\n\n let names: string[];\n try {\n names = (await readdir(dir, { withFileTypes: true }))\n .filter((e) => e.isDirectory() && !e.name.startsWith('.'))\n .map((e) => e.name)\n .sort((a, b) => a.localeCompare(b));\n } catch {\n throw new Error(`Répertoire illisible : ${dir}`);\n }\n\n const truncated = names.length > MAX_ENTRIES;\n const entries: DirectoryEntry[] = [];\n for (const name of names.slice(0, MAX_ENTRIES)) {\n const path = join(dir, name);\n entries.push({ name, path, hasRuneyaProject: await holdsRuneyaProject(path) });\n }\n\n return {\n path: dir,\n // Null at the filesystem root, which is what stops \"up\" from looping.\n parent: dirname(dir) === dir ? null : dirname(dir),\n name: basename(dir) || dir,\n entries,\n truncated,\n hasRuneyaProject: await holdsRuneyaProject(dir),\n };\n }),\n\n /**\n * Whether a directory can receive this project.\n *\n * Two projects in one directory is what makes services run against the wrong\n * code, so a directory that already holds one is refused outright.\n */\n checkProjectTarget: protectedProcedure\n .input(z.object({\n path: PATH_SCHEMA,\n projectId: z.string().min(1).max(128),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .query(async ({ input }) => {\n const dir = safeResolve(input.path);\n\n const info = await stat(dir).catch(() => null);\n if (!info?.isDirectory()) {\n return { ok: false as const, reason: 'missing' as const, path: dir, otherProjectId: null };\n }\n if (await holdsRuneyaProject(dir)) {\n return { ok: false as const, reason: 'has-runeya-project' as const, path: dir, otherProjectId: null };\n }\n const otherProjectId = await projectPathStore.projectAt(dir, { id: input.projectId, orgId: input.orgId });\n if (otherProjectId) {\n return { ok: false as const, reason: 'taken' as const, path: dir, otherProjectId };\n }\n return { ok: true as const, reason: null, path: dir, otherProjectId: null };\n }),\n});\n","import { z } from 'zod';\nimport { isAbsolute } from 'node:path';\nimport { TRPCError } from '@trpc/server';\nimport { protectedProcedure, router } from '../trpc.js';\nimport { suggestLauncher, installLauncher } from '../../services/desktop-launcher.js';\nimport { setTrayAccent } from '../../services/tray-accent.js';\n\n/**\n * Le raccourci de bureau, créé depuis l'interface plutôt qu'en retapant\n * `runeya install-desktop`.\n *\n * `protectedProcedure` : la suggestion révèle le dossier de travail et les\n * ports de l'instance, et l'installation écrit dans l'environnement de bureau\n * de l'utilisateur.\n */\nexport const desktopRouter = router({\n /** Ce que le CLI demanderait, prérempli avec l'instance en cours. */\n suggestLauncher: protectedProcedure.query(() => suggestLauncher()),\n\n /**\n * La couleur du thème de cet onglet.\n *\n * Le thème vit dans le navigateur ; l'icône de barre système, elle, est\n * dessinée par le serveur. Sans cette annonce elle garderait la teinte figée\n * du fichier livré avec le CLI. Rien n'est persisté — voir `tray-accent.ts`.\n */\n setTrayAccent: protectedProcedure\n .input(z.object({\n // `#rgb` ou `#rrggbb` : la forme est vérifiée ici, pas rabotée plus loin.\n color: z.string().regex(/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/).nullable(),\n }))\n .mutation(({ input }) => {\n setTrayAccent(input.color);\n return { ok: true as const };\n }),\n\n installLauncher: protectedProcedure\n .input(z.object({\n name: z.string().trim().min(1).max(120),\n /**\n * `null` : raccourci global, sans dossier épinglé. Sinon un chemin\n * absolu, refusé autrement : le dossier devient un argument positionnel\n * du CLI, où une valeur commençant par un tiret passerait pour un drapeau.\n */\n workingDir: z.string().max(4096).refine(isAbsolute, {\n message: 'Le dossier de travail doit être un chemin absolu.',\n }).nullable(),\n port: z.number().int().min(1).max(65535),\n agentPort: z.number().int().min(1).max(65535),\n }))\n .mutation(async ({ input }) => {\n try {\n return await installLauncher(input);\n } catch (err) {\n const message = (err as Error).message;\n if (message === 'launcher-working-dir-not-absolute') {\n throw new TRPCError({\n code: 'BAD_REQUEST',\n message: 'Le dossier de travail doit être un chemin absolu.',\n });\n }\n if (message === 'launcher-unavailable') {\n throw new TRPCError({\n code: 'PRECONDITION_FAILED',\n message: 'Cette Runeya ne sait pas où trouver son CLI : créez le raccourci avec `runeya install-desktop`.',\n });\n }\n throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message });\n }\n }),\n});\n","/**\n * Créer un raccourci de bureau depuis l'interface, pour une Runeya lancée\n * depuis un terminal.\n *\n * Le raccourci lui-même est écrit par `runeya install-desktop` : c'est lui qui\n * sait produire un `.desktop`, un `.app` ou un `.lnk`, et le dupliquer ici\n * dupliquerait aussi ses corrections. Ce service ne fait donc que deux choses —\n * proposer les réponses que le CLI demanderait (dossier, nom, ports), et\n * rejouer la sous-commande sans poser de question.\n *\n * Le chemin du CLI n'est pas deviné : c'est le CLI qui l'annonce au démarrage\n * (`registerCli`). Sans cet appel — un serveur lancé autrement, une suite de\n * tests — la fonctionnalité se déclare simplement indisponible plutôt que de\n * lancer un exécutable au hasard.\n */\nimport { execFile } from 'node:child_process';\nimport { isAbsolute } from 'node:path';\nimport { promisify } from 'node:util';\nimport { deriveLauncherIdentity } from '@runeya/packages-shared';\nimport { env } from '../config/env.js';\n\nconst exec = promisify(execFile);\n\n/** Au-delà, l'écriture des fichiers a visiblement échoué autrement qu'en erreur. */\nconst INSTALL_TIMEOUT_MS = 30_000;\n\ntype CliLocation = { execPath: string; cliEntry: string };\n\nlet cli: CliLocation | null = null;\n\n/** Annoncé par le CLI au démarrage : l'exécutable Node et l'entrée du CLI. */\nexport function registerCli(location: CliLocation): void {\n cli = location;\n}\n\nexport type LauncherSuggestion = {\n /** Le CLI s'est annoncé : le raccourci peut être créé d'ici. */\n available: boolean;\n /** Cette instance vient déjà d'un raccourci — en proposer un n'a pas de sens. */\n fromDesktop: boolean;\n /** Le dossier que le raccourci épinglerait : celui de cette instance. */\n workingDir: string;\n /** Le nom que le CLI proposerait pour ce dossier. */\n name: string;\n port: number;\n agentPort: number;\n};\n\n/**\n * Les réponses préremplies : celles de l'instance en cours.\n *\n * Un raccourci sert à retrouver *cette* pile — mêmes dossier et mêmes ports —\n * sans retaper la commande. Les ports sont donc ceux réellement en service, pas\n * un tirage : deux Runeya au même port ne peuvent pas cohabiter, et celle-ci\n * tient déjà le sien.\n */\nexport function suggestLauncher(): LauncherSuggestion {\n const workingDir = process.cwd();\n return {\n available: cli !== null,\n fromDesktop: env.FROM_DESKTOP,\n workingDir,\n name: deriveLauncherIdentity(undefined, workingDir).name,\n port: env.PORT,\n agentPort: env.RUNEYA_AGENT_PORT,\n };\n}\n\nexport type InstallLauncherInput = {\n name: string;\n /** `null` : raccourci global, sans dossier épinglé. */\n workingDir: string | null;\n port: number;\n agentPort: number;\n};\n\nexport type InstallLauncherResult = {\n name: string;\n /** Le rapport du CLI, tel qu'il l'écrit — chemins des fichiers et avertissements. */\n output: string;\n};\n\n/**\n * Rejouer `runeya install-desktop` sans question.\n *\n * Le sous-processus n'a pas de TTY : le magicien du CLI ne se déclenche donc\n * pas, et chaque réponse arrive par un drapeau. Rien n'est écrit ici — c'est le\n * CLI qui écrit, et c'est son rapport qui est renvoyé.\n */\nexport async function installLauncher(input: InstallLauncherInput): Promise<InstallLauncherResult> {\n if (!cli) throw new Error('launcher-unavailable');\n /**\n * Le dossier part en argument positionnel, et le CLI lit ses arguments\n * lui-même : une valeur commençant par un tiret y serait un drapeau, pas un\n * chemin — `--help` ferait afficher l'aide au lieu d'installer. Un chemin\n * absolu est de toute façon la seule chose qu'un lanceur puisse épingler,\n * puisqu'il démarre sans répertoire courant à lui.\n */\n if (input.workingDir !== null && !isAbsolute(input.workingDir)) {\n throw new Error('launcher-working-dir-not-absolute');\n }\n\n const args = [\n cli.cliEntry,\n 'install-desktop',\n ...(input.workingDir === null ? ['--no-cwd'] : [input.workingDir]),\n '--name', input.name,\n '--port', String(input.port),\n '--agent-port', String(input.agentPort),\n ];\n\n const { stdout, stderr } = await exec(cli.execPath, args, {\n timeout: INSTALL_TIMEOUT_MS,\n windowsHide: true,\n // Le rapport tient en quelques lignes ; au-delà, quelque chose a dérapé.\n maxBuffer: 1024 * 1024,\n // Sans terminal, le CLI n'ajoute pas de couleurs : la sortie est lisible telle quelle.\n env: { ...process.env, NO_COLOR: '1' },\n });\n\n return { name: input.name, output: [stdout, stderr].filter((s) => s.trim()).join('\\n').trim() };\n}\n","/**\n * La couleur du thème que l'utilisateur regarde, connue du serveur.\n *\n * Le thème vit dans le `localStorage` du navigateur : le serveur ne le\n * connaîtrait pas sans cette annonce. C'est le même chemin que le projet\n * ouvert (`current-project.ts`), et pour la même raison — l'icône de barre\n * système n'a pas d'onglet, et sans cela elle resterait de la couleur figée\n * des fichiers livrés avec le CLI pendant que l'interface change de teinte.\n *\n * Gardée en mémoire, jamais sur le disque : c'est l'état d'une session\n * d'affichage. Un redémarrage repart sans couleur — l'icône livrée reprend sa\n * place — et l'onglet la redit en se rouvrant.\n */\n\nlet accent: string | null = null;\nconst listeners = new Set<() => void>();\n\n/** La couleur annoncée, ou `null` tant qu'aucun onglet ne l'a dite. */\nexport function getTrayAccent(): string | null {\n return accent;\n}\n\n/**\n * Annonce la couleur du thème.\n *\n * Ne prévient que si elle change vraiment : un onglet qui répète la sienne — au\n * rechargement, ou à chaque reconnexion — ne doit pas faire redessiner ce qui\n * n'a pas bougé, ni relancer le rendu d'une icône identique.\n */\nexport function setTrayAccent(next: string | null): void {\n const normalized = next === null ? null : next.trim().toLowerCase();\n if (normalized === accent) return;\n accent = normalized;\n for (const listener of listeners) {\n try {\n listener();\n } catch {\n // Un abonné qui échoue ne doit pas empêcher les autres d'être prévenus.\n }\n }\n}\n\nexport function onTrayAccentChanged(listener: () => void): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n","import { router } from './trpc.js';\nimport { healthRouter } from './routers/health.js';\nimport { appUpdateRouter } from './routers/app-update.js';\nimport { changelogRouter } from './routers/changelog.js';\nimport { projectRouter } from './routers/project.js';\nimport { serviceRouter } from './routers/service.js';\nimport { agentRouter } from './routers/agent.js';\nimport { processRouter } from './routers/process.js';\nimport { auditRouter } from './routers/audit.js';\nimport { setupRouter } from './routers/setup.js';\nimport { environmentRouter } from './routers/environment.js';\nimport { settingsRouter } from './routers/settings.js';\nimport { editorRouter } from './routers/editor.js';\nimport { apiKeysRouter } from './routers/api-keys.js';\nimport { chatRouter } from './routers/chat.js';\nimport { gitRouter } from './routers/git.js';\nimport { scenarioRouter } from './routers/scenario.js';\nimport { debugRouter } from './routers/debug.js';\nimport { diagnosticsRouter } from './routers/diagnostics.js';\nimport { kanbanQueueRouter } from './routers/kanban-queue.js';\nimport { kanbanRouter } from './routers/kanban.js';\nimport { terminalRouter } from './routers/terminal.js';\nimport { utilityRouter } from './routers/utility.js';\nimport { wikiRouter } from './routers/wiki.js';\nimport { configRouter } from './routers/config.js';\nimport { cloudSyncRouter } from './routers/cloud-sync.js';\nimport { cloudAuthRouter } from './routers/cloud-auth.js';\nimport { filesystemRouter } from './routers/filesystem.js';\nimport { desktopRouter } from './routers/desktop.js';\n\n// Re-export server types used in AppRouter so consumers can name them (avoids TS4023)\nexport type { AuditEntry } from '../services/audit-service.js';\nexport type { CliUsageEntry } from '../services/claude-usage.js';\nexport type { Conversation } from '../services/conversation-store.js';\nexport type { KanbanQueueItem, KanbanQueueState } from '../services/kanban-queue.js';\nexport type { PersistedRunState, RunState } from '../services/scenario-run-store.js';\n\nexport const appRouter = router({\n health: healthRouter,\n appUpdate: appUpdateRouter,\n changelog: changelogRouter,\n diagnostics: diagnosticsRouter,\n project: projectRouter,\n service: serviceRouter,\n agent: agentRouter,\n process: processRouter,\n audit: auditRouter,\n setup: setupRouter,\n environment: environmentRouter,\n settings: settingsRouter,\n editor: editorRouter,\n apiKeys: apiKeysRouter,\n chat: chatRouter,\n scenario: scenarioRouter,\n git: gitRouter,\n debug: debugRouter,\n kanbanQueue: kanbanQueueRouter,\n kanban: kanbanRouter,\n terminal: terminalRouter,\n utility: utilityRouter,\n wiki: wikiRouter,\n config: configRouter,\n cloudSync: cloudSyncRouter,\n cloudAuth: cloudAuthRouter,\n filesystem: filesystemRouter,\n desktop: desktopRouter,\n});\n\nexport type AppRouter = typeof appRouter;\n","import { Request, Response, NextFunction } from 'express';\n\nexport function errorHandler(err: Error, _req: Request, res: Response, _next: NextFunction): void {\n console.error('[server] Unhandled error:', err);\n res.status(500).json({ error: 'Internal server error' });\n}\n","import { settingsManager } from './settings-manager.js';\n\n\ninterface Migration {\n version: number;\n name: string;\n up: () => Promise<void>;\n}\n\n// Migrations are registered here. Each adds a transform function.\nconst migrations: Migration[] = [\n];\n\nclass MigrationEngine {\n async run(): Promise<void> {\n const schemaVersion = await settingsManager.getSchemaVersion();\n const currentVersion = schemaVersion.version;\n const targetVersion = settingsManager.getCurrentSchemaVersion();\n\n if (currentVersion >= targetVersion) {\n console.log(`[migration] Schema is up to date (v${currentVersion})`);\n return;\n }\n\n console.log(`[migration] Migrating from v${currentVersion} to v${targetVersion}`);\n const pending = migrations.filter(m => m.version > currentVersion && m.version <= targetVersion);\n pending.sort((a, b) => a.version - b.version);\n\n for (const migration of pending) {\n console.log(`[migration] Running: ${migration.name} (v${migration.version})`);\n await migration.up();\n await settingsManager.saveSchemaVersion({ version: migration.version, migratedAt: new Date() });\n console.log(`[migration] Done: ${migration.name}`);\n }\n\n console.log(`[migration] All migrations complete. Now at v${targetVersion}`);\n }\n}\n\nexport const migrationEngine = new MigrationEngine();\n","import { chmod, stat } from 'node:fs/promises';\nimport { machineFilePath, legacyMachineFilePath } from './vault-resolver.js';\n\nconst SENSITIVE_FILES = [\n 'agents.json',\n 'settings.json',\n 'services.json',\n 'projects.json',\n 'deployments.json',\n 'schema-version.json',\n];\n\nconst SECURE_MODE = 0o600;\n\n/**\n * Ensure all sensitive data files have restrictive permissions (0600).\n * Logs warnings for files with overly permissive modes and auto-fixes them.\n */\nexport async function ensureFilePermissions(): Promise<void> {\n for (const filename of SENSITIVE_FILES) {\n // Both homes are checked: a directory written by an older version still\n // holds these files, and lax permissions there are just as bad.\n for (const filepath of [machineFilePath(filename), legacyMachineFilePath(filename)]) {\n try {\n const stats = await stat(filepath);\n const mode = stats.mode & 0o777;\n if (mode !== SECURE_MODE) {\n console.warn('[security] File', filepath, 'has mode', mode.toString(8) + ', fixing to 600');\n await chmod(filepath, SECURE_MODE);\n }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n console.warn('[security] Cannot check permissions for', filepath + ':', err instanceof Error ? err.message : String(err));\n }\n // ENOENT is fine — file doesn't exist yet\n }\n }\n }\n}\n","import { readdir, readFile, writeFile, mkdir, copyFile, unlink, rename, stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { rekeyJsonValue } from './key-adoption.js';\nimport { readEncryptedKey, verifyEncryptionKey } from './master-password.js';\n\n/**\n * Converts a vault left under its own key to the machine key.\n *\n * Older versions let the launch directory hold a key of its own, so a machine\n * ended up with several master passwords — and, since the cloud session lives\n * beside the key that opens it, several cloud identities. Such a vault is no\n * longer obeyed (see `keyRoot`), which would leave its data unreadable: this is\n * what makes it readable again, under the one key that answers for the machine.\n *\n * Values are found by shape, not by schema. `isEncryptedValue` recognizes what\n * `encryptValue` produced, so every ciphertext is re-keyed wherever it sits —\n * including in files added long after this code was written. Enumerating known\n * fields would have quietly skipped whatever the next release introduces.\n */\n\n/** Files that mark a directory as holding a key, and that end the migration. */\nconst KEY_FILES = ['.encryption.key.enc', '.runeya-verify'];\n\n/**\n * Vault files that belong to the machine rather than to the project.\n *\n * They were only ever in the launch directory because the key was, so they move\n * to the machine root. A file already present there is left alone and reported:\n * overwriting the machine's own agents or cloud session with a stale copy would\n * trade one silent loss for another.\n */\nconst MACHINE_FILES = [\n 'agents.json',\n 'cloud-session.json',\n 'conversations.private.json',\n 'api-keys.json',\n 'api-keys.private.json',\n 'settings.private.json',\n];\n\nexport interface VaultMigrationReport {\n /** Where the untouched copy of the vault was kept. */\n backupDir: string;\n /** Files whose ciphertexts were re-keyed, with how many values each held. */\n rekeyed: { file: string; values: number }[];\n /** Machine-level files moved out of the vault. */\n moved: string[];\n /** Machine-level files left in place because the machine already had one. */\n skipped: string[];\n}\n\n/**\n * Recursively re-key every ciphertext in a parsed JSON value.\n *\n * Partagé avec l'adoption d'une autre clé : les deux font le même travail, et\n * la version commune connaît AUSSI le triplet des agents — que cette migration\n * ignorait, laissant chaque passphrase d'agent chiffrée sous la clé abandonnée.\n */\nconst rekeyValue = rekeyJsonValue;\n\n/** JSON files directly inside the vault — never its backups or subdirectories. */\nasync function vaultJsonFiles(root: string): Promise<string[]> {\n const entries = await readdir(root, { withFileTypes: true });\n return entries.filter((e) => e.isFile() && e.name.endsWith('.json')).map((e) => e.name);\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Prove a master password opens this vault, and hand back the key it holds.\n *\n * Both halves matter: `readEncryptedKey` fails on a wrong password (GCM refuses\n * to authenticate), and the canary then proves the key it yielded is the one\n * this vault's data was encrypted with. A password that passes the first but\n * not the second means the vault's files disagree with each other — better\n * refused than half-migrated.\n */\nexport async function openLegacyVault(legacyRoot: string, masterPassword: string): Promise<Buffer> {\n const key = await readEncryptedKey(legacyRoot, masterPassword);\n await verifyEncryptionKey(legacyRoot, key);\n return key;\n}\n\n/**\n * Re-key a legacy vault onto the machine key.\n *\n * Ordered so that nothing is lost if it stops halfway: the backup is complete\n * before the first write, the key files are removed only once every file has\n * been re-read under the new key, and a file that fails to convert aborts the\n * run while the vault is still entirely readable under the old key.\n */\nexport async function migrateLegacyVault(\n legacyRoot: string,\n machineRootDir: string,\n legacyKey: Buffer,\n machineKey: Buffer,\n now: Date,\n): Promise<VaultMigrationReport> {\n const stamp = now.toISOString().replace(/[:.]/g, '-').substring(0, 19);\n const backupDir = join(legacyRoot, `backup-${stamp}`);\n await mkdir(backupDir, { recursive: true });\n\n const jsonFiles = await vaultJsonFiles(legacyRoot);\n\n // 1. Full copy first — including the key files, so the backup opens on its own.\n for (const name of [...jsonFiles, ...KEY_FILES]) {\n if (await exists(join(legacyRoot, name))) {\n await copyFile(join(legacyRoot, name), join(backupDir, name));\n }\n }\n\n // 2. Re-key in place. A parse or write failure throws, leaving the vault as it was.\n const rekeyed: VaultMigrationReport['rekeyed'] = [];\n for (const name of jsonFiles) {\n const raw = await readFile(join(legacyRoot, name), 'utf-8');\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // Not JSON despite the extension — nothing of ours to convert.\n continue;\n }\n const counter = { n: 0 };\n const converted = rekeyValue(parsed, legacyKey, machineKey, counter);\n if (counter.n === 0) continue;\n // Atomic, like every other write in the vault: a half-written file here\n // would be a file no key opens.\n const tmp = join(legacyRoot, `${name}.tmp`);\n await writeFile(tmp, JSON.stringify(converted, null, 2), 'utf-8');\n await rename(tmp, join(legacyRoot, name));\n rekeyed.push({ file: name, values: counter.n });\n }\n\n // 3. Verify every converted value opens under the machine key before going further.\n for (const { file, values } of rekeyed) {\n const parsed = JSON.parse(await readFile(join(legacyRoot, file), 'utf-8'));\n const check = { n: 0 };\n rekeyValue(parsed, machineKey, machineKey, check);\n if (check.n !== values) {\n throw new Error(\n `Vérification échouée pour ${file} : ${check.n} valeur(s) relisible(s) avec la clé machine, ${values} attendue(s)`,\n );\n }\n }\n\n // 4. Machine-level files go where the machine key lives.\n await mkdir(machineRootDir, { recursive: true });\n const moved: string[] = [];\n const skipped: string[] = [];\n for (const name of MACHINE_FILES) {\n const from = join(legacyRoot, name);\n if (!(await exists(from))) continue;\n const to = join(machineRootDir, name);\n if (await exists(to)) {\n skipped.push(name);\n continue;\n }\n await copyFile(from, to);\n await unlink(from);\n moved.push(name);\n }\n\n // 5. Last of all: drop the local key, which is what hands this directory over\n // to the machine key on the next boot.\n for (const name of KEY_FILES) {\n const path = join(legacyRoot, name);\n if (await exists(path)) await unlink(path);\n }\n\n return { backupDir, rekeyed, moved, skipped };\n}\n","import { readFile, writeFile, rename, unlink, mkdir, chmod, stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { machineFilePath, legacyMachineFilePath, orgVaultRoot, listOrgVaults } from './vault-resolver.js';\nimport { settingsManager } from './settings-manager.js';\n\n/**\n * Faire descendre les réglages là où ils appartiennent, une fois.\n *\n * Les réglages vivaient au niveau du poste alors qu'ils décrivent des choses\n * qui appartiennent à des organisations — les fournisseurs d'IA qui paient le\n * travail d'une équipe, les scénarios qui décrivent ses services. Ils\n * descendent donc dans le coffre de l'organisation, et le fichier machine\n * disparaît : un déplacement, pas un repli à la lecture, pour qu'il n'existe\n * jamais deux endroits où le même réglage pourrait se trouver.\n *\n * Une seule organisation sur ce disque : le fichier est à elle, sans ambiguïté.\n *\n * Plusieurs : personne ne peut deviner à laquelle appartenaient des réglages\n * écrits à une époque où la question ne se posait pas — et les recopier dans\n * chacune répandrait les secrets d'une équipe chez les autres. Le fichier reste\n * alors où il est, et l'utilisateur est prévenu qu'il a une répartition à\n * faire. Se tromper silencieusement serait pire que ne rien faire.\n */\n\nconst SETTINGS_FILE = 'settings.json';\nconst SETTINGS_PRIVATE_FILE = 'settings.private.json';\n\nexport interface SettingsMigrationReport {\n /** Organisation ayant reçu les réglages, quand il n'y avait pas de doute. */\n movedTo: string | null;\n /** Fichiers effectivement déplacés. */\n files: string[];\n /**\n * Organisations entre lesquelles il faut trancher à la main, le cas échéant.\n * Vide quand rien n'est ambigu.\n */\n ambiguous: string[];\n}\n\nasync function exists(path: string): Promise<boolean> {\n return stat(path).then(() => true, () => false);\n}\n\n/** Le fichier écrit par une version précédente, où qu'elle l'ait mis. */\nasync function legacySource(filename: string): Promise<string | null> {\n for (const path of [machineFilePath(filename), legacyMachineFilePath(filename)]) {\n if (await exists(path)) return path;\n }\n return null;\n}\n\nasync function moveInto(root: string, filename: string, from: string): Promise<void> {\n await mkdir(root, { recursive: true });\n const to = join(root, filename);\n // Copie puis effacement plutôt qu'un `rename` : la source et la destination\n // peuvent être sur deux systèmes de fichiers différents (un coffre sous\n // `$HOME`, un répertoire de lancement ailleurs), et `rename` échouerait.\n const contents = await readFile(from, 'utf-8');\n const tmp = to + '.tmp';\n await writeFile(tmp, contents, 'utf-8');\n await rename(tmp, to);\n await chmod(to, 0o600);\n await unlink(from);\n}\n\nexport async function migrateSettingsIntoVaults(): Promise<SettingsMigrationReport> {\n const report: SettingsMigrationReport = { movedTo: null, files: [], ambiguous: [] };\n\n const sources: { filename: string; from: string }[] = [];\n for (const filename of [SETTINGS_FILE, SETTINGS_PRIVATE_FILE]) {\n const from = await legacySource(filename);\n if (from) sources.push({ filename, from });\n }\n if (sources.length === 0) return report;\n\n const orgs = await listOrgVaults();\n // Aucune organisation : les réglages sont déjà chez eux, au niveau du poste,\n // qui est bien le propriétaire de ce qui n'appartient à personne d'autre.\n if (orgs.length === 0) return report;\n if (orgs.length > 1) {\n report.ambiguous = orgs;\n return report;\n }\n\n const orgId = orgs[0]!;\n const root = orgVaultRoot(orgId);\n for (const { filename, from } of sources) {\n // Le coffre a déjà le sien : le fichier machine est un reliquat, et\n // l'écraser avec lui reviendrait à annuler des réglages plus récents.\n if (await exists(join(root, filename))) continue;\n await moveInto(root, filename, from);\n report.files.push(filename);\n }\n if (report.files.length > 0) {\n report.movedTo = orgId;\n settingsManager.forget();\n }\n return report;\n}\n","/**\n * Legacy Runeya → Runeya migration\n *\n * Triggered automatically when DATA_DIR/.runeya/dbs/encryption-key.json is found.\n * Must run BEFORE any store initialisation (called at the top of createLocalServer).\n *\n * Steps:\n * 1. Backup existing DATA_DIR contents\n * 2. Extract legacy libsodium key → load in memory for re-encryption\n * 3. Decrypt all .encrypted.json files with libsodium crypto_secretbox\n * 4. Map legacy structures → Runeya JSON files\n * 5. Clear singleton, store key in pending holder → server enters setup state\n * 6. Rename .runeya → backup to prevent re-running\n */\n\nimport { createRequire } from 'module';\nimport { randomBytes, createCipheriv, createDecipheriv } from 'node:crypto';\nimport { randomUUID } from 'node:crypto';\nimport {\n readFile, writeFile, rename, mkdir, access, readdir,\n} from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport { setEncryptionKey, getEncryptionKey, clearEncryptionKey, setPendingLegacyKey } from '../utils/encryption-key.js';\nimport type { Variable } from '@runeya/packages-shared';\nimport { env } from '../config/env.js';\n\n// CJS interop for libsodium-wrappers\nconst _require = createRequire(import.meta.url);\n\n/** Minimal type for the libsodium-wrappers API used in this migration */\ninterface Sodium {\n ready: Promise<void>;\n crypto_secretbox_NONCEBYTES: number;\n crypto_secretbox_open_easy(ciphertext: Uint8Array, nonce: Uint8Array, key: Uint8Array): Uint8Array;\n from_base64(input: string): Uint8Array;\n}\n\n// Parser ID remapping\nconst PARSER_ID_MAP: Record<string, string> = {\n 'stack-monitor-parser-jsons': 'native:json',\n 'stack-monitor-parser-debug': 'native:debug',\n 'stack-monitor-parser-links': 'native:links',\n 'runeya-parser-jsons': 'native:json',\n 'runeya-parser-debug': 'native:debug',\n 'runeya-parser-links': 'native:links',\n};\n\n// ── Runeya AES-256-GCM encryption (matches service-store / environment-store) ──\n\nfunction encryptValue(plaintext: string): string {\n const key = getEncryptionKey();\n if (!key) throw new Error('[legacy-migration] Encryption key not loaded');\n const iv = randomBytes(16);\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n let enc = cipher.update(plaintext, 'utf-8', 'hex');\n enc += cipher.final('hex');\n const authTag = cipher.getAuthTag().toString('hex');\n return `${iv.toString('hex')}:${authTag}:${enc}`;\n}\n\n/** Strip legacy suffixes from a variable key: _RUNEYA_OVERRIDE → _RUNEYA → base */\nfunction cleanVarKey(key: string): string {\n return key.replace(/_RUNEYA(?:_OVERRIDE)?$|_OVERRIDE$/, '');\n}\n\n/** Valid interpolation token: {{VAR_NAME}} or {{environment.VAR_NAME}} — simple identifiers only, no expressions */\nconst VALID_INTERP_RE = /^\\{\\{(?:environment\\.)?[A-Z_][A-Z0-9_]*\\}\\}$/i;\n\n/** Detect interpolation patterns like ${VAR}, $VAR, {{VAR}} */\nfunction hasInterpolation(value: string): boolean {\n return /\\$\\{[^}]+\\}|\\$[A-Z_][A-Z0-9_]*|\\{\\{[^}]+\\}\\}/.test(value);\n}\n\n/** Returns true only for simple variable references — rejects expressions, ternaries, nested accessors */\nfunction isValidInterpolation(token: string): boolean {\n return VALID_INTERP_RE.test(token.trim());\n}\n\n/** Returns true if the value contains any {{...}} token that is not a valid variable reference */\nfunction hasInvalidInterpolation(value: string): boolean {\n const tokens = value.matchAll(/\\{\\{[^}]+\\}\\}/g);\n for (const match of tokens) {\n if (!isValidInterpolation(match[0])) return true;\n }\n return false;\n}\n\n/**\n * Rewrite legacy {{KEY}} interpolation to Runeya's {{environment.KEY}} format.\n * Strips legacy suffixes (_RUNEYA, _OVERRIDE, _RUNEYA_OVERRIDE).\n * Leaves ${VAR} and $VAR patterns untouched (shell interpolation, handled at runtime).\n */\nfunction rewriteInterpolation(value: string): string {\n return value.replace(/\\{\\{(?!environment\\.)([^}]+)\\}\\}/g, (match, key: string) => {\n // Only rewrite simple variable references — leave expressions untouched (will be encrypted)\n if (!isValidInterpolation(match)) return match;\n return `{{environment.${cleanVarKey(key)}}}`;\n });\n}\n\n/**\n * Detect composite interpolation: a value that contains exactly one {{VAR}} token\n * with surrounding text (e.g. \"{{DATABASE_URL}}/onboarding?authSource=admin\").\n * Returns { pre, interp, post } if composite, null otherwise.\n * Values with multiple {{...}} tokens or $VAR/${{VAR}} patterns are left untouched.\n */\nfunction splitCompositeInterpolation(value: string): { pre: string; interp: string; post: string } | null {\n const tokens = [...value.matchAll(/\\{\\{[^}]+\\}\\}/g)];\n if (tokens.length !== 1) return null; // 0 or 2+ interpolations — skip\n if (/\\$\\{[^}]+\\}|\\$[A-Z_][A-Z0-9_]*/.test(value)) return null; // shell vars — skip\n const match = tokens[0];\n if (!isValidInterpolation(match[0])) return null; // expression/ternary — treat as literal\n const pre = value.slice(0, match.index);\n const post = value.slice((match.index ?? 0) + match[0].length);\n if (!pre && !post) return null; // pure interpolation — nothing to split\n return { pre, interp: match[0], post };\n}\n\n/** Decrypt a migration-encrypted value (same AES-256-GCM as encryptValue above) */\nfunction decryptMigrationValue(encrypted: string): string | null {\n try {\n const key = getEncryptionKey();\n if (!key) return null;\n const parts = encrypted.split(':');\n if (parts.length !== 3) return null;\n const [ivHex, authHex, ct] = parts;\n const dec = createDecipheriv('aes-256-gcm', key, Buffer.from(ivHex, 'hex'), { authTagLength: 16 });\n dec.setAuthTag(Buffer.from(authHex, 'hex'));\n return dec.update(ct, 'hex', 'utf-8') + dec.final('utf-8');\n } catch { return null; }\n}\n\n/**\n * Returns true if the override raw value is identical to the base variable's stored value.\n * Skips writing a redundant override when base and override resolve to the same thing.\n */\nfunction isSameAsBase(overrideRawValue: string, baseVar: Variable | undefined): boolean {\n if (!baseVar) return false;\n const baseSlot = baseVar.value;\n if (!baseSlot.isSecret) {\n return baseSlot.value === rewriteInterpolation(overrideRawValue);\n }\n const decrypted = decryptMigrationValue(baseSlot.value);\n return decrypted === overrideRawValue;\n}\n\n/** Build a Variable with key and value slot — encrypted if secret, plaintext (with rewritten interpolation) otherwise */\nfunction makeVariable(key: string, value: string, pre = '', post = ''): Variable {\n // Auto-detect composite interpolation and ventilate into pre/value/post\n const composite = splitCompositeInterpolation(value);\n if (composite) {\n return {\n key,\n value: {\n value: rewriteInterpolation(composite.interp),\n pre: rewriteInterpolation(pre + composite.pre),\n post: rewriteInterpolation(composite.post + post),\n isSecret: false,\n shareWithAi: false,\n injectIntoAi: false,\n required: false,\n overrideOnly: false,\n description: '',\n },\n };\n }\n\n const secret = !hasInterpolation(value);\n return {\n key,\n value: {\n value: secret ? encryptValue(value) : rewriteInterpolation(value),\n pre: rewriteInterpolation(pre),\n post: rewriteInterpolation(post),\n isSecret: secret,\n shareWithAi: false,\n injectIntoAi: false,\n required: false,\n overrideOnly: false,\n description: '',\n },\n };\n}\n\n// ── libsodium decryption ──────────────────────────────────────────────────────\n\nasync function getSodium(): Promise<Sodium> {\n const _sodium = _require('libsodium-wrappers') as Sodium;\n await _sodium.ready;\n return _sodium;\n}\n\nasync function decryptLegacyFile(\n filePath: string,\n key: Uint8Array,\n sodium: Sodium,\n): Promise<unknown> {\n const raw = (await readFile(filePath, 'utf-8')).trim();\n if (!raw || raw === '[]' || raw === '{}') {\n try { return JSON.parse(raw); } catch { return {}; }\n }\n\n const buf = Buffer.from(raw, 'base64');\n const nonce = buf.subarray(0, sodium.crypto_secretbox_NONCEBYTES as number);\n const ciphertext = buf.subarray(sodium.crypto_secretbox_NONCEBYTES as number);\n const decrypted = sodium.crypto_secretbox_open_easy(\n new Uint8Array(ciphertext),\n new Uint8Array(nonce),\n key,\n ) as Uint8Array;\n\n return JSON.parse(Buffer.from(decrypted).toString('utf-8'));\n}\n\n// ── Atomic write helper ───────────────────────────────────────────────────────\n\nasync function atomicWrite(path: string, data: unknown): Promise<void> {\n const tmp = path + '.tmp';\n await writeFile(tmp, JSON.stringify(data, null, 2), 'utf-8');\n await rename(tmp, path);\n}\n\n// ── Main migration entry point ────────────────────────────────────────────────\n\nexport async function runLegacyMigration(dataDir: string): Promise<boolean> {\n // Legacy .runeya sits in the launch directory. `env.DATA_DIR` is already\n // absolute — resolved once at boot — so it IS that path; joining it onto a\n // cwd would build a nonsense one.\n const legacyRoot = env.DATA_DIR;\n const legacyKeyPath = join(legacyRoot, 'dbs', 'encryption-key.json');\n\n // Detect legacy installation\n try {\n await access(legacyKeyPath);\n } catch {\n return false;\n }\n\n console.log('[legacy-migration] Legacy Runeya data detected, starting migration…');\n\n // ── 1. Move legacy .runeya → .runeya/backup-<date>, create fresh DATA_DIR ───\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-').substring(0, 19);\n // Frère de `legacyRoot`, pas un enfant : on va recréer `dataDir` (le même\n // chemin) juste après, et un temporaire placé dedans serait emporté.\n const legacyTmp = `${legacyRoot}-tmp`;\n await rename(legacyRoot, legacyTmp); // free up the .runeya name\n await mkdir(dataDir, { recursive: true }); // create fresh .runeya/\n const legacyOld = join(dataDir, `backup-${timestamp}`);\n await rename(legacyTmp, legacyOld); // move into .runeya/backup-<date>\n console.log(`[legacy-migration] Legacy data backed up to ${legacyOld}`);\n\n // ── 2. Extract legacy key and initialise Runeya encryption ─────────────────\n const keyJson = JSON.parse(await readFile(join(legacyOld, 'dbs', 'encryption-key.json'), 'utf-8')) as { encryptionKey: string };\n const sodium = await getSodium();\n const sodiumKey = sodium.from_base64(keyJson.encryptionKey) as Uint8Array;\n\n // Load key into singleton temporarily — needed by encryptValue/makeVariable during re-encryption\n const keyBuffer = Buffer.from(sodiumKey);\n const runyeaKeyHex = keyBuffer.toString('hex');\n await setEncryptionKey(runyeaKeyHex);\n console.log('[legacy-migration] Encryption key loaded in memory (temporary)');\n\n // ── 3. Decrypt all legacy files ─────────────────────────────────────────────\n const dbsDir = join(legacyOld, 'dbs');\n\n async function readEncrypted(filePath: string): Promise<any> {\n try {\n return await decryptLegacyFile(filePath, sodiumKey, sodium);\n } catch (err: unknown) {\n console.warn(`[legacy-migration] Failed to decrypt ${filePath}: ${(err as Error).message}`);\n return null;\n }\n }\n\n // Environments\n const envsDir = join(dbsDir, 'envs');\n const envFiles = (await readdir(envsDir).catch(() => [] as string[]))\n .filter(f => f.endsWith('.encrypted.json'));\n\n const legacyEnvs: Record<string, any> = {};\n for (const file of envFiles) {\n const name = file.replace('.encrypted.json', '');\n legacyEnvs[name] = await readEncrypted(join(envsDir, file));\n }\n\n // Services\n const servicesDir = join(dbsDir, 'services');\n const serviceFiles = (await readdir(servicesDir).catch(() => [] as string[]))\n .filter(f => f.endsWith('.encrypted.json'));\n\n const legacyServices: Record<string, any> = {};\n for (const file of serviceFiles) {\n const name = file.replace('.encrypted.json', '');\n if (!name) continue; // skip empty default service\n const data = await readEncrypted(join(servicesDir, file));\n if (data?.label) legacyServices[name] = data;\n }\n\n // Overrides\n const overridesDir = join(dbsDir, 'overrides');\n const overrideFiles = (await readdir(overridesDir).catch(() => [] as string[]))\n .filter(f => f.endsWith('.encrypted.json'));\n\n const legacyServiceOverrides: Record<string, any> = {};\n const legacyEnvOverrides: Record<string, any> = {};\n\n for (const file of overrideFiles) {\n const baseName = file.replace('.encrypted.json', '');\n const data = await readEncrypted(join(overridesDir, file));\n if (!data) continue;\n\n if (baseName.endsWith('-envs')) {\n legacyServiceOverrides[baseName.slice(0, -5)] = data;\n } else if (baseName.endsWith('-environment')) {\n legacyEnvOverrides[baseName.slice(0, -12)] = data;\n }\n }\n\n // Custom parsers\n const parsersDir = join(dbsDir, 'parsers');\n const parserFiles = (await readdir(parsersDir).catch(() => [] as string[]))\n .filter(f => f.endsWith('.encrypted.json'));\n\n const legacyParsers: any[] = [];\n for (const file of parserFiles) {\n const data = await readEncrypted(join(parsersDir, file));\n if (data?.id) legacyParsers.push(data);\n }\n\n // ── 4. Build Runeya data structures ─────────────────────────────────────────\n\n // Projects\n const projectMonoId = randomUUID();\n\n // Environments — two-pass to resolve parentIds after all IDs are known\n // envIdMap keyed by filename (without extension) for ID lookup\n const envIdMap: Record<string, string> = {};\n // labelToKey maps label → filename key, for resolving extends references\n const labelToKey: Record<string, string> = {};\n for (const [name, legacyEnv] of Object.entries(legacyEnvs)) {\n envIdMap[name] = randomUUID();\n if (legacyEnv?.label) labelToKey[legacyEnv.label] = name;\n }\n\n const runeEnvs: any[] = [];\n const defaultEnvName = Object.entries(legacyEnvs).find(([, v]) => v?.default)?.[0];\n\n // Lookup map: `${envId}:${cleanedVarName}` → variableId (UUID)\n const varIdLookup = new Map<string, string>();\n\n for (const [name, legacyEnv] of Object.entries(legacyEnvs)) {\n if (!legacyEnv) continue;\n\n // Collect all variables inherited from parent envs (union, first-parent wins)\n const inheritedVars: Record<string, string> = {};\n for (const parentLabel of legacyEnv.extends || []) {\n const parentKey = labelToKey[parentLabel] ?? parentLabel;\n const parentEnv = legacyEnvs[parentKey];\n for (const [k, v] of Object.entries(parentEnv?.envs ?? {})) {\n if (typeof v === 'string') {\n const cleaned = cleanVarKey(k);\n if (!(cleaned in inheritedVars)) inheritedVars[cleaned] = v;\n }\n }\n }\n\n const variables: Record<string, Variable> = {};\n for (const [key, value] of Object.entries(legacyEnv.envs || {})) {\n if (typeof value === 'string') {\n if (hasInvalidInterpolation(value)) continue;\n const cleaned = cleanVarKey(key);\n // Skip if identical to inherited value — the child inherits it anyway\n if (inheritedVars[cleaned] === value) continue;\n const varId = randomUUID();\n variables[varId] = makeVariable(cleaned, value);\n varIdLookup.set(`${envIdMap[name]}:${cleaned}`, varId);\n }\n }\n\n runeEnvs.push({\n id: envIdMap[name],\n projectId: projectMonoId,\n name: legacyEnv.label || name,\n description: '',\n scope: 'global' as const,\n parentIds: (legacyEnv.extends || [])\n .map((p: string) => envIdMap[labelToKey[p] ?? p])\n .filter(Boolean),\n immutable: false,\n default: name === defaultEnvName,\n color: legacyEnv.bgColor || '#22c55e',\n variables,\n });\n }\n\n // Services\n const serviceIdMap: Record<string, string> = {};\n const runeServices: any[] = [];\n\n for (const [name, legacy] of Object.entries(legacyServices)) {\n const id = randomUUID();\n serviceIdMap[name] = id;\n\n // rootPath = legacy global working directory for this service\n const rootPath: string = legacy.rootPath || '';\n const rootPathCwd = rootPath && rootPath !== '.' ? rootPath : '';\n\n // Commands: spawnCmd + spawnArgs → single command string\n // Command cwd only set if the command has its own explicit cwd (not inherited from rootPath)\n const commands: any[] = [];\n for (const cmd of legacy.commands || []) {\n const parts = [cmd.spawnCmd, ...(cmd.spawnArgs || [])].filter(Boolean);\n if (!parts.length) continue;\n commands.push({\n id: cmd.id || randomUUID(),\n label: 'Launch',\n command: parts.join(' '),\n cwd: cmd.spawnOptions?.cwd || '',\n shell: false,\n });\n }\n\n // Parser IDs — deduplicated, remapped\n const effectiveParsers: any[] =\n legacy.commands?.[0]?.effectiveParsers\n ?? legacy.parsers\n ?? [];\n\n const parserIds: string[] = [];\n for (const parser of effectiveParsers) {\n const rawId: string = typeof parser === 'string' ? parser : (parser.id ?? '');\n const mapped = PARSER_ID_MAP[rawId] ?? rawId;\n if (mapped && !parserIds.includes(mapped)) {\n if (!PARSER_ID_MAP[rawId]) {\n console.warn(`[legacy-migration] Unknown parser \"${rawId}\" on service \"${name}\" — kept as-is`);\n }\n parserIds.push(mapped);\n }\n }\n\n // Health check — extract path from URL, rename returnCode → expectedStatus\n // Only migrate if explicitly enabled (or if enabled field absent, presence of URL implies intent)\n let healthCheck: any;\n if (legacy.health?.url && legacy.health?.enabled !== false) {\n try {\n const healthUrl = new URL(legacy.health.url);\n healthCheck = {\n path: healthUrl.pathname || '/',\n method: legacy.health.method || 'GET',\n ...(typeof legacy.health.interval === 'number' && { interval: legacy.health.interval }),\n expectedStatus: legacy.health.returnCode || 200,\n };\n } catch {\n // Invalid URL — skip health check\n }\n }\n\n // Docker config — map legacy container fields to DockerConfig\n // Legacy structure: container.build (Dockerfile content), container.bootstrap.commands,\n // container.volumes, container.ports, container.name, container.ignoreVolumes, etc.\n let dockerConfig: any;\n const container = legacy.container;\n if (container?.enabled) {\n dockerConfig = {\n volumes: container.volumes || [],\n ports: container.ports || [],\n networkMode: container.networkMode || 'host',\n };\n\n // Dockerfile — legacy uses \"build\" field (not \"dockerfile\")\n // buildContext defaults to \".\" (Docker needs a valid context for COPY/ADD)\n if (container.build) {\n dockerConfig.dockerfile = container.build;\n dockerConfig.buildContext = '.';\n }\n\n // Image (pull mode, mutually exclusive with Dockerfile in UI)\n // Legacy \"name\" field can serve as image if no explicit \"image\" field\n if (container.image) {\n dockerConfig.image = container.image;\n } else if (container.name && !container.build) {\n dockerConfig.image = container.name;\n }\n\n // Build args — legacy uses container.buildArgs (Record<string, string>)\n if (container.buildArgs && typeof container.buildArgs === 'object') {\n dockerConfig.buildArgs = container.buildArgs;\n }\n\n // Target stage — legacy uses container.targetStage\n if (container.targetStage) {\n dockerConfig.targetStage = container.targetStage;\n }\n\n // User — legacy uses container.user or bootstrap command user\n if (container.user) {\n dockerConfig.user = container.user;\n }\n\n // Bootstrap commands — legacy uses container.bootstrap.commands[]\n // Each entry has { entrypoint, cmd, user }\n // Migrate ALL commands as bootstrapCommands[] (structured array)\n const legacyBootstrapCmds: any[] = container.bootstrap?.commands || [];\n if (legacyBootstrapCmds.length > 0) {\n dockerConfig.bootstrapCommands = legacyBootstrapCmds\n .filter((bs: any) => bs.cmd || bs.entrypoint)\n .map((bs: any, idx: number) => ({\n id: bs.id || randomUUID(),\n label: bs.label || `Bootstrap ${idx + 1}`,\n command: bs.cmd || '',\n ...(bs.entrypoint ? { entrypoint: bs.entrypoint } : {}),\n ...(bs.user ? { user: bs.user } : {}),\n }));\n\n // Also set top-level entrypoint/command from first bootstrap for backwards compat\n const first = legacyBootstrapCmds[0];\n if (first?.entrypoint) dockerConfig.entrypoint = first.entrypoint;\n if (first?.cmd) dockerConfig.command = first.cmd;\n\n // Inherit user from first bootstrap if not set at container level\n if (!dockerConfig.user && first?.user) {\n dockerConfig.user = first.user;\n }\n }\n\n // ignoreVolumes → convert to real bind-mount volumes\n // Legacy used ignoreVolumes to mask container paths with a persistent host directory.\n // We convert each to ~/runeya/docker-persistence/<service-id>/<internal-path>:<internal-path>\n const sharedVolume: string = container.sharedVolume || '~/.runeya';\n const ignoreVolumes: string[] = (container.ignoreVolumes || [])\n .filter((v: string) => !v.startsWith(sharedVolume));\n if (ignoreVolumes.length > 0) {\n for (const ignoredPath of ignoreVolumes) {\n // Strip leading slash for the host sub-directory\n const subDir = ignoredPath.replace(/^\\/+/, '');\n const hostPath = `~/runeya/docker-persistence/${id}/${subDir}`;\n dockerConfig.volumes.push(`${hostPath}:${ignoredPath}`);\n }\n console.log(`[legacy-migration] Service \"${legacy.label}\": converted ${ignoreVolumes.length} ignoreVolumes to bind-mount volumes`);\n }\n\n // Native commands (spawnCmd) exist alongside Docker →\n // the service runs its native command inside the container\n if (commands.length > 0) {\n dockerConfig.useNativeCommand = true;\n dockerConfig.nativeCommandMode = 'isolated';\n }\n }\n\n // Port: extract from url (e.g. http://localhost:3034/... → 3034)\n let port: number | undefined;\n const serviceUrl: string = legacy.url || '';\n if (serviceUrl) {\n try {\n const parsed = new URL(serviceUrl);\n const p = Number.parseInt(parsed.port, 10);\n if (p > 0 && p <= 65535) port = p;\n } catch { /* invalid URL */ }\n }\n\n // Top-level cwd = legacy rootPath (global working directory for the service)\n const serviceCwd = rootPathCwd;\n\n const runeService: any = {\n id,\n orgId: null,\n agentId: 'local-agent',\n name: legacy.label,\n commands,\n cwd: serviceCwd,\n runner: dockerConfig ? 'docker' : 'native',\n shortcuts: (legacy.shortcuts || [])\n .filter((s: any) => s.spawnCmd || s.label)\n .map((s: any) => ({\n id: s.id || randomUUID(),\n label: s.label || s.spawnCmd || '',\n command: [s.spawnCmd, ...(s.spawnArgs || [])].filter(Boolean).join(' '),\n ...(s.spawnOptions?.cwd ? { cwd: s.spawnOptions.cwd } : {}),\n })),\n autoRestart: false,\n restartBackoffMs: 1000,\n groups: legacy.groups || [],\n description: legacy.description || '',\n url: legacy.url || '',\n openapiUrl: legacy.openapiURL || '',\n git: {\n remote: legacy.git?.remote || '',\n home: legacy.git?.home || '',\n },\n env: {},\n envSecrets: [],\n parserIds,\n meta: legacy.meta || {},\n ...(port !== undefined ? { ports: [port] } : {}),\n };\n\n if (healthCheck) runeService.healthCheck = healthCheck;\n if (dockerConfig) runeService.dockerConfig = dockerConfig;\n\n runeServices.push(runeService);\n }\n\n // Service inline envs → service-scoped environments (shared base variables)\n // Legacy stores per-service env vars as: service.envs = { \"LOCAL\": { \"KEY\": { value, key } }, ... }\n // These are the shared/committed base values — processed FIRST so overrides can reference their variableIds\n for (const [name, legacy] of Object.entries(legacyServices)) {\n const serviceId = serviceIdMap[name];\n if (!serviceId) continue;\n const service = runeServices.find((s: any) => s.id === serviceId);\n const svcEnvs: Record<string, Record<string, any>> = legacy.envs || {};\n\n for (const [envName, vars] of Object.entries(svcEnvs)) {\n if (!vars || typeof vars !== 'object' || Object.keys(vars).length === 0) continue;\n const globalEnvId = envIdMap[envName];\n const globalEnv = runeEnvs.find((e: any) => e.id === globalEnvId);\n if (!globalEnvId || !globalEnv) continue;\n\n let svcScopedEnv = runeEnvs.find(\n (e: any) => e.scope === 'service' && e.reference === serviceId && e.activateOn === globalEnvId,\n );\n\n if (!svcScopedEnv) {\n svcScopedEnv = {\n id: randomUUID(),\n projectId: projectMonoId,\n name: `${service?.name || name} (${globalEnv.name})`,\n scope: 'service' as const,\n reference: serviceId,\n activateOn: globalEnvId,\n parentIds: [],\n variables: {} as Record<string, Variable>,\n description: '',\n immutable: false,\n default: false,\n };\n runeEnvs.push(svcScopedEnv);\n }\n\n const existingKeys = new Set(\n Object.values(svcScopedEnv.variables as Record<string, Variable>).map((v: Variable) => v.key),\n );\n for (const [, varData] of Object.entries(vars as Record<string, any>)) {\n const varKey: string = typeof varData === 'object' ? String(varData.key ?? '') : '';\n const varValue: string = typeof varData === 'object' ? String(varData.value ?? '') : String(varData ?? '');\n const varPre: string = typeof varData === 'object' ? String(varData.prefix ?? '') : '';\n const varPost: string = typeof varData === 'object' ? String(varData.suffix ?? '') : '';\n if (!varKey || existingKeys.has(cleanVarKey(varKey))) continue;\n const cleaned = cleanVarKey(varKey);\n const varId = randomUUID();\n svcScopedEnv.variables[varId] = makeVariable(cleaned, varValue, varPre, varPost);\n existingKeys.add(cleaned);\n }\n }\n }\n\n // Service overrides → environment-overrides.json (personal/local overrides)\n // Legacy *-envs.encrypted.json files are per-user overrides of service-level env vars.\n // Service-scoped environments share the same override mechanism as global environments,\n // so these go into environment-overrides.json keyed by variableId.\n // If the base variable doesn't exist yet (no entry in service.envs), it is created with an\n // empty value so the override has something to reference.\n const svcFlatOverrides: Record<string, Variable> = {};\n for (const [serviceName, envOverrides] of Object.entries(legacyServiceOverrides)) {\n const serviceId = serviceIdMap[serviceName];\n if (!serviceId) continue;\n const service = runeServices.find((s: any) => s.id === serviceId);\n\n for (const [envName, vars] of Object.entries(envOverrides as Record<string, Record<string, string>>)) {\n const globalEnvId = envIdMap[envName];\n const globalEnv = runeEnvs.find((e: any) => e.id === globalEnvId);\n if (!globalEnv || !vars || typeof vars !== 'object') continue;\n\n // Find or create the service-scoped env for this (service, globalEnv) pair\n let svcScopedEnv = runeEnvs.find(\n (e: any) => e.scope === 'service' && e.reference === serviceId && e.activateOn === globalEnvId,\n );\n if (!svcScopedEnv) {\n svcScopedEnv = {\n id: randomUUID(),\n projectId: projectMonoId,\n name: `${service?.name || serviceName} (${globalEnv.name})`,\n scope: 'service' as const,\n reference: serviceId,\n activateOn: globalEnvId,\n parentIds: [],\n variables: {} as Record<string, Variable>,\n description: '',\n immutable: false,\n default: false,\n };\n runeEnvs.push(svcScopedEnv);\n }\n\n for (const [key, value] of Object.entries(vars)) {\n if (typeof value !== 'string') continue;\n if (hasInvalidInterpolation(value)) continue;\n const cleaned = cleanVarKey(key);\n\n // Find the base variable in the service-scoped env by key name\n const baseEntry = Object.entries(svcScopedEnv.variables as Record<string, Variable>)\n .find(([, v]) => v.key === cleaned);\n let varId = baseEntry?.[0];\n\n if (!varId) {\n // No base variable exists — create an empty base so the override has something to reference\n varId = randomUUID();\n svcScopedEnv.variables[varId] = {\n key: cleaned,\n value: { value: '', pre: '', post: '', isSecret: false, shareWithAi: false, injectIntoAi: false, required: false, overrideOnly: false, description: '' },\n };\n }\n\n // Carry pre/post from the base variable — overrides only replace the value\n const basePre = baseEntry?.[1]?.value?.pre ?? '';\n const basePost = baseEntry?.[1]?.value?.post ?? '';\n // Skip redundant override — value identical to base\n if (isSameAsBase(value, baseEntry?.[1])) continue;\n svcFlatOverrides[varId] = makeVariable(cleaned, value, basePre, basePost);\n }\n }\n }\n\n // Environment overrides — from *-environment.encrypted.json files\n // Keys ending in _OVERRIDE → environment-overrides.json (flat Record<variableId, Variable>)\n // Other keys → merged into environment.variables (additional values)\n const flatOverrides: Record<string, Variable> = { ...svcFlatOverrides };\n for (const [envName, data] of Object.entries(legacyEnvOverrides)) {\n const envId = envIdMap[envName];\n const env = runeEnvs.find((e: any) => e.id === envId);\n if (!envId || !env || !data) continue;\n\n const envVars: Record<string, string> = (data as Record<string, unknown>).envs as Record<string, string> ?? {};\n\n for (const [key, value] of Object.entries(envVars)) {\n if (typeof value !== 'string') continue;\n\n if (key.endsWith('_OVERRIDE')) {\n // Strip all legacy suffixes → goes into environment-overrides.json\n const cleaned = cleanVarKey(key);\n const varId = varIdLookup.get(`${envId}:${cleaned}`);\n if (varId) {\n const baseVar = (env.variables as Record<string, Variable>)[varId];\n // Skip redundant override — value identical to base\n if (!isSameAsBase(value, baseVar)) {\n flatOverrides[varId] = makeVariable(cleaned, value);\n }\n } else {\n // Variable not found in env — create a new UUID entry\n flatOverrides[randomUUID()] = makeVariable(cleaned, value);\n }\n } else {\n // Regular variable → merge into environment.variables (with _RUNEYA stripped)\n const cleaned = cleanVarKey(key);\n // Check if this var already exists in env.variables (by key name)\n const existingVarId = Object.entries(env.variables as Record<string, Variable>)\n .find(([, v]) => v.key === cleaned)?.[0];\n if (!existingVarId) {\n const varId = randomUUID();\n env.variables[varId] = makeVariable(cleaned, value);\n varIdLookup.set(`${envId}:${cleaned}`, varId);\n }\n }\n }\n }\n\n // Projects — single project containing all services\n // Built AFTER service-scoped envs so allEnvIds includes them\n // Priority: explicit default flag → env named LOCAL → first env\n const localEnvName = Object.keys(legacyEnvs).find(n => n.toUpperCase() === 'LOCAL');\n const activeEnvId = defaultEnvName\n ? (envIdMap[defaultEnvName] ?? runeEnvs[0]?.id)\n : (localEnvName ? (envIdMap[localEnvName] ?? runeEnvs[0]?.id) : runeEnvs[0]?.id);\n const allEnvIds = runeEnvs.map(e => e.id);\n const allServiceIds = runeServices.map(s => s.id);\n\n const runeProjects: any[] = [];\n if (allServiceIds.length > 0 || allEnvIds.length > 0) {\n runeProjects.push({\n id: projectMonoId,\n orgId: null,\n name: 'Migrated Project',\n description: '',\n serviceIds: allServiceIds,\n environmentIds: allEnvIds,\n activeEnvironmentId: activeEnvId,\n });\n }\n\n const primaryProjectId = projectMonoId;\n for (const env of runeEnvs) {\n env.projectId = primaryProjectId;\n }\n\n // Settings — preserve existing + add migrated custom parsers\n let existingSettings: any = {};\n try {\n existingSettings = JSON.parse(await readFile(join(dataDir, 'settings.json'), 'utf-8'));\n } catch { /* first run */ }\n\n const migratedParsers = legacyParsers.map(p => ({\n id: p.id,\n name: p.label,\n // Legacy transform uses module.exports API — kept for reference, must be rewritten\n code: `// Migrated from legacy parser \"${p.label}\"\\n// TODO: rewrite using new API: (raw: string, stream: 'stdout'|'stderr') => ParseResult | null\\n// Legacy code (module.exports style — NOT compatible):\\n${p.transform ?? ''}`,\n enabled: false, // disabled until manually rewritten\n }));\n\n const newSettings = {\n ...existingSettings,\n logParsers: [\n ...(existingSettings.logParsers ?? []),\n ...migratedParsers,\n ],\n };\n\n // ── 5. Write output files ────────────────────────────────────────────────────\n await atomicWrite(join(dataDir, 'projects.json'), runeProjects);\n await atomicWrite(join(dataDir, 'services.json'), runeServices);\n await atomicWrite(join(dataDir, 'environments.json'), runeEnvs);\n await atomicWrite(join(dataDir, 'environment-overrides.json'), flatOverrides);\n await atomicWrite(join(dataDir, 'settings.json'), newSettings);\n\n const svcEnvCount = runeEnvs.filter((e: any) => e.scope === 'service').length;\n console.log(`[legacy-migration] Written: ${runeProjects.length} projects, ${runeServices.length} services, ${runeEnvs.length} environments (${svcEnvCount} service-scoped)`);\n console.log(`[legacy-migration] Overrides: ${Object.keys(flatOverrides).length}, custom parsers: ${migratedParsers.length} (all disabled — rewrite required)`);\n\n // Clear the main singleton so hasEncryptionKey() returns false → state = setup\n // Store the key in the pending holder for /api/setup to consume\n clearEncryptionKey();\n setPendingLegacyKey(keyBuffer);\n console.log('[legacy-migration] Done. Data migrated to .runeya — master password setup required');\n\n return true;\n}\n\n// ── Find legacy key in backup (restart between migration and setup) ─────────\n//\n// If the server restarts after runLegacyMigration but before /api/setup,\n// the pending key is lost (in-memory only). This function scans backup dirs\n// to recover the libsodium key so the user can still complete setup.\n\nexport async function findLegacyKeyInBackup(dataDir: string): Promise<Buffer | null> {\n try {\n const entries = await readdir(dataDir);\n // Comparateur par code-point (identique au tri par défaut) : on sélectionne\n // le backup le plus récent, l'ordre doit rester celui des noms backup-<ts>.\n const backupDirs = entries\n .filter(e => e.startsWith('backup-'))\n .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))\n .reverse();\n for (const dir of backupDirs) {\n const keyJsonPath = join(dataDir, dir, 'dbs', 'encryption-key.json');\n try {\n const raw = await readFile(keyJsonPath, 'utf-8');\n const parsed = JSON.parse(raw) as { encryptionKey?: string };\n if (!parsed.encryptionKey) continue;\n const sodium = await getSodium();\n const sodiumKey = sodium.from_base64(parsed.encryptionKey) as Uint8Array;\n const buf = Buffer.from(sodiumKey);\n if (buf.length === 32) {\n console.log(`[legacy-migration] Recovered legacy key from ${keyJsonPath}`);\n return buf;\n }\n } catch {\n // This backup dir doesn't have a valid key — try next\n }\n }\n } catch {\n // dataDir doesn't exist or isn't readable\n }\n return null;\n}\n\n// ── Override-only migration (User B scenario) ──────────────────────────────\n//\n// When the data dir is tracked by git and User A already ran the full migration:\n// - Git deleted dbs/encryption-key.json (was tracked)\n// - Git delivered the migrated JSON files (projects, services, environments…)\n// - But User B's dbs/overrides/*.encrypted.json are still on disk (gitignored)\n// - The full migration didn't trigger (no encryption-key.json)\n// - User B's overrides were never migrated → orphaned\n//\n// This function runs AFTER .encryption.key is available (same 32 bytes as\n// the legacy libsodium key, just in hex format). It decrypts User B's local\n// override files and writes environment-overrides.json.\n\nexport async function runOverrideOnlyMigration(dataDir: string): Promise<boolean> {\n // oxlint-disable-next-line typescript/unbound-method -- resolve is a pure module function from node:path, not a class method\n const { resolve } = await import('node:path');\n const abDataDir = resolve(dataDir);\n\n // Match the full migration: legacy data lives under the launch directory's\n // `.runeya`, which may differ from DATA_DIR when `--data-dir` was given.\n // Prefer the launch-directory path (the one git tracks), fall back to DATA_DIR.\n const candidateDirs = [\n join(dirname(env.DATA_DIR), '.runeya', 'dbs', 'overrides'),\n join(abDataDir, 'dbs', 'overrides'),\n ];\n\n let overridesDir: string | null = null;\n let overrideFiles: string[] = [];\n for (const dir of candidateDirs) {\n try {\n const files = (await readdir(dir)).filter(f => f.endsWith('.encrypted.json'));\n if (files.length > 0) {\n overridesDir = dir;\n overrideFiles = files;\n break;\n }\n } catch { /* dir doesn't exist */ }\n }\n if (!overridesDir || overrideFiles.length === 0) return false;\n\n // If the full migration trigger still exists, let the full migration handle it\n const legacyKeyPath = join(overridesDir, '..', 'encryption-key.json');\n try {\n await access(legacyKeyPath);\n return false; // Full migration should run instead\n } catch {\n // Expected — key was deleted by git\n }\n\n // We need .encryption.key to decrypt (it's the same 32 bytes)\n const encKey = getEncryptionKey();\n if (!encKey) {\n console.warn('[override-migration] Cannot migrate overrides: encryption key not loaded yet');\n return false;\n }\n\n console.log(`[override-migration] Found ${overrideFiles.length} orphaned override file(s) in ${overridesDir}, migrating…`);\n\n const sodium = await getSodium();\n // .encryption.key is the same 32 bytes as the legacy libsodium key\n const sodiumKey = new Uint8Array(encKey);\n\n // Load existing environments.json to build lookups\n const varIdLookup = new Map<string, string>();\n const envNameToId: Record<string, string> = {};\n let envsRaw: unknown[];\n try {\n envsRaw = JSON.parse(await readFile(join(abDataDir, 'environments.json'), 'utf-8')) as unknown[];\n for (const _env of envsRaw) {\n const env = _env as Record<string, unknown>;\n if (env['name'] && env['id']) {\n envNameToId[env['name'] as string] = env['id'] as string;\n }\n if (env['variables'] && env['id']) {\n for (const [varId, variable] of Object.entries(env['variables'] as Record<string, Variable>)) {\n varIdLookup.set(`${env['id'] as string}:${variable.key}`, varId);\n }\n }\n }\n } catch {\n console.warn('[override-migration] Cannot read environments.json — skipping');\n return false;\n }\n\n // Load services.json for service-override matching (legacy fileName → service name)\n let servicesRaw: unknown[] = [];\n const serviceNameToId: Record<string, string> = {};\n try {\n servicesRaw = JSON.parse(await readFile(join(abDataDir, 'services.json'), 'utf-8')) as unknown[];\n for (const _svc of servicesRaw) {\n const svc = _svc as Record<string, unknown>;\n if (svc['name'] && svc['id']) serviceNameToId[svc['name'] as string] = svc['id'] as string;\n }\n } catch { /* services.json missing — service overrides won't match */ }\n\n // Helper: find env ID by name (exact or case-insensitive)\n function findEnvId(name: string): string | undefined {\n return envNameToId[name]\n ?? Object.entries(envNameToId).find(([n]) => n.toLowerCase() === name.toLowerCase())?.[1];\n }\n\n // ── 1. Environment overrides (*-environment.encrypted.json) → environment-overrides.json ──\n const flatOverrides: Record<string, Variable> = {};\n\n for (const file of overrideFiles) {\n const baseName = file.replace('.encrypted.json', '');\n if (!baseName.endsWith('-environment')) continue;\n const envName = baseName.slice(0, -'-environment'.length);\n\n let data: any;\n try {\n data = await decryptLegacyFile(join(overridesDir, file), sodiumKey, sodium);\n } catch (err: unknown) {\n console.warn(`[override-migration] Failed to decrypt ${file}: ${(err as Error).message}`);\n continue;\n }\n if (!data) continue;\n\n const envId = findEnvId(envName);\n if (!envId) {\n console.warn(`[override-migration] No matching environment for \"${envName}\" — skipping`);\n continue;\n }\n\n const envVars: Record<string, string> = data.envs ?? {};\n for (const [key, value] of Object.entries(envVars)) {\n if (typeof value !== 'string') continue;\n if (!key.endsWith('_OVERRIDE')) continue;\n\n const cleaned = cleanVarKey(key);\n const varId = varIdLookup.get(`${envId}:${cleaned}`);\n if (varId) {\n const baseVar = ((envsRaw as Record<string, unknown>[]).find((e) => e['id'] === envId)?.['variables'] as Record<string, Variable> | undefined)?.[varId];\n // Skip redundant override — value identical to base\n if (isSameAsBase(value, baseVar)) continue;\n flatOverrides[varId] = makeVariable(cleaned, value);\n } else {\n flatOverrides[randomUUID()] = makeVariable(cleaned, value);\n }\n }\n }\n\n if (Object.keys(flatOverrides).length > 0) {\n await atomicWrite(join(abDataDir, 'environment-overrides.json'), flatOverrides);\n console.log(`[override-migration] Written ${Object.keys(flatOverrides).length} override(s) to environment-overrides.json`);\n }\n\n // ── 2. Service overrides (*-envs.encrypted.json) → environment-overrides.json ──\n // Service-scoped environments share the same override mechanism as global environments.\n // Personal service variable overrides go into environment-overrides.json (keyed by variableId).\n // If the base variable doesn't exist in the service-scoped env, an empty base is created first.\n let envsModified = false;\n\n for (const file of overrideFiles) {\n const baseName = file.replace('.encrypted.json', '');\n if (!baseName.endsWith('-envs')) continue;\n const serviceName = baseName.slice(0, -'-envs'.length);\n\n let data: any;\n try {\n data = await decryptLegacyFile(join(overridesDir, file), sodiumKey, sodium);\n } catch (err: unknown) {\n console.warn(`[override-migration] Failed to decrypt ${file}: ${(err as Error).message}`);\n continue;\n }\n if (!data || typeof data !== 'object') continue;\n\n // Find service ID: try by legacy filename, then case-insensitive name match\n const serviceId = serviceNameToId[serviceName]\n ?? Object.entries(serviceNameToId).find(([n]) => n.toLowerCase() === serviceName.toLowerCase())?.[1];\n if (!serviceId) {\n console.warn(`[override-migration] No matching service for \"${serviceName}\" — skipping service overrides`);\n continue;\n }\n\n const service = (servicesRaw as Record<string, unknown>[]).find((s) => s['id'] === serviceId);\n\n for (const [envName, vars] of Object.entries(data as Record<string, Record<string, string>>)) {\n const globalEnvId = findEnvId(envName);\n if (!globalEnvId || !vars || typeof vars !== 'object') continue;\n const globalEnv = (envsRaw as Record<string, unknown>[]).find((e) => e['id'] === globalEnvId);\n if (!globalEnv) continue;\n\n // Find or create the service-scoped env for this (service, globalEnv) pair\n let svcScopedEnv = (envsRaw as Record<string, unknown>[]).find(\n (e) => e['scope'] === 'service' && e['reference'] === serviceId && e['activateOn'] === globalEnvId,\n );\n if (!svcScopedEnv) {\n svcScopedEnv = {\n id: randomUUID(),\n projectId: globalEnv['projectId'],\n name: `${(service?.['name'] as string | undefined) || serviceName} (${globalEnv['name'] as string})`,\n scope: 'service' as const,\n reference: serviceId,\n activateOn: globalEnvId,\n parentIds: [],\n variables: {} as Record<string, Variable>,\n description: '',\n immutable: false,\n default: false,\n };\n envsRaw.push(svcScopedEnv);\n envsModified = true;\n }\n\n for (const [key, value] of Object.entries(vars)) {\n if (typeof value !== 'string') continue;\n if (hasInvalidInterpolation(value)) continue;\n const cleaned = cleanVarKey(key);\n\n // Find the base variable in the service-scoped env by key name\n const baseEntry = Object.entries(svcScopedEnv['variables'] as Record<string, Variable>)\n .find(([, v]) => v.key === cleaned);\n let varId = baseEntry?.[0];\n\n if (!varId) {\n // No base variable — create an empty base so the override has something to reference\n varId = randomUUID();\n (svcScopedEnv['variables'] as Record<string, Variable>)[varId] = {\n key: cleaned,\n value: { value: '', pre: '', post: '', isSecret: false, shareWithAi: false, injectIntoAi: false, required: false, overrideOnly: false, description: '' },\n };\n envsModified = true;\n }\n\n // Carry pre/post from the base variable — overrides only replace the value\n const basePre = baseEntry?.[1]?.value?.pre ?? '';\n const basePost = baseEntry?.[1]?.value?.post ?? '';\n // Skip redundant override — value identical to base\n if (isSameAsBase(value, baseEntry?.[1])) continue;\n flatOverrides[varId] = makeVariable(cleaned, value, basePre, basePost);\n }\n }\n }\n\n if (envsModified) {\n await atomicWrite(join(abDataDir, 'environments.json'), envsRaw);\n console.log('[override-migration] Merged service overrides into environments.json');\n }\n\n // Move dbs/overrides/ → dbs/overrides-migrated/ to prevent re-running\n const migratedDir = overridesDir.replace(/overrides$/, 'overrides-migrated');\n try {\n await rename(overridesDir, migratedDir);\n console.log(`[override-migration] Moved overrides/ → overrides-migrated/`);\n } catch (err: unknown) {\n console.warn(`[override-migration] Could not rename overrides dir: ${(err as Error).message}`);\n }\n\n console.log('[override-migration] Done');\n return true;\n}\n","import { join } from 'node:path';\nimport { stat } from 'node:fs/promises';\nimport { hasEncryptionKey, hasPendingLegacyKey } from '../utils/encryption-key.js';\nimport { keyRoot, legacyVaultRoot } from './vault-resolver.js';\n\nexport type ServerState = 'locked' | 'setup' | 'unlocked';\n\nconst ENCRYPTED_KEY_FILENAME = '.encryption.key.enc';\nconst VERIFY_FILENAME = '.runeya-verify';\n\nexport interface ServerStatus {\n state: ServerState;\n hasVerifyFile: boolean;\n isLegacyMigration: boolean;\n hasExistingData: boolean;\n /**\n * A launch directory still sealed under a master password of its own.\n *\n * Reported only once unlocked: the migration asks for the OLD password, which\n * would be one question too many on a screen that is already asking for the\n * machine one.\n */\n legacyVault: string | null;\n}\n\nexport async function getServerState(): Promise<ServerStatus> {\n // The key and its canary answer for the whole machine, so the server's\n // locked/setup state follows them, not the directory it was started in.\n const dataDir = await keyRoot();\n\n let hasEncFile = false;\n let hasVerify = false;\n let hasData = false;\n\n try { await stat(join(dataDir, ENCRYPTED_KEY_FILENAME)); hasEncFile = true; } catch {}\n try { await stat(join(dataDir, VERIFY_FILENAME)); hasVerify = true; } catch {}\n try { await stat(join(dataDir, 'projects.json')); hasData = true; } catch {}\n try { await stat(join(dataDir, 'project.json')); hasData = true; } catch {}\n\n if (hasEncryptionKey()) {\n return {\n state: 'unlocked',\n hasVerifyFile: false,\n isLegacyMigration: false,\n hasExistingData: hasData,\n legacyVault: await legacyVaultRoot(),\n };\n }\n\n if (hasEncFile) {\n return { state: 'locked', hasVerifyFile: hasVerify, isLegacyMigration: false, hasExistingData: hasData, legacyVault: null };\n }\n\n // SETUP state — legacy migration detected via in-memory pending key holder\n return {\n state: 'setup',\n hasVerifyFile: hasVerify,\n isLegacyMigration: hasPendingLegacyKey(),\n hasExistingData: hasData,\n legacyVault: null,\n };\n}\n","import { env } from '../config/env.js';\n\nconst BASE = `http://localhost:${env.PORT}/api/trpc`;\n\nexport function getOpenApiDocument() {\n return {\n openapi: '3.1.0',\n info: {\n title: 'Runeya API',\n version: '1.0.0',\n description: 'Runeya service management API — tRPC over HTTP.\\n\\n**Queries** use `GET /{procedure}?input={json}`.\\n**Mutations** use `POST /{procedure}` with a JSON body.\\n\\nAll protected routes require `Authorization: Bearer <jwt>` header.',\n },\n servers: [{ url: BASE }],\n paths: {\n '/health.check': {\n get: {\n tags: ['Health'],\n summary: 'Health check',\n operationId: 'health.check',\n responses: {\n '200': { description: 'Server is up', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { type: 'object', properties: { status: { type: 'string', example: 'ok' }, uptime: { type: 'number' } } } } } } } } } },\n },\n },\n },\n '/service.list': {\n get: {\n tags: ['Services'],\n summary: 'List services (every project of the machine unless narrowed)',\n operationId: 'service.list',\n security: [{ BearerAuth: [] }],\n parameters: [{\n name: 'input',\n in: 'query',\n required: false,\n schema: { type: 'string' },\n example: '{\"projectId\":\"<projectId>\"}',\n description: 'JSON-encoded input, optional: `{\"projectId\":\"<projectId>\",\"orgId\":\"<orgId>\"}`. Omitted, the response covers every project of every organization on this machine.',\n }],\n responses: {\n '200': { description: 'Array of services', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { type: 'array', items: { $ref: '#/components/schemas/Service' } } } } } } } } },\n },\n },\n },\n '/service.get': {\n get: {\n tags: ['Services'],\n summary: 'Get a service by ID',\n operationId: 'service.get',\n security: [{ BearerAuth: [] }],\n parameters: [{\n name: 'input',\n in: 'query',\n required: true,\n schema: { type: 'string' },\n example: '{\"id\":\"<serviceId>\"}',\n description: 'JSON-encoded input: `{\"id\":\"<serviceId>\"}`',\n }],\n responses: {\n '200': { description: 'Service object', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { $ref: '#/components/schemas/Service' } } } } } } } },\n },\n },\n },\n '/service.create': {\n post: {\n tags: ['Services'],\n summary: 'Create a new service',\n operationId: 'service.create',\n security: [{ BearerAuth: [] }],\n requestBody: {\n required: true,\n content: { 'application/json': { schema: { type: 'object', required: ['agentId', 'name'], properties: {\n agentId: { type: 'string' },\n name: { type: 'string' },\n commands: { type: 'array', items: { type: 'object' } },\n cwd: { type: 'string' },\n port: { type: 'integer' },\n description: { type: 'string' },\n url: { type: 'string' },\n runner: { type: 'string', enum: ['native', 'docker'], default: 'native' },\n } } } },\n },\n responses: {\n '200': { description: 'Created service', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { $ref: '#/components/schemas/Service' } } } } } } } },\n },\n },\n },\n '/service.update': {\n post: {\n tags: ['Services'],\n summary: 'Update a service',\n operationId: 'service.update',\n security: [{ BearerAuth: [] }],\n requestBody: {\n required: true,\n content: { 'application/json': { schema: { type: 'object', required: ['id'], properties: {\n id: { type: 'string' },\n name: { type: 'string' },\n commands: { type: 'array', items: { type: 'object' } },\n cwd: { type: 'string' },\n port: { type: 'integer' },\n description: { type: 'string' },\n url: { type: 'string' },\n } } } },\n },\n responses: {\n '200': { description: 'Updated service', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { $ref: '#/components/schemas/Service' } } } } } } } },\n },\n },\n },\n '/service.delete': {\n post: {\n tags: ['Services'],\n summary: 'Delete a service',\n operationId: 'service.delete',\n security: [{ BearerAuth: [] }],\n requestBody: {\n required: true,\n content: { 'application/json': { schema: { type: 'object', required: ['id'], properties: { id: { type: 'string' } } } } },\n },\n responses: {\n '200': { description: 'Deletion result', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { type: 'object', properties: { success: { type: 'boolean' } } } } } } } } } },\n },\n },\n },\n '/process.list': {\n get: {\n tags: ['Processes'],\n summary: 'List all processes across all connected agents',\n operationId: 'process.list',\n security: [{ BearerAuth: [] }],\n responses: {\n '200': { description: 'Array of processes', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { type: 'array', items: { $ref: '#/components/schemas/Process' } } } } } } } } },\n },\n },\n },\n '/process.get': {\n get: {\n tags: ['Processes'],\n summary: 'Get a process by agent and service ID',\n operationId: 'process.get',\n security: [{ BearerAuth: [] }],\n parameters: [{\n name: 'input',\n in: 'query',\n required: true,\n schema: { type: 'string' },\n example: '{\"agentId\":\"<agentId>\",\"id\":\"<serviceId>\"}',\n description: 'JSON-encoded input: `{\"agentId\":\"<agentId>\",\"id\":\"<serviceId>\"}`',\n }],\n responses: {\n '200': { description: 'Process object' },\n },\n },\n },\n '/process.logs': {\n get: {\n tags: ['Processes'],\n summary: 'Get buffered logs for a process',\n operationId: 'process.logs',\n security: [{ BearerAuth: [] }],\n parameters: [{\n name: 'input',\n in: 'query',\n required: true,\n schema: { type: 'string' },\n example: '{\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}',\n description: 'JSON-encoded input: `{\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}`',\n }],\n responses: {\n '200': { description: 'Array of log lines' },\n },\n },\n },\n '/process.start': {\n post: {\n tags: ['Processes'],\n summary: 'Start a process',\n operationId: 'process.start',\n security: [{ BearerAuth: [] }],\n requestBody: {\n required: true,\n content: { 'application/json': { schema: { type: 'object', required: ['agentId', 'processId'], properties: {\n agentId: { type: 'string' },\n processId: { type: 'string' },\n } } } },\n },\n responses: {\n '200': { description: 'Start result' },\n },\n },\n },\n '/process.stop': {\n post: {\n tags: ['Processes'],\n summary: 'Stop a process',\n operationId: 'process.stop',\n security: [{ BearerAuth: [] }],\n requestBody: {\n required: true,\n content: { 'application/json': { schema: { type: 'object', required: ['agentId', 'processId'], properties: {\n agentId: { type: 'string' },\n processId: { type: 'string' },\n } } } },\n },\n responses: {\n '200': { description: 'Stop result' },\n },\n },\n },\n '/process.restart': {\n post: {\n tags: ['Processes'],\n summary: 'Restart a process',\n operationId: 'process.restart',\n security: [{ BearerAuth: [] }],\n requestBody: {\n required: true,\n content: { 'application/json': { schema: { type: 'object', required: ['agentId', 'processId'], properties: {\n agentId: { type: 'string' },\n processId: { type: 'string' },\n } } } },\n },\n responses: {\n '200': { description: 'Restart result' },\n },\n },\n },\n '/environment.resolveFlat': {\n get: {\n tags: ['Environments'],\n summary: 'Resolve environment variables as a flat key-value map',\n operationId: 'environment.resolveFlat',\n security: [{ BearerAuth: [] }],\n parameters: [{\n name: 'input',\n in: 'query',\n required: true,\n schema: { type: 'string' },\n example: '{\"environmentId\":\"<environmentId>\"}',\n description: 'JSON-encoded input: `{\"environmentId\":\"<environmentId>\"}`',\n }],\n responses: {\n '200': { description: 'Flat key-value map of resolved variables', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { type: 'object', additionalProperties: { type: 'string' } } } } } } } } },\n },\n },\n },\n },\n components: {\n securitySchemes: {\n BearerAuth: { type: 'http', scheme: 'bearer', description: 'JWT token from /api/unlock or /api/setup' },\n },\n schemas: {\n Service: {\n type: 'object',\n properties: {\n id: { type: 'string' },\n name: { type: 'string' },\n agentId: { type: 'string' },\n commands: { type: 'array', items: { type: 'object' } },\n cwd: { type: 'string' },\n port: { type: 'integer' },\n description: { type: 'string' },\n url: { type: 'string' },\n runner: { type: 'string', enum: ['native', 'docker'] },\n },\n },\n Process: {\n type: 'object',\n properties: {\n id: { type: 'string' },\n agentId: { type: 'string' },\n state: { type: 'string', enum: ['stopped', 'starting', 'running', 'stopping', 'errored'] },\n pid: { type: 'integer', nullable: true },\n exitCode: { type: 'integer', nullable: true },\n },\n },\n },\n },\n };\n}\n","import { imageStorageService } from './image-storage.service.js';\n\nexport class ImageCleanupService {\n private timer: ReturnType<typeof setInterval> | null = null;\n\n async runCleanup(): Promise<{ deleted: number; errors: number }> {\n const expired = await imageStorageService.listExpiredImages();\n let deleted = 0;\n let errors = 0;\n await Promise.all(\n expired.map(async (img) => {\n try {\n await imageStorageService.deleteImage(img.imageId);\n deleted++;\n } catch {\n errors++;\n }\n }),\n );\n return { deleted, errors };\n }\n\n start(intervalMs = 60 * 60 * 1000): void {\n if (this.timer) return;\n this.runCleanup().catch((err) => console.error('[image-cleanup] error:', err));\n this.timer = setInterval(() => {\n this.runCleanup().catch((err) => console.error('[image-cleanup] error:', err));\n }, intervalMs);\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n}\n\nexport const imageCleanupService = new ImageCleanupService();\n","import type { Server } from 'node:http';\nimport type { WebSocketServer } from 'ws';\nimport { env } from './config/env.js';\nimport { createLocalServer } from './create-server.js';\nimport { shutdownCodexAppServer } from './services/ai-runners/codex-runner.js';\nimport { resolve as resolvePath } from 'node:path';\nimport dotenv from 'dotenv'\ndotenv.config({ quiet: true })\n\n// Align cwd with the parent of RUNEYA_DATA_DIR when set, so spawned services\n// resolve relative cwds against the user's stack root rather than the server's own dir.\nif (process.env['RUNEYA_DATA_DIR']) {\n const resolved = resolvePath(process.env['RUNEYA_DATA_DIR'], '..');\n process.chdir(resolved);\n console.log(`[server] Working directory: ${resolved} (from RUNEYA_DATA_DIR)`);\n}\n\n// Re-export for CLI usage\nexport { createLocalServer } from './create-server.js';\nexport type { ServerInstance } from './create-server.js';\nexport { pullEnv, PullEnvError } from './commands/pull-env.js';\n// Announced by the CLI once the port is actually bound — a record written\n// before that could advertise a port this instance never got.\nexport { registerInstance } from './services/instance-registry.js';\n// Lecture et pilotage du registre machine, pour les façades qui n'ont pas de\n// serveur derrière elles : la sous-commande `runeya instances` et la barre\n// système. Même source que le routeur tRPC `diagnostics` — une seule\n// implémentation, trois façades.\nexport { listInstances, killInstance, restartInstance } from './services/instance-registry.js';\n// Le redémarrage de soi-même : posé par le routeur tRPC comme par l'icône de\n// barre système, qui appartient au processus qu'elle redémarre.\nexport { scheduleSelfRestart } from './services/instance-registry.js';\n// Ce que l'icône de barre système pilote : les services de cette instance, et\n// le mode réseau local. Le CLI n'a ainsi à connaître ni l'agent, ni le store.\nexport { listTrayServices, onTrayServicesChanged } from './services/tray-services.js';\n// Le logo de l'organisation du projet ouvert, pour l'icône de barre système.\nexport { resolveTrayIcon } from './services/tray-icon.js';\nexport type { TrayService } from './services/tray-services.js';\nexport { startProcess, stopProcess, restartProcess } from './services/process-control.js';\nexport { networkInfo, setLanMode } from './services/lan-mode.js';\n// Où le CLI se trouve, pour que le serveur puisse rejouer `install-desktop` et\n// créer un raccourci de bureau depuis l'interface.\nexport { registerCli as registerCliLocation } from './services/desktop-launcher.js';\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(`[server] 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 // Même garantie que côté CLI, pour un serveur démarré seul : le PATH d'une\n // session graphique ignore les binaires installés par l'utilisateur.\n const { ensureNodeBinOnPath, ensureUserBinsOnPath } = await import('@runeya/packages-shared/node');\n ensureNodeBinOnPath();\n await ensureUserBinsOnPath();\n\n console.log('Hello World 2');\n // oxlint-disable-next-line typescript/unbound-method -- shutdown is a standalone closure returned by createLocalServer, not a class method\n const { server, wss, shutdown } = await createLocalServer();\n\n await listenWithRetry(server, env.PORT, env.HOST, wss);\n console.log(`[server] Local server listening on ${env.HOST}:${env.PORT}`);\n console.log(`[server] tRPC HTTP: http://${env.HOST}:${env.PORT}/api/trpc`);\n console.log(`[server] tRPC WS: ws://${env.HOST}:${env.PORT}`); // nosemgrep:javascript.lang.security.detect-insecure-websocket.detect-insecure-websocket\n console.log(`[server] Mode: ${env.MODE}`);\n if (env.RUNEYA_LAN_PROXY) {\n console.log('[server] LAN mode: server exposed on local network (0.0.0.0)');\n console.log('[server] LAN mode: {{service.HOST}} resolves to 0.0.0.0 — configure your services accordingly');\n }\n\n let shuttingDown = false;\n const gracefulShutdown = async (signal: string) => {\n if (shuttingDown) {\n console.log(`[server] Forced exit (second ${signal})`);\n process.exit(1);\n }\n shuttingDown = true;\n console.log(`[server] 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 shutdownCodexAppServer();\n await shutdown();\n process.exit(0);\n };\n\n process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));\n process.on('SIGINT', () => gracefulShutdown('SIGINT'));\n}\n\n// Only run main if this file is executed directly (not imported)\nif (import.meta.url === `file://${process.argv[1]}`) {\n main().catch((err) => {\n console.error('[server] Fatal error:', err);\n process.exit(1);\n });\n}\n","import { serviceStore } from '../services/service-store.js';\nimport { environmentStore } from '../services/environment-store.js';\nimport { environmentResolver } from '../services/environment-resolver.js';\nimport { ensureEncryptionKey, hasEncryptionKey, loadFromEnv, setEncryptionKeyInMemory } from '../utils/encryption-key.js';\nimport { readEncryptedKey, hasEncryptedKeyFile } from '../services/master-password.js';\nimport { env as serverEnv } from '../config/env.js';\n\nexport class PullEnvError extends Error {\n constructor(\n message: string,\n public readonly exitCode: number,\n ) {\n super(message);\n this.name = 'PullEnvError';\n }\n}\n\nasync function promptPassword(): Promise<string> {\n process.stderr.write('Master password: ');\n return new Promise((resolve) => {\n const stdin = process.stdin;\n const wasRaw = stdin.isRaw;\n if (stdin.isTTY) stdin.setRawMode(true);\n stdin.resume();\n stdin.setEncoding('utf-8');\n let input = '';\n const onData = (ch: string) => {\n if (ch === '\\r' || ch === '\\n') {\n if (stdin.isTTY) stdin.setRawMode(wasRaw ?? false);\n stdin.pause();\n stdin.removeListener('data', onData);\n process.stderr.write('\\n');\n resolve(input);\n } else if (ch === '\\u0003') {\n // Ctrl+C\n process.exit(1);\n } else if (ch === '\\u007f' || ch === '\\b') {\n input = input.slice(0, -1);\n } else {\n input += ch;\n }\n };\n stdin.on('data', onData);\n });\n}\n\nasync function unlockIfNeeded(): Promise<void> {\n // Call ensureEncryptionKey first (allows tests to mock it)\n await ensureEncryptionKey();\n if (hasEncryptionKey()) return;\n\n // CI mode: RUNEYA_ENCRYPTION_KEY env var\n if (await loadFromEnv()) return;\n\n // Check if encrypted key file exists (i.e. setup was completed)\n if (!(await hasEncryptedKeyFile(serverEnv.DATA_DIR))) {\n // No encryption key file — either fresh install or test environment; proceed without encryption\n return;\n }\n\n // Try RUNEYA_MASTER_PASSWORD env var, then prompt\n const masterPassword = process.env['RUNEYA_MASTER_PASSWORD'] || await promptPassword();\n if (!masterPassword) {\n throw new PullEnvError('Master password required to decrypt data', 1);\n }\n\n try {\n const encKey = await readEncryptedKey(serverEnv.DATA_DIR, masterPassword);\n setEncryptionKeyInMemory(encKey);\n } catch {\n throw new PullEnvError('Master password incorrect', 1);\n }\n}\n\n/**\n * Resolve env vars for a service+environment and return them as KEY=VALUE lines.\n * Throws PullEnvError if the service or environment is not found.\n */\nexport async function pullEnv(opts: { service: string; environment: string }): Promise<string> {\n await unlockIfNeeded();\n\n const services = await serviceStore.list();\n const service = services.find(\n (s) => s.id === opts.service || s.name === opts.service,\n );\n if (!service) {\n const available = services.map((s) => s.name).join(', ');\n throw new PullEnvError(`service \"${opts.service}\" not found. Available: ${available || '(none)'}`, 1);\n }\n\n const globalEnvs = await environmentStore.listAllGlobal();\n const globalEnv = globalEnvs.find(\n (e) => e.id === opts.environment || e.name === opts.environment,\n );\n if (!globalEnv) {\n const available = globalEnvs.map((e) => e.name).join(', ');\n throw new PullEnvError(`environment \"${opts.environment}\" not found. Available: ${available || '(none)'}`, 1);\n }\n\n const { env } = await environmentResolver.resolveForService({\n serviceId: service.id,\n activeEnvironmentId: globalEnv.id,\n });\n\n return Object.entries(env)\n .map(([key, value]) => `${key}=${value}`)\n .join('\\n');\n}\n","/**\n * Ce que l'icône de barre système doit savoir des services de cette instance.\n *\n * Le tray vit dans le processus du CLI, qui ne connaît ni `serviceStore` ni\n * `agentManager` : cette vue assemble les deux et n'expose que le nécessaire —\n * un nom, un état, une adresse. Elle ne décide de rien, elle décrit.\n *\n * L'état est poussé, jamais sondé : le pont de l'agent relaie déjà\n * `process.onStatus` en événement `process:status`, et `serviceStore` prévient\n * de ses propres changements. Un menu qui se rafraîchit sur ces deux signaux\n * est à jour sans qu'aucune horloge ne tourne.\n */\nimport { primaryServiceLink } from '@runeya/packages-shared';\nimport { onVaultUnlocked } from '../utils/encryption-key.js';\nimport { agentManager } from './agent-manager.js';\nimport { serviceStore } from './service-store.js';\nimport { projectStore } from './project-store.js';\nimport { listAllProcesses } from './process-control.js';\nimport { getCurrentProject, onCurrentProjectChanged } from './current-project.js';\nimport { onTrayAccentChanged } from './tray-accent.js';\n\n/** Un service, tel qu'une ligne de menu a besoin de le connaître. */\nexport type TrayService = {\n id: string;\n name: string;\n /** L'agent qui le fait tourner, quand il en a un — requis pour l'arrêter. */\n agentId: string | null;\n running: boolean;\n /**\n * En échec : le processus s'est arrêté sur une erreur, ou sa sonde de santé\n * le déclare malade. C'est ce qui fait passer l'icône en alerte.\n */\n failed: boolean;\n /** Première adresse à laquelle il répond, ou null s'il n'en expose aucune. */\n url: string | null;\n};\n\n/**\n * Les services à montrer, et leur état courant.\n *\n * Deux régimes, parce que la question n'est pas la même :\n *\n * - **Un projet est ouvert** : tous ses services, y compris ceux à l'arrêt.\n * C'est là qu'on vient les démarrer, et un service absent du menu ne se\n * démarre pas depuis le menu.\n * - **Aucun projet ouvert** : seulement ce qui tourne ou ce qui est tombé. La\n * machine peut en compter des centaines, tous projets confondus ; les lister\n * ferait un menu que personne ne parcourt, pour une question — « lequel\n * démarrer ? » — que personne ne pose sans avoir d'abord choisi un projet.\n *\n * L'hôte est toujours `localhost` : cette liste ne sert qu'à l'icône du poste,\n * qui ouvre un navigateur sur cette machine. Les adresses de réseau local\n * appartiennent à l'interface, qui sait pour qui elle les affiche.\n */\nexport async function listTrayServices(): Promise<TrayService[]> {\n const [all, processes] = await Promise.all([serviceStore.list(), listAllProcesses()]);\n const byServiceId = new Map(processes.map((p) => [p.serviceId, p]));\n\n const services = all.map((service): TrayService => {\n const status = byServiceId.get(service.id);\n return {\n id: service.id,\n name: service.name,\n agentId: status?.agentId ?? service.agentId ?? null,\n running: status?.state === 'running' || status?.state === 'starting',\n failed: status?.state === 'errored' || status?.healthStatus === 'unhealthy',\n url: primaryServiceLink(service, 'localhost'),\n };\n });\n\n const owned = await currentProjectServiceIds();\n if (owned) return services.filter((service) => owned.has(service.id));\n\n // Ni lancé ni en échec : jamais démarré, ou arrêté et sans rien à en dire.\n // L'agent n'apprend un service qu'à son premier démarrage — un service que\n // personne n'a jamais lancé n'a donc aucun état à montrer.\n return services.filter((service) => service.running || service.failed);\n}\n\n/**\n * Les services du projet regardé, ou `null` quand il n'y en a pas à quoi se\n * référer — aucun onglet ne l'a annoncé, ou le projet annoncé est introuvable\n * (le cas d'un projet du cloud que cette machine n'a pas encore récupéré).\n */\nasync function currentProjectServiceIds(): Promise<Set<string> | null> {\n const ref = getCurrentProject();\n if (!ref) return null;\n\n const project = await projectStore.get(ref);\n if (!project) return null;\n\n return new Set(project.serviceIds);\n}\n\n/**\n * Prévient quand cette liste a pu changer — état d'un process, ou\n * configuration des services.\n *\n * Ne dit pas ce qui a changé : l'appelant reconstruit sa vue entière, qui ne\n * peut alors pas diverger de la réalité. Rend de quoi se désabonner.\n */\nexport function onTrayServicesChanged(listener: () => void): () => void {\n const onStatus = (): void => listener();\n agentManager.on('process:status', onStatus);\n const offServices = serviceStore.onChange(onStatus);\n // Le déverrouillage, sans quoi une icône posée au démarrage resterait sur sa\n // vue vide : au premier lancement comme après un mot de passe maître, les\n // services ne sont lisibles qu'après.\n const offUnlock = onVaultUnlocked(onStatus);\n // Changer de projet change la liste sans qu'aucun service ne bouge.\n const offProject = onCurrentProjectChanged(onStatus);\n // Changer de thème ne change aucune ligne du menu — mais l'icône, si. Ce\n // signal est le seul que la barre système écoute : tout ce qui la redessine\n // passe par ici, sous peine de n'être vu qu'au prochain démarrage de service.\n const offAccent = onTrayAccentChanged(onStatus);\n\n return () => {\n agentManager.off('process:status', onStatus);\n offServices();\n offUnlock();\n offAccent();\n offProject();\n };\n}\n","/**\n * L'icône de barre système : celle de l'organisation du projet ouvert, à\n * défaut celle de Runeya.\n *\n * Une machine fait tourner plusieurs Runeya, et toutes posent la même icône.\n * Le logo de l'organisation est ce qui les distingue d'un coup d'œil, et il\n * existe déjà — le cloud le sert sur `/api/org-logo/<orgId>`, sans session,\n * précisément pour qu'une vignette n'ait pas à négocier un accès.\n *\n * Ce service ne fait que le ramener sur le disque, dans la forme que la barre\n * système attend : un PNG partout, un ICO sous Windows. Tout ce qui échoue —\n * pas de cloud, pas d'organisation, pas de logo, format inattendu — rend\n * `null`, et l'appelant garde l'icône de Runeya. Une icône est un agrément :\n * rien ici ne doit empêcher une Runeya de tourner.\n */\nimport { mkdir, writeFile, rename } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { orgCloudUrl } from './cloud-api.js';\nimport { readOrgLogo } from './vault-resolver.js';\nimport { getCurrentProject } from './current-project.js';\nimport { machineRoot } from './vault-resolver.js';\nimport { pngToIco, isPng } from './png-to-ico.js';\nimport { getTrayAccent } from './tray-accent.js';\nimport { renderRuneyaIcon } from './runeya-icon.js';\n\n/** Au-delà, ce n'est plus une vignette : on renonce plutôt que de tout charger. */\nconst MAX_LOGO_BYTES = 1024 * 1024;\n\n/** Le cloud est joignable ou il ne l'est pas ; une icône n'attend pas. */\nconst FETCH_TIMEOUT_MS = 3_000;\n\n/**\n * Un logo par organisation, retenu un moment.\n *\n * Pas pour la vie du process : un logo d'organisation se change depuis le\n * cloud, et une icône figée jusqu'au prochain redémarrage serait un défaut que\n * personne ne saurait expliquer. Pas à chaque dessin non plus — le menu se\n * redessine à chaque changement d'état d'un service.\n */\nconst CACHE_TTL_MS = 10 * 60_000;\nconst cache = new Map<string, { path: string | null; at: number }>();\n\n/** Le dossier des icônes rapatriées, dans la racine machine. */\nexport function trayIconDir(): string {\n return join(machineRoot(), 'tray-icons');\n}\n\n/**\n * Le logo de l'organisation du projet ouvert, prêt à être posé dans la barre\n * système — ou `null` s'il n'y en a pas.\n *\n * Les octets sont d'abord cherchés dans le coffre : l'interface les y a déjà\n * rapatriés pour s'afficher hors ligne (`cacheOrgLogos`), et les redemander au\n * réseau pour la même image serait le travail d'un doublon.\n *\n * Le format est demandé, pas négocié : `systray2` ne lit que le PNG (et l'ICO\n * sous Windows, fabriqué ici), tandis que la page d'organisation enregistre en\n * JPEG. Le cloud convertit — c'est lui qui a le décodeur d'images ; en ajouter\n * un ici est exclu, le CLI s'installant par npm, où les paquets à script\n * d'installation ne se construisent pas.\n *\n * Les octets reçus sont malgré tout vérifiés : une conversion ratée ou une\n * route plus ancienne rendrait autre chose qu'un PNG, et la barre système n'en\n * dirait rien — elle afficherait une icône vide.\n */\nexport async function resolveTrayIcon(\n platform: NodeJS.Platform = process.platform,\n): Promise<string | null> {\n const orgId = getCurrentProject()?.orgId;\n if (orgId) {\n const cached = cache.get(orgId);\n const logo = cached && Date.now() - cached.at < CACHE_TTL_MS\n ? cached.path\n : await resolveOrgLogo(orgId, platform);\n if (!cached || Date.now() - cached.at >= CACHE_TTL_MS) {\n cache.set(orgId, { path: logo, at: Date.now() });\n }\n if (logo) return logo;\n }\n\n // Pas de logo — ni d'organisation, ou bien elle n'en a pas posé : reste la\n // couleur du thème, qui distingue déjà deux Runeya à l'écran.\n return renderThemedIcon(platform);\n}\n\n/**\n * L'icône Runeya dans la couleur du thème, écrite sur le disque.\n *\n * `null` tant qu'aucun onglet n'a annoncé sa couleur : le CLI garde alors le\n * fichier livré avec lui, qui est cette même icône dans sa teinte d'origine.\n */\nasync function renderThemedIcon(platform: NodeJS.Platform): Promise<string | null> {\n const accent = getTrayAccent();\n if (!accent) return null;\n\n try {\n // 64 pixels : la taille que les barres système réclament au plus, et huit\n // fois moins d'octets à écrire que les 512 des fichiers livrés.\n const png = renderRuneyaIcon(accent, 64);\n if (!png) return null;\n // La couleur est dans le nom : deux thèmes ne se disputent pas un fichier,\n // et repasser à un thème déjà vu ne réécrit rien.\n return writeTrayIcon(`theme-${accent.replace(/[^a-z0-9]/g, '')}`, png, platform);\n } catch (err) {\n console.log(`[tray] icône du thème non écrite : ${(err as Error).message}`);\n return null;\n }\n}\n\n/**\n * Poser une icône dans le dossier, sous la forme que la plateforme attend.\n *\n * Le PNG passe tel quel partout sauf sous Windows, où il est emballé en ICO —\n * la seule chose qui distingue les deux icônes que ce service produit, celle\n * d'une organisation et celle d'un thème.\n */\nasync function writeTrayIcon(\n stem: string,\n png: Uint8Array,\n platform: NodeJS.Platform,\n): Promise<string | null> {\n const dir = trayIconDir();\n await mkdir(dir, { recursive: true });\n const path = join(dir, stem);\n\n if (platform === 'win32') {\n const ico = pngToIco(png);\n return ico ? writeAtomic(`${path}.ico`, ico) : null;\n }\n return writeAtomic(`${path}.png`, png);\n}\n\n/**\n * Écrire l'icône en une fois, jamais en place.\n *\n * Plusieurs Runeya partagent ce dossier et peuvent viser le même fichier au\n * même moment — même organisation, deux piles. Sans le passage par un\n * temporaire, une barre système pourrait lire un fichier à moitié écrit et\n * afficher une icône tronquée. Le motif `.tmp` + `rename` est celui de tout le\n * reste du serveur (§7) ; les helpers existants n'écrivent que du texte.\n */\nasync function writeAtomic(path: string, bytes: Uint8Array): Promise<string> {\n // Le temporaire porte le pid : deux instances qui écrivent ensemble ne\n // doivent pas se disputer le même brouillon.\n const tmp = `${path}.${process.pid}.tmp`;\n await writeFile(tmp, bytes);\n await rename(tmp, path);\n return path;\n}\n\nasync function resolveOrgLogo(orgId: string, platform: NodeJS.Platform): Promise<string | null> {\n try {\n const bytes = await orgLogoBytes(orgId);\n if (!bytes) return null;\n // Le nom est dérivé de l'id, pas fourni par lui : un id est une donnée\n // distante, et il ne compose pas un chemin.\n return writeTrayIcon(`org-${orgId.replace(/[^a-zA-Z0-9_-]/g, '')}`, bytes, platform);\n } catch (err) {\n console.log(`[tray] logo d'organisation indisponible : ${(err as Error).message}`);\n return null;\n }\n}\n\n/**\n * Les octets du logo, en PNG — le seul format que la barre système lise.\n *\n * Le coffre garde l'image telle qu'elle a été envoyée, et la page\n * d'organisation enregistre en JPEG : ce qui s'y trouve n'est donc utilisable\n * directement que si c'est déjà un PNG. Sinon la conversion est demandée au\n * cloud de cette organisation — pas au cloud par défaut, une organisation\n * pouvant être hébergée ailleurs.\n */\nasync function orgLogoBytes(orgId: string): Promise<Uint8Array | null> {\n const stored = await readOrgLogo(orgId);\n if (stored && isPng(stored.bytes)) return stored.bytes;\n\n const url = `${await orgCloudUrl(orgId)}/api/org-logo/${encodeURIComponent(orgId)}?format=png`;\n const response = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n // 404 : cette organisation n'a pas de logo. C'est une réponse, pas une panne.\n if (!response.ok) return null;\n\n const bytes = new Uint8Array(await response.arrayBuffer());\n if (bytes.length === 0 || bytes.length > MAX_LOGO_BYTES) return null;\n // Une conversion ratée, ou un cloud plus ancien qui ignore le paramètre,\n // rendrait autre chose qu'un PNG — que la barre système afficherait vide.\n return isPng(bytes) ? bytes : null;\n}\n","/**\n * Emballer un PNG dans un conteneur ICO.\n *\n * Windows exige un `.ico` dans sa barre système, et un ICO depuis Vista peut\n * contenir un PNG tel quel : il n'y a donc rien à ré-encoder, seulement un\n * en-tête de six octets et une entrée de seize à poser devant. C'est la raison\n * pour laquelle cette conversion tient ici plutôt que dans une dépendance.\n *\n * Rend `null` plutôt que de deviner quand les octets ne sont pas un PNG lisible\n * ou que l'image dépasse 256 pixels — le format ICO code chaque dimension sur\n * un seul octet, et un `0` y signifie 256. Redimensionner demanderait un\n * décodeur d'image ; ce n'est pas le travail de cette fonction.\n */\n\n/** Les huit octets qui ouvrent un PNG, et rien d'autre. */\nexport function isPng(bytes: Uint8Array): boolean {\n const signature = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];\n return bytes.length > signature.length && signature.every((b, i) => bytes[i] === b);\n}\n\n/** Les dimensions d'un PNG, lues dans son IHDR — le premier chunk, toujours. */\nexport function pngSize(bytes: Uint8Array): { width: number; height: number } | null {\n // 8 octets de signature, 4 de longueur, 4 de type, puis largeur et hauteur.\n if (bytes.length < 24 || !isPng(bytes)) return null;\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n if (String.fromCharCode(...bytes.slice(12, 16)) !== 'IHDR') return null;\n const width = view.getUint32(16);\n const height = view.getUint32(20);\n if (width === 0 || height === 0) return null;\n return { width, height };\n}\n\nexport function pngToIco(png: Uint8Array): Uint8Array | null {\n const size = pngSize(png);\n if (!size) return null;\n if (size.width > 256 || size.height > 256) return null;\n\n const header = new Uint8Array(6 + 16);\n const view = new DataView(header.buffer);\n // ICONDIR : réservé (0), type 1 = icône, une seule image.\n view.setUint16(0, 0, true);\n view.setUint16(2, 1, true);\n view.setUint16(4, 1, true);\n // ICONDIRENTRY : 256 se code par 0, la seule valeur qui ne tient pas sur l'octet.\n header[6] = size.width === 256 ? 0 : size.width;\n header[7] = size.height === 256 ? 0 : size.height;\n header[8] = 0; // couleurs de la palette : aucune, l'image est en couleurs vraies\n header[9] = 0; // réservé\n view.setUint16(10, 1, true); // plans\n view.setUint16(12, 32, true); // bits par pixel\n view.setUint32(14, png.length, true);\n view.setUint32(18, header.length, true); // décalage des données : juste après l'en-tête\n\n const ico = new Uint8Array(header.length + png.length);\n ico.set(header, 0);\n ico.set(png, header.length);\n return ico;\n}\n","/**\n * L'icône Runeya, dessinée à la demande dans la couleur du thème.\n *\n * Les PNG livrés avec le CLI ont une couleur figée (`#6366f1`), alors que\n * l'interface se teinte : deux Runeya au thème différent posaient la même\n * icône. Elle est donc redessinée ici, à partir de la même géométrie que\n * `assets/icon.svg` — un rectangle arrondi et deux traits blancs.\n *\n * Redessiner plutôt que recolorer : recolorer demanderait de décoder le PNG\n * livré et de deviner quels pixels appartiennent au fond ; la géométrie, elle,\n * est connue, tient en quatre points, et donne un tracé net à n'importe quelle\n * taille. Rien de tout cela ne demande de bibliothèque : `zlib` suffit à écrire\n * un PNG, et l'anticrénelage se déduit de la distance au tracé.\n */\nimport { deflateSync } from 'node:zlib';\n\n/** Le dessin est décrit dans le repère de `icon.svg` : 28 × 28. */\nconst VIEW = 28;\nconst CORNER_RADIUS = 8;\nconst STROKE_WIDTH = 2.5;\n\n/** Les deux traits blancs, en segments — la polyligne du logo, puis sa barre. */\nconst STROKES: [number, number, number, number][] = [\n [7, 20, 14, 8],\n [14, 8, 21, 20],\n [10, 16, 18, 16],\n];\n\n/** `#rgb` ou `#rrggbb` → composantes, ou `null` si ce n'est pas une couleur. */\nexport function parseHexColor(hex: string): [number, number, number] | null {\n const value = hex.trim().replace(/^#/, '');\n const full = value.length === 3 ? value.replace(/./g, (c) => c + c) : value;\n if (!/^[0-9a-fA-F]{6}$/.test(full)) return null;\n return [\n parseInt(full.slice(0, 2), 16),\n parseInt(full.slice(2, 4), 16),\n parseInt(full.slice(4, 6), 16),\n ];\n}\n\n/** Distance signée à un rectangle arrondi centré à l'origine. */\nfunction distanceToRoundedRect(x: number, y: number, half: number, radius: number): number {\n const dx = Math.abs(x) - (half - radius);\n const dy = Math.abs(y) - (half - radius);\n const outside = Math.hypot(Math.max(dx, 0), Math.max(dy, 0));\n return outside + Math.min(Math.max(dx, dy), 0) - radius;\n}\n\n/** Distance signée à un segment épais aux extrémités rondes — un trait du logo. */\nfunction distanceToStroke(\n x: number, y: number,\n [ax, ay, bx, by]: [number, number, number, number],\n width: number,\n): number {\n const px = x - ax;\n const py = y - ay;\n const vx = bx - ax;\n const vy = by - ay;\n const t = Math.min(1, Math.max(0, (px * vx + py * vy) / (vx * vx + vy * vy)));\n return Math.hypot(px - vx * t, py - vy * t) - width / 2;\n}\n\n/**\n * Combien ce pixel est couvert par la forme, entre 0 et 1.\n *\n * La transition se fait sur la largeur d'un pixel de part et d'autre du bord :\n * c'est ce qui donne les contours lisses, sans suréchantillonner.\n */\nfunction coverage(distance: number, pixel: number): number {\n return Math.min(1, Math.max(0, 0.5 - distance / pixel));\n}\n\n/** Un PNG carré de `size` pixels, dans la couleur donnée. */\nexport function renderRuneyaIcon(color: string, size = 64): Uint8Array | null {\n const rgb = parseHexColor(color);\n if (!rgb || size < 8 || size > 1024) return null;\n\n const scale = size / VIEW;\n const pixel = 1 / scale; // la taille d'un pixel, dans le repère du dessin\n const half = VIEW / 2;\n const rgba = new Uint8Array(size * size * 4);\n\n for (let py = 0; py < size; py += 1) {\n for (let px = 0; px < size; px += 1) {\n // Le centre du pixel, ramené dans le repère 28 × 28.\n const x = (px + 0.5) / scale;\n const y = (py + 0.5) / scale;\n\n const background = coverage(distanceToRoundedRect(x - half, y - half, half, CORNER_RADIUS), pixel);\n if (background <= 0) continue;\n\n let stroke = 0;\n for (const segment of STROKES) {\n stroke = Math.max(stroke, coverage(distanceToStroke(x, y, segment, STROKE_WIDTH), pixel));\n }\n // Le trait ne déborde jamais du fond : il est peint par-dessus, pas à côté.\n stroke = Math.min(stroke, background);\n\n const offset = (py * size + px) * 4;\n for (let channel = 0; channel < 3; channel += 1) {\n rgba[offset + channel] = Math.round(rgb[channel] * (1 - stroke) + 255 * stroke);\n }\n rgba[offset + 3] = Math.round(background * 255);\n }\n }\n\n return encodePng(rgba, size, size);\n}\n\n// ─── Écriture du PNG ─────────────────────────────────────────────────────────\n\nconst CRC_TABLE = (() => {\n const table = new Uint32Array(256);\n for (let n = 0; n < 256; n += 1) {\n let c = n;\n for (let k = 0; k < 8; k += 1) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n table[n] = c >>> 0;\n }\n return table;\n})();\n\nfunction crc32(bytes: Uint8Array): number {\n let crc = 0xffffffff;\n for (const byte of bytes) crc = CRC_TABLE[(crc ^ byte) & 0xff]! ^ (crc >>> 8);\n return (crc ^ 0xffffffff) >>> 0;\n}\n\n/** Un chunk PNG : longueur, type, données, CRC des deux derniers. */\nfunction chunk(type: string, data: Uint8Array): Uint8Array {\n const out = new Uint8Array(data.length + 12);\n const view = new DataView(out.buffer);\n view.setUint32(0, data.length);\n for (let i = 0; i < 4; i += 1) out[4 + i] = type.charCodeAt(i);\n out.set(data, 8);\n view.setUint32(data.length + 8, crc32(out.subarray(4, data.length + 8)));\n return out;\n}\n\nfunction encodePng(rgba: Uint8Array, width: number, height: number): Uint8Array {\n const header = new Uint8Array(13);\n const view = new DataView(header.buffer);\n view.setUint32(0, width);\n view.setUint32(4, height);\n header[8] = 8; // 8 bits par composante\n header[9] = 6; // RGBA\n // compression, filtrage et entrelacement : les seules valeurs que PNG définit.\n\n // Chaque ligne est précédée de son octet de filtre — aucun filtre ici, les\n // gains ne valent pas le code qu'ils demandent sur une image de 64 pixels.\n const raw = new Uint8Array(height * (width * 4 + 1));\n for (let y = 0; y < height; y += 1) {\n raw[y * (width * 4 + 1)] = 0;\n raw.set(rgba.subarray(y * width * 4, (y + 1) * width * 4), y * (width * 4 + 1) + 1);\n }\n\n const signature = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);\n const parts = [\n signature,\n chunk('IHDR', header),\n chunk('IDAT', new Uint8Array(deflateSync(raw))),\n chunk('IEND', new Uint8Array(0)),\n ];\n\n const png = new Uint8Array(parts.reduce((total, part) => total + part.length, 0));\n let at = 0;\n for (const part of parts) {\n png.set(part, at);\n at += part.length;\n }\n return png;\n}\n"],"mappings":"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","names":["resolve","execFile","promisify","z","execFileAsync","promisify","execFile","cli","z","z","value","z","z","TRPCError","join","env","TRPCError","z","resolve","z","TRPCError","z","TRPCError","resolve","z","TRPCError","TRPCError","TRPCError","SUBSCRIPTION_QUEUE_MAX","resolve","z","TRPCError","z","z","z","z","z","TRPCError","z","env","TRPCError","z","TRPCError","maskApiKey","z","TRPCError","current","resolve","z","TRPCError","execFile","spawn","stat","join","homedir","readFile","writeFile","rename","mkdir","chmod","join","z","join","z","mkdir","writeFile","rename","chmod","readFile","homedir","TRPCError","resolve","execFile","z","stat","spawn","join","z","TRPCError","mkdir","writeFile","join","dirname","z","TRPCError","join","mkdir","dirname","writeFile","z","TRPCError","z","TRPCError","resolve","randomUUID","TRPCError","z","TRPCError","TRPCError","Anthropic","OpenAI","Anthropic","OpenAI","chunk","TRPCError","mkdir","join","resolve","publish","result","join","mkdir","isSubtreeComplete","startedAt","current","ScopeShape","z","scopeOf","randomUUID","TRPCError","randomUUID","TRPCError","z","MAX_BUFFER","resolve","z","randomUUID","current","TRPCError","z","TRPCError","chunk","z","resolve","TRPCError","z","randomUUID","EventEmitter","EventEmitter","randomUUID","z","resolve","mkdir","stat","writeFile","join","z","TRPCError","join","stat","mkdir","writeFile","TRPCError","z","cloudFetch","z","TRPCError","z","resolve","TRPCError","z","z","resolve","z","TRPCError","readFile","readdir","stat","writeFile","mkdir","rename","rm","join","dirname","z","TRPCError","mkdir","dirname","entries","readdir","join","stat","readFile","writeFile","rename","rm","z","TRPCError","join","join","randomUUID","mkdir","rm","Y","readFile","dirname","join","randomUUID","join","readFile","dirname","randomUUID","randomUUID","resolve","mkdir","rm","readdir","readFile","writeFile","mkdir","rename","stat","join","createCipheriv","createDecipheriv","randomBytes","createDecipheriv","randomBytes","createCipheriv","entries","readdir","stat","join","readFile","mkdir","writeFile","rename","TRPCError","z","cloudFetch","current","readdir","stat","homedir","join","resolve","dirname","z","MAX_ENTRIES","z","join","homedir","resolve","stat","readdir","entries","dirname","z","isAbsolute","TRPCError","execFile","isAbsolute","promisify","promisify","execFile","INSTALL_TIMEOUT_MS","isAbsolute","listeners","z","isAbsolute","TRPCError","chmod","stat","stat","chmod","readdir","readFile","writeFile","mkdir","copyFile","rename","stat","join","entries","readdir","exists","stat","join","mkdir","copyFile","readFile","writeFile","rename","readFile","writeFile","rename","unlink","mkdir","chmod","stat","join","exists","stat","mkdir","join","readFile","writeFile","rename","chmod","unlink","randomBytes","createCipheriv","createDecipheriv","randomUUID","readFile","writeFile","rename","mkdir","access","readdir","join","dirname","encryptValue","randomBytes","createCipheriv","createDecipheriv","readFile","writeFile","rename","join","access","mkdir","readdir","randomUUID","env","entries","resolve","dirname","join","stat","ENCRYPTED_KEY_FILENAME","VERIFY_FILENAME","stat","join","existsSync","resolve","existsSync","startedAt","randomBytes","resolvePath","resolve","env","mkdir","writeFile","rename","join","cache","join","accent","mkdir","writeFile","rename","resolvePath","resolve"]}
|
|
1
|
+
{"version":3,"sources":["../../server/src/create-server.ts","../../server/src/trpc/routers/health.ts","../../server/src/trpc/routers/app-update.ts","../../server/src/trpc/routers/changelog.ts","../../server/src/trpc/routers/project.ts","../../server/src/services/current-project.ts","../../server/src/services/org-keys.ts","../../server/src/services/master-password.ts","../../server/src/services/service-graph.ts","../../server/src/trpc/routers/agent.ts","../../server/src/trpc/routers/process.ts","../../server/src/services/process-control.ts","../../server/src/trpc/routers/audit.ts","../../server/src/trpc/routers/setup.ts","../../server/src/trpc/routers/environment.ts","../../server/src/trpc/routers/settings.ts","../../server/src/trpc/routers/editor.ts","../../server/src/services/user-config-manager.ts","../../server/src/trpc/routers/api-keys.ts","../../server/src/trpc/routers/git.ts","../../server/src/trpc/routers/scenario.ts","../../server/src/trpc/crud-procedure-utils.ts","../../server/src/trpc/ai-generation-procedure-utils.ts","../../server/src/services/ai-generation.ts","../../server/src/services/scenario-runner.ts","../../server/src/services/scenario-presets.ts","../../server/src/trpc/routers/debug.ts","../../server/src/trpc/routers/diagnostics.ts","../../server/src/services/log-buffer.ts","../../server/src/trpc/routers/kanban-queue.ts","../../server/src/services/kanban-queue.ts","../../server/src/trpc/routers/kanban.ts","../../server/src/trpc/routers/terminal.ts","../../server/src/trpc/routers/utility.ts","../../server/src/trpc/routers/wiki.ts","../../server/src/trpc/routers/config.ts","../../server/src/trpc/routers/cloud-sync.ts","../../server/src/services/org-sync-scope.ts","../../server/src/services/org-canary.ts","../../server/src/services/cloud-sync-bridge.ts","../../server/src/services/sync-doc-cache.ts","../../server/src/services/key-adoption.ts","../../server/src/trpc/routers/filesystem.ts","../../server/src/trpc/routers/desktop.ts","../../server/src/services/desktop-launcher.ts","../../server/src/services/tray-accent.ts","../../server/src/trpc/router.ts","../../server/src/middleware/error-handler.ts","../../server/src/services/migration-engine.ts","../../server/src/services/file-security.ts","../../server/src/services/vault-migration.ts","../../server/src/services/settings-migration.ts","../../server/src/migrations/migrate-from-legacy.ts","../../server/src/services/server-state.ts","../../server/src/services/openapi.ts","../../server/src/services/image-cleanup.service.ts","../../server/src/index.ts","../../server/src/commands/pull-env.ts","../../server/src/services/tray-services.ts","../../server/src/services/tray-icon.ts","../../server/src/services/png-to-ico.ts","../../server/src/services/runeya-icon.ts"],"sourcesContent":["import express from 'express';\nimport cors from 'cors';\nimport { createServer, type Server } from 'node:http';\nimport { resolve } from 'node:path';\nimport { WebSocketServer, WebSocket } from 'ws';\nimport { createExpressMiddleware } from '@trpc/server/adapters/express';\nimport { applyWSSHandler } from '@trpc/server/adapters/ws';\nimport { appRouter } from './trpc/router.js';\nimport { createContext } from './trpc/trpc.js';\nimport { getCloudApiUrl, getDeviceName } from './trpc/routers/cloud-auth.js';\nimport { cloudSessionStore } from './services/cloud-session-store.js';\nimport { readCloudIdentity, accountForOrg, orgCloudUrl } from './services/cloud-api.js';\nimport { APP_VERSION_HEADER, appVersion } from './config/app-version.js';\nimport { errorHandler } from './middleware/error-handler.js';\nimport { agentManager } from './services/agent-manager.js';\nimport { agentSpawner } from './services/agent-spawner.js';\nimport { startClaudeTranscriptWatcher, stopClaudeTranscriptWatcher } from './services/claude-transcript-sync.js';\nimport { startCodexTranscriptWatcher, stopCodexTranscriptWatcher } from './services/codex-transcript-sync.js';\nimport { settingsManager } from './services/settings-manager.js';\nimport { applyPersistedLanMode, registerHttpServer } from './services/lan-mode.js';\nimport { installLogCapture } from './services/log-buffer.js';\nimport { unregisterInstance } from './services/instance-registry.js';\nimport { migrationEngine } from './services/migration-engine.js';\nimport { ensureFilePermissions } from './services/file-security.js';\nimport { auditService } from './services/audit-service.js';\nimport { environmentStore } from './services/environment-store.js';\nimport { ensureDataGitignore } from './utils/ensure-data-gitignore.js';\nimport { machineRoot, keyRoot, legacyVaultRoot, allVaultRoots, listOrgVaults, orgVaultRoot } from './services/vault-resolver.js';\nimport { sweepStaleTempFiles } from './services/run-store-utils.js';\nimport { openLegacyVault, migrateLegacyVault } from './services/vault-migration.js';\nimport { projectStore } from './services/project-store.js';\nimport { cloudSyncBridge } from './services/cloud-sync-bridge.js';\nimport { unlockOrgKeys, sealUnopenedOrgVaults } from './services/org-keys.js';\nimport { migrateSettingsIntoVaults } from './services/settings-migration.js';\nimport { serviceStore } from './services/service-store.js';\nimport { runLegacyMigration, runOverrideOnlyMigration, findLegacyKeyInBackup } from './migrations/migrate-from-legacy.js';\nimport { env } from './config/env.js';\nimport {\n setEncryptionKeyInMemory,\n getEncryptionKey,\n loadFromEnv,\n hasEncryptionKey,\n isCiMode,\n setPendingLegacyKey,\n getPendingLegacyKey,\n clearPendingLegacyKey,\n hasPendingLegacyKey,\n} from './utils/encryption-key.js';\nimport {\n generateJwtSecret,\n signJwt,\n verifyJwt,\n getJwtSecretGeneratedAt,\n} from './services/auth-token.js';\nimport {\n writeEncryptedKey,\n readEncryptedKey,\n writeVerifyFile,\n verifyEncryptionKey,\n hasEncryptedKeyFile,\n hasVerifyFile,\n} from './services/master-password.js';\nimport { getServerState } from './services/server-state.js';\nimport { apiKeyStore } from './services/api-key-store.js';\nimport { generateLlmsTxt } from './services/llms-txt-generator.js';\nimport { getOpenApiDocument } from './services/openapi.js';\nimport rateLimit from 'express-rate-limit';\nimport { existsSync, createReadStream } from 'node:fs';\nimport multer from 'multer';\nimport { imageStorageService, ALLOWED_MIME_TYPES, MAX_IMAGE_SIZE_BYTES } from './services/image-storage.service.js';\nimport { imageCleanupService } from './services/image-cleanup.service.js';\n\nexport interface ServerInstance {\n app: express.Express;\n server: Server;\n wss: WebSocketServer;\n shutdown: () => Promise<void>;\n}\n\nfunction csrfMiddleware(req: express.Request, res: express.Response, next: express.NextFunction): void {\n const contentType = req.headers['content-type'] ?? '';\n if (!contentType.includes('application/json')) {\n res.status(415).json({ error: 'Content-Type must be application/json' });\n return;\n }\n const origin = req.headers['origin'];\n if (origin) {\n const allowedOrigins = [\n `http://localhost:${env.PORT}`,\n `http://127.0.0.1:${env.PORT}`,\n 'http://localhost:5173', // dev Vite\n 'http://127.0.0.1:5173',\n ];\n // In LAN mode, allow any origin pointing to the server port (e.g. tablet on local network)\n if (env.RUNEYA_LAN_PROXY) {\n try {\n const parsed = new URL(origin);\n const originPort = parsed.port || (parsed.protocol === 'https:' ? '443' : '80');\n if (originPort === String(env.PORT) || originPort === '5173') {\n next();\n return;\n }\n } catch {\n // invalid origin URL — fall through to deny\n }\n }\n if (!allowedOrigins.includes(origin)) {\n res.status(403).json({ error: 'Forbidden origin' });\n return;\n }\n }\n next();\n}\n\nconst authLimiter = rateLimit({\n windowMs: 15 * 60 * 1000,\n max: 5,\n standardHeaders: true,\n legacyHeaders: false,\n message: { error: 'Trop de tentatives. Réessayez dans 15 minutes.' },\n});\n\nconst llmsLimiter = rateLimit({\n windowMs: 60 * 1000, // 1 minute\n max: 60,\n standardHeaders: true,\n legacyHeaders: false,\n message: { error: 'Rate limit exceeded. Retry in 1 minute.' },\n});\n\nexport async function createLocalServer(): Promise<ServerInstance> {\n // Before anything logs: the settings panel streams this buffer, and a boot\n // whose first lines are missing is the one you most want to read.\n installLogCapture();\n\n // Generate JWT signing secret first\n generateJwtSecret();\n\n // Load encryption key from env var (CI mode) or check state\n const ciMode = await loadFromEnv();\n\n // Run legacy migration FIRST — loads key temporarily, re-encrypts, then stores in pending holder\n await runLegacyMigration(env.DATA_DIR);\n\n // Handle server restart between migration and setup:\n // The pending key is in-memory only, so recover it from backup if needed.\n // Only attempt recovery if .runeya-verify doesn't exist — if it does, setup\n // was already completed at least once and we should not treat this as a migration.\n const keyDir = await keyRoot();\n if (!ciMode && !hasPendingLegacyKey() && !(await hasEncryptedKeyFile(keyDir)) && !(await hasVerifyFile(keyDir))) {\n const recoveredKey = await findLegacyKeyInBackup(env.DATA_DIR);\n if (recoveredKey) {\n setPendingLegacyKey(recoveredKey);\n console.log('[server] Legacy key recovered from backup — setup required to migrate');\n }\n }\n\n if (!ciMode) {\n const { state } = await getServerState();\n if (state === 'locked') {\n console.log('[server] Serveur verrouillé — master password requis');\n } else if (state === 'setup') {\n console.log('[server] Premier lancement — setup requis');\n }\n }\n\n // The local vault is NOT created here. It appears when a local project is\n // written into it (see `ensureLocalVault`), so working only on cloud projects\n // leaves the directories Runeya was started in untouched.\n const absoluteDataDir = resolve(env.DATA_DIR);\n console.log(`[server] Local project directory: ${absoluteDataDir}`);\n console.log(`[server] Machine directory: ${machineRoot()}`);\n if (existsSync(env.DATA_DIR)) {\n // Only meaningful once the directory exists: it guards files in it.\n await ensureDataGitignore(env.DATA_DIR);\n }\n\n // Initialize settings and run migrations\n await settingsManager.getSettings();\n // Avant toute écoute : le mode LAN mémorisé décide de l'adresse d'écoute.\n await applyPersistedLanMode();\n await migrationEngine.run();\n\n // Enforce secure file permissions on sensitive data files\n await ensureFilePermissions();\n\n // Clean up old audit log entries\n auditService.cleanup().catch((err) => console.error('[server] Audit cleanup failed:', err));\n\n const app = express();\n\n /**\n * Qui tient une connexion, et combien de temps.\n *\n * Un navigateur n'accorde que six connexions par hôte, partagées entre TOUS\n * ses onglets : une poignée de requêtes lentes suffit à faire attendre\n * l'ouverture d'un WebSocket, sans que rien ne le signale nulle part. On\n * journalise donc ce qui dépasse la seconde, et ce qui est encore en vol\n * pendant ce temps.\n */\n let inFlight = 0;\n app.use((req, res, next) => {\n const startedAt = Date.now();\n inFlight++;\n const label = `${req.method} ${req.originalUrl.split('?')[0]}`;\n const slow = setTimeout(() => {\n console.warn(`[http] LENTE (>1s, toujours en cours) ${label} — ${inFlight} requête(s) en vol`);\n }, 1000);\n res.on('close', () => {\n clearTimeout(slow);\n inFlight--;\n const ms = Date.now() - startedAt;\n if (ms >= 1000) console.warn(`[http] ${label} a tenu une connexion ${(ms / 1000).toFixed(1)}s`);\n });\n next();\n });\n\n // CORS: restrict to localhost in dev, configurable via env\n // In LAN mode, allow any origin pointing to the server port or Vite dev port\n const corsOrigin = env.CORS_ORIGIN ?? (env.RUNEYA_LAN_PROXY\n ? (origin: string | undefined, cb: (err: Error | null, allow?: boolean) => void) => {\n if (!origin) { cb(null, false); return; }\n try {\n const parsed = new URL(origin);\n const port = parsed.port || (parsed.protocol === 'https:' ? '443' : '80');\n cb(null, port === String(env.PORT) || port === '5173');\n } catch {\n cb(null, false);\n }\n }\n : 'http://localhost:5173');\n app.use(cors({\n origin: corsOrigin,\n credentials: true,\n }));\n\n // Called once after the encryption key is set in memory (unlock or setup).\n // Idempotent: safe to call even if already done.\n let postUnlockDone = false;\n async function runPostUnlock(masterPassword: string | null = null): Promise<void> {\n if (postUnlockDone) return;\n postUnlockDone = true;\n\n // Avant tout : sceller les coffres qui ont leur propre clé et que rien n'a\n // encore ouverts. Tant qu'ils ne le sont pas, ils héritent en silence de la\n // clé machine — ce qui ne les rend pas lisibles, seulement inscriptibles\n // sous la mauvaise clé.\n const sealed = await sealUnopenedOrgVaults();\n if (sealed.length > 0) {\n console.log(`[org-keys] ${sealed.length} coffre(s) scellé(s) le temps de l'ouverture`);\n }\n\n // Puis : chaque organisation présente sur ce disque reçoit sa clé — la\n // sienne si elle en a déjà une, sinon la clé machine, qui est de toute\n // façon celle sous laquelle ses données sont écrites. Rien n'est converti,\n // et une organisation dont la clé n'est pas la nôtre est simplement laissée\n // fermée plutôt que de bloquer la machine entière.\n const orgKeys = await unlockOrgKeys(masterPassword);\n if (orgKeys.seeded.length > 0) {\n console.log(`[org-keys] ${orgKeys.seeded.length} organisation(s) ont reçu leur propre clé de chiffrement`);\n }\n for (const orgId of orgKeys.locked) {\n console.error(`[org-keys] org ${orgId}: sa clé ne s'ouvre pas avec ce master password — ce coffre reste fermé.`);\n }\n\n // Les réglages descendent dans le coffre de leur organisation, une fois.\n const settingsMove = await migrateSettingsIntoVaults();\n if (settingsMove.movedTo) {\n console.log(`[settings] réglages déplacés vers l'organisation ${settingsMove.movedTo} : ${settingsMove.files.join(', ')}`);\n }\n if (settingsMove.ambiguous.length > 0) {\n console.warn(\n `[settings] réglages encore au niveau du poste : ${settingsMove.ambiguous.length} organisations sur cette machine,`\n + ' impossible de deviner à laquelle ils appartiennent — répartissez-les depuis les réglages.',\n );\n }\n\n await runOverrideOnlyMigration(env.DATA_DIR);\n\n if (env.MODE === 'local-simple') {\n const projects = await projectStore.list();\n if (projects.length === 0) {\n const project = await projectStore.create({\n name: 'My Local Project',\n description: 'Auto-generated default project for local development',\n });\n const localEnv = await environmentStore.create({\n projectId: project.id,\n name: 'Local',\n description: 'Default local environment (immutable)',\n variables: {},\n parentIds: [],\n color: '#22c55e',\n immutable: true,\n }, project.orgId);\n await projectStore.update({\n id: project.id,\n orgId: project.orgId,\n environmentIds: [localEnv.id],\n activeEnvironmentId: localEnv.id,\n });\n console.log('[server] Created default project with Local environment');\n }\n }\n\n // Initialize agent manager (loads persisted remote agents — requires encryption key)\n await agentManager.init();\n\n // Pas d'`await` : le spawn attend que l'agent ait démarré son propre\n // process Node et imprimé sa passphrase (~450 ms). Le retenir ici retardait\n // d'autant le `listen`, alors que rien de ce qui suit n'en dépend et que\n // l'interface sait déjà vivre avec un agent pas encore connecté.\n agentSpawner.spawnLocalAgent().catch((err) => {\n console.warn('[server] Failed to spawn the local agent:', err);\n });\n\n // Watch Claude Code's on-disk transcripts so PTY conversations stay\n // synced live with the non-PTY message view.\n startClaudeTranscriptWatcher().catch((err) => {\n console.warn('[server] Failed to start Claude transcript watcher:', err);\n });\n // Le pendant Codex : sans lui, une conversation Codex en terminal\n // n'annonce jamais la fin d'un tour, et le compagnon ne s'y déclenche pas.\n startCodexTranscriptWatcher();\n\n /**\n * Charger les services maintenant que la clé est là : le premier\n * chargement réussi prévient les abonnés — dont l'icône de barre système,\n * qui a pu lire à vide avant le déverrouillage.\n *\n * Volontairement non fatal. `load()` attrape déjà un `services.json`\n * illisible, mais pas `ensureProjectsLoaded()` ni `allVaultRoots()` : sans\n * cette garde, un coffre en mauvais état empêcherait le serveur de finir\n * son démarrage, là où la lecture paresseuse d'avant ne gênait que\n * l'appelant.\n */\n await serviceStore.list().catch((err) => {\n console.warn('[server] Failed to preload services:', err);\n });\n\n // Les fichiers temporaires d'écritures interrompues — voir sweepStaleTempFiles.\n // En arrière-plan : un balayage de répertoires n'a pas à retarder le démarrage.\n void (async () => {\n const orgRoots = (await listOrgVaults()).map((orgId) => orgVaultRoot(orgId));\n const removed = await sweepStaleTempFiles([machineRoot(), ...orgRoots, ...await allVaultRoots()]);\n if (removed > 0) console.log(`[server] ${removed} fichier(s) temporaire(s) orphelin(s) retiré(s)`);\n })().catch((err) => console.warn('[server] Temp file sweep failed:', err));\n\n // Start continuous project sync for every linked organization (requires the\n // encryption key, now loaded, to decrypt stored sync tokens).\n cloudSyncBridge.start().catch((err) => {\n console.warn('[server] Failed to start cloud sync bridge:', err);\n });\n }\n\n // If key is already available at startup (CI mode or legacy plaintext key), run now\n if (hasEncryptionKey()) {\n await runPostUnlock();\n }\n\n // GET /api/status — public\n app.get('/api/status', async (_req, res) => {\n try {\n const state = await getServerState();\n res.json({ ...state, ciMode: isCiMode() });\n } catch {\n res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n // GET /api/cloud/callback — lands here from the cloud authorization page,\n // carrying a single-use token. Exchanges it for a session token, which stays\n // on this server: the browser never receives a cloud credential.\n app.get('/api/cloud/callback', authLimiter, async (req, res) => {\n const token = typeof req.query['token'] === 'string' ? req.query['token'] : null;\n const state = typeof req.query['state'] === 'string' ? req.query['state'] : null;\n if (!token || !state) {\n res.status(400).send('Missing token or state.');\n return;\n }\n // Binds the callback to a login this server started; also stops a stray\n // redirect from installing someone else's token.\n const returnTo = cloudSessionStore.consumeState(state);\n if (!returnTo) {\n res.status(400).send('Unknown or expired login attempt. Please start again.');\n return;\n }\n try {\n // `/device/link`, not `/one-time-token/verify`: the latter hands back the\n // BROWSER's session, which made every linked machine share one session —\n // a sign-out in the web app unlinked them all, and two accounts could not\n // be linked from the same browser. This mints a session for this machine\n // alone, revocable on its own from the \"linked machines\" screens.\n const verifyRes = await fetch(`${getCloudApiUrl()}/api/auth/device/link`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', [APP_VERSION_HEADER]: appVersion },\n body: JSON.stringify({ token, name: getDeviceName() }),\n signal: AbortSignal.timeout(15_000),\n });\n if (!verifyRes.ok) {\n res.status(401).send('The cloud rejected this login token.');\n return;\n }\n // The bearer plugin exposes the SIGNED session token here. The JSON body\n // carries the raw, unsigned one, which `bearer({ requireSignature: true })`\n // would reject — so this header is the only usable source.\n const sessionToken = verifyRes.headers.get('set-auth-token');\n if (!sessionToken) {\n res.status(502).send('The cloud did not return a session token.');\n return;\n }\n // Qui vient de se connecter : c'est cette identité qui nomme le compte,\n // et sans elle deux liaisons du même utilisateur laisseraient deux tokens\n // côte à côte, dont un que plus rien ne rafraîchit.\n const identity = await readCloudIdentity(getCloudApiUrl(), sessionToken);\n if (!identity) {\n res.status(502).send('The cloud did not say who this session belongs to.');\n return;\n }\n await cloudSessionStore.add(getCloudApiUrl(), sessionToken, identity);\n // Sync authenticates with this session, so a fresh sign-in is exactly what\n // links paused on a rejected session were waiting for.\n void cloudSyncBridge.resumeAll();\n res.redirect(`${returnTo}?cloud=linked`);\n } catch {\n res.status(502).send('Could not reach the Runeya cloud.');\n }\n });\n\n // GET /api/cloud/{chat,kanban}/stream — proxies the cloud's SSE streams.\n // EventSource cannot send an Authorization header, so the local JWT travels\n // as a query param, exactly as the tRPC WebSocket already does. The cloud\n // token itself never leaves this process — it is attached here.\n function proxyCloudStream(localPath: string, upstreamPath: string): void {\n app.get(localPath, async (req, res) => {\n const jwt = typeof req.query['token'] === 'string' ? req.query['token'] : '';\n try {\n await verifyJwt(jwt);\n } catch {\n res.status(401).end();\n return;\n }\n const organizationId = typeof req.query['organizationId'] === 'string' ? req.query['organizationId'] : '';\n if (!organizationId) {\n res.status(400).end();\n return;\n }\n // Le flux appartient à une organisation : c'est elle qui dit sous quel\n // compte le relayer. Prendre « le » token du poste rouvrait le flux d'un\n // autre utilisateur dès qu'il y en a deux.\n const accountId = await accountForOrg(organizationId);\n const token = accountId ? await cloudSessionStore.getToken(accountId) : null;\n if (!accountId || !token) {\n res.status(401).end();\n return;\n }\n // Même règle que partout : l'adresse vient de l'organisation, le compte\n // ne fournit que le jeton.\n const streamBase = await orgCloudUrl(organizationId);\n // Long-lived stream: aborted when the browser disconnects, not on a timeout.\n const upstreamAbort = new AbortController();\n req.on('close', () => upstreamAbort.abort());\n try {\n const upstream = await fetch(\n `${streamBase.replace(/\\/+$/, '')}${upstreamPath}?organizationId=${encodeURIComponent(organizationId)}`,\n {\n headers: {\n Authorization: `Bearer ${token}`,\n [APP_VERSION_HEADER]: appVersion,\n Accept: 'text/event-stream',\n },\n signal: upstreamAbort.signal,\n },\n );\n if (!upstream.ok || !upstream.body) {\n res.status(upstream.status === 401 ? 401 : 502).end();\n return;\n }\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n 'X-Accel-Buffering': 'no',\n });\n const reader = upstream.body.getReader();\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n // nosemgrep: direct-response-write -- relais d'un flux SSE amont (text/event-stream), octets opaques, jamais du HTML\n res.write(value);\n }\n res.end();\n } catch {\n // Client disconnect or upstream failure — nothing left to send.\n if (!res.headersSent) res.status(502).end();\n else res.end();\n }\n });\n }\n\n // POST /api/cloud/kanban/image — relays a card attachment to the cloud, which\n // stores it in S3. The browser has no cloud credential, so the token is\n // attached here; the JWT in the query is what proves the local session, as on\n // the streams above.\n // The body limit here is only a memory guard, deliberately above the cloud's\n // own cap (55 MB, MAX_ATTACHMENT_BYTES): the cloud is the single authority on\n // what is too large, and it answers with a clear message. A tighter limit here\n // would reject the file first, with a bare 413 and no explanation.\n app.post(\n '/api/cloud/kanban/image',\n express.raw({ type: () => true, limit: '64mb' }),\n async (req, res) => {\n const jwt = typeof req.query['token'] === 'string' ? req.query['token'] : '';\n try {\n await verifyJwt(jwt);\n } catch {\n res.status(401).end();\n return;\n }\n const organizationId = typeof req.query['organizationId'] === 'string' ? req.query['organizationId'] : '';\n if (!organizationId) {\n res.status(400).end();\n return;\n }\n // Le flux appartient à une organisation : c'est elle qui dit sous quel\n // compte le relayer. Prendre « le » token du poste rouvrait le flux d'un\n // autre utilisateur dès qu'il y en a deux.\n const accountId = await accountForOrg(organizationId);\n const token = accountId ? await cloudSessionStore.getToken(accountId) : null;\n if (!accountId || !token) {\n res.status(401).end();\n return;\n }\n // Même règle que partout : l'adresse vient de l'organisation, le compte\n // ne fournit que le jeton.\n const streamBase = await orgCloudUrl(organizationId);\n // The original file name has to be forwarded too: the cloud stores it and\n // serves it back in Content-Disposition. Dropping it here is what made\n // every attachment land as \"file\".\n const upstreamQuery = new URLSearchParams({ organizationId });\n if (typeof req.query['name'] === 'string') upstreamQuery.set('name', req.query['name']);\n try {\n const upstream = await fetch(\n `${streamBase.replace(/\\/+$/, '')}/api/kanban/image?${upstreamQuery.toString()}`,\n {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n [APP_VERSION_HEADER]: appVersion,\n 'Content-Type': String(req.headers['content-type'] ?? 'application/octet-stream'),\n },\n body: req.body as Buffer,\n // A 55 MB body over a home upstream link takes minutes, not seconds.\n signal: AbortSignal.timeout(300_000),\n },\n );\n res.status(upstream.status).json(await upstream.json().catch(() => ({})));\n } catch {\n res.status(502).json({ error: 'upload-failed' });\n }\n },\n );\n\n // GET /api/cloud/kanban/file/:id — relays an attachment's bytes. Reading is\n // authenticated on the cloud side, and the browser holds no cloud credential,\n // so the local JWT proves the session here and the cloud token is added on\n // the way out.\n // DELETE goes through the same shape: the browser proves the local session\n // with its JWT, the cloud token is added here.\n app.delete('/api/cloud/kanban/file/:id', async (req, res) => {\n const jwt = typeof req.query['token'] === 'string' ? req.query['token'] : '';\n try {\n await verifyJwt(jwt);\n } catch {\n res.status(401).end();\n return;\n }\n // Comme les flux : la pièce jointe appartient à une organisation, et c'est\n // elle qui dit sous quel compte la demander. Absente — un appelant plus\n // ancien que le multicompte — le compte unique du poste répond, ce qui est\n // exactement ce qu'il attendait.\n const fileOrgId = typeof req.query['organizationId'] === 'string' ? req.query['organizationId'] : '';\n const fileAccountId = fileOrgId ? await accountForOrg(fileOrgId) : null;\n const token = await cloudSessionStore.getToken(fileAccountId ?? undefined);\n if (!token) {\n res.status(401).end();\n return;\n }\n try {\n const upstream = await fetch(\n `${fileOrgId ? await orgCloudUrl(fileOrgId) : ((await cloudSessionStore.getCloudUrl(fileAccountId ?? undefined)) ?? getCloudApiUrl())}`\n + `/api/kanban/file/${encodeURIComponent(req.params.id)}`,\n {\n method: 'DELETE',\n headers: { Authorization: `Bearer ${token}`, [APP_VERSION_HEADER]: appVersion },\n signal: AbortSignal.timeout(15_000),\n },\n );\n res.status(upstream.status).end();\n } catch {\n res.status(502).end();\n }\n });\n\n app.get('/api/cloud/kanban/file/:id', async (req, res) => {\n const jwt = typeof req.query['token'] === 'string' ? req.query['token'] : '';\n try {\n await verifyJwt(jwt);\n } catch {\n res.status(401).end();\n return;\n }\n // Comme les flux : la pièce jointe appartient à une organisation, et c'est\n // elle qui dit sous quel compte la demander. Absente — un appelant plus\n // ancien que le multicompte — le compte unique du poste répond, ce qui est\n // exactement ce qu'il attendait.\n const fileOrgId = typeof req.query['organizationId'] === 'string' ? req.query['organizationId'] : '';\n const fileAccountId = fileOrgId ? await accountForOrg(fileOrgId) : null;\n const token = await cloudSessionStore.getToken(fileAccountId ?? undefined);\n if (!token) {\n res.status(401).end();\n return;\n }\n try {\n const upstream = await fetch(\n `${fileOrgId ? await orgCloudUrl(fileOrgId) : ((await cloudSessionStore.getCloudUrl(fileAccountId ?? undefined)) ?? getCloudApiUrl())}`\n + `/api/kanban/file/${encodeURIComponent(req.params.id)}`,\n {\n headers: { Authorization: `Bearer ${token}`, [APP_VERSION_HEADER]: appVersion },\n signal: AbortSignal.timeout(300_000),\n },\n );\n if (!upstream.ok) {\n res.status(upstream.status).end();\n return;\n }\n res.set('Content-Type', upstream.headers.get('content-type') ?? 'application/octet-stream');\n const disposition = upstream.headers.get('content-disposition');\n if (disposition) res.set('Content-Disposition', disposition);\n res.set('X-Content-Type-Options', 'nosniff');\n res.set('Content-Security-Policy', \"default-src 'none'; sandbox\");\n // nosemgrep: direct-response-write -- relais d'octets de pièce jointe, en-têtes de durcissement conservés\n res.send(Buffer.from(await upstream.arrayBuffer()));\n } catch {\n res.status(502).end();\n }\n });\n\n /**\n * GET /api/cloud/avatar/:userId — relaie les octets d'un avatar.\n *\n * Le cloud sert les avatars publiquement, mais l'adresse de CE cloud est\n * figée dans la donnée : elle est recopiée dans `user.image` au téléversement\n * (`apps/cloud`, `${env.BASE_URL}/api/avatar/…`). Un cloud installé sur une\n * adresse privée — un `localhost:4100` de développement, un cloud d'équipe\n * derrière un VPN — écrit donc une URL que seuls les navigateurs de sa propre\n * machine savent résoudre. Depuis un autre appareil du réseau, l'image casse.\n *\n * Relayé ici, le navigateur ne demande plus qu'à l'origine dont il a chargé\n * l'application : la même en localhost, en LAN, et quand le cloud n'est pas\n * joignable publiquement.\n *\n * Sans jeton, comme la route amont : ces octets sont publics, et un `<img>`\n * ne pose pas d'en-tête. Rien de ce que la requête porte ne choisit l'hôte\n * appelé — il vient des tampons de ce poste — et l'identifiant est validé\n * avant d'entrer dans un chemin.\n */\n app.get('/api/cloud/avatar/:userId', async (req, res) => {\n const userId = req.params.userId;\n // Un identifiant vient du cloud et finit dans une URL : on le vérifie plutôt\n // que de l'assainir, un identifiant tordu désignerait quelqu'un d'autre.\n if (!/^[A-Za-z0-9._-]{1,128}$/.test(userId)) {\n res.status(400).end();\n return;\n }\n // Quel cloud : celui de l'organisation affichée, sinon celui du compte\n // nommé, sinon celui de ce poste. Les identifiants d'utilisateur de deux\n // clouds ne partagent aucun espace de noms.\n const orgId = typeof req.query['organizationId'] === 'string' ? req.query['organizationId'] : '';\n const accountId = typeof req.query['accountId'] === 'string' ? req.query['accountId'] : '';\n try {\n const base = orgId\n ? await orgCloudUrl(orgId)\n : ((await cloudSessionStore.getCloudUrl(accountId || undefined)) ?? getCloudApiUrl());\n const upstream = await fetch(`${base}/api/avatar/${encodeURIComponent(userId)}`, {\n headers: { [APP_VERSION_HEADER]: appVersion },\n signal: AbortSignal.timeout(15_000),\n });\n if (!upstream.ok) {\n res.status(upstream.status).end();\n return;\n }\n res.set('Content-Type', upstream.headers.get('content-type') ?? 'application/octet-stream');\n // Mêmes en-têtes de durcissement que la route amont : ces octets ne\n // doivent jamais être traités comme autre chose qu'une image inerte.\n res.set('X-Content-Type-Options', 'nosniff');\n res.set('Content-Security-Policy', \"default-src 'none'; sandbox\");\n res.set('Cache-Control', 'public, max-age=300');\n // nosemgrep: direct-response-write -- octets d'avatar, en-têtes de durcissement conservés\n res.send(Buffer.from(await upstream.arrayBuffer()));\n } catch {\n res.status(502).end();\n }\n });\n\n proxyCloudStream('/api/cloud/chat/stream', '/api/chat/stream');\n proxyCloudStream('/api/cloud/kanban/stream', '/api/kanban/stream');\n\n // POST /api/unlock — public, rate limited + CSRF\n app.post('/api/unlock', authLimiter, csrfMiddleware, express.json({ limit: '10kb' }), async (req, res) => {\n try {\n const body = req.body as { masterPassword?: unknown };\n const masterPassword = body.masterPassword;\n if (typeof masterPassword !== 'string' || masterPassword.length < 1 || masterPassword.length > 1024) {\n res.status(400).json({ error: 'masterPassword invalide' });\n return;\n }\n const encKey = await readEncryptedKey(await keyRoot(), masterPassword);\n setEncryptionKeyInMemory(encKey);\n await runPostUnlock(masterPassword);\n const token = await signJwt();\n res.json({ token });\n } catch (err) {\n console.error('[server] Unlock error:', err);\n res.status(401).json({ error: 'Master password incorrect' });\n }\n });\n\n // POST /api/setup — public, rate limited + CSRF\n app.post('/api/setup', authLimiter, csrfMiddleware, express.json({ limit: '10kb' }), async (req, res) => {\n try {\n const { state, hasVerifyFile: hasVerify, isLegacyMigration } = await getServerState();\n\n // Reject if already unlocked\n if (state === 'unlocked') {\n res.status(409).json({ error: 'Serveur déjà déverrouillé' });\n return;\n }\n\n const body = req.body as { masterPassword?: unknown; encryptionKey?: unknown };\n const masterPassword = body.masterPassword;\n if (typeof masterPassword !== 'string' || masterPassword.length < 1 || masterPassword.length > 1024) {\n res.status(400).json({ error: 'masterPassword invalide' });\n return;\n }\n\n let encKey: Buffer;\n\n if (isLegacyMigration) {\n // Read pending legacy key from in-memory holder\n const legacyKey = getPendingLegacyKey();\n if (!legacyKey) {\n res.status(500).json({ error: 'Clé legacy introuvable — redémarrez le serveur' });\n return;\n }\n encKey = legacyKey;\n } else if (hasVerify) {\n // New member: encryptionKey required\n const encryptionKeyHex = body.encryptionKey;\n if (typeof encryptionKeyHex !== 'string' || !/^[0-9a-f]{64}$/i.test(encryptionKeyHex)) {\n res.status(400).json({ error: 'encryptionKey invalide (attendu 64 hex)' });\n return;\n }\n encKey = Buffer.from(encryptionKeyHex, 'hex');\n // Verify against canary\n await verifyEncryptionKey(await keyRoot(), encKey);\n } else {\n // Fresh setup: generate new key or use provided key\n if (body.encryptionKey !== undefined) {\n const encryptionKeyHex = body.encryptionKey;\n if (typeof encryptionKeyHex !== 'string' || !/^[0-9a-f]{64}$/i.test(encryptionKeyHex)) {\n res.status(400).json({ error: 'encryptionKey invalide (attendu 64 hex)' });\n return;\n }\n encKey = Buffer.from(encryptionKeyHex, 'hex');\n } else {\n const { randomBytes } = await import('node:crypto');\n encKey = randomBytes(32);\n }\n }\n\n // Write .encryption.key.enc\n await writeEncryptedKey(await keyRoot(), masterPassword, encKey);\n\n // Verify round-trip (critical for legacy migration)\n const readBack = await readEncryptedKey(await keyRoot(), masterPassword);\n if (!readBack.equals(encKey)) {\n res.status(500).json({ error: 'Erreur de vérification round-trip — opération annulée' });\n return;\n }\n\n // Write .runeya-verify if not exists\n if (!hasVerify) {\n await writeVerifyFile(await keyRoot(), encKey);\n }\n\n setEncryptionKeyInMemory(encKey);\n if (isLegacyMigration) {\n clearPendingLegacyKey();\n }\n await runPostUnlock(masterPassword);\n const token = await signJwt();\n res.json({ token });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Erreur interne';\n if (message.includes('incorrecte')) {\n res.status(400).json({ error: message });\n } else {\n console.error('[server] Setup error:', err);\n res.status(500).json({ error: 'Erreur interne' });\n }\n }\n });\n\n /**\n * POST /api/migrate-vault — convert this directory's leftover vault.\n *\n * Authenticated: the caller must already hold the machine key, since that is\n * what the vault is being converted TO. Rate limited like the other\n * password-taking routes — it accepts the old master password, so it is an\n * oracle just as much as unlock is.\n */\n app.post('/api/migrate-vault', authLimiter, csrfMiddleware, express.json({ limit: '10kb' }), async (req, res) => {\n try {\n const jwt = typeof req.headers.authorization === 'string' && req.headers.authorization.startsWith('Bearer ')\n ? req.headers.authorization.slice(7)\n : '';\n if (!isCiMode()) {\n try {\n await verifyJwt(jwt);\n } catch {\n res.status(401).json({ error: 'Session invalide' });\n return;\n }\n }\n\n const machineKey = getEncryptionKey();\n if (!machineKey) {\n res.status(409).json({ error: 'Serveur verrouillé' });\n return;\n }\n\n const legacyRoot = await legacyVaultRoot();\n if (!legacyRoot) {\n res.status(409).json({ error: 'Aucun coffre à migrer dans ce répertoire' });\n return;\n }\n\n const body = req.body as { masterPassword?: unknown };\n const masterPassword = body.masterPassword;\n if (typeof masterPassword !== 'string' || masterPassword.length < 1 || masterPassword.length > 1024) {\n res.status(400).json({ error: 'masterPassword invalide' });\n return;\n }\n\n let legacyKey: Buffer;\n try {\n legacyKey = await openLegacyVault(legacyRoot, masterPassword);\n } catch {\n res.status(401).json({ error: 'Ancien master password incorrect' });\n return;\n }\n\n const report = await migrateLegacyVault(legacyRoot, machineRoot(), legacyKey, machineKey, new Date());\n console.log(`[vault-migration] ${legacyRoot} migré — sauvegarde : ${report.backupDir}`);\n res.json(report);\n } catch (err) {\n console.error('[server] Vault migration error:', err);\n res.status(500).json({ error: err instanceof Error ? err.message : 'Erreur interne' });\n }\n });\n\n // GET /:apikey/llms.txt — LLM API keys scopées\n app.get('/:apikey/llms.txt', llmsLimiter, async (req, res) => {\n const apikey = Array.isArray(req.params['apikey']) ? req.params['apikey'][0] : req.params['apikey'];\n // Validate format first — always 401 to avoid oracle\n if (!apikey || !/^[0-9a-f]{64}$/i.test(apikey)) {\n res.status(401).send('Unauthorized');\n return;\n }\n try {\n const key = await apiKeyStore.validateKey(apikey);\n if (!key) {\n res.status(401).send('Unauthorized');\n return;\n }\n if (!hasEncryptionKey()) {\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\n res.setHeader('Cache-Control', 'no-store');\n const uiUrl = process.env.NODE_ENV === 'development' ? 'http://localhost:5173' : `http://localhost:${env.PORT}`;\n res.status(503).send(`# Runeya — Service Management API\\n\\n> Server is locked. Unlock with your master password at ${uiUrl} to access the full service list.\\n`);\n return;\n }\n const allServices = await serviceStore.list();\n const services = allServices.filter(s =>\n key.scopes.services.some(p => p.serviceId === s.id),\n );\n\n const content = generateLlmsTxt(key, services);\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\n res.setHeader('Cache-Control', 'no-store');\n res.send(content);\n } catch (err) {\n console.error('[server] llms.txt error:', err);\n res.status(500).send('Internal server error');\n }\n });\n\n // GET /api/docs — Scalar API reference UI (standalone HTML, no auth required)\n app.get('/api/docs', (req, res) => {\n const dark = req.query['dark'] === '1';\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n res.setHeader('Cache-Control', 'no-store');\n res.send(`<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>Runeya API Docs</title>\n <meta name=\"description\" content=\"Runeya service management API reference\" />\n <style>\n body { margin: 0; }\n </style>\n</head>\n<body>\n <script src=\"https://cdn.jsdelivr.net/npm/@scalar/api-reference\"></script>\n <script>\n Scalar.createApiReference(document.body, {\n url: '/api/openapi.json',\n darkMode: ${dark},\n layout: 'modern',\n defaultHttpClient: { targetKey: 'shell', clientKey: 'curl' },\n defaultOpenAllTags: false,\n persistAuth: true,\n agent: { disabled: true },\n metaData: {\n title: 'Runeya API Docs',\n description: 'Runeya service management API reference',\n ogTitle: 'Runeya API Docs',\n ogDescription: 'Runeya service management API reference',\n },\n });\n </script>\n</body>\n</html>`);\n });\n\n // GET /api/openapi.json — OpenAPI specification (public, no auth required)\n app.get('/api/openapi.json', (_req, res) => {\n try {\n res.json(getOpenApiDocument());\n } catch (err) {\n console.error('[server] openapi.json error:', err instanceof Error ? err.stack : err);\n res.status(500).json({ error: 'Failed to generate OpenAPI document', detail: err instanceof Error ? err.message : String(err) });\n }\n });\n\n // ── Image upload & serve endpoints ──────────────────────────────────────\n const memStorage = multer.memoryStorage();\n const upload = multer({\n storage: memStorage,\n limits: { fileSize: MAX_IMAGE_SIZE_BYTES },\n fileFilter: (_req, file, cb) => {\n if (ALLOWED_MIME_TYPES.has(file.mimetype)) {\n cb(null, true);\n } else {\n cb(new Error(`Unsupported MIME type: ${file.mimetype}`));\n }\n },\n });\n\n const CONV_ID_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/;\n const IMAGE_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n // Les erreurs de multer (MIME refusé par fileFilter, dépassement de taille)\n // sont des erreurs client : sans ce wrapper elles remontent au gestionnaire\n // d'erreurs global, qui répond 500 « Internal server error ».\n const uploadSingleImage = (req: express.Request, res: express.Response, next: express.NextFunction) => {\n upload.single('image')(req, res, (err: unknown) => {\n if (err) {\n const isTooLarge = (err as { code?: string }).code === 'LIMIT_FILE_SIZE';\n const message = err instanceof Error ? err.message : 'Upload failed';\n res.status(isTooLarge ? 413 : 400).json({ error: message });\n return;\n }\n next();\n });\n };\n\n app.post('/api/images/upload', uploadSingleImage, async (req, res) => {\n try {\n if (!req.file) {\n res.status(400).json({ error: 'No image file provided' });\n return;\n }\n const conversationId = (req.query?.['conversationId'] ?? req.body?.conversationId) as string | undefined;\n if (!conversationId || !CONV_ID_RE.test(conversationId)) {\n res.status(400).json({ error: 'Missing or invalid conversationId' });\n return;\n }\n const stored = await imageStorageService.saveImage(\n req.file.buffer,\n req.file.originalname,\n req.file.mimetype,\n conversationId,\n );\n res.json({\n imageId: stored.imageId,\n url: `/api/images/${conversationId}/${stored.imageId}`,\n mimeType: stored.mimeType,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Upload failed';\n res.status(400).json({ error: message });\n }\n });\n\n app.get('/api/images/:conversationId/:imageId', async (req, res) => {\n try {\n const { conversationId, imageId } = req.params as { conversationId: string; imageId: string };\n if (!conversationId || !CONV_ID_RE.test(conversationId)) {\n res.status(400).json({ error: 'Invalid conversationId' });\n return;\n }\n if (!imageId || !IMAGE_ID_RE.test(imageId)) {\n res.status(400).json({ error: 'Invalid imageId' });\n return;\n }\n // Le conversationId de l'URL doit correspondre au contexte enregistré :\n // sans ça le scoping par conversation n'est que décoratif.\n const result = await imageStorageService.getImagePath(imageId, conversationId);\n if (!result) {\n res.status(404).json({ error: 'Image not found' });\n return;\n }\n res.setHeader('Content-Type', result.mimeType);\n res.setHeader('Cache-Control', 'no-store');\n createReadStream(result.filePath).pipe(res);\n } catch (err) {\n console.error('[server] image serve error:', err);\n res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n // tRPC HTTP handler\n app.use('/api/trpc', createExpressMiddleware({\n router: appRouter,\n createContext,\n }));\n\n // Global error handler\n app.use(errorHandler);\n\n const server = createServer(app);\n registerHttpServer(server);\n\n // tRPC WebSocket handler — noServer mode so we control the upgrade\n const wss = new WebSocketServer({ noServer: true });\n applyWSSHandler({\n wss,\n router: appRouter,\n createContext: ({ req }) => {\n const headerAuth = req.headers.authorization ?? null;\n // Browser WebSocket can't set headers — also accept token from query param\n const urlObj = new URL(req.url ?? '/', `http://localhost:${env.PORT}`);\n const queryToken = urlObj.searchParams.get('token');\n const queryAuth = queryToken ? `Bearer ${queryToken}` : null;\n return { authorization: headerAuth ?? queryAuth };\n },\n });\n\n // Registry of active WS connections (stores only exp + iat, never the JWT)\n interface WsConnMeta { exp: number; iat: number; }\n const wsConnRegistry = new Map<WebSocket, WsConnMeta>();\n\n // Intercept HTTP→WS upgrade: validate JWT BEFORE handleUpgrade (spec Point 3)\n // Mirror protectedProcedure: skip JWT check when encryption key is in memory\n // (covers both CI mode and normal mode after master-password unlock).\n server.on('upgrade', async (req, socket, head) => {\n // Daté à l'arrivée : c'est ce qui distingue « le navigateur n'a pas encore\n // demandé » de « on a refusé ». Un rejet ne laissait aucune trace, et une\n // demande qui n'arrive jamais encore moins.\n // Une par onglet : bruyante en usage normal, précieuse quand on cherche\n // pourquoi un WebSocket tarde. RUNEYA_DEBUG=1 la rallume.\n if (process.env['RUNEYA_DEBUG']) console.log('[ws-upgrade] demande reçue');\n const auth = req.headers['authorization'] as string | undefined;\n const headerToken = auth?.startsWith('Bearer ') ? auth.slice(7) : null;\n // Browser WebSocket API can't set headers — accept token from query param as fallback\n const urlObj = new URL(req.url ?? '/', `http://localhost:${env.PORT}`);\n const queryToken = urlObj.searchParams.get('token');\n const token = headerToken ?? queryToken;\n\n if (!hasEncryptionKey()) {\n // Encryption key not in memory — require JWT (not yet unlocked)\n if (!token) {\n console.warn('[ws-upgrade] refusée : serveur verrouillé et aucun jeton fourni');\n socket.write('HTTP/1.1 401 Unauthorized\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n try {\n await verifyJwt(token);\n } catch {\n console.warn('[ws-upgrade] refusée : jeton invalide ou expiré');\n socket.write('HTTP/1.1 401 Unauthorized\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n }\n\n wss.handleUpgrade(req, socket, head, (ws) => {\n if (process.env['RUNEYA_DEBUG']) console.log('[ws-upgrade] acceptée — WebSocket établi');\n wss.emit('connection', ws, req);\n });\n });\n\n // Register connection — JWT already verified at upgrade, safe to use verifyJwt for exp/iat\n wss.on('connection', (ws, req) => {\n const auth = req.headers['authorization'] as string | undefined;\n const headerToken = auth?.startsWith('Bearer ') ? auth.slice(7) : null;\n const urlObj2 = new URL(req.url ?? '/', `http://localhost:${env.PORT}`);\n const token = headerToken ?? urlObj2.searchParams.get('token');\n if (token) {\n verifyJwt(token).then(({ exp, iat }) => {\n wsConnRegistry.set(ws, { exp, iat });\n }).catch(() => {});\n }\n ws.on('close', () => wsConnRegistry.delete(ws));\n });\n\n // Tick every 30s — close expired connections\n const wsTickInterval = setInterval(() => {\n const now = Math.floor(Date.now() / 1000);\n const secretGeneratedAt = getJwtSecretGeneratedAt();\n for (const [ws, meta] of wsConnRegistry) {\n if (meta.exp <= now || meta.iat < secretGeneratedAt) {\n ws.close(4401, 'JWT expired or signing secret rotated');\n wsConnRegistry.delete(ws);\n }\n }\n }, 30_000);\n\n const shutdown = async () => {\n console.log('[server] Shutting down...');\n clearInterval(wsTickInterval);\n stopClaudeTranscriptWatcher();\n stopCodexTranscriptWatcher();\n imageCleanupService.stop();\n void cloudSyncBridge.stopAll();\n // Kill agent immediately (SIGKILL, stateless) and close WS bridges in parallel\n await Promise.all([\n unregisterInstance(),\n agentSpawner.shutdown(),\n agentManager.shutdown(),\n ]);\n // Force-close all active connections so the port is released instantly\n server.closeAllConnections();\n await Promise.race([\n new Promise<void>((resolve) => wss.close(() => resolve())),\n new Promise<void>((resolve) => setTimeout(resolve, 2_000)),\n ]);\n await Promise.race([\n new Promise<void>((resolve) => server.close(() => resolve())),\n new Promise<void>((resolve) => setTimeout(resolve, 2_000)),\n ]);\n console.log('[server] Shutdown complete');\n };\n\n // Le compagnon écoute les fins de tour.\n //\n // Ici, et pas dans le `main()` de ce paquet : celui-ci ne s'exécute que si\n // `index.ts` est lancé directement. Le CLI publié, lui, importe\n // `createLocalServer` et l'appelle — le compagnon n'aurait jamais été branché\n // pour un utilisateur installé, alors qu'il l'était en développement.\n const { initCompanion } = await import('./services/companion.js');\n initCompanion();\n\n return { app, server, wss, shutdown };\n}\n","import os from 'node:os';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { z } from 'zod';\nimport { appVersion } from '../../config/app-version.js';\nimport { router, publicProcedure, protectedProcedure } from '../trpc.js';\n\nconst execFileAsync = promisify(execFile);\n\n/** Récupère la version de Docker si le binaire est présent, sinon null. */\nasync function getDockerVersion(): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync('docker', ['--version'], {\n timeout: 3000,\n windowsHide: true,\n });\n // Format typique : \"Docker version 27.3.1, build ce12230\"\n const match = /Docker version\\s+([^,\\s]+)/i.exec(stdout);\n return match?.[1] ?? (stdout.trim() || null);\n } catch {\n return null;\n }\n}\n\nconst startedAt = Date.now();\n\nconst NPM_LATEST_URL = 'https://registry.npmjs.org/@runeya%2Fruneya/latest';\n\n/** Compare deux versions semver simples. Renvoie 1 si a>b, -1 si a<b, 0 si égales. */\nfunction compareSemver(a: string, b: string): number {\n const pa = a.split('.').map((n) => Number.parseInt(n, 10) || 0);\n const pb = b.split('.').map((n) => Number.parseInt(n, 10) || 0);\n for (let i = 0; i < 3; i++) {\n const da = pa[i] ?? 0;\n const db = pb[i] ?? 0;\n if (da > db) return 1;\n if (da < db) return -1;\n }\n return 0;\n}\n\n/**\n * Le client revérifie périodiquement et au retour au premier plan : sans ce\n * cache, chaque fenêtre rouverte irait interroger le registre npm. Volontairement\n * plus court que l'intervalle du client (5 min) : à durée égale, un tic arrivant\n * une fraction de seconde trop tôt se ferait servir l'entrée précédente et le\n * délai réel doublerait.\n */\nconst VERSION_CACHE_MS = 4 * 60 * 1000;\nlet versionCache: { at: number; latest: string | null } | null = null;\n\n/**\n * Plancher entre deux vérifications forcées.\n *\n * Le cache ci-dessus existe pour les vérifications automatiques ; un clic sur\n * « Revérifier » le court-circuite, sinon le bouton mentirait pendant quatre\n * minutes après une publication. Ce plancher-là ne protège pas le confort mais\n * le registre : la route est publique, et sans lui une boucle de clics — ou un\n * client qui redemande en rafale — irait taper npm à chaque appel.\n */\nconst FORCED_CHECK_FLOOR_MS = 2_000;\nlet lastForcedAt = 0;\n\n/**\n * Version publiée la plus récente, ou null si le registre est injoignable.\n *\n * `force` ignore le cache ET le remplace : la réponse fraîche est donc aussi\n * celle que verront les autres écrans à leur prochaine question — c'est ce qui\n * fait apparaître le bandeau de mise à jour dans la foulée du clic.\n */\nasync function fetchLatestVersion(force = false): Promise<string | null> {\n const now = Date.now();\n const forcing = force && now - lastForcedAt >= FORCED_CHECK_FLOOR_MS;\n if (forcing) lastForcedAt = now;\n if (!forcing && versionCache && now - versionCache.at < VERSION_CACHE_MS) {\n return versionCache.latest;\n }\n let latest: string | null = null;\n try {\n const res = await fetch(NPM_LATEST_URL, {\n headers: { accept: 'application/json' },\n signal: AbortSignal.timeout(5000),\n });\n if (res.ok) {\n const parsed = z.object({ version: z.string().max(64) }).safeParse(await res.json());\n if (parsed.success) latest = parsed.data.version;\n }\n } catch {\n latest = null;\n }\n versionCache = { at: Date.now(), latest };\n return latest;\n}\n\nexport const healthRouter = router({\n check: publicProcedure\n .meta({ openapi: { method: 'GET', path: '/health', tags: ['health'], summary: 'Health check' } })\n .output(z.object({ status: z.literal('ok'), uptime: z.number(), version: z.string() }))\n .query(() => {\n return {\n status: 'ok' as const,\n uptime: Date.now() - startedAt,\n version: appVersion,\n };\n }),\n versionInfo: publicProcedure\n // `force` : le bouton « Revérifier » des réglages, qui n'a de sens que s'il\n // interroge vraiment le registre.\n .input(z.object({ force: z.boolean().optional() }).optional())\n .output(\n z.object({\n current: z.string(),\n latest: z.string().nullable(),\n status: z.enum(['up-to-date', 'outdated', 'ahead', 'dev', 'unknown']),\n }),\n )\n .query(async ({ input }) => {\n // En mode dev, pas de version publiée à comparer.\n if (appVersion === 'dev') {\n return { current: appVersion, latest: null, status: 'dev' as const };\n }\n\n const latest = await fetchLatestVersion(input?.force ?? false);\n if (latest === null) {\n return { current: appVersion, latest: null, status: 'unknown' as const };\n }\n const cmp = compareSemver(appVersion, latest);\n const status = cmp === 0 ? 'up-to-date' : cmp < 0 ? 'outdated' : 'ahead';\n return { current: appVersion, latest, status };\n }),\n systemInfo: protectedProcedure\n .output(\n z.object({\n version: z.string(),\n nodeVersion: z.string(),\n platform: z.string(),\n arch: z.string(),\n osType: z.string(),\n osRelease: z.string(),\n hostname: z.string(),\n cpuModel: z.string(),\n cpuCount: z.number(),\n totalMemoryBytes: z.number(),\n freeMemoryBytes: z.number(),\n serverUptimeMs: z.number(),\n osUptimeSec: z.number(),\n dockerVersion: z.string().nullable(),\n }),\n )\n .query(async () => {\n const cpus = os.cpus();\n const dockerVersion = await getDockerVersion();\n return {\n version: appVersion,\n nodeVersion: process.version,\n platform: process.platform,\n arch: process.arch,\n osType: os.type(),\n osRelease: os.release(),\n hostname: os.hostname(),\n cpuModel: cpus[0]?.model.trim() ?? 'unknown',\n cpuCount: cpus.length,\n totalMemoryBytes: os.totalmem(),\n freeMemoryBytes: os.freemem(),\n serverUptimeMs: Date.now() - startedAt,\n osUptimeSec: os.uptime(),\n dockerVersion,\n };\n }),\n});\n","import { spawn, execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { router, publicProcedure, requireLoopbackOrToken } from '../trpc.js';\nimport { env } from '../../config/env.js';\nimport { appVersion } from '../../config/app-version.js';\n\nconst execFileAsync = promisify(execFile);\n\n/** Le paquet publié, seul nom que cette route accepte d'installer. */\nconst PACKAGE_NAME = '@runeya/runeya';\n\n/** `npm install -g` télécharge, compile parfois, et n'est pas pressé. */\nconst INSTALL_TIMEOUT_MS = 10 * 60_000;\n\n/**\n * Mettre à jour Runeya depuis Runeya, pour les installations de bureau.\n *\n * Lancé depuis un terminal, on met à jour comme on a installé : un `npm i -g`\n * dans le terminal qu'on a déjà sous la main. Lancé depuis un raccourci, il n'y\n * a pas de terminal — et la version qui tourne peut vieillir indéfiniment sans\n * que rien ne le dise. D'où ces routes, réservées à ce cas.\n *\n * Elles répondent SANS jeton à la boucle locale : le bandeau s'affiche aussi\n * avant l'entrée dans l'application (déverrouillage, migration de coffre), là\n * où aucun jeton n'existe encore et où rester bloqué sur une version trop\n * ancienne est justement le cas à traiter.\n *\n * Elles répondent aussi à un appelant muni du jeton d'application, d'où qu'il\n * vienne. Sans quoi une Runeya pilotée depuis une tablette — tout l'objet du\n * mode LAN — ne pouvait plus se mettre à jour du tout : la seule machine\n * autorisée était celle devant laquelle personne n'était assis. Le jeton dit ce\n * que la boucle locale disait, et il le dit à distance.\n */\n\n/**\n * Comment lancer `npm` sans passer par un shell.\n *\n * Une session graphique n'a pas le `PATH` d'un shell de connexion : les\n * gestionnaires de version (n, nvm, fnm, volta) n'y figurent pas, et `npm` est\n * introuvable alors même qu'il est installé, juste à côté du `node` qui exécute\n * ce code.\n *\n * D'où le script JS de npm, lancé par le `node` courant : c'est la seule forme\n * qui marche partout **sans shell**. Sur Windows, `npm` n'est qu'un `npm.cmd`,\n * et depuis le correctif de CVE-2024-27980 Node refuse de lancer un `.cmd` sans\n * `shell: true` — le nommer en entier ne suffit donc plus. C'est ce qui faisait\n * répondre « npm est introuvable » sur une machine où npm est parfaitement\n * installé, à côté du node qui tourne.\n */\ntype NpmCommand = { command: string; args: string[]; shell: boolean };\n\nfunction resolveNpm(): NpmCommand {\n const nodeDir = dirname(process.execPath);\n const candidates = [\n // Windows (installateur officiel, nvm-windows, volta) : npm est un dossier\n // frère de node.exe.\n join(nodeDir, 'node_modules', 'npm', 'bin', 'npm-cli.js'),\n // Unix : node est dans `bin/`, npm sous `lib/node_modules/`.\n join(nodeDir, '..', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'),\n ];\n for (const cli of candidates) {\n if (existsSync(cli)) return { command: process.execPath, args: [cli], shell: false };\n }\n // Repli sur le PATH. Sur Windows il n'y a que le `.cmd`, qui exige un shell —\n // les arguments sont tous des constantes de ce fichier, rien de ce que\n // l'appelant envoie n'y entre.\n return process.platform === 'win32'\n ? { command: 'npm.cmd', args: [], shell: true }\n : { command: 'npm', args: [], shell: false };\n}\n\n/** Ce qu'on affiche pour dire quel npm a été retenu. */\nfunction npmLabel(npm: NpmCommand): string {\n return [npm.command, ...npm.args].join(' ');\n}\n\n/** Version d'un exécutable, ou `null` s'il ne répond pas. */\nasync function probeVersion(npm: NpmCommand, args: string[]): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(npm.command, [...npm.args, ...args], {\n timeout: 10_000,\n windowsHide: true,\n shell: npm.shell,\n });\n return stdout.trim().split('\\n')[0]?.trim() || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Refuse tout ce qui ne vient pas d'un lancement par raccourci.\n *\n * Ces routes installent du code et redémarrent le process : les ouvrir à une\n * instance lancée en terminal n'apporterait rien — l'utilisateur y a déjà son\n * shell — et élargirait la surface d'attaque pour rien.\n */\nfunction requireDesktop(): void {\n if (!env.FROM_DESKTOP) {\n throw new TRPCError({\n code: 'PRECONDITION_FAILED',\n message: 'Update from the app is only available for desktop launches.',\n });\n }\n}\n\nexport const appUpdateRouter = router({\n /** De quoi la mise à jour a besoin, et ce que la machine en offre. */\n prerequisites: publicProcedure\n .output(\n z.object({\n fromDesktop: z.boolean(),\n nodeVersion: z.string(),\n npmVersion: z.string().nullable(),\n npmPath: z.string(),\n globalPrefix: z.string().nullable(),\n ready: z.boolean(),\n }),\n )\n .query(async ({ ctx }) => {\n await requireLoopbackOrToken(ctx);\n const npm = resolveNpm();\n const npmVersion = await probeVersion(npm, ['--version']);\n // Le préfixe dit OÙ l'installation atterrira : utile à afficher quand\n // Runeya a été installé par un autre gestionnaire, où la mise à jour\n // réussirait sans jamais remplacer la version qui tourne.\n const globalPrefix = npmVersion ? await probeVersion(npm, ['prefix', '-g']) : null;\n\n return {\n fromDesktop: env.FROM_DESKTOP,\n nodeVersion: process.version,\n npmVersion,\n npmPath: npmLabel(npm),\n globalPrefix,\n ready: env.FROM_DESKTOP && npmVersion !== null,\n };\n }),\n\n /**\n * Installe la dernière version publiée, globalement.\n *\n * La sortie complète est renvoyée telle quelle, succès comme échec : quand\n * `npm` refuse (droits sur le préfixe, réseau, registre privé), son message\n * est la seule chose qui dit à l'utilisateur quoi faire.\n */\n install: publicProcedure\n .output(\n z.object({\n ok: z.boolean(),\n output: z.string(),\n installedVersion: z.string().nullable(),\n }),\n )\n .mutation(async ({ ctx }) => {\n await requireLoopbackOrToken(ctx);\n requireDesktop();\n\n const npm = resolveNpm();\n try {\n const { stdout, stderr } = await execFileAsync(\n npm.command,\n [...npm.args, 'install', '-g', `${PACKAGE_NAME}@latest`],\n { timeout: INSTALL_TIMEOUT_MS, windowsHide: true, shell: npm.shell, maxBuffer: 10 * 1024 * 1024 },\n );\n const installedVersion = await probeVersion(npm, ['view', `${PACKAGE_NAME}`, 'version']);\n return { ok: true, output: [stdout, stderr].filter(Boolean).join('\\n').trim(), installedVersion };\n } catch (err) {\n const e = err as { stdout?: string; stderr?: string; message: string };\n const output = [e.stdout, e.stderr, e.message].filter(Boolean).join('\\n').trim();\n return { ok: false, output, installedVersion: null };\n }\n }),\n\n /**\n * Relance Runeya, puis rend la main au nouveau process.\n *\n * Le remplaçant est détaché et démarre avec les mêmes arguments : il rouvre\n * donc la fenêtre lui-même. Le port est encore tenu par l'ancien pendant\n * quelques instants — le démarrage réessaie déjà sur EADDRINUSE, c'est ce qui\n * rend ce relais possible sans temporisation ici.\n */\n restart: publicProcedure\n .output(z.object({ restarting: z.literal(true), version: z.string() }))\n .mutation(async ({ ctx }) => {\n await requireLoopbackOrToken(ctx);\n requireDesktop();\n\n const child = spawn(process.execPath, process.argv.slice(1), {\n detached: true,\n stdio: 'ignore',\n // `detached` demande une console neuve à Windows, et une console neuve\n // est une fenêtre de commande à l'écran : le lanceur de bureau cache la\n // sienne, la mise à jour n'a pas à en rouvrir une.\n windowsHide: true,\n cwd: process.cwd(),\n // Le relais s'annonce comme tel : sans cela le CLI, relancé avec\n // `--from-desktop`, sonde le port, y trouve l'ancien process encore\n // vivant pendant sa demi-seconde de sursis, en conclut qu'une Runeya\n // tourne déjà et se contente de rouvrir la fenêtre. L'ancien mourait\n // juste après, et « Redémarrer » ne redémarrait rien.\n env: { ...process.env, RUNEYA_RESTART_HANDOFF: '1' },\n });\n child.unref();\n\n // Laisse la réponse partir avant de couper : sans ce délai, le client voit\n // une socket fermée et non un redémarrage.\n setTimeout(() => process.exit(0), 500);\n\n return { restarting: true as const, version: appVersion };\n }),\n});\n","import { z } from 'zod';\nimport {\n ChangelogIndexItemSchema,\n ChangelogReleaseSchema,\n ChangelogSurfaceSchema,\n} from '@runeya/packages-shared';\nimport { router, publicProcedure } from '../trpc.js';\nimport { appVersion } from '../../config/app-version.js';\nimport { getCloudApiUrl } from '../../services/cloud-api.js';\n\n/**\n * Le journal des nouveautés, relayé depuis le cloud.\n *\n * Relayé, et non appelé directement par l'interface : le cloud n'autorise en\n * CORS que ses propres origines, et une Runeya locale n'en est pas une — elle\n * répond sur un port choisi au lancement, et sur une IP de LAN dès que le mode\n * réseau est actif. Le relais évite aussi de dépendre d'une session cloud :\n * le journal est public, une machine jamais reliée doit le lire.\n *\n * Les routes sont publiques pour la même raison que le bandeau de mise à jour :\n * elles servent aussi avant l'entrée dans l'application (déverrouillage,\n * migration de coffre), là où aucun jeton n'existe encore.\n */\n\n/** Le registre bouge à l'échelle du déploiement ; cinq minutes suffisent, et bornent les allers-retours. */\nconst CACHE_MS = 5 * 60 * 1000;\nconst cache = new Map<string, { at: number; value: unknown }>();\n\nasync function cloudChangelog(path: string, params: Record<string, string | null>): Promise<unknown> {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) if (value) search.set(key, value);\n const url = `${getCloudApiUrl()}${path}?${search.toString()}`;\n\n const hit = cache.get(url);\n if (hit && Date.now() - hit.at < CACHE_MS) return hit.value;\n\n const res = await fetch(url, {\n headers: { accept: 'application/json' },\n signal: AbortSignal.timeout(8000),\n });\n if (!res.ok) throw new Error(`changelog: HTTP ${res.status}`);\n const value: unknown = await res.json();\n cache.set(url, { at: Date.now(), value });\n return value;\n}\n\n/**\n * La version qui borne ce que l'app peut annoncer.\n *\n * En développement il n'y a pas de version publiée : rien n'est borné, sinon un\n * poste de développement ne verrait jamais l'entrée qu'il vient d'écrire.\n */\nfunction appCeiling(): string | null {\n return appVersion === 'dev' ? null : appVersion;\n}\n\nconst inputSchema = z.object({\n surface: ChangelogSurfaceSchema,\n /** Dernière version déjà vue par ce navigateur, exclue du résultat. */\n since: z.string().max(32).nullish(),\n});\n\nexport const changelogRouter = router({\n /** Ce qu'il y a à lire, sans les corps. */\n index: publicProcedure\n .input(inputSchema)\n .output(z.object({ releases: z.array(ChangelogIndexItemSchema), currentAppVersion: z.string() }))\n .query(async ({ input }) => {\n const data = await cloudChangelog('/api/changelog', {\n surface: input.surface,\n since: input.since ?? null,\n until: input.surface === 'app' ? appCeiling() : null,\n });\n const parsed = z.object({ releases: z.array(ChangelogIndexItemSchema) }).parse(data);\n return { releases: parsed.releases, currentAppVersion: appVersion };\n }),\n\n /** Les entrées complètes. */\n releases: publicProcedure\n .input(inputSchema)\n .output(z.object({ releases: z.array(ChangelogReleaseSchema), currentAppVersion: z.string() }))\n .query(async ({ input }) => {\n const data = await cloudChangelog('/api/changelog/releases', {\n surface: input.surface,\n since: input.since ?? null,\n until: input.surface === 'app' ? appCeiling() : null,\n });\n const parsed = z.object({ releases: z.array(ChangelogReleaseSchema) }).parse(data);\n return { releases: parsed.releases, currentAppVersion: appVersion };\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { router, protectedProcedure, getAllowedServiceIds } from '../trpc.js';\nimport { projectStore, LocalProjectExistsError } from '../../services/project-store.js';\nimport { setCurrentProject } from '../../services/current-project.js';\nimport { serviceStore } from '../../services/service-store.js';\nimport { environmentStore } from '../../services/environment-store.js';\nimport { environmentResolver } from '../../services/environment-resolver.js';\nimport { agentManager } from '../../services/agent-manager.js';\nimport { auditService } from '../../services/audit-service.js';\nimport { projectPathStore, holdsRuneyaProject } from '../../services/project-path-store.js';\nimport { assertOrgVaultReadable, OrgVaultUnreadableError } from '../../services/org-keys.js';\nimport { buildServiceGraph } from '../../services/service-graph.js';\n\n/**\n * Le dernier verrou avant de servir un projet d'organisation.\n *\n * `cloud-sync` garde l'ouverture initiale, mais un projet déjà matérialisé se\n * relit à chaque démarrage sans repasser par lui — et un poste qui a perdu la\n * clé de l'organisation, ou qui ne l'a jamais eue, le rouvrirait comme si de\n * rien n'était. La lecture y mène l'écriture : ce qui s'affiche se sauvegarde.\n */\nasync function assertReadable(orgId: string | null | undefined): Promise<void> {\n if (!orgId) return;\n try {\n await assertOrgVaultReadable(orgId);\n } catch (err) {\n if (err instanceof OrgVaultUnreadableError) {\n throw new TRPCError({ code: 'FORBIDDEN', message: err.message });\n }\n throw err;\n }\n}\n\nexport const projectRouter = router({\n list: protectedProcedure.query(async () => {\n return projectStore.list();\n }),\n\n /**\n * `orgId` names which project — the same id can exist in several\n * organizations. Left out, the id must answer for exactly one project.\n */\n get: protectedProcedure\n .input(z.object({ id: z.string().max(128), orgId: z.string().max(128).nullable().optional() }))\n .query(async ({ input }) => {\n const project = await projectStore.get(input);\n if (!project) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.id} not found` });\n }\n await assertReadable(project.orgId);\n return project;\n }),\n\n /**\n * Build a portable snapshot of a project for cloud storage: the project\n * record plus its services in sanitized (secret-free) on-disk form.\n * Environments are intentionally excluded — they carry secret values that\n * stay local.\n */\n export: protectedProcedure\n .input(z.object({ id: z.string().max(128), orgId: z.string().max(128).nullable().optional() }))\n .query(async ({ input }) => {\n const project = await projectStore.get(input);\n if (!project) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.id} not found` });\n }\n await assertReadable(project.orgId);\n const services = (\n await Promise.all(project.serviceIds.map((sid) => serviceStore.getSanitized(sid)))\n ).filter((s): s is NonNullable<typeof s> => s !== null);\n return { project, services };\n }),\n\n create: protectedProcedure\n .input(\n z.object({\n name: z.string().min(1).max(200),\n description: z.string().max(10000).optional(),\n orgId: z.string().max(128).nullable().optional(),\n serviceIds: z.array(z.string().max(128)).max(10000).optional(),\n }),\n )\n .mutation(async ({ input }) => {\n // Create the project first (with empty environmentIds, will be updated after creating local env)\n let project;\n try {\n project = await projectStore.create({\n ...input,\n description: input.description ?? '',\n serviceIds: input.serviceIds ?? [],\n environmentIds: [],\n });\n } catch (err) {\n // A directory holds a single local project. That is a conflict the user\n // can act on, not a server fault: surfaced as such, and carrying the\n // machine-readable code so the UI can say it in the user's language.\n if (err instanceof LocalProjectExistsError) {\n throw new TRPCError({ code: 'CONFLICT', message: err.code, cause: err });\n }\n throw new TRPCError({ code: 'CONFLICT', message: (err as Error).message });\n }\n\n // Create the default 'local' immutable environment for this project\n const localEnv = await environmentStore.create({\n projectId: project.id,\n name: 'local',\n description: 'Default local environment (immutable)',\n parentIds: [],\n immutable: true,\n }, project.orgId);\n\n // Update the project with the local environment\n const result = await projectStore.update({\n id: project.id,\n orgId: project.orgId,\n environmentIds: [localEnv.id],\n activeEnvironmentId: localEnv.id,\n });\n\n await auditService.log({ userId: 'local', action: 'create', entityType: 'project', entityId: project.id, metadata: { name: input.name } });\n return result!;\n }),\n\n update: protectedProcedure\n .input(\n z.object({\n id: z.string().max(128),\n name: z.string().min(1).max(200).optional(),\n description: z.string().max(10000).optional(),\n orgId: z.string().max(128).nullable().optional(),\n serviceIds: z.array(z.string().max(128)).max(10000).optional(),\n groupOrder: z.array(z.string().max(200)).max(100).optional(),\n }),\n )\n .mutation(async ({ input }) => {\n const project = await projectStore.update(input);\n if (!project) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.id} not found` });\n }\n await auditService.log({ userId: 'local', action: 'update', entityType: 'project', entityId: input.id });\n return project;\n }),\n\n delete: protectedProcedure\n .input(z.object({ id: z.string().max(128), orgId: z.string().max(128).nullable().optional() }))\n .mutation(async ({ input }) => {\n const deleted = await projectStore.delete(input);\n if (!deleted) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.id} not found` });\n }\n await auditService.log({ userId: 'local', action: 'delete', entityType: 'project', entityId: input.id });\n return { success: true as const };\n }),\n\n addService: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n serviceId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n const target = { id: input.projectId, orgId: input.orgId };\n const project = await projectStore.addService(target, input.serviceId);\n if (!project) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.projectId} not found` });\n }\n\n // Auto-create service-scoped environments for each global env in the project\n const service = await serviceStore.get(input.serviceId);\n if (service) {\n const globalEnvs = await environmentStore.listByScope(input.projectId, 'global', input.orgId);\n for (const globalEnv of globalEnvs) {\n const svcEnv = await environmentStore.create({\n projectId: input.projectId,\n name: `${service.name} (${globalEnv.name})`,\n scope: 'service',\n reference: input.serviceId,\n activateOn: globalEnv.id,\n parentIds: [globalEnv.id],\n variables: {},\n }, input.orgId);\n await projectStore.addEnvironment(target, svcEnv.id);\n }\n }\n\n await auditService.log({\n userId: 'local',\n action: 'update',\n entityType: 'project',\n entityId: input.projectId,\n metadata: { operation: 'addService', serviceId: input.serviceId },\n });\n return project;\n }),\n\n removeService: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n serviceId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n const project = await projectStore.removeService(\n { id: input.projectId, orgId: input.orgId }, input.serviceId,\n );\n if (!project) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.projectId} not found` });\n }\n await auditService.log({\n userId: 'local',\n action: 'update',\n entityType: 'project',\n entityId: input.projectId,\n metadata: { operation: 'removeService', serviceId: input.serviceId },\n });\n return project;\n }),\n\n setActiveEnvironment: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n environmentId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n const project = await projectStore.get({ id: input.projectId, orgId: input.orgId });\n if (!project) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.projectId} not found` });\n }\n\n // Validate environment exists\n const environment = await environmentStore.get(input.environmentId);\n if (!environment) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.environmentId} not found` });\n }\n if (environment.projectId !== input.projectId) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Environment does not belong to this project' });\n }\n\n // Collect running services before changing environment\n const runningServices: { serviceId: string; agentId: string }[] = [];\n\n for (const serviceId of project.serviceIds) {\n const service = await serviceStore.get(serviceId);\n if (!service || !service.agentId) continue;\n\n const agentStatus = agentManager.getStatus(service.agentId);\n if (!agentStatus?.connected) continue;\n\n try {\n const processStatus = await agentManager.agentQuery<{ status: string }>(\n service.agentId,\n 'process.get',\n { id: serviceId }\n );\n\n if (processStatus?.status === 'running' || processStatus?.status === 'starting') {\n runningServices.push({ serviceId, agentId: service.agentId });\n }\n } catch {\n // Agent unreachable or process not deployed — skip\n }\n }\n\n // Update environment\n const updated = await projectStore.setActiveEnvironment(\n { id: input.projectId, orgId: input.orgId }, input.environmentId,\n );\n\n if (!updated) {\n throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Failed to set active environment' });\n }\n\n // Push resolved config to ALL assigned services (running or not)\n for (const serviceId of project.serviceIds) {\n const service = await serviceStore.get(serviceId);\n if (!service || !service.agentId) continue;\n\n const agentStatus = agentManager.getStatus(service.agentId);\n if (!agentStatus?.connected) continue;\n\n // Always resolve — the resolver handles empty service variables\n let resolvedService = service;\n try {\n const resolved = await environmentResolver.resolveForService({\n serviceId: service.id,\n activeEnvironmentId: input.environmentId,\n });\n\n resolvedService = {\n ...service,\n env: { ...resolved.env },\n envSecrets: [...resolved.envSecrets],\n };\n } catch (err) {\n console.error('[project-router] Failed to resolve variables for service', serviceId + ':', (err as Error).message);\n }\n\n const wasRunning = runningServices.some(rs => rs.serviceId === serviceId);\n\n if (wasRunning) {\n // Stop → deploy (with new env) → start\n // Uses deploy instead of updateConfig for consistency with the lazy deploy pattern\n try {\n await agentManager.agentMutation(service.agentId, 'process.stop', { id: serviceId });\n await agentManager.agentMutation(service.agentId, 'process.deploy', resolvedService);\n await agentManager.agentMutation(service.agentId, 'process.start', { id: serviceId });\n } catch (err) {\n console.error('[project-router] Failed to restart service', serviceId + ':', (err as Error).message);\n }\n }\n // Stopped services: no need to push config — the next start will\n // lazy-deploy with the freshly resolved environment anyway.\n }\n\n return updated;\n }),\n\n /**\n * Where this project lives on this machine, for every project at once.\n *\n * Machine-local by design: a directory of mine means nothing on a teammate's\n * machine, and the cloud sync pushes projects wholesale — a path stored on the\n * project itself would travel with it.\n */\n /**\n * Le projet que cet onglet regarde.\n *\n * Le choix vit dans le navigateur ; le serveur ne le connaîtrait pas sans\n * cette annonce. Il n'en fait rien de persistant — seule l'icône de barre\n * système s'en sert, pour montrer les services du projet ouvert plutôt que\n * ceux de toute la machine.\n */\n setCurrent: protectedProcedure\n .input(z.object({ id: z.string().max(128), orgId: z.string().max(128).nullable().default(null) }).nullable())\n .mutation(({ input }) => {\n setCurrentProject(input ? { id: input.id, orgId: input.orgId } : null);\n return { ok: true as const };\n }),\n\n /**\n * Le graphe des dépendances du projet : qui a besoin de qui.\n *\n * Les arêtes ne sont pas déclarées, elles se lisent — une variable de A qui\n * cite `{{services.<slug-de-B>.PORT}}` EST la dépendance, celle-là même que\n * l'interpolation résout au déploiement. Rien à tenir à jour à côté, donc\n * rien qui puisse mentir.\n *\n * Seules les CLÉS des variables sortent d'ici. Les valeurs résolues portent\n * des secrets déchiffrés : elles servent à détecter la référence, et\n * s'arrêtent là.\n */\n graph: protectedProcedure\n .input(z.object({\n id: z.string().min(1).max(128),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .query(async ({ ctx, input }) => {\n const project = await projectStore.get(input);\n if (!project) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${input.id} not found` });\n }\n await assertReadable(project.orgId);\n\n const allowed = getAllowedServiceIds(ctx);\n const services = (await Promise.all(project.serviceIds.map((sid) => serviceStore.get(sid))))\n .filter((s) => s !== null);\n\n // Sans environnement actif, aucune variable n'est résolue : le graphe\n // rend alors ses nœuds et aucune arête, ce qui est la vérité.\n const envByServiceId: Record<string, Record<string, string>> = {};\n if (project.activeEnvironmentId) {\n const activeEnvironmentId = project.activeEnvironmentId;\n await Promise.all(services.map(async (service) => {\n try {\n const resolved = await environmentResolver.resolveForService({\n serviceId: service.id,\n activeEnvironmentId,\n });\n envByServiceId[service.id] = resolved.env;\n } catch (err) {\n // Un environnement illisible ne doit pas emporter le graphe\n // entier : ce service perd ses arêtes, les autres gardent les\n // leurs.\n console.error('[project-router] Failed to resolve variables for graph, service', service.id + ':', (err as Error).message);\n }\n }));\n }\n\n const graph = buildServiceGraph({\n services: services.map((s) => ({ id: s.id, name: s.name })),\n envByServiceId,\n });\n\n // Une clé d'API ne voit que les services qu'elle porte. Le filtre vient\n // APRÈS le calcul, jamais avant : bâtir le graphe sur une liste amputée\n // ferait passer les services retirés pour des références mortes, et\n // publierait leurs slugs dans `dangling` — soit exactement le nom qu'on\n // voulait taire.\n if (allowed === null) return graph;\n return {\n nodes: graph.nodes.filter((n) => allowed.has(n.id)),\n edges: graph.edges.filter((e) => allowed.has(e.from) && allowed.has(e.to)),\n dangling: graph.dangling.filter((d) => allowed.has(d.from)),\n };\n }),\n\n localPaths: protectedProcedure.query(async () => {\n return projectPathStore.all();\n }),\n\n getLocalPath: protectedProcedure\n .input(z.object({\n id: z.string().min(1).max(128),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .query(async ({ input }) => {\n return { path: await projectPathStore.get(input) };\n }),\n\n /**\n * Place a project in a directory of this machine.\n *\n * Refuses a directory that already holds a Runeya project, or one another\n * project was already placed in: two projects sharing a directory is what\n * makes services run against the wrong code.\n */\n setLocalPath: protectedProcedure\n .input(z.object({\n id: z.string().min(1).max(128),\n orgId: z.string().max(128).nullable().optional(),\n path: z.string().min(1).max(4096),\n }))\n .mutation(async ({ input }) => {\n const project = await projectStore.get(input);\n if (!project) throw new TRPCError({ code: 'NOT_FOUND', message: 'Projet introuvable' });\n\n if (await holdsRuneyaProject(input.path)) {\n throw new TRPCError({\n code: 'CONFLICT',\n message: 'Ce répertoire contient déjà un projet Runeya',\n });\n }\n const taken = await projectPathStore.projectAt(input.path, project);\n if (taken) {\n throw new TRPCError({\n code: 'CONFLICT',\n message: 'Un autre projet est déjà rattaché à ce répertoire',\n });\n }\n\n await projectPathStore.set(project, input.path);\n await auditService.log({ userId: 'local', action: 'update', entityType: 'project', entityId: input.id, metadata: { localPath: input.path } });\n return { path: input.path };\n }),\n /**\n * Ce qui a changé dans les stores, à mesure que ça change.\n *\n * Un projet, un service ou un environnement n'arrive pas toujours de\n * l'utilisateur assis devant : il descend du cloud quand un collègue le\n * pousse, ou d'une autre Runeya de cette machine. Les stores étaient déjà\n * prévenus — la synchronisation s'appuie sur les mêmes signaux — mais rien ne\n * portait l'information jusqu'à l'écran, qui gardait donc ce qu'il avait\n * chargé à l'ouverture de la vue.\n *\n * Ce flux annonce les collections touchées, pas leur contenu. Chacune a déjà\n * sa route, avec ses règles — un service ne sort jamais d'ici sans être\n * expurgé de ses secrets — et les redire ici en ferait une seconde version à\n * tenir d'accord avec la première.\n *\n * Les réveils sont groupés : une synchronisation qui descend un projet touche\n * ses trois collections coup sur coup, et trois annonces feraient trois\n * rechargements là où un seul suffit.\n */\n onDataChanged: protectedProcedure.subscription(async function* ({ signal }) {\n const touched = new Set<'projects' | 'services' | 'environments'>();\n let wake: (() => void) | null = null;\n\n const mark = (collection: 'projects' | 'services' | 'environments') => () => {\n touched.add(collection);\n if (wake) { wake(); wake = null; }\n };\n const onProjects = mark('projects');\n projectStore.events.on('saved', onProjects);\n const offs = [serviceStore.onChange(mark('services')), environmentStore.onChange(mark('environments'))];\n\n // Sans ce réveil, un client parti pendant l'attente laisserait le\n // générateur suspendu pour toujours — l'abandon ne franchit pas un `await`,\n // donc le désabonnement ci-dessous n'arriverait jamais.\n const onAbort = () => { if (wake) { wake(); wake = null; } };\n signal?.addEventListener('abort', onAbort);\n\n try {\n while (!signal?.aborted) {\n if (touched.size > 0) {\n const collections = Array.from(touched);\n touched.clear();\n yield { collections };\n } else {\n await new Promise<void>((resolve) => { wake = resolve; });\n }\n }\n } finally {\n projectStore.events.off('saved', onProjects);\n for (const off of offs) off();\n signal?.removeEventListener('abort', onAbort);\n }\n }),\n});\n","/**\n * Le projet que l'utilisateur regarde, connu du serveur.\n *\n * Ce choix vit dans le `localStorage` du navigateur : c'est l'onglet qui sait\n * quel projet est ouvert, et rien ne le disait au serveur. L'icône de barre\n * système, elle, n'a pas d'onglet — sans cette annonce, elle listerait les\n * services de tous les projets de la machine alors que l'écran n'en montre\n * qu'un.\n *\n * Gardé en mémoire, jamais sur le disque : c'est l'état d'une session\n * d'affichage, pas une configuration. Un redémarrage repart sans projet\n * courant, et l'onglet le redit en se rouvrant.\n */\nimport type { ProjectRef } from './project-key.js';\n\nlet current: ProjectRef | null = null;\nconst listeners = new Set<() => void>();\n\n/** Le projet regardé, ou `null` tant qu'aucun onglet ne l'a annoncé. */\nexport function getCurrentProject(): ProjectRef | null {\n return current;\n}\n\n/**\n * Annonce le projet regardé.\n *\n * Ne prévient que si le projet change vraiment : un onglet qui répète son\n * choix — au rechargement, ou à chaque reconnexion — ne doit pas faire\n * redessiner ce qui n'a pas bougé.\n */\nexport function setCurrentProject(next: ProjectRef | null): void {\n if (current?.id === next?.id && current?.orgId === next?.orgId) return;\n current = next;\n for (const listener of listeners) {\n try {\n listener();\n } catch {\n // Un abonné qui échoue ne doit pas empêcher les autres d'être prévenus.\n }\n }\n}\n\nexport function onCurrentProjectChanged(listener: () => void): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n","import { mkdir } from 'node:fs/promises';\nimport {\n readEncryptedKey,\n writeEncryptedKey,\n writeVerifyFile,\n readVerifyFile,\n matchesCanary,\n hasEncryptedKeyFile,\n} from './master-password.js';\nimport { setEncryptionKeyInMemory, getEncryptionKey, markVaultLocked, isVaultLocked, hasEncryptionKey } from '../utils/encryption-key.js';\nimport { orgVaultRoot, listOrgVaults, keyRoot } from './vault-resolver.js';\n\n/**\n * Une clé de chiffrement par organisation.\n *\n * La clé protégeait tout le poste, alors que ce qu'elle protège appartient à\n * des organisations différentes : une clé qui change — ou une organisation dont\n * la clé n'est pas la nôtre — emportait donc la machine entière. Chaque\n * organisation a désormais la sienne, rangée dans son coffre et scellée par le\n * même master password, si bien que déverrouiller la machine les ouvre toutes\n * d'un geste.\n *\n * La bascule est gratuite, et c'est voulu : une organisation sans clé propre\n * reçoit **la clé machine actuelle**. Ses données sont déjà chiffrées sous\n * elle, il n'y a donc rien à convertir, rien à perdre, et rien à demander à\n * l'utilisateur. Le jour où une organisation adopte une autre clé, seul son\n * coffre est re-chiffré — le reste de la machine ne bouge pas.\n */\n\nexport interface OrgKeyReport {\n /** Organisations dont la clé a été ouverte depuis leur coffre. */\n opened: string[];\n /** Organisations qui viennent de recevoir la clé machine comme clé propre. */\n seeded: string[];\n /**\n * Organisations dont la clé existe mais que ce master password n'ouvre pas.\n *\n * Le poste reste utilisable : ces coffres-là ne se déchiffrent pas, et la\n * synchronisation les écartera en le disant, plutôt que de rendre toute la\n * machine inaccessible pour une organisation.\n */\n locked: string[];\n}\n\n/**\n * Ouvrir — ou amorcer — la clé de chaque organisation présente sur ce disque.\n *\n * Appelé au déverrouillage, une fois la clé machine chargée. `masterPassword`\n * peut manquer (mode CI, où la clé vient de l'environnement) : on charge alors\n * la clé machine en mémoire pour chaque organisation sans rien écrire, ce qui\n * reproduit exactement le comportement d'avant les clés par organisation.\n */\nexport async function unlockOrgKeys(masterPassword: string | null): Promise<OrgKeyReport> {\n const machineKey = getEncryptionKey();\n const report: OrgKeyReport = { opened: [], seeded: [], locked: [] };\n if (!machineKey) return report;\n\n for (const orgId of await listOrgVaults()) {\n const root = orgVaultRoot(orgId);\n\n // Sans master password, rien ne peut être ni ouvert ni scellé. La clé\n // machine sert alors pour les organisations qui n'ont pas la leur — mais\n // JAMAIS pour celles qui en ont une : leur donner la clé machine ne les\n // rend pas lisibles, ça les rend inscriptibles sous la mauvaise clé, et\n // c'est ainsi qu'un coffre finit à moitié dans un chiffrement et à moitié\n // dans l'autre.\n if (!masterPassword) {\n if (await hasEncryptedKeyFile(root)) {\n markVaultLocked(orgId);\n report.locked.push(orgId);\n continue;\n }\n setEncryptionKeyInMemory(machineKey, orgId);\n continue;\n }\n\n const canary = await readVerifyFile(root);\n if (canary) {\n try {\n const key = await readEncryptedKey(root, masterPassword, await keyRoot());\n // Le canari du coffre tranche : le mot de passe peut ouvrir le fichier\n // et rendre une clé qui n'est pas celle sous laquelle ce coffre a été\n // écrit — auquel cas s'en servir écrirait du charabia par-dessus.\n if (!matchesCanary(canary, key)) {\n markVaultLocked(orgId);\n report.locked.push(orgId);\n continue;\n }\n setEncryptionKeyInMemory(key, orgId);\n report.opened.push(orgId);\n } catch {\n markVaultLocked(orgId);\n report.locked.push(orgId);\n }\n continue;\n }\n\n // Première rencontre : l'organisation adopte la clé machine, qui est déjà\n // celle de ses données. Écrit avant d'être chargé — une clé en mémoire que\n // le disque ignore disparaîtrait au redémarrage en laissant le coffre\n // chiffré sous une clé que plus rien ne nomme.\n await mkdir(root, { recursive: true });\n await writeEncryptedKey(root, masterPassword, machineKey, await keyRoot());\n await writeVerifyFile(root, machineKey);\n setEncryptionKeyInMemory(machineKey, orgId);\n report.seeded.push(orgId);\n }\n\n return report;\n}\n\n/**\n * Installer une clé donnée comme clé d'une organisation.\n *\n * Ne convertit rien : c'est à l'appelant d'avoir re-chiffré le coffre au\n * préalable, faute de quoi son contenu deviendrait illisible. Utilisé par\n * l'adoption, qui fait les deux dans le bon ordre.\n */\nexport async function installOrgKey(\n orgId: string,\n key: Buffer,\n masterPassword: string,\n): Promise<void> {\n const root = orgVaultRoot(orgId);\n await mkdir(root, { recursive: true });\n const pepperDir = await keyRoot();\n await writeEncryptedKey(root, masterPassword, key, pepperDir);\n const readBack = await readEncryptedKey(root, masterPassword, pepperDir);\n if (!readBack.equals(key)) {\n throw new Error(\"Vérification du fichier de clé de l'organisation échouée.\");\n }\n await writeVerifyFile(root, key);\n setEncryptionKeyInMemory(key, orgId);\n}\n\n/**\n * Le coffre d'une organisation est illisible depuis ce poste.\n *\n * Distinct d'une panne : la donnée est là, intacte, mais sous une clé que cette\n * machine n'a pas. Le geste qui répare est l'adoption de la clé, pas une\n * nouvelle tentative.\n */\nexport class OrgVaultUnreadableError extends Error {\n readonly code = 'ORG_VAULT_UNREADABLE';\n constructor(readonly orgId: string) {\n // Le code, pas la phrase : c'est l'interface qui sait dire où adopter.\n super('ORG_VAULT_UNREADABLE');\n this.name = 'OrgVaultUnreadableError';\n }\n}\n\n/**\n * Refuser d'ouvrir ce qu'on ne saura pas lire.\n *\n * Purement local, et c'est le point : `reconcileOrgCanary` interroge le cloud et\n * n'est éprouvé qu'à la première connexion d'une organisation, si bien qu'une\n * machine déjà connectée ouvrait ensuite n'importe quel projet sans que rien ne\n * revérifie la clé. Or ouvrir un projet, c'est charger ses environnements, ses\n * services et ses conversations — puis les réécrire à la première sauvegarde.\n * Sous la mauvaise clé, cette écriture passe par-dessus des secrets qu'on n'a\n * pas su lire : mieux vaut ne pas ouvrir du tout.\n *\n * Deux cas refusent :\n * - le coffre est verrouillé — sa clé existe, ce master password ne l'ouvre pas ;\n * - il a un canari que la clé en usage ici n'ouvre pas — c'est exactement la\n * situation où `getEncryptionKey` retombe en silence sur la clé machine.\n *\n * Une organisation sans canari local n'a pas encore de clé à elle : ses données\n * sont sous la clé machine, et l'ouvrir est sans risque.\n */\nexport async function assertOrgVaultReadable(orgId: string): Promise<void> {\n if (isVaultLocked(orgId)) throw new OrgVaultUnreadableError(orgId);\n\n const canary = await readVerifyFile(orgVaultRoot(orgId));\n if (!canary) return;\n\n const key = getEncryptionKey(orgId);\n if (!key || !matchesCanary(canary, key)) throw new OrgVaultUnreadableError(orgId);\n}\n\n/**\n * Fermer d'avance tout coffre qui a sa propre clé et qu'on n'a pas ouverte.\n *\n * Sans ça, `getEncryptionKey(orgId)` retombe en silence sur la clé machine pour\n * un coffre absent du trousseau. Le repli est juste pour une organisation qui\n * n'a pas encore de clé — ses données SONT sous la clé machine — et faux pour\n * une organisation qui en a une : la lecture échoue, et surtout l'écriture\n * réussit, sous une clé que ce coffre n'emploie pas. C'est ainsi qu'un fichier\n * se retrouve chiffré autrement que ses voisins, sans que rien ne le signale.\n *\n * Appelé avant que le moindre store ne lise le disque : à partir de là, un\n * coffre non ouvert refuse au lieu de se tromper. `setEncryptionKeyInMemory`\n * lève le verrou dès que la vraie clé arrive.\n */\nexport async function sealUnopenedOrgVaults(): Promise<string[]> {\n const sealed: string[] = [];\n for (const orgId of await listOrgVaults()) {\n if (hasEncryptionKey(orgId)) continue;\n if (!(await hasEncryptedKeyFile(orgVaultRoot(orgId)))) continue;\n markVaultLocked(orgId);\n sealed.push(orgId);\n }\n return sealed;\n}\n","import { randomBytes, createCipheriv, createDecipheriv } from 'node:crypto';\nimport { readFile, writeFile, chmod, stat, rename } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { Entry } from '@napi-rs/keyring';\nimport { hashRaw as argon2HashRaw } from '@node-rs/argon2';\n\nconst KEYRING_SERVICE = 'runeya';\nconst KEYRING_ACCOUNT = 'pepper';\nconst VERIFY_FILENAME = '.runeya-verify';\nconst ENCRYPTED_KEY_FILENAME = '.encryption.key.enc';\nconst PEPPER_FILENAME = '.pepper.private';\nconst CANARY_PLAINTEXT = 'runeya:v1:key-verification';\nconst MAX_KEY_FILE_SIZE = 1024; // 1 KB\nconst ARGON2_OPTIONS = { memoryCost: 65536, timeCost: 3, parallelism: 4, outputLen: 32 };\n\n// Helper: validate file size before reading\nasync function readKeyFile(filePath: string): Promise<Buffer> {\n const s = await stat(filePath);\n if (s.size > MAX_KEY_FILE_SIZE) throw new Error(`Fichier suspect : ${filePath} (${s.size} octets)`);\n return readFile(filePath);\n}\n\n// AES-256-GCM encrypt\nfunction aesEncrypt(key: Buffer, plaintext: Buffer): Buffer {\n const iv = randomBytes(12);\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);\n const authTag = cipher.getAuthTag();\n return Buffer.concat([iv, authTag, encrypted]); // 12 + 16 + N bytes\n}\n\n// AES-256-GCM decrypt — throws if authTag invalid\nfunction aesDecrypt(key: Buffer, data: Buffer): Buffer {\n const iv = data.subarray(0, 12);\n const authTag = data.subarray(12, 28);\n const ciphertext = data.subarray(28);\n const decipher = createDecipheriv('aes-256-gcm', key, iv, { authTagLength: 16 });\n decipher.setAuthTag(authTag);\n return Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n}\n\n// Fallback: store pepper as a file in dataDir (chmod 600)\nasync function getPepperFromFile(dataDir: string): Promise<Buffer | null> {\n try {\n const raw = await readKeyFile(join(dataDir, PEPPER_FILENAME));\n const hex = raw.toString('utf-8').trim();\n if (/^[0-9a-f]{64}$/i.test(hex)) return Buffer.from(hex, 'hex');\n } catch { /* not found */ }\n return null;\n}\n\nasync function writePepperToFile(dataDir: string, pepper: Buffer): Promise<void> {\n const filePath = join(dataDir, PEPPER_FILENAME);\n const tmpPath = filePath + '.tmp';\n await writeFile(tmpPath, pepper.toString('hex'), 'utf-8');\n await chmod(tmpPath, 0o600);\n await rename(tmpPath, filePath);\n}\n\nfunction tryKeyringGet(): string | null {\n try { return new Entry(KEYRING_SERVICE, KEYRING_ACCOUNT).getPassword(); } catch { return null; }\n}\n\nfunction tryKeyringSet(value: string): boolean {\n try { new Entry(KEYRING_SERVICE, KEYRING_ACCOUNT).setPassword(value); return true; } catch { return false; }\n}\n\n// Get or generate pepper — keyring first, file fallback\nasync function getOrCreatePepper(dataDir: string): Promise<Buffer> {\n // Try keyring read\n const pepperHex = tryKeyringGet();\n if (pepperHex && /^[0-9a-f]{64}$/i.test(pepperHex)) {\n return Buffer.from(pepperHex, 'hex');\n }\n // Keyring failed or empty — try file fallback\n const filePepper = await getPepperFromFile(dataDir);\n if (filePepper) return filePepper;\n // Generate new pepper, persist in keyring if possible, else file\n const pepper = randomBytes(32);\n const saved = tryKeyringSet(pepper.toString('hex'));\n if (!saved) {\n console.warn('[master-password] Keyring unavailable, storing pepper in dataDir (fallback)');\n await writePepperToFile(dataDir, pepper);\n }\n return pepper;\n}\n\n// Derive key from master password + pepper using Argon2id\n// Returns 32-byte derived key (never stored)\nasync function deriveKey(masterPassword: string, pepper: Buffer, salt: Buffer): Promise<Buffer> {\n const combined = masterPassword + pepper.toString('hex');\n const derived = await argon2HashRaw(combined, {\n ...ARGON2_OPTIONS,\n salt,\n });\n return Buffer.from(derived);\n}\n\n// Encrypt encryption key and write to .encryption.key.enc\n// Format: base64(salt_16 + iv_12 + authTag_16 + ciphertext_32)\n/**\n * `pepperDir` dit où trouver le poivre quand le trousseau de l'OS est\n * indisponible. Il vaut le répertoire de la clé par défaut, mais un coffre\n * d'organisation le fait pointer vers la racine machine : le poivre décrit le\n * poste, pas l'organisation, et en semer une copie par coffre en ferait un\n * secret de plus à tenir en accord avec les autres.\n */\nexport async function writeEncryptedKey(\n dataDir: string,\n masterPassword: string,\n encryptionKey: Buffer,\n pepperDir: string = dataDir,\n): Promise<void> {\n const pepper = await getOrCreatePepper(pepperDir);\n const salt = randomBytes(16);\n const derivedKey = await deriveKey(masterPassword, pepper, salt);\n const payload = aesEncrypt(derivedKey, encryptionKey); // iv(12) + authTag(16) + ciphertext(32)\n const fileContent = Buffer.concat([salt, payload]);\n const encoded = fileContent.toString('base64');\n const filePath = join(dataDir, ENCRYPTED_KEY_FILENAME);\n const tmpPath = filePath + '.tmp';\n await writeFile(tmpPath, encoded, 'utf-8');\n await chmod(tmpPath, 0o600);\n await rename(tmpPath, filePath);\n}\n\n// Read and decrypt .encryption.key.enc — throws on wrong password\nexport async function readEncryptedKey(\n dataDir: string,\n masterPassword: string,\n pepperDir: string = dataDir,\n): Promise<Buffer> {\n const filePath = join(dataDir, ENCRYPTED_KEY_FILENAME);\n const raw = await readKeyFile(filePath);\n const fileContent = Buffer.from(raw.toString('utf-8').trim(), 'base64');\n const salt = fileContent.subarray(0, 16);\n const payload = fileContent.subarray(16); // iv(12) + authTag(16) + ciphertext(32)\n const pepper = await getPepperFromKeychain(pepperDir);\n const derivedKey = await deriveKey(masterPassword, pepper, salt);\n // throws if authTag invalid → wrong password\n return aesDecrypt(derivedKey, payload);\n}\n\n// Get pepper from keychain, file fallback (must exist — throws if not found anywhere)\nasync function getPepperFromKeychain(dataDir: string): Promise<Buffer> {\n const pepperHex = tryKeyringGet();\n if (pepperHex && /^[0-9a-f]{64}$/i.test(pepperHex)) {\n return Buffer.from(pepperHex, 'hex');\n }\n // Fallback to file\n const filePepper = await getPepperFromFile(dataDir);\n if (filePepper) return filePepper;\n throw new Error('Pepper introuvable (keyring et fichier). Re-setup requis.');\n}\n\n// Write canary file .runeya-verify\nexport async function writeVerifyFile(dataDir: string, encryptionKey: Buffer): Promise<void> {\n const payload = aesEncrypt(encryptionKey, Buffer.from(CANARY_PLAINTEXT, 'utf-8'));\n const filePath = join(dataDir, VERIFY_FILENAME);\n const tmpPath = filePath + '.tmp';\n await writeFile(tmpPath, payload.toString('base64'), 'utf-8');\n await rename(tmpPath, filePath);\n}\n\n// Verify encryption key against .runeya-verify — throws if wrong key\nexport async function verifyEncryptionKey(dataDir: string, encryptionKey: Buffer): Promise<void> {\n const filePath = join(dataDir, VERIFY_FILENAME);\n const raw = await readKeyFile(filePath);\n if (!matchesCanary(raw.toString('utf-8'), encryptionKey)) {\n throw new Error('Clé d\\'encryption incorrecte');\n }\n}\n\n/**\n * Whether a canary was produced by this key.\n *\n * Canaries cannot be compared to each other: `aesEncrypt` uses a random IV, so\n * the same key yields a different canary every time. The only test is to\n * decrypt — which is also why holding a canary reveals nothing about the key.\n *\n * Takes the canary value rather than a path, so the same check works on the\n * local `.runeya-verify` and on the one an organization publishes to the cloud.\n */\nexport function matchesCanary(canaryBase64: string, encryptionKey: Buffer): boolean {\n try {\n const payload = Buffer.from(canaryBase64.trim(), 'base64');\n return aesDecrypt(encryptionKey, payload).toString('utf-8') === CANARY_PLAINTEXT;\n } catch {\n // Wrong key => GCM auth failure. Indistinguishable from a corrupt canary,\n // and both mean the same thing here: this key does not open it.\n return false;\n }\n}\n\n/** This machine's canary, or null when setup has not written one yet. */\nexport async function readVerifyFile(dataDir: string): Promise<string | null> {\n try {\n return (await readKeyFile(join(dataDir, VERIFY_FILENAME))).toString('utf-8').trim();\n } catch {\n return null;\n }\n}\n\n// Check if .runeya-verify exists\nexport async function hasVerifyFile(dataDir: string): Promise<boolean> {\n try {\n await stat(join(dataDir, VERIFY_FILENAME));\n return true;\n } catch {\n return false;\n }\n}\n\n// Check if .encryption.key.enc exists\nexport async function hasEncryptedKeyFile(dataDir: string): Promise<boolean> {\n try {\n await stat(join(dataDir, ENCRYPTED_KEY_FILENAME));\n return true;\n } catch {\n return false;\n }\n}\n\n","import { ambiguousServiceSlugs, crossServiceSlugsIn, serviceSlug } from '@runeya/packages-shared';\n\n/**\n * Le graphe des dépendances entre services d'un projet, tel qu'il se lit dans\n * les variables d'environnement.\n *\n * Rien de nouveau n'est déclaré pour le construire : une arête `A → B` existe\n * parce qu'une variable de A cite `{{services.<slug-de-B>.PORT}}` — la même\n * référence que l'interpolation remplace au déploiement (voir\n * `buildServerBuiltins`). Le graphe décrit donc ce qui se passe vraiment, et\n * ne peut pas se désynchroniser d'une configuration tenue à part.\n */\n\ninterface ServiceGraphNode {\n id: string;\n name: string;\n slug: string;\n /**\n * Deux services du projet portent ce slug : aucun des deux n'est adressable\n * (`buildServerBuiltins` les exclut tous les deux). Les références qui les\n * nomment restent donc sans effet — et l'interface a de quoi le dire.\n */\n ambiguousSlug: boolean;\n}\n\ninterface ServiceGraphEdge {\n /** Le service qui a besoin de l'autre. */\n from: string;\n /** Celui dont il lit le port, l'URL ou le nom. */\n to: string;\n /** Les variables qui portent la référence — leurs clés, jamais leurs valeurs. */\n keys: string[];\n}\n\n/** Une référence qui ne mène à aucun service : faute de frappe, ou service retiré. */\ninterface ServiceGraphDanglingRef {\n from: string;\n slug: string;\n keys: string[];\n}\n\nexport interface ServiceGraph {\n nodes: ServiceGraphNode[];\n edges: ServiceGraphEdge[];\n dangling: ServiceGraphDanglingRef[];\n}\n\nexport interface ServiceGraphInput {\n services: { id: string; name: string }[];\n /**\n * Pour chaque service, ses variables résolues AVANT interpolation des\n * builtins : les `{{services.*}}` y sont donc encore lisibles. C'est ce que\n * rend `environmentResolver.resolveForService`.\n *\n * Seules les CLÉS ressortent d'ici : une valeur peut être un secret déchiffré.\n */\n envByServiceId: Record<string, Record<string, string>>;\n}\n\n/** Accumule les clés par couple (source, cible), sans jamais garder de valeur. */\nfunction addKey(\n buckets: Map<string, { from: string; target: string; keys: Set<string> }>,\n from: string,\n target: string,\n key: string,\n): void {\n // Le couple sert d'identité ; les deux moitiés sont conservées à part pour\n // n'avoir aucune chaîne à ré-analyser ensuite. Le séparateur est écrit en\n // séquence d'échappement, jamais en caractère brut : un octet nul dans le\n // source ferait classer ce fichier comme binaire par git, et il n'aurait\n // plus ni diff ni fusion.\n const id = `${from}\\u0000${target}`;\n const bucket = buckets.get(id) ?? { from, target, keys: new Set<string>() };\n bucket.keys.add(key);\n buckets.set(id, bucket);\n}\n\n/**\n * Volontairement pur — aucun store, aucun accès disque : la règle qui compte\n * ici (quelle référence fait quelle arête) se teste sans monter un serveur.\n */\nexport function buildServiceGraph(input: ServiceGraphInput): ServiceGraph {\n const ambiguous = ambiguousServiceSlugs(input.services.map((s) => s.name));\n\n const nodes: ServiceGraphNode[] = input.services.map((service) => {\n const slug = serviceSlug(service.name);\n return {\n id: service.id,\n name: service.name,\n slug,\n ambiguousSlug: ambiguous.has(slug),\n };\n });\n\n // Un slug ambigu n'entre pas dans la table : le résoudre vers l'un des deux\n // services dépendrait de l'ordre de chargement — exactement ce que\n // `buildServerBuiltins` refuse de faire au moment d'interpoler.\n const bySlug = new Map<string, string>();\n for (const node of nodes) {\n if (node.slug && !node.ambiguousSlug) bySlug.set(node.slug, node.id);\n }\n\n const edgeBuckets = new Map<string, { from: string; target: string; keys: Set<string> }>();\n const danglingBuckets = new Map<string, { from: string; target: string; keys: Set<string> }>();\n\n for (const service of input.services) {\n const env = input.envByServiceId[service.id] ?? {};\n for (const [key, value] of Object.entries(env)) {\n for (const slug of crossServiceSlugsIn(value)) {\n const target = bySlug.get(slug);\n // Une auto-référence n'est pas une dépendance : `{{services.a.PORT}}`\n // écrit depuis A redit ce que `{{service.PORT}}` dit déjà. Ni arête,\n // ni signalement.\n if (target === service.id) continue;\n if (target) addKey(edgeBuckets, service.id, target, key);\n else addKey(danglingBuckets, service.id, slug, key);\n }\n }\n }\n\n const edges: ServiceGraphEdge[] = [...edgeBuckets.values()].map((b) => ({\n from: b.from,\n to: b.target,\n keys: [...b.keys].sort(),\n }));\n const dangling: ServiceGraphDanglingRef[] = [...danglingBuckets.values()].map((b) => ({\n from: b.from,\n slug: b.target,\n keys: [...b.keys].sort(),\n }));\n\n return { nodes, edges, dangling };\n}\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { LOG_BUFFER_SIZE } from '@runeya/packages-shared';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { agentManager } from '../../services/agent-manager.js';\nimport type { AgentStatus } from '@runeya/packages-shared';\n\nconst SUBSCRIPTION_QUEUE_MAX = LOG_BUFFER_SIZE;\n\nexport const agentRouter = router({\n /** List all registered agents with their connection status */\n list: protectedProcedure.query(() => {\n return agentManager.listAgents();\n }),\n\n /** Get a single agent's config and status */\n get: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .query(({ input }) => {\n const agent = agentManager.getAgent(input.id);\n if (!agent) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Agent ${input.id} not found` });\n }\n return {\n config: { ...agent.config, passphrase: '***' },\n status: agent.status,\n };\n }),\n\n /** Test connectivity to an agent given url + passphrase */\n testConnection: protectedProcedure\n .input(\n z.object({\n url: z.string().url().max(2048),\n passphrase: z.string().min(1).max(1024).optional(),\n agentId: z.string().max(128).optional(),\n }),\n )\n .mutation(async ({ input }) => {\n let passphrase = input.passphrase;\n let targetUrl = input.url;\n if (!passphrase && input.agentId) {\n const agent = agentManager.getAgentConfig(input.agentId);\n if (!agent) {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'Agent not found' });\n }\n passphrase = agent.passphrase;\n // SECURITY: When using a stored passphrase, always use the stored agent URL\n // to prevent exfiltration of the passphrase to an attacker-controlled URL\n targetUrl = agent.url;\n }\n if (!passphrase) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Passphrase is required' });\n }\n\n const url = new URL('/api/trpc/health.check', targetUrl);\n try {\n const res = await fetch(url.toString(), {\n headers: { 'Authorization': `Bearer ${passphrase}`, 'Content-Type': 'application/json' },\n signal: AbortSignal.timeout(5000),\n });\n if (!res.ok) {\n return { success: false as const, error: `HTTP ${res.status} ${res.statusText}` };\n }\n const json = await res.json() as { error?: { message?: string }; result?: { data?: { uptime?: number } } };\n if (json.error) {\n return { success: false as const, error: json.error.message ?? 'Agent returned an error' };\n }\n return { success: true as const, uptime: json.result?.data?.uptime };\n } catch (err) {\n const msg = err instanceof Error ? err.message : 'Unknown error';\n return { success: false as const, error: msg };\n }\n }),\n\n /** Register a new agent */\n register: protectedProcedure\n .input(\n z.object({\n name: z.string().min(1).max(100),\n url: z.string().url().max(2048),\n passphrase: z.string().min(1).max(1024),\n // À quelle organisation rattacher l'agent. Absent = la machine, ce que\n // font l'agent local et tout client antérieur à ce champ.\n orgId: z.string().min(1).max(128).nullable().optional(),\n }),\n )\n .mutation(async ({ input }) => {\n const config = await agentManager.register(\n input.name, input.url, input.passphrase, input.orgId ?? null,\n );\n return { ...config, passphrase: '***' };\n }),\n\n /** Update an existing agent */\n update: protectedProcedure\n .input(\n z.object({\n id: z.string().max(128),\n name: z.string().min(1).max(100).optional(),\n url: z.string().url().max(2048).optional(),\n passphrase: z.string().min(1).max(1024).optional(),\n passthroughEnv: z.array(\n z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/).max(256),\n ).max(100).optional(),\n }),\n )\n .mutation(async ({ input }) => {\n try {\n const { id, ...fields } = input;\n const config = await agentManager.update(id, fields);\n return { ...config, passphrase: '***' };\n } catch (err) {\n if (err instanceof Error) {\n if (err.message.includes('not found')) {\n throw new TRPCError({ code: 'NOT_FOUND', message: err.message });\n }\n if (err.message.includes('Cannot modify')) {\n throw new TRPCError({ code: 'FORBIDDEN', message: err.message });\n }\n }\n throw err;\n }\n }),\n\n /** Get resolved passthrough env values from an agent */\n getPassthroughEnv: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .query(async ({ input }) => {\n try {\n return await agentManager.agentQuery<Record<string, string>>(input.id, 'config.getPassthroughEnv');\n } catch {\n return {};\n }\n }),\n\n /** Remove a registered agent */\n remove: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .mutation(async ({ input }) => {\n try {\n const removed = await agentManager.remove(input.id);\n if (!removed) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Agent ${input.id} not found` });\n }\n return { success: true as const };\n } catch (err) {\n if (err instanceof Error && err.message === 'Cannot remove the local agent') {\n throw new TRPCError({ code: 'FORBIDDEN', message: err.message });\n }\n throw err;\n }\n }),\n\n /** Subscribe to real-time agent status changes */\n onStatus: protectedProcedure.subscription(async function* () {\n // Yield current state of all agents immediately so the client\n // doesn't have to wait for the next health tick.\n for (const agent of agentManager.listAgents()) {\n yield { agentId: agent.config.id, status: agent.status };\n }\n\n const queue: Array<{ agentId: string; status: AgentStatus }> = [];\n let resolve: (() => void) | null = null;\n\n const handler = (event: { agentId: string; status: AgentStatus }) => {\n if (queue.length >= SUBSCRIPTION_QUEUE_MAX) queue.shift();\n queue.push(event);\n if (resolve) {\n resolve();\n resolve = null;\n }\n };\n\n agentManager.on('status', handler);\n\n try {\n while (true) {\n if (queue.length > 0) {\n yield queue.shift()!;\n } else {\n await new Promise<void>((r) => { resolve = r; });\n }\n }\n } finally {\n agentManager.off('status', handler);\n }\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { LOG_BUFFER_SIZE, ServiceShortcutSchema, AGENT_LONG_FETCH_TIMEOUT } from '@runeya/packages-shared';\nimport type { ProcessStatus, ProcessMetrics } from '@runeya/packages-shared';\nimport { router, protectedProcedure, requireServiceAction, getAllowedServiceIds } from '../trpc.js';\nimport type { AuthContext } from '../trpc.js';\nimport { agentManager } from '../../services/agent-manager.js';\nimport { auditService } from '../../services/audit-service.js';\nimport { serviceStore } from '../../services/service-store.js';\nimport { startProcess, stopProcess, restartProcess, listAllProcesses } from '../../services/process-control.js';\nimport { resolveServiceVariables } from './service.js';\nimport { resolveAgentCwd } from '../../services/workspace-cwd.js';\n\n/** Max items in a subscription queue before dropping oldest */\nconst SUBSCRIPTION_QUEUE_MAX = LOG_BUFFER_SIZE;\n\n/**\n * Helper that creates a queued async generator forwarding events from agentManager.\n * Deduplicates the queue+handler pattern used by all process subscriptions.\n */\nasync function* forwardEvents<T = Record<string, unknown>>(\n eventName: string,\n filter?: (data: Record<string, unknown>) => boolean,\n): AsyncGenerator<T> {\n const queue: T[] = [];\n let resolve: (() => void) | null = null;\n\n const handler = (data: Record<string, unknown>) => {\n if (filter && !filter(data)) return;\n if (queue.length >= SUBSCRIPTION_QUEUE_MAX) queue.shift();\n queue.push(data as T);\n if (resolve) { resolve(); resolve = null; }\n };\n\n agentManager.on(eventName, handler);\n\n try {\n while (true) {\n if (queue.length > 0) {\n yield queue.shift()!;\n } else {\n await new Promise<void>((r) => { resolve = r; });\n }\n }\n } finally {\n agentManager.off(eventName, handler);\n }\n}\n\n/**\n * Helper for log batch forwarding. The AgentWSBridge wraps array data as\n * `{ batch: ParsedLog[], agentId }`. We filter by agentId + processId,\n * then yield the filtered batch to the frontend.\n */\nasync function* forwardLogBatches(\n agentId: string,\n processId: string,\n): AsyncGenerator<unknown[]> {\n const queue: unknown[][] = [];\n let resolve: (() => void) | null = null;\n\n const handler = (data: Record<string, unknown>) => {\n if (data.agentId !== agentId) return;\n const batch = data.batch as Array<Record<string, unknown>>;\n if (!Array.isArray(batch)) return;\n const filtered = batch.filter((log) => log.processId === processId);\n if (filtered.length === 0) return;\n if (queue.length >= SUBSCRIPTION_QUEUE_MAX) queue.shift();\n queue.push(filtered);\n if (resolve) { resolve(); resolve = null; }\n };\n\n agentManager.on('process:log', handler);\n\n try {\n while (true) {\n if (queue.length > 0) {\n yield queue.shift()!;\n } else {\n await new Promise<void>((r) => { resolve = r; });\n }\n }\n } finally {\n agentManager.off('process:log', handler);\n }\n}\n\nexport const processRouter = router({\n /** List all processes across all connected agents */\n list: protectedProcedure\n .meta({ openapi: { method: 'GET', path: '/processes', tags: ['processes'], summary: 'List all processes', protect: true } })\n .output(z.any())\n .query(() => listAllProcesses()),\n\n\n /** Get a single process from a specific agent */\n get: protectedProcedure\n .meta({ openapi: { method: 'GET', path: '/processes/{agentId}/{id}', tags: ['processes'], summary: 'Get a process by agent and ID', protect: true } })\n .input(z.object({ agentId: z.string().max(128), id: z.string().max(128) }))\n .output(z.any())\n .query(async ({ input, ctx }) => {\n requireServiceAction(ctx as AuthContext, input.id, 'service:read');\n const status = agentManager.getStatus(input.agentId);\n if (!status) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Agent ${input.agentId} not found` });\n }\n\n const proc = await agentManager.agentQuery<ProcessStatus>(input.agentId, 'process.get', { id: input.id });\n return { ...proc, agentId: input.agentId };\n }),\n\n\n /** Start a process on an agent.\n * Lazy deploy: the agent only learns about a service when it is first started\n * (or restarted). This avoids pushing configs for every service at agent boot,\n * which would be wasteful when many services are never started.\n * The deploy call is idempotent — creates the process if missing, updates config if it exists. */\n start: protectedProcedure\n .meta({ openapi: { method: 'POST', path: '/processes/{agentId}/{processId}/start', tags: ['processes'], summary: 'Start a process', protect: true } })\n .input(z.object({ agentId: z.string().max(128).optional(), processId: z.string().max(128) }))\n .output(z.any())\n .mutation(async ({ input, ctx }) => {\n requireServiceAction(ctx as AuthContext, input.processId, 'service:start');\n return startProcess(input.processId, input.agentId);\n }),\n\n /** Stop a process on an agent */\n stop: protectedProcedure\n .meta({ openapi: { method: 'POST', path: '/processes/{agentId}/{processId}/stop', tags: ['processes'], summary: 'Stop a process', protect: true } })\n .input(z.object({ agentId: z.string().max(128), processId: z.string().max(128) }))\n .output(z.any())\n .mutation(async ({ input, ctx }) => {\n requireServiceAction(ctx as AuthContext, input.processId, 'service:stop');\n return stopProcess(input.processId, input.agentId);\n }),\n\n /** Restart a process on an agent.\n * Sends stop → deploy (latest resolved config) → start so that\n * config/variable changes take effect. Same lazy deploy pattern as start. */\n restart: protectedProcedure\n .meta({ openapi: { method: 'POST', path: '/processes/{agentId}/{processId}/restart', tags: ['processes'], summary: 'Restart a process', protect: true } })\n .input(z.object({ agentId: z.string().max(128).optional(), processId: z.string().max(128) }))\n .output(z.any())\n .mutation(async ({ input, ctx }) => {\n requireServiceAction(ctx as AuthContext, input.processId, 'service:restart');\n return restartProcess(input.processId, input.agentId);\n }),\n\n /** Get buffered logs for a process from an agent */\n logs: protectedProcedure\n .meta({ openapi: { method: 'GET', path: '/processes/{agentId}/{processId}/logs', tags: ['processes'], summary: 'Get buffered logs for a process', protect: true } })\n .input(z.object({ agentId: z.string().max(128), processId: z.string().max(128) }))\n .output(z.any())\n .query(async ({ input, ctx }) => {\n requireServiceAction(ctx as AuthContext, input.processId, 'logs:read');\n return agentManager.agentQuery(input.agentId, 'process.logs', { id: input.processId });\n }),\n\n /** Clear buffered logs for a process on an agent */\n clearLogBuffer: protectedProcedure\n .input(z.object({ agentId: z.string().max(128), processId: z.string().max(128) }))\n .mutation(async ({ input }) => {\n await agentManager.agentMutation(input.agentId, 'process.clearLogBuffer', { id: input.processId });\n await auditService.log({ userId: 'local', action: 'clearLogBuffer', entityType: 'process', entityId: input.processId, metadata: { agentId: input.agentId } });\n return { success: true };\n }),\n\n /** Execute a shortcut command on an agent, streaming output into the process log */\n executeShortcut: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n processId: z.string().max(128),\n shortcut: ServiceShortcutSchema,\n }))\n .mutation(async ({ input }) => {\n // Lazy deploy: ensure the agent knows about this service (same pattern as start/restart)\n const service = await serviceStore.get(input.processId);\n if (service) {\n try {\n const resolved = await resolveServiceVariables(service);\n await agentManager.agentMutation(input.agentId, 'process.deploy', resolved);\n } catch (err) {\n console.debug('[process-router] Failed to deploy before executeShortcut for', input.processId + ':', (err as Error).message);\n }\n }\n\n const result = await agentManager.agentMutation<{ exitCode: number | null }>(\n input.agentId, 'process.executeShortcut',\n { id: input.processId, shortcut: input.shortcut },\n AGENT_LONG_FETCH_TIMEOUT,\n );\n await auditService.log({\n userId: 'local',\n action: 'executeShortcut',\n entityType: 'process',\n entityId: input.processId,\n metadata: { agentId: input.agentId, shortcutId: input.shortcut.id, shortcutLabel: input.shortcut.label },\n });\n return result;\n }),\n\n /** Execute an ad-hoc command on an agent, streaming output into the process log */\n executeAdHocCommand: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n processId: z.string().max(128),\n command: z.string().min(1).max(4096),\n cwd: z.string().max(4096).optional(),\n commandId: z.string().max(128).optional(),\n }))\n .mutation(async ({ input }) => {\n // Lazy deploy: ensure the agent knows about this service (same pattern as start/restart)\n const service = await serviceStore.get(input.processId);\n if (service) {\n try {\n const resolved = await resolveServiceVariables(service);\n await agentManager.agentMutation(input.agentId, 'process.deploy', resolved);\n } catch (err) {\n console.debug('[process-router] Failed to deploy before executeAdHocCommand for', input.processId + ':', (err as Error).message);\n }\n }\n\n const result = await agentManager.agentMutation<{ exitCode: number | null }>(\n input.agentId, 'process.executeAdHocCommand',\n {\n id: input.processId,\n command: input.command,\n // An explicit cwd wins; otherwise the service's directory, anchored on\n // its project rather than on the server's launch directory.\n cwd: input.cwd ?? await resolveAgentCwd({ serviceId: input.processId }),\n commandId: input.commandId,\n },\n AGENT_LONG_FETCH_TIMEOUT,\n );\n await auditService.log({\n userId: 'local',\n action: 'executeAdHocCommand',\n entityType: 'process',\n entityId: input.processId,\n metadata: { agentId: input.agentId, command: input.command },\n });\n return result;\n }),\n\n /** Cancel a running shortcut command on an agent */\n cancelShortcut: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n processId: z.string().max(128),\n shortcutId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n await agentManager.agentMutation(input.agentId, 'process.cancelShortcut', { id: input.processId, shortcutId: input.shortcutId });\n return { success: true };\n }),\n\n /** Cancel a running ad-hoc command on an agent */\n cancelAdHocCommand: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n processId: z.string().max(128),\n commandId: z.string().max(128).optional(),\n }))\n .mutation(async ({ input }) => {\n await agentManager.agentMutation(input.agentId, 'process.cancelAdHocCommand', { id: input.processId, commandId: input.commandId });\n return { success: true };\n }),\n\n /** Get current metrics for a process from an agent */\n metrics: protectedProcedure\n .input(z.object({ agentId: z.string().max(128), processId: z.string().max(128) }))\n .query(async ({ input }) => {\n return agentManager.agentQuery<ProcessMetrics>(input.agentId, 'process.metrics', { id: input.processId });\n }),\n\n /**\n * Subscribe to real-time log stream for a process.\n * Forwards batched events from the AgentWSBridge in real-time.\n * Historical logs are fetched separately via process.logs query.\n */\n onLog: protectedProcedure\n .input(z.object({ agentId: z.string().max(128), processId: z.string().max(128) }))\n .subscription(async function* ({ input, ctx }) {\n requireServiceAction(ctx as AuthContext, input.processId, 'logs:read');\n yield* forwardLogBatches(input.agentId, input.processId);\n }),\n\n /**\n * Subscribe to real-time status changes for processes.\n * Input is optional — omit agentId/processId for global monitoring (dashboard).\n * Forwards events from the AgentWSBridge in real-time.\n */\n onStatus: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128).optional(),\n processId: z.string().max(128).optional(),\n }).optional())\n .subscription(async function* ({ input, ctx }) {\n const allowedIds = getAllowedServiceIds(ctx as AuthContext);\n if (input?.processId) requireServiceAction(ctx as AuthContext, input.processId, 'service:status');\n\n // Yield initial state\n try {\n const agents = agentManager.listAgents();\n for (const agent of agents.filter(a => a.status.connected)) {\n if (input?.agentId && agent.config.id !== input.agentId) continue;\n try {\n const processes = await agentManager.agentQuery<any[]>(agent.config.id, 'process.list');\n for (const proc of processes) {\n if (input?.processId && proc.id !== input.processId) continue;\n if (allowedIds && !allowedIds.has(proc.id)) continue;\n yield { ...proc, agentId: agent.config.id };\n }\n } catch {\n // Agent unreachable, skip\n }\n }\n } catch {\n // Ignore errors during initial load\n }\n\n yield* forwardEvents('process:status', (d) => {\n if (input?.agentId && d.agentId !== input.agentId) return false;\n if (input?.processId && d.processId !== input.processId) return false;\n if (allowedIds && !allowedIds.has(d.processId as string)) return false;\n return true;\n });\n }),\n\n /** Subscribe to real-time metrics for a process. */\n onMetrics: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128).optional(),\n processId: z.string().max(128).optional(),\n }).optional())\n .subscription(async function* ({ input, ctx }) {\n const allowedIds = getAllowedServiceIds(ctx as AuthContext);\n if (input?.processId) requireServiceAction(ctx as AuthContext, input.processId, 'service:status');\n\n yield* forwardEvents<ProcessMetrics>('process:metrics', (d) => {\n if (input?.agentId && d.agentId !== input.agentId) return false;\n if (input?.processId && d.processId !== input.processId) return false;\n if (allowedIds && !allowedIds.has(d.processId as string)) return false;\n return true;\n });\n }),\n\n /** Subscribe to real-time health status changes. */\n onHealth: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128).optional(),\n processId: z.string().max(128).optional(),\n }).optional())\n .subscription(async function* ({ input, ctx }) {\n const allowedIds = getAllowedServiceIds(ctx as AuthContext);\n if (input?.processId) requireServiceAction(ctx as AuthContext, input.processId, 'service:healthcheck');\n\n yield* forwardEvents('process:health', (d) => {\n if (input?.agentId && d.agentId !== input.agentId) return false;\n if (input?.processId && d.processId !== input.processId) return false;\n if (allowedIds && !allowedIds.has(d.processId as string)) return false;\n return true;\n });\n }),\n});\n","/**\n * Démarrer, arrêter, redémarrer un service — la logique, sans le transport.\n *\n * Extrait du routeur tRPC `process` parce qu'il n'en est plus le seul appelant :\n * l'icône de barre système pilote les mêmes services, et elle tourne DANS le\n * processus du serveur. Sans cette extraction, elle aurait dû soit recopier ces\n * enchaînements — déploiement paresseux, purge des logs, résolution de l'agent\n * effectif —, soit se forger un jeton pour s'appeler elle-même par tRPC. Le\n * premier duplique un comportement délicat ; le second ouvre une porte dans\n * l'authentification pour un appelant qui n'en a pas besoin.\n *\n * Ce qui reste au routeur : le contrôle des droits (`requireServiceAction`),\n * qui dépend de l'appelant et n'a aucun sens ici.\n */\nimport { TRPCError } from '@trpc/server';\nimport { AGENT_STOP_FETCH_TIMEOUT } from '@runeya/packages-shared';\nimport type { ProcessStatus, ServiceConfig } from '@runeya/packages-shared';\nimport { agentManager } from './agent-manager.js';\nimport { auditService } from './audit-service.js';\nimport { serviceStore } from './service-store.js';\nimport { projectStore } from './project-store.js';\nimport { environmentResolver } from './environment-resolver.js';\n// Dette connue, antérieure à ce fichier : ces deux aides vivent dans un\n// routeur alors qu'elles n'ont rien de transport. Les déplacer touche bien\n// plus que le sujet du jour ; l'import reste donc dirigé comme il l'était.\nimport { resolveServiceVariables, resolveEffectiveAgentId } from '../trpc/routers/service.js';\n\n/** Le résultat d'un geste : l'état rendu par l'agent, et lequel a répondu. */\nexport type ProcessControlResult = ProcessStatus & { agentId: string };\n\n/**\n * L'agent qui doit exécuter le geste.\n *\n * La configuration du service ou de l'environnement l'emporte toujours sur\n * l'agent passé par l'appelant, pour qu'un changement d'agent prenne effet\n * immédiatement.\n */\nasync function resolveTarget(\n processId: string,\n fallbackAgentId?: string | null,\n): Promise<{ agentId: string; service: ServiceConfig | null }> {\n // Lu une seule fois et transporté : le service sert ici ET au déploiement.\n const service = (await serviceStore.get(processId)) ?? null;\n const agentId = (service ? await resolveEffectiveAgentId(service) : null) ?? fallbackAgentId ?? null;\n if (!agentId) {\n throw new TRPCError({\n code: 'BAD_REQUEST',\n message: 'No agent assigned to this service. Set an agent on the service or on the active environment.',\n });\n }\n return { agentId, service };\n}\n\n/**\n * Un service ne démarre pas tant que son environnement a des trous.\n *\n * Le contrôle est fatal, contrairement au déploiement paresseux qui le suit :\n * une variable obligatoire vide ne produit pas un service dégradé mais un\n * service qui tombe plus loin, avec un message qui ne nomme jamais la variable.\n * Autant refuser ici, en la nommant.\n *\n * Un service hors projet, ou dans un projet sans environnement actif, n'a rien\n * à vérifier : il n'y a pas d'environnement pour porter une exigence.\n */\nasync function assertEnvironmentComplete(service: ServiceConfig | null): Promise<void> {\n if (!service) return;\n\n const project = await projectStore.ofService(service.id);\n if (!project?.activeEnvironmentId) return;\n\n const missing = await environmentResolver.findMissingForService({\n serviceId: service.id,\n activeEnvironmentId: project.activeEnvironmentId,\n });\n if (missing.length === 0) return;\n\n throw new TRPCError({\n code: 'PRECONDITION_FAILED',\n message: `Missing environment variables: ${missing.map((m) => m.key).join(', ')}`,\n cause: { missingVariables: missing, environmentId: project.activeEnvironmentId },\n });\n}\n\n/**\n * Déploiement paresseux : l'agent n'apprend un service qu'à son premier\n * démarrage. Idempotent, et volontairement non bloquant — un déploiement raté\n * ne doit pas empêcher d'essayer de démarrer.\n */\nasync function deployBefore(\n processId: string,\n agentId: string,\n service: ServiceConfig | null,\n step: 'start' | 'restart',\n): Promise<void> {\n if (service) {\n try {\n const resolved = await resolveServiceVariables(service);\n await agentManager.agentMutation(agentId, 'process.deploy', resolved);\n } catch (err) {\n console.debug(`[process-control] Failed to deploy before ${step} for`, processId + ':', (err as Error).message);\n }\n }\n\n if (service?.clearLogsOnStart) {\n try {\n await agentManager.agentMutation(agentId, 'process.clearLogBuffer', { id: processId });\n agentManager.emit('process:log', { agentId, batch: [{ processId, __clearLogBuffer: true }] });\n } catch (err) {\n console.debug(`[process-control] Failed to clear logs before ${step} for`, processId + ':', (err as Error).message);\n }\n }\n}\n\nexport async function startProcess(processId: string, fallbackAgentId?: string | null): Promise<ProcessControlResult> {\n const { agentId, service } = await resolveTarget(processId, fallbackAgentId);\n\n await assertEnvironmentComplete(service);\n\n await deployBefore(processId, agentId, service, 'start');\n\n let result: ProcessStatus;\n try {\n result = await agentManager.agentMutation<ProcessStatus>(agentId, 'process.start', { id: processId });\n } catch (err: unknown) {\n const err_ = err as { cause?: { code?: string }; message?: string; name?: string };\n const isFetchError = err_?.cause?.code === 'ECONNREFUSED' || err_?.message === 'fetch failed' || err_?.name === 'TypeError';\n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message: isFetchError ? `Cannot reach agent — make sure the agent is running` : (err_?.message ?? 'Failed to start process'),\n });\n }\n\n await auditService.log({ userId: 'local', action: 'start', entityType: 'process', entityId: processId, metadata: { agentId } });\n return { ...result, agentId };\n}\n\nexport async function stopProcess(processId: string, agentId: string): Promise<ProcessControlResult> {\n const result = await agentManager.agentMutation<ProcessStatus>(\n agentId,\n 'process.stop',\n { id: processId },\n AGENT_STOP_FETCH_TIMEOUT,\n );\n await auditService.log({ userId: 'local', action: 'stop', entityType: 'process', entityId: processId, metadata: { agentId } });\n return { ...result, agentId };\n}\n\n/**\n * Arrêt → redéploiement de la configuration à jour → démarrage, pour qu'un\n * changement de configuration ou de variable prenne effet.\n */\nexport async function restartProcess(processId: string, fallbackAgentId?: string | null): Promise<ProcessControlResult> {\n const { agentId, service } = await resolveTarget(processId, fallbackAgentId);\n\n await assertEnvironmentComplete(service);\n\n // L'arrêt est permissif : le process peut ne pas encore exister sur l'agent.\n try {\n await agentManager.agentMutation<{ success: true }>(agentId, 'process.stop', { id: processId }, AGENT_STOP_FETCH_TIMEOUT);\n } catch (err) {\n console.debug('[process-control] Stop before restart ignored (process not found on agent?):', (err as Error).message);\n }\n\n await deployBefore(processId, agentId, service, 'restart');\n\n const result = await agentManager.agentMutation<ProcessStatus>(agentId, 'process.start', { id: processId });\n await auditService.log({ userId: 'local', action: 'restart', entityType: 'process', entityId: processId, metadata: { agentId } });\n return { ...result, agentId };\n}\n\n/**\n * L'état de tous les process, tous agents connectés confondus.\n *\n * Les agents injoignables sont ignorés plutôt que fatals : un agent distant\n * éteint ne doit pas priver l'appelant de l'état des autres.\n */\nexport async function listAllProcesses(): Promise<ProcessControlResult[]> {\n const results: ProcessControlResult[] = [];\n\n await Promise.allSettled(\n agentManager\n .listAgents()\n .filter((a) => a.status.connected)\n .map(async (a) => {\n try {\n const processes = await agentManager.agentQuery<ProcessStatus[]>(a.config.id, 'process.list');\n for (const proc of processes) results.push({ ...proc, agentId: a.config.id });\n } catch {\n // Agent unreachable, skip\n }\n }),\n );\n\n return results;\n}\n","import { z } from 'zod';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { auditService } from '../../services/audit-service.js';\n\nexport const auditRouter = router({\n list: protectedProcedure\n .input(z.object({\n action: z.string().max(50).optional(),\n entityType: z.string().max(50).optional(),\n entityId: z.string().max(100).optional(),\n limit: z.number().int().positive().max(100).default(50),\n offset: z.number().int().nonnegative().default(0),\n }).optional())\n .query(async ({ input }) => {\n return auditService.list(input ?? {});\n }),\n});\n","import { z } from 'zod';\nimport { router, publicProcedure, protectedProcedure } from '../trpc.js';\nimport { hasEncryptionKey, setEncryptionKey, getEncryptionKey, isVaultLocked } from '../../utils/encryption-key.js';\nimport { listOrgVaults, readOrgNames, readOrgClouds, orgVaultRoot } from '../../services/vault-resolver.js';\nimport { readVerifyFile, matchesCanary } from '../../services/master-password.js';\nimport { getCloudApiUrl } from '../../services/cloud-api.js';\nimport { agentStore } from '../../services/agent-store.js';\nimport { apiKeyStore } from '../../services/api-key-store.js';\nimport { conversationStore } from '../../services/conversation-store.js';\nimport { environmentStore } from '../../services/environment-store.js';\nimport { agentSpawner } from '../../services/agent-spawner.js';\nimport { env } from '../../config/env.js';\nimport { cloudSessionStore } from '../../services/cloud-session-store.js';\n\nexport const setupRouter = router({\n /**\n * Check if encryption key is required (project initialized but no key).\n */\n needsEncryptionKey: publicProcedure.query(async () => {\n return {\n needsKey: !hasEncryptionKey(),\n };\n }),\n\n /**\n * Get current encryption key in hex format (for sharing with team).\n * Only available in local-simple mode for security.\n */\n getEncryptionKeyHex: protectedProcedure.query(async () => {\n if (env.MODE !== 'local-simple') {\n throw new Error('Encryption key export only available in local-simple mode');\n }\n\n const key = getEncryptionKey();\n if (!key) {\n throw new Error('No encryption key loaded');\n }\n\n return {\n keyHex: key.toString('hex'),\n };\n }),\n\n /**\n * Les clés des organisations suivies sur ce poste.\n *\n * Le pendant de l'adoption : celle-ci demande une clé, celle-là la donne. Sans\n * elle, un membre qui doit transmettre la clé de son organisation à un\n * collègue n'a nulle part où la lire — l'onglet Sécurité ne montrant que la\n * clé machine, qui n'est pas la même dès qu'une organisation a la sienne.\n *\n * `source` n'est pas décoratif. `getEncryptionKey(orgId)` retombe en silence\n * sur la clé machine pour un coffre sans clé propre ; rendre ce hex sans le\n * dire afficherait la clé machine sous l'étiquette « clé de l'organisation »,\n * soit exactement la confusion que cette route existe pour lever.\n */\n getOrgKeys: protectedProcedure.query(async () => {\n if (env.MODE !== 'local-simple') {\n throw new Error('Encryption key export only available in local-simple mode');\n }\n\n const machineKey = getEncryptionKey();\n const orgs = await listOrgVaults();\n // Le nom vient du tampon du coffre, pas du cloud : c'est ce qui le rend\n // lisible hors ligne, quand l'id seul ne dit plus rien.\n const names = await readOrgNames();\n // Le cloud d'où vient chaque coffre. `~/.runeya/orgs/` est global à la\n // machine : un poste qui a parlé à deux clouds — l'hébergé et un local de\n // développement — y mélange leurs organisations, et rien ne les distingue\n // sans ce tampon. Sans lui, le panneau présentait la clé d'une organisation\n // d'un autre cloud comme une clé à transmettre à un collègue.\n const clouds = await readOrgClouds();\n const currentCloud = getCloudApiUrl();\n // Les clouds où ce poste a un compte. « Étranger » veut dire « d'un cloud\n // dont je ne suis membre nulle part » : avec deux comptes sur deux clouds,\n // comparer au seul cloud configuré rangeait toutes les organisations du\n // second sous « un autre cloud », clé comprise.\n const ownCloudUrls = new Set([\n currentCloud,\n ...(await cloudSessionStore.list()).map((a) => a.cloudUrl.replace(/\\/+$/, '')),\n ]);\n // Ce que chaque coffre garde sans savoir le lire. Les stores le préservent\n // déjà sur le disque ; le compter ici est ce qui le rend visible, au lieu\n // d'un silence qui se lit comme « il n'y a rien ».\n const [unreadableConversations, unreadableSecrets] = await Promise.all([\n conversationStore.unreadableByVault(),\n environmentStore.unreadableByVault(),\n ]);\n\n return {\n // Le cloud de cette instance, dit explicitement : c'est l'étalon contre\n // lequel `foreign` est mesuré, et sans lui « un autre cloud » ne veut\n // rien dire pour qui lit.\n currentCloud,\n orgs: await Promise.all(orgs.map(async (orgId) => {\n const name = names[orgId] ?? null;\n // Un coffre sans tampon vient forcément d'ici : il a été écrit avant\n // que le tampon existe, donc par ce cloud-là.\n const cloudUrl = clouds[orgId] ?? currentCloud;\n const foreign = !ownCloudUrls.has(cloudUrl.replace(/\\/+$/, ''));\n const unreadable = {\n apiKeys: await apiKeyStore.unreadableCount(orgId),\n conversations: unreadableConversations.get(orgId) ?? 0,\n secrets: unreadableSecrets.get(orgId) ?? 0,\n };\n // Un coffre verrouillé a une clé propre que ce master password n'ouvre\n // pas : il n'y a rien à montrer, et le repli sur la clé machine serait\n // un mensonge.\n if (isVaultLocked(orgId)) {\n return { orgId, name, cloudUrl, foreign, keyHex: null, source: 'locked' as const, unreadable };\n }\n const key = getEncryptionKey(orgId);\n if (!key) return { orgId, name, cloudUrl, foreign, keyHex: null, source: 'locked' as const, unreadable };\n const isMachineKey = machineKey !== null && key.equals(machineKey);\n return {\n orgId,\n name,\n cloudUrl,\n foreign,\n keyHex: key.toString('hex'),\n source: isMachineKey ? ('machine' as const) : ('own' as const),\n unreadable,\n };\n })),\n };\n }),\n\n /**\n * Éprouver une clé contre le canari du coffre, sans passer par le cloud.\n *\n * `cloudSync.checkOrgKey` interroge le canari publié par l'organisation :\n * il prouve « cette clé est celle de l'organisation », mais il exige que le\n * cloud réponde et que l'organisation y existe encore. Un poste hors ligne —\n * ou qui reprend un coffre dont l'organisation a disparu côté cloud — n'avait\n * alors plus aucun moyen de vérifier une clé avant de l'adopter.\n *\n * Le coffre porte pourtant son propre canari, écrit en même temps que sa clé.\n * Attention à ce qu'il dit : il éprouve la clé COURANTE du coffre, donc il ne\n * répond « oui » que pour celle déjà en place — c'est-à-dire exactement le\n * cas où l'adoption n'a rien à faire, et qu'elle refuse. Le confondre avec\n * une validation de la clé à adopter rendait le parcours impossible : vert\n * quand le geste est inutile, rouge sinon.\n */\n checkOrgKeyLocal: protectedProcedure\n .input(z.object({\n orgId: z.string().min(1).max(128),\n keyHex: z.string().length(64).regex(/^[0-9a-f]+$/i, 'Invalid hex format'),\n }))\n .query(async ({ input }) => {\n const canary = await readVerifyFile(orgVaultRoot(input.orgId));\n // Sans canari local, rien à comparer : l'adoption reste possible, mais\n // elle ne peut pas être confirmée d'avance, et le dire vaut mieux que\n // laisser croire à une vérification qui n'a pas eu lieu.\n if (!canary) return { isCurrentKey: false, hasCanary: false };\n return {\n isCurrentKey: matchesCanary(canary, Buffer.from(input.keyHex, 'hex')),\n hasCanary: true,\n };\n }),\n\n /**\n * Submit and validate encryption key.\n * Attempts to decrypt existing data to validate the key.\n * Spawns the local agent if in local-simple mode.\n */\n submitEncryptionKey: publicProcedure\n .input(\n z.object({\n keyHex: z.string().length(64).regex(/^[0-9a-f]+$/i, 'Invalid hex format'),\n }),\n )\n .mutation(async ({ input }) => {\n try {\n // Set the key\n await setEncryptionKey(input.keyHex);\n\n // Validate by attempting to read encrypted data\n // If agents.json exists with encrypted data, this will decrypt it\n await agentStore.list();\n\n // Spawn the local agent now that the encryption key is available\n // (in local-simple mode, the agent couldn't spawn during server startup\n // because the key wasn't available yet)\n if (env.MODE === 'local-simple') {\n console.log('[setup] Encryption key validated, spawning local agent...');\n await agentSpawner.spawnLocalAgent();\n }\n\n return { success: true };\n } catch (err: unknown) {\n // If decryption fails, the key is invalid\n const message = err instanceof Error ? err.message : 'Unknown error';\n throw new Error(`Invalid encryption key: ${message}`);\n }\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { protectedProcedure, router, requireEnvAction, canEnvAction } from '../trpc.js';\nimport type { AuthContext } from '../trpc.js';\nimport { environmentStore } from '../../services/environment-store.js';\nimport { environmentOverridesStore } from '../../services/environment-overrides-store.js';\nimport { environmentResolver } from '../../services/environment-resolver.js';\nimport { projectStore } from '../../services/project-store.js';\nimport { serviceStore } from '../../services/service-store.js';\nimport { CreateEnvironmentSchema, UpdateEnvironmentSchema, VariableSchema, VariableOverrideSchema, MissingVariableReasonSchema } from '@runeya/packages-shared';\n\nexport const environmentRouter = router({\n list: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .query(async ({ input }) => {\n return await environmentStore.list(input.projectId, input.orgId);\n }),\n\n get: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .query(async ({ input }) => {\n const env = await environmentStore.get(input.id);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.id} not found` });\n return env;\n }),\n\n listByScope: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n scope: z.enum(['global', 'service']),\n }))\n .query(async ({ input }) => {\n return await environmentStore.listByScope(input.projectId, input.scope, input.orgId);\n }),\n\n findServiceEnvironment: protectedProcedure\n .input(z.object({ serviceId: z.string().max(128), globalEnvId: z.string().max(128) }))\n .query(async ({ input }) => {\n return await environmentStore.findServiceEnvironment(input.serviceId, input.globalEnvId);\n }),\n\n create: protectedProcedure\n // `orgId` accompagne le projet sans faire partie de l'environnement : il\n // dit dans quel coffre le poser quand l'id du projet répond pour plusieurs\n // organisations.\n .input(CreateEnvironmentSchema.extend({\n orgId: z.string().max(128).nullable().optional(),\n }))\n .mutation(async ({ input }) => {\n const { orgId, ...environment } = input;\n const target = { id: input.projectId, orgId };\n const env = await environmentStore.create(environment, orgId);\n\n // Add environment to project's environmentIds list\n const project = await projectStore.get(target);\n if (project && !project.environmentIds?.includes(env.id)) {\n await projectStore.addEnvironment(target, env.id);\n }\n\n // If creating a global env, auto-create service-scoped envs for each service in the project\n if (env.scope === 'global' && project) {\n for (const serviceId of project.serviceIds) {\n const service = await serviceStore.get(serviceId);\n if (!service) continue;\n // Include service-scoped envs from parent globals so inheritance chains work correctly\n const parentServiceEnvIds: string[] = [];\n for (const parentGlobalId of env.parentIds) {\n const parentServiceEnv = await environmentStore.findServiceEnvironment(serviceId, parentGlobalId);\n if (parentServiceEnv) {\n parentServiceEnvIds.push(parentServiceEnv.id);\n }\n }\n const svcEnv = await environmentStore.create({\n projectId: input.projectId,\n name: `${service.name} (${env.name})`,\n scope: 'service',\n reference: serviceId,\n activateOn: env.id,\n parentIds: [env.id, ...parentServiceEnvIds],\n variables: {},\n }, orgId);\n await projectStore.addEnvironment(target, svcEnv.id);\n }\n }\n\n return env;\n }),\n\n update: protectedProcedure\n .input(UpdateEnvironmentSchema)\n .mutation(async ({ input }) => {\n const existing = await environmentStore.get(input.id);\n if (!existing) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.id} not found` });\n\n const env = await environmentStore.update(input);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.id} not found` });\n\n // If a global environment was renamed, cascade to service-scoped environment names\n if (env.scope === 'global' && input.name && input.name !== existing.name) {\n // Le couple, déduit du coffre de l'environnement.\n const project = await projectStore.get(environmentStore.projectRefOf(env) ?? env.projectId);\n if (project) {\n const serviceNames = new Map<string, string>();\n for (const serviceId of project.serviceIds) {\n const service = await serviceStore.get(serviceId);\n if (service) serviceNames.set(serviceId, service.name);\n }\n await environmentStore.renameByActivateOn(env.id, input.name, serviceNames);\n }\n }\n\n return env;\n }),\n\n delete: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .mutation(async ({ input }) => {\n const env = await environmentStore.get(input.id);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.id} not found` });\n\n if (env.immutable) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Cannot delete immutable environment' });\n }\n\n // If deleting a global env, also delete all service-scoped envs that activateOn it\n if (env.scope === 'global') {\n await environmentStore.deleteByActivateOn(input.id);\n }\n\n const deleted = await environmentStore.delete(input.id);\n if (!deleted) throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Failed to delete environment' });\n\n // Remove environment from project\n await projectStore.removeEnvironment(environmentStore.projectRefOf(env) ?? env.projectId, input.id);\n\n return { success: true };\n }),\n\n resolve: protectedProcedure\n .input(z.object({ environmentId: z.string().max(128) }))\n .query(async ({ input, ctx }) => {\n const { includeSecrets } = requireEnvAction(ctx as AuthContext, input.environmentId, 'env:read');\n const env = await environmentStore.get(input.environmentId);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.environmentId} not found` });\n\n const resolved = await environmentResolver.resolveEnvironmentWithSources(input.environmentId);\n\n if (!includeSecrets) {\n // Strip secret values — replace with empty string to preserve variable shape\n const sanitized = { ...resolved };\n if (sanitized.variables) {\n sanitized.variables = Object.fromEntries(\n Object.entries(sanitized.variables).map(([id, v]) => [\n id,\n v.value?.isSecret ? { ...v, value: { ...v.value, value: '' } } : v,\n ]),\n );\n }\n return sanitized;\n }\n\n return resolved;\n }),\n\n resolveFlat: protectedProcedure\n .meta({ openapi: { method: 'GET', path: '/environments/{environmentId}/resolve-flat', tags: ['environments'], summary: 'Resolve environment variables as a flat key-value map', protect: true } })\n .input(z.object({ environmentId: z.string().max(128) }))\n .output(z.record(z.string(), z.string()))\n .query(async ({ input, ctx }) => {\n const { includeSecrets } = requireEnvAction(ctx as AuthContext, input.environmentId, 'env:read');\n const env = await environmentStore.get(input.environmentId);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.environmentId} not found` });\n\n const { env: resolved, envSecrets } = await environmentResolver.resolveEnvironment(input.environmentId);\n\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(resolved)) {\n if (!includeSecrets && envSecrets.includes(key)) {\n result[key] = '*****';\n } else {\n result[key] = value;\n }\n }\n return result;\n }),\n\n // --- Overrides (flat, by variableId) ---\n\n /**\n * Les variables qu'il reste à remplir sous un environnement : les siennes,\n * celles dont il hérite, et celles des environnements de service qui\n * s'activent avec lui.\n *\n * Aucune valeur n'en sort : uniquement les clés, leur description et le\n * motif. C'est ce que l'assistant de complétion affiche, et il n'a pas\n * besoin de connaître ce qui est déjà rempli ailleurs.\n */\n missingVariables: protectedProcedure\n .input(z.object({ environmentId: z.string().max(128) }))\n .query(async ({ input, ctx }) => {\n requireEnvAction(ctx as AuthContext, input.environmentId, 'env:read');\n const env = await environmentStore.get(input.environmentId);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.environmentId} not found` });\n\n const missing = await environmentResolver.findMissingForActiveEnvironment(input.environmentId);\n // Le contrôle d'entrée ne couvre que l'environnement demandé, alors que\n // le balayage remonte ses parents et descend dans ses environnements de\n // service. Chaque entrée est donc repassée au crible de son propre\n // environnement : pour l'app locale c'est toujours oui, pour une clé\n // bornée cela retire ce qu'elle n'a pas le droit de lire.\n return missing.filter((item) => canEnvAction(ctx as AuthContext, item.environmentId, 'env:read'));\n }),\n\n /**\n * Remplir une variable réclamée par l'assistant de complétion, sans toucher\n * au reste de sa définition.\n *\n * La destination dépend du motif, et c'est le serveur qui tranche parce que\n * lui seul a la définition sous les yeux :\n *\n * - `required` écrit une valeur **partagée** dans l'environnement qui définit\n * la variable, en préservant `pre`, `post` et tous ses drapeaux. Passer par\n * `upsertVariable` reviendrait à réécrire le slot entier depuis un client\n * qui n'en connaît qu'un morceau — un préfixe `postgres://` disparaîtrait.\n * - `overrideOnly` écrit une **surcharge machine**, qui ne quitte jamais ce\n * poste, en recopiant depuis la définition la forme (`pre`, `post`) et le\n * caractère secret que la surcharge ne porte pas d'elle-même.\n */\n fillVariable: protectedProcedure\n .input(z.object({\n environmentId: z.string().max(128),\n variableId: z.string().max(128),\n value: z.string().max(8192),\n reason: MissingVariableReasonSchema,\n }))\n .mutation(async ({ input, ctx }) => {\n requireEnvAction(ctx as AuthContext, input.environmentId, 'env:write');\n const env = await environmentStore.get(input.environmentId);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.environmentId} not found` });\n\n const variable = env.variables[input.variableId];\n if (!variable) throw new TRPCError({ code: 'NOT_FOUND', message: `Variable ${input.variableId} not found` });\n\n const slot = variable.value;\n if (input.reason === 'overrideOnly') {\n await environmentOverridesStore.setOverride(input.variableId, {\n value: { ...slot, value: input.value, required: false, overrideOnly: false },\n });\n return { success: true };\n }\n\n const result = await environmentStore.upsertVariable(input.environmentId, input.variableId, {\n ...variable,\n value: { ...slot, value: input.value },\n });\n if (!result) throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Failed to fill variable' });\n return { success: true };\n }),\n\n setOverride: protectedProcedure\n .input(z.object({\n variableId: z.string().max(128),\n // Only the value slot: the env var name comes from the variable\n // definition (a `key` sent by an older client is stripped here).\n variable: VariableOverrideSchema,\n }))\n .mutation(async ({ input }) => {\n await environmentOverridesStore.setOverride(input.variableId, input.variable);\n return { success: true };\n }),\n\n removeOverride: protectedProcedure\n .input(z.object({\n variableId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n await environmentOverridesStore.removeOverride(input.variableId);\n return { success: true };\n }),\n\n getOverrides: protectedProcedure\n .query(async () => {\n return await environmentOverridesStore.getAll();\n }),\n\n upsertVariable: protectedProcedure\n .meta({ openapi: { method: 'PUT', path: '/environments/{environmentId}/variables/{variableId}', tags: ['environments'], summary: 'Upsert a variable in an environment', protect: true } })\n .output(z.any())\n .input(z.object({\n environmentId: z.string().max(128),\n variableId: z.string().max(128),\n variable: VariableSchema,\n }))\n .mutation(async ({ input, ctx }) => {\n requireEnvAction(ctx as AuthContext, input.environmentId, 'env:write');\n const env = await environmentStore.get(input.environmentId);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.environmentId} not found` });\n const result = await environmentStore.upsertVariable(input.environmentId, input.variableId, input.variable);\n if (!result) throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Failed to update variable' });\n return result;\n }),\n\n /**\n * List everywhere a variable key is used inside a project: environments that\n * define it, and variables that reference it through {{environment.KEY}}.\n * Used by the UI to warn before editing a shared variable from a resolved view.\n */\n keyUsages: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n key: z.string().min(1).max(256),\n /** Environment holding the variable about to be edited — enables inherited-impact detection */\n environmentId: z.string().max(128).optional(),\n }))\n .query(async ({ input }) => {\n const environments = await environmentStore.list(input.projectId, input.orgId);\n const services = await serviceStore.list();\n const serviceName = (id?: string) => services.find(s => s.id === id)?.name;\n\n // Escape the key before embedding it in a regexp — it is user input.\n const escaped = input.key.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n // nosemgrep: detect-non-literal-regexp -- la clé est échappée juste au-dessus ; le motif reste linéaire (pas de quantificateur imbriqué)\n const refPattern = new RegExp(`\\\\{\\\\{environment\\\\.${escaped}\\\\}\\\\}`);\n\n const definedIn: Array<{ environmentId: string; environmentName: string; scope: string; serviceName?: string }> = [];\n const referencedBy: Array<{ environmentId: string; environmentName: string; scope: string; serviceName?: string; key: string }> = [];\n\n for (const env of environments) {\n const name = serviceName(env.reference);\n for (const variable of Object.values(env.variables ?? {})) {\n if (variable.key === input.key) {\n definedIn.push({\n environmentId: env.id,\n environmentName: env.name,\n scope: env.scope ?? 'global',\n ...(name ? { serviceName: name } : {}),\n });\n continue;\n }\n const slot = variable.value;\n if (refPattern.test(`${slot.pre}${slot.value}${slot.post}`)) {\n referencedBy.push({\n environmentId: env.id,\n environmentName: env.name,\n scope: env.scope ?? 'global',\n ...(name ? { serviceName: name } : {}),\n key: variable.key,\n });\n }\n }\n }\n\n // Indirect impact: environments that receive the variable through the\n // inheritance chain. We ask the resolver rather than re-deriving the\n // rules, so explicit parents, implicit service-ancestor inheritance and\n // dedup-by-key shadowing are all accounted for by construction.\n const inheritedBy: Array<{ environmentId: string; environmentName: string; scope: string; serviceName?: string }> = [];\n if (input.environmentId) {\n for (const env of environments) {\n if (env.id === input.environmentId) continue;\n try {\n const resolved = await environmentResolver.resolveEnvironmentWithSources(env.id);\n const inherits = Object.entries(resolved.variables).some(\n ([varId, variable]) =>\n variable.key === input.key\n && resolved.sources[varId]?.environmentId === input.environmentId,\n );\n if (inherits) {\n const name = serviceName(env.reference);\n inheritedBy.push({\n environmentId: env.id,\n environmentName: env.name,\n scope: env.scope ?? 'global',\n ...(name ? { serviceName: name } : {}),\n });\n }\n } catch {\n // Unresolvable environment (e.g. circular chain) — skip it\n }\n }\n }\n\n return { definedIn, referencedBy, inheritedBy };\n }),\n\n removeVariable: protectedProcedure\n .input(z.object({\n environmentId: z.string().max(128),\n variableId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n const env = await environmentStore.get(input.environmentId);\n if (!env) throw new TRPCError({ code: 'NOT_FOUND', message: `Environment ${input.environmentId} not found` });\n const result = await environmentStore.removeVariable(input.environmentId, input.variableId);\n if (!result) throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Failed to remove variable' });\n return result;\n }),\n});\n","import { promises as dns } from 'node:dns';\nimport { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { JSLogParserSchema, type JSLogParserDef, NotificationPreferencesSchema, SettingsSchema, nativeParsers, AIProviderSchema, type AIProvider, JSLogParser } from '@runeya/packages-shared';\nimport { settingsManager } from '../../services/settings-manager.js';\nimport { logParserStore } from '../../services/log-parser-store.js';\nimport { vaultOfProject } from '../../services/settings-scope.js';\nimport { env } from '../../config/env.js';\nimport { machineRoot } from '../../services/vault-resolver.js';\nimport { encryptValue, decryptValue, stableEncryptValue } from '../../services/crypto-helpers.js';\nimport { traefikManager } from '../../services/traefik-manager.js';\nimport { agentStore } from '../../services/agent-store.js';\nimport { agentManager } from '../../services/agent-manager.js';\nimport { TraefikConfigSchema } from '@runeya/packages-shared';\nimport { resolveWorkspaceCwd } from '../../services/workspace-cwd.js';\nimport { networkInfo, setLanMode } from '../../services/lan-mode.js';\nimport { companionDefaultPrompt } from '../../services/companion.js';\n\nconst NotificationPreferencesPatchSchema = NotificationPreferencesSchema.partial().strict();\n\n/**\n * Les parseurs tels qu'un écran les reçoit : les natifs de l'application, puis\n * ceux du coffre, chacun disant d'où il vient.\n *\n * L'origine n'est pas stockée — elle se déduit de l'endroit d'où la liste a été\n * lue — mais elle voyage, parce que modifier un parseur d'organisation change\n * le code qui tourne chez tous ses membres, et que l'écran doit pouvoir le dire.\n */\nfunction listWithOrigin(parsers: JSLogParserDef[], vault: string | undefined) {\n return [\n ...nativeParsers.map((p) => ({ ...p, origin: 'native' as const })),\n ...parsers.map((p) => ({ ...p, origin: vault ? ('org' as const) : ('machine' as const) })),\n ];\n}\n\nfunction maskApiKey(plaintext: string): string {\n if (plaintext.length <= 8) return '****';\n return plaintext.slice(0, 4) + '****' + plaintext.slice(-4);\n}\n\n/**\n * De quelle organisation on lit — ou écrit — les réglages.\n *\n * Les fournisseurs d'IA et les préférences de notification appartiennent à\n * l'organisation dont ils décrivent le travail, pas au poste. L'appelant dit\n * laquelle : soit directement, soit par le projet concerné, dont l'organisation\n * se déduit. Absent des deux, ce sont les réglages du poste — ceux d'une\n * machine qui ne travaille pour aucune organisation.\n */\nconst ScopeShape = {\n orgId: z.string().max(128).nullable().optional(),\n projectId: z.string().max(128).optional(),\n};\n\nasync function scopeOf(input?: { orgId?: string | null; projectId?: string }): Promise<string | undefined> {\n return input?.orgId ?? await vaultOfProject(input?.projectId);\n}\n\nexport const settingsRouter = router({\n /**\n * Get all settings\n */\n get: protectedProcedure.query(async () => {\n const settings = await settingsManager.getSettings();\n return settings;\n }),\n\n /**\n * Paths the server is running from (working directory + data directory).\n * Read-only, purely informational for the settings UI.\n */\n getPaths: protectedProcedure.query(async () => ({\n // The launch directory, not the process's current one — they are the same\n // today only because nothing calls chdir, which is exactly what must not be\n // relied on.\n cwd: await resolveWorkspaceCwd({}),\n dataDir: env.DATA_DIR,\n // Where cloud projects live: their vaults belong to the machine, not to\n // whichever directory the server happened to be started in.\n machineDir: machineRoot(),\n })),\n\n /**\n * Où le serveur écoute, et s'il est joignable depuis le réseau local.\n */\n getNetwork: protectedProcedure.query(() => networkInfo()),\n\n /**\n * Exposer — ou retirer — Runeya du réseau local, sans redémarrage.\n *\n * La socket d'écoute est rouverte sur place : les connexions en cours, dont\n * celle de l'onglet qui bascule, ne sont pas coupées. Le choix est mémorisé\n * dans les réglages, donc conservé au prochain démarrage.\n */\n setLanMode: protectedProcedure\n .input(z.object({ enabled: z.boolean() }))\n .mutation(async ({ input }) => {\n try {\n return await setLanMode(input.enabled);\n } catch (err) {\n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message: `Impossible de changer l'adresse d'écoute : ${(err as Error).message}`,\n });\n }\n }),\n\n /**\n * Update settings (mode, cloudUrl)\n */\n update: protectedProcedure\n .input(SettingsSchema.pick({ mode: true, cloudUrl: true, globalDocsPath: true }).partial())\n .mutation(async ({ input }) => {\n const current = await settingsManager.getSettings();\n const updated = {\n ...current,\n ...input,\n };\n await settingsManager.saveSettings(updated);\n return updated;\n }),\n\n /**\n * Get notification preferences\n */\n getNotificationPreferences: protectedProcedure\n .input(z.object(ScopeShape).optional())\n .query(async ({ input }) => {\n const priv = await settingsManager.getPrivateSettings(await scopeOf(input));\n return NotificationPreferencesSchema.parse(priv.notifications ?? {});\n }),\n\n /**\n * Update notification preferences (granular mute)\n */\n updateNotificationPreferences: protectedProcedure\n .input(NotificationPreferencesPatchSchema.extend(ScopeShape))\n .mutation(async ({ input }) => {\n const vault = await scopeOf(input);\n const priv = await settingsManager.getPrivateSettings(vault);\n const currentPrefs = NotificationPreferencesSchema.parse(priv.notifications ?? {});\n const updatedPrefs = {\n ...currentPrefs,\n ...input,\n };\n await settingsManager.savePrivateSettings({\n ...priv,\n notifications: updatedPrefs,\n }, vault);\n return updatedPrefs;\n }),\n\n /**\n * List all parsers\n *\n * Les natifs, puis ceux du coffre visé. L'origine accompagne chacun : un\n * parseur d'organisation se modifie pour toute l'équipe, et l'interface doit\n * pouvoir le dire avant que quelqu'un le change sans le savoir.\n */\n listParsers: protectedProcedure\n .input(z.object(ScopeShape).optional())\n .query(async ({ input }) => {\n const vault = await scopeOf(input);\n return listWithOrigin(await logParserStore.list(vault), vault);\n }),\n\n /**\n * Les parseurs du coffre visé, à chaque fois qu'ils changent.\n *\n * Les services arrivent en temps réel, et un parseur écrit par un collègue\n * atteint le disque tout aussi vite ; sans ce flux, seul l'écran resterait en\n * retard — affichant une liste dans laquelle le parseur qu'un service vient\n * de référencer n'existe pas encore.\n */\n onParsersChanged: protectedProcedure\n .input(z.object(ScopeShape).optional())\n .subscription(async function* ({ input, signal }) {\n const vault = await scopeOf(input);\n let pending = true;\n let wake: (() => void) | null = null;\n\n const off = logParserStore.onChanged((touched) => {\n // Un autre coffre ne regarde pas cet écran.\n if (touched !== vault) return;\n pending = true;\n if (wake) { wake(); wake = null; }\n });\n\n // Sans ce réveil, un client parti pendant l'attente laisserait le\n // générateur suspendu pour toujours — l'abandon ne franchit pas un\n // `await`, donc le désabonnement ci-dessous n'arriverait jamais.\n const onAbort = () => { if (wake) { wake(); wake = null; } };\n signal?.addEventListener('abort', onAbort);\n\n try {\n while (!signal?.aborted) {\n if (pending) {\n pending = false;\n // La même liste que `listParsers`, natifs compris : un abonné\n // remplace ce qu'il a reçu, et rendre moins ici ferait disparaître\n // les natifs de l'écran au premier changement.\n yield listWithOrigin(await logParserStore.list(vault), vault);\n } else {\n await new Promise<void>((resolve) => { wake = resolve; });\n }\n }\n } finally {\n off();\n signal?.removeEventListener('abort', onAbort);\n }\n }),\n\n /**\n * Get single parser by ID\n */\n getParser: protectedProcedure\n .input(z.object({ id: z.string().max(128), ...ScopeShape }))\n .query(async ({ input }) => {\n const parser = await logParserStore.get(input.id, await scopeOf(input));\n if (!parser) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Parser not found: ${input.id}` });\n }\n return parser;\n }),\n\n /**\n * Create new parser\n */\n createParser: protectedProcedure\n .input(\n JSLogParserSchema.omit({\n id: true,\n createdAt: true,\n updatedAt: true,\n }).extend(ScopeShape)\n )\n .mutation(async ({ input }) => {\n const { orgId, projectId, ...fields } = input;\n // Basic code validation (schema already validated forbiden patterns)\n if (!fields.code.trim()) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Parser code cannot be empty' });\n }\n return logParserStore.create(fields, await scopeOf({ orgId, projectId }));\n }),\n\n /**\n * Update existing parser\n */\n updateParser: protectedProcedure\n .input(\n JSLogParserSchema.omit({\n createdAt: true,\n updatedAt: true,\n }).partial()\n .required({ id: true })\n .extend(ScopeShape)\n )\n .mutation(async ({ input }) => {\n const { id, orgId, projectId, ...patch } = input;\n if (id.startsWith('native:')) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Cannot modify built-in parsers' });\n }\n if (patch.code !== undefined && !patch.code.trim()) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Parser code cannot be empty' });\n }\n const updated = await logParserStore.update(id, patch, await scopeOf({ orgId, projectId }));\n if (!updated) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Parser not found: ${id}` });\n }\n return updated;\n }),\n\n /**\n * Delete parser by ID\n */\n deleteParser: protectedProcedure\n .input(z.object({ id: z.string().max(128), ...ScopeShape }))\n .mutation(async ({ input }) => {\n if (input.id.startsWith('native:')) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Cannot delete built-in parsers' });\n }\n const deleted = await logParserStore.delete(input.id, await scopeOf(input));\n if (!deleted) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Parser not found: ${input.id}` });\n }\n return { deleted: true };\n }),\n\n // ---------------------------------------------------------------------------\n // AI Providers\n // ---------------------------------------------------------------------------\n\n // ---------------------------------------------------------------------------\n // Compagnon de relecture\n // ---------------------------------------------------------------------------\n\n /*\n * Réglages du POSTE, sans portée d'organisation (§9).\n *\n * Ils décrivent comment cette machine fait travailler ses agents. Rangés dans\n * un coffre d'organisation, un même poste aurait autant de compagnons que\n * d'organisations regardées — et le réglage changerait sous les yeux de\n * l'utilisateur au gré du projet ouvert.\n */\n getCompanionSettings: protectedProcedure\n .query(async () => {\n const settings = await settingsManager.getSettings();\n const c = settings.companion ?? { enabledByDefault: false };\n return {\n enabledByDefault: c.enabledByDefault ?? false,\n prompt: c.prompt ?? '',\n /**\n * Conservé dans la réponse pour ne pas casser un client déjà construit,\n * mais l'écran n'en fait plus un texte à modifier : le réglage ajoute\n * seulement des spécificités aux consignes Runeya.\n */\n defaultPrompt: companionDefaultPrompt(),\n };\n }),\n\n setCompanionSettings: protectedProcedure\n .input(z.object({\n enabledByDefault: z.boolean().optional(),\n // Rejeté au-delà, jamais tronqué : un prompt coupé produirait des\n // relectures incohérentes sans rien signaler.\n prompt: z.string().max(20_000).optional(),\n }))\n .mutation(async ({ input }) => {\n const settings = await settingsManager.getSettings();\n const current = settings.companion ?? { enabledByDefault: false };\n const prompt = input.prompt?.trim();\n await settingsManager.saveSettings({\n ...settings,\n companion: {\n enabledByDefault: input.enabledByDefault ?? current.enabledByDefault ?? false,\n // Vide = « celles de Runeya » : on efface le réglage plutôt que d'y\n // ranger une chaîne vide qui signifierait « aucune consigne ».\n ...(input.prompt === undefined\n ? (current.prompt ? { prompt: current.prompt } : {})\n : (prompt ? { prompt } : {})),\n },\n });\n return { ok: true };\n }),\n\n /**\n * List AI providers (API keys are masked)\n */\n listAIProviders: protectedProcedure\n .input(z.object(ScopeShape).optional())\n .query(async ({ input }) => {\n const vault = await scopeOf(input);\n const priv = await settingsManager.getPrivateSettings(vault);\n return (priv.aiProviders ?? []).map((p: AIProvider) => {\n let maskedKey = '(aucune)';\n if (p.encryptedApiKey) {\n try {\n maskedKey = maskApiKey(decryptValue(p.encryptedApiKey, vault));\n } catch { maskedKey = '(clé invalide)'; }\n }\n return { id: p.id, name: p.name, provider: p.provider, model: p.model, active: p.active, maskedKey, createdAt: p.createdAt, updatedAt: p.updatedAt };\n });\n }),\n\n /**\n * Create AI provider\n */\n createAIProvider: protectedProcedure\n .input(z.object({\n name: z.string().min(1).max(200),\n provider: AIProviderSchema.shape.provider,\n apiKey: z.string().max(500).optional(), // optional for providers like Ollama\n model: z.string().max(200).optional(),\n ...ScopeShape,\n }))\n .mutation(async ({ input }) => {\n if (input.provider !== 'ollama' && !input.apiKey?.trim()) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Une clé API est requise pour ce provider.' });\n }\n const vault = await scopeOf(input);\n const priv = await settingsManager.getPrivateSettings(vault);\n const id = `aiprovider-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;\n const now = new Date();\n const plainKey = input.apiKey ?? '';\n const newProvider: AIProvider = {\n id,\n name: input.name,\n provider: input.provider,\n // Chiffrée par la clé de l'organisation : c'est ce qui permet de\n // partager le fournisseur qu'elle paie sans partager la clé du poste.\n encryptedApiKey: plainKey ? encryptValue(plainKey, vault) : '',\n model: input.model,\n active: (priv.aiProviders ?? []).length === 0, // first one is active by default\n createdAt: now,\n updatedAt: now,\n };\n await settingsManager.savePrivateSettings({\n ...priv,\n aiProviders: [...(priv.aiProviders ?? []), newProvider],\n }, vault);\n return { ...newProvider, maskedKey: plainKey ? maskApiKey(plainKey) : '(aucune)', encryptedApiKey: undefined };\n }),\n\n /**\n * Update AI provider (apiKey optional — omit to keep existing)\n */\n updateAIProvider: protectedProcedure\n .input(z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200).optional(),\n provider: AIProviderSchema.shape.provider.optional(),\n apiKey: z.string().min(1).max(500).optional(),\n model: z.string().max(200).optional(),\n ...ScopeShape,\n }))\n .mutation(async ({ input }) => {\n const vault = await scopeOf(input);\n const priv = await settingsManager.getPrivateSettings(vault);\n const providers = priv.aiProviders ?? [];\n const idx = providers.findIndex((p: AIProvider) => p.id === input.id);\n if (idx === -1) throw new TRPCError({ code: 'NOT_FOUND', message: `AI provider not found: ${input.id}` });\n const existing = providers[idx];\n const encryptedApiKey = input.apiKey\n ? stableEncryptValue(input.apiKey, existing.encryptedApiKey, vault)\n : existing.encryptedApiKey;\n const updated: AIProvider = {\n ...existing,\n ...(input.name ? { name: input.name } : {}),\n ...(input.provider ? { provider: input.provider } : {}),\n ...(input.model !== undefined ? { model: input.model || undefined } : {}),\n encryptedApiKey,\n updatedAt: new Date(),\n };\n const newProviders = [...providers];\n newProviders[idx] = updated;\n await settingsManager.savePrivateSettings({ ...priv, aiProviders: newProviders }, vault);\n let maskedKey = '(aucune)';\n if (updated.encryptedApiKey) {\n try { maskedKey = maskApiKey(decryptValue(updated.encryptedApiKey, vault)); } catch { /* */ }\n }\n return { ...updated, maskedKey, encryptedApiKey: undefined };\n }),\n\n /**\n * Delete AI provider\n */\n deleteAIProvider: protectedProcedure\n .input(z.object({ id: z.string().min(1).max(128), ...ScopeShape }))\n .mutation(async ({ input }) => {\n const vault = await scopeOf(input);\n const priv = await settingsManager.getPrivateSettings(vault);\n const providers = priv.aiProviders ?? [];\n const filtered = providers.filter((p: AIProvider) => p.id !== input.id);\n if (filtered.length === providers.length) throw new TRPCError({ code: 'NOT_FOUND', message: `AI provider not found: ${input.id}` });\n // If deleted was active, promote first remaining to active\n const deletedWasActive = providers.find((p: AIProvider) => p.id === input.id)?.active ?? false;\n if (deletedWasActive && filtered.length > 0) filtered[0].active = true;\n await settingsManager.savePrivateSettings({ ...priv, aiProviders: filtered }, vault);\n return { deleted: true };\n }),\n\n /**\n * Set one provider as active (clears active flag on all others)\n */\n setActiveAIProvider: protectedProcedure\n .input(z.object({ id: z.string().min(1).max(128), ...ScopeShape }))\n .mutation(async ({ input }) => {\n const vault = await scopeOf(input);\n const priv = await settingsManager.getPrivateSettings(vault);\n const providers = priv.aiProviders ?? [];\n const idx = providers.findIndex((p: AIProvider) => p.id === input.id);\n if (idx === -1) throw new TRPCError({ code: 'NOT_FOUND', message: `AI provider not found: ${input.id}` });\n const updated = providers.map((p: AIProvider) => ({ ...p, active: p.id === input.id }));\n await settingsManager.savePrivateSettings({ ...priv, aiProviders: updated }, vault);\n return { id: input.id, active: true };\n }),\n\n // ---------------------------------------------------------------------------\n // Traefik config\n // ---------------------------------------------------------------------------\n\n /**\n * Get Traefik config for a specific agent (never returns credentials or cert key in plain text)\n */\n getAgentTraefikConfig: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .query(async ({ input }) => {\n const raw = agentStore.getTraefikConfig(input.agentId);\n const parsed = raw ? TraefikConfigSchema.safeParse(raw) : null;\n const config = parsed?.success ? parsed.data : null;\n return {\n enabled: config?.enabled ?? false,\n acmeEmail: config?.acmeEmail,\n wildcardDomain: config?.wildcardDomain,\n httpPort: config?.httpPort ?? 80,\n httpsPort: config?.httpsPort ?? 443,\n dnsProvider: config?.dnsProvider,\n hasDnsCredentials: Object.keys(config?.dnsCredentials ?? {}).length > 0,\n dnsCredentialKeys: Object.keys(config?.dnsCredentials ?? {}),\n hasCert: !!config?.encryptedCert,\n acmeStaging: config?.acmeStaging ?? false,\n };\n }),\n\n /**\n * Update Traefik config for a specific agent (credentials are encrypted before saving)\n */\n updateAgentTraefikConfig: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n enabled: z.boolean().optional(),\n acmeEmail: z.string().email().max(256).optional(),\n wildcardDomain: z.string().max(253).optional(),\n httpPort: z.number().int().min(1).max(65535).optional(),\n httpsPort: z.number().int().min(1).max(65535).optional(),\n dnsProvider: z.string().max(64).optional(),\n dnsCredentials: z.record(z.string().max(64), z.string().max(2048)).optional(),\n acmeStaging: z.boolean().optional(),\n }))\n .mutation(async ({ input }) => {\n const { agentId, ...fields } = input;\n const raw = agentStore.getTraefikConfig(agentId);\n const parsed = raw ? TraefikConfigSchema.safeParse(raw) : null;\n const existing = parsed?.success ? parsed.data : { enabled: false, dnsCredentials: {}, httpPort: 80, httpsPort: 443 };\n\n const encryptedCredentials = fields.dnsCredentials\n ? traefikManager.encryptDnsCredentials(fields.dnsCredentials)\n : existing.dnsCredentials;\n\n const updated = {\n ...existing,\n ...(fields.enabled !== undefined && { enabled: fields.enabled }),\n ...(fields.acmeEmail !== undefined && { acmeEmail: fields.acmeEmail }),\n ...(fields.wildcardDomain !== undefined && { wildcardDomain: fields.wildcardDomain }),\n ...(fields.httpPort !== undefined && { httpPort: fields.httpPort }),\n ...(fields.httpsPort !== undefined && { httpsPort: fields.httpsPort }),\n ...(fields.dnsProvider !== undefined && { dnsProvider: fields.dnsProvider }),\n ...(fields.acmeStaging !== undefined && { acmeStaging: fields.acmeStaging }),\n dnsCredentials: encryptedCredentials,\n };\n\n await agentStore.saveTraefikConfig(agentId, updated);\n\n // Déchiffrer les credentials avant push à l'agent\n const configToPush = {\n ...updated,\n dnsCredentials: traefikManager.decryptDnsCredentials(updated.dnsCredentials ?? {}),\n };\n // Push to connected agent\n await agentManager.pushTraefikConfig(agentId, configToPush);\n\n return { success: true };\n }),\n\n /**\n * Get Traefik config files content for a specific agent\n */\n getAgentTraefikConfigFiles: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .query(async ({ input }) => {\n return agentManager.agentQuery<{ static: string; dynamic: string }>(\n input.agentId,\n 'config.getTraefikConfigFiles',\n );\n }),\n\n getAgentTraefikFileTree: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .query(async ({ input }) => {\n return agentManager.agentQuery<Array<{ path: string; content: string }>>(\n input.agentId,\n 'config.getTraefikFileTree',\n );\n }),\n\n /**\n * Get Traefik container logs for a specific agent (snapshot)\n */\n getAgentTraefikLogs: protectedProcedure\n .input(z.object({ agentId: z.string().max(128), lines: z.number().int().min(1).max(500).default(100) }))\n .query(async ({ input }) => {\n const result = await agentManager.agentQuery<{ logs: string }>(\n input.agentId,\n 'config.getTraefikLogs',\n { lines: input.lines },\n );\n return result;\n }),\n\n /**\n * Stream Traefik logs in real-time (subscription, yields new lines every 500ms)\n */\n streamAgentTraefikLogs: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .subscription(async function* ({ input, signal }) {\n let seen = 0;\n while (!signal?.aborted) {\n try {\n const result = await agentManager.agentQuery<{ logs: string }>(\n input.agentId,\n 'config.getTraefikLogs',\n { lines: 500 },\n );\n const lines = result.logs?.trim() ? result.logs.split('\\n') : [];\n if (lines.length > seen) {\n const newLines = lines.slice(seen);\n seen = lines.length;\n yield { lines: newLines };\n }\n } catch {\n // agent not reachable yet — wait and retry\n }\n await new Promise(resolve => setTimeout(resolve, 500));\n }\n }),\n\n /**\n * Restart Traefik container on a specific agent (re-pushes config first to handle agent restarts)\n */\n restartAgentTraefik: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .mutation(async ({ input }) => {\n const raw = agentStore.getTraefikConfig(input.agentId);\n const parsed = raw ? TraefikConfigSchema.safeParse(raw) : null;\n const config = parsed?.success ? parsed.data : null;\n if (!config?.enabled) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Traefik non activé sur cet agent' });\n const decrypted = { ...config, dnsCredentials: traefikManager.decryptDnsCredentials(config.dnsCredentials ?? {}) };\n await agentManager.agentMutation(input.agentId, 'config.initTraefikConfig', decrypted, 5000);\n await agentManager.agentMutation(input.agentId, 'config.restartTraefik', undefined, 30000);\n return { success: true };\n }),\n\n /**\n * Force certificate renewal for a specific agent (wipes acme.json + restarts container)\n */\n renewAgentTraefikCert: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .mutation(async ({ input }) => {\n const raw = agentStore.getTraefikConfig(input.agentId);\n const parsed = raw ? TraefikConfigSchema.safeParse(raw) : null;\n const config = parsed?.success ? parsed.data : null;\n if (!config?.enabled) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Traefik non activé sur cet agent' });\n const decrypted = { ...config, dnsCredentials: traefikManager.decryptDnsCredentials(config.dnsCredentials ?? {}) };\n await agentManager.agentMutation(input.agentId, 'config.initTraefikConfig', decrypted, 5000);\n await agentManager.agentMutation(input.agentId, 'config.renewTraefikCert', undefined, 30000);\n return { success: true };\n }),\n\n /**\n * Validate Traefik configuration for a specific agent\n */\n validateAgentTraefikConfig: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .query(async ({ input }) => {\n const raw = agentStore.getTraefikConfig(input.agentId);\n const parsed = raw ? TraefikConfigSchema.safeParse(raw) : null;\n const config = parsed?.success ? parsed.data : null;\n\n const checks: Array<{ id: string; ok: boolean; message: string }> = [];\n\n // Config completeness checks (server-side)\n checks.push({\n id: 'enabled',\n ok: config?.enabled === true,\n message: config?.enabled ? 'Traefik activé' : 'Traefik non activé',\n });\n checks.push({\n id: 'domain',\n ok: !!config?.wildcardDomain?.trim(),\n message: config?.wildcardDomain ? `Domaine : ${config.wildcardDomain}` : 'Domaine wildcard non configuré',\n });\n checks.push({\n id: 'email',\n ok: !!config?.acmeEmail?.trim(),\n message: config?.acmeEmail ? `Email ACME : ${config.acmeEmail}` : 'Email ACME non configuré',\n });\n checks.push({\n id: 'dns_provider',\n ok: !!config?.dnsProvider?.trim(),\n message: config?.dnsProvider ? `Provider DNS : ${config.dnsProvider}` : 'Provider DNS non configuré',\n });\n checks.push({\n id: 'credentials',\n ok: Object.keys(config?.dnsCredentials ?? {}).length > 0,\n message: Object.keys(config?.dnsCredentials ?? {}).length > 0\n ? `${Object.keys(config!.dnsCredentials!).length} variable(s) configurée(s)`\n : 'Variables d\\'environnement DNS manquantes',\n });\n\n // DNS resolution check — only proceed if domain contains valid hostname characters.\n if (config?.wildcardDomain?.trim()) {\n const sanitisedDomain = config.wildcardDomain.replace(/^\\*\\./, '').replace(/[^a-z0-9.-]/gi, '');\n const probe = `probe.${sanitisedDomain}`;\n try {\n const addresses = await dns.resolve4(probe);\n const pointsToLocalhost = addresses.some(a => a === '127.0.0.1');\n checks.push({\n id: 'dns_resolution',\n ok: pointsToLocalhost,\n message: pointsToLocalhost\n ? `${probe} → 127.0.0.1 ✓`\n : `${probe} résout vers ${addresses.join(', ')} (attendu : 127.0.0.1)`,\n });\n } catch {\n checks.push({\n id: 'dns_resolution',\n ok: false,\n message: `${probe} ne résout pas — vérifiez le DNS wildcard`,\n });\n }\n }\n\n // Agent-side checks (Docker, container status)\n let agentChecks: Array<{ id: string; ok: boolean; message: string }> = [];\n try {\n const status = await agentManager.agentQuery<{\n containerRunning: boolean;\n dockerAvailable: boolean;\n configFileExists: boolean;\n cert: { hasCert: boolean; domain: string | null; expiresAt: string | null; daysLeft: number | null; expired: boolean };\n }>(input.agentId, 'config.getTraefikStatus');\n agentChecks.push({\n id: 'docker',\n ok: status.dockerAvailable,\n message: status.dockerAvailable ? 'Docker disponible' : 'Docker non trouvé dans PATH',\n });\n agentChecks.push({\n id: 'container',\n ok: status.containerRunning,\n message: status.containerRunning ? 'Container Traefik en cours d\\'exécution' : 'Container Traefik arrêté',\n });\n agentChecks.push({\n id: 'config_file',\n ok: status.configFileExists,\n message: status.configFileExists ? 'Fichier de configuration présent' : 'Fichier traefik.yml absent (enregistrez la config)',\n });\n const c = status.cert;\n if (c.hasCert && !c.expired) {\n agentChecks.push({\n id: 'ssl_cert',\n ok: true,\n message: `Certificat SSL valide pour ${c.domain} — expire dans ${c.daysLeft} jour(s) (${c.expiresAt})`,\n });\n } else if (c.hasCert && c.expired) {\n agentChecks.push({\n id: 'ssl_cert',\n ok: false,\n message: `Certificat SSL expiré pour ${c.domain} (depuis ${c.expiresAt})`,\n });\n } else {\n agentChecks.push({\n id: 'ssl_cert',\n ok: false,\n message: c.domain\n ? `Aucun certificat SSL pour ${c.domain} — Traefik doit être actif pour déclencher le challenge DNS-01`\n : 'Aucun certificat SSL trouvé dans acme.json',\n });\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const isNotFound = msg.includes('not found') || msg.includes('not connected');\n agentChecks.push({\n id: 'agent_reachable',\n ok: false,\n message: isNotFound\n ? `Agent non connecté au serveur (id: ${input.agentId})`\n : `Agent non joignable — ${msg}`,\n });\n }\n\n return { checks: [...checks, ...agentChecks] };\n }),\n\n /**\n * Test parser code: compile and run it against sample logs, return per-line results\n */\n testParser: protectedProcedure\n .input(\n z.object({\n code: z.string().max(50000),\n sampleLogs: z\n .array(\n z.object({\n raw: z.string().max(16384),\n stream: z.enum(['stdout', 'stderr']),\n })\n )\n .max(100)\n .default([]),\n })\n )\n .mutation(async ({ input }) => {\n // Compile via shared JSLogParser (same implementation as the agent)\n let jsParser: JSLogParser;\n try {\n jsParser = new JSLogParser([{\n id: 'preview',\n name: 'preview',\n code: input.code,\n enabled: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n }]);\n } catch (err) {\n throw new TRPCError({\n code: 'BAD_REQUEST',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n\n let idCounter = 0;\n const results = input.sampleLogs.map((log) => {\n const inputLine = {\n raw: log.raw,\n stream: log.stream as 'stdout' | 'stderr',\n level: 'info' as const,\n message: log.raw,\n hidden: false,\n metadata: {} as Record<string, unknown>,\n };\n\n try {\n const output = jsParser.parse({ ...inputLine });\n const logCard = output.json\n ? { id: `sim-${++idCounter}`, type: 'json', header: output.jsonHeader ?? 'JSON', state: 'self' as const, collapsable: true }\n : undefined;\n return { input: inputLine, output: { ...output, logCard }, error: null };\n } catch (err) {\n return { input: inputLine, output: null, error: err instanceof Error ? err.message : String(err) };\n }\n });\n\n return { validated: true, results };\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { execFile, spawn } from 'node:child_process';\nimport { stat } from 'node:fs/promises';\nimport { resolve, join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { SUPPORTED_EDITORS, EDITOR_BY_KEY } from '@runeya/packages-shared';\nimport { resolveCliInvocation, whichCommand } from '@runeya/packages-shared/node';\nimport { userConfigManager } from '../../services/user-config-manager.js';\nimport { serviceStore } from '../../services/service-store.js';\nimport { resolveWorkspaceCwd } from '../../services/workspace-cwd.js';\n\nfunction resolveCwd(cwd: string): string {\n const withHome = cwd.replace(/^~(\\/|$)/, `${homedir()}$1`);\n return withHome.replace(/\\$\\{(\\w+)\\}|\\$(\\w+)/g, (match, braced, plain) => {\n const name = braced ?? plain;\n return process.env[name] ?? match;\n });\n}\n\nasync function getServiceCwd(serviceId: string): Promise<string> {\n const services = await serviceStore.list();\n const service = services.find((s) => s.id === serviceId);\n if (!service) {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'Service not found' });\n }\n // Anchored on the project the service belongs to, rather than on whatever\n // directory the server was launched in.\n return resolveCwd(await resolveWorkspaceCwd({ serviceId }));\n}\n\nasync function isCommandAvailable(command: string): Promise<boolean> {\n return new Promise((resolve) => {\n execFile(whichCommand(), [command], { timeout: 5_000, windowsHide: true }, (err) => {\n resolve(!err);\n });\n });\n}\n\nexport const editorRouter = router({\n listAvailable: protectedProcedure.query(async () => {\n const results = await Promise.all(\n SUPPORTED_EDITORS.map(async (editor) => ({\n ...editor,\n installed: await isCommandAvailable(editor.command),\n })),\n );\n return results;\n }),\n\n getPreferences: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .query(async ({ input }) => {\n return userConfigManager.getEditorPreferences({ id: input.projectId, orgId: input.orgId });\n }),\n\n setDefault: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n editorKey: z.string().max(64),\n }))\n .mutation(async ({ input }) => {\n if (!EDITOR_BY_KEY.has(input.editorKey)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: `Unknown editor: ${input.editorKey}` });\n }\n await userConfigManager.setEditorPreference(\n { id: input.projectId, orgId: input.orgId }, 'default', input.editorKey,\n );\n return { success: true };\n }),\n\n setServiceEditor: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n serviceId: z.string().max(128),\n editorKey: z.string().max(64),\n }))\n .mutation(async ({ input }) => {\n if (!EDITOR_BY_KEY.has(input.editorKey)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: `Unknown editor: ${input.editorKey}` });\n }\n await userConfigManager.setEditorPreference(\n { id: input.projectId, orgId: input.orgId }, input.serviceId, input.editorKey,\n );\n return { success: true };\n }),\n\n removeServiceEditor: protectedProcedure\n .input(z.object({\n projectId: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n serviceId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n await userConfigManager.removeEditorPreference(\n { id: input.projectId, orgId: input.orgId }, input.serviceId,\n );\n return { success: true };\n }),\n\n open: protectedProcedure\n .input(z.object({\n editorKey: z.string().max(64),\n path: z.string().max(4096),\n }))\n .mutation(async ({ input }) => {\n const editor = EDITOR_BY_KEY.get(input.editorKey);\n if (!editor) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: `Unknown editor: ${input.editorKey}` });\n }\n\n // Expand ~ and $VAR/${VAR} from process.env, then resolve relative paths\n const expanded = input.path\n .replace(/^~(\\/|$)/, `${process.env['HOME'] ?? '/tmp'}$1`)\n .replace(/\\$\\{(\\w+)\\}|\\$(\\w+)/g, (_, a, b) => process.env[a || b] ?? '');\n const resolvedPath = resolve(expanded || '.');\n\n // Validate path exists (directory or file)\n try {\n await stat(resolvedPath);\n } catch (err) {\n if (err instanceof TRPCError) throw err;\n throw new TRPCError({ code: 'BAD_REQUEST', message: `Path does not exist: ${resolvedPath}` });\n }\n\n // Windows : `code`, `cursor` & co sont des shims `.cmd` — inchangé sur POSIX.\n const invocation = resolveCliInvocation(editor.command, [resolvedPath]);\n const child = spawn(invocation.command, invocation.args, {\n shell: false,\n detached: true,\n stdio: 'ignore',\n windowsHide: true,\n });\n child.unref();\n\n return { success: true };\n }),\n\n openFile: protectedProcedure\n .input(z.object({\n editorKey: z.string().max(64),\n serviceId: z.string().max(128),\n relativePath: z.string().max(4096),\n }))\n .mutation(async ({ input }) => {\n const editor = EDITOR_BY_KEY.get(input.editorKey);\n if (!editor) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: `Unknown editor: ${input.editorKey}` });\n }\n\n const cwd = await getServiceCwd(input.serviceId);\n const filePath = join(cwd, input.relativePath);\n\n // Prevent path traversal\n if (!filePath.startsWith(cwd)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Path traversal not allowed' });\n }\n\n try {\n await stat(filePath);\n } catch {\n throw new TRPCError({ code: 'BAD_REQUEST', message: `File does not exist: ${filePath}` });\n }\n\n // Windows : `code`, `cursor` & co sont des shims `.cmd` — inchangé sur POSIX.\n const invocation = resolveCliInvocation(editor.command, [filePath]);\n const child = spawn(invocation.command, invocation.args, {\n shell: false,\n detached: true,\n stdio: 'ignore',\n windowsHide: true,\n });\n child.unref();\n\n return { success: true };\n }),\n});\n","import { readFile, writeFile, rename, mkdir, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { z } from 'zod';\nimport { projectKey, type ProjectRef } from './project-key.js';\n\nconst CONFIG_DIR = join(homedir(), '.runeya');\nconst CONFIG_FILE = 'runeya.conf';\n\nconst EditorPreferencesSchema = z.object({\n default: z.string().max(64).optional(),\n}).catchall(z.string().max(64))\n .refine((obj) => Object.keys(obj).length <= 500, 'Too many editor preferences');\n\nconst ProjectSettingsSchema = z.object({\n settings: z.object({\n editors: EditorPreferencesSchema.optional(),\n }).optional(),\n});\n\nconst UserConfigSchema = z.record(\n z.string().max(128),\n ProjectSettingsSchema,\n).refine((obj) => Object.keys(obj).length <= 100, 'Too many projects in config');\n\ntype UserConfig = z.infer<typeof UserConfigSchema>;\n\n/**\n * Les préférences sont rangées par projet, et un projet est désigné par le\n * couple (organisation, projet) : deux projets de même id, dans deux\n * organisations, partageaient sinon les mêmes préférences d'éditeur. Les\n * entrées écrites par une version antérieure (id nu) sont encore lues.\n */\nfunction configKey(ref: ProjectRef): string {\n return projectKey(ref);\n}\n\nclass UserConfigManager {\n private config: UserConfig | null = null;\n\n private async ensureDir(): Promise<void> {\n await mkdir(CONFIG_DIR, { recursive: true });\n }\n\n private async atomicWrite(data: unknown): Promise<void> {\n await this.ensureDir();\n const filePath = join(CONFIG_DIR, CONFIG_FILE);\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 async getConfig(): Promise<UserConfig> {\n if (!this.config) {\n try {\n const raw = await readFile(join(CONFIG_DIR, CONFIG_FILE), 'utf-8');\n const parsed = UserConfigSchema.safeParse(JSON.parse(raw));\n this.config = parsed.success ? parsed.data : {};\n } catch {\n this.config = {};\n }\n }\n return this.config;\n }\n\n async saveConfig(config: UserConfig): Promise<void> {\n this.config = config;\n await this.atomicWrite(config);\n }\n\n async getEditorPreferences(ref: ProjectRef): Promise<Record<string, string>> {\n const config = await this.getConfig();\n return config[configKey(ref)]?.settings?.editors ?? config[ref.id]?.settings?.editors ?? {};\n }\n\n async setEditorPreference(ref: ProjectRef, target: string, editorKey: string): Promise<void> {\n const config = await this.getConfig();\n const key = configKey(ref);\n if (!config[key]) config[key] = { settings: config[ref.id]?.settings };\n if (!config[key].settings) config[key].settings = {};\n if (!config[key].settings!.editors) config[key].settings!.editors = {};\n config[key].settings!.editors![target] = editorKey;\n await this.saveConfig(config);\n }\n\n async removeEditorPreference(ref: ProjectRef, target: string): Promise<void> {\n const config = await this.getConfig();\n const editors = config[configKey(ref)]?.settings?.editors;\n if (editors && target in editors) {\n delete editors[target];\n await this.saveConfig(config);\n }\n }\n}\n\nexport const userConfigManager = new UserConfigManager();\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport { protectedProcedure, router } from '../trpc.js';\nimport { apiKeyStore, maskApiKey } from '../../services/api-key-store.js';\nimport { ApiKeyScopeSchema } from '@runeya/packages-shared';\nimport { resolveWorkspaceCwd } from '../../services/workspace-cwd.js';\n\nconst ALLOWED_SKILL_PATHS = new Set([\n '.claude/skills/runeya/SKILL.md',\n '.cursor/rules/runeya.mdc',\n '.windsurf/rules/runeya.md',\n]);\n\nconst KeyInputSchema = z.object({\n name: z.string().min(1).max(200),\n scopes: ApiKeyScopeSchema,\n isPublic: z.boolean().default(false),\n});\n\nexport const apiKeysRouter = router({\n list: protectedProcedure\n .query(() => apiKeyStore.list()),\n\n create: protectedProcedure\n // `orgId` n'est ajouté qu'à la création : changer de propriétaire déplace la\n // clé d'un coffre à l'autre, ce qui n'est pas une modification comme une\n // autre et mérite sa propre opération.\n .input(KeyInputSchema.extend({ orgId: z.string().min(1).max(128).nullable().optional() }))\n .mutation(({ input }) =>\n apiKeyStore.create(input.name, input.scopes, input.isPublic, input.orgId ?? null),\n ),\n\n /**\n * Renvoie le secret d'une seule clé, sur demande explicite. `list` ne le\n * contient pas : une clé ne doit jamais être re-servie en masse.\n */\n reveal: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .query(async ({ input }) => {\n const key = await apiKeyStore.reveal(input.id);\n if (!key) throw new TRPCError({ code: 'NOT_FOUND', message: 'API key not found' });\n return { key };\n }),\n\n update: protectedProcedure\n .input(KeyInputSchema.extend({ id: z.string().max(128) }))\n .mutation(async ({ input }) => {\n const updated = await apiKeyStore.update(input.id, input.name, input.scopes, input.isPublic);\n if (!updated) throw new TRPCError({ code: 'NOT_FOUND', message: 'API key not found' });\n // Un renommage n'est pas une raison de re-révéler le secret.\n return maskApiKey(updated);\n }),\n\n remove: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .mutation(async ({ input }) => {\n const removed = await apiKeyStore.remove(input.id);\n if (!removed) throw new TRPCError({ code: 'NOT_FOUND', message: 'API key not found' });\n return { success: true };\n }),\n\n renewKey: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .mutation(async ({ input }) => {\n const renewed = await apiKeyStore.renewKey(input.id);\n if (!renewed) throw new TRPCError({ code: 'NOT_FOUND', message: 'API key not found' });\n return renewed;\n }),\n\n writeSkillFile: protectedProcedure\n .input(z.object({\n relativePath: z.string().max(256),\n content: z.string().max(32768),\n }))\n .mutation(async ({ input }) => {\n if (!ALLOWED_SKILL_PATHS.has(input.relativePath)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Chemin non autorisé' });\n }\n // The launch directory, taken from the vault rather than from the process:\n // a skill file must land where Runeya was started, whatever the process's\n // own directory happens to be.\n const abs = join(await resolveWorkspaceCwd({}), input.relativePath);\n await mkdir(dirname(abs), { recursive: true });\n await writeFile(abs, input.content, { encoding: 'utf-8', mode: 0o644 });\n return { path: input.relativePath };\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport Anthropic from '@anthropic-ai/sdk';\nimport OpenAI from 'openai';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { serviceStore } from '../../services/service-store.js';\nimport { resolveWorkspaceCwd, resolveAgentCwd } from '../../services/workspace-cwd.js';\nimport { agentManager } from '../../services/agent-manager.js';\nimport { getActiveProvider, DEFAULT_MODELS, OPENAI_COMPAT_BASE_URLS } from '../../services/ai-provider-utils.js';\nimport { vaultOfProject } from '../../services/settings-scope.js';\nimport { resolveEffectiveAgentId } from './service.js';\nimport { OptionalProviderIdSchema } from '../shared-schemas.js';\n\nconst SERVICE_ID_SCHEMA = z.string().max(128);\nconst SAFE_PATH_SCHEMA = z\n .string()\n .min(1)\n .max(4096)\n .refine((p) => !p.startsWith('/') && !p.includes('../'), {\n message: 'Path must be relative and not traverse up',\n });\nconst REMOTE_SCHEMA = z.string().min(1).max(128).regex(/^[a-zA-Z0-9_\\-.]+$/);\nconst BRANCH_SCHEMA = z.string().min(1).max(256).regex(/^[a-zA-Z0-9._\\-/]+$/);\n\n/**\n * Resolve the effective agentId and absolute cwd for a service.\n * Throws if service not found or no agent is configured.\n */\nasync function resolveServiceContext(serviceId: string): Promise<{ agentId: string; cwd: string }> {\n const service = await serviceStore.get(serviceId);\n if (!service) {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'Service not found' });\n }\n const agentId = await resolveEffectiveAgentId(service);\n if (!agentId) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'No agent configured for this service' });\n }\n // Anchored on the project when the service's cwd is relative; a `~`/`$VAR`\n // cwd comes back untouched, since only the agent can expand it.\n return { agentId, cwd: await resolveWorkspaceCwd({ serviceId }) };\n}\n\n// Shared input shape: a git target is EITHER a service (serviceId) OR an agent's\n// own repository (agentId → cwd '.'). The latter lets the AI chat reuse this\n// view against the agent's working directory when no service is attached.\nconst gitTargetShape = {\n serviceId: SERVICE_ID_SCHEMA.optional(),\n agentId: z.string().max(128).optional(),\n /** Anchors on a project when no service is targeted (e.g. from the AI chat). */\n projectId: z.string().max(128).optional(),\n /** Son organisation : un id de projet seul peut en nommer un par organisation. */\n orgId: z.string().max(128).nullable().optional(),\n};\n\n/**\n * Resolve the effective agentId + cwd from a git target. Prefers serviceId when\n * present; otherwise targets the agent's own working directory (cwd '.').\n */\nasync function resolveGitContext(input: {\n serviceId?: string; agentId?: string; projectId?: string; orgId?: string | null;\n}): Promise<{ agentId: string; cwd: string }> {\n if (input.serviceId) return resolveServiceContext(input.serviceId);\n // No service: target an agent's own working directory (cwd '.'). Fall back to\n // the default agent when no explicit agentId is given (e.g. a chat conversation\n // that let the server pick the agent).\n const agentId = input.agentId ?? agentManager.getDefaultAgentId();\n if (!agentId) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'No agent available' });\n }\n // A project anchors the target. Without one, '.' — the AGENT's own directory,\n // which it resolves itself and which may not be on this machine at all.\n const cwd = await resolveAgentCwd({ projectId: input.projectId, orgId: input.orgId }) ?? '.';\n return { agentId, cwd };\n}\n\nexport const gitRouter = router({\n /** Get full git status */\n status: protectedProcedure\n .input(z.object({ ...gitTargetShape }))\n .query(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentQuery(agentId, 'git.status', { cwd });\n }),\n\n /** Get commit log */\n log: protectedProcedure\n .input(z.object({ ...gitTargetShape,limit: z.number().int().min(1).max(200).default(50) }))\n .query(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentQuery(agentId, 'git.log', { cwd, limit: input.limit });\n }),\n\n /** List local and remote branches */\n branches: protectedProcedure\n .input(z.object({ ...gitTargetShape }))\n .query(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentQuery(agentId, 'git.branches', { cwd });\n }),\n\n /** Checkout a branch */\n checkout: protectedProcedure\n .input(z.object({ ...gitTargetShape,branch: BRANCH_SCHEMA, create: z.boolean().default(false) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.checkout', { cwd, branch: input.branch, create: input.create });\n }),\n\n /** Stage files */\n stage: protectedProcedure\n .input(z.object({ ...gitTargetShape,paths: z.array(SAFE_PATH_SCHEMA).min(1).max(500) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.stage', { cwd, paths: input.paths });\n }),\n\n /** Stage all files */\n stageAll: protectedProcedure\n .input(z.object({ ...gitTargetShape }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.stageAll', { cwd });\n }),\n\n /** Unstage files */\n unstage: protectedProcedure\n .input(z.object({ ...gitTargetShape,paths: z.array(SAFE_PATH_SCHEMA).min(1).max(500) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.unstage', { cwd, paths: input.paths });\n }),\n\n /** Unstage all files */\n unstageAll: protectedProcedure\n .input(z.object({ ...gitTargetShape }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.unstageAll', { cwd });\n }),\n\n /** Commit staged changes */\n commit: protectedProcedure\n .input(z.object({ ...gitTargetShape,message: z.string().min(1).max(4096) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.commit', { cwd, message: input.message });\n }),\n\n /** Push to remote */\n push: protectedProcedure\n .input(z.object({ ...gitTargetShape,remote: REMOTE_SCHEMA.default('origin'), setUpstream: z.boolean().default(false) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.push', { cwd, remote: input.remote, setUpstream: input.setUpstream });\n }),\n\n /** Pull from remote */\n pull: protectedProcedure\n .input(z.object({ ...gitTargetShape,remote: REMOTE_SCHEMA.default('origin') }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.pull', { cwd, remote: input.remote });\n }),\n\n /** Fetch from remote */\n fetch: protectedProcedure\n .input(z.object({ ...gitTargetShape,remote: REMOTE_SCHEMA.default('origin') }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.fetch', { cwd, remote: input.remote });\n }),\n\n /** Get diff for a file or the whole index */\n diff: protectedProcedure\n .input(z.object({\n ...gitTargetShape,\n path: z.string().max(4096).optional(),\n staged: z.boolean().default(false),\n untracked: z.boolean().default(false),\n }))\n .query(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentQuery(agentId, 'git.diff', { cwd, path: input.path, staged: input.staged, untracked: input.untracked });\n }),\n\n /** Discard changes to working tree files */\n discard: protectedProcedure\n .input(z.object({ ...gitTargetShape,paths: z.array(SAFE_PATH_SCHEMA).min(1).max(500) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.discard', { cwd, paths: input.paths });\n }),\n\n /** Generate a commit message from staged diffs using AI (diff fetched from agent, AI runs on server) */\n generateCommitMessage: protectedProcedure\n .input(z.object({ ...gitTargetShape, providerId: OptionalProviderIdSchema, model: z.string().max(200).optional() }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n const { diff } = await agentManager.agentQuery<{ diff: string }>(agentId, 'git.stagedDiff', { cwd });\n\n if (!diff.trim()) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'No staged changes to generate a commit message from' });\n }\n\n // Falls back to the default (active) provider when the caller doesn't pick one.\n // Les fournisseurs sont ceux de l'organisation du projet visé : l'appel\n // porte déjà le couple, il n'y a rien à deviner.\n const active = await getActiveProvider(\n input.providerId,\n input.orgId ?? await vaultOfProject(input.projectId),\n );\n if (!active) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'No AI provider configured' });\n }\n\n const systemPrompt = `You are a git commit message generator. Given a git diff, write a concise and meaningful conventional commit message (e.g. feat:, fix:, refactor:, chore:, docs:, style:, test:).\nRules:\n- First line: type(optional scope): short summary (max 72 chars)\n- Optionally add a blank line and a brief body if the changes are complex\n- Write in English\n- Return ONLY the commit message, nothing else`;\n\n const { provider, plaintextKey } = active;\n const model = input.model || provider.model || DEFAULT_MODELS[provider.provider] || 'claude-opus-4-6';\n\n if (provider.provider === 'anthropic') {\n const client = new Anthropic({ apiKey: plaintextKey });\n const res = await client.messages.create({\n model,\n max_tokens: 512,\n system: systemPrompt,\n messages: [{ role: 'user', content: diff }],\n });\n const block = res.content[0];\n return { message: block?.type === 'text' ? block.text.trim() : '' };\n }\n\n if (provider.provider in OPENAI_COMPAT_BASE_URLS) {\n const baseURL = OPENAI_COMPAT_BASE_URLS[provider.provider]!;\n const client = new OpenAI({ apiKey: plaintextKey || 'ollama', baseURL });\n const res = await client.chat.completions.create({\n model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: diff },\n ],\n });\n return { message: res.choices[0]?.message?.content?.trim() ?? '' };\n }\n\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Unsupported AI provider' });\n }),\n\n /** Merge a branch into the current branch */\n merge: protectedProcedure\n .input(z.object({ ...gitTargetShape,branch: BRANCH_SCHEMA, noFf: z.boolean().default(false) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.merge', { cwd, branch: input.branch, noFf: input.noFf });\n }),\n\n /** Rebase current branch onto another branch */\n rebase: protectedProcedure\n .input(z.object({ ...gitTargetShape,branch: BRANCH_SCHEMA }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.rebase', { cwd, branch: input.branch });\n }),\n\n /** List stash entries */\n stashList: protectedProcedure\n .input(z.object({ ...gitTargetShape }))\n .query(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentQuery(agentId, 'git.stashList', { cwd });\n }),\n\n /** Stash current changes */\n stashPush: protectedProcedure\n .input(z.object({ ...gitTargetShape,message: z.string().max(4096).optional(), includeUntracked: z.boolean().default(true) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.stashPush', { cwd, message: input.message, includeUntracked: input.includeUntracked });\n }),\n\n /** Pop a stash entry */\n stashPop: protectedProcedure\n .input(z.object({ ...gitTargetShape,index: z.number().int().min(0).max(1000).default(0) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.stashPop', { cwd, index: input.index });\n }),\n\n /** Apply a stash entry without dropping it */\n stashApply: protectedProcedure\n .input(z.object({ ...gitTargetShape,index: z.number().int().min(0).max(1000).default(0) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.stashApply', { cwd, index: input.index });\n }),\n\n /** Drop a stash entry */\n stashDrop: protectedProcedure\n .input(z.object({ ...gitTargetShape,index: z.number().int().min(0).max(1000).default(0) }))\n .mutation(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentMutation(agentId, 'git.stashDrop', { cwd, index: input.index });\n }),\n\n /** Watch .git/ for changes and stream updated status */\n onStatusChange: protectedProcedure\n .input(z.object({ ...gitTargetShape }))\n .subscription(async function* ({ input }) {\n const { agentId, cwd } = await resolveGitContext(input);\n\n const queue: unknown[] = [];\n let resolve: (() => void) | null = null;\n let done = false;\n\n let unsubscribe: (() => void) | undefined;\n try {\n unsubscribe = agentManager.agentSubscribe(\n agentId,\n 'git.onStatusChange',\n { cwd },\n (data) => {\n queue.push(data);\n if (resolve) { resolve(); resolve = null; }\n },\n () => {\n done = true;\n if (resolve) { resolve(); resolve = null; }\n },\n );\n } catch (err) {\n throw new TRPCError({\n code: 'BAD_REQUEST',\n message: `Cannot subscribe to git status: ${(err as Error).message}`,\n });\n }\n\n try {\n while (!done || queue.length > 0) {\n if (queue.length > 0) {\n yield queue.shift()!;\n } else {\n await new Promise<void>((r) => { resolve = r; });\n }\n }\n } finally {\n unsubscribe?.();\n }\n }),\n\n /** List remotes */\n remotes: protectedProcedure\n .input(z.object({ ...gitTargetShape }))\n .query(async ({ input }) => {\n const { agentId, cwd } = await resolveGitContext(input);\n return agentManager.agentQuery(agentId, 'git.remotes', { cwd });\n }),\n});\n","import { randomUUID } from 'node:crypto';\nimport { TRPCError } from '@trpc/server';\nimport { z } from 'zod';\nimport { ScenarioNodeSchema, ScenarioGroupSchema } from '@runeya/packages-shared';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { createOrBadRequest, deleteOrNotFound, getOrNotFound, updateOrThrow } from '../crud-procedure-utils.js';\nimport { streamWithActiveProvider } from '../ai-generation-procedure-utils.js';\nimport {\n ConversationIdSchema,\n DescriptionSchema,\n Id128Schema,\n NameSchema,\n OptionalProviderIdSchema,\n} from '../shared-schemas.js';\nimport { vaultOfProject } from '../../services/settings-scope.js';\nimport { scenarioStore } from '../../services/scenario-store.js';\nimport { scenarioRunStore } from '../../services/scenario-run-store.js';\nimport { runScenario, tapBus, isScenarioRunning, abortScenario, resolveNodeInput } from '../../services/scenario-runner.js';\nimport { listPresets, getPreset } from '../../services/scenario-presets.js';\n\n// ─── AI generation helpers ────────────────────────────────────────────────────\n\nconst SCENARIO_SYSTEM_PROMPT = `You are an scenario org-chart builder assistant. You generate JSON structures representing an scenario hierarchy.\n\nIMPORTANT: Respond with ONLY a valid JSON object. No markdown, no code fences, no explanation. Pure JSON only.\n\nOutput schema:\n{\n \"leaderId\": \"string — id of the leader node\",\n \"groups\": [{ \"id\": \"string\", \"name\": \"string\", \"position\": { \"x\": number, \"y\": number }, \"width\": number, \"height\": number }],\n \"nodes\": [{ \"id\": \"string\", \"label\": \"string\", \"role\": \"manager|engineer|designer|analyst|qa|devops|product|writer|researcher|other\", \"groupId\": \"string (must match a group id)\", \"parentId\": \"string|null (null only for the leader)\", \"prompt\": \"string — detailed role description and instructions for this AI agent\", \"autoGenerated\": true, \"canAddNode\": false, \"position\": { \"x\": number, \"y\": number } }]\n}\n\nRules:\n- Every node MUST have a groupId that references an existing group id.\n- Exactly one node is the leader: parentId=null, their id = leaderId.\n- All other nodes MUST have parentId set to their manager's id.\n- The leader MUST always be in the group with id \"group-management\" and name \"Management\".\n- The leader MUST always have role \"manager\".\n- Use role to reflect each node's actual function: managers coordinate and delegate (never implement), engineers write code, etc.\n- Use short readable ids: \"group-engineering\", \"node-alice\", etc.\n- Groups: position spaced 400px apart (e.g. x=0, x=400, x=800). width >= 300, height >= 200.\n- Nodes positions are relative to their group: x/y in 30-260 range.\n- The \"prompt\" field must be detailed: role, responsibilities, communication style, expected outputs.`;\n\nfunction buildScenarioUserMessage(\n userPrompt: string,\n current?: { leaderId: string; groups: unknown[]; nodes: unknown[] },\n): string {\n if (current && (current.groups.length > 0 || current.nodes.length > 0)) {\n return `Current scenario:\\n${JSON.stringify(current, null, 2)}\\n\\nUser request: ${userPrompt}\\n\\nModify the scenario. Keep existing ids when possible.`;\n }\n return `Generate an scenario org-chart based on: ${userPrompt}`;\n}\n\n/**\n * L'organisation dont on lit — ou écrit — les scénarios : ils décrivent ses\n * services. Donnée directement, ou déduite du projet concerné. Absente des\n * deux, ce sont ceux du poste.\n */\nconst ScopeShape = {\n orgId: z.string().max(128).nullable().optional(),\n projectId: Id128Schema.optional(),\n};\n\nasync function scopeOf(input?: { orgId?: string | null; projectId?: string }): Promise<string | undefined> {\n return input?.orgId ?? await vaultOfProject(input?.projectId);\n}\n\nexport const scenarioRouter = router({\n list: protectedProcedure\n .input(z.object(ScopeShape).optional())\n .query(async ({ input }) => scenarioStore.list(await scopeOf(input))),\n\n get: protectedProcedure\n .input(z.object({ id: Id128Schema, ...ScopeShape }))\n .query(async ({ input }) => getOrNotFound(\n async () => scenarioStore.get(input.id, await scopeOf(input)),\n 'Scenario not found',\n )),\n\n create: protectedProcedure\n .input(z.object({\n name: NameSchema,\n icon: z.string().max(64).optional(),\n description: DescriptionSchema.optional(),\n leaderId: Id128Schema,\n groups: z.array(ScenarioGroupSchema).max(100).optional(),\n nodes: z.array(ScenarioNodeSchema).min(1).max(500),\n traversalMode: z.enum(['hierarchical', 'topological']).optional(),\n presetId: z.string().max(128).optional(),\n isPublished: z.boolean().optional(),\n ...ScopeShape,\n }))\n .mutation(({ input }) => {\n const now = Date.now();\n return createOrBadRequest(async () => scenarioStore.create({\n id: randomUUID(),\n name: input.name,\n icon: input.icon,\n description: input.description,\n leaderId: input.leaderId,\n groups: input.groups ?? [],\n nodes: input.nodes,\n traversalMode: input.traversalMode ?? 'hierarchical',\n presetId: input.presetId,\n isPublished: input.isPublished ?? false,\n createdAt: now,\n updatedAt: now,\n }));\n }),\n\n update: protectedProcedure\n .input(z.object({\n id: Id128Schema,\n name: NameSchema.optional(),\n icon: z.string().max(64).optional(),\n description: DescriptionSchema.optional(),\n leaderId: Id128Schema.optional(),\n groups: z.array(ScenarioGroupSchema).max(100).optional(),\n nodes: z.array(ScenarioNodeSchema).min(1).max(500).optional(),\n traversalMode: z.enum(['hierarchical', 'topological']).optional(),\n presetId: z.string().max(128).optional(),\n isPublished: z.boolean().optional(),\n ...ScopeShape,\n }))\n .mutation(({ input }) => updateOrThrow(\n async () => scenarioStore.update(input.id, {\n name: input.name,\n icon: input.icon,\n description: input.description,\n leaderId: input.leaderId,\n groups: input.groups,\n nodes: input.nodes,\n traversalMode: input.traversalMode,\n presetId: input.presetId,\n isPublished: input.isPublished,\n updatedAt: Date.now(),\n }, await scopeOf(input)),\n 'Scenario not found',\n )),\n\n delete: protectedProcedure\n .input(z.object({ id: Id128Schema, ...ScopeShape }))\n .mutation(({ input }) => deleteOrNotFound(\n async () => scenarioStore.delete(input.id, await scopeOf(input)),\n 'Scenario not found',\n )),\n\n run: protectedProcedure\n .input(z.object({\n conversationId: ConversationIdSchema,\n scenarioId: Id128Schema,\n userRequest: z.string().max(100_000),\n runnerOverride: z.enum(['claude-code', 'codex']).optional(),\n modelOverride: Id128Schema.optional(),\n agentId: Id128Schema.optional(),\n /** Anchors the run's working directory on the project it belongs to. */\n projectId: Id128Schema.optional(),\n /** Son organisation : sans elle, un id partagé désignerait un projet au hasard. */\n orgId: z.string().max(128).nullable().optional(),\n resume: z.boolean().optional(),\n }))\n .subscription(async function* ({ input, signal }) {\n const scenario = await scenarioStore.get(input.scenarioId, await scopeOf(input));\n if (!scenario) throw new TRPCError({ code: 'NOT_FOUND', message: 'Scenario not found' });\n\n // Start only on explicit user request or resume.\n // Reconnect/resubscribe paths pass an empty request and must never restart runs.\n const canStart = input.userRequest.trim().length > 0 || !!input.resume;\n if (!isScenarioRunning(input.conversationId) && canStart) {\n // On resume, load original user request from workspace if not provided\n let userRequest = input.userRequest;\n if (input.resume && !userRequest.trim()) {\n userRequest = await scenarioRunStore.readUserRequest(input.conversationId) ?? '';\n }\n void runScenario(input.conversationId, input.scenarioId, userRequest, {\n runnerOverride: input.runnerOverride,\n modelOverride: input.modelOverride,\n agentId: input.agentId,\n orgId: input.orgId,\n }, !!input.resume);\n // Small yield to let the bus be created before tapping\n await new Promise(r => setTimeout(r, 10));\n }\n\n // Tap into the live event bus (replays buffer for late subscribers)\n yield* tapBus(input.conversationId, signal ?? new AbortController().signal);\n }),\n\n stop: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .mutation(({ input }) => {\n abortScenario(input.conversationId);\n return { ok: true };\n }),\n\n sendNodeInput: protectedProcedure\n .input(z.object({\n conversationId: ConversationIdSchema,\n nodeId: Id128Schema,\n text: z.string().min(1).max(100_000),\n }))\n .mutation(({ input }) => {\n const resolved = resolveNodeInput(input.conversationId, input.nodeId, input.text);\n if (!resolved) throw new TRPCError({ code: 'NOT_FOUND', message: 'No pending input request for this node' });\n return { ok: true };\n }),\n\n isRunning: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .query(({ input }) => ({ running: isScenarioRunning(input.conversationId) })),\n\n runState: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .query(({ input }) => {\n const runState = scenarioRunStore.getRunState(input.conversationId);\n return runState ?? { nodeStates: {}, nodeOutputs: {}, activeNodeId: undefined };\n }),\n\n getPersistedRunState: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .query(async ({ input }) => {\n return await scenarioRunStore.loadPersistedRunState(input.conversationId);\n }),\n\n getReadme: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .query(async ({ input }) => {\n return await scenarioRunStore.readReadme(input.conversationId);\n }),\n\n getSnapshot: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .query(async ({ input }) => {\n return await scenarioRunStore.loadScenarioSnapshot(input.conversationId);\n }),\n\n streamGenerateWithAI: protectedProcedure\n .input(z.object({\n prompt: z.string().min(1).max(10_000),\n providerId: OptionalProviderIdSchema,\n model: z.string().max(200).optional(),\n current: z.object({\n leaderId: Id128Schema,\n groups: z.array(ScenarioGroupSchema).max(100),\n nodes: z.array(ScenarioNodeSchema).max(500),\n }).optional(),\n }))\n .subscription(async function* ({ input, signal }) {\n const userMessage = buildScenarioUserMessage(input.prompt, input.current);\n yield* streamWithActiveProvider({\n providerId: input.providerId,\n model: input.model,\n systemPrompt: SCENARIO_SYSTEM_PROMPT,\n userMessage,\n maxTokens: 8192,\n signal: signal ?? undefined,\n });\n }),\n\n streamRunEvents: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .subscription(async function* ({ input }) {\n const convId = input.conversationId;\n // For now, yield the current state once\n // In a real implementation, this would track state changes over time\n const runState = scenarioRunStore.getRunState(convId);\n if (runState) {\n for (const [nodeId, state] of Object.entries(runState.nodeStates)) {\n yield { type: 'node_state' as const, nodeId, state };\n }\n }\n }),\n\n /**\n * Returns the Claude Code session-id + agent-id for a node, so the UI can\n * open a debug PTY with `claude --resume <sessionId>` on the right agent.\n * Falls back to the persisted run-state for past nodes.\n */\n getNodeSession: protectedProcedure\n .input(z.object({\n conversationId: ConversationIdSchema,\n nodeId: Id128Schema,\n }))\n .query(async ({ input }) => {\n return await scenarioRunStore.getNodeSessionPersistent(input.conversationId, input.nodeId);\n }),\n\n listPresets: protectedProcedure.query(() => listPresets()),\n\n getPreset: protectedProcedure\n .input(z.object({ id: Id128Schema }))\n .query(({ input }) => {\n const preset = getPreset(input.id);\n if (!preset) throw new TRPCError({ code: 'NOT_FOUND', message: 'Preset not found' });\n return preset;\n }),\n});\n","import { TRPCError } from '@trpc/server';\n\nexport async function getOrNotFound<T>(\n getter: () => Promise<T | null>,\n notFoundMessage: string,\n): Promise<T> {\n const entity = await getter();\n if (!entity) throw new TRPCError({ code: 'NOT_FOUND', message: notFoundMessage });\n return entity;\n}\n\nexport async function createOrBadRequest<T>(creator: () => Promise<T>): Promise<T> {\n try {\n return await creator();\n } catch (err) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: (err as Error).message });\n }\n}\n\nexport async function updateOrThrow<T>(\n updater: () => Promise<T | null>,\n notFoundMessage: string,\n): Promise<T> {\n try {\n const entity = await updater();\n if (!entity) throw new TRPCError({ code: 'NOT_FOUND', message: notFoundMessage });\n return entity;\n } catch (err) {\n if (err instanceof TRPCError) throw err;\n throw new TRPCError({ code: 'BAD_REQUEST', message: (err as Error).message });\n }\n}\n\nexport async function deleteOrNotFound(\n deleter: () => Promise<boolean>,\n notFoundMessage: string,\n): Promise<{ ok: true }> {\n const deleted = await deleter();\n if (!deleted) throw new TRPCError({ code: 'NOT_FOUND', message: notFoundMessage });\n return { ok: true };\n}\n","import { TRPCError } from '@trpc/server';\nimport { streamProviderText } from '../services/ai-generation.js';\nimport { DEFAULT_MODELS, getActiveProvider } from '../services/ai-provider-utils.js';\n\ninterface ActiveProviderGenerationOptions {\n providerId?: string;\n /** L'organisation dont on lit les fournisseurs ; absente = les réglages du poste. */\n vault?: string;\n /** Overrides the provider's configured model when the caller picked one. */\n model?: string;\n systemPrompt: string;\n userMessage: string;\n maxTokens?: number;\n signal?: AbortSignal;\n}\n\nexport async function* streamWithActiveProvider(\n opts: ActiveProviderGenerationOptions,\n): AsyncGenerator<{ type: 'delta' | 'done'; text: string }> {\n const active = await getActiveProvider(opts.providerId, opts.vault);\n if (!active) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Aucun fournisseur IA configuré' });\n\n const { provider, plaintextKey } = active;\n const model = opts.model || provider.model || DEFAULT_MODELS[provider.provider] || '';\n\n try {\n for await (const text of streamProviderText({\n provider,\n plaintextKey,\n model,\n systemPrompt: opts.systemPrompt,\n userMessage: opts.userMessage,\n maxTokens: opts.maxTokens,\n signal: opts.signal,\n })) {\n yield { type: 'delta', text };\n }\n yield { type: 'done', text: '' };\n } catch (err) {\n if (String((err as Error)?.message ?? '').startsWith('Unsupported provider:')) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: `Fournisseur non supporté: ${provider.provider}` });\n }\n throw err;\n }\n}\n","import Anthropic from '@anthropic-ai/sdk';\nimport OpenAI from 'openai';\nimport type { AIProvider } from '@runeya/packages-shared';\nimport { OPENAI_COMPAT_BASE_URLS } from './ai-provider-utils.js';\n\nexport interface ProviderGenerationInput {\n provider: AIProvider;\n plaintextKey: string;\n model: string;\n systemPrompt: string;\n userMessage: string;\n maxTokens?: number;\n signal?: AbortSignal;\n}\n\nexport async function* streamProviderText(input: ProviderGenerationInput): AsyncGenerator<string> {\n const {\n provider,\n plaintextKey,\n model,\n systemPrompt,\n userMessage,\n maxTokens = 8192,\n signal,\n } = input;\n\n if (provider.provider === 'anthropic') {\n const client = new Anthropic({ apiKey: plaintextKey });\n const stream = client.messages.stream({\n model,\n max_tokens: maxTokens,\n system: systemPrompt,\n messages: [{ role: 'user', content: userMessage }],\n });\n for await (const event of stream) {\n if (signal?.aborted) return;\n if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {\n yield event.delta.text;\n }\n }\n return;\n }\n\n if (provider.provider in OPENAI_COMPAT_BASE_URLS) {\n const baseURL = OPENAI_COMPAT_BASE_URLS[provider.provider]!;\n const client = new OpenAI({ apiKey: plaintextKey || 'ollama', baseURL });\n const stream = await client.chat.completions.create({\n model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userMessage },\n ],\n stream: true,\n max_tokens: maxTokens,\n }, { signal: signal ?? undefined });\n for await (const chunk of stream) {\n if (signal?.aborted) return;\n const text = chunk.choices[0]?.delta?.content;\n if (text) yield text;\n }\n return;\n }\n\n throw new Error(`Unsupported provider: ${provider.provider}`);\n}\n","import { mkdir } from 'node:fs/promises';\nimport { randomUUID } from 'node:crypto';\nimport { join } from 'node:path';\nimport { scenarioStore } from './scenario-store.js';\nimport { scenarioRunStore, type NodeState } from './scenario-run-store.js';\nimport type { Scenario, ScenarioNode } from '@runeya/packages-shared';\nimport { getPreset } from './scenario-presets.js';\nimport { atomicWriteSecure, resolveConversationRunDir } from './run-store-utils.js';\nimport { ClaudeCodeRunner } from './ai-runners/claude-code-runner.js';\nimport { CodexRunner } from './ai-runners/codex-runner.js';\nimport type { AiRunner } from './ai-runners/ai-runner.js';\nimport { agentManager } from './agent-manager.js';\nimport { resolveConversationCwd } from './workspace-cwd.js';\n\nconst DEFAULT_NODE_MODELS: Record<'claude-code' | 'codex', string> = {\n 'claude-code': 'sonnet',\n codex: '',\n};\n\nexport interface ScenarioRunOverrides {\n runnerOverride?: 'claude-code' | 'codex';\n modelOverride?: string;\n agentId?: string;\n /**\n * L'organisation qui possède le scénario — celle dont le coffre le contient.\n *\n * Le répertoire de travail, lui, ne se transmet plus ici : il se lit de la\n * conversation au moment de lancer le CLI (`resolveConversationCwd`).\n */\n orgId?: string | null;\n}\n\n// ─── Event types ──────────────────────────────────────────────────────────────\n\nexport type ScenarioEvent =\n | { type: 'node_started'; nodeId: string }\n | { type: 'node_delta'; nodeId: string; text: string }\n | { type: 'node_status'; nodeId: string; text: string }\n | { type: 'node_tool_call'; nodeId: string; id: string; name: string; input: Record<string, unknown>; rawInput?: string }\n | { type: 'node_tool_result'; nodeId: string; id: string; result: string; isError: boolean }\n | { type: 'node_thinking'; nodeId: string; text: string }\n | { type: 'node_command'; nodeId: string; command: string }\n | { type: 'node_duration'; nodeId: string; durationMs: number }\n | { type: 'node_done'; nodeId: string; output: string; state: string }\n | { type: 'node_state_change'; nodeId: string; state: string }\n | { type: 'node_error'; nodeId: string; error: string }\n | { type: 'node_waiting_input'; nodeId: string; question: string }\n | { type: 'node_prompt'; nodeId: string; label: string; systemContext: string; userMessage: string }\n | { type: 'readme_append'; text: string }\n | { type: 'scenario_complete'; summary: string }\n | { type: 'scenario_error'; error: string };\n\n// ─── Event bus ────────────────────────────────────────────────────────────────\n\nconst MAX_BUFFER = 500;\n\ninterface RunBus {\n buffer: ScenarioEvent[];\n /** Absolute index of buffer[0] in the full event stream */\n baseIndex: number;\n listeners: Set<(evt: ScenarioEvent | null) => void>;\n done: boolean;\n}\n\nconst activeBuses = new Map<string, RunBus>();\nconst activeAbortControllers = new Map<string, AbortController>();\n\nfunction formatTs(): string {\n const d = new Date();\n const off = -d.getTimezoneOffset();\n const sign = off >= 0 ? '+' : '-';\n const pad2 = (n: number) => String(n).padStart(2, '0');\n return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())} ${pad2(d.getHours())}:${pad2(d.getMinutes())}:${pad2(d.getSeconds())} ${sign}${pad2(Math.floor(Math.abs(off) / 60))}:${pad2(Math.abs(off) % 60)}`;\n}\n\n// ─── Pending user-input requests (keyed by conversationId:nodeId) ──────────\n\nconst pendingNodeInputs = new Map<string, (text: string) => void>();\n\nfunction pendingNodeKey(conversationId: string, nodeId: string) {\n return `${conversationId}:${nodeId}`;\n}\n\n/** Called by scenario.sendNodeInput tRPC mutation when the user submits their reply. */\nexport function resolveNodeInput(conversationId: string, nodeId: string, text: string): boolean {\n const key = pendingNodeKey(conversationId, nodeId);\n const resolver = pendingNodeInputs.get(key);\n if (!resolver) return false;\n pendingNodeInputs.delete(key);\n resolver(text);\n return true;\n}\n\nfunction createBus(conversationId: string): RunBus {\n const bus: RunBus = { buffer: [], baseIndex: 0, listeners: new Set(), done: false };\n activeBuses.set(conversationId, bus);\n return bus;\n}\n\n// Events that are only useful in real-time and should not be replayed to late subscribers\nconst NO_BUFFER_EVENTS = new Set<ScenarioEvent['type']>(['node_status', 'node_thinking']);\n\nfunction publishToBus(bus: RunBus, evt: ScenarioEvent | null): void {\n if (evt !== null) {\n if (!NO_BUFFER_EVENTS.has(evt.type)) {\n bus.buffer.push(evt);\n while (bus.buffer.length > MAX_BUFFER) {\n const idx = bus.buffer.findIndex(e => e.type === 'node_delta');\n bus.buffer.splice(idx >= 0 ? idx : 0, 1);\n bus.baseIndex += 1;\n }\n }\n } else {\n bus.done = true;\n }\n for (const listener of bus.listeners) listener(evt);\n bus.listeners.clear();\n}\n\nexport async function* tapBus(conversationId: string, signal: AbortSignal): AsyncGenerator<ScenarioEvent> {\n const bus = activeBuses.get(conversationId);\n if (!bus) return;\n\n let cursor = bus.baseIndex;\n\n while (true) {\n if (cursor < bus.baseIndex) {\n // Buffer rotated (old events dropped). Jump forward to oldest still available.\n cursor = bus.baseIndex;\n }\n while (cursor < bus.baseIndex + bus.buffer.length) {\n const evt = bus.buffer[cursor - bus.baseIndex]!;\n cursor += 1;\n yield evt;\n }\n if (bus.done) return;\n if (signal.aborted) return;\n\n await new Promise<void>((resolve) => {\n const onAbort = () => {\n bus.listeners.delete(notify);\n resolve();\n };\n const notify = () => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n };\n bus.listeners.add(notify);\n signal.addEventListener('abort', onAbort, { once: true });\n // Race guard: if an event was published between the last buffer drain and\n // listener registration, wake immediately instead of waiting forever.\n if (cursor < bus.baseIndex + bus.buffer.length || bus.done || signal.aborted) {\n bus.listeners.delete(notify);\n signal.removeEventListener('abort', onAbort);\n resolve();\n }\n });\n }\n}\n\nexport function isScenarioRunning(conversationId: string): boolean {\n const bus = activeBuses.get(conversationId);\n return bus !== undefined && !bus.done;\n}\n\nexport function abortScenario(conversationId: string): boolean {\n const ctrl = activeAbortControllers.get(conversationId);\n if (!ctrl) return false;\n ctrl.abort();\n return true;\n}\n\n// ─── Hierarchy helpers ────────────────────────────────────────────────────────\n\nconst FINISHED_STATES = new Set(['done', 'error', 'synthesized']);\nconst MAX_MANAGER_REVIEW_ROUNDS = Infinity;\n\n/**\n * After a BFS level completes, promote any 'waiting' ancestor to 'done'\n * if all their descendants (recursively) are now in a finished state.\n */\nfunction resolveWaitingStates(\n nodes: ScenarioNode[],\n conversationId: string,\n byParent: Map<string, ScenarioNode[]>,\n publish: (evt: ScenarioEvent) => void,\n skipNodeIds: Set<string> = new Set(),\n): void {\n function allDescendantsDone(nodeId: string): boolean {\n for (const child of byParent.get(nodeId) ?? []) {\n const s = scenarioRunStore.getRunState(conversationId)?.nodeStates[child.id];\n if (!s || !FINISHED_STATES.has(s)) return false;\n if (!allDescendantsDone(child.id)) return false;\n }\n return true;\n }\n\n for (const node of nodes) {\n if (skipNodeIds.has(node.id)) continue;\n const s = scenarioRunStore.getRunState(conversationId)?.nodeStates[node.id];\n if (s === 'waiting' && allDescendantsDone(node.id)) {\n scenarioRunStore.setNodeState(conversationId, node.id, 'done');\n publish({ type: 'node_state_change', nodeId: node.id, state: 'done' });\n }\n }\n}\n\nfunction normalizeForMatch(value: string): string {\n return value\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, ' ')\n .trim();\n}\n\nfunction getDirectReports(nodes: ScenarioNode[], managerId: string): ScenarioNode[] {\n return nodes.filter((p) => p.parentIds[0] === managerId);\n}\n\n/**\n * Parse <next_person> directives from AI output.\n *\n * Supported forms:\n * <next_person name=\"Alice Martin\">specific instruction (multiline ok)</next_person>\n * <next_person name=\"STOP\" />\n */\nfunction parseRuneyaNextNodeDirectives(output: string): { name: string; instruction: string | null }[] {\n const results: { name: string; instruction: string | null }[] = [];\n // Self-closing form: <next_person name=\"STOP\" />\n for (const m of output.matchAll(/<next_person\\s+name=\"([^\"]*?)\"\\s*\\/>/g)) {\n results.push({ name: m[1].trim(), instruction: null });\n }\n // Content form: <next_person name=\"Alice\">instruction</next_person>\n for (const m of output.matchAll(/<next_person\\s+name=\"([^\"]*?)\">([\\s\\S]*?)<\\/next_person>/g)) {\n results.push({ name: m[1].trim(), instruction: m[2].trim() || null });\n }\n return results;\n}\n\ninterface HireDirectivePayload {\n label: string;\n role: string;\n prompt: string;\n}\n\n/**\n * Parse <hire_person> directives from AI output.\n *\n * <hire_person label=\"Jane Doe\" role=\"engineer\">Task focus prompt</hire_person>\n */\nfunction parseRuneyaHireDirectives(output: string): HireDirectivePayload[] {\n const results: HireDirectivePayload[] = [];\n for (const m of output.matchAll(/<hire_person\\s+label=\"([^\"]*?)\"\\s+role=\"([^\"]*?)\">([\\s\\S]*?)<\\/hire_person>/g)) {\n const label = m[1].trim();\n const role = m[2].trim();\n const prompt = m[3].trim();\n if (label && role && prompt) results.push({ label, role, prompt });\n }\n return results;\n}\n\nconst HIRE_LAYOUT = {\n startY: 88,\n siblingGap: 24,\n minXInTeam: 20,\n minYInTeam: 36,\n nodeWidthEstimate: 180,\n nodeHeightEstimate: 50,\n groupRightPadding: 24,\n groupBottomPadding: 28,\n minGroupWidth: 300,\n minGroupHeight: 200,\n} as const;\n\nfunction computeHirePosition(manager: ScenarioNode, nodes: ScenarioNode[]): { x: number; y: number } {\n const sameTeamReports = nodes.filter((p) => p.parentIds[0] === manager.id && p.groupId === (manager.groupId ?? null));\n const managerX = Number.isFinite(manager.position?.x) ? manager.position.x : 140;\n const managerY = Number.isFinite(manager.position?.y) ? manager.position.y : 40;\n const baseY = managerY + HIRE_LAYOUT.startY;\n const rightMost = sameTeamReports\n .filter((p) => Number.isFinite(p.position?.x))\n .sort((a, b) => (a.position?.x ?? 0) - (b.position?.x ?? 0))\n .at(-1);\n\n let x = managerX;\n let y = baseY;\n if (rightMost) {\n x = (rightMost.position?.x ?? managerX) + HIRE_LAYOUT.nodeWidthEstimate + HIRE_LAYOUT.siblingGap;\n y = Math.max(baseY, rightMost.position?.y ?? baseY);\n }\n\n if (manager.groupId) {\n x = Math.max(HIRE_LAYOUT.minXInTeam, x);\n y = Math.max(HIRE_LAYOUT.minYInTeam, y);\n } else {\n x = Math.max(0, x);\n y = Math.max(0, y);\n }\n\n return { x, y };\n}\n\nfunction ensureGroupCanContainNode(scenario: Scenario, groupId: string | null, position: { x: number; y: number }): void {\n if (!groupId) return;\n const group = scenario.groups.find((t) => t.id === groupId);\n if (!group) return;\n\n const width = Number.isFinite(group.width) ? group.width : HIRE_LAYOUT.minGroupWidth;\n const height = Number.isFinite(group.height) ? group.height : HIRE_LAYOUT.minGroupHeight;\n\n const neededWidth = position.x + HIRE_LAYOUT.nodeWidthEstimate + HIRE_LAYOUT.groupRightPadding;\n const neededHeight = position.y + HIRE_LAYOUT.nodeHeightEstimate + HIRE_LAYOUT.groupBottomPadding;\n\n group.width = Math.max(width, HIRE_LAYOUT.minGroupWidth, neededWidth);\n group.height = Math.max(height, HIRE_LAYOUT.minGroupHeight, neededHeight);\n}\n\nfunction applyHireDirectivesFromOutput(\n manager: ScenarioNode,\n scenario: Scenario,\n output: string,\n): ScenarioNode[] {\n const hireDirectives = parseRuneyaHireDirectives(output);\n if (hireDirectives.length === 0) return [];\n if (!manager.canAddNode) {\n throw new Error(`${manager.label} attempted to hire without permission`);\n }\n\n const hired: ScenarioNode[] = [];\n for (const payload of hireDirectives) {\n const id = `hire-${randomUUID().slice(0, 8)}`;\n const position = computeHirePosition(manager, scenario.nodes);\n ensureGroupCanContainNode(scenario, manager.groupId ?? null, position);\n const node: ScenarioNode = {\n id,\n type: 'ai',\n parentIds: [manager.id],\n groupId: manager.groupId ?? null,\n label: payload.label,\n role: payload.role,\n prompt: payload.prompt,\n question: '',\n autoGenerated: true,\n canAddNode: false,\n aiCli: manager.aiCli ?? 'claude-code',\n model: '',\n position,\n injectParentOutputs: false,\n injectedAncestorIds: [],\n };\n scenario.nodes.push(node);\n hired.push(node);\n }\n return hired;\n}\n\nfunction selectExplicitDirectReportsFromOutput(\n manager: ScenarioNode,\n nodes: ScenarioNode[],\n managerOutput: string,\n): { selected: ScenarioNode[]; unknownNames: string[]; assignments: Map<string, string>; missingAssignments: string[] } {\n const directReports = getDirectReports(nodes, manager.id);\n\n const directives = parseRuneyaNextNodeDirectives(managerOutput);\n const normalizedDirectives = directives.map((d) => ({ norm: normalizeForMatch(d.name), instruction: d.instruction }));\n const stopDirective = normalizedDirectives.length === 1 && normalizedDirectives[0]!.norm === 'stop';\n if (normalizedDirectives.length === 0 || stopDirective) return { selected: [], unknownNames: [], assignments: new Map(), missingAssignments: [] };\n\n const selected: ScenarioNode[] = [];\n const assignments = new Map<string, string>();\n const matchedDirectives = new Set<string>();\n for (const report of directReports) {\n const fullName = normalizeForMatch(report.label);\n const reverseName = normalizeForMatch(`${report.label}`);\n const matched = normalizedDirectives.find((d) => d.norm === fullName || d.norm === reverseName);\n if (matched) {\n selected.push(report);\n matchedDirectives.add(matched.norm);\n if (matched.instruction) assignments.set(report.id, matched.instruction);\n }\n }\n const unknownNames = normalizedDirectives.filter((d) => d.norm !== 'stop' && !matchedDirectives.has(d.norm)).map((d) => d.norm);\n const missingAssignments = selected.filter((r) => !assignments.has(r.id)).map((r) => r.label);\n return { selected, unknownNames, assignments, missingAssignments };\n}\n\n\n\nfunction hasExplicitNoDelegationDecision(output: string): boolean {\n const nextDirectives = parseRuneyaNextNodeDirectives(output);\n // STOP is only valid when it is the single NEXT_PERSON directive.\n return nextDirectives.length === 1 && normalizeForMatch(nextDirectives[0]?.name ?? '') === 'stop';\n}\n\nfunction buildDelegationRetryMessage(\n manager: ScenarioNode,\n directReports: ScenarioNode[],\n userRequest: string,\n previousOutput: string,\n): string {\n const reportsList = directReports\n .map((r) => `- ${r.label} | role: ${r.role ?? 'other'} | profile: ${r.prompt || 'no description'}`)\n .join('\\n');\n\n return [\n `## Original Request`,\n userRequest,\n ``,\n `## Your Previous Output`,\n `<previous_output>`,\n previousOutput,\n `</previous_output>`,\n ``,\n `## Delegation Retry (mandatory)`,\n `You must explicitly choose which direct reports to contact now.`,\n `Use the exact full names from the allowed list below.`,\n `If you still do not provide explicit names, your run will fail.`,\n ``,\n `## Allowed Direct Reports`,\n reportsList || '(none)',\n ``,\n ...(manager.canAddNode ? [\n `## Optional Hire Command`,\n `You may hire temporary contractors with:`,\n `<hire_person label=\"Jane Doe\" role=\"engineer\">Task focus prompt</hire_person>`,\n `If you hire someone and want them to run now, also include: <next_person name=\"Jane Doe\">their task</next_person>`,\n ``,\n ] : []),\n `## Output Format`,\n `Write one XML tag per selected node including their specific instruction:`,\n `<next_person name=\"FirstName LastName\">their specific task (multiline ok)</next_person>`,\n `Or explicitly choose no delegation with: <next_person name=\"STOP\" />`,\n ].join('\\n');\n}\n\nfunction buildMissingAssignmentsRetryMessage(\n _manager: ScenarioNode,\n missingNames: string[],\n previousOutput: string,\n): string {\n return [\n `## Missing Assignments`,\n `You selected the following nodes but did not provide a specific instruction for each:`,\n missingNames.map((n) => `- ${n}`).join('\\n'),\n ``,\n `## Your Previous Output`,\n `<previous_output>`,\n previousOutput,\n `</previous_output>`,\n ``,\n `## Required Format`,\n `For each node listed above, output one XML tag with their instruction:`,\n `<next_person name=\"FirstName LastName\">their specific task instruction (multiline ok)</next_person>`,\n `The instruction content is mandatory. Be concise and actionable.`,\n ].join('\\n');\n}\n\nfunction buildManagerReviewMessage(\n manager: ScenarioNode,\n directReports: ScenarioNode[],\n userRequest: string,\n previousOutput: string,\n childReportsSection: string,\n): string {\n const reportsList = directReports\n .map((r) => `- ${r.label} | role: ${r.role ?? 'other'} | profile: ${r.prompt || 'no description'}`)\n .join('\\n');\n\n return [\n `## Original Request`,\n userRequest,\n ``,\n `## Your Previous Output`,\n `<previous_output>`,\n previousOutput,\n `</previous_output>`,\n ``,\n `## Children Reports Collected`,\n childReportsSection || '(none)',\n ``,\n `## Parent Review Decision (mandatory)`,\n `You are now in review mode after collecting child reports.`,\n `Your decision rule is simple:`,\n `- If the deliverable is complete and satisfies the original request → output <next_person name=\"STOP\" /> immediately. Do NOT re-run for process reasons (wrong node assigned, style preferences, etc.).`,\n `- If something is factually missing or incorrect in the deliverable → request a targeted re-run with precise instructions.`,\n `Use the exact full names from your direct reports list below.`,\n ``,\n `## Allowed Direct Reports`,\n reportsList || '(none)',\n ``,\n ...(manager.canAddNode ? [\n `## Optional Hire Command`,\n `You may hire temporary contractors with:`,\n `<hire_person label=\"Jane Doe\" role=\"engineer\">Task focus prompt</hire_person>`,\n `If you hire someone and want them to run now, also include: <next_person name=\"Jane Doe\">their task</next_person>`,\n ``,\n ] : []),\n `## Output Format`,\n `If no more child work is needed: output <next_person name=\"STOP\" /> first, then immediately write a complete synthesis of all children's deliverables so your parent can evaluate the result. Do NOT summarize — include the full content (scripts, outputs, data, etc.).`,\n `If refinement is needed, output one XML tag per selected node with their specific instruction:`,\n `<next_person name=\"FirstName LastName\">precise refinement instruction (multiline ok)</next_person>`,\n ].join('\\n');\n}\n\n// ─── Prompt builders ──────────────────────────────────────────────────────────\n\n\nfunction buildSystemPrompt(\n node: ScenarioNode,\n scenario: Scenario,\n): string {\n const group = scenario.groups.find(t => t.id === node.groupId);\n const manager = node.parentIds[0] ? scenario.nodes.find(p => p.id === node.parentIds[0]) : null;\n const reports = getDirectReports(scenario.nodes, node.id);\n\n const preset = scenario.presetId ? getPreset(scenario.presetId) : undefined;\n const presetRole = preset?.roles.find(r => r.id === (node.role ?? 'other'));\n const roleBehavior = presetRole?.systemPrompt ?? '';\n const rolePrompt = presetRole?.prompt ?? '';\n\n const lines = [\n `You are ${node.label}${group ? `, member of the ${group.name} group` : ''}.`,\n `Your role type: **${(node.role ?? 'other').toUpperCase()}**.`,\n '',\n ];\n\n if (roleBehavior) {\n lines.push('## Role Behavior (strictly enforce)', roleBehavior, '');\n }\n\n const profileSection = [node.prompt, rolePrompt].filter(Boolean).join('\\n\\n');\n lines.push('## Your Profile & Instructions', profileSection || '(No profile provided)', '');\n\n if (manager) {\n lines.push(`## Reporting Line`, `You report to ${manager.label} (${manager.role ?? 'other'}).`, '');\n } else {\n lines.push(`## Position`, `You are the leader of this scenario. You coordinate all groups.`, '');\n }\n\n if (reports.length > 0) {\n lines.push(\n `## Your Direct Reports`,\n ...reports.map(r => {\n const rGroup = scenario.groups.find(g => g.id === r.groupId);\n const groupInfo = rGroup\n ? ` | group: ${rGroup.name}${rGroup.description ? ` (${rGroup.description})` : ''}`\n : '';\n return `- ${r.label} (${r.role ?? 'other'})${groupInfo}: ${r.prompt || '(No profile provided)'}`;\n }),\n '',\n );\n }\n\n if (node.canAddNode) {\n lines.push(\n '## Hiring Capability',\n 'You are allowed to hire temporary contractors for this run.',\n 'Use exactly: <hire_person label=\"Jane Doe\" role=\"engineer\">Task focus prompt</hire_person>',\n 'Any hired node will automatically be placed in your own group.',\n 'To execute the hired node in this run, also output: <next_person name=\"Jane Doe\">their task</next_person>',\n '',\n );\n }\n\n lines.push(\n '## Output Instructions',\n 'Write your output clearly and in a structured format.',\n 'Stay strictly within your role — do not produce deliverables that belong to a different role.',\n 'Be concise and actionable.',\n 'Only use <ask_user>...</ask_user> when you are genuinely blocked by missing information that no one in the group can provide (e.g. a secret, a business decision, an external credential). NEVER use it to ask for confirmation, approval, or readiness (e.g. \"are you ready?\", \"shall I proceed?\"). Always proceed autonomously unless truly blocked.',\n );\n\n // Inject RUNEYA_AI_* environment variables\n const runeya_ai_vars = Object.entries(process.env)\n .filter(([k]) => k.startsWith('RUNEYA_AI_'))\n .map(([k, v]) => `${k}=${v}`)\n .join('\\n');\n if (runeya_ai_vars) {\n lines.push('', '## Environment', '', runeya_ai_vars);\n }\n\n return lines.join('\\n');\n}\n\nfunction buildUserMessage(\n node: ScenarioNode,\n scenario: Scenario,\n userRequest: string,\n managerOutput: string | null,\n isLeaderSynthesis: boolean,\n isLeaderDispatch: boolean,\n allOutputs?: Map<string, string>,\n): string {\n const parts: string[] = [];\n\n if (node.prompt) {\n parts.push(`## Your Profile & Instructions (reminder)\\n\\n${node.prompt}`);\n }\n\n parts.push(`## Original Request\\n\\n${userRequest}`);\n\n if (isLeaderSynthesis && allOutputs) {\n // Leader's final synthesis pass: receive all group outputs\n const teamSection = scenario.nodes\n .filter(p => p.id !== scenario.leaderId && allOutputs.has(p.id))\n .map(p => {\n const name = p.label.trim() || p.id;\n const output = allOutputs.get(p.id) ?? '';\n return `<team_member id=\"${p.id}\" name=\"${name}\">\\n${output}\\n</team_member>`;\n })\n .join('\\n\\n');\n\n if (teamSection) {\n parts.push(`## Your Group's Outputs\\n\\n${teamSection}`);\n }\n\n parts.push(\n `## Your Task`,\n `Synthesize all group outputs above and deliver a final, comprehensive answer to the original request.`,\n `Highlight key results, decisions, and any remaining open points.`,\n );\n } else if (isLeaderDispatch) {\n // Leader's dispatch pass: break down the request and assign sub-tasks\n const directReports = getDirectReports(scenario.nodes, node.id);\n const reportsList = directReports\n .map(r => {\n const group = scenario.groups.find(t => t.id === r.groupId);\n return `- ${r.label} | role: ${r.role ?? 'other'}${group ? ` | group: ${group.name}${group.description ? ` (${group.description})` : ''}` : ''} | profile: ${r.prompt || 'no description'}`;\n })\n .join('\\n');\n\n parts.push(\n `## Your Direct Reports\\n\\n${reportsList || '(none)'}`,\n `## Your Task`,\n `As the leader, your role here is STRICTLY to delegate — NEVER to solve the request yourself.`,\n `Do NOT ask yourself whether you should answer directly or delegate. You ALWAYS delegate.`,\n `⚠️ IMPORTANT: Before selecting anyone, re-read your Profile & Instructions above. Any constraint written there (e.g. \"do not contact X\", \"must hire someone\") is MANDATORY and overrides everything else.`,\n `Instead, analyze the request and produce a clear **delegation plan**:`,\n `1. Break down the request into concrete sub-tasks, one per direct report (or group of reports if relevant).`,\n `2. For each node, write a specific, actionable assignment that fits their role and expertise.`,\n `3. Provide any strategic context, constraints, or success criteria they need.`,\n `4. Do NOT produce the final answer — your group will do that. You coordinate.`,\n `5. IMPORTANT: explicitly mention the exact full name of each direct report you want to contact. Only explicitly mentioned nodes will be executed.`,\n `6. For each node you assign, output one XML tag with their name AND specific instruction: <next_person name=\"FirstName LastName\">their specific instruction (multiline ok)</next_person>`,\n `7. If you intentionally decide to contact nobody, write exactly: <next_person name=\"STOP\" />`,\n ...(node.canAddNode ? [\n `8. You may hire temporary contractors with: <hire_person label=\"Jane Doe\" role=\"engineer\">Task focus prompt</hire_person>`,\n `9. Hired nodes are always placed in your own group (no group field needed).`,\n `10. If you hire someone and want them to execute now, also include: <next_person name=\"Jane Doe\">their task</next_person>`,\n ] : []),\n ``,\n `Format your output as a brief intro followed by one clearly labeled section per direct report.`,\n );\n } else {\n if (managerOutput) {\n const manager = scenario.nodes.find(p => p.id === node.parentIds[0]);\n const managerName = manager ? manager.label.trim() : 'your manager';\n parts.push(\n `## Assignment from ${managerName}\\n\\n<manager_output>\\n${managerOutput}\\n</manager_output>`,\n );\n }\n\n // Inject outputs from explicitly selected ancestor nodes\n if (allOutputs && !isLeaderSynthesis) {\n const injectedIds = new Set<string>();\n // Always inject all parent outputs when the node has multiple parents (aggregation node),\n // or when explicitly requested via injectParentOutputs.\n if (node.injectParentOutputs || node.parentIds.length > 1) {\n for (const pid of node.parentIds) injectedIds.add(pid);\n }\n for (const aid of (node.injectedAncestorIds ?? [])) injectedIds.add(aid);\n // Remove first parent since its output is already shown as \"Assignment from manager\" (avoid duplicate)\n injectedIds.delete(node.parentIds[0] ?? '');\n\n const prevOutputs = scenario.nodes\n .filter(p => injectedIds.has(p.id) && allOutputs.has(p.id))\n .map(p => {\n const name = p.label.trim() || p.id;\n const output = allOutputs.get(p.id) ?? '';\n return `<context_node id=\"${p.id}\" name=\"${name}\">\\n${output}\\n</context_node>`;\n })\n .join('\\n\\n');\n if (prevOutputs) {\n parts.push(`## Context from Related Nodes\\n\\n${prevOutputs}`);\n }\n }\n\n parts.push(\n `## Your Task`,\n `Based on the original request${managerOutput ? ' and your manager\\'s assignment above' : ''}${allOutputs && !isLeaderSynthesis && ((node.parentIds.length > 1 || node.injectParentOutputs) || (node.injectedAncestorIds ?? []).length > 0) ? ' and the context from related nodes above' : ''}, ` +\n `complete your specific part according to your role and expertise. ` +\n `Be thorough and actionable. Report your output clearly — your manager will use it for the final synthesis.`,\n );\n\n const directReports = getDirectReports(scenario.nodes, node.id);\n if (directReports.length > 0) {\n const reportsList = directReports\n .map((r) => `- ${r.label} | role: ${r.role ?? 'other'} | profile: ${r.prompt || 'no description'}`)\n .join('\\n');\n parts.push(\n ...(node.canAddNode ? [\n `## Hiring (available to you)`,\n `You may hire a temporary contractor for this run: <hire_person label=\"Jane Doe\" role=\"engineer\">Task focus prompt</hire_person>`,\n `If you hire someone and want them to execute immediately, also add: <next_person name=\"Jane Doe\">their task</next_person>`,\n `Hired nodes join your group automatically — no group field needed.`,\n ] : []),\n `## Direct Reports You Can Also Contact\\n\\n${reportsList}`,\n `⚠️ MANDATORY: Re-read your Profile & Instructions above before selecting anyone. Any constraint there (e.g. \"do not contact X\", \"must hire\") overrides everything.`,\n `For each node you assign, output one XML tag with their name AND specific instruction: <next_person name=\"FirstName LastName\">their specific instruction (multiline ok)</next_person>`,\n `Only names declared with <next_person> will run.`,\n `If you intentionally choose to delegate to nobody, write: <next_person name=\"STOP\" />`,\n );\n }\n }\n\n return parts.join('\\n\\n');\n}\n\n// ─── Single-node AI call (streaming) ───────────────────────────────────────\n\nfunction resolveNodeExecutionConfig(\n node: ScenarioNode,\n runOverrides?: ScenarioRunOverrides,\n): { aiCli: 'claude-code' | 'codex'; model: string } {\n const baseCli = node.aiCli ?? 'claude-code';\n const aiCli = runOverrides?.runnerOverride ?? baseCli;\n const crossFamily = !!runOverrides?.runnerOverride && runOverrides.runnerOverride !== baseCli;\n const modelOverride = runOverrides?.modelOverride?.trim() ?? '';\n const nodeModel = node.model?.trim() ?? '';\n const model = modelOverride || (crossFamily ? DEFAULT_NODE_MODELS[aiCli] : (nodeModel || DEFAULT_NODE_MODELS[aiCli]));\n return { aiCli, model };\n}\n\n// ─── Per-node runner state (session continuity across ASK_USER loops) ───────\n\ninterface NodeRunnerState {\n runner: AiRunner;\n sessionId: string;\n isResume: boolean;\n}\n\nfunction createNodeRunnerState(aiCli: 'claude-code' | 'codex'): NodeRunnerState {\n return {\n runner: aiCli === 'codex' ? new CodexRunner() : new ClaudeCodeRunner(),\n sessionId: '',\n isResume: false,\n };\n}\n\nasync function runNodeCall(\n conversationId: string,\n node: ScenarioNode,\n systemContext: string,\n userMessage: string,\n runOverrides: ScenarioRunOverrides | undefined,\n signal: AbortSignal,\n publish: (evt: ScenarioEvent) => void,\n onDelta: (text: string) => void,\n runnerStates: Map<string, NodeRunnerState>,\n label = 'call',\n readme?: (text: string) => Promise<void>,\n): Promise<string> {\n publish({ type: 'node_prompt', nodeId: node.id, label, systemContext, userMessage });\n const { aiCli, model } = resolveNodeExecutionConfig(node, runOverrides);\n\n if (!runnerStates.has(node.id)) {\n runnerStates.set(node.id, createNodeRunnerState(aiCli));\n }\n const state = runnerStates.get(node.id)!;\n\n let currentPrompt = userMessage;\n let accumulated = '';\n let persistTimer: ReturnType<typeof setTimeout> | null = null;\n\n const schedulePersist = () => {\n if (persistTimer) return;\n persistTimer = setTimeout(() => {\n persistTimer = null;\n appendNodeOutput(conversationId, node, accumulated).catch(() => {});\n }, 500);\n };\n\n const flushPersist = () => {\n if (persistTimer) { clearTimeout(persistTimer); persistTimer = null; }\n };\n\n while (true) {\n const turnStart = Date.now();\n\n const result = await state.runner.run({\n agentId: runOverrides?.agentId ?? agentManager.getDefaultAgentId() ?? undefined,\n // Without this the CLI would run wherever the server was launched, whatever\n // project the scenario belongs to. Read from the conversation, so un lancement\n // sans requête HTTP — la file kanban — est ancré comme les autres. No project:\n // left unset, so the runner keeps its own default rather than being sent to\n // this machine's path.\n cwd: await resolveConversationCwd(conversationId),\n sessionId: state.sessionId,\n prompt: currentPrompt,\n isResume: state.isResume,\n systemContext,\n apiBaseUrl: '',\n apiToken: '',\n model,\n effort: 'normal',\n signal,\n onDelta: (text) => {\n accumulated += text;\n onDelta(text);\n schedulePersist();\n },\n onStatus: (text) => publish({ type: 'node_status', nodeId: node.id, text }),\n onToolCall: (id, name, input, rawInput) => publish({ type: 'node_tool_call', nodeId: node.id, id, name, input, rawInput }),\n onToolResult: (id, result, isError) => publish({ type: 'node_tool_result', nodeId: node.id, id, result, isError }),\n onThinking: (text) => publish({ type: 'node_thinking', nodeId: node.id, text }),\n onCommand: (cmd) => publish({ type: 'node_command', nodeId: node.id, command: cmd }),\n });\n\n flushPersist();\n // Update to the actual session ID reported by claude (may differ from our initial UUID)\n if (result.actualSessionId) state.sessionId = result.actualSessionId;\n state.isResume = true;\n\n // Persist the claude session-id per node so the user can later open a\n // `claude --resume <sessionId>` PTY from the debug button.\n const agentForNode = runOverrides?.agentId ?? agentManager.getDefaultAgentId() ?? null;\n if (state.sessionId && agentForNode) {\n scenarioRunStore.setNodeSession(conversationId, node.id, state.sessionId, agentForNode);\n void scenarioRunStore.persistRunState(conversationId);\n }\n\n if (result.tokenStatus === 'ask_user') {\n publish({ type: 'node_duration', nodeId: node.id, durationMs: Date.now() - turnStart });\n scenarioRunStore.setNodeState(conversationId, node.id, 'waiting_input');\n scenarioRunStore.setWaitingInput(conversationId, node.id, result.tokenMessage);\n flushPersist();\n publish({ type: 'node_waiting_input', nodeId: node.id, question: result.tokenMessage });\n await readme?.(`- ❓ [${formatTs()}] **${node.label}** — waiting for user input\\n`);\n\n const answer = await new Promise<string>((resolve, reject) => {\n const key = pendingNodeKey(conversationId, node.id);\n pendingNodeInputs.set(key, resolve);\n signal.addEventListener('abort', () => {\n pendingNodeInputs.delete(key);\n reject(new Error('Aborted'));\n }, { once: true });\n });\n\n scenarioRunStore.clearWaitingInput(conversationId, node.id);\n await readme?.(`- 💬 [${formatTs()}] **User replied** to ${node.label}\\n`);\n const qaBlock = `\\n\\n---\\n**Question:** ${result.tokenMessage}\\n\\n**Your answer:** ${answer}\\n`;\n await appendNodeOutput(conversationId, node, qaBlock);\n publish({ type: 'node_delta', nodeId: node.id, text: qaBlock });\n accumulated = '';\n scenarioRunStore.setNodeState(conversationId, node.id, 'running');\n publish({ type: 'node_started', nodeId: node.id });\n currentPrompt = `L'utilisateur a répondu : ${answer}`;\n continue;\n }\n\n publish({ type: 'node_duration', nodeId: node.id, durationMs: Date.now() - turnStart });\n return result.output;\n }\n}\n\n// ─── Persist output to workspace file ────────────────────────────────────────\n\nfunction getScenarioRunDir(conversationId: string): string | null {\n try {\n return resolveConversationRunDir('scenario-runs', conversationId);\n } catch {\n return null;\n }\n}\n\nasync function appendNodeOutput(conversationId: string, node: ScenarioNode, output: string): Promise<void> {\n const dir = getScenarioRunDir(conversationId);\n if (!dir) return;\n\n const slug = node.label.toLowerCase().replace(/[^a-z0-9]+/g, '-').slice(0, 60) || 'member';\n const safeId = node.id.replace(/[^a-z0-9_-]/gi, '-').slice(0, 80);\n const filePath = join(dir, `${slug}_${safeId}.md`);\n\n const content = `## Output\\n\\n${output}\\n`;\n await atomicWriteSecure(filePath, content);\n}\n\nasync function appendToReadme(\n conversationId: string,\n bus: RunBus,\n text: string,\n): Promise<void> {\n const dir = getScenarioRunDir(conversationId);\n if (!dir) return;\n\n const line = `${text}\\n`;\n try {\n await mkdir(dir, { recursive: true });\n const { appendFile } = await import('node:fs/promises');\n await appendFile(join(dir, 'README.md'), line, 'utf-8');\n } catch {\n // Non-fatal — still publish the event even if disk write fails\n }\n publishToBus(bus, { type: 'readme_append', text: line });\n}\n\nasync function writeFinalMd(\n conversationId: string,\n bus: RunBus,\n userRequest: string,\n content: string,\n): Promise<void> {\n const dir = getScenarioRunDir(conversationId);\n if (!dir) return;\n\n const fullContent = `# Final Report\\n\\n## User Request\\n\\n> ${userRequest.replaceAll('\\n', '\\n> ')}\\n\\n---\\n\\n## Result\\n\\n${content}\\n`;\n\n const filePath = join(dir, 'FINAL.md');\n await atomicWriteSecure(filePath, fullContent);\n\n // Stream FINAL.md content as readme_append so UI sees it inline\n await appendToReadme(conversationId, bus,\n `\\n---\\n\\n## ✅ FINAL REPORT\\n\\n**User request:**\\n\\n> ${userRequest.replaceAll('\\n', '\\n> ')}\\n\\n${content}\\n`,\n );\n}\n\n// ─── Main orchestration ───────────────────────────────────────────────────────\n\n/**\n * Runs the scenario multi-agent workflow for a given conversation.\n * Execution order: BFS level by level (leader → direct reports → their reports, …).\n * Nodes at the same level run in parallel.\n * After all agents complete, the leader runs a synthesis pass.\n * All events are published to the run bus so late subscribers can reconnect.\n */\nfunction applyRunOverridesToScenario(\n scenario: Scenario,\n runOverrides?: ScenarioRunOverrides,\n): Scenario {\n if (!runOverrides?.runnerOverride && !runOverrides?.modelOverride?.trim()) return scenario;\n return {\n ...scenario,\n nodes: scenario.nodes.map((node) => {\n const { aiCli, model } = resolveNodeExecutionConfig(node, runOverrides);\n return { ...node, aiCli, model };\n }),\n };\n}\n\nexport async function runScenario(\n conversationId: string,\n scenarioId: string,\n userRequest: string,\n runOverrides?: ScenarioRunOverrides,\n resume?: boolean,\n): Promise<void> {\n if (isScenarioRunning(conversationId)) return;\n\n const bus = createBus(conversationId);\n const ctrl = new AbortController();\n activeAbortControllers.set(conversationId, ctrl);\n const signal = ctrl.signal;\n\n const publish = (evt: ScenarioEvent) => publishToBus(bus, evt);\n const readme = (text: string) => appendToReadme(conversationId, bus, text);\n // Bullet list item with automatic timestamp prefix: `- emoji [ts] rest`\n const li = (emoji: string, content: string) => readme(`- ${emoji} [${formatTs()}] ${content}\\n`);\n\n const ts = () => formatTs();\n const fmtDuration = (startMs: number) => {\n const ms = Math.max(0, Date.now() - startMs);\n const sec = ms / 1000;\n return sec < 10 ? `${sec.toFixed(1)}s` : `${Math.round(sec)}s`;\n };\n\n let finalWritten = false;\n\n async function execute() {\n try {\n const scenario: Scenario = await (async () => {\n const base = await scenarioRunStore.loadScenarioSnapshot(conversationId)\n // Les surcharges de run portent le projet visé, donc l'organisation\n // dont ce scénario relève.\n ?? await scenarioStore.get(scenarioId, runOverrides?.orgId ?? undefined);\n if (!base) throw new Error(`Scenario ${scenarioId} not found`);\n // Apply overrides in memory only — snapshot on disk stays clean\n return applyRunOverridesToScenario(base, runOverrides);\n })();\n const leader = scenario.nodes.find((p) => p.id === scenario.leaderId);\n if (!leader) throw new Error('Scenario has no leader');\n\n // Build parent→children map for hierarchy lookups\n const byParent = new Map<string, ScenarioNode[]>();\n const nodesById = new Map(scenario.nodes.map((p) => [p.id, p]));\n\n // outputs[nodeId] = full text output of that node\n const outputs = new Map<string, string>();\n let leaderDispatchOutput: string | null = null;\n let leaderDispatchAssignments: Map<string, string> = new Map();\n\n // Runner state per node — preserves session for ASK_USER continuations\n const runnerStates = new Map<string, NodeRunnerState>();\n\n // ── Resume: load persisted state and pre-populate outputs for done persons ──\n const persistedState = resume\n ? await scenarioRunStore.loadPersistedRunState(conversationId)\n : null;\n\n function isSubtreeComplete(nodeId: string): boolean {\n if (!persistedState) return false;\n const state = persistedState.nodeStates[nodeId];\n if (state !== 'done' && state !== 'synthesized') return false;\n for (const child of getDirectReports(scenario.nodes, nodeId)) {\n if (!isSubtreeComplete(child.id)) return false;\n }\n return true;\n }\n\n if (persistedState) {\n for (const [nodeId, output] of Object.entries(persistedState.nodeOutputs)) {\n const state = persistedState.nodeStates[nodeId];\n if (state === 'done' || state === 'synthesized') {\n outputs.set(nodeId, output);\n scenarioRunStore.setNodeState(conversationId, nodeId, state as NodeState);\n scenarioRunStore.setNodeOutput(conversationId, nodeId, output);\n }\n }\n }\n\n if (resume) {\n await readme(`\\n---\\n\\n## ♻️ Run resumed — ${ts()}\\n`);\n } else {\n await readme(`\\n## Run started — ${ts()}\\n\\n**User request:**\\n\\n> ${userRequest.replaceAll('\\n', '\\n> ')}\\n`);\n }\n\n // Resume: restore leader dispatch from cache if available\n let leaderDispatchHandled = false;\n if (persistedState && outputs.has(leader.id)) {\n const cachedOut = outputs.get(leader.id)!;\n leaderDispatchOutput = cachedOut;\n const leaderResult = selectExplicitDirectReportsFromOutput(leader, scenario.nodes, cachedOut);\n byParent.set(leader.id, leaderResult.selected);\n leaderDispatchAssignments = leaderResult.assignments;\n const leaderState = leaderResult.selected.length > 0 ? 'waiting' : 'done';\n scenarioRunStore.setNodeState(conversationId, leader.id, leaderState);\n publish({ type: 'node_state_change', nodeId: leader.id, state: leaderState });\n publish({ type: 'node_done', nodeId: leader.id, output: cachedOut, state: leaderState });\n await li('♻️', `**${leader.label}** (Leader) — restored from previous run`);\n leaderDispatchHandled = true;\n }\n\n // Leader dispatch phase — hierarchical mode only\n if (scenario.traversalMode !== 'topological' && !leaderDispatchHandled) {\n const startedAt = Date.now();\n publish({ type: 'node_started', nodeId: leader.id });\n scenarioRunStore.setNodeState(conversationId, leader.id, 'running');\n await readme(`### [${ts()}] 📋 ${leader.label} (Leader) — dispatching assignments\\n`);\n await li('▶️', `**${leader.label}** — started`);\n\n try {\n const systemPrompt = buildSystemPrompt(leader, scenario);\n const userMsg = buildUserMessage(leader, scenario, userRequest, null, false, true);\n const out = await runNodeCall(conversationId, leader, systemPrompt, userMsg, runOverrides, signal, publish, (delta) => {\n publish({ type: 'node_delta', nodeId: leader.id, text: delta });\n }, runnerStates, 'dispatch', readme);\n\n outputs.set(leader.id, out);\n leaderDispatchOutput = out;\n const hiredByLeader = applyHireDirectivesFromOutput(leader, scenario, out);\n if (hiredByLeader.length > 0) {\n await scenarioRunStore.saveScenarioSnapshot(conversationId, scenario);\n await li('🆕', `${leader.label} hired: ${hiredByLeader.map((p) => `${p.label} (${p.role})`).join(', ')}`);\n }\n const directReports = getDirectReports(scenario.nodes, leader.id);\n const leaderResult = selectExplicitDirectReportsFromOutput(leader, scenario.nodes, out);\n // Auto-include hired nodes not already named in NEXT_PERSON\n const seenIds = new Set(leaderResult.selected.map((r) => r.id));\n for (const h of hiredByLeader) { if (!seenIds.has(h.id)) { leaderResult.selected.push(h); seenIds.add(h.id); } }\n let assignedReports = leaderResult.selected;\n let leaderAssignments = leaderResult.assignments;\n let explicitStop = hasExplicitNoDelegationDecision(out);\n let finalLeaderOutput = out;\n const needsRetry = directReports.length > 0 && assignedReports.length === 0 && !explicitStop;\n const hasUnknown = leaderResult.unknownNames.length > 0;\n const hasMissingAssignments = leaderResult.missingAssignments.length > 0;\n if (needsRetry || hasUnknown || hasMissingAssignments) {\n if (hasUnknown) await li('⚠️', `Unknown node(s) named by ${leader.label}: ${leaderResult.unknownNames.join(', ')}. Retrying.`);\n else if (hasMissingAssignments) await li('⚠️', `Missing assignments for ${leaderResult.missingAssignments.join(', ')} from ${leader.label}. Retrying.`);\n else await li('⚠️', `No explicit assignees parsed for ${leader.label}. Retrying once to force explicit selection.`);\n const retryUserMsg = hasMissingAssignments\n ? buildMissingAssignmentsRetryMessage(leader, leaderResult.missingAssignments, out)\n : buildDelegationRetryMessage(leader, directReports, userRequest, out);\n // Fresh session for retry — --resume on a killed/early-exited process is unreliable\n runnerStates.delete(leader.id);\n const retryOut = await runNodeCall(conversationId, leader, systemPrompt, retryUserMsg, runOverrides, signal, publish, (delta) => {\n publish({ type: 'node_delta', nodeId: leader.id, text: delta });\n }, runnerStates, 'dispatch-retry', readme);\n const hiredOnRetry = applyHireDirectivesFromOutput(leader, scenario, retryOut);\n if (hiredOnRetry.length > 0) {\n await scenarioRunStore.saveScenarioSnapshot(conversationId, scenario);\n await li('🆕', `${leader.label} hired on retry: ${hiredOnRetry.map((p) => `${p.label} (${p.role})`).join(', ')}`);\n }\n const retryResult = selectExplicitDirectReportsFromOutput(leader, scenario.nodes, retryOut);\n const seenRetryIds = new Set(retryResult.selected.map((r) => r.id));\n for (const h of hiredOnRetry) { if (!seenRetryIds.has(h.id)) { retryResult.selected.push(h); seenRetryIds.add(h.id); } }\n assignedReports = retryResult.selected;\n leaderAssignments = new Map([...leaderAssignments, ...retryResult.assignments]);\n explicitStop = hasExplicitNoDelegationDecision(retryOut);\n finalLeaderOutput = `${out}\\n\\n## Delegation Retry Output\\n${retryOut}`;\n if (assignedReports.length === 0 && !explicitStop) {\n throw new Error(`No explicit assignees parsed for ${leader.label} after retry`);\n }\n if (assignedReports.length > 0) {\n await li('✅', `Explicit assignees parsed for ${leader.label} after retry.`);\n }\n }\n if (assignedReports.length === 0 && explicitStop) {\n await li('⏹️', `${leader.label} explicitly chose to delegate to nobody (STOP).`);\n }\n\n outputs.set(leader.id, finalLeaderOutput);\n leaderDispatchOutput = finalLeaderOutput;\n await appendNodeOutput(conversationId, leader, finalLeaderOutput);\n\n byParent.set(leader.id, assignedReports);\n scenarioRunStore.setNodeState(conversationId, leader.id, assignedReports.length > 0 ? 'waiting' : 'done');\n scenarioRunStore.setNodeOutput(conversationId, leader.id, finalLeaderOutput);\n await scenarioRunStore.persistRunState(conversationId);\n\n for (const report of assignedReports) {\n await li('→', `**${report.label}** assigned by ${leader.label}`);\n }\n leaderDispatchAssignments = leaderAssignments;\n await li('✅', `**${leader.label}** (Leader) — done in ${fmtDuration(startedAt)}`);\n publish({ type: 'node_done', nodeId: leader.id, output: finalLeaderOutput, state: scenarioRunStore.getRunState(conversationId)?.nodeStates[leader.id] ?? 'done' });\n } catch (err) {\n if (signal.aborted) throw err;\n const msg = (err as Error).message;\n scenarioRunStore.setNodeState(conversationId, leader.id, 'error');\n await readme(`### [${ts()}] ❌ ${leader.label} (Leader) — FAILED after ${fmtDuration(startedAt)}: ${msg}\\n`);\n publish({ type: 'node_error', nodeId: leader.id, error: msg });\n runnerStates.delete(leader.id);\n const leaderErrorOutput = `❌ Leader failed: ${msg}`;\n scenarioRunStore.setNodeOutput(conversationId, leader.id, leaderErrorOutput);\n await appendNodeOutput(conversationId, leader, leaderErrorOutput);\n publish({ type: 'node_delta', nodeId: leader.id, text: `\\n\\n${leaderErrorOutput}` });\n throw new Error(`Leader failed: ${msg}`);\n }\n }\n\n // Group execution with parent review loops:\n // manager executes -> children execute -> manager reviews and decides STOP or targeted re-run.\n async function runDelegationPass(\n node: ScenarioNode,\n userMsg: string,\n modeLabel: string,\n ): Promise<{ finalOutput: string; assignedReports: ScenarioNode[]; assignments: Map<string, string> }> {\n const startedAt = Date.now();\n publish({ type: 'node_started', nodeId: node.id });\n scenarioRunStore.setNodeState(conversationId, node.id, 'running');\n await li('▶️', `**${node.label}** — started`);\n try {\n const manager = node.parentIds[0] ? nodesById.get(node.parentIds[0]) ?? null : null;\n const systemPrompt = buildSystemPrompt(node, scenario);\n const out = await runNodeCall(conversationId, node, systemPrompt, userMsg, runOverrides, signal, publish, (delta) => {\n publish({ type: 'node_delta', nodeId: node.id, text: delta });\n }, runnerStates, modeLabel, readme);\n const hiredByNode = applyHireDirectivesFromOutput(node, scenario, out);\n if (hiredByNode.length > 0) {\n await scenarioRunStore.saveScenarioSnapshot(conversationId, scenario);\n await li('🆕', `${node.label} hired: ${hiredByNode.map((p) => `${p.label} (${p.role})`).join(', ')}`);\n }\n\n const directReports = getDirectReports(scenario.nodes, node.id);\n let nodeResult = selectExplicitDirectReportsFromOutput(node, scenario.nodes, out);\n const seenIds = new Set(nodeResult.selected.map((r) => r.id));\n for (const h of hiredByNode) { if (!seenIds.has(h.id)) { nodeResult.selected.push(h); seenIds.add(h.id); } }\n let assignedReports = nodeResult.selected;\n let assignments = nodeResult.assignments;\n let explicitStop = hasExplicitNoDelegationDecision(out);\n let finalOutput = out;\n const needsRetry = directReports.length > 0 && assignedReports.length === 0 && !explicitStop;\n const hasUnknown = nodeResult.unknownNames.length > 0;\n const hasMissingAssignments = nodeResult.missingAssignments.length > 0;\n if (needsRetry || hasUnknown || hasMissingAssignments) {\n if (hasUnknown) await li('⚠️', `Unknown node(s) named by ${node.label}: ${nodeResult.unknownNames.join(', ')}. Retrying.`);\n else if (hasMissingAssignments) await li('⚠️', `Missing assignments for ${nodeResult.missingAssignments.join(', ')} from ${node.label}. Retrying.`);\n else await li('⚠️', `No explicit assignees parsed for ${node.label}. Retrying once to force explicit selection.`);\n const retryUserMsg = hasMissingAssignments\n ? buildMissingAssignmentsRetryMessage(node, nodeResult.missingAssignments, out)\n : buildDelegationRetryMessage(node, directReports, userRequest, out);\n // Fresh session for retry — --resume on a killed/early-exited process is unreliable\n runnerStates.delete(node.id);\n const retryOut = await runNodeCall(conversationId, node, systemPrompt, retryUserMsg, runOverrides, signal, publish, (delta) => {\n publish({ type: 'node_delta', nodeId: node.id, text: delta });\n }, runnerStates, `${modeLabel}-retry`, readme);\n const hiredOnRetry = applyHireDirectivesFromOutput(node, scenario, retryOut);\n if (hiredOnRetry.length > 0) {\n await scenarioRunStore.saveScenarioSnapshot(conversationId, scenario);\n await li('🆕', `${node.label} hired on retry: ${hiredOnRetry.map((p) => `${p.label} (${p.role})`).join(', ')}`);\n }\n const retryResult = selectExplicitDirectReportsFromOutput(node, scenario.nodes, retryOut);\n const seenRetryIds = new Set(retryResult.selected.map((r) => r.id));\n for (const h of hiredOnRetry) { if (!seenRetryIds.has(h.id)) { retryResult.selected.push(h); seenRetryIds.add(h.id); } }\n assignedReports = retryResult.selected;\n assignments = new Map([...assignments, ...retryResult.assignments]);\n explicitStop = hasExplicitNoDelegationDecision(retryOut);\n finalOutput = `${out}\\n\\n## Delegation Retry Output\\n${retryOut}`;\n if (assignedReports.length === 0 && !explicitStop) {\n throw new Error(`No explicit assignees parsed for ${node.label} after retry`);\n }\n if (assignedReports.length > 0) {\n await li('✅', `Explicit assignees parsed for ${node.label} after retry.`);\n }\n }\n if (assignedReports.length === 0 && explicitStop) {\n await li('⏹️', `${node.label} explicitly chose to delegate to nobody (STOP).`);\n }\n\n outputs.set(node.id, finalOutput);\n await appendNodeOutput(conversationId, node, finalOutput);\n byParent.set(node.id, assignedReports);\n\n scenarioRunStore.setNodeState(conversationId, node.id, assignedReports.length > 0 ? 'waiting' : 'done');\n scenarioRunStore.setNodeOutput(conversationId, node.id, finalOutput);\n await scenarioRunStore.persistRunState(conversationId);\n\n if (assignedReports.length > 0) {\n for (const report of assignedReports) {\n await li('→', `**${report.label}** assigned by ${node.label}`);\n }\n }\n const reportTo = manager ? manager.label : 'Leader';\n await li('✅', `**${node.label}** (${node.role ?? 'other'}) — done in ${fmtDuration(startedAt)}, reporting to ${reportTo}`);\n publish({ type: 'node_done', nodeId: node.id, output: finalOutput, state: scenarioRunStore.getRunState(conversationId)?.nodeStates[node.id] ?? 'done' });\n return { finalOutput, assignedReports, assignments };\n } catch (err) {\n if (signal.aborted) throw err;\n const msg = (err as Error).message;\n scenarioRunStore.setNodeState(conversationId, node.id, 'error');\n await li('❌', `**${node.label}** — error after ${fmtDuration(startedAt)}: ${msg}`);\n publish({ type: 'node_error', nodeId: node.id, error: msg });\n // Reset runner state so next retry starts a fresh session\n runnerStates.delete(node.id);\n const errorOutput = `[ERROR: ${node.label} failed — ${msg}]\\n\\n${outputs.get(node.id) ?? ''}`.trim();\n outputs.set(node.id, errorOutput);\n scenarioRunStore.setNodeOutput(conversationId, node.id, errorOutput);\n await appendNodeOutput(conversationId, node, `\\n\\n❌ Error: ${msg}`);\n publish({ type: 'node_delta', nodeId: node.id, text: `\\n\\n❌ Error: ${msg}` });\n return { finalOutput: errorOutput, assignedReports: [], assignments: new Map() };\n }\n }\n\n async function runAskNode(node: ScenarioNode): Promise<string> {\n const question = node.question?.trim() || node.label || node.id;\n publish({ type: 'node_started', nodeId: node.id });\n scenarioRunStore.setNodeState(conversationId, node.id, 'waiting_input');\n scenarioRunStore.setWaitingInput(conversationId, node.id, question);\n publish({ type: 'node_waiting_input', nodeId: node.id, question });\n await readme(`- ❓ [${ts()}] **${node.label || node.id}** — waiting for user input\\n`);\n\n const answer = await new Promise<string>((resolve, reject) => {\n const key = pendingNodeKey(conversationId, node.id);\n pendingNodeInputs.set(key, resolve);\n signal.addEventListener('abort', () => {\n pendingNodeInputs.delete(key);\n reject(new Error('Aborted'));\n }, { once: true });\n });\n\n scenarioRunStore.clearWaitingInput(conversationId, node.id);\n await readme(`- 💬 [${ts()}] **User replied** to ${node.label || node.id}\\n`);\n const output = `**Question:** ${question}\\n\\n**Answer:** ${answer}`;\n scenarioRunStore.setNodeOutput(conversationId, node.id, output);\n outputs.set(node.id, output);\n scenarioRunStore.setNodeState(conversationId, node.id, 'done');\n publish({ type: 'node_done', nodeId: node.id, output, state: 'done' });\n return output;\n }\n\n async function runNodeSubtree(node: ScenarioNode, managerOutput: string | null): Promise<void> {\n // Ask node: skip AI entirely, wait for human input\n if (node.type === 'ask') {\n if (!isSubtreeComplete(node.id)) await runAskNode(node);\n else {\n publish({ type: 'node_state_change', nodeId: node.id, state: 'done' });\n publish({ type: 'node_done', nodeId: node.id, output: outputs.get(node.id) ?? '', state: 'done' });\n }\n return;\n }\n\n // Resume: skip entire subtree if all persons in it are done\n if (isSubtreeComplete(node.id)) {\n publish({ type: 'node_state_change', nodeId: node.id, state: 'done' });\n publish({ type: 'node_done', nodeId: node.id, output: outputs.get(node.id) ?? '', state: 'done' });\n return;\n }\n\n // Resume: if this node's own execution is cached but children aren't all done,\n // use cached output to derive delegation (skip the AI call for this node only)\n let firstPassResult: { finalOutput: string; assignedReports: ScenarioNode[]; assignments: Map<string, string> };\n if (persistedState && outputs.has(node.id)) {\n const cachedOut = outputs.get(node.id)!;\n const result = selectExplicitDirectReportsFromOutput(node, scenario.nodes, cachedOut);\n byParent.set(node.id, result.selected);\n const newState = result.selected.length > 0 ? 'waiting' : 'done';\n scenarioRunStore.setNodeState(conversationId, node.id, newState);\n scenarioRunStore.setNodeOutput(conversationId, node.id, cachedOut);\n publish({ type: 'node_state_change', nodeId: node.id, state: newState });\n publish({ type: 'node_done', nodeId: node.id, output: cachedOut, state: newState });\n await li('♻️', `**${node.label}** — restored from previous run`);\n firstPassResult = { finalOutput: cachedOut, assignedReports: result.selected, assignments: result.assignments };\n } else {\n const initialUserMsg = buildUserMessage(node, scenario, userRequest, managerOutput, false, false);\n firstPassResult = await runDelegationPass(node, initialUserMsg, '(execution)');\n }\n\n let { finalOutput, assignedReports, assignments } = firstPassResult;\n\n let reviewRound = 0;\n while (assignedReports.length > 0) {\n if (signal.aborted) throw new Error('Aborted');\n reviewRound += 1;\n if (reviewRound > MAX_MANAGER_REVIEW_ROUNDS) {\n throw new Error(`${node.label} exceeded review loop limit (${MAX_MANAGER_REVIEW_ROUNDS})`);\n }\n\n await readme(`\\n### [${ts()}] Review loop ${reviewRound} for ${node.label} — collecting child reports\\n`);\n await Promise.all(assignedReports.map((report) => {\n const instruction = assignments.get(report.id) ?? null;\n return runNodeSubtree(report, instruction ?? finalOutput);\n }));\n\n const childReportsSection = assignedReports\n .map((report) => {\n const reportOut = outputs.get(report.id) ?? '';\n return `<child_report node=\"${report.label}\" id=\"${report.id}\">\\n${reportOut}\\n</child_report>`;\n })\n .join('\\n\\n');\n\n const reviewUserMsg = buildManagerReviewMessage(\n node,\n getDirectReports(scenario.nodes, node.id),\n userRequest,\n finalOutput,\n childReportsSection,\n );\n const pass = await runDelegationPass(node, reviewUserMsg, `(review round ${reviewRound})`);\n finalOutput = pass.finalOutput;\n assignedReports = pass.assignedReports;\n assignments = pass.assignments;\n }\n }\n\n if (scenario.traversalMode === 'topological') {\n // ── Topological mode: level-by-level, siblings run in parallel ──\n // Helper: get all parent IDs of a node (parentId + parentIds)\n const allParentIds = (n: ScenarioNode): string[] => n.parentIds ?? [];\n // Helper: get all children of a node (nodes that list it as any parent)\n const allChildren = (nodeId: string): ScenarioNode[] =>\n scenario.nodes.filter((n) => allParentIds(n).includes(nodeId));\n\n // Build levels: a node's level = max(parent levels) + 1\n const nodeLevelMap = new Map<string, number>();\n nodeLevelMap.set(leader.id, 0);\n // BFS to assign levels\n const bfsQueue: ScenarioNode[] = [leader];\n while (bfsQueue.length > 0) {\n const cur = bfsQueue.shift()!;\n const curLevel = nodeLevelMap.get(cur.id) ?? 0;\n for (const child of allChildren(cur.id)) {\n const newLevel = curLevel + 1;\n const existing = nodeLevelMap.get(child.id) ?? -1;\n if (newLevel > existing) {\n nodeLevelMap.set(child.id, newLevel);\n bfsQueue.push(child);\n }\n }\n }\n // Group nodes by level\n const maxLevel = Math.max(...nodeLevelMap.values());\n const levels: ScenarioNode[][] = Array.from({ length: maxLevel + 1 }, () => []);\n for (const node of scenario.nodes) {\n const lvl = nodeLevelMap.get(node.id);\n if (lvl !== undefined) levels[lvl].push(node);\n }\n\n const runTopoNode = async (node: ScenarioNode) => {\n if (signal.aborted) throw new Error('Aborted');\n\n // Ask node: skip AI entirely, wait for human input\n if (node.type === 'ask') {\n if (persistedState && outputs.has(node.id)) {\n scenarioRunStore.setNodeState(conversationId, node.id, 'done');\n scenarioRunStore.setNodeOutput(conversationId, node.id, outputs.get(node.id)!);\n publish({ type: 'node_state_change', nodeId: node.id, state: 'done' });\n publish({ type: 'node_done', nodeId: node.id, output: outputs.get(node.id)!, state: 'done' });\n await li('♻️', `**${node.label}** — restored from previous run`);\n } else {\n await runAskNode(node);\n }\n return;\n }\n\n // Resume: skip already-done nodes\n if (persistedState && outputs.has(node.id)) {\n const cached = outputs.get(node.id)!;\n scenarioRunStore.setNodeState(conversationId, node.id, 'done');\n scenarioRunStore.setNodeOutput(conversationId, node.id, cached);\n publish({ type: 'node_state_change', nodeId: node.id, state: 'done' });\n publish({ type: 'node_done', nodeId: node.id, output: cached, state: 'done' });\n await li('♻️', `**${node.label}** — restored from previous run`);\n return;\n }\n\n const startedAt = Date.now();\n publish({ type: 'node_started', nodeId: node.id });\n scenarioRunStore.setNodeState(conversationId, node.id, 'running');\n await readme(`### [${ts()}] ▶️ ${node.label} — started\\n`);\n await li('▶️', `**${node.label}** — started`);\n\n try {\n const parentOutput = node.parentIds[0] ? outputs.get(node.parentIds[0]) ?? null : null;\n const systemPrompt = buildSystemPrompt(node, scenario);\n const userMsg = buildUserMessage(node, scenario, userRequest, parentOutput, false, false, new Map(outputs));\n const out = await runNodeCall(conversationId, node, systemPrompt, userMsg, runOverrides, signal, publish, (delta) => {\n publish({ type: 'node_delta', nodeId: node.id, text: delta });\n }, runnerStates, '(topological)', readme);\n\n outputs.set(node.id, out);\n scenarioRunStore.setNodeState(conversationId, node.id, 'done');\n scenarioRunStore.setNodeOutput(conversationId, node.id, out);\n await scenarioRunStore.persistRunState(conversationId);\n await appendNodeOutput(conversationId, node, out);\n await li('✅', `**${node.label}** — done in ${fmtDuration(startedAt)}`);\n publish({ type: 'node_done', nodeId: node.id, output: out, state: 'done' });\n } catch (err) {\n if (signal.aborted) throw err;\n const msg = (err as Error).message;\n scenarioRunStore.setNodeState(conversationId, node.id, 'error');\n await readme(`### [${ts()}] ❌ ${node.label} — FAILED after ${fmtDuration(startedAt)}: ${msg}\\n`);\n publish({ type: 'node_error', nodeId: node.id, error: msg });\n runnerStates.delete(node.id);\n throw new Error(`${node.label} failed: ${msg}`);\n }\n };\n\n for (const level of levels) {\n // Run all nodes in the same level in parallel, wait before next level\n await Promise.all(level.map(runTopoNode));\n }\n } else {\n // ── Hierarchical mode: leader review loops + recursive subtree runs ──\n let leaderAssignedReports = byParent.get(leader.id) ?? [];\n let leaderCurrentOutput = leaderDispatchOutput ?? outputs.get(leader.id) ?? '';\n let leaderAssignments: Map<string, string> = leaderDispatchAssignments;\n let leaderReviewRound = 0;\n\n while (leaderAssignedReports.length > 0) {\n if (signal.aborted) throw new Error('Aborted');\n leaderReviewRound += 1;\n if (leaderReviewRound > MAX_MANAGER_REVIEW_ROUNDS) {\n throw new Error(`${leader.label} exceeded review loop limit (${MAX_MANAGER_REVIEW_ROUNDS})`);\n }\n\n await readme(`\\n### [${ts()}] Leader review loop ${leaderReviewRound} — running assigned children in parallel\\n`);\n await Promise.all(leaderAssignedReports.map((report) => {\n const instruction = leaderAssignments.get(report.id) ?? null;\n return runNodeSubtree(report, instruction ?? leaderCurrentOutput);\n }));\n\n const leaderChildReportsSection = leaderAssignedReports\n .map((report) => {\n const reportOut = outputs.get(report.id) ?? '';\n return `<child_report node=\"${report.label}\" id=\"${report.id}\">\\n${reportOut}\\n</child_report>`;\n })\n .join('\\n\\n');\n\n const leaderReviewMsg = buildManagerReviewMessage(\n leader,\n getDirectReports(scenario.nodes, leader.id),\n userRequest,\n leaderCurrentOutput,\n leaderChildReportsSection,\n );\n const leaderPass = await runDelegationPass(leader, leaderReviewMsg, `(leader review round ${leaderReviewRound})`);\n leaderCurrentOutput = leaderPass.finalOutput;\n leaderDispatchOutput = leaderCurrentOutput;\n leaderAssignedReports = leaderPass.assignedReports;\n leaderAssignments = leaderPass.assignments;\n }\n\n resolveWaitingStates(scenario.nodes, conversationId, byParent, publish, new Set([scenario.leaderId]));\n }\n\n // ── Phase 2: Leader synthesis → writes FINAL.md ────────────────────────\n const synthesisKey = `${leader.id}:synthesis`;\n const synthesisAlreadyDone = persistedState?.nodeStates[synthesisKey] === 'synthesized'\n && !!persistedState?.nodeOutputs[synthesisKey];\n\n if (synthesisAlreadyDone) {\n const summary = persistedState!.nodeOutputs[synthesisKey]!;\n await writeFinalMd(conversationId, bus, userRequest, summary);\n finalWritten = true;\n scenarioRunStore.setNodeState(conversationId, leader.id, 'done');\n publish({ type: 'node_state_change', nodeId: leader.id, state: 'done' });\n scenarioRunStore.setNodeState(conversationId, synthesisKey, 'synthesized');\n publish({ type: 'node_state_change', nodeId: synthesisKey, state: 'synthesized' });\n publish({ type: 'scenario_complete', summary });\n await li('♻️', `Synthesis restored from previous run`);\n } else if (scenario.nodes.length > 1) {\n const startedAt = Date.now();\n publish({ type: 'node_started', nodeId: `${leader.id}:synthesis` });\n await readme(`\\n### [${ts()}] 🔄 ${leader.label} (Leader) — synthesizing all outputs\\n`);\n await li('▶️', `**${leader.label}** synthesis — started`);\n\n try {\n const systemPrompt = buildSystemPrompt(leader, scenario);\n const userMsg = buildUserMessage(leader, scenario, userRequest, null, true, false, outputs);\n\n let summary = '';\n summary = await runNodeCall(conversationId, leader, systemPrompt, userMsg, runOverrides, signal, publish, (delta) => {\n publish({ type: 'node_delta', nodeId: `${leader.id}:synthesis`, text: delta });\n }, runnerStates, 'synthesis', readme);\n\n await writeFinalMd(conversationId, bus, userRequest, summary);\n finalWritten = true;\n\n // Leader completion condition: FINAL.md has been written.\n scenarioRunStore.setNodeState(conversationId, leader.id, 'done');\n publish({ type: 'node_state_change', nodeId: leader.id, state: 'done' });\n\n scenarioRunStore.setNodeState(conversationId, `${leader.id}:synthesis`, 'synthesized');\n scenarioRunStore.setNodeOutput(conversationId, `${leader.id}:synthesis`, summary);\n await scenarioRunStore.persistRunState(conversationId);\n\n await li('✅', `**${leader.label}** synthesis — done in ${fmtDuration(startedAt)}`);\n publish({ type: 'node_done', nodeId: `${leader.id}:synthesis`, output: summary, state: 'synthesized' });\n publish({ type: 'scenario_complete', summary });\n } catch (err) {\n if (signal.aborted) throw err;\n // Synthesis failed — write FINAL.md with what we have as fallback\n const fallback = [...outputs.entries()]\n .map(([id, out]) => {\n const p = scenario.nodes.find(x => x.id === id);\n const name = p ? p.label.trim() : id;\n return `### ${name}\\n\\n${out}`;\n })\n .join('\\n\\n---\\n\\n');\n await readme(`\\n⚠️ Leader synthesis failed — writing partial FINAL.md\\n`);\n await li('❌', `**${leader.label}** synthesis — failed after ${fmtDuration(startedAt)}`);\n await writeFinalMd(conversationId, bus, userRequest, fallback);\n finalWritten = true;\n // Leader completion condition: FINAL.md has been written.\n scenarioRunStore.setNodeState(conversationId, leader.id, 'done');\n publish({ type: 'node_state_change', nodeId: leader.id, state: 'done' });\n publish({ type: 'scenario_complete', summary: fallback });\n }\n } else {\n // Solo leader — their output IS the final\n const summary = leaderDispatchOutput ?? outputs.get(leader.id) ?? '';\n await writeFinalMd(conversationId, bus, userRequest, summary);\n finalWritten = true;\n // Leader completion condition: FINAL.md has been written.\n scenarioRunStore.setNodeState(conversationId, leader.id, 'done');\n publish({ type: 'node_state_change', nodeId: leader.id, state: 'done' });\n publish({ type: 'scenario_complete', summary });\n }\n } catch (err) {\n if (!signal.aborted) {\n const msg = (err as Error).message;\n // Guard: if we exit without FINAL.md, report it explicitly\n if (!finalWritten) {\n await appendToReadme(conversationId, bus,\n `\\n### [${ts()}] 🚨 GUARD: Run ended without FINAL.md — ${msg}\\n`,\n ).catch(() => {/* non-fatal */});\n }\n publish({ type: 'scenario_error', error: msg });\n }\n } finally {\n if (!finalWritten && !signal.aborted) {\n // Secondary guard: bus closing without FINAL.md written\n await appendToReadme(conversationId, bus,\n `\\n### [${ts()}] 🚨 GUARD: No FINAL.md detected at end of run. Check individual agent outputs.\\n`,\n ).catch(() => {/* non-fatal */});\n }\n // Final persist: capture any state changes (solo-leader done, synthesis\n // fallback, last-second updates) so a reload after completion shows the\n // finished scenario instead of a fresh-looking one.\n await scenarioRunStore.persistRunState(conversationId).catch(() => {/* non-fatal */});\n publishToBus(bus, null); // signal end-of-stream\n activeAbortControllers.delete(conversationId);\n }\n }\n\n // Fire-and-forget — run asynchronously so callers can subscribe immediately\n execute().catch(() => {/* errors published to bus */});\n}\n","import type { ScenarioPreset } from '@runeya/packages-shared';\n\nconst BUILT_IN_PRESETS: ScenarioPreset[] = [\n {\n id: 'enterprise',\n name: 'Enterprise',\n icon: 'pi-building',\n labels: {\n group: { en: 'Department', fr: 'Département' },\n node: { en: 'Employee', fr: 'Employé' },\n role: { en: 'Position', fr: 'Poste' },\n leader: { en: 'Director', fr: 'Directeur' },\n },\n defaultTraversalMode: 'hierarchical',\n canChangeTraversalMode: false,\n initialData: {\n leaderId: 'leader',\n groups: [\n { id: 'group-management', name: 'Management', position: { x: 0, y: 0 }, width: 300, height: 200 },\n ],\n nodes: [\n {\n id: 'leader',\n type: 'ai' as const,\n parentIds: [],\n groupId: 'group-management',\n label: 'Leader One',\n role: 'manager',\n prompt: 'Analyze the objective. Break it into concrete tasks and assign each to the right team member with a clear expected output. Do not do the technical work yourself.',\n question: '',\n autoGenerated: false,\n canAddNode: false,\n aiCli: 'claude-code',\n model: 'sonnet',\n position: { x: 50, y: 50 },\n },\n ],\n },\n roles: [\n {\n id: 'manager',\n name: 'Manager',\n systemPrompt: [\n 'You are a MANAGER. Your only job is to coordinate, plan, and delegate.',\n 'NEVER write code, scripts, or any technical artifact — not even as an example.',\n 'NEVER answer a technical question directly — always assign it to the right person.',\n 'Output only: task breakdowns, assignments, decisions, and synthesis.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'engineer',\n name: 'Engineer',\n systemPrompt: [\n 'You are an ENGINEER. Write working, production-ready code.',\n 'Always prefer real implementation over pseudocode or high-level descriptions.',\n 'Be concise in prose; let the code speak.',\n 'Output: source files, architecture decisions, technical specifications.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'designer',\n name: 'Designer',\n systemPrompt: [\n 'You are a DESIGNER. Define UX flows, visual hierarchy, and interaction patterns.',\n 'NEVER write code or CSS.',\n 'Describe interfaces in structured text: component name, layout, states, behavior.',\n 'Output: text wireframes, design decisions, component specs, UX guidelines.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'analyst',\n name: 'Analyst',\n systemPrompt: [\n 'You are an ANALYST. Investigate data, identify patterns, and surface actionable insights.',\n 'NEVER write code or scripts — if you need data processed, request it from an Engineer.',\n 'Output: structured analysis, metrics, findings, and evidence-based recommendations.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'qa',\n name: 'QA',\n systemPrompt: [\n 'You are a QA ENGINEER. Define what must be tested and how.',\n 'NEVER write implementation code.',\n 'You may write Gherkin / BDD scenarios or structured test cases as plain text.',\n 'Output: test plans, test cases, edge cases, risk assessments, acceptance criteria.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'devops',\n name: 'DevOps',\n systemPrompt: [\n 'You are a DEVOPS ENGINEER. Own infrastructure, deployment, and operations.',\n 'Write actual scripts and configuration files (shell, YAML, HCL, Dockerfile…) — no pseudocode.',\n 'Output: scripts, CI/CD pipelines, infrastructure-as-code, runbooks.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'product',\n name: 'Product',\n systemPrompt: [\n 'You are a PRODUCT MANAGER. Own requirements and priorities.',\n 'NEVER write code or technical specifications.',\n 'Output: PRDs, user stories with acceptance criteria, prioritization decisions, roadmap items.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'writer',\n name: 'Writer',\n systemPrompt: [\n 'You are a TECHNICAL WRITER. Produce clear, accurate, well-structured written content.',\n 'NEVER write code. If a code example is needed, flag it for an Engineer.',\n 'Output: documentation, guides, release notes, changelogs, communication drafts.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'researcher',\n name: 'Researcher',\n systemPrompt: [\n 'You are a RESEARCHER. Gather information, compare options, and synthesize knowledge into actionable insights.',\n 'NEVER write code.',\n 'Output: research summaries, comparisons, pros/cons analyses, evidence-based recommendations.',\n ].join('\\n'),\n prompt: '',\n },\n {\n id: 'other',\n name: 'Other',\n systemPrompt: '',\n prompt: '',\n },\n ],\n },\n];\n\nexport function listPresets(): ScenarioPreset[] {\n return BUILT_IN_PRESETS;\n}\n\nexport function getPreset(id: string): ScenarioPreset | undefined {\n return BUILT_IN_PRESETS.find(p => p.id === id);\n}\n","import { randomUUID } from 'node:crypto';\nimport { TRPCError } from '@trpc/server';\nimport { z } from 'zod';\nimport { protectedProcedure, router } from '../trpc.js';\n\ntype RandomTickEvent = {\n type: 'tick';\n jobId: string;\n index: number;\n value: number;\n at: number;\n};\n\ntype RandomDoneEvent = {\n type: 'done';\n jobId: string;\n reason: 'stopped' | 'max_ticks';\n at: number;\n};\n\ntype RandomJobEvent = RandomTickEvent | RandomDoneEvent;\n\ninterface RandomJob {\n id: string;\n startedAt: number;\n intervalMs: number;\n maxTicks: number;\n tick: number;\n done: boolean;\n timer: ReturnType<typeof setInterval>;\n buffer: RandomJobEvent[];\n baseIndex: number;\n listeners: Set<(event: RandomJobEvent | null) => void>;\n}\n\nconst MAX_BUFFER = 300;\nconst jobs = new Map<string, RandomJob>();\n\nfunction publish(job: RandomJob, event: RandomJobEvent | null): void {\n if (event) {\n job.buffer.push(event);\n if (job.buffer.length > MAX_BUFFER) {\n job.buffer.shift();\n job.baseIndex += 1;\n }\n } else {\n job.done = true;\n }\n\n for (const listener of job.listeners) listener(event);\n job.listeners.clear();\n}\n\nfunction stopJob(jobId: string, reason: 'stopped' | 'max_ticks'): boolean {\n const job = jobs.get(jobId);\n if (!job) return false;\n if (job.done) return true;\n\n clearInterval(job.timer);\n publish(job, { type: 'done', jobId, reason, at: Date.now() });\n publish(job, null);\n jobs.delete(jobId);\n return true;\n}\n\nasync function* tapJob(job: RandomJob, signal: AbortSignal): AsyncGenerator<RandomJobEvent> {\n let cursor = job.baseIndex;\n\n while (true) {\n if (cursor < job.baseIndex) cursor = job.baseIndex;\n while (cursor < job.baseIndex + job.buffer.length) {\n const evt = job.buffer[cursor - job.baseIndex];\n cursor += 1;\n if (!evt) continue;\n yield evt;\n }\n\n if (job.done || signal.aborted) return;\n\n await new Promise<void>((resolve) => {\n const onAbort = () => {\n job.listeners.delete(notify);\n resolve();\n };\n\n const notify = () => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n };\n\n job.listeners.add(notify);\n signal.addEventListener('abort', onAbort, { once: true });\n if (cursor < job.baseIndex + job.buffer.length || job.done || signal.aborted) {\n job.listeners.delete(notify);\n signal.removeEventListener('abort', onAbort);\n resolve();\n }\n });\n }\n}\n\nexport const debugRouter = router({\n startRandomJob: protectedProcedure\n .input(z.object({\n intervalMs: z.number().int().min(100).max(5000).optional(),\n maxTicks: z.number().int().min(1).max(10000).optional(),\n }).optional())\n .mutation(({ input }) => {\n const jobId = randomUUID();\n const intervalMs = input?.intervalMs ?? 400;\n const maxTicks = input?.maxTicks ?? 500;\n\n const job: RandomJob = {\n id: jobId,\n startedAt: Date.now(),\n intervalMs,\n maxTicks,\n tick: 0,\n done: false,\n timer: setInterval(() => {\n const current = jobs.get(jobId);\n if (!current || current.done) return;\n\n current.tick += 1;\n publish(current, {\n type: 'tick',\n jobId,\n index: current.tick,\n value: Math.random(),\n at: Date.now(),\n });\n\n if (current.tick >= current.maxTicks) {\n stopJob(jobId, 'max_ticks');\n }\n }, intervalMs),\n buffer: [],\n baseIndex: 0,\n listeners: new Set(),\n };\n\n jobs.set(jobId, job);\n return { jobId, intervalMs, maxTicks, startedAt: job.startedAt };\n }),\n\n streamRandomJob: protectedProcedure\n .input(z.object({ jobId: z.string().max(128) }))\n .subscription(async function* ({ input, signal }) {\n const job = jobs.get(input.jobId);\n if (!job) {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'Random job not found' });\n }\n\n yield* tapJob(job, signal ?? new AbortController().signal);\n }),\n\n stopRandomJob: protectedProcedure\n .input(z.object({ jobId: z.string().max(128) }))\n .mutation(({ input }) => ({ ok: stopJob(input.jobId, 'stopped') })),\n\n randomJobStatus: protectedProcedure\n .input(z.object({ jobId: z.string().max(128) }))\n .query(({ input }) => {\n const job = jobs.get(input.jobId);\n return {\n running: !!job && !job.done,\n tick: job?.tick ?? 0,\n };\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { protectedProcedure, router } from '../trpc.js';\nimport { recentEntries, entriesSince, onEntry, type LogEntry } from '../../services/log-buffer.js';\nimport { listInstances, killInstance, restartInstance, scheduleSelfRestart } from '../../services/instance-registry.js';\n\n/**\n * Live view of what this Runeya is doing, and of the other Runeya instances\n * sharing the machine.\n *\n * Everything here is `protectedProcedure`: the log stream carries whatever the\n * server and agent print, which routinely includes paths, project names and\n * command lines. It is diagnostic data, not public data.\n */\nexport const diagnosticsRouter = router({\n /** Backlog for a client that just opened the panel. */\n recentLogs: protectedProcedure\n .input(z.object({ limit: z.number().int().min(1).max(2000).default(500) }).optional())\n .query(({ input }) => recentEntries(input?.limit ?? 500)),\n\n /**\n * Live log stream.\n *\n * `afterSeq` lets a reconnecting client ask for what it missed instead of\n * restarting from an arbitrary window — without it, a dropped WebSocket\n * silently loses lines, which is precisely what someone watching a boot\n * failure cannot afford.\n */\n streamLogs: protectedProcedure\n .input(z.object({ afterSeq: z.number().int().nonnegative().default(0) }).optional())\n .subscription(async function* ({ input, signal }) {\n // Replay first, so nothing between the query and the subscription is lost.\n for (const entry of entriesSince(input?.afterSeq ?? 0)) yield entry;\n\n const queue: LogEntry[] = [];\n let wake: (() => void) | null = null;\n\n const off = onEntry((entry) => {\n queue.push(entry);\n wake?.();\n });\n\n try {\n while (!signal?.aborted) {\n if (queue.length === 0) {\n await new Promise<void>((resolve) => {\n wake = resolve;\n // Wake on abort too, otherwise an idle stream would hold the\n // generator open until the next line — which may never come.\n signal?.addEventListener('abort', () => resolve(), { once: true });\n });\n wake = null;\n continue;\n }\n yield queue.shift()!;\n }\n } finally {\n off();\n }\n }),\n\n /** Every Runeya answering on this machine, this one included. */\n instances: protectedProcedure.query(() => listInstances()),\n\n /**\n * Stop another Runeya on this machine — its agent first, then its server.\n *\n * The pid is a *selector*, not an instruction: it is looked up in the list\n * `listInstances()` has just vouched for, and anything absent from it is\n * refused. That is what keeps this from being a way to signal arbitrary\n * processes with the server's privileges.\n */\n killInstance: protectedProcedure\n .input(z.object({ pid: z.number().int().positive() }))\n .mutation(async ({ input }) => {\n try {\n return await killInstance(input.pid);\n } catch (err) {\n const reason = (err as Error).message;\n if (reason === 'instance-not-found') {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'No live Runeya instance with this pid.' });\n }\n if (reason === 'instance-is-current') {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'This instance cannot stop itself.' });\n }\n throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: reason });\n }\n }),\n\n /**\n * Redémarrer une Runeya de cette machine : même exécutable, mêmes arguments,\n * même répertoire, mêmes `RUNEYA_*`.\n *\n * Deux chemins pour une même promesse. Une autre instance est arrêtée puis\n * relancée d'ici, et la réponse dit ce qui s'est passé. Celle-ci ne peut pas :\n * elle répond d'abord, pose un relanceur détaché, et part — d'où un résultat\n * qui annonce un redémarrage à venir plutôt qu'un redémarrage fait.\n *\n * Mêmes garde-fous que `killInstance` — le pid est un sélecteur cherché dans\n * la liste validée — plus un refus propre quand le lancement n'est pas\n * reproductible : instance trop ancienne pour avoir publié sa ligne de\n * commande, ou lancée avec un secret que le registre ne conserve pas.\n */\n restartInstance: protectedProcedure\n .input(z.object({ pid: z.number().int().positive() }))\n .mutation(async ({ input }) => {\n try {\n if (input.pid === process.pid) {\n const { relauncherPid, port } = await scheduleSelfRestart();\n return { self: true as const, relauncherPid, port };\n }\n return { self: false as const, ...await restartInstance(input.pid) };\n } catch (err) {\n const reason = (err as Error).message;\n if (reason === 'instance-not-found') {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'No live Runeya instance with this pid.' });\n }\n if (reason.startsWith('instance-not-restartable:')) {\n throw new TRPCError({\n code: 'BAD_REQUEST',\n message: `This instance cannot be restarted (${reason.split(':')[1]}).`,\n });\n }\n throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: reason });\n }\n }),\n});\n","import { EventEmitter } from 'node:events';\n\n/**\n * In-memory ring buffer of everything this Runeya instance writes.\n *\n * The agent does not log to a file or a socket of its own: `agent-spawner`\n * reads its stdout line by line and re-emits it through the server's console\n * with an `[agent]` prefix. So capturing the server process's own output\n * captures both, and there is exactly one place to tap.\n *\n * The capture is a tee, never a filter: whatever was going to the terminal\n * still goes there. A developer running `runeya` in a shell must see exactly\n * what they saw before this existed.\n */\n\nexport type LogSource = 'server' | 'agent';\nexport type LogLevel = 'info' | 'warn' | 'error';\n\nexport type LogEntry = {\n /** Monotonic within a process; used by clients to de-duplicate on reconnect. */\n seq: number;\n at: number;\n source: LogSource;\n level: LogLevel;\n text: string;\n};\n\n/**\n * Roughly a full boot plus a long tail of activity. Bounded because this is a\n * diagnostic convenience, not a log store — anyone who needs history should be\n * redirecting the process output to a file.\n */\nconst MAX_ENTRIES = 2_000;\nconst MAX_TEXT_LENGTH = 4_000;\n\nconst entries: LogEntry[] = [];\nconst emitter = new EventEmitter();\n// Every open subscription attaches a listener; the default cap of 10 would warn\n// as soon as a few tabs watch the stream.\nemitter.setMaxListeners(0);\n\nlet seq = 0;\nlet installed = false;\n\n/** Lines the agent-spawner re-emits carry this prefix. */\nconst AGENT_PREFIX = '[agent] ';\n\n/**\n * Classify a line without pretending to parse it.\n *\n * stderr is not evidence of an error — plenty of tools write progress there —\n * so the stream only sets the floor, and the content can raise it.\n */\nexport function classify(line: string, stream: 'stdout' | 'stderr'): { source: LogSource; level: LogLevel; text: string } {\n const isAgent = line.startsWith(AGENT_PREFIX);\n const text = isAgent ? line.slice(AGENT_PREFIX.length) : line;\n\n let level: LogLevel = stream === 'stderr' ? 'warn' : 'info';\n // Word boundaries matter on the ASCII words: \"terrorism\" contains \"error\",\n // and a service with that in its name should not glow red. `\\b` is\n // ASCII-based though, so it never matches before an accented letter —\n // the French words are therefore matched without it.\n if (/\\b(error|fatal|failed|exception)\\b/i.test(text)\n || /(échec|erreur)/i.test(text)\n || text.includes('❌')) {\n level = 'error';\n } else if (/\\bwarn(ing)?\\b/i.test(text) || text.includes('⚠')) {\n level = 'warn';\n }\n\n return { source: isAgent ? 'agent' : 'server', level, text };\n}\n\nfunction push(line: string, stream: 'stdout' | 'stderr'): void {\n const { source, level, text } = classify(line, stream);\n const entry: LogEntry = {\n seq: ++seq,\n at: Date.now(),\n source,\n level,\n text: text.length > MAX_TEXT_LENGTH ? `${text.slice(0, MAX_TEXT_LENGTH)}…` : text,\n };\n\n entries.push(entry);\n if (entries.length > MAX_ENTRIES) entries.splice(0, entries.length - MAX_ENTRIES);\n emitter.emit('entry', entry);\n}\n\n/**\n * Start capturing. Idempotent: calling it twice would otherwise wrap the\n * already-wrapped `write` and record every line as many times as it was\n * installed.\n */\nexport function installLogCapture(): void {\n if (installed) return;\n installed = true;\n\n for (const [stream, name] of [\n [process.stdout, 'stdout'],\n [process.stderr, 'stderr'],\n ] as const) {\n const original = stream.write.bind(stream);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stream.write = ((chunk: any, encoding?: any, callback?: any) => {\n try {\n const text = typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf8');\n // Split on \\n and drop a trailing \\r: Windows tools emit CRLF, and the\n // stray carriage return would otherwise ride along into the UI.\n for (const raw of text.split('\\n')) {\n const line = raw.endsWith('\\r') ? raw.slice(0, -1) : raw;\n if (line.trim() !== '') push(line, name);\n }\n } catch {\n // Capturing must never be the reason a write fails\n }\n return original(chunk, encoding, callback);\n }) as typeof stream.write;\n }\n}\n\n/** The last `limit` entries, oldest first. */\nexport function recentEntries(limit = 500): LogEntry[] {\n return entries.slice(-Math.max(1, Math.min(limit, MAX_ENTRIES)));\n}\n\n/** Entries recorded after `afterSeq`, for a client catching up after a reconnect. */\nexport function entriesSince(afterSeq: number): LogEntry[] {\n return entries.filter((e) => e.seq > afterSeq);\n}\n\nexport function onEntry(listener: (entry: LogEntry) => void): () => void {\n emitter.on('entry', listener);\n return () => emitter.off('entry', listener);\n}\n","import { z } from 'zod';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { kanbanQueue } from '../../services/kanban-queue.js';\nimport type { KanbanQueueState } from '../../services/kanban-queue.js';\n\nexport const kanbanQueueRouter = router({\n getState: protectedProcedure.query(() => kanbanQueue.getState()),\n\n add: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n cardId: z.string().max(128),\n runner: z.enum(['claude-code', 'codex']).optional(),\n model: z.string().max(128).optional(),\n scenarioId: z.string().max(128).optional(),\n // Le projet ouvert quand la carte a été mise en file : la conversation\n // qui en naîtra lui appartient, plutôt que de rester orpheline et de\n // s'afficher dans tous les projets.\n projectId: z.string().max(128).optional(),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .mutation(({ input }) => kanbanQueue.add(input)),\n\n addColumn: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n columnId: z.string().max(128),\n // Les cartes visibles côté écran : une colonne filtrée n'envoie qu'elles.\n cardIds: z.array(z.string().max(128)).max(5000).optional(),\n runner: z.enum(['claude-code', 'codex']).optional(),\n model: z.string().max(128).optional(),\n scenarioId: z.string().max(128).optional(),\n projectId: z.string().max(128).optional(),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .mutation(async ({ input }) => {\n const { boardId, columnId, ...options } = input;\n return kanbanQueue.addColumn(boardId, columnId, options);\n }),\n\n remove: protectedProcedure\n .input(z.object({ itemId: z.string().max(128) }))\n .mutation(({ input }) => ({ removed: kanbanQueue.remove(input.itemId) })),\n\n stopAll: protectedProcedure\n .mutation(() => { kanbanQueue.stopAll(); return { ok: true }; }),\n\n setMaxConcurrent: protectedProcedure\n .input(z.object({ max: z.number().int().min(1).max(20) }))\n .mutation(({ input }) => { kanbanQueue.setMaxConcurrent(input.max); return kanbanQueue.getState(); }),\n\n onChanged: protectedProcedure.subscription(async function* () {\n const queue: KanbanQueueState[] = [];\n let resolve: (() => void) | null = null;\n\n const handler = () => {\n if (queue.length >= 50) queue.shift();\n queue.push(kanbanQueue.getState());\n if (resolve) { resolve(); resolve = null; }\n };\n\n kanbanQueue.on('changed', handler);\n // Emit initial state\n queue.push(kanbanQueue.getState());\n\n try {\n while (true) {\n if (queue.length > 0) {\n yield queue.shift()!;\n } else {\n await new Promise<void>((r) => { resolve = r; });\n }\n }\n } finally {\n kanbanQueue.off('changed', handler);\n }\n }),\n});\n","import { randomUUID } from 'node:crypto';\nimport { EventEmitter } from 'node:events';\nimport { kanbanStore } from './kanban-store.js';\nimport { conversationStore } from './conversation-store.js';\nimport { scenarioRunStore } from './scenario-run-store.js';\nimport { scenarioStore } from './scenario-store.js';\nimport { runScenario, tapBus, abortScenario } from './scenario-runner.js';\nimport { activeSessionRegistry } from './active-session-registry.js';\nimport { startCliSession } from '../trpc/routers/chat.js';\nimport { signJwt } from './auth-token.js';\nimport { companionSettings } from './companion.js';\n\nexport interface KanbanQueueItem {\n id: string;\n boardId: string;\n cardId: string;\n runner?: 'claude-code' | 'codex';\n model?: string;\n scenarioId?: string;\n /** Le projet depuis lequel la carte a été mise en file — celui de la conversation. */\n projectId?: string;\n /** Son organisation : avec l'id, c'est le couple qui désigne le coffre. */\n orgId?: string | null;\n addedAt: string;\n}\n\ninterface KanbanRunningItem {\n id: string;\n boardId: string;\n cardId: string;\n conversationId: string;\n startedAt: string;\n}\n\nexport interface KanbanQueueState {\n items: KanbanQueueItem[];\n running: KanbanRunningItem[];\n maxConcurrent: number;\n}\n\nclass KanbanQueueService extends EventEmitter {\n private items: KanbanQueueItem[] = [];\n private running: KanbanRunningItem[] = [];\n private maxConcurrent = 1;\n private startingCount = 0; // items whose startItem() is in-flight but not yet in this.running\n\n constructor() {\n super();\n // Un listener 'changed' par abonnement WS (onglet ouvert) : la limite par défaut de 10 est trop basse.\n this.setMaxListeners(0);\n }\n\n getState(): KanbanQueueState {\n return {\n items: [...this.items],\n running: [...this.running],\n maxConcurrent: this.maxConcurrent,\n };\n }\n\n add(rawItem: Omit<KanbanQueueItem, 'id' | 'addedAt'>): KanbanQueueItem {\n // Sans scénario ni runner, startItem() n'avait rien à lancer : la carte\n // entrait en file et en ressortait aussitôt, sans un mot. C'est ce que\n // faisait l'icône d'une carte, et le choix « Auto » d'une colonne.\n const item = rawItem.scenarioId || rawItem.runner\n ? rawItem\n : { ...rawItem, runner: 'claude-code' as const };\n const alreadyQueued = this.items.find(i => i.boardId === item.boardId && i.cardId === item.cardId);\n if (alreadyQueued) return alreadyQueued;\n const alreadyRunning = this.running.find(r => r.boardId === item.boardId && r.cardId === item.cardId);\n if (alreadyRunning) {\n // Return a fake item representing the running entry\n return { id: alreadyRunning.id, addedAt: alreadyRunning.startedAt, ...item };\n }\n\n const queueItem: KanbanQueueItem = {\n id: randomUUID(),\n ...item,\n addedAt: new Date().toISOString(),\n };\n this.items.push(queueItem);\n this.emit('changed');\n this.tick();\n return queueItem;\n }\n\n async addColumn(\n boardId: string,\n columnId: string,\n options: {\n runner?: 'claude-code' | 'codex';\n model?: string;\n scenarioId?: string;\n /**\n * Les cartes que l'écran montrait au moment du geste. L'utilisateur met en\n * file ce qu'il voit : une colonne filtrée n'envoie que ses cartes filtrées.\n * Absent = toute la colonne (aucun filtre actif).\n */\n cardIds?: string[];\n },\n ): Promise<KanbanQueueItem[]> {\n const board = await kanbanStore.get(boardId);\n if (!board) return [];\n const col = board.columns.find(c => c.id === columnId);\n if (!col) return [];\n const { cardIds, ...itemOptions } = options;\n const wanted = cardIds ? new Set(cardIds) : null;\n const cards = wanted ? col.cards.filter(card => wanted.has(card.id)) : col.cards;\n return cards.map(card => this.add({ boardId, cardId: card.id, ...itemOptions }));\n }\n\n remove(itemId: string): boolean {\n const idx = this.items.findIndex(i => i.id === itemId);\n if (idx >= 0) {\n this.items.splice(idx, 1);\n this.emit('changed');\n return true;\n }\n const runIdx = this.running.findIndex(r => r.id === itemId);\n if (runIdx >= 0) {\n const run = this.running[runIdx];\n abortScenario(run.conversationId);\n activeSessionRegistry.kill(run.conversationId);\n this.running.splice(runIdx, 1);\n this.emit('changed');\n this.tick();\n return true;\n }\n return false;\n }\n\n stopAll(): void {\n this.items = [];\n for (const run of this.running) {\n abortScenario(run.conversationId);\n activeSessionRegistry.kill(run.conversationId);\n }\n this.running = [];\n this.emit('changed');\n }\n\n setMaxConcurrent(max: number): void {\n this.maxConcurrent = Math.max(1, max);\n this.emit('changed');\n this.tick();\n }\n\n private tick(): void {\n while (this.running.length + this.startingCount < this.maxConcurrent && this.items.length > 0) {\n const item = this.items.shift()!;\n this.startingCount++;\n this.startItem(item).catch(err => {\n console.error('[kanban-queue] startItem error:', err);\n }).finally(() => {\n this.startingCount--;\n });\n }\n }\n\n private async startItem(item: KanbanQueueItem): Promise<void> {\n const board = await kanbanStore.get(item.boardId);\n if (!board) { this.tick(); return; }\n\n let card = null;\n for (const col of board.columns) {\n card = col.cards.find(c => c.id === item.cardId) ?? null;\n if (card) break;\n }\n if (!card) { this.tick(); return; }\n\n // Même règle que `chat.create` : le compagnon d'office suit le réglage du\n // poste, y compris pour les cartes lancées depuis la file.\n const companionByDefault = (await companionSettings()).enabledByDefault;\n\n const conv = await conversationStore.create(\n `Queue: ${card.title}`,\n !!item.runner,\n item.scenarioId,\n item.scenarioId ? 'scenario' : undefined,\n item.runner,\n item.boardId,\n item.cardId,\n undefined,\n item.projectId,\n item.orgId,\n companionByDefault ? { companionEnabled: true } : undefined,\n );\n\n const cardContent = card.title + (card.markdown ? '\\n\\n' + card.markdown : '');\n\n if (item.scenarioId) {\n // La file porte déjà le couple projet + organisation : les scénarios lus\n // sont ceux de l'organisation à qui appartient la carte.\n const scenario = await scenarioStore.get(item.scenarioId, item.orgId ?? undefined);\n if (scenario) {\n await scenarioRunStore.initializeConversationWorkspace(conv.id, scenario, cardContent);\n }\n }\n\n const runItem: KanbanRunningItem = {\n id: item.id,\n boardId: item.boardId,\n cardId: item.cardId,\n conversationId: conv.id,\n startedAt: new Date().toISOString(),\n };\n this.running.push(runItem);\n this.emit('changed');\n\n // Une ligne de journal pour que le tableau montre qu'une IA travaille ici.\n // Route ciblée : elle ne fait pas repasser le graphe de cartes par le réseau.\n const eventType = item.scenarioId ? 'scenario_started' : 'conversation_started';\n kanbanStore.addCardEvent(board.id, item.cardId, eventType, conv.id).catch(() => {});\n\n if (item.scenarioId) {\n void runScenario(conv.id, item.scenarioId, cardContent, {\n runnerOverride: item.runner,\n modelOverride: item.model,\n });\n this.monitorCompletion(runItem).catch(() => {});\n } else if (item.runner) {\n this.runWithRunner(runItem, item, cardContent).catch(err => {\n console.error('[kanban-queue] runWithRunner error:', err);\n this.finishItem(item.id);\n });\n } else {\n this.finishItem(item.id);\n }\n }\n\n private async runWithRunner(\n runItem: KanbanRunningItem,\n item: KanbanQueueItem,\n cardContent: string,\n ): Promise<void> {\n try {\n // Aucun modèle imposé : chaque CLI utilise celui que l'utilisateur a configuré.\n const model = item.model || '';\n // La file tourne hors requête HTTP : aucun `ctx.authorization` d'où tirer le\n // JWT. Sans lui, le serveur MCP est lancé sans RUNEYA_API_TOKEN et toutes\n // ses tools répondent « No auth token available ». On en signe un ici.\n const jwt = await signJwt();\n const { done } = await startCliSession(item.runner, runItem.conversationId, cardContent, { model, jwt });\n await done;\n } finally {\n this.finishItem(runItem.id);\n }\n }\n\n private async monitorCompletion(runItem: KanbanRunningItem): Promise<void> {\n // Wait a bit for the scenario bus to be created\n await new Promise(r => setTimeout(r, 100));\n const abortCtrl = new AbortController();\n try {\n for await (const event of tapBus(runItem.conversationId, abortCtrl.signal)) {\n if (event.type === 'scenario_complete') break;\n }\n } catch {\n // Aborted or ended\n } finally {\n this.finishItem(runItem.id);\n }\n }\n\n private finishItem(itemId: string): void {\n const idx = this.running.findIndex(r => r.id === itemId);\n if (idx >= 0) this.running.splice(idx, 1);\n this.emit('changed');\n this.tick();\n }\n}\n\nexport const kanbanQueue = new KanbanQueueService();\n","import { mkdir, readdir, rm, stat, writeFile } from 'node:fs/promises';\nimport { createHash } from 'node:crypto';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { z } from 'zod';\nimport { machineRoot } from '../../services/vault-resolver.js';\nimport { TRPCError } from '@trpc/server';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { cloudFetch, accountForOrgScope, soleAccountScope } from './cloud-auth.js';\nimport { executeKanbanCommands, executeKanbanBoardCommands } from '../../services/kanban-commands.js';\nimport { kanbanStore } from '../../services/kanban-store.js';\nimport type { KanbanBoard, KanbanCard } from '@runeya/packages-shared';\n\n/**\n * A card as the read routes expose it.\n *\n * Deliberately not the stored card: the history and the attachments are the\n * bulk of a board, and an agent listing cards has no use for either. The body\n * is kept — it is what the card *says* — and the rest is reduced to counts.\n *\n * Le journal n'arrive même plus jusqu'ici : le cloud le laisse en base et\n * envoie le décompte. Le fil d'une carte se lit par `kanbanStore.cardHistory`,\n * pour la seule carte qui intéresse l'agent.\n */\nfunction summarizeCard(card: KanbanCard, boardId: string, columnTitle: string): Record<string, unknown> {\n return {\n boardId,\n column: columnTitle,\n id: card.id,\n title: card.title,\n markdown: card.markdown ?? '',\n assignees: (card.assignees ?? []).map((a) => a.name),\n commentCount: card.commentCount ?? (card.history ?? []).filter((e) => e.type === 'comment').length,\n attachmentCount: (card.attachments ?? []).length,\n // Metadata only — the bytes are fetched on demand by `downloadAttachment`.\n attachments: (card.attachments ?? []).map((f) => ({\n id: f.id,\n name: f.name,\n contentType: f.contentType,\n size: f.size,\n })),\n createdAt: card.createdAt,\n updatedAt: card.updatedAt,\n };\n}\n\n/**\n * The cloud's board *list* omits `columns` (a board carries its whole card\n * graph, so listing them in full would be megabytes) and sends counts instead.\n * The shared type describes the full board, hence this narrow read.\n */\nfunction boardCounts(board: KanbanBoard): { columnCount: number; cardCount: number; columns: string[] } {\n const summary = board as unknown as { columnCount?: number; cardCount?: number };\n const columns = board.columns ?? [];\n return {\n columnCount: summary.columnCount ?? columns.length,\n cardCount: summary.cardCount ?? columns.reduce((sum, c) => sum + c.cards.length, 0),\n columns: columns.map((c) => c.title),\n };\n}\n\n/**\n * Attachment ids are server-issued base64url (see the cloud's `putAttachment`).\n * Validated before it reaches a URL or a file path: the id is both.\n */\nconst ATTACHMENT_ID_REGEX = /^[A-Za-z0-9_-]{1,128}$/;\n\n/** A malformed `filename*` must lose the name, not blow up the download. */\nfunction safeDecode(value: string): string {\n try {\n return decodeURIComponent(value);\n } catch {\n return '';\n }\n}\n\n/** Mirrors the cloud's own upload ceiling — nothing larger can exist. */\nconst MAX_ATTACHMENT_BYTES = 55 * 1024 * 1024;\n\n/**\n * Où atterrissent les pièces jointes téléchargées, un fichier par id.\n *\n * Le dossier temporaire de la machine, et non le `DATA_DIR` du projet : ces\n * fichiers sont un cache, pas des données. L'original vit dans le cloud, tout\n * est re-téléchargeable, et rien ici ne mérite d'être sauvegardé, synchronisé\n * ni versionné. Le système fait déjà le ménage de ce dossier ; la purge\n * ci-dessous s'occupe du reste, pour ne pas dépendre de sa politique.\n */\nexport function attachmentCacheDir(): string {\n return join(tmpdir(), 'runeya-kanban-attachments');\n}\n\n/** Au-delà, un fichier du cache ne sert plus personne. */\nconst ATTACHMENT_CACHE_TTL_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Oublier les fichiers que plus aucune conversation ne lit.\n *\n * Sans cela le cache ne fait que grossir — une pièce jointe pèse jusqu'à 55 Mo\n * et chaque agent qui en ouvre une en dépose une copie. Au mieux et silencieux :\n * un fichier qu'on n'arrive pas à supprimer n'a aucune raison de faire échouer\n * le téléchargement qui vient d'aboutir.\n */\nexport async function purgeStaleAttachments(\n dir: string,\n ttlMs: number = ATTACHMENT_CACHE_TTL_MS,\n): Promise<void> {\n try {\n const cutoff = Date.now() - ttlMs;\n for (const name of await readdir(dir)) {\n const path = join(dir, name);\n const info = await stat(path).catch(() => null);\n if (info && info.mtimeMs < cutoff) await rm(path, { force: true });\n }\n } catch {\n /* le cache est jetable : un ménage raté n'est pas une erreur */\n }\n}\n\n/**\n * Les emplacements du cache, du plus souhaitable au plus sûr.\n *\n * Le dossier temporaire d'abord : ces fichiers sont jetables et n'ont rien à\n * faire dans le projet. Le `DATA_DIR` ensuite, comme filet — un `/tmp` monté\n * en lecture seule, plein, ou hors de portée d'un agent au bac à sable ne doit\n * pas priver l'IA d'une pièce jointe qu'elle a le droit de lire.\n */\nfunction attachmentCacheDirs(): string[] {\n return [attachmentCacheDir(), join(machineRoot(), 'kanban-attachments')];\n}\n\n/**\n * Poser les octets sur le disque, et dire clairement si c'est impossible.\n *\n * Sans cela, un `/tmp` non inscriptible remontait à l'agent en 500 brut —\n * après un téléchargement déjà payé — sans qu'il puisse distinguer une panne\n * du cloud d'un problème de sa propre machine, ni savoir quoi faire. Ici, le\n * repli est tenté, puis l'échec est nommé, avec tous les chemins essayés.\n */\nexport async function storeAttachment(\n id: string,\n name: string,\n body: Buffer,\n dirs: string[] = attachmentCacheDirs(),\n): Promise<string> {\n const refusals: string[] = [];\n for (const dir of dirs) {\n try {\n // `recursive` couvre le cas du dossier absent : il est créé, parents compris.\n await mkdir(dir, { recursive: true });\n const path = join(dir, safeLocalName(id, name));\n await writeFile(path, body);\n // Après l'écriture, jamais avant : le ménage ne doit pas retarder ce\n // pour quoi l'agent attend, ni s'exécuter dans un dossier condamné.\n void purgeStaleAttachments(dir);\n return path;\n } catch (err) {\n refusals.push(`${dir} (${err instanceof Error ? err.message : String(err)})`);\n }\n }\n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message:\n `Impossible d'écrire la pièce jointe sur cette machine. Emplacements essayés : ${refusals.join(' ; ')}.`\n + ' Vérifiez les droits d\\'écriture, ou l\\'espace disque.',\n });\n}\n\n/**\n * Keep the extension the uploader gave the file (agents pick their reader from\n * it) but never let the name escape the cache directory.\n *\n * Le nom vient d'une empreinte de l'id, jamais de l'id lui-même : les\n * identifiants sont du base64url, donc sensibles à la casse, alors que les\n * systèmes de fichiers de Windows et de macOS ne le sont pas par défaut. Deux\n * pièces jointes ne différant que par la casse s'y écraseraient l'une l'autre,\n * et un agent lirait les octets d'un autre fichier que celui demandé.\n */\nexport function safeLocalName(id: string, name: string): string {\n const base = createHash('sha256').update(id).digest('hex').slice(0, 32);\n const ext = /\\.([A-Za-z0-9]{1,12})$/.exec(name)?.[1];\n return ext ? `${base}.${ext.toLowerCase()}` : base;\n}\n\nexport const kanbanRouter = router({\n /**\n * The organization's boards, without their cards — a board carries its whole\n * card graph, so listing them in full would be megabytes to answer \"which\n * boards exist?\". Use `getBoard` for the cards of one.\n */\n listBoards: protectedProcedure\n .input(z.object({\n includeArchived: z.boolean().optional(),\n organizationId: z.string().max(128).optional(),\n }).optional())\n .query(async ({ input }) => {\n const { organizationId, boards } = await kanbanStore.list(\n input?.includeArchived ?? false,\n input?.organizationId,\n );\n return {\n // Répondue explicitement : une liste vide doit dire à QUI la question\n // a été posée, sinon on ne peut pas distinguer « rien ici » de\n // « mauvaise organisation ».\n organizationId,\n boards: boards.map((b) => {\n const counts = boardCounts(b);\n return {\n id: b.id,\n name: b.name,\n description: b.description,\n archived: b.archived,\n columnCount: counts.columnCount,\n cardCount: counts.cardCount,\n updatedAt: b.updatedAt,\n };\n }),\n };\n }),\n\n /** One board: its columns, and the cards in each. */\n getBoard: protectedProcedure\n .input(z.object({ boardId: z.string().max(128) }))\n .query(async ({ input }) => {\n const board = await kanbanStore.get(input.boardId);\n if (!board) return { board: null };\n // La filiation vit hors du tableau, donc elle se demande à part — et elle\n // vaut d'être jointe ici : un agent qui lit un tableau doit voir qu'une\n // carte en attend une autre, sans avoir à le deviner du texte.\n const { links } = await kanbanStore.cardLinks(input.boardId);\n const parentOf = new Map(links.map((l) => [l.childCardId, l.parentCardId]));\n const childrenOf = new Map<string, string[]>();\n for (const link of links) {\n childrenOf.set(link.parentCardId, [...(childrenOf.get(link.parentCardId) ?? []), link.childCardId]);\n }\n const withLinks = (card: Record<string, unknown>): Record<string, unknown> => {\n const id = String(card['id']);\n const parent = parentOf.get(id);\n const children = childrenOf.get(id) ?? [];\n return {\n ...card,\n ...(parent ? { parentCardId: parent } : {}),\n ...(children.length ? { childCardIds: children } : {}),\n };\n };\n return {\n board: {\n id: board.id,\n name: board.name,\n description: board.description,\n instructions: board.instructions ?? '',\n archived: board.archived,\n columns: [...board.columns]\n .sort((a, b) => a.order - b.order)\n .map((col) => ({\n id: col.id,\n title: col.title,\n cards: [...col.cards]\n .sort((a, b) => a.order - b.order)\n .map((card) => withLinks(summarizeCard(card, board.id, col.title))),\n })),\n },\n };\n }),\n\n /**\n * Free-text search over card titles and bodies, across every board of the\n * organization — or one board when `boardId` is given. Archived boards are\n * left out: they are what the team decided to stop looking at.\n */\n searchCards: protectedProcedure\n .input(z.object({\n query: z.string().min(1).max(256),\n boardId: z.string().max(128).optional(),\n limit: z.number().int().min(1).max(100).optional(),\n organizationId: z.string().max(128).optional(),\n }))\n .query(async ({ input }) => {\n // La recherche se fait dans le cloud, avec le prédicat de ses propres\n // écrans : titre, corps et commentaires, sans casse ni accents. Filtrer\n // ici obligeait à rapatrier tous les tableaux entiers, et laissait de\n // côté ce que le tableau ne porte plus — les commentaires et l'archive.\n return kanbanStore.searchCards(input);\n }),\n\n /**\n * Le fil de commentaires d'une carte, relu à la demande.\n *\n * Le contexte d'un agent embarque les commentaires tels qu'ils étaient au\n * lancement de la tâche — un instantané. Le support qui répond dix minutes\n * plus tard écrit dans un fil que l'agent ne voit plus : `getBoard` ne rend\n * qu'un `commentCount`, et rien n'en donnait le texte. Cette route est la\n * relecture, pour une seule carte : c'est le journal qui pèse, pas le reste.\n */\n getCardComments: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n cardId: z.string().max(128),\n limit: z.number().int().min(1).max(200).optional(),\n }))\n .query(async ({ input }) => {\n const history = await kanbanStore.cardHistory(input.boardId, input.cardId);\n const comments = history.filter((e) => e.type === 'comment');\n // Les derniers, pas les premiers : un fil se lit par la fin.\n const slice = comments.slice(-(input.limit ?? 50));\n return {\n total: comments.length,\n comments: slice.map((c) => ({\n id: c.id,\n timestamp: c.timestamp,\n author: c.author ?? 'user',\n authorName: c.authorUser?.name,\n editedAt: c.editedAt,\n text: c.detail ?? '',\n attachments: (c.attachments ?? []).map((f) => ({\n id: f.id,\n name: f.name,\n contentType: f.contentType,\n size: f.size,\n })),\n })),\n };\n }),\n\n /**\n * La filiation des cartes d'un tableau : qui dépend de qui.\n *\n * `getBoard` en donne déjà l'essentiel carte par carte ; cette route sert\n * quand c'est l'arbre lui-même qu'on veut, dates et auteurs compris.\n */\n getCardLinks: protectedProcedure\n .input(z.object({ boardId: z.string().max(128) }))\n .query(async ({ input }) => kanbanStore.cardLinks(input.boardId)),\n\n /**\n * Rattacher une carte à une carte parente, ou l'en détacher.\n *\n * Sans `parentCardId`, le lien est retiré. Le parent peut vivre sur un autre\n * tableau : `parentBoardId` le désigne alors, sinon c'est celui de la carte.\n */\n setCardParent: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n cardId: z.string().max(128),\n parentCardId: z.string().max(128).optional(),\n parentBoardId: z.string().max(128).optional(),\n }))\n .mutation(async ({ input }) => {\n const ok = await kanbanStore.setCardParent(\n input.boardId,\n input.cardId,\n input.parentCardId\n ? { boardId: input.parentBoardId ?? input.boardId, cardId: input.parentCardId }\n : null,\n );\n if (!ok) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'The cloud refused the link (unknown card, or a cycle).' });\n }\n return { ok: true };\n }),\n\n moveCard: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n cardId: z.string().max(128),\n targetColumn: z.string().max(256),\n }))\n .mutation(async ({ input }) => {\n await executeKanbanCommands(input.boardId, input.cardId, [\n { type: 'move_card', columnTitle: input.targetColumn },\n ]);\n return { ok: true };\n }),\n\n addComment: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n cardId: z.string().max(128),\n comment: z.string().max(100_000),\n }))\n .mutation(async ({ input }) => {\n await executeKanbanCommands(input.boardId, input.cardId, [\n { type: 'add_comment', comment: input.comment },\n ]);\n return { ok: true };\n }),\n\n addCard: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n column: z.string().max(256),\n title: z.string().max(512),\n content: z.string().max(20000).optional(),\n }))\n .mutation(async ({ input }) => {\n await executeKanbanBoardCommands(input.boardId, [\n { type: 'add_card', columnTitle: input.column, cardTitle: input.title, cardContent: input.content },\n ]);\n return { ok: true };\n }),\n\n /**\n * Lire une carte, seule.\n *\n * `getBoard` rapatrie le tableau entier pour n'en regarder qu'une ; et il ne\n * porte pas les cartes rangées. Une carte s'adresse par son identifiant.\n */\n getCard: protectedProcedure\n .input(z.object({ boardId: z.string().max(128), cardId: z.string().max(128) }))\n .query(async ({ input }) => {\n const found = await kanbanStore.card(input.boardId, input.cardId);\n if (!found) throw new Error(`Carte ${input.cardId} introuvable sur le tableau ${input.boardId}.`);\n return { ...summarizeCard(found.card, input.boardId, ''), columnId: found.columnId };\n }),\n\n /**\n * Modifier une carte.\n *\n * Le manque le plus coûteux du kanban vu par un agent : sans lui, il ne\n * pouvait qu'ajouter. Face à une carte à corriger, il en créait une seconde.\n *\n * Un champ absent n'est pas touché ; `null` l'efface. La distinction compte —\n * changer un titre ne doit pas vider une couleur.\n */\n updateCard: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n cardId: z.string().max(128),\n title: z.string().min(1).max(512).optional(),\n content: z.string().max(100000).optional(),\n priority: z.number().int().min(1).max(10).nullable().optional(),\n color: z.string().max(32).nullable().optional(),\n groups: z.array(z.string().min(1).max(60)).max(30).optional(),\n deadline: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).nullable().optional(),\n assignees: z.array(z.string().max(128)).max(50).optional(),\n }))\n .mutation(async ({ input }) => {\n const { boardId, cardId, content, ...rest } = input;\n const patch: Record<string, unknown> = { ...rest };\n // Le cloud nomme `markdown` ce que l'outil appelle `content`, comme\n // `kanban_add_card` : un agent n'a pas à connaître deux noms.\n if (content !== undefined) patch.markdown = content;\n if (!Object.keys(patch).length) throw new Error('Rien à modifier : précisez au moins un champ.');\n const card = await kanbanStore.updateCard(boardId, cardId, patch);\n if (!card) throw new Error(`La carte ${cardId} n'a pas pu être modifiée.`);\n return summarizeCard(card, boardId, '');\n }),\n\n /** Ranger une carte, ou la reprendre. */\n setCardArchived: protectedProcedure\n .input(z.object({\n boardId: z.string().max(128),\n cardId: z.string().max(128),\n archived: z.boolean(),\n }))\n .mutation(async ({ input }) => {\n const ok = await kanbanStore.setCardArchived(input.boardId, input.cardId, input.archived);\n if (!ok) throw new Error(`La carte ${input.cardId} n'a pas pu être ${input.archived ? 'archivée' : 'reprise'}.`);\n return { ok: true };\n }),\n\n /**\n * Qui peut se voir assigner une carte.\n *\n * Sans cette liste, assigner revient à deviner un identifiant — et l'agent\n * n'a aucun moyen de le trouver.\n */\n listMembers: protectedProcedure\n .input(z.object({ organizationId: z.string().max(128).optional() }))\n .query(async ({ input }) => ({ members: await kanbanStore.members(input.organizationId) })),\n\n /**\n * Fetch one card attachment from the cloud and drop it on this machine, so an\n * agent can open it with its own file tools. The bytes never go through the\n * prompt: the card context lists the attachments, this returns a path.\n */\n downloadAttachment: protectedProcedure\n .input(z.object({\n attachmentId: z.string().max(128),\n // La pièce jointe appartient à une organisation : la nommer dit sous quel\n // compte la demander. C'est le SEUL appel qui tolère de ne pas l'avoir —\n // un agent n'a qu'un identifiant de fichier — et il échoue alors en le\n // disant dès que ce poste a plusieurs comptes.\n orgId: z.string().max(128).optional(),\n }))\n .mutation(async ({ input }) => {\n const id = input.attachmentId;\n if (!ATTACHMENT_ID_REGEX.test(id)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Invalid attachment id' });\n }\n\n // The cloud authorizes this: it checks the machine's session against the\n // organization owning the file before serving a single byte.\n const res = await cloudFetch(`/api/kanban/file/${id}`, {\n timeoutMs: 120_000,\n accountId: input.orgId\n ? await accountForOrgScope(input.orgId)\n : await soleAccountScope(),\n });\n if (res.status === 404) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Attachment ${id} not found` });\n }\n if (!res.ok) {\n throw new TRPCError({\n code: res.status === 403 ? 'FORBIDDEN' : 'INTERNAL_SERVER_ERROR',\n message: `Cloud refused the attachment (HTTP ${res.status})`,\n });\n }\n\n // Trust the header only to fail early; the real check is on the bytes.\n const declared = Number(res.headers.get('content-length') ?? 0);\n if (declared > MAX_ATTACHMENT_BYTES) {\n throw new TRPCError({ code: 'PAYLOAD_TOO_LARGE', message: 'Attachment too large to download' });\n }\n const body = Buffer.from(await res.arrayBuffer());\n if (body.length > MAX_ATTACHMENT_BYTES) {\n throw new TRPCError({ code: 'PAYLOAD_TOO_LARGE', message: 'Attachment too large to download' });\n }\n\n const contentType = res.headers.get('content-type') ?? 'application/octet-stream';\n const disposition = res.headers.get('content-disposition') ?? '';\n // `filename*` first: it carries the real, non-ASCII name (RFC 6266). The\n // quoted `filename` is only the transliterated fallback for old clients,\n // so reading it first would write \"Analyse d_un projet.docx\" to disk.\n const encoded = /filename\\*=UTF-8''([^;]+)/i.exec(disposition)?.[1];\n const name = (encoded ? safeDecode(encoded) : '')\n || /filename=\"([^\"]*)\"/.exec(disposition)?.[1]\n || id;\n\n const path = await storeAttachment(id, name, body);\n return { path, name, contentType, size: body.length };\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { agentManager } from '../../services/agent-manager.js';\nimport { resolveAgentCwd } from '../../services/workspace-cwd.js';\n\nexport interface TerminalSessionInfo {\n sessionId: string;\n title: string;\n cwd: string;\n cols: number;\n rows: number;\n createdAt: number;\n}\n\nexport const terminalRouter = router({\n /** Create a PTY shell session on the target agent */\n create: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n cwd: z.string().max(512).optional(),\n /** Anchors the terminal when no explicit cwd is given. */\n serviceId: z.string().max(128).optional(),\n projectId: z.string().max(128).optional(),\n /** L'organisation du projet : un id seul peut en nommer un par organisation. */\n orgId: z.string().max(128).nullable().optional(),\n cols: z.number().int().min(1).max(512).optional(),\n rows: z.number().int().min(1).max(256).optional(),\n title: z.string().max(128).optional(),\n }))\n .mutation(async ({ input }) => {\n const result = await agentManager.agentMutation<{ sessionId: string }>(\n input.agentId,\n 'terminal.create',\n {\n // An explicit cwd wins; otherwise the service's directory, then the\n // project's — never the directory the server was launched in.\n cwd: input.cwd ?? await resolveAgentCwd({\n serviceId: input.serviceId, projectId: input.projectId, orgId: input.orgId,\n }),\n cols: input.cols,\n rows: input.rows,\n title: input.title,\n },\n );\n return result;\n }),\n\n /** Les sessions PTY encore vivantes sur l'agent (onglets à retrouver) */\n list: protectedProcedure\n .input(z.object({ agentId: z.string().max(128) }))\n .query(async ({ input }) => {\n return agentManager.agentQuery<{ sessions: TerminalSessionInfo[] }>(\n input.agentId,\n 'terminal.list',\n );\n }),\n\n /** Renommer un onglet */\n rename: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n sessionId: z.string().max(128),\n title: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n await agentManager.agentMutation(\n input.agentId,\n 'terminal.rename',\n { sessionId: input.sessionId, title: input.title },\n );\n return { ok: true as const };\n }),\n\n /** Send keystrokes / data to a PTY session */\n write: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n sessionId: z.string().max(128),\n data: z.string().max(65536),\n }))\n .mutation(async ({ input }) => {\n await agentManager.agentMutation(\n input.agentId,\n 'terminal.write',\n { sessionId: input.sessionId, data: input.data },\n );\n return { ok: true as const };\n }),\n\n /** Resize the PTY */\n resize: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n sessionId: z.string().max(128),\n cols: z.number().int().min(1).max(512),\n rows: z.number().int().min(1).max(256),\n }))\n .mutation(async ({ input }) => {\n await agentManager.agentMutation(\n input.agentId,\n 'terminal.resize',\n { sessionId: input.sessionId, cols: input.cols, rows: input.rows },\n );\n return { ok: true as const };\n }),\n\n /** Destroy a PTY session */\n destroy: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n sessionId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n await agentManager.agentMutation(\n input.agentId,\n 'terminal.destroy',\n { sessionId: input.sessionId },\n );\n return { ok: true as const };\n }),\n\n /** Stream PTY output — proxied via AgentWSBridge dynamic subscription */\n onData: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128),\n sessionId: z.string().max(128),\n /** Rejouer l'historique de la session avant le flux temps réel. */\n replay: z.boolean().optional(),\n }))\n .subscription(async function* ({ input }) {\n const queue: string[] = [];\n let resolve: (() => void) | null = null;\n let done = false;\n\n let unsubscribe: (() => void) | undefined;\n try {\n unsubscribe = agentManager.agentSubscribe(\n input.agentId,\n 'terminal.onData',\n { sessionId: input.sessionId, replay: input.replay },\n (data) => {\n if (typeof data === 'string') queue.push(data);\n if (resolve) { resolve(); resolve = null; }\n },\n () => {\n done = true;\n if (resolve) { resolve(); resolve = null; }\n },\n );\n } catch (err) {\n throw new TRPCError({\n code: 'BAD_REQUEST',\n message: `Cannot subscribe to terminal: ${(err as Error).message}`,\n });\n }\n\n try {\n while (!done || queue.length > 0) {\n if (queue.length > 0) {\n yield queue.shift()!;\n } else {\n await new Promise<void>((r) => { resolve = r; });\n }\n }\n } finally {\n unsubscribe?.();\n }\n }),\n});\n","import { z } from 'zod';\nimport { router, protectedProcedure } from '../trpc.js';\n\nconst MAX_WAIT_MS = 5 * 60 * 1000; // 5 minutes max\n\nexport const utilityRouter = router({\n wait: protectedProcedure\n .input(z.object({\n ms: z.number().int().min(0).max(MAX_WAIT_MS),\n }))\n .mutation(async ({ input }) => {\n await new Promise(resolve => setTimeout(resolve, input.ms));\n return { waited: input.ms };\n }),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { readFile, readdir, stat, realpath, writeFile, mkdir, rename, rm } from 'node:fs/promises';\nimport type { Dirent } from 'node:fs';\nimport { resolve as resolvePath, join, relative, sep, dirname } from 'node:path';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { env } from '../../config/env.js';\nimport { serviceStore } from '../../services/service-store.js';\nimport { resolveWorkspaceCwd } from '../../services/workspace-cwd.js';\nimport { settingsManager } from '../../services/settings-manager.js';\nimport { agentManager } from '../../services/agent-manager.js';\nimport { resolveEffectiveAgentId } from './service.js';\n\nconst SCOPE_SCHEMA = z.union([\n z.literal('global'),\n z.string().regex(/^service:[A-Za-z0-9_-]{1,128}$/, 'Invalid service scope'),\n]);\nconst REL_PATH_SCHEMA = z\n .string()\n .min(1)\n .max(512)\n .regex(/^[A-Za-z0-9_./-]+$/)\n .refine((p) => !p.includes('..') && !p.startsWith('/'), {\n message: 'Path must be a relative path without traversal',\n });\n\nconst MAX_FILES = 500;\nconst MAX_DEPTH = 8;\nconst MAX_FILE_BYTES = 2_000_000;\nconst IGNORED_DIRS = new Set([\n 'node_modules', '.git', 'dist', 'build', '.next', '.turbo',\n '.cache', 'coverage', '.yarn', '.pnpm-store', 'target', 'out',\n]);\n\ntype DocsFileEntry = { type: 'file'; name: string; path: string };\ntype DocsDirEntry = { type: 'dir'; name: string; path: string; children: DocsEntry[] };\nexport type DocsEntry = DocsFileEntry | DocsDirEntry;\n\nconst DocsEntrySchema: z.ZodType<DocsEntry> = z.lazy(() => z.union([\n z.object({ type: z.literal('file'), name: z.string(), path: z.string() }),\n z.object({ type: z.literal('dir'), name: z.string(), path: z.string(), children: z.array(DocsEntrySchema) }),\n]));\n\n/**\n * For service scope: resolve via agent (agent expands $VAR and ~).\n * Returns { mode: 'agent', agentId, cwd } to call agent endpoints.\n *\n * For global scope: resolve locally on the server using the absolute globalDocsPath.\n * Returns { mode: 'local', root }.\n */\nasync function resolveScope(scope: string): Promise<\n | { mode: 'agent'; agentId: string; cwd: string }\n | { mode: 'local'; root: string }\n> {\n if (scope === 'global') {\n const settings = await settingsManager.getSettings();\n const sub = (settings.globalDocsPath?.trim() || 'wiki').replace(/^[\\\\/]+|[\\\\/]+$/g, '');\n if (sub.includes('..') || sub.includes('\\0')) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Sous-chemin invalide' });\n }\n // Base = parent of DATA_DIR (docs live alongside the data dir, not inside it)\n const dataDirAbs = resolvePath(env.DATA_DIR);\n await mkdir(dataDirAbs, { recursive: true });\n const base = dirname(await realpath(dataDirAbs));\n const target = resolvePath(base, sub);\n // Pre-check (defense-in-depth): the resolved target path must already live under base.\n if (target !== base && !(target + sep).startsWith(base + sep)) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Hors du dossier de données du serveur' });\n }\n await mkdir(target, { recursive: true });\n const root = await realpath(target);\n // Post-realpath check: a pre-existing symlink at `target` could resolve outside base.\n if (root !== base && !(root + sep).startsWith(base + sep)) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Le dossier wiki résout hors du dossier de données' });\n }\n return { mode: 'local', root };\n }\n // service:<id>\n const serviceId = scope.slice('service:'.length);\n const service = await serviceStore.get(serviceId);\n if (!service) throw new TRPCError({ code: 'NOT_FOUND', message: 'Service introuvable' });\n const agentId = await resolveEffectiveAgentId(service);\n if (!agentId) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Aucun agent configuré pour ce service' });\n // docsPath when defined, else the service's cwd — both anchored on the\n // project's directory rather than on wherever the server was launched.\n const cwd = await resolveWorkspaceCwd({ serviceId, override: service.docsPath?.trim() || undefined });\n return { mode: 'agent', agentId, cwd };\n}\n\n// ─── Local FS helpers (for global scope) ──────────────────────────────\n\nasync function walkLocal(root: string, dir: string, depth: number, counter: { n: number }): Promise<DocsEntry[]> {\n if (depth > MAX_DEPTH || counter.n >= MAX_FILES) return [];\n let entries: Dirent[];\n try { entries = await readdir(dir, { withFileTypes: true }); } catch { return []; }\n const out: DocsEntry[] = [];\n for (const e of entries) {\n if (counter.n >= MAX_FILES) break;\n if (e.name.startsWith('.') && e.name !== '.') continue;\n const abs = join(dir, e.name);\n const rel = relative(root, abs).split(sep).join('/');\n if (e.isDirectory()) {\n if (IGNORED_DIRS.has(e.name)) continue;\n const children = await walkLocal(root, abs, depth + 1, counter);\n out.push({ type: 'dir', name: e.name, path: rel, children });\n } else if (e.isFile() && /\\.(md|markdown)$/i.test(e.name)) {\n counter.n += 1;\n out.push({ type: 'file', name: e.name, path: rel });\n }\n }\n out.sort((a, b) => {\n if (a.type !== b.type) return a.type === 'dir' ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n return out;\n}\n\nasync function resolveSafeLocal(root: string, relPath: string, requireExist: boolean): Promise<string> {\n if (relPath.includes('..') || relPath.startsWith('/')) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Chemin invalide' });\n }\n const target = resolvePath(root, relPath);\n if (requireExist) {\n let real: string;\n try { real = await realpath(target); } catch {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'Chemin introuvable' });\n }\n if (real !== root && !(real + sep).startsWith(root + sep)) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Hors du dossier autorisé' });\n }\n return real;\n }\n const parent = dirname(target);\n let realParent: string;\n try { realParent = await realpath(parent); } catch { realParent = parent; }\n if (realParent !== root && !(realParent + sep).startsWith(root + sep)) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'Hors du dossier autorisé' });\n }\n return resolvePath(realParent, target.slice(parent.length).replace(/^[\\\\/]+/, ''));\n}\n\n// ─── Router ───────────────────────────────────────────────────────────\n\nexport const wikiRouter = router({\n list: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA }))\n .output(z.object({ root: z.string(), entries: z.array(DocsEntrySchema), truncated: z.boolean() }))\n .query(async ({ input }) => {\n const target = await resolveScope(input.scope);\n if (target.mode === 'agent') {\n return agentManager.agentQuery(target.agentId, 'wiki.listRepoMarkdown', { cwd: target.cwd }) as Promise<{ root: string; entries: DocsEntry[]; truncated: boolean }>;\n }\n const counter = { n: 0 };\n const entries = await walkLocal(target.root, target.root, 0, counter);\n return { root: target.root, entries, truncated: counter.n >= MAX_FILES };\n }),\n\n read: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA, path: REL_PATH_SCHEMA }))\n .output(z.object({ path: z.string(), content: z.string() }))\n .query(async ({ input }) => {\n if (!/\\.(md|markdown)$/i.test(input.path)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Seuls les .md/.markdown sont autorisés' });\n }\n const target = await resolveScope(input.scope);\n if (target.mode === 'agent') {\n return agentManager.agentQuery(target.agentId, 'wiki.readRepoMarkdown', { cwd: target.cwd, path: input.path }) as Promise<{ path: string; content: string }>;\n }\n const file = await resolveSafeLocal(target.root, input.path, true);\n const s = await stat(file);\n if (!s.isFile()) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Pas un fichier' });\n if (s.size > MAX_FILE_BYTES) throw new TRPCError({ code: 'PAYLOAD_TOO_LARGE', message: 'Fichier trop volumineux' });\n const content = await readFile(file, 'utf-8');\n return { path: input.path, content };\n }),\n\n write: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA, path: REL_PATH_SCHEMA, content: z.string().max(5_000_000) }))\n .mutation(async ({ input }) => {\n if (!/\\.(md|markdown)$/i.test(input.path)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Seuls les .md/.markdown sont autorisés' });\n }\n const target = await resolveScope(input.scope);\n if (target.mode === 'agent') {\n return agentManager.agentMutation(target.agentId, 'wiki.writeMarkdown', { cwd: target.cwd, path: input.path, content: input.content }) as Promise<{ path: string; ok: boolean }>;\n }\n const file = await resolveSafeLocal(target.root, input.path, false);\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, input.content, 'utf-8');\n return { path: input.path, ok: true };\n }),\n\n createFile: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA, path: REL_PATH_SCHEMA }))\n .mutation(async ({ input }) => {\n if (!/\\.(md|markdown)$/i.test(input.path)) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Seuls les .md/.markdown sont autorisés' });\n }\n const target = await resolveScope(input.scope);\n if (target.mode === 'agent') {\n return agentManager.agentMutation(target.agentId, 'wiki.createFile', { cwd: target.cwd, path: input.path }) as Promise<{ path: string; ok: boolean }>;\n }\n const file = await resolveSafeLocal(target.root, input.path, false);\n try { await stat(file); throw new TRPCError({ code: 'CONFLICT', message: 'Fichier déjà existant' }); }\n catch (err) { if (err instanceof TRPCError) throw err; }\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, '', 'utf-8');\n return { path: input.path, ok: true };\n }),\n\n createDir: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA, path: REL_PATH_SCHEMA }))\n .mutation(async ({ input }) => {\n const target = await resolveScope(input.scope);\n if (target.mode === 'agent') {\n return agentManager.agentMutation(target.agentId, 'wiki.createDir', { cwd: target.cwd, path: input.path }) as Promise<{ path: string; ok: boolean }>;\n }\n const dir = await resolveSafeLocal(target.root, input.path, false);\n await mkdir(dir, { recursive: true });\n return { path: input.path, ok: true };\n }),\n\n rename: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA, fromPath: REL_PATH_SCHEMA, toPath: REL_PATH_SCHEMA }))\n .mutation(async ({ input }) => {\n const target = await resolveScope(input.scope);\n if (target.mode === 'agent') {\n return agentManager.agentMutation(target.agentId, 'wiki.renamePath', { cwd: target.cwd, fromPath: input.fromPath, toPath: input.toPath }) as Promise<{ fromPath: string; toPath: string; ok: boolean }>;\n }\n const from = await resolveSafeLocal(target.root, input.fromPath, true);\n const to = await resolveSafeLocal(target.root, input.toPath, false);\n try { await stat(to); throw new TRPCError({ code: 'CONFLICT', message: 'La cible existe déjà' }); }\n catch (err) { if (err instanceof TRPCError) throw err; }\n await mkdir(dirname(to), { recursive: true });\n await rename(from, to);\n return { fromPath: input.fromPath, toPath: input.toPath, ok: true };\n }),\n\n ensureRoot: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA }))\n .mutation(async ({ input }) => {\n if (input.scope === 'global') {\n // Already created by resolveScope for global — call it once to materialise\n await resolveScope('global');\n return { ok: true };\n }\n // Service scope: ask the agent to mkdir its resolved docsPath\n const serviceId = input.scope.slice('service:'.length);\n const service = await serviceStore.get(serviceId);\n if (!service) throw new TRPCError({ code: 'NOT_FOUND', message: 'Service introuvable' });\n const agentId = await resolveEffectiveAgentId(service);\n if (!agentId) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Aucun agent configuré' });\n const cwd = await resolveWorkspaceCwd({ serviceId, override: service.docsPath?.trim() || undefined });\n return agentManager.agentMutation(agentId, 'wiki.ensureRoot', { cwd }) as Promise<{ root: string; ok: boolean }>;\n }),\n\n delete: protectedProcedure\n .input(z.object({ scope: SCOPE_SCHEMA, path: REL_PATH_SCHEMA }))\n .mutation(async ({ input }) => {\n const target = await resolveScope(input.scope);\n if (target.mode === 'agent') {\n return agentManager.agentMutation(target.agentId, 'wiki.deletePath', { cwd: target.cwd, path: input.path }) as Promise<{ path: string; ok: boolean }>;\n }\n const fp = await resolveSafeLocal(target.root, input.path, true);\n if (fp === target.root) throw new TRPCError({ code: 'FORBIDDEN', message: 'Impossible de supprimer la racine' });\n await rm(fp, { recursive: true, force: true });\n return { path: input.path, ok: true };\n }),\n});\n","import { router, publicProcedure } from '../trpc.js';\nimport { env } from '../../config/env.js';\n\n/**\n * Runtime configuration the web app needs before/without authentication.\n * The cloud endpoints are set on the server at launch (env vars) and fetched\n * by the web — never configured in the browser.\n */\nexport const configRouter = router({\n cloud: publicProcedure.query(() => ({\n apiUrl: env.CLOUD_URL,\n appUrl: env.CLOUD_APP_URL,\n })),\n\n /** How this instance was launched, and where it answers. */\n app: publicProcedure.query(() => ({\n fromDesktop: env.FROM_DESKTOP,\n port: env.PORT,\n })),\n});\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { readOrgClouds, readOrgAccounts, stampOrgCloud, rememberOrgName, rememberOrgAccount, readOrgNames, rememberOrgLogo, forgetOrgLogo, readOrgLogos, keyRoot, orgVaultRoot } from '../../services/vault-resolver.js';\nimport { assertOrgVaultReadable, OrgVaultUnreadableError } from '../../services/org-keys.js';\nimport { readVerifyFile, matchesCanary } from '../../services/master-password.js';\nimport { orgsToSync } from '../../services/org-sync-scope.js';\nimport { getCloudApiUrl, orgCloudUrl, accountForOrg } from '../../services/cloud-api.js';\nimport {\n reconcileOrgCanary,\n OrgKeyMismatchError,\n CanaryUnavailableError,\n} from '../../services/org-canary.js';\nimport { cloudSyncBridge, ProjectHeldElsewhereError } from '../../services/cloud-sync-bridge.js';\nimport { projectStore } from '../../services/project-store.js';\nimport { conversationStore } from '../../services/conversation-store.js';\nimport { projectPathStore } from '../../services/project-path-store.js';\nimport { cloudFetch, accountForOrgScope } from './cloud-auth.js';\nimport { adoptOrgKey } from '../../services/key-adoption.js';\nimport { getEncryptionKey } from '../../utils/encryption-key.js';\n\n/** Ce que le cloud a répondu, en clair : son `message` s'il en donne un. */\nasync function cloudMessage(res: Response): Promise<string> {\n try {\n const body = await res.text();\n if (!body) return '';\n try {\n const parsed = JSON.parse(body) as { message?: unknown };\n if (typeof parsed.message === 'string') return parsed.message;\n } catch {\n // Pas du JSON : le corps brut reste plus parlant que rien.\n }\n return body.slice(0, 300);\n } catch {\n return '';\n }\n}\n\n/**\n * Prove this machine's key is the org's, in the router's language.\n *\n * The check itself is a service — the sync bridge runs it too — so its refusals\n * come back as plain errors and are turned into tRPC codes here.\n */\n/**\n * Ce que ce poste sait lire, avant tout ce qu'il ira chercher.\n *\n * Éprouvé à CHAQUE ouverture, connexion en cours ou non : `assertOrgKey` ne\n * l'était qu'au premier projet d'une organisation, ce qui laissait les suivants\n * s'ouvrir sans que rien ne revérifie la clé.\n */\n/**\n * Le compte d'une organisation, sous la forme que `connect` attend.\n *\n * Rendu vide plutôt que `{ accountId: undefined }` : le lien est comparé\n * ailleurs, et un champ présent mais vide n'est pas la même chose qu'absent.\n */\nasync function accountScope(orgId: string): Promise<{ accountId?: string }> {\n const accountId = await accountForOrg(orgId);\n return accountId ? { accountId } : {};\n}\n\n/** Combien attendre l'état d'ouverture du cloud avant de suivre un projet. */\nconst OPENING_TIMEOUT_MS = 10_000;\n\nasync function assertOrgReadable(orgId: string): Promise<void> {\n try {\n await assertOrgVaultReadable(orgId);\n } catch (err) {\n if (err instanceof OrgVaultUnreadableError) {\n throw new TRPCError({ code: 'FORBIDDEN', message: err.message });\n }\n throw err;\n }\n}\n\nasync function assertOrgKey(orgId: string): Promise<void> {\n try {\n await reconcileOrgCanary(orgId);\n } catch (err) {\n if (err instanceof OrgKeyMismatchError) {\n throw new TRPCError({ code: 'FORBIDDEN', message: err.message });\n }\n if (err instanceof CanaryUnavailableError) {\n throw new TRPCError({ code: 'PRECONDITION_FAILED', message: err.message });\n }\n throw err;\n }\n}\n\n/**\n * Manages what this local server continuously syncs with the cloud.\n *\n * Nothing here records which organizations to sync: opening a project pulls its\n * vault, and that vault on disk IS the decision (see `org-sync-scope.ts`). The\n * transport authenticates with this machine's cloud session, so no credential\n * is stored either.\n */\n/**\n * Live sync state of an org, or 'stopped' when nothing is connected.\n *\n * Returned alongside the mutations the switcher calls, so the UI can tell a\n * paused session (a rejected sign-in, an app the cloud considers too old) from\n * a pull that is merely slow.\n */\nfunction syncState(orgId: string): string {\n return cloudSyncBridge.states().find((s) => s.orgId === orgId)?.state ?? 'stopped';\n}\n\nexport const cloudSyncRouter = router({\n /**\n * Follow one more project of an org, and pull it now.\n *\n * This is what opening a project in the switcher calls. It links the org on\n * first use, so the UI never has to know whether a link already exists —\n * \"open this project\" is the whole gesture.\n */\n trackProject: protectedProcedure\n .input(\n z.object({\n orgId: z.string().min(1).max(128),\n cloudUrl: z.string().url().max(2048),\n projectId: z.string().min(1).max(128),\n // Le compte sous lequel cette organisation a été listée. Tamponné avec\n // elle : c'est ce qui permettra à tout appel ultérieur de retrouver le\n // bon token sans qu'on ait à le lui redire.\n accountId: z.string().max(64).optional(),\n }),\n )\n .mutation(async ({ input }) => {\n // Avant toute chose : ce coffre s'ouvre-t-il ici ? Ouvrir un projet sous\n // la mauvaise clé ne rate pas — ça écrit par-dessus.\n await assertOrgReadable(input.orgId);\n const connected = cloudSyncBridge.states().some((s) => s.orgId === input.orgId);\n if (!connected) {\n // First project of this org on this machine. The stamp is written\n // BEFORE anything is pulled: it is what tells a later boot which cloud\n // this org's vault came from, and a vault without one would be taken\n // for an org of whatever cloud is configured then.\n await assertOrgKey(input.orgId);\n await stampOrgCloud(input.orgId, input.cloudUrl, undefined, input.accountId);\n await cloudSyncBridge.connect({\n orgId: input.orgId,\n cloudUrl: input.cloudUrl,\n ...(await accountScope(input.orgId)),\n });\n } else if (input.accountId) {\n // L'organisation synchronise déjà — connectée au démarrage, sans passer\n // par ici. Son coffre peut donc n'avoir jamais appris de quel compte il\n // relève, et rien d'autre ne le lui dira : le tampon n'était écrit qu'à\n // la toute première liaison, si bien qu'un poste redémarré une fois ne\n // le recevait plus jamais. Ouvrir un projet est le seul geste où le\n // compte est connu de façon certaine.\n await stampOrgCloud(input.orgId, input.cloudUrl, undefined, input.accountId);\n }\n // Le projet ne se trouve dans le document qu'une fois l'état d'ouverture du\n // cloud reçu : le suivre avant ne trouvait rien, sur un poste qui ouvre le\n // premier projet d'une organisation.\n await cloudSyncBridge.whenOpened(input.orgId, OPENING_TIMEOUT_MS);\n // Idempotent: following a project it already holds re-pulls it, which is\n // what makes re-opening a project fix a pull that never landed.\n try {\n const pulled = await cloudSyncBridge.followProject(input.orgId, input.projectId);\n return { pulled, state: syncState(input.orgId) };\n } catch (err) {\n // Un conflit que l'utilisateur peut lever lui-même, pas une panne : le\n // code voyage, l'interface le dit dans sa langue.\n if (err instanceof ProjectHeldElsewhereError) {\n throw new TRPCError({ code: 'CONFLICT', message: err.code, cause: err });\n }\n throw err;\n }\n }),\n\n /**\n * Faire passer le projet local de cette machine dans une organisation.\n *\n * Le projet n'est pas copié : il déménage. Son coffre quitte\n * `<cwd>/.runeya` pour celui de l'organisation, en gardant son identifiant,\n * puis il est suivi comme n'importe quel projet cloud — la réconciliation le\n * pousse alors dans le doc, services et environnements compris.\n *\n * Le déménagement est ce qui rend le geste sûr : il ne peut jamais y avoir\n * deux copies du même projet, donc rien à écraser. Un projet que\n * l'organisation porte déjà sous le même identifiant est refusé plutôt que\n * fusionné.\n */\n publishProject: protectedProcedure\n .input(\n z.object({\n orgId: z.string().min(1).max(128),\n cloudUrl: z.string().url().max(2048),\n projectId: z.string().min(1).max(128),\n // Le compte sous lequel cette organisation a été listée. Tamponné avec\n // elle : c'est ce qui permettra à tout appel ultérieur de retrouver le\n // bon token sans qu'on ait à le lui redire.\n accountId: z.string().max(64).optional(),\n }),\n )\n .mutation(async ({ input }) => {\n const local = await projectStore.get({ id: input.projectId, orgId: null });\n if (!local) {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'PROJECT_NOT_LOCAL' });\n }\n if (await projectStore.get({ id: input.projectId, orgId: input.orgId })) {\n throw new TRPCError({ code: 'CONFLICT', message: 'PROJECT_ALREADY_IN_ORG' });\n }\n\n // L'organisation doit synchroniser AVANT le déménagement : si sa clé ne\n // convient pas, ou si le lien échoue, le projet doit rester local plutôt\n // que d'atterrir dans un coffre que rien ne pousse.\n await assertOrgReadable(input.orgId);\n const connected = cloudSyncBridge.states().some((s) => s.orgId === input.orgId);\n if (!connected) {\n await assertOrgKey(input.orgId);\n await stampOrgCloud(input.orgId, input.cloudUrl, undefined, input.accountId);\n await cloudSyncBridge.connect({\n orgId: input.orgId,\n cloudUrl: input.cloudUrl,\n ...(await accountScope(input.orgId)),\n });\n } else if (input.accountId) {\n // L'organisation synchronise déjà — connectée au démarrage, sans passer\n // par ici. Son coffre peut donc n'avoir jamais appris de quel compte il\n // relève, et rien d'autre ne le lui dira : le tampon n'était écrit qu'à\n // la toute première liaison, si bien qu'un poste redémarré une fois ne\n // le recevait plus jamais. Ouvrir un projet est le seul geste où le\n // compte est connu de façon certaine.\n await stampOrgCloud(input.orgId, input.cloudUrl, undefined, input.accountId);\n }\n\n await projectStore.moveToOrg(input.projectId, input.orgId);\n // Le répertoire des sources suit le projet : il n'a pas bougé sur le\n // disque, seule la clé qui le désigne a changé d'organisation.\n await projectPathStore.relocate(\n { id: input.projectId, orgId: null },\n { id: input.projectId, orgId: input.orgId },\n );\n // Les conversations suivent leur projet ; leur store n'est pas atteignable\n // depuis celui des projets (il en dépend), d'où l'appel ici.\n await conversationStore.relocateAll();\n\n try {\n await cloudSyncBridge.followProject(input.orgId, input.projectId);\n } catch (err) {\n if (err instanceof ProjectHeldElsewhereError) {\n throw new TRPCError({ code: 'CONFLICT', message: err.code, cause: err });\n }\n throw err;\n }\n return { state: syncState(input.orgId) };\n }),\n\n /**\n * Cette clé est-elle celle de l'organisation ? Rien n'est écrit.\n *\n * L'étape à faire avant tout le reste : on ne re-chiffre pas une machine\n * entière sur une clé dont on n'a pas la preuve qu'elle ouvre le canari\n * publié. Le cloud, lui, ne peut pas répondre — il n'a que du chiffré sous\n * les yeux — donc le canari est rapatrié et jugé ici.\n */\n checkOrgKey: protectedProcedure\n .input(z.object({\n orgId: z.string().min(1).max(128),\n keyHex: z.string().length(64).regex(/^[0-9a-f]+$/i),\n }))\n .query(async ({ input }) => {\n const res = await cloudFetch(\n `/api/auth/organization/canary?organizationId=${encodeURIComponent(input.orgId)}`,\n { method: 'GET', accountId: await accountForOrgScope(input.orgId) },\n );\n if (!res.ok) {\n throw new TRPCError({ code: 'BAD_GATEWAY', message: await cloudMessage(res) || `CANARY_READ_FAILED (${res.status})` });\n }\n const { canary } = (await res.json()) as { canary?: unknown };\n // Pas encore de canari : la première machine à synchroniser publiera le\n // sien. N'importe quelle clé conviendrait, donc aucune n'est confirmée.\n if (typeof canary !== 'string') return { matches: false, published: false };\n return { matches: matchesCanary(canary, Buffer.from(input.keyHex, 'hex')), published: true };\n }),\n\n /**\n * Le canari de cette organisation s'ouvre-t-il avec la clé d'ici ?\n *\n * Le pendant sans synchronisation de `isKeyMismatch` : l'état `key-mismatch`\n * n'existe que pour une organisation dont la synchronisation tourne, or une\n * organisation vide n'en a aucune. Elle refusait donc toute publication sans\n * que l'interface puisse proposer ni l'adoption ni la remise à zéro — le seul\n * chemin qui la répare. Rien n'est écrit ici, ni sur le disque ni sur le cloud.\n */\n orgKeyStatus: protectedProcedure\n .input(z.object({ orgId: z.string().min(1).max(128) }))\n .query(async ({ input }) => {\n const key = getEncryptionKey(input.orgId);\n if (!key) return { status: 'unknown' as const };\n const res = await cloudFetch(\n `/api/auth/organization/canary?organizationId=${encodeURIComponent(input.orgId)}`,\n { method: 'GET', accountId: await accountForOrgScope(input.orgId) },\n );\n if (!res.ok) return { status: 'unknown' as const };\n const { canary } = (await res.json()) as { canary?: unknown };\n // Pas encore de canari : la première machine à synchroniser publiera le\n // sien, et ce sera celui d'ici. Rien à réparer.\n if (typeof canary !== 'string') return { status: 'unpublished' as const };\n return { status: matchesCanary(canary, key) ? ('ok' as const) : ('mismatch' as const) };\n }),\n\n /**\n * Faire adopter à cette machine la clé d'une organisation.\n *\n * Le pendant de `resetOrgKey` : là où celle-ci fait plier l'organisation à la\n * clé d'ici, celle-là fait plier cette machine à la sienne — et c'est la\n * seule des deux qui rend lisible ce qui avait déjà été chiffré sous elle.\n *\n * Bornée au coffre de l'organisation et à ceux de ses projets : les autres\n * organisations et la machine gardent leur clé.\n */\n adoptOrgKey: protectedProcedure\n .input(z.object({\n orgId: z.string().min(1).max(128),\n keyHex: z.string().length(64).regex(/^[0-9a-f]+$/i),\n masterPassword: z.string().min(1).max(1024),\n }))\n .mutation(async ({ input }) => {\n const report = await adoptOrgKey(\n input.orgId,\n Buffer.from(input.keyHex, 'hex'),\n input.masterPassword,\n new Date(),\n );\n // La reconnexion refait le contrôle du canari : c'est elle, et non le\n // succès de la conversion, qui prouve que l'organisation synchronise.\n await cloudSyncBridge.restartAll();\n return { converted: report.converted.length, backups: report.backups, state: syncState(input.orgId) };\n }),\n\n /**\n * Réinitialiser la clé de référence d'une organisation avec celle de cette\n * machine, puis relancer sa synchronisation.\n *\n * Le canari publié par le cloud est write-once : c'est ce qui empêche un\n * membre tenant la mauvaise clé d'enfermer les autres dehors. Le revers, c'est\n * qu'une clé machine qui change — réinstallation, `~/.runeya` perdu, migration\n * d'un ancien coffre — laisse l'organisation insynchronisable pour toujours.\n * Cette route est la sortie de secours, réservée au propriétaire côté cloud.\n *\n * Elle ne re-chiffre rien : ce qui a déjà été synchronisé sous l'ancienne clé\n * reste illisible. L'interface le dit avant de la déclencher.\n */\n resetOrgKey: protectedProcedure\n .input(z.object({ orgId: z.string().min(1).max(128) }))\n .mutation(async ({ input }) => {\n // Le canari du coffre de l'organisation d'abord : c'est LUI que la\n // publication éprouvera (`reconcileOrgCanary` lit `getEncryptionKey(orgId)`).\n // Publier celui de la machine sur une organisation qui a sa clé propre\n // laissait la référence fausse, et le mismatch entier.\n const canary = (await readVerifyFile(orgVaultRoot(input.orgId)))\n ?? (await readVerifyFile(await keyRoot()));\n // Publier un canari qu'on n'a pas remplacerait la référence de l'org par\n // rien du tout : mieux vaut refuser que verrouiller tout le monde dehors.\n if (!canary) {\n throw new TRPCError({\n code: 'PRECONDITION_FAILED',\n message: \"Cette machine n'a pas encore de clé de chiffrement.\",\n });\n }\n const res = await cloudFetch('/api/auth/organization/canary/reset', {\n method: 'POST',\n body: { organizationId: input.orgId, canary },\n accountId: await accountForOrgScope(input.orgId),\n });\n if (!res.ok) {\n const detail = await cloudMessage(res);\n throw new TRPCError({\n code: res.status === 403 ? 'FORBIDDEN' : 'BAD_GATEWAY',\n message: detail || `ORG_KEY_RESET_FAILED (${res.status})`,\n });\n }\n // La reconnexion refait le contrôle du canari : c'est elle, et non le\n // succès de l'appel, qui prouve que l'organisation synchronise à nouveau.\n const cloudUrl = (await orgsToSync()).find((l) => l.orgId === input.orgId)?.cloudUrl\n ?? getCloudApiUrl();\n await cloudSyncBridge.connect({ orgId: input.orgId, cloudUrl, ...(await accountScope(input.orgId)) });\n return { state: syncState(input.orgId) };\n }),\n\n /**\n * Stop materializing one project of an org on this machine.\n *\n * Removes its vault, and nothing else: the project stays in the org, for\n * every other member and for this one on another machine.\n */\n untrackProject: protectedProcedure\n .input(\n z.object({\n orgId: z.string().min(1).max(128),\n projectId: z.string().min(1).max(128),\n }),\n )\n .mutation(async ({ input }) => {\n await cloudSyncBridge.unfollowProject(input.orgId, input.projectId);\n return { success: true as const };\n }),\n\n /**\n * Retirer un projet de l'organisation — pour tous ses membres.\n *\n * À ne pas confondre avec `untrackProject`, qui ne concerne que cette\n * machine. Ici le projet quitte l'organisation : il disparaît pour chaque\n * membre, et le cloud rend son identifiant. La suppression locale n'est pas\n * faite ici : elle arrive par la synchronisation, comme pour tout autre\n * membre, ce qui évite d'effacer les fichiers si le cloud a refusé l'ordre.\n */\n deleteProjectFromOrg: protectedProcedure\n .input(\n z.object({\n orgId: z.string().min(1).max(128),\n projectId: z.string().min(1).max(128),\n }),\n )\n .mutation(async ({ input }) => {\n let res: Response;\n try {\n res = await cloudFetch('/api/auth/project/delete', {\n method: 'POST',\n body: { organizationId: input.orgId, projectId: input.projectId },\n // Dans le `try` : ne rien avoir à quoi rattacher l'organisation doit\n // ressortir comme CLOUD_NOT_LINKED, pas comme une erreur interne.\n accountId: await accountForOrgScope(input.orgId),\n });\n } catch (err) {\n // Pas de session cloud : un état de cette machine, dit avec un code que\n // l'interface traduit — la phrase anglaise de `cloudFetch` finissait\n // telle quelle sous les yeux de l'utilisateur.\n if (err instanceof TRPCError && err.code === 'PRECONDITION_FAILED') {\n throw new TRPCError({ code: 'PRECONDITION_FAILED', message: 'CLOUD_NOT_LINKED' });\n }\n throw err;\n }\n if (res.ok) return { success: true as const };\n\n // Le cloud dit précisément ce qui bloque — pas membre, rôle insuffisant,\n // projet absent. Écraser tout cela derrière un seul code laissait\n // l'utilisateur devant un message faux : « il faut être administrateur »\n // alors qu'il l'est, et que la cause était ailleurs.\n const detail = await cloudMessage(res);\n if (res.status === 403) {\n const code = /not a member/i.test(detail) ? 'PROJECT_NOT_MEMBER' : 'PROJECT_DELETE_FORBIDDEN';\n throw new TRPCError({ code: 'FORBIDDEN', message: code, cause: new Error(detail) });\n }\n if (res.status === 404) {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'PROJECT_NOT_IN_ORG', cause: new Error(detail) });\n }\n // Tout le reste voyage tel quel : un statut inattendu (426 version, 401\n // session expirée, panne réseau) mérite d'être lu, pas maquillé.\n throw new TRPCError({\n code: 'BAD_GATEWAY',\n message: detail || `PROJECT_DELETE_FAILED (${res.status})`,\n });\n }),\n\n /**\n * List the orgs this machine syncs, with their live sync state so the UI can\n * surface one whose sync is paused awaiting a fresh cloud sign-in.\n *\n * Derived from the vaults on disk, so it says what is actually synced rather\n * than what someone once asked for.\n */\n /**\n * Retenir localement le nom des organisations que le cloud vient de nommer.\n *\n * Les coffres sont rangés par identifiant, et l'identifiant est un hash : une\n * fois la session cloud éteinte, l'interface n'avait plus rien d'humain à\n * afficher. Le nom est donc recopié dans le tampon du coffre au passage, là\n * où il est déjà lu au démarrage suivant.\n */\n /**\n * Retenir à quel compte appartient chaque organisation.\n *\n * Poussé par l'interface avec ce que le cloud vient de répondre : une\n * organisation appartient au compte qui la LISTE. Le poste ne peut pas le\n * déduire — il l'a tenté, et il a rangé sous un compte les organisations\n * d'un autre. Même forme que `rememberOrgNames`, et pour la même raison :\n * ce que seul le cloud sait, on le recopie quand il le dit.\n */\n rememberOrgAccounts: protectedProcedure\n .input(z.object({\n orgs: z.array(z.object({\n orgId: z.string().min(1).max(128),\n accountId: z.string().min(1).max(64),\n })).max(200),\n }))\n .mutation(async ({ input }) => {\n // Une organisation peut être listée par PLUSIEURS comptes : deux\n // utilisateurs de ce poste en sont membres tous les deux. N'importe\n // lequel conviendrait, mais en écrire un au hasard le ferait changer à\n // chaque démarrage — le compte affiché sauterait sans raison visible. Le\n // tampon en place l'emporte donc tant qu'il reste un membre légitime.\n const candidates = new Map<string, string[]>();\n for (const { orgId, accountId } of input.orgs) {\n candidates.set(orgId, [...(candidates.get(orgId) ?? []), accountId]);\n }\n const current = await readOrgAccounts();\n let remembered = 0;\n for (const [orgId, accountIds] of candidates) {\n const kept = current[orgId];\n if (kept && accountIds.includes(kept)) continue;\n await rememberOrgAccount(orgId, accountIds[0]!);\n remembered++;\n }\n return { remembered };\n }),\n\n rememberOrgNames: protectedProcedure\n .input(z.object({\n orgs: z.array(z.object({\n orgId: z.string().min(1).max(128),\n name: z.string().min(1).max(100),\n })).max(200),\n }))\n .mutation(async ({ input }) => {\n for (const { orgId, name } of input.orgs) await rememberOrgName(orgId, name);\n return { remembered: input.orgs.length };\n }),\n\n /**\n * Les noms retenus dans les coffres de ce poste.\n *\n * Le pendant en lecture de `rememberOrgNames`, qui n'en avait pas : le nom\n * était recopié sur le disque au passage du cloud, puis n'était relu que par\n * le panneau des clés. L'écran de lancement, lui, ne connaissait que le cloud\n * — hors ligne, ou avant que la session ne réponde, il n'affichait donc qu'un\n * hash pour des organisations dont le nom était pourtant là, à côté.\n */\n orgNames: protectedProcedure.query(async () => readOrgNames()),\n\n /**\n * Rapatrier le logo des organisations données, pour que l'interface les\n * reconnaisse hors ligne comme elle les nomme hors ligne.\n *\n * C'est le serveur qui va le chercher, et non le navigateur : la route\n * d'image du cloud ne pose aucun en-tête CORS — un `fetch` depuis l'interface\n * serait refusé, et un `<img>` ne rend pas ses octets. Chaque organisation est\n * interrogée sur SON cloud (le tampon de son coffre), jamais sur celui\n * configuré à l'instant : un poste qui a connu deux clouds ramènerait sinon\n * l'image du mauvais.\n *\n * Un 404 efface le logo retenu — l'organisation en a retiré un — tandis qu'un\n * réseau muet laisse en place ce qui est déjà là : hors ligne, on garde.\n */\n cacheOrgLogos: protectedProcedure\n .input(z.object({ orgIds: z.array(z.string().min(1).max(128)).max(200) }))\n .mutation(async ({ input }) => {\n let cached = 0;\n for (const orgId of input.orgIds) {\n const base = await orgCloudUrl(orgId);\n try {\n // `format=png` : ce qui est rangé ici est relu par l'interface, mais\n // aussi posé dans la barre système, qui ne lit que le PNG. Le\n // demander au rapatriement évite d'avoir à convertir à chaque\n // affichage — et fait tenir l'icône hors ligne. Un cloud trop ancien\n // ignore le paramètre et rend l'original : c'est ce qui était rangé\n // jusqu'ici, rien n'est perdu.\n const res = await fetch(`${base}/api/org-logo/${encodeURIComponent(orgId)}?format=png`, {\n signal: AbortSignal.timeout(10_000),\n });\n if (res.status === 404) {\n await forgetOrgLogo(orgId);\n continue;\n }\n if (!res.ok) continue;\n const contentType = (res.headers.get('content-type') ?? '').split(';')[0]!.trim().toLowerCase();\n const bytes = Buffer.from(await res.arrayBuffer());\n // Même plafond que celui posé à l'envoi côté cloud : ce qui dépasse\n // ne vient pas de notre route, et n'a rien à faire dans un coffre.\n if (bytes.length === 0 || bytes.length > 512 * 1024) continue;\n await rememberOrgLogo(orgId, contentType, bytes.toString('base64'));\n cached += 1;\n } catch {\n // Cloud injoignable : on garde ce qui est déjà retenu.\n }\n }\n return { cached };\n }),\n\n /** Les logos retenus dans les coffres de ce poste, en data URL. */\n orgLogos: protectedProcedure.query(async () => readOrgLogos()),\n\n list: protectedProcedure.query(async () => {\n const links = await orgsToSync();\n const states = new Map(cloudSyncBridge.states().map((s) => [s.orgId, s]));\n return links.map((l) => {\n const found = states.get(l.orgId);\n return {\n orgId: l.orgId,\n cloudUrl: l.cloudUrl,\n state: found?.state ?? 'stopped',\n // Renseigné seulement quand le cloud a refusé cette app comme trop\n // ancienne : c'est lui qui publie le plancher, on ne le devine pas. La\n // borne est exclusive — il faut strictement plus récent que ce numéro.\n lastIncompatibleVersion: found?.lastIncompatibleVersion ?? null,\n };\n });\n }),\n\n /**\n * The cloud instance behind every org vault on this machine.\n *\n * Wider than `list`, which only reports the orgs actually synced here: a vault\n * may come from another cloud entirely, and saying so is how the UI explains\n * an org it can see but not reach.\n */\n orgClouds: protectedProcedure.query(async () => {\n const clouds = await readOrgClouds();\n // An org synced here without a stamp (a vault written before stamping\n // existed) belongs to the cloud this installation talks to.\n for (const { orgId } of await orgsToSync()) clouds[orgId] ??= getCloudApiUrl();\n return clouds;\n }),\n});\n","import { access } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { listCloudVaults, readOrgClouds, readOrgAccounts } from './vault-resolver.js';\nimport { cloudSessionStore } from './cloud-session-store.js';\nimport { getCloudApiUrl } from './cloud-api.js';\n\n/**\n * Which organizations this machine syncs — read from the disk, never stored.\n *\n * Syncing follows the projects you open: opening one materializes its vault\n * under `~/.runeya/orgs/<org>/projects/<id>`, and dropping it removes that\n * vault. The set of organizations worth connecting to is therefore already\n * written down, by the layout itself.\n *\n * It used to be a file of its own (`cloud-sync.json`), which had to be kept in\n * agreement with what was actually on disk — and did not: the UI stopped\n * offering link/unlink long ago, so the file recorded a decision nobody made\n * any more, while its disappearance silently stopped all syncing.\n */\n\nexport interface OrgSyncTarget {\n orgId: string;\n cloudUrl: string;\n /**\n * Le compte au nom duquel synchroniser cette organisation.\n *\n * Résolu ici, une fois, plutôt qu'à chaque requête : la question se tranche\n * en lisant le disque, et la poser à chaque push mettait une lecture de\n * fichier sur le chemin le plus chaud de l'application. Absent : le poste\n * n'en a qu'un, ou n'en a pas — `undefined` laisse le magasin retomber sur\n * son compte unique, ce qui est exactement la situation d'avant.\n */\n accountId?: string;\n}\n\n/**\n * A directory alone does not make a project: the stores create one as soon as\n * they write anything under it, so an org whose only trace is an empty\n * `environments.json` would otherwise be connected forever. `project.json` is\n * the file that says \"this project is materialized here\".\n */\nasync function isMaterialized(root: string): Promise<boolean> {\n return access(join(root, 'project.json')).then(() => true, () => false);\n}\n\n/**\n * Organizations with at least one materialized project on this machine.\n *\n * An org stamped with a cloud no account of this machine is signed into is left\n * out: its vault came from another instance, and connecting it here would ask a\n * cloud about an organization it knows nothing of. An unstamped org is assumed\n * to belong to the single account — that is how vaults written before the stamp\n * read, and with several accounts there is nothing to assume, so it waits for a\n * stamp rather than being offered to whoever happens to be first.\n *\n * L'adresse rendue est celle du tampon, plus celle configurée : deux comptes\n * peuvent vivre sur deux clouds, et l'adresse configurée n'est celle d'aucun\n * des deux en particulier.\n */\nexport async function orgsToSync(): Promise<OrgSyncTarget[]> {\n const [stamps, stampedAccounts, accounts] = await Promise.all([\n readOrgClouds(), readOrgAccounts(), cloudSessionStore.list(),\n ]);\n // Le cloud configuré compte parmi les connus même sans compte lié : une\n // session expirée ne doit pas faire disparaître l'organisation de la liste,\n // elle doit l'y laisser en « non authentifiée » — c'est cet état qui dit à\n // l'utilisateur qu'il a une connexion à refaire.\n const known = new Set([\n getCloudApiUrl(),\n ...accounts.map((a) => a.cloudUrl.replace(/\\/+$/, '')),\n ]);\n const fallback = accounts.length <= 1\n ? (accounts[0]?.cloudUrl.replace(/\\/+$/, '') ?? getCloudApiUrl())\n : null;\n const targets = new Map<string, OrgSyncTarget>();\n\n for (const vault of await listCloudVaults()) {\n if (targets.has(vault.orgId)) continue;\n const stamped = stamps[vault.orgId]?.replace(/\\/+$/, '');\n if (stamped ? !known.has(stamped) : fallback === null) continue;\n const cloudUrl = stamped ?? fallback;\n if (!cloudUrl) continue;\n const accountId = stampedAccounts[vault.orgId]\n ?? (accounts.length === 1 ? accounts[0]!.id : undefined);\n if (await isMaterialized(vault.root)) {\n targets.set(vault.orgId, { orgId: vault.orgId, cloudUrl, ...(accountId ? { accountId } : {}) });\n }\n }\n\n return Array.from(targets.values());\n}\n","import { cloudFetch, accountForOrgOrThrow } from './cloud-api.js';\nimport { matchesCanary, readVerifyFile } from './master-password.js';\nimport { getEncryptionKey } from '../utils/encryption-key.js';\nimport { keyRoot, orgVaultRoot } from './vault-resolver.js';\n\n/**\n * Reconcile this machine's encryption key with an organization's.\n *\n * Members share one key, out of band — the cloud never carries it. What the org\n * does publish is a canary: a blob only the right key can open. So before\n * syncing, this machine proves its key opens the org's canary; otherwise it\n * would happily receive everyone's data and be unable to read any secret in it,\n * with no explanation.\n *\n * The first machine to sync an org publishes its own canary and becomes the\n * reference for the others.\n *\n * Lives here rather than in the cloud-sync router because it is now also\n * checked when the sync starts on its own — an org is synced because its vault\n * is on disk, and nobody re-affirms the decision on boot, so the key that was\n * right when the project was pulled must be proven right again.\n */\n\n/** The check could not be carried out — no key, no canary, or no cloud. */\nexport class CanaryUnavailableError extends Error {\n readonly code = 'CANARY_UNAVAILABLE';\n /** `detail` reste pour les journaux ; le message est le code, pour l'interface. */\n constructor(readonly detail: string) {\n super('CANARY_UNAVAILABLE');\n this.name = 'CanaryUnavailableError';\n }\n}\n\n/** This machine's key is not the organization's — syncing would yield gibberish. */\nexport class OrgKeyMismatchError extends Error {\n readonly code = 'ORG_KEY_MISMATCH';\n /**\n * Le message EST le code, comme partout ailleurs sur ces routes.\n *\n * Une phrase écrite ici traverse le serveur telle quelle et s'affiche dans\n * l'interface sans passer par la traduction : une interface en français\n * annonçait donc l'échec en anglais, et le texte ne pouvait renvoyer nulle\n * part puisque le serveur ignore où se trouve l'écran qui répare. Le client\n * traduit `serverErrors.ORG_KEY_MISMATCH` et nomme le chemin.\n */\n constructor() {\n super('ORG_KEY_MISMATCH');\n this.name = 'OrgKeyMismatchError';\n }\n}\n\nexport async function reconcileOrgCanary(orgId: string): Promise<void> {\n // La clé de CETTE organisation, pas celle du poste : c'est tout l'intérêt\n // d'une clé par organisation — appartenir à deux organisations aux clés\n // différentes ne doit plus obliger à en sacrifier une.\n const key = getEncryptionKey(orgId);\n if (!key) throw new CanaryUnavailableError(\"Clé de l'organisation non chargée.\");\n\n // Le canari publié est celui de cette clé-là. Le coffre de l'organisation a\n // le sien dès qu'elle a reçu sa clé ; sinon c'est encore celui de la machine,\n // ce qui est exact puisque la clé l'est aussi.\n const local = (await readVerifyFile(orgVaultRoot(orgId))) ?? (await readVerifyFile(await keyRoot()));\n if (!local) throw new CanaryUnavailableError('This machine has no key canary yet.');\n\n // Publishing is write-once server-side: the value that comes back is the org's\n // reference, whether we just set it or someone else already had.\n const res = await cloudFetch('/api/auth/organization/canary', {\n method: 'POST',\n body: { organizationId: orgId, canary: local },\n accountId: await accountForOrgOrThrow(orgId),\n });\n if (!res.ok) {\n throw new CanaryUnavailableError('Could not reach the organization on the cloud.');\n }\n const { canary } = (await res.json()) as { canary?: unknown };\n if (typeof canary !== 'string') {\n throw new CanaryUnavailableError('The cloud returned no key canary.');\n }\n if (!matchesCanary(canary, key)) throw new OrgKeyMismatchError();\n}\n","import { randomUUID } from 'node:crypto';\nimport { mkdir, rm } from 'node:fs/promises';\nimport * as Y from 'yjs';\nimport { projectStore } from './project-store.js';\nimport { serviceStore } from './service-store.js';\nimport { environmentStore } from './environment-store.js';\nimport { logParserStore, isShareableParser } from './log-parser-store.js';\nimport { orgsToSync, type OrgSyncTarget as CloudSyncLink } from './org-sync-scope.js';\nimport { reconcileOrgCanary, OrgKeyMismatchError } from './org-canary.js';\nimport { cloudSessionStore } from './cloud-session-store.js';\nimport { APP_VERSION_HEADER, appVersion } from '../config/app-version.js';\nimport { getCollection, readEntity, writeEntity } from '@runeya/packages-shared';\nimport type { Project } from '@runeya/packages-shared';\nimport { listCloudVaults, projectVaultRoot } from './vault-resolver.js';\nimport { readSyncDoc, writeSyncDoc, writeSyncDocSync } from './sync-doc-cache.js';\nimport { isLocallyRemoved, clearLocalRemoval, isDetached, clearDetached } from './local-removals.js';\n\n/**\n * Continuous, bidirectional synchronization between this local server and the\n * cloud, for every organization this server is linked to.\n *\n * Scope follows the hierarchy — org → project → services/environments — and\n * mirrors what git already shares: each entity's *on-disk* form, whatever\n * fields it happens to carry. Runtime-only state (a project's active\n * environment, a service's resolved env) is not persisted, so it is not synced\n * either; no allowlist decides this, \"is it on disk?\" does.\n *\n * Local-first is preserved: the `.runeya` JSON files stay the source of truth.\n * A per-org `Y.Doc` (CRDT) mirrors them and is relayed through the cloud over an\n * HTTP + SSE transport, so concurrent edits from different members merge instead\n * of overwriting each other.\n *\n * Loop prevention relies on Yjs transaction origins:\n * - local mutation → reconcile into doc under origin `local-bridge` → the\n * resulting incremental update is POSTed to the cloud.\n * - remote update → applied to the doc under origin `remote` → the observer\n * writes it back into the stores.\n * The stores then save and notify, which re-enters reconciliation — harmless\n * only because every write here is diff-guarded down to the field.\n */\n\nconst LOCAL_ORIGIN = 'local-bridge';\nconst REMOTE_ORIGIN = 'remote';\n/** History reloaded from this machine's cache: already on disk, not re-applied. */\nconst CACHE_ORIGIN = 'cache';\n/** Les projets recréés par une restauration du cloud — voir `apps/cloud/src/lib/sync-docs.ts`. */\nconst RESTORED_PROJECTS = 'projectRestores';\nconst PERSIST_DEBOUNCE_MS = 1_000;\nconst RECONNECT_DELAY_MS = 3_000;\n\n/**\n * How long to wait before retrying once the cloud rejected our session.\n *\n * A rejection usually needs a human (sign in again), so retrying on the normal\n * 3s cadence would just spam the logs forever. But it is not always terminal —\n * a cloud-side bug or a deploy rejects perfectly good sessions too, and those\n * heal on their own. Retrying slowly keeps the sync self-healing without the\n * noise; a fresh sign-in still resumes immediately via `resumeAll()`.\n */\nconst UNAUTHENTICATED_RETRY_MS = 5 * 60_000;\n\n/**\n * How long to wait before retrying once the cloud declared this app too old.\n *\n * Longer than a session rejection, because nothing heals here without a human\n * updating the app — but not never: the cloud may lower its floor again, or the\n * user may update without restarting anything we can observe.\n */\nconst OUTDATED_RETRY_MS = 30 * 60_000;\n\ntype CollectionName = 'projects' | 'services' | 'environments';\nconst COLLECTIONS: CollectionName[] = ['projects', 'services', 'environments'];\n\n/**\n * Les parseurs de logs, tenus à part des trois autres collections.\n *\n * Celles-ci descendent toutes d'un projet, et leur logique en dépend : ce que\n * cette machine « suit », ce qu'elle a le droit de supprimer, ce qu'un projet\n * jamais téléchargé lui interdit de toucher. Un parseur n'a pas de projet\n * parent — il appartient à l'organisation entière, et chaque membre en tient le\n * jeu complet. Le faire passer par `isTracked` reviendrait à lui inventer un\n * projet ; il a donc son observateur et sa réconciliation, plus courts parce\n * que la question « m'appartient-il ? » ne se pose pas.\n */\nconst PARSERS = 'logParsers';\n\n/** What the sync of one organization is currently doing, for the UI. */\nexport type SyncState =\n | 'connecting' | 'live' | 'unauthenticated' | 'outdated' | 'stopped' | 'key-mismatch';\n\nexport interface SyncStateReport {\n orgId: string;\n state: SyncState;\n lastIncompatibleVersion: string | null;\n}\n\n/** The cloud rejected our session (expired, signed out, or membership revoked). */\nclass SyncAuthError extends Error {\n constructor(status: number) {\n super(`cloud rejected the session (HTTP ${status})`);\n }\n}\n\n/**\n * The cloud refuses this app's version (HTTP 426).\n *\n * Distinct from an auth rejection because the cure is different: no amount of\n * retrying or signing back in fixes it, only updating the app — so it gets its\n * own state, its own cadence, and its own message.\n */\nclass SyncOutdatedError extends Error {\n /** Dernière version que le cloud refuse — la borne est exclusive. */\n public readonly lastIncompatibleVersion: string | null;\n\n constructor(lastIncompatibleVersion: string | null) {\n super(\n `this app (${appVersion}) is too old for this cloud`\n + `${lastIncompatibleVersion ? ` (needs newer than ${lastIncompatibleVersion})` : ''}`,\n );\n this.lastIncompatibleVersion = lastIncompatibleVersion;\n }\n}\n\n/** One live sync connection for a single organization. */\n/**\n * Le projet est déjà tenu ici pour une autre organisation — ou en local.\n *\n * Porte un code stable plutôt qu'une phrase : le message affiché est traduit\n * côté interface, celui-ci part dans les journaux.\n */\nexport class ProjectHeldElsewhereError extends Error {\n readonly code = 'PROJECT_HELD_ELSEWHERE';\n\n constructor(readonly projectId: string, readonly heldByOrgId: string | null) {\n super(\n `Project ${projectId} is already held here for ${heldByOrgId ? `organization ${heldByOrgId}` : 'this directory'}. ` +\n 'Two copies of one project share every entity id — stop following the other one first.',\n );\n this.name = 'ProjectHeldElsewhereError';\n }\n}\n\nclass OrgSyncConnection {\n private readonly doc = new Y.Doc();\n private readonly projects = getCollection(this.doc, 'projects');\n private readonly services = getCollection(this.doc, 'services');\n private readonly environments = getCollection(this.doc, 'environments');\n private readonly logParsers = getCollection(this.doc, PARSERS);\n private readonly conn = randomUUID();\n private link: CloudSyncLink;\n private stopped = false;\n private initializing = true;\n private abort: AbortController | null = null;\n private state: SyncState = 'connecting';\n /** Last version the cloud refuses, as it told us when rejecting this app. */\n private lastIncompatibleVersion: string | null = null;\n /** Local state still owed to the cloud (initial sync, or a rejected episode). */\n private needsPush = false;\n /**\n * Set while a newly followed project is being materialized.\n *\n * Reconciliation reads \"absent locally\" as \"removed from the project\", which\n * is true for an edit and catastrophically false mid-pull: a project whose\n * files have not landed yet would have its services and environments wiped\n * from the doc — for every member of the org, not just here.\n */\n private pulling = false;\n /**\n * Projects of this org materialized on this machine — the ones whose vault\n * exists. Refreshed from disk rather than held in a saved list: a list is one\n * more thing that can disagree with what is actually there, and a project on\n * disk but missing from it is the \"already here, still offered as a download\"\n * bug this replaces.\n */\n private tracked: Set<string> = new Set();\n /**\n * Whether the doc's opening state has been applied.\n *\n * It separates \"the org already had these projects\" from \"someone just\n * created one\". The first must not land here — joining a fifty-project org\n * would drop all fifty on the disk — while the second should, so a colleague\n * creating a project sees it appear on their teammates' machines.\n */\n private initialDocApplied = false;\n /**\n * Whether local state has been written into the doc.\n *\n * Never before the doc holds the known history — reloaded from disk, or\n * received from the cloud. Written into an empty doc, local state is\n * concurrent with every past write and loses to some of them at random: an\n * offline edit reverted, a service on disk erased by an older deletion.\n */\n private seeded = false;\n private markOpened!: () => void;\n /**\n * Réglée quand le document tient l'état d'ouverture du cloud — ou quand il ne\n * l'aura pas : session refusée, app trop ancienne, connexion arrêtée.\n */\n readonly opened = new Promise<void>((resolve) => { this.markOpened = resolve; });\n /** Store applications started by remote events and not finished yet. */\n private readonly applying = new Set<Promise<void>>();\n /**\n * When each entity was last changed by a remote update (`collection:id` → tick).\n *\n * Reconciliation reads the stores, waits, then writes what it read. A remote\n * change landing in between makes that read stale, and writing it would erase\n * the value that just arrived — for every member. Entities touched since the\n * read began are left alone: their application brings the disk up to date,\n * and the reconciliation it triggers starts from there.\n */\n private readonly remoteTouch = new Map<string, number>();\n private remoteClock = 0;\n private persistTimer: ReturnType<typeof setTimeout> | null = null;\n /** The cache write under way, so stopping can wait for it to land. */\n private persisting: Promise<void> = Promise.resolve();\n private readonly unsubscribes: (() => void)[] = [];\n private readonly onSaved = () => void this.reconcileLocalToDoc();\n\n constructor(link: CloudSyncLink) {\n this.link = link;\n }\n\n private collection(name: CollectionName): Y.Map<unknown> {\n return this[name];\n }\n\n getState(): SyncState {\n return this.state;\n }\n\n /** The cloud's version floor, known only once it has rejected us for it. */\n getLastIncompatibleVersion(): string | null {\n return this.lastIncompatibleVersion;\n }\n\n getLink(): CloudSyncLink {\n return this.link;\n }\n\n async start(): Promise<void> {\n // What this machine already holds decides what the doc may write here, so\n // it has to be known before the first remote event is applied.\n await this.refreshTracked();\n\n // Outbound: relay local-origin doc updates to the cloud (skipped while the\n // initial full push is being assembled).\n this.doc.on('update', (update: Uint8Array, origin: unknown) => {\n if (this.stopped || this.initializing) return;\n if (origin === LOCAL_ORIGIN) void this.pushUpdate(update);\n });\n\n // Inbound: apply remote-origin doc changes back into the local stores.\n for (const name of COLLECTIONS) {\n this.collection(name).observeDeep((events, txn) => {\n if (txn.origin !== REMOTE_ORIGIN) return;\n // Read before the flag is raised below: within one transaction every\n // observer runs synchronously, so all of them must see the same answer\n // for \"is this the opening state?\".\n const isInitial = !this.initialDocApplied;\n if (name === 'projects') this.initialDocApplied = true;\n this.track(this.applyDocEventsToStore(name, events, isInitial));\n });\n }\n\n // Les parseurs n'ont pas de projet parent : tout ce qui arrive est pour\n // cette machine, et il n'y a rien à filtrer.\n this.logParsers.observeDeep((events, txn) => {\n if (txn.origin !== REMOTE_ORIGIN) return;\n this.track(this.applyParserEventsToStore(events));\n });\n\n projectStore.events.on('saved', this.onSaved);\n this.unsubscribes.push(serviceStore.onChange(this.onSaved));\n this.unsubscribes.push(environmentStore.onChange(this.onSaved));\n this.unsubscribes.push(logParserStore.onLocalChange(this.onSaved));\n\n // The history this machine already knew, applied without touching the\n // stores: the disk already reflects it. Local state then goes on top.\n const cached = await readSyncDoc(this.link.orgId);\n let cacheLoaded = false;\n if (cached) {\n try {\n Y.applyUpdate(this.doc, cached, CACHE_ORIGIN);\n cacheLoaded = true;\n } catch (err) {\n console.error('[cloud-sync] unreadable sync cache for org %s, ignored:', this.link.orgId, (err as Error).message);\n }\n }\n this.doc.on('update', () => this.schedulePersist());\n // `initialDocApplied` reste faux : la première trame du cloud rattrape ce que\n // l'organisation a fait pendant que la machine était fermée. C'est un état\n // d'ouverture, pas des créations en direct — un projet apparu entre-temps\n // reste proposé, pas installé d'office.\n if (cacheLoaded) await this.seed();\n\n // Without a cache, seeding waits for the cloud's opening state (see\n // `streamOnce`). A rejected session does not abort the start — the loop\n // retries slowly and recovers on its own.\n void this.streamLoop();\n }\n\n /** Write local state on top of the known history, then owe it to the cloud. */\n private async seed(): Promise<void> {\n this.seeded = true;\n await this.reconcileLocalToDoc();\n this.initializing = false;\n this.needsPush = true;\n }\n\n private track(work: Promise<void>): void {\n this.applying.add(work);\n void work.finally(() => this.applying.delete(work));\n }\n\n private async settleApplying(): Promise<void> {\n while (this.applying.size > 0) await Promise.allSettled(this.applying);\n }\n\n private schedulePersist(): void {\n if (this.stopped || this.persistTimer) return;\n this.persistTimer = setTimeout(() => {\n this.persistTimer = null;\n this.persisting = this.persisting.then(() => this.persist());\n }, PERSIST_DEBOUNCE_MS);\n }\n\n private async persist(): Promise<void> {\n // Stopping already wrote the latest state; a write queued behind it has nothing to add.\n if (this.stopped) return;\n try {\n await writeSyncDoc(this.link.orgId, Y.encodeStateAsUpdate(this.doc));\n } catch (err) {\n console.error('[cloud-sync] could not save sync cache for org %s:', this.link.orgId, (err as Error).message);\n }\n }\n\n /** Resolves once any cache write already under way has landed. */\n stop(): Promise<void> {\n this.stopped = true;\n this.markOpened();\n this.state = 'stopped';\n projectStore.events.off('saved', this.onSaved);\n for (const off of this.unsubscribes.splice(0)) off();\n this.abort?.abort();\n if (this.persistTimer) {\n clearTimeout(this.persistTimer);\n this.persistTimer = null;\n }\n // Only once seeded: before that the doc is not yet a history worth keeping.\n if (this.seeded) {\n try {\n writeSyncDocSync(this.link.orgId, Y.encodeStateAsUpdate(this.doc));\n } catch (err) {\n console.error('[cloud-sync] could not save sync cache for org %s:', this.link.orgId, (err as Error).message);\n }\n }\n this.doc.destroy();\n return this.persisting;\n }\n\n // ---- Transport -------------------------------------------------------\n\n /**\n * Read the cloud session token fresh on every request, so signing back in\n * resumes sync without a restart. Throws when signed out, which the callers\n * treat as terminal exactly like a rejection from the cloud.\n */\n private async authHeader(): Promise<string> {\n // Le compte suit l'organisation, jamais « le » compte du poste : deux\n // organisations d'utilisateurs différents se synchronisent en même temps,\n // et un token unique en condamnait une des deux à un 403 perpétuel. Il est\n // porté par le lien, résolu une fois à la connexion — le relire ici\n // mettrait une lecture disque sur chaque push.\n const token = await cloudSessionStore.getToken(this.link.accountId);\n if (!token) throw new SyncAuthError(401);\n return `Bearer ${token}`;\n }\n\n private async headers(): Promise<Record<string, string>> {\n return {\n Authorization: await this.authHeader(),\n [APP_VERSION_HEADER]: appVersion,\n 'Content-Type': 'application/json',\n };\n }\n\n /**\n * Turn a 426 into a typed error, reading the floor the cloud published in the\n * body. The body is advisory: a missing or malformed one still blocks, it just\n * makes for a vaguer message.\n */\n private async outdatedError(res: Response): Promise<SyncOutdatedError> {\n try {\n const body = (await res.json()) as { lastIncompatibleVersion?: unknown };\n return new SyncOutdatedError(\n typeof body.lastIncompatibleVersion === 'string' ? body.lastIncompatibleVersion : null,\n );\n } catch {\n return new SyncOutdatedError(null);\n }\n }\n\n /** Remember the floor and stop pretending sync will resume on its own. */\n private markOutdated(err: SyncOutdatedError): void {\n this.markOpened();\n const alreadyReported = this.state === 'outdated';\n this.state = 'outdated';\n this.lastIncompatibleVersion = err.lastIncompatibleVersion;\n // Everything written while we were refused still has to reach the cloud\n // once the app is updated.\n this.needsPush = true;\n if (alreadyReported) return;\n console.error(`[cloud-sync] org ${this.link.orgId}: ${err.message} — sync paused until the app is updated.`);\n }\n\n /**\n * Mark this org as needing a fresh sign-in. Logged once per episode, not on\n * every slow retry: the point of retrying is to recover quietly.\n */\n private markUnauthenticated(err: SyncAuthError): void {\n this.markOpened();\n const alreadyReported = this.state === 'unauthenticated';\n this.state = 'unauthenticated';\n // Anything local was written while we were rejected: push it again once the\n // session works, or those changes would never reach the cloud.\n this.needsPush = true;\n if (alreadyReported) return;\n console.error(\n `[cloud-sync] org ${this.link.orgId}: ${err.message} — sync paused; retrying every`\n + ` ${UNAUTHENTICATED_RETRY_MS / 60_000} min, or immediately when you sign in to the cloud again.`,\n );\n }\n\n /** Sleep that gives up as soon as the connection is stopped. */\n private async delay(ms: number): Promise<void> {\n const step = 250;\n for (let waited = 0; waited < ms && !this.stopped; waited += step) {\n await new Promise((r) => setTimeout(r, Math.min(step, ms - waited)));\n }\n }\n\n private url(path: string): string {\n return `${this.link.cloudUrl.replace(/\\/$/, '')}/api/sync/${encodeURIComponent(this.link.orgId)}${path}`;\n }\n\n private async initialPush(): Promise<void> {\n try {\n const svRes = await fetch(this.url('/state-vector'), {\n headers: await this.headers(),\n signal: AbortSignal.timeout(15_000),\n });\n if (svRes.status === 426) throw await this.outdatedError(svRes);\n if (svRes.status === 401 || svRes.status === 403) throw new SyncAuthError(svRes.status);\n if (!svRes.ok) return;\n const { sv } = (await svRes.json()) as { sv: string };\n const cloudSv = new Uint8Array(Buffer.from(sv, 'base64'));\n const diff = Y.encodeStateAsUpdate(this.doc, cloudSv);\n await this.pushUpdate(diff);\n } catch (err) {\n if (err instanceof SyncAuthError || err instanceof SyncOutdatedError) throw err;\n console.error('[cloud-sync] initial push failed for org %s:', this.link.orgId, (err as Error).message);\n }\n }\n\n private async pushUpdate(update: Uint8Array): Promise<void> {\n try {\n const res = await fetch(this.url('/update'), {\n method: 'POST',\n headers: await this.headers(),\n body: JSON.stringify({ update: Buffer.from(update).toString('base64'), conn: this.conn }),\n signal: AbortSignal.timeout(15_000),\n });\n if (res.status === 426) throw await this.outdatedError(res);\n if (res.status === 401 || res.status === 403) throw new SyncAuthError(res.status);\n } catch (err) {\n if (err instanceof SyncOutdatedError) {\n this.markOutdated(err);\n this.abort?.abort();\n return;\n }\n if (err instanceof SyncAuthError) {\n this.markUnauthenticated(err);\n this.abort?.abort();\n return;\n }\n if (!this.stopped) console.error('[cloud-sync] push failed for org %s:', this.link.orgId, (err as Error).message);\n }\n }\n\n /**\n * Long-lived SSE connection; reconnects on drop, and backs off to a slow\n * cadence while the cloud is rejecting our session.\n */\n private async streamLoop(): Promise<void> {\n while (!this.stopped) {\n try {\n // Catches up whatever changed locally while we were disconnected.\n if (this.needsPush) {\n await this.initialPush();\n this.needsPush = false;\n }\n this.state = 'connecting';\n await this.streamOnce();\n } catch (err) {\n if (err instanceof SyncOutdatedError) {\n this.markOutdated(err);\n await this.delay(OUTDATED_RETRY_MS);\n continue;\n }\n if (err instanceof SyncAuthError) {\n this.markUnauthenticated(err);\n await this.delay(UNAUTHENTICATED_RETRY_MS);\n continue;\n }\n if (!this.stopped) console.error('[cloud-sync] stream error for org %s:', this.link.orgId, (err as Error).message);\n }\n await this.delay(RECONNECT_DELAY_MS);\n }\n }\n\n private async streamOnce(): Promise<void> {\n this.abort = new AbortController();\n const since = Buffer.from(Y.encodeStateVector(this.doc)).toString('base64');\n const res = await fetch(this.url(`/stream?conn=${this.conn}&since=${encodeURIComponent(since)}`), {\n headers: { Authorization: await this.authHeader(), [APP_VERSION_HEADER]: appVersion },\n signal: this.abort.signal,\n });\n if (res.status === 426) throw await this.outdatedError(res);\n if (res.status === 401 || res.status === 403) throw new SyncAuthError(res.status);\n if (!res.ok || !res.body) throw new Error(`stream HTTP ${res.status}`);\n this.state = 'live';\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n for (;;) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const frames = buffer.split('\\n\\n');\n buffer = frames.pop() ?? '';\n for (const frame of frames) {\n const line = frame.split('\\n').find((l) => l.startsWith('data: '));\n if (!line) continue;\n try {\n const payload = JSON.parse(line.slice(6)) as { type: string; update: string };\n const update = new Uint8Array(Buffer.from(payload.update, 'base64'));\n Y.applyUpdate(this.doc, update, REMOTE_ORIGIN);\n } catch {\n // Ignore malformed frames (comments/pings never carry `data:`).\n continue;\n }\n // Posé après la première trame, qu'elle ait touché aux projets ou non :\n // tout ce qui arrive ensuite est du direct.\n this.initialDocApplied = true;\n this.markOpened();\n if (!this.seeded) {\n // The opening state is in: let it reach the disk first, so what\n // reconciliation reads there already includes it, then put local\n // state on top and send it.\n await this.settleApplying();\n if (this.stopped) return;\n await this.seed();\n await this.initialPush();\n this.needsPush = false;\n }\n }\n }\n }\n\n // ---- Project selection ------------------------------------------------\n\n /**\n * Whether a doc entity is one this machine holds.\n *\n * The org is the unit of transport — the doc carries every project a member\n * can see — but not the unit of storage: a machine materializes only the\n * projects its user opened. Without this filter, opening one project of a\n * fifty-project org would drop the other forty-nine onto this disk.\n *\n * Having a vault is what \"followed\" means. Opening a project creates its\n * directory, dropping it removes the directory, and nothing else has to be\n * kept in agreement with the disk.\n */\n private isTracked(name: CollectionName, id: string): boolean {\n if (name === 'projects') return this.tracked.has(id);\n\n const fields = readEntity(this.collection(name), id);\n if (!fields) return false;\n if (name === 'environments') {\n const projectId = fields['projectId'];\n return typeof projectId === 'string' && this.tracked.has(projectId);\n }\n // A service is tracked when a tracked project lists it.\n return this.trackedProjectOf(id) !== null;\n }\n\n /** The tracked project whose `serviceIds` list this service, per the doc. */\n private trackedProjectOf(serviceId: string): string | null {\n const projects = this.collection('projects');\n for (const projectId of this.tracked) {\n const serviceIds = readEntity(projects, projectId)?.['serviceIds'];\n if (Array.isArray(serviceIds) && serviceIds.includes(serviceId)) return projectId;\n }\n return null;\n }\n\n /** Re-read which projects of this org have a vault on this machine. */\n private async refreshTracked(): Promise<void> {\n const vaults = await listCloudVaults();\n this.tracked = new Set(\n vaults.filter((v) => v.orgId === this.link.orgId).map((v) => v.projectId),\n );\n }\n\n /**\n * Whether a *removal* announced by the doc concerns this machine.\n *\n * Deletions cannot go through `isTracked`: the entity is already gone from\n * the doc, so there is nothing left to read its `projectId` from. Projects\n * still answer from the selection; for their contents we lean on\n * `deleteLocally` being a no-op for anything this machine never pulled, which\n * is precisely the untracked case.\n */\n private isTrackedForDeletion(name: CollectionName, id: string): boolean {\n if (name === 'projects') return this.tracked.has(id);\n return true;\n }\n\n /**\n * Follow a project: give it a vault, then fill it from the doc.\n *\n * Idempotent on purpose. Widening a selection is not the only way a project\n * comes to be missing — a first pull can fail on a rejected session, or land\n * before the doc arrived — and re-opening the project has to be able to retry\n * it. Returns whether the doc actually held the project.\n */\n public async followProject(projectId: string): Promise<boolean> {\n const inDoc = readEntity(this.collection('projects'), projectId) !== null;\n // Asked for by couple: the same id can name a project of another org held\n // here too, and following would otherwise inspect that one's state.\n const existing = await projectStore.get({ id: projectId, orgId: this.link.orgId })\n ?? await projectStore.get({ id: projectId, orgId: null });\n // The same id already held as a local project: following it would give one\n // project two vaults, each overwriting the other's view of it. Refused\n // rather than merged — the two histories are not ours to reconcile.\n if (existing && !existing.orgId) {\n console.error(\n '[cloud-sync] project %s is already a local project here — not following it for org %s',\n projectId, this.link.orgId,\n );\n throw new ProjectHeldElsewhereError(projectId, null);\n }\n // Le même id déjà suivi pour une AUTRE organisation. Les deux copies portent\n // les mêmes ids de services, d'environnements et de conversations : les\n // tenir ensemble ferait écrire le contenu de l'une dans le coffre de\n // l'autre. Refusé, en nommant l'organisation qui le détient déjà — c'est\n // elle qu'il faut cesser de suivre pour prendre celle-ci.\n const heldBy = await projectStore.list().then((all) => all.find(\n (p) => p.id === projectId && p.orgId && p.orgId !== this.link.orgId,\n ));\n if (heldBy?.orgId) {\n throw new ProjectHeldElsewhereError(projectId, heldBy.orgId);\n }\n // A project just created here is not in the doc yet — it gets there through\n // reconciliation — but it is already ours to follow.\n const isLocal = existing?.orgId === this.link.orgId;\n if (!inDoc && !isLocal) return false;\n\n await mkdir(projectVaultRoot(this.link.orgId, projectId), { recursive: true });\n this.tracked.add(projectId);\n if (inDoc) await this.pullFromDoc([projectId]);\n else await this.reconcileLocalToDoc();\n return true;\n }\n\n /**\n * Stop following a project on this machine.\n *\n * Its vault goes with it — the directory *is* the selection — but the doc is\n * left untouched: the user stops following the project here, they do not ask\n * for it to be deleted for the whole organization.\n */\n public async unfollowProject(projectId: string): Promise<void> {\n this.tracked.delete(projectId);\n await projectStore.forgetLocally({ id: projectId, orgId: this.link.orgId });\n await rm(projectVaultRoot(this.link.orgId, projectId), { recursive: true, force: true })\n .catch(() => {});\n }\n\n /**\n * Materialize locally everything the doc holds for these projects.\n *\n * Contents land before their project, so that the moment the project becomes\n * local — and therefore \"owned\" by reconciliation — its services and\n * environments are already on disk. The guard covers the rest of the window,\n * including the saves this very method triggers.\n */\n private async pullFromDoc(projectIds: string[]): Promise<void> {\n this.pulling = true;\n try {\n for (const name of ['services', 'environments', 'projects'] as CollectionName[]) {\n const collection = this.collection(name);\n for (const id of Array.from(collection.keys())) {\n if (name === 'projects' ? !projectIds.includes(id) : !this.isTracked(name, id)) continue;\n const fields = readEntity(collection, id);\n if (fields) await this.upsertLocally(name, id, fields);\n }\n }\n } finally {\n this.pulling = false;\n }\n // Les contenus ont atterri avant leur projet — c'est voulu — donc dans le\n // coffre de lancement, faute de savoir encore à qui ils appartiennent. Le\n // projet est là maintenant : les remettre dans son coffre, ce qui les\n // retire du précédent. Sans ce passage ils y restaient, invisibles jusqu'au\n // redémarrage suivant, qui les relisait comme des contenus locaux orphelins —\n // services comme environnements.\n await serviceStore.relocateAll();\n await environmentStore.relocateAll();\n // Everything is on disk now, so reconciliation sees a coherent picture.\n await this.reconcileLocalToDoc();\n }\n\n // ---- Local ↔ Doc reconciliation --------------------------------------\n\n private async applyDocEventsToStore(\n name: CollectionName,\n events: Y.YEvent<Y.AbstractType<unknown>>[],\n isInitial = false,\n ): Promise<void> {\n const collection = this.collection(name);\n const deleted = new Set<string>();\n const affected = new Set<string>();\n // Kept apart from `affected`: an entity appearing is not the same event as\n // an entity changing, and only the first can mean \"a project was created\".\n const added = new Set<string>();\n for (const event of events) {\n if (event.target === collection) {\n for (const [key, change] of event.changes.keys) {\n if (change.action === 'delete') deleted.add(key);\n else {\n affected.add(key);\n if (change.action === 'add') added.add(key);\n }\n }\n } else {\n // A nested change (a field, an array element): the entity is the first\n // path segment.\n const topKey = event.path[0];\n if (typeof topKey === 'string') affected.add(topKey);\n }\n }\n\n // Still synchronous here — the observer's own call — so a reconciliation\n // already under way sees these ticks before it writes.\n for (const id of [...deleted, ...affected]) this.remoteTouch.set(`${name}:${id}`, ++this.remoteClock);\n\n // A deletion is applied for tracked entities only. `isTracked` reads the\n // doc, where the entity is already gone, so projects fall back to the\n // selection and contents to what we hold locally — never to \"unknown means\n // delete it\".\n for (const id of deleted) {\n if (!this.isTrackedForDeletion(name, id)) continue;\n await this.deleteLocally(name, id);\n }\n // A project created in the org after this machine caught up is followed on\n // its own. Doing so during the opening state would materialize the whole\n // org, which is exactly what per-project vaults exist to avoid.\n // Only on creation. An edit to a project this machine deliberately dropped\n // must not bring it back — the user stopped following it, a colleague\n // renaming it does not undo that.\n if (name === 'projects' && !isInitial) {\n for (const id of added) {\n if (deleted.has(id) || this.tracked.has(id)) continue;\n // Recréé par une restauration du cloud, pas créé : rien ne dit que ce\n // poste le voulait. Il reste proposé dans la liste des projets.\n if (this.doc.getMap(RESTORED_PROJECTS).has(id)) continue;\n try {\n await this.followProject(id);\n } catch (err) {\n // Un id que cette machine tient déjà ailleurs (projet local, ou autre\n // organisation). C'est un refus légitime quand quelqu'un demande de\n // suivre ce projet ; ici personne n'a rien demandé — le projet est\n // simplement apparu chez un collègue. Le laisser remonter couperait\n // l'application du reste de l'évènement et finirait en rejet non\n // capturé, puisque l'observateur Yjs n'attend pas cette promesse.\n if (!(err instanceof ProjectHeldElsewhereError)) throw err;\n console.warn(\n '[cloud-sync] project %s appeared in org %s but is already held here — not followed',\n id, this.link.orgId,\n );\n }\n }\n }\n\n for (const id of affected) {\n if (deleted.has(id)) continue;\n if (!this.isTracked(name, id)) continue;\n const fields = readEntity(collection, id);\n if (!fields) continue;\n await this.upsertLocally(name, id, fields);\n }\n }\n\n /**\n * Nombre d'applications distantes de parseurs en cours.\n *\n * La réconciliation lit le coffre et supprime du document ce qu'elle n'y\n * trouve pas ; déclenchée par un service enregistré au même instant, elle\n * lirait un coffre où le parseur qui arrive n'est pas encore écrit — et\n * l'effacerait pour toute l'organisation. Un compteur plutôt qu'un booléen :\n * plusieurs évènements peuvent se chevaucher, et le premier terminé ne doit\n * pas rouvrir la porte pour les autres.\n */\n private applyingParsers = 0;\n\n /**\n * Porter au disque les parseurs que le document vient de changer.\n *\n * Une suppression est appliquée telle quelle, sans l'équivalent du garde qui\n * protège les contenus d'un projet non téléchargé : chaque membre tient le\n * jeu complet de l'organisation, donc un parseur retiré du document l'a bien\n * été pour tout le monde.\n */\n private async applyParserEventsToStore(\n events: Y.YEvent<Y.AbstractType<unknown>>[],\n ): Promise<void> {\n const deleted = new Set<string>();\n const affected = new Set<string>();\n for (const event of events) {\n if (event.target === this.logParsers) {\n for (const [key, change] of event.changes.keys) {\n if (change.action === 'delete') deleted.add(key);\n else affected.add(key);\n }\n } else {\n const topKey = event.path[0];\n if (typeof topKey === 'string') affected.add(topKey);\n }\n }\n\n this.applyingParsers += 1;\n try {\n for (const id of deleted) {\n await logParserStore.applyRemoteDelete(id, this.link.orgId);\n }\n for (const id of affected) {\n if (deleted.has(id)) continue;\n const fields = readEntity(this.logParsers, id);\n if (!fields) continue;\n await logParserStore.applyRemoteUpsert(id, fields, this.link.orgId);\n }\n } finally {\n this.applyingParsers -= 1;\n }\n }\n\n private async upsertLocally(name: CollectionName, id: string, fields: unknown): Promise<void> {\n // L'organisation est passée explicitement : les secrets qui arrivent sont\n // chiffrés par SA clé, et le coffre de destination ne peut pas encore être\n // déduit — les contenus atterrissent avant leur projet, exprès, donc rien\n // ne relie encore ce service à une organisation. Sans elle, ils seraient\n // ouverts avec la clé machine, échoueraient en silence, et un chiffré\n // pourrait repartir chiffré une seconde fois.\n if (name === 'services') {\n // Son projet est lu dans le doc : il peut ne pas être encore descendu, et\n // le service doit tout de même rejoindre son coffre, pas celui de lancement.\n await serviceStore.applyRemoteUpsert(id, fields, this.link.orgId, this.trackedProjectOf(id) ?? undefined);\n return;\n }\n if (name === 'environments') {\n await environmentStore.applyRemoteUpsert(id, fields, this.link.orgId);\n return;\n }\n // The org is decided by the connection that carried the project, not by the\n // field: a doc claiming `orgId: null` would otherwise turn a synced project\n // into a local one — and have it overwrite the launch directory's own.\n const result = await projectStore.applyRemoteUpsert(id, {\n ...(fields as object),\n orgId: this.link.orgId,\n });\n // A project created from a remote peer has no local environment yet;\n // bootstrap a default immutable \"local\" env so the UI is usable. Its own\n // environments may still be in flight, hence the check inside.\n if (result?.created) await this.bootstrapEnvironment(id);\n }\n\n private async deleteLocally(name: CollectionName, id: string): Promise<void> {\n if (name === 'services') { await serviceStore.applyRemoteDelete(id); return; }\n if (name === 'environments') { await environmentStore.applyRemoteDelete(id); return; }\n\n // Un projet que le cloud a refusé de stocker n'a pas été supprimé par\n // l'organisation : il n'a jamais été accepté. Ses fichiers restent ici —\n // les effacer perdrait un travail que personne n'a demandé à jeter — et la\n // machine cesse simplement de le pousser.\n const refusal = this.refusalFor(id);\n if (refusal) {\n console.error(\n '[cloud-sync] project %s refused by the cloud for org %s (%s) — kept on disk, no longer pushed',\n id, this.link.orgId, refusal,\n );\n this.tracked.delete(id);\n return;\n }\n await projectStore.applyRemoteDelete({ id, orgId: this.link.orgId });\n }\n\n /** Le motif du refus du cloud pour ce projet, s'il en a écrit un. */\n private refusalFor(projectId: string): string | null {\n const entry = this.doc.getMap('projectRefusals').get(projectId);\n if (!entry || typeof entry !== 'object') return null;\n const reason = (entry as { reason?: unknown }).reason;\n return typeof reason === 'string' ? reason : 'refused';\n }\n\n private async bootstrapEnvironment(projectId: string): Promise<void> {\n try {\n const existing = await environmentStore.getByProjectId(projectId).catch(() => []);\n if (existing.length > 0) return;\n const localEnv = await environmentStore.create({\n projectId,\n name: 'local',\n description: 'Default local environment (immutable)',\n parentIds: [],\n immutable: true,\n }, this.link.orgId);\n await projectStore.addEnvironment({ id: projectId, orgId: this.link.orgId }, localEnv.id);\n } catch (err) {\n console.error('[cloud-sync] env bootstrap failed for project %s:', projectId, (err as Error).message);\n }\n }\n\n /**\n * Mirror the org's local on-disk state into the doc.\n *\n * Membership follows the hierarchy: the org's projects, then their services\n * and environments.\n *\n * Deliberately additive for projects: a project that vanished locally is NOT\n * removed from the doc. Deleting files on one machine — or simply not having\n * pulled a project — must never wipe it for the whole organization. Removing a\n * project from the org is an explicit, admin-only action taken on the cloud,\n * which reaches every member as a remote deletion.\n *\n * Services and environments are different: they are the *contents* of a\n * project, so dropping one locally is an edit to that project and does\n * propagate — otherwise a service could never be removed.\n */\n private async reconcileLocalToDoc(): Promise<void> {\n if (this.stopped || this.pulling || !this.seeded) return;\n const readAt = this.remoteClock;\n const touchedSinceRead = (name: CollectionName, id: string): boolean =>\n (this.remoteTouch.get(`${name}:${id}`) ?? 0) > readAt;\n // Un projet que le cloud a refusé n'est pas repoussé : il reviendrait se\n // faire retirer à chaque réconciliation, indéfiniment.\n const projects = (await projectStore.listDiskFormByOrg(this.link.orgId))\n .filter((p) => !this.refusalFor(p.id));\n const projectIds = projects.map((p) => p.id);\n const serviceIds = [...new Set(projects.flatMap((p) => p.serviceIds ?? []))];\n const [services, environments] = await Promise.all([\n serviceStore.listSanitizedByIds(serviceIds),\n environmentStore.listEncryptedByProjectIds(projectIds),\n ]);\n if (this.stopped) return;\n\n // Les natifs ne partent pas : chaque poste a déjà les siens, et une copie\n // dans le document vieillirait à côté de l'original (voir `isShareable`).\n const parsers = (await logParserStore.list(this.link.orgId)).filter(isShareableParser);\n if (this.stopped) return;\n\n const local: Record<CollectionName, { id: string }[]> = { projects, services, environments };\n // Contents of projects this machine actually holds: anything belonging to a\n // project we never pulled is none of our business to delete.\n const ownedProjectIds = new Set(projectIds);\n\n this.doc.transact(() => {\n for (const name of COLLECTIONS) {\n const collection = this.collection(name);\n const entities = local[name];\n const ids = new Set(entities.map((e) => e.id));\n for (const entity of entities) {\n if (touchedSinceRead(name, entity.id)) continue;\n writeEntity(\n collection, entity.id,\n name === 'projects' ? this.keepUnknownLinks(entity as Project) : entity,\n );\n }\n if (name === 'projects') continue;\n // Jamais de suppression déduite d'une absence : ce qui manque ici peut\n // n'avoir pas été lu (coffre écarté ou scellé, copie pas encore\n // descendue). Seul un retrait fait sur cette machine part au cloud.\n for (const id of Array.from(collection.keys())) {\n if (ids.has(id) || touchedSinceRead(name, id)) continue;\n if (!isLocallyRemoved(name, id)) continue;\n if (this.belongsToOwnedProject(name, id, ownedProjectIds)) collection.delete(id);\n clearLocalRemoval(name, id);\n }\n }\n\n // Les parseurs se réconcilient dans les deux sens sans réserve : cette\n // machine tient le jeu complet de l'organisation, donc un parseur absent\n // ici a été supprimé, pas simplement jamais téléchargé.\n const parserIds = new Set(parsers.map((p) => p.id));\n for (const parser of parsers) writeEntity(this.logParsers, parser.id, parser);\n if (this.applyingParsers === 0) {\n for (const id of Array.from(this.logParsers.keys())) {\n if (parserIds.has(id) || !isLocallyRemoved('logParsers', id)) continue;\n this.logParsers.delete(id);\n clearLocalRemoval('logParsers', id);\n }\n }\n }, LOCAL_ORIGIN);\n }\n\n /**\n * Le projet local tel qu'il doit partir : ses listes gardent les ids que le\n * document connaît et pas cette machine, sauf ceux qu'elle a détachés.\n *\n * Un projet local en retard (coffre relu tard, autre version) repoussait\n * sinon d'anciens `serviceIds` : le service récent sortait du projet pour\n * toute l'organisation, et sa suppression suivait.\n */\n private keepUnknownLinks(project: Project): Project {\n const inDoc = readEntity(this.collection('projects'), project.id);\n const merged = { ...project };\n for (const field of ['serviceIds', 'environmentIds'] as const) {\n const local = project[field] ?? [];\n const remote = inDoc?.[field];\n const extra = Array.isArray(remote)\n ? remote.filter((id): id is string =>\n typeof id === 'string' && !local.includes(id) && !isDetached(project.id, field, id))\n : [];\n merged[field] = [...local, ...extra];\n clearDetached(project.id, field);\n }\n return merged;\n }\n\n /**\n * Whether a doc entity belongs to a project this machine holds — i.e. whether\n * its absence locally is a real removal rather than a project we never pulled.\n */\n private belongsToOwnedProject(\n name: CollectionName,\n id: string,\n ownedProjectIds: Set<string>,\n ): boolean {\n const fields = readEntity(this.collection(name), id);\n if (!fields) return false;\n if (name === 'environments') {\n const projectId = fields['projectId'];\n return typeof projectId === 'string' && ownedProjectIds.has(projectId);\n }\n // A service belongs to whichever projects list it in `serviceIds`.\n const projects = this.collection('projects');\n for (const projectId of projects.keys()) {\n const project = readEntity(projects, projectId);\n const serviceIds = project?.['serviceIds'];\n if (!Array.isArray(serviceIds) || !serviceIds.includes(id)) continue;\n if (!ownedProjectIds.has(projectId)) return false; // still used elsewhere\n }\n return true;\n }\n}\n\n/** Manages one sync connection per linked organization for the whole server. */\nclass CloudSyncBridge {\n private connections = new Map<string, OrgSyncConnection>();\n /**\n * Orgs whose key this machine does not have.\n *\n * Tenues à part : la connexion n'est jamais ouverte, donc il n'y a rien à qui\n * demander son état — et une organisation qui ne peut pas synchroniser tant\n * qu'un humain n'a pas fourni de clé ne doit pas se lire « arrêtée ».\n */\n private keyMismatch = new Set<string>();\n private started = false;\n\n /**\n * Start syncing every organization this machine holds a project of.\n *\n * The scope is read from the disk (see `org-sync-scope.ts`) rather than from\n * a list of links: opening a project is what makes its org worth syncing, and\n * dropping the last one is what ends it.\n */\n async start(): Promise<void> {\n if (this.started) return;\n this.started = true;\n let links: CloudSyncLink[] = [];\n try {\n links = await orgsToSync();\n } catch (err) {\n console.error('[cloud-sync] could not read which organizations to sync:', (err as Error).message);\n return;\n }\n await this.migrateMachineParsers(links);\n for (const link of links) await this.connect(link);\n // Compté sur les connexions réellement ouvertes, pas sur les liens trouvés :\n // une organisation écartée (clé absente, verrou tenu ailleurs) annonçait une\n // synchro qui n'existait pas, juste après la ligne d'erreur qui le disait.\n const connected = this.connections.size;\n if (links.length > 0) {\n const skipped = links.length - connected;\n console.log(\n `[cloud-sync] syncing ${connected}/${links.length} organization(s)`\n + (skipped > 0 ? ` — ${skipped} not syncing (see the errors above)` : ''),\n );\n }\n }\n\n /**\n * Reconnect every link whose session had been rejected. Called after a cloud\n * sign-in, so sync resumes without restarting the server.\n */\n async resumeAll(): Promise<void> {\n const paused = Array.from(this.connections.values())\n .filter((c) => c.getState() === 'unauthenticated')\n .map((c) => c.getLink());\n for (const link of paused) await this.connect(link);\n }\n\n /**\n * Tout reconnecter, quel que soit l'état où chaque organisation s'était\n * arrêtée.\n *\n * `resumeAll` ne reprend que les sessions rejetées ; après un changement de\n * clé, ce sont justement les organisations écartées pour clé différente qu'il\n * faut retenter — et elles n'ont pas de connexion à reprendre, seulement un\n * lien sur le disque.\n */\n async restartAll(): Promise<void> {\n this.keyMismatch.clear();\n let links: CloudSyncLink[] = [];\n try {\n links = await orgsToSync();\n } catch (err) {\n console.error('[cloud-sync] could not read which organizations to sync:', (err as Error).message);\n return;\n }\n await this.migrateMachineParsers(links);\n for (const link of links) await this.connect(link);\n }\n\n /**\n * Déplacer les parseurs du poste dans les organisations de cette machine.\n *\n * Avant d'ouvrir les connexions, pour que la première réconciliation parte\n * d'un coffre déjà complet — sinon les parseurs partiraient au document au\n * coup d'après, ce qui marche mais laisse une fenêtre où l'équipe voit une\n * liste vide.\n *\n * Fait ici plutôt que dans chaque connexion : la liste du poste est vidée à\n * la fin, et deux connexions qui migreraient en parallèle se la\n * disputeraient — la seconde trouverait une machine déjà vide.\n */\n private async migrateMachineParsers(links: CloudSyncLink[]): Promise<void> {\n try {\n await logParserStore.migrateMachineParsersInto(links.map((l) => l.orgId));\n } catch (err) {\n // Un parseur non remonté se rattrape à la prochaine ouverture ; il ne\n // vaut pas d'empêcher la synchronisation de démarrer.\n console.error('[cloud-sync] could not move machine parsers into organizations:', (err as Error).message);\n }\n }\n\n /** Per-org sync state, for the UI. */\n states(): SyncStateReport[] {\n const live = Array.from(this.connections.entries()).map(([orgId, conn]) => ({\n orgId,\n state: conn.getState(),\n lastIncompatibleVersion: conn.getLastIncompatibleVersion(),\n }));\n // Sans cette entrée, une organisation dont la clé ne correspond pas se\n // lisait « arrêtée », et l'utilisateur n'avait qu'une ligne de journal —\n // vue par personne — pour l'apprendre.\n const mismatched = Array.from(this.keyMismatch)\n .filter((orgId) => !this.connections.has(orgId))\n .map((orgId) => ({\n orgId,\n state: 'key-mismatch' as SyncState,\n lastIncompatibleVersion: null,\n }));\n return [...live, ...mismatched];\n }\n\n /**\n * Follow one project of an org on this machine, pulling it now.\n *\n * Returns false when the org is not connected or the doc does not hold the\n * project — both mean \"not on this machine yet\", and the caller reports the\n * sync state rather than a bare timeout.\n */\n public async followProject(orgId: string, projectId: string): Promise<boolean> {\n const conn = this.connections.get(orgId);\n if (!conn) return false;\n return conn.followProject(projectId);\n }\n\n /** Stop following one project of an org on this machine. */\n public async unfollowProject(orgId: string, projectId: string): Promise<void> {\n await this.connections.get(orgId)?.unfollowProject(projectId);\n }\n\n /**\n * Begin (or restart) syncing a single organization.\n *\n * Takes the org's lock first. An org's vaults are shared by every Runeya on\n * this machine, so a second instance syncing the same org would write the\n * same files from its own copy of the doc — silently overwriting the first.\n * Refusing to sync is the safe answer: the instance keeps running, that org\n * simply does not sync here.\n */\n async connect(link: CloudSyncLink): Promise<void> {\n this.disconnect(link.orgId);\n\n // Nobody re-affirms this org on boot — its vault on disk is the whole\n // decision — so the key that was right when the project was pulled has to\n // be proven right again before anything is received under it.\n try {\n await reconcileOrgCanary(link.orgId);\n } catch (err) {\n if (err instanceof OrgKeyMismatchError) {\n console.error('[cloud-sync] org %s: %s', link.orgId, err.message);\n this.keyMismatch.add(link.orgId);\n return;\n }\n // Anything else — offline, signed out, no canary yet — is transient and\n // must not cost the org its sync: the transport already retries, and its\n // own auth failures are what pause it.\n console.warn(\n '[cloud-sync] org %s: could not check the organization key (%s) — syncing anyway.',\n // Le message porte désormais le code, destiné à l'interface ; le détail\n // lisible reste sur l'erreur, et c'est lui qui a sa place dans un log.\n link.orgId, (err as { detail?: string; message: string }).detail ?? (err as Error).message,\n );\n }\n // Le contrôle vient de passer : si la clé manquait, ce n'est plus le cas.\n this.keyMismatch.delete(link.orgId);\n\n // Rien n'interdit plus qu'une autre Runeya de ce poste synchronise la même\n // organisation. Un verrou l'empêchait, au motif que deux instances\n // écriraient les mêmes fichiers sans que la perdante l'apprenne — mais elle\n // l'apprend : les stores relisent leur coffre dès qu'il a bougé, et le\n // document leur porte ce que l'autre pousse, exactement comme entre deux\n // machines. Le verrou ne protégeait plus rien et privait de synchronisation\n // l'instance qui n'avait pas démarré la première.\n const conn = new OrgSyncConnection(link);\n this.connections.set(link.orgId, conn);\n try {\n await conn.start();\n } catch (err) {\n console.error('[cloud-sync] failed to start org %s:', link.orgId, (err as Error).message);\n }\n }\n\n disconnect(orgId: string): void {\n const existing = this.connections.get(orgId);\n if (existing) {\n void existing.stop();\n this.connections.delete(orgId);\n }\n }\n\n /**\n * Attendre que le document d'une organisation tienne l'état du cloud.\n *\n * Suivre un projet juste après avoir ouvert la connexion ne trouvait rien : la\n * trame d'ouverture n'était pas arrivée, et l'app concluait à un échec. Rend la\n * main au plus tard après `timeoutMs` — l'appelant lit alors l'état.\n */\n async whenOpened(orgId: string, timeoutMs: number): Promise<void> {\n const conn = this.connections.get(orgId);\n if (!conn) return;\n let timer: ReturnType<typeof setTimeout> | undefined;\n await Promise.race([\n conn.opened,\n new Promise<void>((resolve) => { timer = setTimeout(resolve, timeoutMs); }),\n ]);\n clearTimeout(timer);\n }\n\n /** Stops at once; the promise only says when pending cache writes have landed. */\n stopAll(): Promise<void> {\n const stopping = [...this.connections.values()].map((conn) => conn.stop());\n this.connections.clear();\n this.keyMismatch.clear();\n return Promise.all(stopping).then(() => {});\n }\n}\n\nexport const cloudSyncBridge = new CloudSyncBridge();\n","import { readFileSync, renameSync, rmSync, writeFileSync, mkdirSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport * as Y from 'yjs';\nimport { orgVaultRoot } from './vault-resolver.js';\nimport { atomicWriteSecure } from './run-store-utils.js';\n\n/**\n * Le document de synchronisation d'une organisation, gardé d'un lancement à\n * l'autre.\n *\n * Sans lui, chaque démarrage repartait d'un document vide et y écrivait le\n * disque avant d'avoir reçu l'historique du cloud : Yjs tenait alors ces\n * écritures pour concurrentes de tout ce que les autres avaient déjà écrit, et\n * les départageait par identifiant de client — une modification faite hors\n * ligne pouvait perdre, et un service supprimé plus tôt dans le document\n * effaçait celui que le disque venait de rendre. Rechargé, l'historique connu\n * précède ce que le disque y ajoute, et ce qui est ajouté l'emporte.\n */\nconst FILE = 'sync-doc.bin';\n\nfunction cachePath(orgId: string): string {\n return join(orgVaultRoot(orgId), FILE);\n}\n\nexport async function readSyncDoc(orgId: string): Promise<Uint8Array | null> {\n try {\n return new Uint8Array(await readFile(cachePath(orgId)));\n } catch {\n return null;\n }\n}\n\n/**\n * Fusionner plutôt que remplacer : deux Runeya d'un même poste partagent le\n * fichier, et chacune y apporte ce que l'autre n'a peut-être pas encore reçu.\n */\nfunction mergeWith(existing: Uint8Array | null, state: Uint8Array): Uint8Array {\n if (!existing) return state;\n try {\n return Y.mergeUpdates([existing, state]);\n } catch {\n // Un fichier illisible ne vaut rien à garder : l'état en mémoire le remplace.\n return state;\n }\n}\n\nexport async function writeSyncDoc(orgId: string, state: Uint8Array): Promise<void> {\n await atomicWriteSecure(cachePath(orgId), mergeWith(await readSyncDoc(orgId), state));\n}\n\n/** À l'arrêt : un processus qui se termine n'attend pas les promesses. */\nexport function writeSyncDocSync(orgId: string, state: Uint8Array): void {\n const path = cachePath(orgId);\n let existing: Uint8Array | null = null;\n try {\n existing = new Uint8Array(readFileSync(path));\n } catch {\n // Pas encore de document gardé.\n }\n mkdirSync(dirname(path), { recursive: true });\n const tmp = `${path}.${process.pid}.${randomUUID()}.tmp`;\n try {\n writeFileSync(tmp, mergeWith(existing, state), { mode: 0o600 });\n renameSync(tmp, path);\n } catch (err) {\n rmSync(tmp, { force: true });\n throw err;\n }\n}\n","import { readdir, readFile, writeFile, mkdir, copyFile, rename, stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';\nimport { decryptValueWith, encryptValueWith, isEncryptedValue } from './crypto-helpers.js';\nimport { readEncryptedKey } from './master-password.js';\nimport { getEncryptionKey, clearVaultLock } from '../utils/encryption-key.js';\nimport { installOrgKey } from './org-keys.js';\nimport { environmentStore } from './environment-store.js';\nimport { serviceStore } from './service-store.js';\nimport { conversationStore } from './conversation-store.js';\nimport { apiKeyStore } from './api-key-store.js';\nimport { keyRoot, orgVaultRoot, listCloudVaults } from './vault-resolver.js';\n\n/**\n * Adopter la clé d'une organisation.\n *\n * Distinct de la réinitialisation de son canari, qui la fait repartir sous la\n * clé d'ici en laissant illisible tout ce qui a déjà été chiffré sous l'autre.\n * Ici c'est l'inverse : c'est nous qui rejoignons la clé — ce qui rend lisible\n * ce qui existait déjà sous elle, et c'est la seule des deux voies qui répare\n * vraiment.\n *\n * Depuis que chaque organisation a sa clé, l'opération est bornée à son coffre\n * et à ceux de ses projets : le reste du poste ne bouge pas.\n */\n\nconst ALGORITHM = 'aes-256-gcm';\n\n/** Un secret d'agent, chiffré à part : un triplet hex, pas la forme `iv:tag:ct`. */\ninterface AgentTriplet {\n encrypted: string;\n iv: string;\n authTag: string;\n}\n\n/**\n * Reconnaît le triplet des agents.\n *\n * `agents.json` n'utilise pas `encryptValue` mais son propre format, hérité :\n * trois champs hex côte à côte. `isEncryptedValue` ne le voit donc pas, et une\n * conversion qui ne regarderait que les chaînes laisserait chaque passphrase\n * d'agent chiffrée sous l'ancienne clé — muette, sans rien pour le signaler.\n */\nfunction isAgentTriplet(value: Record<string, unknown>): boolean {\n const hex = (v: unknown): boolean => typeof v === 'string' && /^[0-9a-f]+$/i.test(v);\n return hex(value['encrypted']) && hex(value['iv']) && hex(value['authTag']);\n}\n\nfunction decryptTriplet(key: Buffer, t: AgentTriplet): string {\n const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(t.iv, 'hex'), { authTagLength: 16 });\n decipher.setAuthTag(Buffer.from(t.authTag, 'hex'));\n return decipher.update(t.encrypted, 'hex', 'utf-8') + decipher.final('utf-8');\n}\n\nfunction encryptTriplet(key: Buffer, plaintext: string): AgentTriplet {\n const iv = randomBytes(16);\n const cipher = createCipheriv(ALGORITHM, key, iv);\n const encrypted = cipher.update(plaintext, 'utf-8', 'hex') + cipher.final('hex');\n return { encrypted, iv: iv.toString('hex'), authTag: cipher.getAuthTag().toString('hex') };\n}\n\n/**\n * Re-chiffre récursivement tout ce qu'une valeur JSON porte de chiffré.\n *\n * Les valeurs sont trouvées par leur forme, jamais par un schéma : c'est ce qui\n * fait qu'un champ ajouté par une version ultérieure est converti lui aussi.\n * Ce qui ne s'ouvre pas sous l'ancienne clé est laissé tel quel — re-chiffrer\n * du charabia détruirait la seule copie de ce qu'il était.\n */\nexport function rekeyJsonValue(\n value: unknown,\n from: Buffer,\n to: Buffer,\n counter: { n: number },\n): unknown {\n if (typeof value === 'string') {\n if (!isEncryptedValue(value)) return value;\n let plaintext: string;\n try {\n plaintext = decryptValueWith(from, value);\n } catch {\n return value;\n }\n counter.n += 1;\n return encryptValueWith(to, plaintext);\n }\n if (Array.isArray(value)) return value.map((v) => rekeyJsonValue(v, from, to, counter));\n if (value && typeof value === 'object') {\n const record = value as Record<string, unknown>;\n if (isAgentTriplet(record)) {\n try {\n const plaintext = decryptTriplet(from, record as unknown as AgentTriplet);\n counter.n += 1;\n return { ...record, ...encryptTriplet(to, plaintext) };\n } catch {\n return record;\n }\n }\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(record)) out[k] = rekeyJsonValue(v, from, to, counter);\n return out;\n }\n return value;\n}\n\nexport interface KeyAdoptionReport {\n /** Chaque fichier converti, avec le nombre de secrets qu'il portait. */\n converted: { file: string; values: number }[];\n /** Les sauvegardes déposées avant écriture, une par coffre touché. */\n backups: string[];\n}\n\n/**\n * Les coffres d'une organisation : le sien, et celui de chacun de ses projets.\n *\n * Rien d'autre. C'est la différence que fait une clé par organisation :\n * adopter celle d'une organisation ne demande plus de re-chiffrer le poste\n * entier — les autres organisations, et la machine, gardent la leur.\n */\nasync function rootsOfOrg(orgId: string): Promise<string[]> {\n const roots = new Set<string>([orgVaultRoot(orgId)]);\n for (const vault of await listCloudVaults()) {\n if (vault.orgId === orgId) roots.add(vault.root);\n }\n return Array.from(roots);\n}\n\n/** Les JSON directement dans un coffre — jamais ses sauvegardes ni ses sous-dossiers. */\nasync function jsonFilesIn(root: string): Promise<string[]> {\n try {\n const entries = await readdir(root, { withFileTypes: true });\n return entries.filter((e) => e.isFile() && e.name.endsWith('.json')).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nasync function exists(path: string): Promise<boolean> {\n return stat(path).then(() => true, () => false);\n}\n\n/**\n * Faire adopter une autre clé à UNE organisation.\n *\n * Tout est lu et converti **en mémoire d'abord**, et rien n'est écrit avant que\n * la dernière conversion ait réussi. Une panne au milieu laisserait sinon\n * certains coffres sous la nouvelle clé et d'autres sous l'ancienne — un état\n * qu'aucune clé n'ouvre en entier, et dont on ne sait pas revenir.\n *\n * `masterPassword` est exigé parce que c'est lui qui scelle le fichier de clé\n * de l'organisation : l'adopter sans pouvoir l'écrire donnerait un coffre que\n * plus rien n'ouvrirait au redémarrage.\n */\nexport async function adoptOrgKey(\n orgId: string,\n newKey: Buffer,\n masterPassword: string,\n now: Date,\n): Promise<KeyAdoptionReport> {\n const currentKey = getEncryptionKey(orgId);\n if (!currentKey) {\n throw new Error(\"La clé actuelle de cette organisation n'est pas chargée.\");\n }\n if (newKey.equals(currentKey)) {\n // Un code : l'interface le traduit, et sait dire que rien n'est à faire.\n throw new Error('ORG_KEY_ALREADY_CURRENT');\n }\n // Le mot de passe doit ouvrir le fichier de clé du poste : c'est lui qui\n // scellera la nouvelle clé, et on ne réécrit pas un sésame sur la foi d'une\n // saisie non vérifiée.\n const machineRootDir = await keyRoot();\n await readEncryptedKey(machineRootDir, masterPassword);\n\n // 1. Lire et convertir, sans rien écrire.\n const pending: { path: string; content: string; values: number }[] = [];\n const touchedRoots = new Set<string>();\n for (const vaultRoot of await rootsOfOrg(orgId)) {\n for (const name of await jsonFilesIn(vaultRoot)) {\n const path = join(vaultRoot, name);\n let parsed: unknown;\n try {\n parsed = JSON.parse(await readFile(path, 'utf-8'));\n } catch {\n // Pas du JSON malgré l'extension : rien de nous à convertir.\n continue;\n }\n const counter = { n: 0 };\n const converted = rekeyJsonValue(parsed, currentKey, newKey, counter);\n if (counter.n === 0) continue;\n pending.push({ path, content: JSON.stringify(converted, null, 2), values: counter.n });\n touchedRoots.add(vaultRoot);\n }\n }\n\n // 2. Sauvegarder chaque coffre touché, entièrement, avant la première écriture.\n const stamp = now.toISOString().replace(/[:.]/g, '-').substring(0, 19);\n const backups: string[] = [];\n for (const vaultRoot of touchedRoots) {\n const backupDir = join(vaultRoot, `backup-key-${stamp}`);\n await mkdir(backupDir, { recursive: true });\n for (const name of await jsonFilesIn(vaultRoot)) {\n await copyFile(join(vaultRoot, name), join(backupDir, name));\n }\n // La clé d'origine part avec : sans elle, la sauvegarde ne s'ouvrirait plus.\n for (const name of ['.encryption.key.enc', '.runeya-verify']) {\n if (await exists(join(vaultRoot, name))) {\n await copyFile(join(vaultRoot, name), join(backupDir, name));\n }\n }\n backups.push(backupDir);\n }\n\n // 3. Écrire, atomiquement comme partout ailleurs dans les coffres.\n for (const item of pending) {\n const tmp = item.path + '.tmp';\n await writeFile(tmp, item.content, 'utf-8');\n await rename(tmp, item.path);\n }\n\n // 4. La clé de l'organisation en dernier : tant qu'elle n'a pas basculé, les\n // données converties sont inaccessibles, et c'est le bon sens de l'échec.\n await installOrgKey(orgId, newKey, masterPassword);\n clearVaultLock(orgId);\n\n // 5. Les stores ont lu le disque d'avant : leur mémoire décrit un coffre qui\n // n'existe plus. Sans cet oubli, l'interface continuerait d'annoncer des\n // données illisibles alors qu'elles viennent d'être réparées — et, plus\n // grave, la première sauvegarde réécrirait l'ancien chiffré par-dessus le\n // nouveau, défaisant en silence ce que les étapes 1 à 4 ont fait.\n environmentStore.resetCache();\n serviceStore.resetCache();\n conversationStore.resetCache();\n apiKeyStore.resetCache();\n\n return { converted: pending.map(({ path, values }) => ({ file: path, values })), backups };\n}\n","import { readdir, stat } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { isAbsolute, join, resolve, dirname, basename } from 'node:path';\nimport { z } from 'zod';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { holdsRuneyaProject, projectPathStore } from '../../services/project-path-store.js';\nimport { resolveWorkspaceCwd } from '../../services/workspace-cwd.js';\n\n/**\n * Directory browsing, for choosing where a cloud project lives on this machine.\n *\n * The browser cannot produce an absolute path — `showDirectoryPicker` yields an\n * opaque handle and `webkitdirectory` only relative names — so the machine has\n * to offer the tree itself.\n *\n * Deliberately narrow: directories only, never file contents, never file names.\n * Listing a tree is already more than the rest of the API exposes, so it gives\n * away as little as it can while still being usable. It stays behind\n * `protectedProcedure` like everything else, and the server only ever binds to\n * localhost.\n */\n\n/** Entries returned for one directory. Enough for deep trees, bounded for /nix and friends. */\nconst MAX_ENTRIES = 500;\n\nconst PATH_SCHEMA = z.string().min(1).max(4096);\n\nexport interface DirectoryEntry {\n name: string;\n path: string;\n /** A directory already holding a Runeya project cannot receive another one. */\n hasRuneyaProject: boolean;\n}\n\n/** Reject anything that is not a plain absolute path before touching the disk. */\nfunction safeResolve(input: string): string {\n if (input.includes('\\0')) throw new Error('Chemin invalide');\n const expanded = input.startsWith('~') ? join(homedir(), input.slice(1)) : input;\n if (!isAbsolute(expanded)) throw new Error('Le chemin doit être absolu');\n return resolve(expanded);\n}\n\nexport const filesystemRouter = router({\n /** Where a picker should open when the user has chosen nothing yet. */\n suggestedRoots: protectedProcedure.query(async () => {\n const roots = [\n { label: 'home', path: homedir() },\n // The launch directory, taken from the vault rather than the process.\n { label: 'cwd', path: await resolveWorkspaceCwd({}) },\n ];\n // De-duplicated: launching from home would otherwise offer the same row twice.\n const seen = new Set<string>();\n return roots.filter((r) => !seen.has(r.path) && seen.add(r.path));\n }),\n\n /**\n * The sub-directories of one directory.\n *\n * Hidden entries are skipped: they are noise for choosing a workspace, and\n * `.runeya` itself would invite placing a project inside another's data.\n */\n listDirectories: protectedProcedure\n .input(z.object({ path: PATH_SCHEMA }))\n .query(async ({ input }) => {\n const dir = safeResolve(input.path);\n\n const info = await stat(dir).catch(() => null);\n if (!info?.isDirectory()) {\n throw new Error(`Ce n'est pas un répertoire : ${dir}`);\n }\n\n let names: string[];\n try {\n names = (await readdir(dir, { withFileTypes: true }))\n .filter((e) => e.isDirectory() && !e.name.startsWith('.'))\n .map((e) => e.name)\n .sort((a, b) => a.localeCompare(b));\n } catch {\n throw new Error(`Répertoire illisible : ${dir}`);\n }\n\n const truncated = names.length > MAX_ENTRIES;\n const entries: DirectoryEntry[] = [];\n for (const name of names.slice(0, MAX_ENTRIES)) {\n const path = join(dir, name);\n entries.push({ name, path, hasRuneyaProject: await holdsRuneyaProject(path) });\n }\n\n return {\n path: dir,\n // Null at the filesystem root, which is what stops \"up\" from looping.\n parent: dirname(dir) === dir ? null : dirname(dir),\n name: basename(dir) || dir,\n entries,\n truncated,\n hasRuneyaProject: await holdsRuneyaProject(dir),\n };\n }),\n\n /**\n * Whether a directory can receive this project.\n *\n * Two projects in one directory is what makes services run against the wrong\n * code, so a directory that already holds one is refused outright.\n */\n checkProjectTarget: protectedProcedure\n .input(z.object({\n path: PATH_SCHEMA,\n projectId: z.string().min(1).max(128),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .query(async ({ input }) => {\n const dir = safeResolve(input.path);\n\n const info = await stat(dir).catch(() => null);\n if (!info?.isDirectory()) {\n return { ok: false as const, reason: 'missing' as const, path: dir, otherProjectId: null };\n }\n if (await holdsRuneyaProject(dir)) {\n return { ok: false as const, reason: 'has-runeya-project' as const, path: dir, otherProjectId: null };\n }\n const otherProjectId = await projectPathStore.projectAt(dir, { id: input.projectId, orgId: input.orgId });\n if (otherProjectId) {\n return { ok: false as const, reason: 'taken' as const, path: dir, otherProjectId };\n }\n return { ok: true as const, reason: null, path: dir, otherProjectId: null };\n }),\n});\n","import { z } from 'zod';\nimport { isAbsolute } from 'node:path';\nimport { TRPCError } from '@trpc/server';\nimport { protectedProcedure, router } from '../trpc.js';\nimport { suggestLauncher, installLauncher } from '../../services/desktop-launcher.js';\nimport { setTrayAccent } from '../../services/tray-accent.js';\n\n/**\n * Le raccourci de bureau, créé depuis l'interface plutôt qu'en retapant\n * `runeya install-desktop`.\n *\n * `protectedProcedure` : la suggestion révèle le dossier de travail et les\n * ports de l'instance, et l'installation écrit dans l'environnement de bureau\n * de l'utilisateur.\n */\nexport const desktopRouter = router({\n /** Ce que le CLI demanderait, prérempli avec l'instance en cours. */\n suggestLauncher: protectedProcedure.query(() => suggestLauncher()),\n\n /**\n * La couleur du thème de cet onglet.\n *\n * Le thème vit dans le navigateur ; l'icône de barre système, elle, est\n * dessinée par le serveur. Sans cette annonce elle garderait la teinte figée\n * du fichier livré avec le CLI. Rien n'est persisté — voir `tray-accent.ts`.\n */\n setTrayAccent: protectedProcedure\n .input(z.object({\n // `#rgb` ou `#rrggbb` : la forme est vérifiée ici, pas rabotée plus loin.\n color: z.string().regex(/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/).nullable(),\n }))\n .mutation(({ input }) => {\n setTrayAccent(input.color);\n return { ok: true as const };\n }),\n\n installLauncher: protectedProcedure\n .input(z.object({\n name: z.string().trim().min(1).max(120),\n /**\n * `null` : raccourci global, sans dossier épinglé. Sinon un chemin\n * absolu, refusé autrement : le dossier devient un argument positionnel\n * du CLI, où une valeur commençant par un tiret passerait pour un drapeau.\n */\n workingDir: z.string().max(4096).refine(isAbsolute, {\n message: 'Le dossier de travail doit être un chemin absolu.',\n }).nullable(),\n port: z.number().int().min(1).max(65535),\n agentPort: z.number().int().min(1).max(65535),\n }))\n .mutation(async ({ input }) => {\n try {\n return await installLauncher(input);\n } catch (err) {\n const message = (err as Error).message;\n if (message === 'launcher-working-dir-not-absolute') {\n throw new TRPCError({\n code: 'BAD_REQUEST',\n message: 'Le dossier de travail doit être un chemin absolu.',\n });\n }\n if (message === 'launcher-unavailable') {\n throw new TRPCError({\n code: 'PRECONDITION_FAILED',\n message: 'Cette Runeya ne sait pas où trouver son CLI : créez le raccourci avec `runeya install-desktop`.',\n });\n }\n throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message });\n }\n }),\n});\n","/**\n * Créer un raccourci de bureau depuis l'interface, pour une Runeya lancée\n * depuis un terminal.\n *\n * Le raccourci lui-même est écrit par `runeya install-desktop` : c'est lui qui\n * sait produire un `.desktop`, un `.app` ou un `.lnk`, et le dupliquer ici\n * dupliquerait aussi ses corrections. Ce service ne fait donc que deux choses —\n * proposer les réponses que le CLI demanderait (dossier, nom, ports), et\n * rejouer la sous-commande sans poser de question.\n *\n * Le chemin du CLI n'est pas deviné : c'est le CLI qui l'annonce au démarrage\n * (`registerCli`). Sans cet appel — un serveur lancé autrement, une suite de\n * tests — la fonctionnalité se déclare simplement indisponible plutôt que de\n * lancer un exécutable au hasard.\n */\nimport { execFile } from 'node:child_process';\nimport { isAbsolute } from 'node:path';\nimport { promisify } from 'node:util';\nimport { deriveLauncherIdentity } from '@runeya/packages-shared';\nimport { env } from '../config/env.js';\n\nconst exec = promisify(execFile);\n\n/** Au-delà, l'écriture des fichiers a visiblement échoué autrement qu'en erreur. */\nconst INSTALL_TIMEOUT_MS = 30_000;\n\ntype CliLocation = { execPath: string; cliEntry: string };\n\nlet cli: CliLocation | null = null;\n\n/** Annoncé par le CLI au démarrage : l'exécutable Node et l'entrée du CLI. */\nexport function registerCli(location: CliLocation): void {\n cli = location;\n}\n\nexport type LauncherSuggestion = {\n /** Le CLI s'est annoncé : le raccourci peut être créé d'ici. */\n available: boolean;\n /** Cette instance vient déjà d'un raccourci — en proposer un n'a pas de sens. */\n fromDesktop: boolean;\n /** Le dossier que le raccourci épinglerait : celui de cette instance. */\n workingDir: string;\n /** Le nom que le CLI proposerait pour ce dossier. */\n name: string;\n port: number;\n agentPort: number;\n};\n\n/**\n * Les réponses préremplies : celles de l'instance en cours.\n *\n * Un raccourci sert à retrouver *cette* pile — mêmes dossier et mêmes ports —\n * sans retaper la commande. Les ports sont donc ceux réellement en service, pas\n * un tirage : deux Runeya au même port ne peuvent pas cohabiter, et celle-ci\n * tient déjà le sien.\n */\nexport function suggestLauncher(): LauncherSuggestion {\n const workingDir = process.cwd();\n return {\n available: cli !== null,\n fromDesktop: env.FROM_DESKTOP,\n workingDir,\n name: deriveLauncherIdentity(undefined, workingDir).name,\n port: env.PORT,\n agentPort: env.RUNEYA_AGENT_PORT,\n };\n}\n\nexport type InstallLauncherInput = {\n name: string;\n /** `null` : raccourci global, sans dossier épinglé. */\n workingDir: string | null;\n port: number;\n agentPort: number;\n};\n\nexport type InstallLauncherResult = {\n name: string;\n /** Le rapport du CLI, tel qu'il l'écrit — chemins des fichiers et avertissements. */\n output: string;\n};\n\n/**\n * Rejouer `runeya install-desktop` sans question.\n *\n * Le sous-processus n'a pas de TTY : le magicien du CLI ne se déclenche donc\n * pas, et chaque réponse arrive par un drapeau. Rien n'est écrit ici — c'est le\n * CLI qui écrit, et c'est son rapport qui est renvoyé.\n */\nexport async function installLauncher(input: InstallLauncherInput): Promise<InstallLauncherResult> {\n if (!cli) throw new Error('launcher-unavailable');\n /**\n * Le dossier part en argument positionnel, et le CLI lit ses arguments\n * lui-même : une valeur commençant par un tiret y serait un drapeau, pas un\n * chemin — `--help` ferait afficher l'aide au lieu d'installer. Un chemin\n * absolu est de toute façon la seule chose qu'un lanceur puisse épingler,\n * puisqu'il démarre sans répertoire courant à lui.\n */\n if (input.workingDir !== null && !isAbsolute(input.workingDir)) {\n throw new Error('launcher-working-dir-not-absolute');\n }\n\n const args = [\n cli.cliEntry,\n 'install-desktop',\n ...(input.workingDir === null ? ['--no-cwd'] : [input.workingDir]),\n '--name', input.name,\n '--port', String(input.port),\n '--agent-port', String(input.agentPort),\n ];\n\n const { stdout, stderr } = await exec(cli.execPath, args, {\n timeout: INSTALL_TIMEOUT_MS,\n windowsHide: true,\n // Le rapport tient en quelques lignes ; au-delà, quelque chose a dérapé.\n maxBuffer: 1024 * 1024,\n // Sans terminal, le CLI n'ajoute pas de couleurs : la sortie est lisible telle quelle.\n env: { ...process.env, NO_COLOR: '1' },\n });\n\n return { name: input.name, output: [stdout, stderr].filter((s) => s.trim()).join('\\n').trim() };\n}\n","/**\n * La couleur du thème que l'utilisateur regarde, connue du serveur.\n *\n * Le thème vit dans le `localStorage` du navigateur : le serveur ne le\n * connaîtrait pas sans cette annonce. C'est le même chemin que le projet\n * ouvert (`current-project.ts`), et pour la même raison — l'icône de barre\n * système n'a pas d'onglet, et sans cela elle resterait de la couleur figée\n * des fichiers livrés avec le CLI pendant que l'interface change de teinte.\n *\n * Gardée en mémoire, jamais sur le disque : c'est l'état d'une session\n * d'affichage. Un redémarrage repart sans couleur — l'icône livrée reprend sa\n * place — et l'onglet la redit en se rouvrant.\n */\n\nlet accent: string | null = null;\nconst listeners = new Set<() => void>();\n\n/** La couleur annoncée, ou `null` tant qu'aucun onglet ne l'a dite. */\nexport function getTrayAccent(): string | null {\n return accent;\n}\n\n/**\n * Annonce la couleur du thème.\n *\n * Ne prévient que si elle change vraiment : un onglet qui répète la sienne — au\n * rechargement, ou à chaque reconnexion — ne doit pas faire redessiner ce qui\n * n'a pas bougé, ni relancer le rendu d'une icône identique.\n */\nexport function setTrayAccent(next: string | null): void {\n const normalized = next === null ? null : next.trim().toLowerCase();\n if (normalized === accent) return;\n accent = normalized;\n for (const listener of listeners) {\n try {\n listener();\n } catch {\n // Un abonné qui échoue ne doit pas empêcher les autres d'être prévenus.\n }\n }\n}\n\nexport function onTrayAccentChanged(listener: () => void): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n","import { router } from './trpc.js';\nimport { healthRouter } from './routers/health.js';\nimport { appUpdateRouter } from './routers/app-update.js';\nimport { changelogRouter } from './routers/changelog.js';\nimport { projectRouter } from './routers/project.js';\nimport { serviceRouter } from './routers/service.js';\nimport { agentRouter } from './routers/agent.js';\nimport { processRouter } from './routers/process.js';\nimport { auditRouter } from './routers/audit.js';\nimport { setupRouter } from './routers/setup.js';\nimport { environmentRouter } from './routers/environment.js';\nimport { settingsRouter } from './routers/settings.js';\nimport { editorRouter } from './routers/editor.js';\nimport { apiKeysRouter } from './routers/api-keys.js';\nimport { chatRouter } from './routers/chat.js';\nimport { gitRouter } from './routers/git.js';\nimport { scenarioRouter } from './routers/scenario.js';\nimport { debugRouter } from './routers/debug.js';\nimport { diagnosticsRouter } from './routers/diagnostics.js';\nimport { kanbanQueueRouter } from './routers/kanban-queue.js';\nimport { kanbanRouter } from './routers/kanban.js';\nimport { terminalRouter } from './routers/terminal.js';\nimport { utilityRouter } from './routers/utility.js';\nimport { wikiRouter } from './routers/wiki.js';\nimport { configRouter } from './routers/config.js';\nimport { cloudSyncRouter } from './routers/cloud-sync.js';\nimport { cloudAuthRouter } from './routers/cloud-auth.js';\nimport { filesystemRouter } from './routers/filesystem.js';\nimport { desktopRouter } from './routers/desktop.js';\n\n// Re-export server types used in AppRouter so consumers can name them (avoids TS4023)\nexport type { AuditEntry } from '../services/audit-service.js';\nexport type { CliUsageEntry } from '../services/claude-usage.js';\nexport type { Conversation } from '../services/conversation-store.js';\nexport type { KanbanQueueItem, KanbanQueueState } from '../services/kanban-queue.js';\nexport type { PersistedRunState, RunState } from '../services/scenario-run-store.js';\n\nexport const appRouter = router({\n health: healthRouter,\n appUpdate: appUpdateRouter,\n changelog: changelogRouter,\n diagnostics: diagnosticsRouter,\n project: projectRouter,\n service: serviceRouter,\n agent: agentRouter,\n process: processRouter,\n audit: auditRouter,\n setup: setupRouter,\n environment: environmentRouter,\n settings: settingsRouter,\n editor: editorRouter,\n apiKeys: apiKeysRouter,\n chat: chatRouter,\n scenario: scenarioRouter,\n git: gitRouter,\n debug: debugRouter,\n kanbanQueue: kanbanQueueRouter,\n kanban: kanbanRouter,\n terminal: terminalRouter,\n utility: utilityRouter,\n wiki: wikiRouter,\n config: configRouter,\n cloudSync: cloudSyncRouter,\n cloudAuth: cloudAuthRouter,\n filesystem: filesystemRouter,\n desktop: desktopRouter,\n});\n\nexport type AppRouter = typeof appRouter;\n","import { Request, Response, NextFunction } from 'express';\n\nexport function errorHandler(err: Error, _req: Request, res: Response, _next: NextFunction): void {\n console.error('[server] Unhandled error:', err);\n res.status(500).json({ error: 'Internal server error' });\n}\n","import { settingsManager } from './settings-manager.js';\n\n\ninterface Migration {\n version: number;\n name: string;\n up: () => Promise<void>;\n}\n\n// Migrations are registered here. Each adds a transform function.\nconst migrations: Migration[] = [\n];\n\nclass MigrationEngine {\n async run(): Promise<void> {\n const schemaVersion = await settingsManager.getSchemaVersion();\n const currentVersion = schemaVersion.version;\n const targetVersion = settingsManager.getCurrentSchemaVersion();\n\n if (currentVersion >= targetVersion) {\n console.log(`[migration] Schema is up to date (v${currentVersion})`);\n return;\n }\n\n console.log(`[migration] Migrating from v${currentVersion} to v${targetVersion}`);\n const pending = migrations.filter(m => m.version > currentVersion && m.version <= targetVersion);\n pending.sort((a, b) => a.version - b.version);\n\n for (const migration of pending) {\n console.log(`[migration] Running: ${migration.name} (v${migration.version})`);\n await migration.up();\n await settingsManager.saveSchemaVersion({ version: migration.version, migratedAt: new Date() });\n console.log(`[migration] Done: ${migration.name}`);\n }\n\n console.log(`[migration] All migrations complete. Now at v${targetVersion}`);\n }\n}\n\nexport const migrationEngine = new MigrationEngine();\n","import { chmod, stat } from 'node:fs/promises';\nimport { machineFilePath, legacyMachineFilePath } from './vault-resolver.js';\n\nconst SENSITIVE_FILES = [\n 'agents.json',\n 'settings.json',\n 'services.json',\n 'projects.json',\n 'deployments.json',\n 'schema-version.json',\n];\n\nconst SECURE_MODE = 0o600;\n\n/**\n * Ensure all sensitive data files have restrictive permissions (0600).\n * Logs warnings for files with overly permissive modes and auto-fixes them.\n */\nexport async function ensureFilePermissions(): Promise<void> {\n for (const filename of SENSITIVE_FILES) {\n // Both homes are checked: a directory written by an older version still\n // holds these files, and lax permissions there are just as bad.\n for (const filepath of [machineFilePath(filename), legacyMachineFilePath(filename)]) {\n try {\n const stats = await stat(filepath);\n const mode = stats.mode & 0o777;\n if (mode !== SECURE_MODE) {\n console.warn('[security] File', filepath, 'has mode', mode.toString(8) + ', fixing to 600');\n await chmod(filepath, SECURE_MODE);\n }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n console.warn('[security] Cannot check permissions for', filepath + ':', err instanceof Error ? err.message : String(err));\n }\n // ENOENT is fine — file doesn't exist yet\n }\n }\n }\n}\n","import { readdir, readFile, writeFile, mkdir, copyFile, unlink, rename, stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { rekeyJsonValue } from './key-adoption.js';\nimport { readEncryptedKey, verifyEncryptionKey } from './master-password.js';\n\n/**\n * Converts a vault left under its own key to the machine key.\n *\n * Older versions let the launch directory hold a key of its own, so a machine\n * ended up with several master passwords — and, since the cloud session lives\n * beside the key that opens it, several cloud identities. Such a vault is no\n * longer obeyed (see `keyRoot`), which would leave its data unreadable: this is\n * what makes it readable again, under the one key that answers for the machine.\n *\n * Values are found by shape, not by schema. `isEncryptedValue` recognizes what\n * `encryptValue` produced, so every ciphertext is re-keyed wherever it sits —\n * including in files added long after this code was written. Enumerating known\n * fields would have quietly skipped whatever the next release introduces.\n */\n\n/** Files that mark a directory as holding a key, and that end the migration. */\nconst KEY_FILES = ['.encryption.key.enc', '.runeya-verify'];\n\n/**\n * Vault files that belong to the machine rather than to the project.\n *\n * They were only ever in the launch directory because the key was, so they move\n * to the machine root. A file already present there is left alone and reported:\n * overwriting the machine's own agents or cloud session with a stale copy would\n * trade one silent loss for another.\n */\nconst MACHINE_FILES = [\n 'agents.json',\n 'cloud-session.json',\n 'conversations.private.json',\n 'api-keys.json',\n 'api-keys.private.json',\n 'settings.private.json',\n];\n\nexport interface VaultMigrationReport {\n /** Where the untouched copy of the vault was kept. */\n backupDir: string;\n /** Files whose ciphertexts were re-keyed, with how many values each held. */\n rekeyed: { file: string; values: number }[];\n /** Machine-level files moved out of the vault. */\n moved: string[];\n /** Machine-level files left in place because the machine already had one. */\n skipped: string[];\n}\n\n/**\n * Recursively re-key every ciphertext in a parsed JSON value.\n *\n * Partagé avec l'adoption d'une autre clé : les deux font le même travail, et\n * la version commune connaît AUSSI le triplet des agents — que cette migration\n * ignorait, laissant chaque passphrase d'agent chiffrée sous la clé abandonnée.\n */\nconst rekeyValue = rekeyJsonValue;\n\n/** JSON files directly inside the vault — never its backups or subdirectories. */\nasync function vaultJsonFiles(root: string): Promise<string[]> {\n const entries = await readdir(root, { withFileTypes: true });\n return entries.filter((e) => e.isFile() && e.name.endsWith('.json')).map((e) => e.name);\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Prove a master password opens this vault, and hand back the key it holds.\n *\n * Both halves matter: `readEncryptedKey` fails on a wrong password (GCM refuses\n * to authenticate), and the canary then proves the key it yielded is the one\n * this vault's data was encrypted with. A password that passes the first but\n * not the second means the vault's files disagree with each other — better\n * refused than half-migrated.\n */\nexport async function openLegacyVault(legacyRoot: string, masterPassword: string): Promise<Buffer> {\n const key = await readEncryptedKey(legacyRoot, masterPassword);\n await verifyEncryptionKey(legacyRoot, key);\n return key;\n}\n\n/**\n * Re-key a legacy vault onto the machine key.\n *\n * Ordered so that nothing is lost if it stops halfway: the backup is complete\n * before the first write, the key files are removed only once every file has\n * been re-read under the new key, and a file that fails to convert aborts the\n * run while the vault is still entirely readable under the old key.\n */\nexport async function migrateLegacyVault(\n legacyRoot: string,\n machineRootDir: string,\n legacyKey: Buffer,\n machineKey: Buffer,\n now: Date,\n): Promise<VaultMigrationReport> {\n const stamp = now.toISOString().replace(/[:.]/g, '-').substring(0, 19);\n const backupDir = join(legacyRoot, `backup-${stamp}`);\n await mkdir(backupDir, { recursive: true });\n\n const jsonFiles = await vaultJsonFiles(legacyRoot);\n\n // 1. Full copy first — including the key files, so the backup opens on its own.\n for (const name of [...jsonFiles, ...KEY_FILES]) {\n if (await exists(join(legacyRoot, name))) {\n await copyFile(join(legacyRoot, name), join(backupDir, name));\n }\n }\n\n // 2. Re-key in place. A parse or write failure throws, leaving the vault as it was.\n const rekeyed: VaultMigrationReport['rekeyed'] = [];\n for (const name of jsonFiles) {\n const raw = await readFile(join(legacyRoot, name), 'utf-8');\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // Not JSON despite the extension — nothing of ours to convert.\n continue;\n }\n const counter = { n: 0 };\n const converted = rekeyValue(parsed, legacyKey, machineKey, counter);\n if (counter.n === 0) continue;\n // Atomic, like every other write in the vault: a half-written file here\n // would be a file no key opens.\n const tmp = join(legacyRoot, `${name}.tmp`);\n await writeFile(tmp, JSON.stringify(converted, null, 2), 'utf-8');\n await rename(tmp, join(legacyRoot, name));\n rekeyed.push({ file: name, values: counter.n });\n }\n\n // 3. Verify every converted value opens under the machine key before going further.\n for (const { file, values } of rekeyed) {\n const parsed = JSON.parse(await readFile(join(legacyRoot, file), 'utf-8'));\n const check = { n: 0 };\n rekeyValue(parsed, machineKey, machineKey, check);\n if (check.n !== values) {\n throw new Error(\n `Vérification échouée pour ${file} : ${check.n} valeur(s) relisible(s) avec la clé machine, ${values} attendue(s)`,\n );\n }\n }\n\n // 4. Machine-level files go where the machine key lives.\n await mkdir(machineRootDir, { recursive: true });\n const moved: string[] = [];\n const skipped: string[] = [];\n for (const name of MACHINE_FILES) {\n const from = join(legacyRoot, name);\n if (!(await exists(from))) continue;\n const to = join(machineRootDir, name);\n if (await exists(to)) {\n skipped.push(name);\n continue;\n }\n await copyFile(from, to);\n await unlink(from);\n moved.push(name);\n }\n\n // 5. Last of all: drop the local key, which is what hands this directory over\n // to the machine key on the next boot.\n for (const name of KEY_FILES) {\n const path = join(legacyRoot, name);\n if (await exists(path)) await unlink(path);\n }\n\n return { backupDir, rekeyed, moved, skipped };\n}\n","import { readFile, writeFile, rename, unlink, mkdir, chmod, stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { machineFilePath, legacyMachineFilePath, orgVaultRoot, listOrgVaults } from './vault-resolver.js';\nimport { settingsManager } from './settings-manager.js';\n\n/**\n * Faire descendre les réglages là où ils appartiennent, une fois.\n *\n * Les réglages vivaient au niveau du poste alors qu'ils décrivent des choses\n * qui appartiennent à des organisations — les fournisseurs d'IA qui paient le\n * travail d'une équipe, les scénarios qui décrivent ses services. Ils\n * descendent donc dans le coffre de l'organisation, et le fichier machine\n * disparaît : un déplacement, pas un repli à la lecture, pour qu'il n'existe\n * jamais deux endroits où le même réglage pourrait se trouver.\n *\n * Une seule organisation sur ce disque : le fichier est à elle, sans ambiguïté.\n *\n * Plusieurs : personne ne peut deviner à laquelle appartenaient des réglages\n * écrits à une époque où la question ne se posait pas — et les recopier dans\n * chacune répandrait les secrets d'une équipe chez les autres. Le fichier reste\n * alors où il est, et l'utilisateur est prévenu qu'il a une répartition à\n * faire. Se tromper silencieusement serait pire que ne rien faire.\n */\n\nconst SETTINGS_FILE = 'settings.json';\nconst SETTINGS_PRIVATE_FILE = 'settings.private.json';\n\nexport interface SettingsMigrationReport {\n /** Organisation ayant reçu les réglages, quand il n'y avait pas de doute. */\n movedTo: string | null;\n /** Fichiers effectivement déplacés. */\n files: string[];\n /**\n * Organisations entre lesquelles il faut trancher à la main, le cas échéant.\n * Vide quand rien n'est ambigu.\n */\n ambiguous: string[];\n}\n\nasync function exists(path: string): Promise<boolean> {\n return stat(path).then(() => true, () => false);\n}\n\n/** Le fichier écrit par une version précédente, où qu'elle l'ait mis. */\nasync function legacySource(filename: string): Promise<string | null> {\n for (const path of [machineFilePath(filename), legacyMachineFilePath(filename)]) {\n if (await exists(path)) return path;\n }\n return null;\n}\n\nasync function moveInto(root: string, filename: string, from: string): Promise<void> {\n await mkdir(root, { recursive: true });\n const to = join(root, filename);\n // Copie puis effacement plutôt qu'un `rename` : la source et la destination\n // peuvent être sur deux systèmes de fichiers différents (un coffre sous\n // `$HOME`, un répertoire de lancement ailleurs), et `rename` échouerait.\n const contents = await readFile(from, 'utf-8');\n const tmp = to + '.tmp';\n await writeFile(tmp, contents, 'utf-8');\n await rename(tmp, to);\n await chmod(to, 0o600);\n await unlink(from);\n}\n\nexport async function migrateSettingsIntoVaults(): Promise<SettingsMigrationReport> {\n const report: SettingsMigrationReport = { movedTo: null, files: [], ambiguous: [] };\n\n const sources: { filename: string; from: string }[] = [];\n for (const filename of [SETTINGS_FILE, SETTINGS_PRIVATE_FILE]) {\n const from = await legacySource(filename);\n if (from) sources.push({ filename, from });\n }\n if (sources.length === 0) return report;\n\n const orgs = await listOrgVaults();\n // Aucune organisation : les réglages sont déjà chez eux, au niveau du poste,\n // qui est bien le propriétaire de ce qui n'appartient à personne d'autre.\n if (orgs.length === 0) return report;\n if (orgs.length > 1) {\n report.ambiguous = orgs;\n return report;\n }\n\n const orgId = orgs[0]!;\n const root = orgVaultRoot(orgId);\n for (const { filename, from } of sources) {\n // Le coffre a déjà le sien : le fichier machine est un reliquat, et\n // l'écraser avec lui reviendrait à annuler des réglages plus récents.\n if (await exists(join(root, filename))) continue;\n await moveInto(root, filename, from);\n report.files.push(filename);\n }\n if (report.files.length > 0) {\n report.movedTo = orgId;\n settingsManager.forget();\n }\n return report;\n}\n","/**\n * Legacy Runeya → Runeya migration\n *\n * Triggered automatically when DATA_DIR/.runeya/dbs/encryption-key.json is found.\n * Must run BEFORE any store initialisation (called at the top of createLocalServer).\n *\n * Steps:\n * 1. Backup existing DATA_DIR contents\n * 2. Extract legacy libsodium key → load in memory for re-encryption\n * 3. Decrypt all .encrypted.json files with libsodium crypto_secretbox\n * 4. Map legacy structures → Runeya JSON files\n * 5. Clear singleton, store key in pending holder → server enters setup state\n * 6. Rename .runeya → backup to prevent re-running\n */\n\nimport { createRequire } from 'module';\nimport { randomBytes, createCipheriv, createDecipheriv } from 'node:crypto';\nimport { randomUUID } from 'node:crypto';\nimport {\n readFile, writeFile, rename, mkdir, access, readdir,\n} from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport { setEncryptionKey, getEncryptionKey, clearEncryptionKey, setPendingLegacyKey } from '../utils/encryption-key.js';\nimport type { Variable } from '@runeya/packages-shared';\nimport { env } from '../config/env.js';\n\n// CJS interop for libsodium-wrappers\nconst _require = createRequire(import.meta.url);\n\n/** Minimal type for the libsodium-wrappers API used in this migration */\ninterface Sodium {\n ready: Promise<void>;\n crypto_secretbox_NONCEBYTES: number;\n crypto_secretbox_open_easy(ciphertext: Uint8Array, nonce: Uint8Array, key: Uint8Array): Uint8Array;\n from_base64(input: string): Uint8Array;\n}\n\n// Parser ID remapping\nconst PARSER_ID_MAP: Record<string, string> = {\n 'stack-monitor-parser-jsons': 'native:json',\n 'stack-monitor-parser-debug': 'native:debug',\n 'stack-monitor-parser-links': 'native:links',\n 'runeya-parser-jsons': 'native:json',\n 'runeya-parser-debug': 'native:debug',\n 'runeya-parser-links': 'native:links',\n};\n\n// ── Runeya AES-256-GCM encryption (matches service-store / environment-store) ──\n\nfunction encryptValue(plaintext: string): string {\n const key = getEncryptionKey();\n if (!key) throw new Error('[legacy-migration] Encryption key not loaded');\n const iv = randomBytes(16);\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n let enc = cipher.update(plaintext, 'utf-8', 'hex');\n enc += cipher.final('hex');\n const authTag = cipher.getAuthTag().toString('hex');\n return `${iv.toString('hex')}:${authTag}:${enc}`;\n}\n\n/** Strip legacy suffixes from a variable key: _RUNEYA_OVERRIDE → _RUNEYA → base */\nfunction cleanVarKey(key: string): string {\n return key.replace(/_RUNEYA(?:_OVERRIDE)?$|_OVERRIDE$/, '');\n}\n\n/** Valid interpolation token: {{VAR_NAME}} or {{environment.VAR_NAME}} — simple identifiers only, no expressions */\nconst VALID_INTERP_RE = /^\\{\\{(?:environment\\.)?[A-Z_][A-Z0-9_]*\\}\\}$/i;\n\n/** Detect interpolation patterns like ${VAR}, $VAR, {{VAR}} */\nfunction hasInterpolation(value: string): boolean {\n return /\\$\\{[^}]+\\}|\\$[A-Z_][A-Z0-9_]*|\\{\\{[^}]+\\}\\}/.test(value);\n}\n\n/** Returns true only for simple variable references — rejects expressions, ternaries, nested accessors */\nfunction isValidInterpolation(token: string): boolean {\n return VALID_INTERP_RE.test(token.trim());\n}\n\n/** Returns true if the value contains any {{...}} token that is not a valid variable reference */\nfunction hasInvalidInterpolation(value: string): boolean {\n const tokens = value.matchAll(/\\{\\{[^}]+\\}\\}/g);\n for (const match of tokens) {\n if (!isValidInterpolation(match[0])) return true;\n }\n return false;\n}\n\n/**\n * Rewrite legacy {{KEY}} interpolation to Runeya's {{environment.KEY}} format.\n * Strips legacy suffixes (_RUNEYA, _OVERRIDE, _RUNEYA_OVERRIDE).\n * Leaves ${VAR} and $VAR patterns untouched (shell interpolation, handled at runtime).\n */\nfunction rewriteInterpolation(value: string): string {\n return value.replace(/\\{\\{(?!environment\\.)([^}]+)\\}\\}/g, (match, key: string) => {\n // Only rewrite simple variable references — leave expressions untouched (will be encrypted)\n if (!isValidInterpolation(match)) return match;\n return `{{environment.${cleanVarKey(key)}}}`;\n });\n}\n\n/**\n * Detect composite interpolation: a value that contains exactly one {{VAR}} token\n * with surrounding text (e.g. \"{{DATABASE_URL}}/onboarding?authSource=admin\").\n * Returns { pre, interp, post } if composite, null otherwise.\n * Values with multiple {{...}} tokens or $VAR/${{VAR}} patterns are left untouched.\n */\nfunction splitCompositeInterpolation(value: string): { pre: string; interp: string; post: string } | null {\n const tokens = [...value.matchAll(/\\{\\{[^}]+\\}\\}/g)];\n if (tokens.length !== 1) return null; // 0 or 2+ interpolations — skip\n if (/\\$\\{[^}]+\\}|\\$[A-Z_][A-Z0-9_]*/.test(value)) return null; // shell vars — skip\n const match = tokens[0];\n if (!isValidInterpolation(match[0])) return null; // expression/ternary — treat as literal\n const pre = value.slice(0, match.index);\n const post = value.slice((match.index ?? 0) + match[0].length);\n if (!pre && !post) return null; // pure interpolation — nothing to split\n return { pre, interp: match[0], post };\n}\n\n/** Decrypt a migration-encrypted value (same AES-256-GCM as encryptValue above) */\nfunction decryptMigrationValue(encrypted: string): string | null {\n try {\n const key = getEncryptionKey();\n if (!key) return null;\n const parts = encrypted.split(':');\n if (parts.length !== 3) return null;\n const [ivHex, authHex, ct] = parts;\n const dec = createDecipheriv('aes-256-gcm', key, Buffer.from(ivHex, 'hex'), { authTagLength: 16 });\n dec.setAuthTag(Buffer.from(authHex, 'hex'));\n return dec.update(ct, 'hex', 'utf-8') + dec.final('utf-8');\n } catch { return null; }\n}\n\n/**\n * Returns true if the override raw value is identical to the base variable's stored value.\n * Skips writing a redundant override when base and override resolve to the same thing.\n */\nfunction isSameAsBase(overrideRawValue: string, baseVar: Variable | undefined): boolean {\n if (!baseVar) return false;\n const baseSlot = baseVar.value;\n if (!baseSlot.isSecret) {\n return baseSlot.value === rewriteInterpolation(overrideRawValue);\n }\n const decrypted = decryptMigrationValue(baseSlot.value);\n return decrypted === overrideRawValue;\n}\n\n/** Build a Variable with key and value slot — encrypted if secret, plaintext (with rewritten interpolation) otherwise */\nfunction makeVariable(key: string, value: string, pre = '', post = ''): Variable {\n // Auto-detect composite interpolation and ventilate into pre/value/post\n const composite = splitCompositeInterpolation(value);\n if (composite) {\n return {\n key,\n value: {\n value: rewriteInterpolation(composite.interp),\n pre: rewriteInterpolation(pre + composite.pre),\n post: rewriteInterpolation(composite.post + post),\n isSecret: false,\n shareWithAi: false,\n injectIntoAi: false,\n required: false,\n overrideOnly: false,\n description: '',\n },\n };\n }\n\n const secret = !hasInterpolation(value);\n return {\n key,\n value: {\n value: secret ? encryptValue(value) : rewriteInterpolation(value),\n pre: rewriteInterpolation(pre),\n post: rewriteInterpolation(post),\n isSecret: secret,\n shareWithAi: false,\n injectIntoAi: false,\n required: false,\n overrideOnly: false,\n description: '',\n },\n };\n}\n\n// ── libsodium decryption ──────────────────────────────────────────────────────\n\nasync function getSodium(): Promise<Sodium> {\n const _sodium = _require('libsodium-wrappers') as Sodium;\n await _sodium.ready;\n return _sodium;\n}\n\nasync function decryptLegacyFile(\n filePath: string,\n key: Uint8Array,\n sodium: Sodium,\n): Promise<unknown> {\n const raw = (await readFile(filePath, 'utf-8')).trim();\n if (!raw || raw === '[]' || raw === '{}') {\n try { return JSON.parse(raw); } catch { return {}; }\n }\n\n const buf = Buffer.from(raw, 'base64');\n const nonce = buf.subarray(0, sodium.crypto_secretbox_NONCEBYTES as number);\n const ciphertext = buf.subarray(sodium.crypto_secretbox_NONCEBYTES as number);\n const decrypted = sodium.crypto_secretbox_open_easy(\n new Uint8Array(ciphertext),\n new Uint8Array(nonce),\n key,\n ) as Uint8Array;\n\n return JSON.parse(Buffer.from(decrypted).toString('utf-8'));\n}\n\n// ── Atomic write helper ───────────────────────────────────────────────────────\n\nasync function atomicWrite(path: string, data: unknown): Promise<void> {\n const tmp = path + '.tmp';\n await writeFile(tmp, JSON.stringify(data, null, 2), 'utf-8');\n await rename(tmp, path);\n}\n\n// ── Main migration entry point ────────────────────────────────────────────────\n\nexport async function runLegacyMigration(dataDir: string): Promise<boolean> {\n // Legacy .runeya sits in the launch directory. `env.DATA_DIR` is already\n // absolute — resolved once at boot — so it IS that path; joining it onto a\n // cwd would build a nonsense one.\n const legacyRoot = env.DATA_DIR;\n const legacyKeyPath = join(legacyRoot, 'dbs', 'encryption-key.json');\n\n // Detect legacy installation\n try {\n await access(legacyKeyPath);\n } catch {\n return false;\n }\n\n console.log('[legacy-migration] Legacy Runeya data detected, starting migration…');\n\n // ── 1. Move legacy .runeya → .runeya/backup-<date>, create fresh DATA_DIR ───\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-').substring(0, 19);\n // Frère de `legacyRoot`, pas un enfant : on va recréer `dataDir` (le même\n // chemin) juste après, et un temporaire placé dedans serait emporté.\n const legacyTmp = `${legacyRoot}-tmp`;\n await rename(legacyRoot, legacyTmp); // free up the .runeya name\n await mkdir(dataDir, { recursive: true }); // create fresh .runeya/\n const legacyOld = join(dataDir, `backup-${timestamp}`);\n await rename(legacyTmp, legacyOld); // move into .runeya/backup-<date>\n console.log(`[legacy-migration] Legacy data backed up to ${legacyOld}`);\n\n // ── 2. Extract legacy key and initialise Runeya encryption ─────────────────\n const keyJson = JSON.parse(await readFile(join(legacyOld, 'dbs', 'encryption-key.json'), 'utf-8')) as { encryptionKey: string };\n const sodium = await getSodium();\n const sodiumKey = sodium.from_base64(keyJson.encryptionKey) as Uint8Array;\n\n // Load key into singleton temporarily — needed by encryptValue/makeVariable during re-encryption\n const keyBuffer = Buffer.from(sodiumKey);\n const runyeaKeyHex = keyBuffer.toString('hex');\n await setEncryptionKey(runyeaKeyHex);\n console.log('[legacy-migration] Encryption key loaded in memory (temporary)');\n\n // ── 3. Decrypt all legacy files ─────────────────────────────────────────────\n const dbsDir = join(legacyOld, 'dbs');\n\n async function readEncrypted(filePath: string): Promise<any> {\n try {\n return await decryptLegacyFile(filePath, sodiumKey, sodium);\n } catch (err: unknown) {\n console.warn(`[legacy-migration] Failed to decrypt ${filePath}: ${(err as Error).message}`);\n return null;\n }\n }\n\n // Environments\n const envsDir = join(dbsDir, 'envs');\n const envFiles = (await readdir(envsDir).catch(() => [] as string[]))\n .filter(f => f.endsWith('.encrypted.json'));\n\n const legacyEnvs: Record<string, any> = {};\n for (const file of envFiles) {\n const name = file.replace('.encrypted.json', '');\n legacyEnvs[name] = await readEncrypted(join(envsDir, file));\n }\n\n // Services\n const servicesDir = join(dbsDir, 'services');\n const serviceFiles = (await readdir(servicesDir).catch(() => [] as string[]))\n .filter(f => f.endsWith('.encrypted.json'));\n\n const legacyServices: Record<string, any> = {};\n for (const file of serviceFiles) {\n const name = file.replace('.encrypted.json', '');\n if (!name) continue; // skip empty default service\n const data = await readEncrypted(join(servicesDir, file));\n if (data?.label) legacyServices[name] = data;\n }\n\n // Overrides\n const overridesDir = join(dbsDir, 'overrides');\n const overrideFiles = (await readdir(overridesDir).catch(() => [] as string[]))\n .filter(f => f.endsWith('.encrypted.json'));\n\n const legacyServiceOverrides: Record<string, any> = {};\n const legacyEnvOverrides: Record<string, any> = {};\n\n for (const file of overrideFiles) {\n const baseName = file.replace('.encrypted.json', '');\n const data = await readEncrypted(join(overridesDir, file));\n if (!data) continue;\n\n if (baseName.endsWith('-envs')) {\n legacyServiceOverrides[baseName.slice(0, -5)] = data;\n } else if (baseName.endsWith('-environment')) {\n legacyEnvOverrides[baseName.slice(0, -12)] = data;\n }\n }\n\n // Custom parsers\n const parsersDir = join(dbsDir, 'parsers');\n const parserFiles = (await readdir(parsersDir).catch(() => [] as string[]))\n .filter(f => f.endsWith('.encrypted.json'));\n\n const legacyParsers: any[] = [];\n for (const file of parserFiles) {\n const data = await readEncrypted(join(parsersDir, file));\n if (data?.id) legacyParsers.push(data);\n }\n\n // ── 4. Build Runeya data structures ─────────────────────────────────────────\n\n // Projects\n const projectMonoId = randomUUID();\n\n // Environments — two-pass to resolve parentIds after all IDs are known\n // envIdMap keyed by filename (without extension) for ID lookup\n const envIdMap: Record<string, string> = {};\n // labelToKey maps label → filename key, for resolving extends references\n const labelToKey: Record<string, string> = {};\n for (const [name, legacyEnv] of Object.entries(legacyEnvs)) {\n envIdMap[name] = randomUUID();\n if (legacyEnv?.label) labelToKey[legacyEnv.label] = name;\n }\n\n const runeEnvs: any[] = [];\n const defaultEnvName = Object.entries(legacyEnvs).find(([, v]) => v?.default)?.[0];\n\n // Lookup map: `${envId}:${cleanedVarName}` → variableId (UUID)\n const varIdLookup = new Map<string, string>();\n\n for (const [name, legacyEnv] of Object.entries(legacyEnvs)) {\n if (!legacyEnv) continue;\n\n // Collect all variables inherited from parent envs (union, first-parent wins)\n const inheritedVars: Record<string, string> = {};\n for (const parentLabel of legacyEnv.extends || []) {\n const parentKey = labelToKey[parentLabel] ?? parentLabel;\n const parentEnv = legacyEnvs[parentKey];\n for (const [k, v] of Object.entries(parentEnv?.envs ?? {})) {\n if (typeof v === 'string') {\n const cleaned = cleanVarKey(k);\n if (!(cleaned in inheritedVars)) inheritedVars[cleaned] = v;\n }\n }\n }\n\n const variables: Record<string, Variable> = {};\n for (const [key, value] of Object.entries(legacyEnv.envs || {})) {\n if (typeof value === 'string') {\n if (hasInvalidInterpolation(value)) continue;\n const cleaned = cleanVarKey(key);\n // Skip if identical to inherited value — the child inherits it anyway\n if (inheritedVars[cleaned] === value) continue;\n const varId = randomUUID();\n variables[varId] = makeVariable(cleaned, value);\n varIdLookup.set(`${envIdMap[name]}:${cleaned}`, varId);\n }\n }\n\n runeEnvs.push({\n id: envIdMap[name],\n projectId: projectMonoId,\n name: legacyEnv.label || name,\n description: '',\n scope: 'global' as const,\n parentIds: (legacyEnv.extends || [])\n .map((p: string) => envIdMap[labelToKey[p] ?? p])\n .filter(Boolean),\n immutable: false,\n default: name === defaultEnvName,\n color: legacyEnv.bgColor || '#22c55e',\n variables,\n });\n }\n\n // Services\n const serviceIdMap: Record<string, string> = {};\n const runeServices: any[] = [];\n\n for (const [name, legacy] of Object.entries(legacyServices)) {\n const id = randomUUID();\n serviceIdMap[name] = id;\n\n // rootPath = legacy global working directory for this service\n const rootPath: string = legacy.rootPath || '';\n const rootPathCwd = rootPath && rootPath !== '.' ? rootPath : '';\n\n // Commands: spawnCmd + spawnArgs → single command string\n // Command cwd only set if the command has its own explicit cwd (not inherited from rootPath)\n const commands: any[] = [];\n for (const cmd of legacy.commands || []) {\n const parts = [cmd.spawnCmd, ...(cmd.spawnArgs || [])].filter(Boolean);\n if (!parts.length) continue;\n commands.push({\n id: cmd.id || randomUUID(),\n label: 'Launch',\n command: parts.join(' '),\n cwd: cmd.spawnOptions?.cwd || '',\n shell: false,\n });\n }\n\n // Parser IDs — deduplicated, remapped\n const effectiveParsers: any[] =\n legacy.commands?.[0]?.effectiveParsers\n ?? legacy.parsers\n ?? [];\n\n const parserIds: string[] = [];\n for (const parser of effectiveParsers) {\n const rawId: string = typeof parser === 'string' ? parser : (parser.id ?? '');\n const mapped = PARSER_ID_MAP[rawId] ?? rawId;\n if (mapped && !parserIds.includes(mapped)) {\n if (!PARSER_ID_MAP[rawId]) {\n console.warn(`[legacy-migration] Unknown parser \"${rawId}\" on service \"${name}\" — kept as-is`);\n }\n parserIds.push(mapped);\n }\n }\n\n // Health check — extract path from URL, rename returnCode → expectedStatus\n // Only migrate if explicitly enabled (or if enabled field absent, presence of URL implies intent)\n let healthCheck: any;\n if (legacy.health?.url && legacy.health?.enabled !== false) {\n try {\n const healthUrl = new URL(legacy.health.url);\n healthCheck = {\n path: healthUrl.pathname || '/',\n method: legacy.health.method || 'GET',\n ...(typeof legacy.health.interval === 'number' && { interval: legacy.health.interval }),\n expectedStatus: legacy.health.returnCode || 200,\n };\n } catch {\n // Invalid URL — skip health check\n }\n }\n\n // Docker config — map legacy container fields to DockerConfig\n // Legacy structure: container.build (Dockerfile content), container.bootstrap.commands,\n // container.volumes, container.ports, container.name, container.ignoreVolumes, etc.\n let dockerConfig: any;\n const container = legacy.container;\n if (container?.enabled) {\n dockerConfig = {\n volumes: container.volumes || [],\n ports: container.ports || [],\n networkMode: container.networkMode || 'host',\n };\n\n // Dockerfile — legacy uses \"build\" field (not \"dockerfile\")\n // buildContext defaults to \".\" (Docker needs a valid context for COPY/ADD)\n if (container.build) {\n dockerConfig.dockerfile = container.build;\n dockerConfig.buildContext = '.';\n }\n\n // Image (pull mode, mutually exclusive with Dockerfile in UI)\n // Legacy \"name\" field can serve as image if no explicit \"image\" field\n if (container.image) {\n dockerConfig.image = container.image;\n } else if (container.name && !container.build) {\n dockerConfig.image = container.name;\n }\n\n // Build args — legacy uses container.buildArgs (Record<string, string>)\n if (container.buildArgs && typeof container.buildArgs === 'object') {\n dockerConfig.buildArgs = container.buildArgs;\n }\n\n // Target stage — legacy uses container.targetStage\n if (container.targetStage) {\n dockerConfig.targetStage = container.targetStage;\n }\n\n // User — legacy uses container.user or bootstrap command user\n if (container.user) {\n dockerConfig.user = container.user;\n }\n\n // Bootstrap commands — legacy uses container.bootstrap.commands[]\n // Each entry has { entrypoint, cmd, user }\n // Migrate ALL commands as bootstrapCommands[] (structured array)\n const legacyBootstrapCmds: any[] = container.bootstrap?.commands || [];\n if (legacyBootstrapCmds.length > 0) {\n dockerConfig.bootstrapCommands = legacyBootstrapCmds\n .filter((bs: any) => bs.cmd || bs.entrypoint)\n .map((bs: any, idx: number) => ({\n id: bs.id || randomUUID(),\n label: bs.label || `Bootstrap ${idx + 1}`,\n command: bs.cmd || '',\n ...(bs.entrypoint ? { entrypoint: bs.entrypoint } : {}),\n ...(bs.user ? { user: bs.user } : {}),\n }));\n\n // Also set top-level entrypoint/command from first bootstrap for backwards compat\n const first = legacyBootstrapCmds[0];\n if (first?.entrypoint) dockerConfig.entrypoint = first.entrypoint;\n if (first?.cmd) dockerConfig.command = first.cmd;\n\n // Inherit user from first bootstrap if not set at container level\n if (!dockerConfig.user && first?.user) {\n dockerConfig.user = first.user;\n }\n }\n\n // ignoreVolumes → convert to real bind-mount volumes\n // Legacy used ignoreVolumes to mask container paths with a persistent host directory.\n // We convert each to ~/runeya/docker-persistence/<service-id>/<internal-path>:<internal-path>\n const sharedVolume: string = container.sharedVolume || '~/.runeya';\n const ignoreVolumes: string[] = (container.ignoreVolumes || [])\n .filter((v: string) => !v.startsWith(sharedVolume));\n if (ignoreVolumes.length > 0) {\n for (const ignoredPath of ignoreVolumes) {\n // Strip leading slash for the host sub-directory\n const subDir = ignoredPath.replace(/^\\/+/, '');\n const hostPath = `~/runeya/docker-persistence/${id}/${subDir}`;\n dockerConfig.volumes.push(`${hostPath}:${ignoredPath}`);\n }\n console.log(`[legacy-migration] Service \"${legacy.label}\": converted ${ignoreVolumes.length} ignoreVolumes to bind-mount volumes`);\n }\n\n // Native commands (spawnCmd) exist alongside Docker →\n // the service runs its native command inside the container\n if (commands.length > 0) {\n dockerConfig.useNativeCommand = true;\n dockerConfig.nativeCommandMode = 'isolated';\n }\n }\n\n // Port: extract from url (e.g. http://localhost:3034/... → 3034)\n let port: number | undefined;\n const serviceUrl: string = legacy.url || '';\n if (serviceUrl) {\n try {\n const parsed = new URL(serviceUrl);\n const p = Number.parseInt(parsed.port, 10);\n if (p > 0 && p <= 65535) port = p;\n } catch { /* invalid URL */ }\n }\n\n // Top-level cwd = legacy rootPath (global working directory for the service)\n const serviceCwd = rootPathCwd;\n\n const runeService: any = {\n id,\n orgId: null,\n agentId: 'local-agent',\n name: legacy.label,\n commands,\n cwd: serviceCwd,\n runner: dockerConfig ? 'docker' : 'native',\n shortcuts: (legacy.shortcuts || [])\n .filter((s: any) => s.spawnCmd || s.label)\n .map((s: any) => ({\n id: s.id || randomUUID(),\n label: s.label || s.spawnCmd || '',\n command: [s.spawnCmd, ...(s.spawnArgs || [])].filter(Boolean).join(' '),\n ...(s.spawnOptions?.cwd ? { cwd: s.spawnOptions.cwd } : {}),\n })),\n autoRestart: false,\n restartBackoffMs: 1000,\n groups: legacy.groups || [],\n description: legacy.description || '',\n url: legacy.url || '',\n openapiUrl: legacy.openapiURL || '',\n git: {\n remote: legacy.git?.remote || '',\n home: legacy.git?.home || '',\n },\n env: {},\n envSecrets: [],\n parserIds,\n meta: legacy.meta || {},\n ...(port !== undefined ? { ports: [port] } : {}),\n };\n\n if (healthCheck) runeService.healthCheck = healthCheck;\n if (dockerConfig) runeService.dockerConfig = dockerConfig;\n\n runeServices.push(runeService);\n }\n\n // Service inline envs → service-scoped environments (shared base variables)\n // Legacy stores per-service env vars as: service.envs = { \"LOCAL\": { \"KEY\": { value, key } }, ... }\n // These are the shared/committed base values — processed FIRST so overrides can reference their variableIds\n for (const [name, legacy] of Object.entries(legacyServices)) {\n const serviceId = serviceIdMap[name];\n if (!serviceId) continue;\n const service = runeServices.find((s: any) => s.id === serviceId);\n const svcEnvs: Record<string, Record<string, any>> = legacy.envs || {};\n\n for (const [envName, vars] of Object.entries(svcEnvs)) {\n if (!vars || typeof vars !== 'object' || Object.keys(vars).length === 0) continue;\n const globalEnvId = envIdMap[envName];\n const globalEnv = runeEnvs.find((e: any) => e.id === globalEnvId);\n if (!globalEnvId || !globalEnv) continue;\n\n let svcScopedEnv = runeEnvs.find(\n (e: any) => e.scope === 'service' && e.reference === serviceId && e.activateOn === globalEnvId,\n );\n\n if (!svcScopedEnv) {\n svcScopedEnv = {\n id: randomUUID(),\n projectId: projectMonoId,\n name: `${service?.name || name} (${globalEnv.name})`,\n scope: 'service' as const,\n reference: serviceId,\n activateOn: globalEnvId,\n parentIds: [],\n variables: {} as Record<string, Variable>,\n description: '',\n immutable: false,\n default: false,\n };\n runeEnvs.push(svcScopedEnv);\n }\n\n const existingKeys = new Set(\n Object.values(svcScopedEnv.variables as Record<string, Variable>).map((v: Variable) => v.key),\n );\n for (const [, varData] of Object.entries(vars as Record<string, any>)) {\n const varKey: string = typeof varData === 'object' ? String(varData.key ?? '') : '';\n const varValue: string = typeof varData === 'object' ? String(varData.value ?? '') : String(varData ?? '');\n const varPre: string = typeof varData === 'object' ? String(varData.prefix ?? '') : '';\n const varPost: string = typeof varData === 'object' ? String(varData.suffix ?? '') : '';\n if (!varKey || existingKeys.has(cleanVarKey(varKey))) continue;\n const cleaned = cleanVarKey(varKey);\n const varId = randomUUID();\n svcScopedEnv.variables[varId] = makeVariable(cleaned, varValue, varPre, varPost);\n existingKeys.add(cleaned);\n }\n }\n }\n\n // Service overrides → environment-overrides.json (personal/local overrides)\n // Legacy *-envs.encrypted.json files are per-user overrides of service-level env vars.\n // Service-scoped environments share the same override mechanism as global environments,\n // so these go into environment-overrides.json keyed by variableId.\n // If the base variable doesn't exist yet (no entry in service.envs), it is created with an\n // empty value so the override has something to reference.\n const svcFlatOverrides: Record<string, Variable> = {};\n for (const [serviceName, envOverrides] of Object.entries(legacyServiceOverrides)) {\n const serviceId = serviceIdMap[serviceName];\n if (!serviceId) continue;\n const service = runeServices.find((s: any) => s.id === serviceId);\n\n for (const [envName, vars] of Object.entries(envOverrides as Record<string, Record<string, string>>)) {\n const globalEnvId = envIdMap[envName];\n const globalEnv = runeEnvs.find((e: any) => e.id === globalEnvId);\n if (!globalEnv || !vars || typeof vars !== 'object') continue;\n\n // Find or create the service-scoped env for this (service, globalEnv) pair\n let svcScopedEnv = runeEnvs.find(\n (e: any) => e.scope === 'service' && e.reference === serviceId && e.activateOn === globalEnvId,\n );\n if (!svcScopedEnv) {\n svcScopedEnv = {\n id: randomUUID(),\n projectId: projectMonoId,\n name: `${service?.name || serviceName} (${globalEnv.name})`,\n scope: 'service' as const,\n reference: serviceId,\n activateOn: globalEnvId,\n parentIds: [],\n variables: {} as Record<string, Variable>,\n description: '',\n immutable: false,\n default: false,\n };\n runeEnvs.push(svcScopedEnv);\n }\n\n for (const [key, value] of Object.entries(vars)) {\n if (typeof value !== 'string') continue;\n if (hasInvalidInterpolation(value)) continue;\n const cleaned = cleanVarKey(key);\n\n // Find the base variable in the service-scoped env by key name\n const baseEntry = Object.entries(svcScopedEnv.variables as Record<string, Variable>)\n .find(([, v]) => v.key === cleaned);\n let varId = baseEntry?.[0];\n\n if (!varId) {\n // No base variable exists — create an empty base so the override has something to reference\n varId = randomUUID();\n svcScopedEnv.variables[varId] = {\n key: cleaned,\n value: { value: '', pre: '', post: '', isSecret: false, shareWithAi: false, injectIntoAi: false, required: false, overrideOnly: false, description: '' },\n };\n }\n\n // Carry pre/post from the base variable — overrides only replace the value\n const basePre = baseEntry?.[1]?.value?.pre ?? '';\n const basePost = baseEntry?.[1]?.value?.post ?? '';\n // Skip redundant override — value identical to base\n if (isSameAsBase(value, baseEntry?.[1])) continue;\n svcFlatOverrides[varId] = makeVariable(cleaned, value, basePre, basePost);\n }\n }\n }\n\n // Environment overrides — from *-environment.encrypted.json files\n // Keys ending in _OVERRIDE → environment-overrides.json (flat Record<variableId, Variable>)\n // Other keys → merged into environment.variables (additional values)\n const flatOverrides: Record<string, Variable> = { ...svcFlatOverrides };\n for (const [envName, data] of Object.entries(legacyEnvOverrides)) {\n const envId = envIdMap[envName];\n const env = runeEnvs.find((e: any) => e.id === envId);\n if (!envId || !env || !data) continue;\n\n const envVars: Record<string, string> = (data as Record<string, unknown>).envs as Record<string, string> ?? {};\n\n for (const [key, value] of Object.entries(envVars)) {\n if (typeof value !== 'string') continue;\n\n if (key.endsWith('_OVERRIDE')) {\n // Strip all legacy suffixes → goes into environment-overrides.json\n const cleaned = cleanVarKey(key);\n const varId = varIdLookup.get(`${envId}:${cleaned}`);\n if (varId) {\n const baseVar = (env.variables as Record<string, Variable>)[varId];\n // Skip redundant override — value identical to base\n if (!isSameAsBase(value, baseVar)) {\n flatOverrides[varId] = makeVariable(cleaned, value);\n }\n } else {\n // Variable not found in env — create a new UUID entry\n flatOverrides[randomUUID()] = makeVariable(cleaned, value);\n }\n } else {\n // Regular variable → merge into environment.variables (with _RUNEYA stripped)\n const cleaned = cleanVarKey(key);\n // Check if this var already exists in env.variables (by key name)\n const existingVarId = Object.entries(env.variables as Record<string, Variable>)\n .find(([, v]) => v.key === cleaned)?.[0];\n if (!existingVarId) {\n const varId = randomUUID();\n env.variables[varId] = makeVariable(cleaned, value);\n varIdLookup.set(`${envId}:${cleaned}`, varId);\n }\n }\n }\n }\n\n // Projects — single project containing all services\n // Built AFTER service-scoped envs so allEnvIds includes them\n // Priority: explicit default flag → env named LOCAL → first env\n const localEnvName = Object.keys(legacyEnvs).find(n => n.toUpperCase() === 'LOCAL');\n const activeEnvId = defaultEnvName\n ? (envIdMap[defaultEnvName] ?? runeEnvs[0]?.id)\n : (localEnvName ? (envIdMap[localEnvName] ?? runeEnvs[0]?.id) : runeEnvs[0]?.id);\n const allEnvIds = runeEnvs.map(e => e.id);\n const allServiceIds = runeServices.map(s => s.id);\n\n const runeProjects: any[] = [];\n if (allServiceIds.length > 0 || allEnvIds.length > 0) {\n runeProjects.push({\n id: projectMonoId,\n orgId: null,\n name: 'Migrated Project',\n description: '',\n serviceIds: allServiceIds,\n environmentIds: allEnvIds,\n activeEnvironmentId: activeEnvId,\n });\n }\n\n const primaryProjectId = projectMonoId;\n for (const env of runeEnvs) {\n env.projectId = primaryProjectId;\n }\n\n // Settings — preserve existing + add migrated custom parsers\n let existingSettings: any = {};\n try {\n existingSettings = JSON.parse(await readFile(join(dataDir, 'settings.json'), 'utf-8'));\n } catch { /* first run */ }\n\n const migratedParsers = legacyParsers.map(p => ({\n id: p.id,\n name: p.label,\n // Legacy transform uses module.exports API — kept for reference, must be rewritten\n code: `// Migrated from legacy parser \"${p.label}\"\\n// TODO: rewrite using new API: (raw: string, stream: 'stdout'|'stderr') => ParseResult | null\\n// Legacy code (module.exports style — NOT compatible):\\n${p.transform ?? ''}`,\n enabled: false, // disabled until manually rewritten\n }));\n\n const newSettings = {\n ...existingSettings,\n logParsers: [\n ...(existingSettings.logParsers ?? []),\n ...migratedParsers,\n ],\n };\n\n // ── 5. Write output files ────────────────────────────────────────────────────\n await atomicWrite(join(dataDir, 'projects.json'), runeProjects);\n await atomicWrite(join(dataDir, 'services.json'), runeServices);\n await atomicWrite(join(dataDir, 'environments.json'), runeEnvs);\n await atomicWrite(join(dataDir, 'environment-overrides.json'), flatOverrides);\n await atomicWrite(join(dataDir, 'settings.json'), newSettings);\n\n const svcEnvCount = runeEnvs.filter((e: any) => e.scope === 'service').length;\n console.log(`[legacy-migration] Written: ${runeProjects.length} projects, ${runeServices.length} services, ${runeEnvs.length} environments (${svcEnvCount} service-scoped)`);\n console.log(`[legacy-migration] Overrides: ${Object.keys(flatOverrides).length}, custom parsers: ${migratedParsers.length} (all disabled — rewrite required)`);\n\n // Clear the main singleton so hasEncryptionKey() returns false → state = setup\n // Store the key in the pending holder for /api/setup to consume\n clearEncryptionKey();\n setPendingLegacyKey(keyBuffer);\n console.log('[legacy-migration] Done. Data migrated to .runeya — master password setup required');\n\n return true;\n}\n\n// ── Find legacy key in backup (restart between migration and setup) ─────────\n//\n// If the server restarts after runLegacyMigration but before /api/setup,\n// the pending key is lost (in-memory only). This function scans backup dirs\n// to recover the libsodium key so the user can still complete setup.\n\nexport async function findLegacyKeyInBackup(dataDir: string): Promise<Buffer | null> {\n try {\n const entries = await readdir(dataDir);\n // Comparateur par code-point (identique au tri par défaut) : on sélectionne\n // le backup le plus récent, l'ordre doit rester celui des noms backup-<ts>.\n const backupDirs = entries\n .filter(e => e.startsWith('backup-'))\n .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))\n .reverse();\n for (const dir of backupDirs) {\n const keyJsonPath = join(dataDir, dir, 'dbs', 'encryption-key.json');\n try {\n const raw = await readFile(keyJsonPath, 'utf-8');\n const parsed = JSON.parse(raw) as { encryptionKey?: string };\n if (!parsed.encryptionKey) continue;\n const sodium = await getSodium();\n const sodiumKey = sodium.from_base64(parsed.encryptionKey) as Uint8Array;\n const buf = Buffer.from(sodiumKey);\n if (buf.length === 32) {\n console.log(`[legacy-migration] Recovered legacy key from ${keyJsonPath}`);\n return buf;\n }\n } catch {\n // This backup dir doesn't have a valid key — try next\n }\n }\n } catch {\n // dataDir doesn't exist or isn't readable\n }\n return null;\n}\n\n// ── Override-only migration (User B scenario) ──────────────────────────────\n//\n// When the data dir is tracked by git and User A already ran the full migration:\n// - Git deleted dbs/encryption-key.json (was tracked)\n// - Git delivered the migrated JSON files (projects, services, environments…)\n// - But User B's dbs/overrides/*.encrypted.json are still on disk (gitignored)\n// - The full migration didn't trigger (no encryption-key.json)\n// - User B's overrides were never migrated → orphaned\n//\n// This function runs AFTER .encryption.key is available (same 32 bytes as\n// the legacy libsodium key, just in hex format). It decrypts User B's local\n// override files and writes environment-overrides.json.\n\nexport async function runOverrideOnlyMigration(dataDir: string): Promise<boolean> {\n // oxlint-disable-next-line typescript/unbound-method -- resolve is a pure module function from node:path, not a class method\n const { resolve } = await import('node:path');\n const abDataDir = resolve(dataDir);\n\n // Match the full migration: legacy data lives under the launch directory's\n // `.runeya`, which may differ from DATA_DIR when `--data-dir` was given.\n // Prefer the launch-directory path (the one git tracks), fall back to DATA_DIR.\n const candidateDirs = [\n join(dirname(env.DATA_DIR), '.runeya', 'dbs', 'overrides'),\n join(abDataDir, 'dbs', 'overrides'),\n ];\n\n let overridesDir: string | null = null;\n let overrideFiles: string[] = [];\n for (const dir of candidateDirs) {\n try {\n const files = (await readdir(dir)).filter(f => f.endsWith('.encrypted.json'));\n if (files.length > 0) {\n overridesDir = dir;\n overrideFiles = files;\n break;\n }\n } catch { /* dir doesn't exist */ }\n }\n if (!overridesDir || overrideFiles.length === 0) return false;\n\n // If the full migration trigger still exists, let the full migration handle it\n const legacyKeyPath = join(overridesDir, '..', 'encryption-key.json');\n try {\n await access(legacyKeyPath);\n return false; // Full migration should run instead\n } catch {\n // Expected — key was deleted by git\n }\n\n // We need .encryption.key to decrypt (it's the same 32 bytes)\n const encKey = getEncryptionKey();\n if (!encKey) {\n console.warn('[override-migration] Cannot migrate overrides: encryption key not loaded yet');\n return false;\n }\n\n console.log(`[override-migration] Found ${overrideFiles.length} orphaned override file(s) in ${overridesDir}, migrating…`);\n\n const sodium = await getSodium();\n // .encryption.key is the same 32 bytes as the legacy libsodium key\n const sodiumKey = new Uint8Array(encKey);\n\n // Load existing environments.json to build lookups\n const varIdLookup = new Map<string, string>();\n const envNameToId: Record<string, string> = {};\n let envsRaw: unknown[];\n try {\n envsRaw = JSON.parse(await readFile(join(abDataDir, 'environments.json'), 'utf-8')) as unknown[];\n for (const _env of envsRaw) {\n const env = _env as Record<string, unknown>;\n if (env['name'] && env['id']) {\n envNameToId[env['name'] as string] = env['id'] as string;\n }\n if (env['variables'] && env['id']) {\n for (const [varId, variable] of Object.entries(env['variables'] as Record<string, Variable>)) {\n varIdLookup.set(`${env['id'] as string}:${variable.key}`, varId);\n }\n }\n }\n } catch {\n console.warn('[override-migration] Cannot read environments.json — skipping');\n return false;\n }\n\n // Load services.json for service-override matching (legacy fileName → service name)\n let servicesRaw: unknown[] = [];\n const serviceNameToId: Record<string, string> = {};\n try {\n servicesRaw = JSON.parse(await readFile(join(abDataDir, 'services.json'), 'utf-8')) as unknown[];\n for (const _svc of servicesRaw) {\n const svc = _svc as Record<string, unknown>;\n if (svc['name'] && svc['id']) serviceNameToId[svc['name'] as string] = svc['id'] as string;\n }\n } catch { /* services.json missing — service overrides won't match */ }\n\n // Helper: find env ID by name (exact or case-insensitive)\n function findEnvId(name: string): string | undefined {\n return envNameToId[name]\n ?? Object.entries(envNameToId).find(([n]) => n.toLowerCase() === name.toLowerCase())?.[1];\n }\n\n // ── 1. Environment overrides (*-environment.encrypted.json) → environment-overrides.json ──\n const flatOverrides: Record<string, Variable> = {};\n\n for (const file of overrideFiles) {\n const baseName = file.replace('.encrypted.json', '');\n if (!baseName.endsWith('-environment')) continue;\n const envName = baseName.slice(0, -'-environment'.length);\n\n let data: any;\n try {\n data = await decryptLegacyFile(join(overridesDir, file), sodiumKey, sodium);\n } catch (err: unknown) {\n console.warn(`[override-migration] Failed to decrypt ${file}: ${(err as Error).message}`);\n continue;\n }\n if (!data) continue;\n\n const envId = findEnvId(envName);\n if (!envId) {\n console.warn(`[override-migration] No matching environment for \"${envName}\" — skipping`);\n continue;\n }\n\n const envVars: Record<string, string> = data.envs ?? {};\n for (const [key, value] of Object.entries(envVars)) {\n if (typeof value !== 'string') continue;\n if (!key.endsWith('_OVERRIDE')) continue;\n\n const cleaned = cleanVarKey(key);\n const varId = varIdLookup.get(`${envId}:${cleaned}`);\n if (varId) {\n const baseVar = ((envsRaw as Record<string, unknown>[]).find((e) => e['id'] === envId)?.['variables'] as Record<string, Variable> | undefined)?.[varId];\n // Skip redundant override — value identical to base\n if (isSameAsBase(value, baseVar)) continue;\n flatOverrides[varId] = makeVariable(cleaned, value);\n } else {\n flatOverrides[randomUUID()] = makeVariable(cleaned, value);\n }\n }\n }\n\n if (Object.keys(flatOverrides).length > 0) {\n await atomicWrite(join(abDataDir, 'environment-overrides.json'), flatOverrides);\n console.log(`[override-migration] Written ${Object.keys(flatOverrides).length} override(s) to environment-overrides.json`);\n }\n\n // ── 2. Service overrides (*-envs.encrypted.json) → environment-overrides.json ──\n // Service-scoped environments share the same override mechanism as global environments.\n // Personal service variable overrides go into environment-overrides.json (keyed by variableId).\n // If the base variable doesn't exist in the service-scoped env, an empty base is created first.\n let envsModified = false;\n\n for (const file of overrideFiles) {\n const baseName = file.replace('.encrypted.json', '');\n if (!baseName.endsWith('-envs')) continue;\n const serviceName = baseName.slice(0, -'-envs'.length);\n\n let data: any;\n try {\n data = await decryptLegacyFile(join(overridesDir, file), sodiumKey, sodium);\n } catch (err: unknown) {\n console.warn(`[override-migration] Failed to decrypt ${file}: ${(err as Error).message}`);\n continue;\n }\n if (!data || typeof data !== 'object') continue;\n\n // Find service ID: try by legacy filename, then case-insensitive name match\n const serviceId = serviceNameToId[serviceName]\n ?? Object.entries(serviceNameToId).find(([n]) => n.toLowerCase() === serviceName.toLowerCase())?.[1];\n if (!serviceId) {\n console.warn(`[override-migration] No matching service for \"${serviceName}\" — skipping service overrides`);\n continue;\n }\n\n const service = (servicesRaw as Record<string, unknown>[]).find((s) => s['id'] === serviceId);\n\n for (const [envName, vars] of Object.entries(data as Record<string, Record<string, string>>)) {\n const globalEnvId = findEnvId(envName);\n if (!globalEnvId || !vars || typeof vars !== 'object') continue;\n const globalEnv = (envsRaw as Record<string, unknown>[]).find((e) => e['id'] === globalEnvId);\n if (!globalEnv) continue;\n\n // Find or create the service-scoped env for this (service, globalEnv) pair\n let svcScopedEnv = (envsRaw as Record<string, unknown>[]).find(\n (e) => e['scope'] === 'service' && e['reference'] === serviceId && e['activateOn'] === globalEnvId,\n );\n if (!svcScopedEnv) {\n svcScopedEnv = {\n id: randomUUID(),\n projectId: globalEnv['projectId'],\n name: `${(service?.['name'] as string | undefined) || serviceName} (${globalEnv['name'] as string})`,\n scope: 'service' as const,\n reference: serviceId,\n activateOn: globalEnvId,\n parentIds: [],\n variables: {} as Record<string, Variable>,\n description: '',\n immutable: false,\n default: false,\n };\n envsRaw.push(svcScopedEnv);\n envsModified = true;\n }\n\n for (const [key, value] of Object.entries(vars)) {\n if (typeof value !== 'string') continue;\n if (hasInvalidInterpolation(value)) continue;\n const cleaned = cleanVarKey(key);\n\n // Find the base variable in the service-scoped env by key name\n const baseEntry = Object.entries(svcScopedEnv['variables'] as Record<string, Variable>)\n .find(([, v]) => v.key === cleaned);\n let varId = baseEntry?.[0];\n\n if (!varId) {\n // No base variable — create an empty base so the override has something to reference\n varId = randomUUID();\n (svcScopedEnv['variables'] as Record<string, Variable>)[varId] = {\n key: cleaned,\n value: { value: '', pre: '', post: '', isSecret: false, shareWithAi: false, injectIntoAi: false, required: false, overrideOnly: false, description: '' },\n };\n envsModified = true;\n }\n\n // Carry pre/post from the base variable — overrides only replace the value\n const basePre = baseEntry?.[1]?.value?.pre ?? '';\n const basePost = baseEntry?.[1]?.value?.post ?? '';\n // Skip redundant override — value identical to base\n if (isSameAsBase(value, baseEntry?.[1])) continue;\n flatOverrides[varId] = makeVariable(cleaned, value, basePre, basePost);\n }\n }\n }\n\n if (envsModified) {\n await atomicWrite(join(abDataDir, 'environments.json'), envsRaw);\n console.log('[override-migration] Merged service overrides into environments.json');\n }\n\n // Move dbs/overrides/ → dbs/overrides-migrated/ to prevent re-running\n const migratedDir = overridesDir.replace(/overrides$/, 'overrides-migrated');\n try {\n await rename(overridesDir, migratedDir);\n console.log(`[override-migration] Moved overrides/ → overrides-migrated/`);\n } catch (err: unknown) {\n console.warn(`[override-migration] Could not rename overrides dir: ${(err as Error).message}`);\n }\n\n console.log('[override-migration] Done');\n return true;\n}\n","import { join } from 'node:path';\nimport { stat } from 'node:fs/promises';\nimport { hasEncryptionKey, hasPendingLegacyKey } from '../utils/encryption-key.js';\nimport { keyRoot, legacyVaultRoot } from './vault-resolver.js';\n\nexport type ServerState = 'locked' | 'setup' | 'unlocked';\n\nconst ENCRYPTED_KEY_FILENAME = '.encryption.key.enc';\nconst VERIFY_FILENAME = '.runeya-verify';\n\nexport interface ServerStatus {\n state: ServerState;\n hasVerifyFile: boolean;\n isLegacyMigration: boolean;\n hasExistingData: boolean;\n /**\n * A launch directory still sealed under a master password of its own.\n *\n * Reported only once unlocked: the migration asks for the OLD password, which\n * would be one question too many on a screen that is already asking for the\n * machine one.\n */\n legacyVault: string | null;\n}\n\nexport async function getServerState(): Promise<ServerStatus> {\n // The key and its canary answer for the whole machine, so the server's\n // locked/setup state follows them, not the directory it was started in.\n const dataDir = await keyRoot();\n\n let hasEncFile = false;\n let hasVerify = false;\n let hasData = false;\n\n try { await stat(join(dataDir, ENCRYPTED_KEY_FILENAME)); hasEncFile = true; } catch {}\n try { await stat(join(dataDir, VERIFY_FILENAME)); hasVerify = true; } catch {}\n try { await stat(join(dataDir, 'projects.json')); hasData = true; } catch {}\n try { await stat(join(dataDir, 'project.json')); hasData = true; } catch {}\n\n if (hasEncryptionKey()) {\n return {\n state: 'unlocked',\n hasVerifyFile: false,\n isLegacyMigration: false,\n hasExistingData: hasData,\n legacyVault: await legacyVaultRoot(),\n };\n }\n\n if (hasEncFile) {\n return { state: 'locked', hasVerifyFile: hasVerify, isLegacyMigration: false, hasExistingData: hasData, legacyVault: null };\n }\n\n // SETUP state — legacy migration detected via in-memory pending key holder\n return {\n state: 'setup',\n hasVerifyFile: hasVerify,\n isLegacyMigration: hasPendingLegacyKey(),\n hasExistingData: hasData,\n legacyVault: null,\n };\n}\n","import { env } from '../config/env.js';\n\nconst BASE = `http://localhost:${env.PORT}/api/trpc`;\n\nexport function getOpenApiDocument() {\n return {\n openapi: '3.1.0',\n info: {\n title: 'Runeya API',\n version: '1.0.0',\n description: 'Runeya service management API — tRPC over HTTP.\\n\\n**Queries** use `GET /{procedure}?input={json}`.\\n**Mutations** use `POST /{procedure}` with a JSON body.\\n\\nAll protected routes require `Authorization: Bearer <jwt>` header.',\n },\n servers: [{ url: BASE }],\n paths: {\n '/health.check': {\n get: {\n tags: ['Health'],\n summary: 'Health check',\n operationId: 'health.check',\n responses: {\n '200': { description: 'Server is up', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { type: 'object', properties: { status: { type: 'string', example: 'ok' }, uptime: { type: 'number' } } } } } } } } } },\n },\n },\n },\n '/service.list': {\n get: {\n tags: ['Services'],\n summary: 'List services (every project of the machine unless narrowed)',\n operationId: 'service.list',\n security: [{ BearerAuth: [] }],\n parameters: [{\n name: 'input',\n in: 'query',\n required: false,\n schema: { type: 'string' },\n example: '{\"projectId\":\"<projectId>\"}',\n description: 'JSON-encoded input, optional: `{\"projectId\":\"<projectId>\",\"orgId\":\"<orgId>\"}`. Omitted, the response covers every project of every organization on this machine.',\n }],\n responses: {\n '200': { description: 'Array of services', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { type: 'array', items: { $ref: '#/components/schemas/Service' } } } } } } } } },\n },\n },\n },\n '/service.get': {\n get: {\n tags: ['Services'],\n summary: 'Get a service by ID',\n operationId: 'service.get',\n security: [{ BearerAuth: [] }],\n parameters: [{\n name: 'input',\n in: 'query',\n required: true,\n schema: { type: 'string' },\n example: '{\"id\":\"<serviceId>\"}',\n description: 'JSON-encoded input: `{\"id\":\"<serviceId>\"}`',\n }],\n responses: {\n '200': { description: 'Service object', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { $ref: '#/components/schemas/Service' } } } } } } } },\n },\n },\n },\n '/service.create': {\n post: {\n tags: ['Services'],\n summary: 'Create a new service',\n operationId: 'service.create',\n security: [{ BearerAuth: [] }],\n requestBody: {\n required: true,\n content: { 'application/json': { schema: { type: 'object', required: ['agentId', 'name'], properties: {\n agentId: { type: 'string' },\n name: { type: 'string' },\n commands: { type: 'array', items: { type: 'object' } },\n cwd: { type: 'string' },\n port: { type: 'integer' },\n description: { type: 'string' },\n url: { type: 'string' },\n runner: { type: 'string', enum: ['native', 'docker'], default: 'native' },\n } } } },\n },\n responses: {\n '200': { description: 'Created service', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { $ref: '#/components/schemas/Service' } } } } } } } },\n },\n },\n },\n '/service.update': {\n post: {\n tags: ['Services'],\n summary: 'Update a service',\n operationId: 'service.update',\n security: [{ BearerAuth: [] }],\n requestBody: {\n required: true,\n content: { 'application/json': { schema: { type: 'object', required: ['id'], properties: {\n id: { type: 'string' },\n name: { type: 'string' },\n commands: { type: 'array', items: { type: 'object' } },\n cwd: { type: 'string' },\n port: { type: 'integer' },\n description: { type: 'string' },\n url: { type: 'string' },\n } } } },\n },\n responses: {\n '200': { description: 'Updated service', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { $ref: '#/components/schemas/Service' } } } } } } } },\n },\n },\n },\n '/service.delete': {\n post: {\n tags: ['Services'],\n summary: 'Delete a service',\n operationId: 'service.delete',\n security: [{ BearerAuth: [] }],\n requestBody: {\n required: true,\n content: { 'application/json': { schema: { type: 'object', required: ['id'], properties: { id: { type: 'string' } } } } },\n },\n responses: {\n '200': { description: 'Deletion result', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { type: 'object', properties: { success: { type: 'boolean' } } } } } } } } } },\n },\n },\n },\n '/process.list': {\n get: {\n tags: ['Processes'],\n summary: 'List all processes across all connected agents',\n operationId: 'process.list',\n security: [{ BearerAuth: [] }],\n responses: {\n '200': { description: 'Array of processes', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { type: 'array', items: { $ref: '#/components/schemas/Process' } } } } } } } } },\n },\n },\n },\n '/process.get': {\n get: {\n tags: ['Processes'],\n summary: 'Get a process by agent and service ID',\n operationId: 'process.get',\n security: [{ BearerAuth: [] }],\n parameters: [{\n name: 'input',\n in: 'query',\n required: true,\n schema: { type: 'string' },\n example: '{\"agentId\":\"<agentId>\",\"id\":\"<serviceId>\"}',\n description: 'JSON-encoded input: `{\"agentId\":\"<agentId>\",\"id\":\"<serviceId>\"}`',\n }],\n responses: {\n '200': { description: 'Process object' },\n },\n },\n },\n '/process.logs': {\n get: {\n tags: ['Processes'],\n summary: 'Get buffered logs for a process',\n operationId: 'process.logs',\n security: [{ BearerAuth: [] }],\n parameters: [{\n name: 'input',\n in: 'query',\n required: true,\n schema: { type: 'string' },\n example: '{\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}',\n description: 'JSON-encoded input: `{\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}`',\n }],\n responses: {\n '200': { description: 'Array of log lines' },\n },\n },\n },\n '/process.start': {\n post: {\n tags: ['Processes'],\n summary: 'Start a process',\n operationId: 'process.start',\n security: [{ BearerAuth: [] }],\n requestBody: {\n required: true,\n content: { 'application/json': { schema: { type: 'object', required: ['agentId', 'processId'], properties: {\n agentId: { type: 'string' },\n processId: { type: 'string' },\n } } } },\n },\n responses: {\n '200': { description: 'Start result' },\n },\n },\n },\n '/process.stop': {\n post: {\n tags: ['Processes'],\n summary: 'Stop a process',\n operationId: 'process.stop',\n security: [{ BearerAuth: [] }],\n requestBody: {\n required: true,\n content: { 'application/json': { schema: { type: 'object', required: ['agentId', 'processId'], properties: {\n agentId: { type: 'string' },\n processId: { type: 'string' },\n } } } },\n },\n responses: {\n '200': { description: 'Stop result' },\n },\n },\n },\n '/process.restart': {\n post: {\n tags: ['Processes'],\n summary: 'Restart a process',\n operationId: 'process.restart',\n security: [{ BearerAuth: [] }],\n requestBody: {\n required: true,\n content: { 'application/json': { schema: { type: 'object', required: ['agentId', 'processId'], properties: {\n agentId: { type: 'string' },\n processId: { type: 'string' },\n } } } },\n },\n responses: {\n '200': { description: 'Restart result' },\n },\n },\n },\n '/environment.resolveFlat': {\n get: {\n tags: ['Environments'],\n summary: 'Resolve environment variables as a flat key-value map',\n operationId: 'environment.resolveFlat',\n security: [{ BearerAuth: [] }],\n parameters: [{\n name: 'input',\n in: 'query',\n required: true,\n schema: { type: 'string' },\n example: '{\"environmentId\":\"<environmentId>\"}',\n description: 'JSON-encoded input: `{\"environmentId\":\"<environmentId>\"}`',\n }],\n responses: {\n '200': { description: 'Flat key-value map of resolved variables', content: { 'application/json': { schema: { type: 'object', properties: { result: { type: 'object', properties: { data: { type: 'object', additionalProperties: { type: 'string' } } } } } } } } },\n },\n },\n },\n },\n components: {\n securitySchemes: {\n BearerAuth: { type: 'http', scheme: 'bearer', description: 'JWT token from /api/unlock or /api/setup' },\n },\n schemas: {\n Service: {\n type: 'object',\n properties: {\n id: { type: 'string' },\n name: { type: 'string' },\n agentId: { type: 'string' },\n commands: { type: 'array', items: { type: 'object' } },\n cwd: { type: 'string' },\n port: { type: 'integer' },\n description: { type: 'string' },\n url: { type: 'string' },\n runner: { type: 'string', enum: ['native', 'docker'] },\n },\n },\n Process: {\n type: 'object',\n properties: {\n id: { type: 'string' },\n agentId: { type: 'string' },\n state: { type: 'string', enum: ['stopped', 'starting', 'running', 'stopping', 'errored'] },\n pid: { type: 'integer', nullable: true },\n exitCode: { type: 'integer', nullable: true },\n },\n },\n },\n },\n };\n}\n","import { imageStorageService } from './image-storage.service.js';\n\nexport class ImageCleanupService {\n private timer: ReturnType<typeof setInterval> | null = null;\n\n async runCleanup(): Promise<{ deleted: number; errors: number }> {\n const expired = await imageStorageService.listExpiredImages();\n let deleted = 0;\n let errors = 0;\n await Promise.all(\n expired.map(async (img) => {\n try {\n await imageStorageService.deleteImage(img.imageId);\n deleted++;\n } catch {\n errors++;\n }\n }),\n );\n return { deleted, errors };\n }\n\n start(intervalMs = 60 * 60 * 1000): void {\n if (this.timer) return;\n this.runCleanup().catch((err) => console.error('[image-cleanup] error:', err));\n this.timer = setInterval(() => {\n this.runCleanup().catch((err) => console.error('[image-cleanup] error:', err));\n }, intervalMs);\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n}\n\nexport const imageCleanupService = new ImageCleanupService();\n","import type { Server } from 'node:http';\nimport type { WebSocketServer } from 'ws';\nimport { env } from './config/env.js';\nimport { createLocalServer } from './create-server.js';\nimport { shutdownCodexAppServer } from './services/ai-runners/codex-runner.js';\nimport { resolve as resolvePath } from 'node:path';\nimport dotenv from 'dotenv'\ndotenv.config({ quiet: true })\n\n// Align cwd with the parent of RUNEYA_DATA_DIR when set, so spawned services\n// resolve relative cwds against the user's stack root rather than the server's own dir.\nif (process.env['RUNEYA_DATA_DIR']) {\n const resolved = resolvePath(process.env['RUNEYA_DATA_DIR'], '..');\n process.chdir(resolved);\n console.log(`[server] Working directory: ${resolved} (from RUNEYA_DATA_DIR)`);\n}\n\n// Re-export for CLI usage\nexport { createLocalServer } from './create-server.js';\nexport type { ServerInstance } from './create-server.js';\nexport { pullEnv, PullEnvError } from './commands/pull-env.js';\n// Announced by the CLI once the port is actually bound — a record written\n// before that could advertise a port this instance never got.\nexport { registerInstance } from './services/instance-registry.js';\n// Lecture et pilotage du registre machine, pour les façades qui n'ont pas de\n// serveur derrière elles : la sous-commande `runeya instances` et la barre\n// système. Même source que le routeur tRPC `diagnostics` — une seule\n// implémentation, trois façades.\nexport { listInstances, killInstance, restartInstance } from './services/instance-registry.js';\n// Le redémarrage de soi-même : posé par le routeur tRPC comme par l'icône de\n// barre système, qui appartient au processus qu'elle redémarre.\nexport { scheduleSelfRestart } from './services/instance-registry.js';\n// Ce que l'icône de barre système pilote : les services de cette instance, et\n// le mode réseau local. Le CLI n'a ainsi à connaître ni l'agent, ni le store.\nexport { listTrayServices, onTrayServicesChanged } from './services/tray-services.js';\n// Le logo de l'organisation du projet ouvert, pour l'icône de barre système.\nexport { resolveTrayIcon } from './services/tray-icon.js';\nexport type { TrayService } from './services/tray-services.js';\nexport { startProcess, stopProcess, restartProcess } from './services/process-control.js';\nexport { networkInfo, setLanMode } from './services/lan-mode.js';\n// Où le CLI se trouve, pour que le serveur puisse rejouer `install-desktop` et\n// créer un raccourci de bureau depuis l'interface.\nexport { registerCli as registerCliLocation } from './services/desktop-launcher.js';\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(`[server] 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 // Même garantie que côté CLI, pour un serveur démarré seul : le PATH d'une\n // session graphique ignore les binaires installés par l'utilisateur.\n const { ensureNodeBinOnPath, ensureUserBinsOnPath } = await import('@runeya/packages-shared/node');\n ensureNodeBinOnPath();\n await ensureUserBinsOnPath();\n\n console.log('Hello World 2');\n // oxlint-disable-next-line typescript/unbound-method -- shutdown is a standalone closure returned by createLocalServer, not a class method\n const { server, wss, shutdown } = await createLocalServer();\n\n await listenWithRetry(server, env.PORT, env.HOST, wss);\n console.log(`[server] Local server listening on ${env.HOST}:${env.PORT}`);\n console.log(`[server] tRPC HTTP: http://${env.HOST}:${env.PORT}/api/trpc`);\n console.log(`[server] tRPC WS: ws://${env.HOST}:${env.PORT}`); // nosemgrep:javascript.lang.security.detect-insecure-websocket.detect-insecure-websocket\n console.log(`[server] Mode: ${env.MODE}`);\n if (env.RUNEYA_LAN_PROXY) {\n console.log('[server] LAN mode: server exposed on local network (0.0.0.0)');\n console.log('[server] LAN mode: {{service.HOST}} resolves to 0.0.0.0 — configure your services accordingly');\n }\n\n let shuttingDown = false;\n const gracefulShutdown = async (signal: string) => {\n if (shuttingDown) {\n console.log(`[server] Forced exit (second ${signal})`);\n process.exit(1);\n }\n shuttingDown = true;\n console.log(`[server] 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 shutdownCodexAppServer();\n await shutdown();\n process.exit(0);\n };\n\n process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));\n process.on('SIGINT', () => gracefulShutdown('SIGINT'));\n}\n\n// Only run main if this file is executed directly (not imported)\nif (import.meta.url === `file://${process.argv[1]}`) {\n main().catch((err) => {\n console.error('[server] Fatal error:', err);\n process.exit(1);\n });\n}\n","import { serviceStore } from '../services/service-store.js';\nimport { environmentStore } from '../services/environment-store.js';\nimport { environmentResolver } from '../services/environment-resolver.js';\nimport { ensureEncryptionKey, hasEncryptionKey, loadFromEnv, setEncryptionKeyInMemory } from '../utils/encryption-key.js';\nimport { readEncryptedKey, hasEncryptedKeyFile } from '../services/master-password.js';\nimport { env as serverEnv } from '../config/env.js';\n\nexport class PullEnvError extends Error {\n constructor(\n message: string,\n public readonly exitCode: number,\n ) {\n super(message);\n this.name = 'PullEnvError';\n }\n}\n\nasync function promptPassword(): Promise<string> {\n process.stderr.write('Master password: ');\n return new Promise((resolve) => {\n const stdin = process.stdin;\n const wasRaw = stdin.isRaw;\n if (stdin.isTTY) stdin.setRawMode(true);\n stdin.resume();\n stdin.setEncoding('utf-8');\n let input = '';\n const onData = (ch: string) => {\n if (ch === '\\r' || ch === '\\n') {\n if (stdin.isTTY) stdin.setRawMode(wasRaw ?? false);\n stdin.pause();\n stdin.removeListener('data', onData);\n process.stderr.write('\\n');\n resolve(input);\n } else if (ch === '\\u0003') {\n // Ctrl+C\n process.exit(1);\n } else if (ch === '\\u007f' || ch === '\\b') {\n input = input.slice(0, -1);\n } else {\n input += ch;\n }\n };\n stdin.on('data', onData);\n });\n}\n\nasync function unlockIfNeeded(): Promise<void> {\n // Call ensureEncryptionKey first (allows tests to mock it)\n await ensureEncryptionKey();\n if (hasEncryptionKey()) return;\n\n // CI mode: RUNEYA_ENCRYPTION_KEY env var\n if (await loadFromEnv()) return;\n\n // Check if encrypted key file exists (i.e. setup was completed)\n if (!(await hasEncryptedKeyFile(serverEnv.DATA_DIR))) {\n // No encryption key file — either fresh install or test environment; proceed without encryption\n return;\n }\n\n // Try RUNEYA_MASTER_PASSWORD env var, then prompt\n const masterPassword = process.env['RUNEYA_MASTER_PASSWORD'] || await promptPassword();\n if (!masterPassword) {\n throw new PullEnvError('Master password required to decrypt data', 1);\n }\n\n try {\n const encKey = await readEncryptedKey(serverEnv.DATA_DIR, masterPassword);\n setEncryptionKeyInMemory(encKey);\n } catch {\n throw new PullEnvError('Master password incorrect', 1);\n }\n}\n\n/**\n * Resolve env vars for a service+environment and return them as KEY=VALUE lines.\n * Throws PullEnvError if the service or environment is not found.\n */\nexport async function pullEnv(opts: { service: string; environment: string }): Promise<string> {\n await unlockIfNeeded();\n\n const services = await serviceStore.list();\n const service = services.find(\n (s) => s.id === opts.service || s.name === opts.service,\n );\n if (!service) {\n const available = services.map((s) => s.name).join(', ');\n throw new PullEnvError(`service \"${opts.service}\" not found. Available: ${available || '(none)'}`, 1);\n }\n\n const globalEnvs = await environmentStore.listAllGlobal();\n const globalEnv = globalEnvs.find(\n (e) => e.id === opts.environment || e.name === opts.environment,\n );\n if (!globalEnv) {\n const available = globalEnvs.map((e) => e.name).join(', ');\n throw new PullEnvError(`environment \"${opts.environment}\" not found. Available: ${available || '(none)'}`, 1);\n }\n\n const { env } = await environmentResolver.resolveForService({\n serviceId: service.id,\n activeEnvironmentId: globalEnv.id,\n });\n\n return Object.entries(env)\n .map(([key, value]) => `${key}=${value}`)\n .join('\\n');\n}\n","/**\n * Ce que l'icône de barre système doit savoir des services de cette instance.\n *\n * Le tray vit dans le processus du CLI, qui ne connaît ni `serviceStore` ni\n * `agentManager` : cette vue assemble les deux et n'expose que le nécessaire —\n * un nom, un état, une adresse. Elle ne décide de rien, elle décrit.\n *\n * L'état est poussé, jamais sondé : le pont de l'agent relaie déjà\n * `process.onStatus` en événement `process:status`, et `serviceStore` prévient\n * de ses propres changements. Un menu qui se rafraîchit sur ces deux signaux\n * est à jour sans qu'aucune horloge ne tourne.\n */\nimport { primaryServiceLink } from '@runeya/packages-shared';\nimport { onVaultUnlocked } from '../utils/encryption-key.js';\nimport { agentManager } from './agent-manager.js';\nimport { serviceStore } from './service-store.js';\nimport { projectStore } from './project-store.js';\nimport { listAllProcesses } from './process-control.js';\nimport { getCurrentProject, onCurrentProjectChanged } from './current-project.js';\nimport { onTrayAccentChanged } from './tray-accent.js';\n\n/** Un service, tel qu'une ligne de menu a besoin de le connaître. */\nexport type TrayService = {\n id: string;\n name: string;\n /** L'agent qui le fait tourner, quand il en a un — requis pour l'arrêter. */\n agentId: string | null;\n running: boolean;\n /**\n * En échec : le processus s'est arrêté sur une erreur, ou sa sonde de santé\n * le déclare malade. C'est ce qui fait passer l'icône en alerte.\n */\n failed: boolean;\n /** Première adresse à laquelle il répond, ou null s'il n'en expose aucune. */\n url: string | null;\n};\n\n/**\n * Les services à montrer, et leur état courant.\n *\n * Deux régimes, parce que la question n'est pas la même :\n *\n * - **Un projet est ouvert** : tous ses services, y compris ceux à l'arrêt.\n * C'est là qu'on vient les démarrer, et un service absent du menu ne se\n * démarre pas depuis le menu.\n * - **Aucun projet ouvert** : seulement ce qui tourne ou ce qui est tombé. La\n * machine peut en compter des centaines, tous projets confondus ; les lister\n * ferait un menu que personne ne parcourt, pour une question — « lequel\n * démarrer ? » — que personne ne pose sans avoir d'abord choisi un projet.\n *\n * L'hôte est toujours `localhost` : cette liste ne sert qu'à l'icône du poste,\n * qui ouvre un navigateur sur cette machine. Les adresses de réseau local\n * appartiennent à l'interface, qui sait pour qui elle les affiche.\n */\nexport async function listTrayServices(): Promise<TrayService[]> {\n const [all, processes] = await Promise.all([serviceStore.list(), listAllProcesses()]);\n const byServiceId = new Map(processes.map((p) => [p.serviceId, p]));\n\n const services = all.map((service): TrayService => {\n const status = byServiceId.get(service.id);\n return {\n id: service.id,\n name: service.name,\n agentId: status?.agentId ?? service.agentId ?? null,\n running: status?.state === 'running' || status?.state === 'starting',\n failed: status?.state === 'errored' || status?.healthStatus === 'unhealthy',\n url: primaryServiceLink(service, 'localhost'),\n };\n });\n\n const owned = await currentProjectServiceIds();\n if (owned) return services.filter((service) => owned.has(service.id));\n\n // Ni lancé ni en échec : jamais démarré, ou arrêté et sans rien à en dire.\n // L'agent n'apprend un service qu'à son premier démarrage — un service que\n // personne n'a jamais lancé n'a donc aucun état à montrer.\n return services.filter((service) => service.running || service.failed);\n}\n\n/**\n * Les services du projet regardé, ou `null` quand il n'y en a pas à quoi se\n * référer — aucun onglet ne l'a annoncé, ou le projet annoncé est introuvable\n * (le cas d'un projet du cloud que cette machine n'a pas encore récupéré).\n */\nasync function currentProjectServiceIds(): Promise<Set<string> | null> {\n const ref = getCurrentProject();\n if (!ref) return null;\n\n const project = await projectStore.get(ref);\n if (!project) return null;\n\n return new Set(project.serviceIds);\n}\n\n/**\n * Prévient quand cette liste a pu changer — état d'un process, ou\n * configuration des services.\n *\n * Ne dit pas ce qui a changé : l'appelant reconstruit sa vue entière, qui ne\n * peut alors pas diverger de la réalité. Rend de quoi se désabonner.\n */\nexport function onTrayServicesChanged(listener: () => void): () => void {\n const onStatus = (): void => listener();\n agentManager.on('process:status', onStatus);\n const offServices = serviceStore.onChange(onStatus);\n // Le déverrouillage, sans quoi une icône posée au démarrage resterait sur sa\n // vue vide : au premier lancement comme après un mot de passe maître, les\n // services ne sont lisibles qu'après.\n const offUnlock = onVaultUnlocked(onStatus);\n // Changer de projet change la liste sans qu'aucun service ne bouge.\n const offProject = onCurrentProjectChanged(onStatus);\n // Changer de thème ne change aucune ligne du menu — mais l'icône, si. Ce\n // signal est le seul que la barre système écoute : tout ce qui la redessine\n // passe par ici, sous peine de n'être vu qu'au prochain démarrage de service.\n const offAccent = onTrayAccentChanged(onStatus);\n\n return () => {\n agentManager.off('process:status', onStatus);\n offServices();\n offUnlock();\n offAccent();\n offProject();\n };\n}\n","/**\n * L'icône de barre système : celle de l'organisation du projet ouvert, à\n * défaut celle de Runeya.\n *\n * Une machine fait tourner plusieurs Runeya, et toutes posent la même icône.\n * Le logo de l'organisation est ce qui les distingue d'un coup d'œil, et il\n * existe déjà — le cloud le sert sur `/api/org-logo/<orgId>`, sans session,\n * précisément pour qu'une vignette n'ait pas à négocier un accès.\n *\n * Ce service ne fait que le ramener sur le disque, dans la forme que la barre\n * système attend : un PNG partout, un ICO sous Windows. Tout ce qui échoue —\n * pas de cloud, pas d'organisation, pas de logo, format inattendu — rend\n * `null`, et l'appelant garde l'icône de Runeya. Une icône est un agrément :\n * rien ici ne doit empêcher une Runeya de tourner.\n */\nimport { mkdir, writeFile, rename } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { orgCloudUrl } from './cloud-api.js';\nimport { readOrgLogo } from './vault-resolver.js';\nimport { getCurrentProject } from './current-project.js';\nimport { machineRoot } from './vault-resolver.js';\nimport { pngToIco, isPng } from './png-to-ico.js';\nimport { getTrayAccent } from './tray-accent.js';\nimport { renderRuneyaIcon } from './runeya-icon.js';\n\n/** Au-delà, ce n'est plus une vignette : on renonce plutôt que de tout charger. */\nconst MAX_LOGO_BYTES = 1024 * 1024;\n\n/** Le cloud est joignable ou il ne l'est pas ; une icône n'attend pas. */\nconst FETCH_TIMEOUT_MS = 3_000;\n\n/**\n * Un logo par organisation, retenu un moment.\n *\n * Pas pour la vie du process : un logo d'organisation se change depuis le\n * cloud, et une icône figée jusqu'au prochain redémarrage serait un défaut que\n * personne ne saurait expliquer. Pas à chaque dessin non plus — le menu se\n * redessine à chaque changement d'état d'un service.\n */\nconst CACHE_TTL_MS = 10 * 60_000;\nconst cache = new Map<string, { path: string | null; at: number }>();\n\n/** Le dossier des icônes rapatriées, dans la racine machine. */\nexport function trayIconDir(): string {\n return join(machineRoot(), 'tray-icons');\n}\n\n/**\n * Le logo de l'organisation du projet ouvert, prêt à être posé dans la barre\n * système — ou `null` s'il n'y en a pas.\n *\n * Les octets sont d'abord cherchés dans le coffre : l'interface les y a déjà\n * rapatriés pour s'afficher hors ligne (`cacheOrgLogos`), et les redemander au\n * réseau pour la même image serait le travail d'un doublon.\n *\n * Le format est demandé, pas négocié : `systray2` ne lit que le PNG (et l'ICO\n * sous Windows, fabriqué ici), tandis que la page d'organisation enregistre en\n * JPEG. Le cloud convertit — c'est lui qui a le décodeur d'images ; en ajouter\n * un ici est exclu, le CLI s'installant par npm, où les paquets à script\n * d'installation ne se construisent pas.\n *\n * Les octets reçus sont malgré tout vérifiés : une conversion ratée ou une\n * route plus ancienne rendrait autre chose qu'un PNG, et la barre système n'en\n * dirait rien — elle afficherait une icône vide.\n */\nexport async function resolveTrayIcon(\n platform: NodeJS.Platform = process.platform,\n): Promise<string | null> {\n const orgId = getCurrentProject()?.orgId;\n if (orgId) {\n const cached = cache.get(orgId);\n const logo = cached && Date.now() - cached.at < CACHE_TTL_MS\n ? cached.path\n : await resolveOrgLogo(orgId, platform);\n if (!cached || Date.now() - cached.at >= CACHE_TTL_MS) {\n cache.set(orgId, { path: logo, at: Date.now() });\n }\n if (logo) return logo;\n }\n\n // Pas de logo — ni d'organisation, ou bien elle n'en a pas posé : reste la\n // couleur du thème, qui distingue déjà deux Runeya à l'écran.\n return renderThemedIcon(platform);\n}\n\n/**\n * L'icône Runeya dans la couleur du thème, écrite sur le disque.\n *\n * `null` tant qu'aucun onglet n'a annoncé sa couleur : le CLI garde alors le\n * fichier livré avec lui, qui est cette même icône dans sa teinte d'origine.\n */\nasync function renderThemedIcon(platform: NodeJS.Platform): Promise<string | null> {\n const accent = getTrayAccent();\n if (!accent) return null;\n\n try {\n // 64 pixels : la taille que les barres système réclament au plus, et huit\n // fois moins d'octets à écrire que les 512 des fichiers livrés.\n const png = renderRuneyaIcon(accent, 64);\n if (!png) return null;\n // La couleur est dans le nom : deux thèmes ne se disputent pas un fichier,\n // et repasser à un thème déjà vu ne réécrit rien.\n return writeTrayIcon(`theme-${accent.replace(/[^a-z0-9]/g, '')}`, png, platform);\n } catch (err) {\n console.log(`[tray] icône du thème non écrite : ${(err as Error).message}`);\n return null;\n }\n}\n\n/**\n * Poser une icône dans le dossier, sous la forme que la plateforme attend.\n *\n * Le PNG passe tel quel partout sauf sous Windows, où il est emballé en ICO —\n * la seule chose qui distingue les deux icônes que ce service produit, celle\n * d'une organisation et celle d'un thème.\n */\nasync function writeTrayIcon(\n stem: string,\n png: Uint8Array,\n platform: NodeJS.Platform,\n): Promise<string | null> {\n const dir = trayIconDir();\n await mkdir(dir, { recursive: true });\n const path = join(dir, stem);\n\n if (platform === 'win32') {\n const ico = pngToIco(png);\n return ico ? writeAtomic(`${path}.ico`, ico) : null;\n }\n return writeAtomic(`${path}.png`, png);\n}\n\n/**\n * Écrire l'icône en une fois, jamais en place.\n *\n * Plusieurs Runeya partagent ce dossier et peuvent viser le même fichier au\n * même moment — même organisation, deux piles. Sans le passage par un\n * temporaire, une barre système pourrait lire un fichier à moitié écrit et\n * afficher une icône tronquée. Le motif `.tmp` + `rename` est celui de tout le\n * reste du serveur (§7) ; les helpers existants n'écrivent que du texte.\n */\nasync function writeAtomic(path: string, bytes: Uint8Array): Promise<string> {\n // Le temporaire porte le pid : deux instances qui écrivent ensemble ne\n // doivent pas se disputer le même brouillon.\n const tmp = `${path}.${process.pid}.tmp`;\n await writeFile(tmp, bytes);\n await rename(tmp, path);\n return path;\n}\n\nasync function resolveOrgLogo(orgId: string, platform: NodeJS.Platform): Promise<string | null> {\n try {\n const bytes = await orgLogoBytes(orgId);\n if (!bytes) return null;\n // Le nom est dérivé de l'id, pas fourni par lui : un id est une donnée\n // distante, et il ne compose pas un chemin.\n return writeTrayIcon(`org-${orgId.replace(/[^a-zA-Z0-9_-]/g, '')}`, bytes, platform);\n } catch (err) {\n console.log(`[tray] logo d'organisation indisponible : ${(err as Error).message}`);\n return null;\n }\n}\n\n/**\n * Les octets du logo, en PNG — le seul format que la barre système lise.\n *\n * Le coffre garde l'image telle qu'elle a été envoyée, et la page\n * d'organisation enregistre en JPEG : ce qui s'y trouve n'est donc utilisable\n * directement que si c'est déjà un PNG. Sinon la conversion est demandée au\n * cloud de cette organisation — pas au cloud par défaut, une organisation\n * pouvant être hébergée ailleurs.\n */\nasync function orgLogoBytes(orgId: string): Promise<Uint8Array | null> {\n const stored = await readOrgLogo(orgId);\n if (stored && isPng(stored.bytes)) return stored.bytes;\n\n const url = `${await orgCloudUrl(orgId)}/api/org-logo/${encodeURIComponent(orgId)}?format=png`;\n const response = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n // 404 : cette organisation n'a pas de logo. C'est une réponse, pas une panne.\n if (!response.ok) return null;\n\n const bytes = new Uint8Array(await response.arrayBuffer());\n if (bytes.length === 0 || bytes.length > MAX_LOGO_BYTES) return null;\n // Une conversion ratée, ou un cloud plus ancien qui ignore le paramètre,\n // rendrait autre chose qu'un PNG — que la barre système afficherait vide.\n return isPng(bytes) ? bytes : null;\n}\n","/**\n * Emballer un PNG dans un conteneur ICO.\n *\n * Windows exige un `.ico` dans sa barre système, et un ICO depuis Vista peut\n * contenir un PNG tel quel : il n'y a donc rien à ré-encoder, seulement un\n * en-tête de six octets et une entrée de seize à poser devant. C'est la raison\n * pour laquelle cette conversion tient ici plutôt que dans une dépendance.\n *\n * Rend `null` plutôt que de deviner quand les octets ne sont pas un PNG lisible\n * ou que l'image dépasse 256 pixels — le format ICO code chaque dimension sur\n * un seul octet, et un `0` y signifie 256. Redimensionner demanderait un\n * décodeur d'image ; ce n'est pas le travail de cette fonction.\n */\n\n/** Les huit octets qui ouvrent un PNG, et rien d'autre. */\nexport function isPng(bytes: Uint8Array): boolean {\n const signature = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];\n return bytes.length > signature.length && signature.every((b, i) => bytes[i] === b);\n}\n\n/** Les dimensions d'un PNG, lues dans son IHDR — le premier chunk, toujours. */\nexport function pngSize(bytes: Uint8Array): { width: number; height: number } | null {\n // 8 octets de signature, 4 de longueur, 4 de type, puis largeur et hauteur.\n if (bytes.length < 24 || !isPng(bytes)) return null;\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n if (String.fromCharCode(...bytes.slice(12, 16)) !== 'IHDR') return null;\n const width = view.getUint32(16);\n const height = view.getUint32(20);\n if (width === 0 || height === 0) return null;\n return { width, height };\n}\n\nexport function pngToIco(png: Uint8Array): Uint8Array | null {\n const size = pngSize(png);\n if (!size) return null;\n if (size.width > 256 || size.height > 256) return null;\n\n const header = new Uint8Array(6 + 16);\n const view = new DataView(header.buffer);\n // ICONDIR : réservé (0), type 1 = icône, une seule image.\n view.setUint16(0, 0, true);\n view.setUint16(2, 1, true);\n view.setUint16(4, 1, true);\n // ICONDIRENTRY : 256 se code par 0, la seule valeur qui ne tient pas sur l'octet.\n header[6] = size.width === 256 ? 0 : size.width;\n header[7] = size.height === 256 ? 0 : size.height;\n header[8] = 0; // couleurs de la palette : aucune, l'image est en couleurs vraies\n header[9] = 0; // réservé\n view.setUint16(10, 1, true); // plans\n view.setUint16(12, 32, true); // bits par pixel\n view.setUint32(14, png.length, true);\n view.setUint32(18, header.length, true); // décalage des données : juste après l'en-tête\n\n const ico = new Uint8Array(header.length + png.length);\n ico.set(header, 0);\n ico.set(png, header.length);\n return ico;\n}\n","/**\n * L'icône Runeya, dessinée à la demande dans la couleur du thème.\n *\n * Les PNG livrés avec le CLI ont une couleur figée (`#6366f1`), alors que\n * l'interface se teinte : deux Runeya au thème différent posaient la même\n * icône. Elle est donc redessinée ici, à partir de la même géométrie que\n * `assets/icon.svg` — un rectangle arrondi et deux traits blancs.\n *\n * Redessiner plutôt que recolorer : recolorer demanderait de décoder le PNG\n * livré et de deviner quels pixels appartiennent au fond ; la géométrie, elle,\n * est connue, tient en quatre points, et donne un tracé net à n'importe quelle\n * taille. Rien de tout cela ne demande de bibliothèque : `zlib` suffit à écrire\n * un PNG, et l'anticrénelage se déduit de la distance au tracé.\n */\nimport { deflateSync } from 'node:zlib';\n\n/** Le dessin est décrit dans le repère de `icon.svg` : 28 × 28. */\nconst VIEW = 28;\nconst CORNER_RADIUS = 8;\nconst STROKE_WIDTH = 2.5;\n\n/** Les deux traits blancs, en segments — la polyligne du logo, puis sa barre. */\nconst STROKES: [number, number, number, number][] = [\n [7, 20, 14, 8],\n [14, 8, 21, 20],\n [10, 16, 18, 16],\n];\n\n/** `#rgb` ou `#rrggbb` → composantes, ou `null` si ce n'est pas une couleur. */\nexport function parseHexColor(hex: string): [number, number, number] | null {\n const value = hex.trim().replace(/^#/, '');\n const full = value.length === 3 ? value.replace(/./g, (c) => c + c) : value;\n if (!/^[0-9a-fA-F]{6}$/.test(full)) return null;\n return [\n parseInt(full.slice(0, 2), 16),\n parseInt(full.slice(2, 4), 16),\n parseInt(full.slice(4, 6), 16),\n ];\n}\n\n/** Distance signée à un rectangle arrondi centré à l'origine. */\nfunction distanceToRoundedRect(x: number, y: number, half: number, radius: number): number {\n const dx = Math.abs(x) - (half - radius);\n const dy = Math.abs(y) - (half - radius);\n const outside = Math.hypot(Math.max(dx, 0), Math.max(dy, 0));\n return outside + Math.min(Math.max(dx, dy), 0) - radius;\n}\n\n/** Distance signée à un segment épais aux extrémités rondes — un trait du logo. */\nfunction distanceToStroke(\n x: number, y: number,\n [ax, ay, bx, by]: [number, number, number, number],\n width: number,\n): number {\n const px = x - ax;\n const py = y - ay;\n const vx = bx - ax;\n const vy = by - ay;\n const t = Math.min(1, Math.max(0, (px * vx + py * vy) / (vx * vx + vy * vy)));\n return Math.hypot(px - vx * t, py - vy * t) - width / 2;\n}\n\n/**\n * Combien ce pixel est couvert par la forme, entre 0 et 1.\n *\n * La transition se fait sur la largeur d'un pixel de part et d'autre du bord :\n * c'est ce qui donne les contours lisses, sans suréchantillonner.\n */\nfunction coverage(distance: number, pixel: number): number {\n return Math.min(1, Math.max(0, 0.5 - distance / pixel));\n}\n\n/** Un PNG carré de `size` pixels, dans la couleur donnée. */\nexport function renderRuneyaIcon(color: string, size = 64): Uint8Array | null {\n const rgb = parseHexColor(color);\n if (!rgb || size < 8 || size > 1024) return null;\n\n const scale = size / VIEW;\n const pixel = 1 / scale; // la taille d'un pixel, dans le repère du dessin\n const half = VIEW / 2;\n const rgba = new Uint8Array(size * size * 4);\n\n for (let py = 0; py < size; py += 1) {\n for (let px = 0; px < size; px += 1) {\n // Le centre du pixel, ramené dans le repère 28 × 28.\n const x = (px + 0.5) / scale;\n const y = (py + 0.5) / scale;\n\n const background = coverage(distanceToRoundedRect(x - half, y - half, half, CORNER_RADIUS), pixel);\n if (background <= 0) continue;\n\n let stroke = 0;\n for (const segment of STROKES) {\n stroke = Math.max(stroke, coverage(distanceToStroke(x, y, segment, STROKE_WIDTH), pixel));\n }\n // Le trait ne déborde jamais du fond : il est peint par-dessus, pas à côté.\n stroke = Math.min(stroke, background);\n\n const offset = (py * size + px) * 4;\n for (let channel = 0; channel < 3; channel += 1) {\n rgba[offset + channel] = Math.round(rgb[channel] * (1 - stroke) + 255 * stroke);\n }\n rgba[offset + 3] = Math.round(background * 255);\n }\n }\n\n return encodePng(rgba, size, size);\n}\n\n// ─── Écriture du PNG ─────────────────────────────────────────────────────────\n\nconst CRC_TABLE = (() => {\n const table = new Uint32Array(256);\n for (let n = 0; n < 256; n += 1) {\n let c = n;\n for (let k = 0; k < 8; k += 1) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n table[n] = c >>> 0;\n }\n return table;\n})();\n\nfunction crc32(bytes: Uint8Array): number {\n let crc = 0xffffffff;\n for (const byte of bytes) crc = CRC_TABLE[(crc ^ byte) & 0xff]! ^ (crc >>> 8);\n return (crc ^ 0xffffffff) >>> 0;\n}\n\n/** Un chunk PNG : longueur, type, données, CRC des deux derniers. */\nfunction chunk(type: string, data: Uint8Array): Uint8Array {\n const out = new Uint8Array(data.length + 12);\n const view = new DataView(out.buffer);\n view.setUint32(0, data.length);\n for (let i = 0; i < 4; i += 1) out[4 + i] = type.charCodeAt(i);\n out.set(data, 8);\n view.setUint32(data.length + 8, crc32(out.subarray(4, data.length + 8)));\n return out;\n}\n\nfunction encodePng(rgba: Uint8Array, width: number, height: number): Uint8Array {\n const header = new Uint8Array(13);\n const view = new DataView(header.buffer);\n view.setUint32(0, width);\n view.setUint32(4, height);\n header[8] = 8; // 8 bits par composante\n header[9] = 6; // RGBA\n // compression, filtrage et entrelacement : les seules valeurs que PNG définit.\n\n // Chaque ligne est précédée de son octet de filtre — aucun filtre ici, les\n // gains ne valent pas le code qu'ils demandent sur une image de 64 pixels.\n const raw = new Uint8Array(height * (width * 4 + 1));\n for (let y = 0; y < height; y += 1) {\n raw[y * (width * 4 + 1)] = 0;\n raw.set(rgba.subarray(y * width * 4, (y + 1) * width * 4), y * (width * 4 + 1) + 1);\n }\n\n const signature = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);\n const parts = [\n signature,\n chunk('IHDR', header),\n chunk('IDAT', new Uint8Array(deflateSync(raw))),\n chunk('IEND', new Uint8Array(0)),\n ];\n\n const png = new Uint8Array(parts.reduce((total, part) => total + part.length, 0));\n let at = 0;\n for (const part of parts) {\n png.set(part, at);\n at += part.length;\n }\n return png;\n}\n"],"mappings":"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","names":["resolve","execFile","promisify","z","execFileAsync","promisify","execFile","cli","z","z","value","z","z","TRPCError","join","env","TRPCError","z","resolve","z","TRPCError","z","TRPCError","resolve","z","TRPCError","TRPCError","TRPCError","SUBSCRIPTION_QUEUE_MAX","resolve","z","TRPCError","z","z","z","z","z","TRPCError","z","env","TRPCError","z","TRPCError","maskApiKey","z","TRPCError","current","resolve","z","TRPCError","execFile","spawn","stat","join","homedir","readFile","writeFile","rename","mkdir","chmod","join","z","join","z","mkdir","writeFile","rename","chmod","readFile","homedir","TRPCError","resolve","execFile","z","stat","spawn","join","z","TRPCError","mkdir","writeFile","join","dirname","z","TRPCError","join","mkdir","dirname","writeFile","z","TRPCError","z","TRPCError","resolve","randomUUID","TRPCError","z","TRPCError","TRPCError","Anthropic","OpenAI","Anthropic","OpenAI","chunk","TRPCError","mkdir","join","resolve","publish","result","join","mkdir","isSubtreeComplete","startedAt","current","ScopeShape","z","scopeOf","randomUUID","TRPCError","randomUUID","TRPCError","z","MAX_BUFFER","resolve","z","randomUUID","current","TRPCError","z","TRPCError","chunk","z","resolve","TRPCError","z","randomUUID","EventEmitter","EventEmitter","randomUUID","z","resolve","mkdir","stat","writeFile","join","z","TRPCError","join","stat","mkdir","writeFile","TRPCError","z","cloudFetch","z","TRPCError","z","resolve","TRPCError","z","z","resolve","z","TRPCError","readFile","readdir","stat","writeFile","mkdir","rename","rm","join","dirname","z","TRPCError","mkdir","dirname","entries","readdir","join","stat","readFile","writeFile","rename","rm","z","TRPCError","join","join","randomUUID","mkdir","rm","Y","readFile","dirname","join","randomUUID","join","readFile","dirname","randomUUID","randomUUID","resolve","mkdir","rm","readdir","readFile","writeFile","mkdir","rename","stat","join","createCipheriv","createDecipheriv","randomBytes","createDecipheriv","randomBytes","createCipheriv","entries","readdir","stat","join","readFile","mkdir","writeFile","rename","TRPCError","z","cloudFetch","current","readdir","stat","homedir","join","resolve","dirname","z","MAX_ENTRIES","z","join","homedir","resolve","stat","readdir","entries","dirname","z","isAbsolute","TRPCError","execFile","isAbsolute","promisify","promisify","execFile","INSTALL_TIMEOUT_MS","isAbsolute","listeners","z","isAbsolute","TRPCError","chmod","stat","stat","chmod","readdir","readFile","writeFile","mkdir","copyFile","rename","stat","join","entries","readdir","exists","stat","join","mkdir","copyFile","readFile","writeFile","rename","readFile","writeFile","rename","unlink","mkdir","chmod","stat","join","exists","stat","mkdir","join","readFile","writeFile","rename","chmod","unlink","randomBytes","createCipheriv","createDecipheriv","randomUUID","readFile","writeFile","rename","mkdir","access","readdir","join","dirname","encryptValue","randomBytes","createCipheriv","createDecipheriv","readFile","writeFile","rename","join","access","mkdir","readdir","randomUUID","env","entries","resolve","dirname","join","stat","ENCRYPTED_KEY_FILENAME","VERIFY_FILENAME","stat","join","existsSync","resolve","existsSync","startedAt","randomBytes","resolvePath","resolve","env","mkdir","writeFile","rename","join","cache","join","accent","mkdir","writeFile","rename","resolvePath","resolve"]}
|