@runeya/runeya 2.0.27 → 2.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/index.js +23 -1
- package/agent/index.js.map +1 -1
- package/agent-manager-KGITN4AE.js +7 -0
- package/{chunk-Y2R42AXQ.js → chunk-PZHVJHTC.js} +24 -2
- package/chunk-PZHVJHTC.js.map +1 -0
- package/index.js +1 -1
- package/mcp-server/index.js +11 -1
- package/mcp-server/index.js.map +1 -1
- package/package.json +1 -1
- package/{src-RMLLDYCE.js → src-W64XJTN5.js} +345 -208
- package/src-W64XJTN5.js.map +1 -0
- package/web/assets/{AgentScalarChatInterface.vue-DSPI6Iw-.js → AgentScalarChatInterface.vue-Tid9c7AI.js} +1 -1
- package/web/assets/{AgentTerminalPage-COqIEzlq.js → AgentTerminalPage-Bfmc2lJ5.js} +1 -1
- package/web/assets/AiChatPage-LbXbHkW7.js +1 -0
- package/web/assets/{AppLayout-CduB5PAm.js → AppLayout-Cq3bBVsr.js} +1 -1
- package/web/assets/{AuditPage-BKRt4q5p.js → AuditPage-BTk2MLfW.js} +1 -1
- package/web/assets/CloudAccountPage--sgdl0BR.js +1 -0
- package/web/assets/{CloudAccountPage-BdtMRHqA.js → CloudAccountPage-sObD2Djw.js} +1 -1
- package/web/assets/{CloudMessagingPage-CKRgPVNR.js → CloudMessagingPage-DbkITdyZ.js} +1 -1
- package/web/assets/{DashboardPage-COXIB50G.js → DashboardPage-CW5p34P0.js} +1 -1
- package/web/assets/{EditorIcon-DIdkqlIr.js → EditorIcon-D1wp4885.js} +1 -1
- package/web/assets/{EnvironmentForm-94JbjgMc.js → EnvironmentForm-BA-0wfqa.js} +1 -1
- package/web/assets/{EnvironmentFormPage-BPFoGLYG.js → EnvironmentFormPage-ePoUSDaO.js} +1 -1
- package/web/assets/{EnvironmentListPage-DoWsGpIn.js → EnvironmentListPage-Cgn6NwWL.js} +1 -1
- package/web/assets/{EnvironmentSelector-D7xKYoZZ.js → EnvironmentSelector-C8aULVdj.js} +1 -1
- package/web/assets/KanbanBoardPage-0TVI8ncW.js +4 -0
- package/web/assets/KanbanBoardPage-kpZiPs_o.css +1 -0
- package/web/assets/{KanbanListPage-Cgw2ik7W.js → KanbanListPage-B6QRYUG8.js} +1 -1
- package/web/assets/{LaunchProjectPage-447Nb6i3.js → LaunchProjectPage-jx4qoZlc.js} +1 -1
- package/web/assets/{LaunchServicesPage-CFU9SkfH.js → LaunchServicesPage-C2hQ8iiO.js} +1 -1
- package/web/assets/{LogViewer-DlDsNuvU.js → LogViewer-DPQTUsar.js} +1 -1
- package/web/assets/{ProcessControls-BvaAllZ_.js → ProcessControls-n_p4xwJz.js} +1 -1
- package/web/assets/{ProcessDetailPage-pS2cLCxq.js → ProcessDetailPage-Cm2iN-19.js} +1 -1
- package/web/assets/{ProcessMetrics-BLvaSlXi.js → ProcessMetrics-DRxTLIIf.js} +1 -1
- package/web/assets/{ProjectDetailPage-Dg74KYBj.js → ProjectDetailPage-DO7pKGee.js} +1 -1
- package/web/assets/{ProjectListPage-CIhtK--_.js → ProjectListPage-CljuUt8K.js} +1 -1
- package/web/assets/{RandomJobTestPage-34yoDjxB.js → RandomJobTestPage-DqbzEMbv.js} +1 -1
- package/web/assets/{ScenarioEditorPage-C0qdLDFR.js → ScenarioEditorPage-DRUK4ep3.js} +1 -1
- package/web/assets/{SendToChatDialog-COS28j81.js → SendToChatDialog-C6d_cEQ4.js} +1 -1
- package/web/assets/{ServiceControlsBar-BDtQvmNc.js → ServiceControlsBar-BcCBOny2.js} +1 -1
- package/web/assets/{ServiceDetailPage-C_drtJlU.js → ServiceDetailPage-B5Z2oyG1.js} +1 -1
- package/web/assets/{ServiceFormPage-mD2msQ6o.js → ServiceFormPage-BkRlzAMF.js} +1 -1
- package/web/assets/{SettingsPage-C8BPcYEM.js → SettingsPage-CkAaTz8q.js} +4 -4
- package/web/assets/{SetupPage-DK2db8Hp.js → SetupPage-DRRqBmwE.js} +1 -1
- package/web/assets/{UnlockPage-WopGWLhW.js → UnlockPage-DFHKtpGb.js} +1 -1
- package/web/assets/{VariablesTable-D65CafB_.js → VariablesTable-Csi8gzLH.js} +1 -1
- package/web/assets/{VersionBadge-CE0ovTHa.js → VersionBadge-C1-aqmd0.js} +1 -1
- package/web/assets/WikiPage-amGnOY35.js +1 -0
- package/web/assets/{WikiView-CF6FvyCm.js → WikiView-BSFsn874.js} +1 -1
- package/web/assets/{add-scalar-classes-CaO2Xice.js → add-scalar-classes-BrZlN4Hz.js} +3 -3
- package/web/assets/auth-errors-VpVD7Ji8.js +1 -0
- package/web/assets/{autocomplete-CnW5yK7q.js → autocomplete-CqNBR7AV.js} +1 -1
- package/web/assets/{basic-shape-diamond.svg-Bkv9ZjHf.js → basic-shape-diamond.svg-pmR0NFra.js} +1 -1
- package/web/assets/{basic-shape-hexagon.svg-D20uJxmK.js → basic-shape-hexagon.svg-DoFRZCyQ.js} +1 -1
- package/web/assets/{basic-shape-primary-circle-ellipse-round.svg-B5XhKGTG.js → basic-shape-primary-circle-ellipse-round.svg-CPjLQmZx.js} +1 -1
- package/web/assets/{basic-shape-primary-square-rectangle.svg-BWQZbeJS.js → basic-shape-primary-square-rectangle.svg-DcMAxrju.js} +1 -1
- package/web/assets/{basic-shape-shield.svg-Cas8taBL.js → basic-shape-shield.svg-Dmg9h6Ld.js} +1 -1
- package/web/assets/{browser-CKAGCYBM.js → browser-C6RUDE7s.js} +1 -1
- package/web/assets/{browser-ZjFgFnVC.js → browser-DfiNANMf.js} +1 -1
- package/web/assets/{card-C20l4eFB.js → card-BtNd-O08.js} +1 -1
- package/web/assets/{checkbox-DfnQXBty.js → checkbox-CCOdP3PH.js} +1 -1
- package/web/assets/{chip-BJLSl2tN.js → chip-CKD4ZA_K.js} +1 -1
- package/web/assets/{client-CiZKwix4.js → client-DUaS1tvD.js} +1 -1
- package/web/assets/{cloud-chat.store-D-s33s91.js → cloud-chat.store-Do2pLXa6.js} +1 -1
- package/web/assets/cloud-client-DkNqusEt.js +1 -0
- package/web/assets/{column-Ce2OMgI5.js → column-EYuEVcRt.js} +1 -1
- package/web/assets/{computer-device-desktop-monitor.svg-C1wBG8Sy.js → computer-device-desktop-monitor.svg-C8qLTM16.js} +1 -1
- package/web/assets/{computer-device-desktop.svg-CyY6f6_9.js → computer-device-desktop.svg-BwIQxUgG.js} +1 -1
- package/web/assets/{computer-device-laptop.svg-BPNvNYfT.js → computer-device-laptop.svg-je8g4h4s.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-android-samsung-back.svg-DbltFZte.js → computer-device-mobile-phone-android-samsung-back.svg-DXuOmvmg.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-android-samsung.svg-CrLSCe_x.js → computer-device-mobile-phone-android-samsung.svg-Dvck__2L.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-iphone-x-back.svg-BY19Nult.js → computer-device-mobile-phone-iphone-x-back.svg-BRzKNDWY.js} +1 -1
- package/web/assets/{computer-device-mobile-phone-iphone-x.svg-H7FI65UW.js → computer-device-mobile-phone-iphone-x.svg-DwKt9Eia.js} +1 -1
- package/web/assets/{computer-device-mobile-tablet-touch.svg-Cmx8jUA5.js → computer-device-mobile-tablet-touch.svg-B65iLEZR.js} +1 -1
- package/web/assets/{computer-device-mobile-tablet.svg-C-ij0kaB.js → computer-device-mobile-tablet.svg-BbUYpqRa.js} +1 -1
- package/web/assets/{computer-device-network-ethernet-cat6.svg-BxWINH6l.js → computer-device-network-ethernet-cat6.svg-TVQFk_lM.js} +1 -1
- package/web/assets/{computer-device-network-lan-www.svg-BSgN4bQe.js → computer-device-network-lan-www.svg-D9wNL1d9.js} +1 -1
- package/web/assets/{computer-device-network-wifi-connection.svg-9-Af1cyW.js → computer-device-network-wifi-connection.svg-B3l3vDCq.js} +1 -1
- package/web/assets/{computer-device-network-wifi-router.svg-PGbsNleo.js → computer-device-network-wifi-router.svg-CfJjWVyH.js} +1 -1
- package/web/assets/{cssMode-BXCNwJJl.js → cssMode-CT0VgZiM.js} +1 -1
- package/web/assets/{divider-D15eSJOf.js → divider-BAtaraJT.js} +1 -1
- package/web/assets/{ecology-science-erlenmeyer-flask.svg-D1TcAurA.js → ecology-science-erlenmeyer-flask.svg-DCqj3wuN.js} +1 -1
- package/web/assets/{fieldset-DpjemOKg.js → fieldset-Bmfuw85t.js} +1 -1
- package/web/assets/{freemarker2-vGwcFsrU.js → freemarker2-DcS0oW9c.js} +1 -1
- package/web/assets/{handlebars-CgczpBKv.js → handlebars-EYnEyJJj.js} +1 -1
- package/web/assets/{html-BFGITMD0.js → html-Cy3hBLsT.js} +1 -1
- package/web/assets/{htmlMode-B3rE7DS5.js → htmlMode-7YMQ7tB-.js} +1 -1
- package/web/assets/{image-flash-lightning.svg-xzLxZzA4.js → image-flash-lightning.svg-D6x2pDl8.js} +1 -1
- package/web/assets/{image-picture-flower.svg-pnrEOEKg.js → image-picture-flower.svg-qlZATukV.js} +1 -1
- package/web/assets/{index-gKo3WNkm.css → index-DtsVLZzz.css} +1 -1
- package/web/assets/{index-pgDYqJbK.js → index-ZFdBtCGG.js} +6 -6
- package/web/assets/{interface-alert-exclamation-diamond.svg-CI092Np8.js → interface-alert-exclamation-diamond.svg-Bt2YgBdz.js} +1 -1
- package/web/assets/{interface-alert-exclamation-triangle-warning.svg-C4mqQzrp.js → interface-alert-exclamation-triangle-warning.svg-BL6E9tsG.js} +1 -1
- package/web/assets/{interface-alert-information-circle.svg-BT4vnvBw.js → interface-alert-information-circle.svg-C2mU-Jrm.js} +1 -1
- package/web/assets/{interface-award-crown.svg-CRPOUMXT.js → interface-award-crown.svg-C_908siC.js} +1 -1
- package/web/assets/{interface-bookmark.svg-DTAetZsa.js → interface-bookmark-tag.svg-CdwmwagL.js} +1 -1
- package/web/assets/{interface-bookmark-tag.svg-DPVkmndo.js → interface-bookmark.svg-DiGis0Pq.js} +1 -1
- package/web/assets/{interface-calendar-date-one.svg-6dLyIX8s.js → interface-calendar-date-one.svg-DZJTVsRH.js} +1 -1
- package/web/assets/{interface-content-book-open-pages.svg-6XF6zc4V.js → interface-content-book-open-pages.svg-BWjmGbGN.js} +1 -1
- package/web/assets/{interface-content-book-page.svg-bdqhi6K9.js → interface-content-book-page.svg-HTArRhqF.js} +1 -1
- package/web/assets/{interface-content-file.svg-1G5vO-Bf.js → interface-content-file.svg-CEK-6Dir.js} +1 -1
- package/web/assets/{interface-content-folder.svg-D850sLcG.js → interface-content-folder.svg-CvFy9IIg.js} +1 -1
- package/web/assets/interface-content-folder.svg-D9a2SnRw.js +1 -0
- package/web/assets/{interface-copy-clipboard.svg-BccvE8VI.js → interface-copy-clipboard.svg-CA9ObKG2.js} +1 -1
- package/web/assets/{interface-edit-attachment.svg-Ce4FGCOQ.js → interface-edit-attachment.svg-BuZlaKV6.js} +1 -1
- package/web/assets/{interface-edit-binocular.svg-DPRn5hZu.js → interface-edit-binocular.svg-Bu-T_qRU.js} +1 -1
- package/web/assets/{interface-edit-magic-wand.svg-DXe8x6h5.js → interface-edit-magic-wand.svg-ZyOEyv4O.js} +1 -1
- package/web/assets/{interface-edit-tool-paint-roller.svg-DiSg_nu0.js → interface-edit-tool-paint-roller.svg-DBwhOf_F.js} +1 -1
- package/web/assets/{interface-edit-tool-pencil.svg-CJ7nntID.js → interface-edit-tool-pencil.svg-CMKU5EZ0.js} +1 -1
- package/web/assets/{interface-favorite-award.svg-Bp7EXD5O.js → interface-favorite-award.svg-Djfprlrh.js} +1 -1
- package/web/assets/{interface-favorite-flag.svg-X3mutHkA.js → interface-favorite-flag.svg-MM0Rm1Rf.js} +1 -1
- package/web/assets/{interface-favorite-heart.svg-BZN7wndr.js → interface-favorite-heart.svg-8eXxbVlD.js} +1 -1
- package/web/assets/{interface-favorite-star.svg-DLgGRGba.js → interface-favorite-star.svg-CYpNa-DM.js} +1 -1
- package/web/assets/{interface-favorite-stars-sparkles.svg-B4M9nCgv.js → interface-favorite-stars-sparkles.svg-KYu8S1Mc.js} +1 -1
- package/web/assets/{interface-hierarchy-flowchart.svg-CU5Tp_c9.js → interface-hierarchy-flowchart.svg-fr4rLXph.js} +1 -1
- package/web/assets/{interface-home-house.svg-B1qI4Bnk.js → interface-home-house.svg-UfcAwTPa.js} +1 -1
- package/web/assets/{interface-hyperlink.svg-DDLaWCwm.js → interface-hyperlink.svg-DLpXwEy6.js} +1 -1
- package/web/assets/{interface-lighting-brightness.svg-C0XYahxq.js → interface-lighting-brightness.svg-aY4osIqa.js} +1 -1
- package/web/assets/{interface-lock-closed.svg-BJGiYphz.js → interface-lock-closed.svg-CiMIugbj.js} +1 -1
- package/web/assets/{interface-lock-open-unlock.svg-B9mZbDai.js → interface-lock-open-unlock.svg-d5UkSt1y.js} +1 -1
- package/web/assets/{interface-login-key.svg-CLg9rb5N.js → interface-login-key.svg-C7Ml1iaN.js} +1 -1
- package/web/assets/{interface-search.svg-C_hyT038.js → interface-search.svg-D8jY9D2U.js} +1 -1
- package/web/assets/{interface-setting-cog.svg-CPJEcVaX.js → interface-setting-cog.svg-3DAxFuOM.js} +1 -1
- package/web/assets/{interface-share-megaphone-bullhorn.svg-D9mnWTl1.js → interface-share-megaphone-bullhorn.svg-BsbqqS8a.js} +1 -1
- package/web/assets/{interface-share-rocket.svg-Cv-mm6Sf.js → interface-share-rocket.svg-C_8HYujm.js} +1 -1
- package/web/assets/{interface-share-satellite.svg-KG8vUTu7.js → interface-share-satellite.svg-3O-1mL1W.js} +1 -1
- package/web/assets/{interface-share-space-ship.svg-G-gPwAXE.js → interface-share-space-ship.svg-BDge8YMa.js} +1 -1
- package/web/assets/{interface-share.svg-DqUCb7Ru.js → interface-share.svg-Fehxvv85.js} +1 -1
- package/web/assets/{interface-signal-square.svg-D3hMImVy.js → interface-signal-square.svg-C0c3wlFq.js} +1 -1
- package/web/assets/{interface-time-clock-circle.svg-BJygBdct.js → interface-time-clock-circle.svg-Bj3gcDKD.js} +1 -1
- package/web/assets/{interface-time-hour-glass.svg-C6VAxVap.js → interface-time-hour-glass.svg-DUim2QDE.js} +1 -1
- package/web/assets/{interface-users-multiple.svg-CoxyjUld.js → interface-users-multiple.svg-vooB7JL-.js} +1 -1
- package/web/assets/{interface-weather-moon.svg-D-X12JVO.js → interface-weather-moon.svg-BcUz22tg.js} +1 -1
- package/web/assets/{javascript-C84J6-4w.js → javascript-xFG-91vE.js} +1 -1
- package/web/assets/{jsonMode-C27w1Qms.js → jsonMode-CXRfjDm6.js} +1 -1
- package/web/assets/{liquid-DgfNbtcl.js → liquid-DFaP2Us7.js} +1 -1
- package/web/assets/{lspLanguageFeatures-C_7i29Bj.js → lspLanguageFeatures-Cj2beqH7.js} +1 -1
- package/web/assets/{mail-chat-bubble-square.svg-DkpMmHLK.js → mail-chat-bubble-square.svg-Q5_Wlk-h.js} +1 -1
- package/web/assets/{mail-send-email-paper-airplane.svg-D6NabH2T.js → mail-send-email-paper-airplane.svg-CjqQ7405.js} +1 -1
- package/web/assets/{mail-send-envelope.svg-BbPAyASY.js → mail-send-envelope.svg-MH4dR__N.js} +1 -1
- package/web/assets/{mdx-BCuKGABs.js → mdx-DDj1td2N.js} +1 -1
- package/web/assets/{message-CoRxRh0u.js → message-Dgvz1ZaX.js} +1 -1
- package/web/assets/{minus-5Bqt5ofK.js → minus-Hsxq04kB.js} +1 -1
- package/web/assets/modal-BCbrFXdF.js +1 -0
- package/web/assets/{modal-DwRiR841.js → modal-pAb11yGJ.js} +1 -1
- package/web/assets/{money-cashier-receipt.svg-VmdcIGRH.js → money-cashier-receipt.svg-W10QYjo6.js} +1 -1
- package/web/assets/{money-currency-dollar-pay.svg-BmWJQEO0.js → money-currency-dollar-pay.svg-jlzMCQus.js} +1 -1
- package/web/assets/{money-graph-arrow-increase.svg-D0-SVIVY.js → money-graph-arrow-increase.svg-DjiVgX3u.js} +1 -1
- package/web/assets/{money-graph-bar-chart-increase.svg-DTdIZ1yD.js → money-graph-bar-chart-increase.svg-BetO29r-.js} +1 -1
- package/web/assets/{multiselect-yuMT5FAw.js → multiselect-DAvUHXe1.js} +1 -1
- package/web/assets/{nature-ecology-leaf.svg-ftrud9Ee.js → nature-ecology-leaf.svg-68pXd-Nz.js} +1 -1
- package/web/assets/{password-Cw64wBy9.js → password-fBZDwzDL.js} +1 -1
- package/web/assets/{phone-telephone.svg-BukpdVe6.js → phone-telephone.svg-5-34SVF9.js} +1 -1
- package/web/assets/{plus-DUWBjv5i.js → plus-BybvY8Jc.js} +1 -1
- package/web/assets/process.store-e8DffExf.js +1 -0
- package/web/assets/{programming-bug.svg-BCduWuVf.js → programming-bug.svg-2bQdYECv.js} +1 -1
- package/web/assets/{programming-cloud.svg-BkuU9JZc.js → programming-cloud.svg-DZ2V0eJT.js} +1 -1
- package/web/assets/{programming-computer-database-server.svg-Dz36JAv6.js → programming-computer-database-server.svg-hDSuUD9Z.js} +1 -1
- package/web/assets/{programming-computer-database.svg-CgLUxdNj.js → programming-computer-database.svg-BySVZkMc.js} +1 -1
- package/web/assets/{programming-module-four-layout.svg-CUcqFbuN.js → programming-module-four-layout.svg-CKIgCJwc.js} +1 -1
- package/web/assets/{programming-module-three.svg-Drh_K9UP.js → programming-module-three.svg-DiWesNwV.js} +1 -1
- package/web/assets/{programming-module.svg-DpmnuolN.js → programming-module.svg-DU0zOvVK.js} +1 -1
- package/web/assets/{programming-script-code.svg-aLlzlZCt.js → programming-script-code.svg-DfSmaPH7.js} +1 -1
- package/web/assets/{python-Ch8jlEn0.js → python-C25OjXtn.js} +1 -1
- package/web/assets/{radiobutton-DG85qUd5.js → radiobutton-K1Libu7g.js} +1 -1
- package/web/assets/{razor-CUll3FMU.js → razor-DrRHsFwp.js} +1 -1
- package/web/assets/router-BQjVOlyD.js +1 -0
- package/web/assets/{settings.store-qZCJj_4D.js → settings.store-BCaFk23O.js} +1 -1
- package/web/assets/{shopping-cart.svg-yEPUTw_R.js → shopping-cart.svg-NMibYZ0k.js} +1 -1
- package/web/assets/{shopping-gift-present.svg-DaqJhwWl.js → shopping-gift-present.svg-dqvSn838.js} +1 -1
- package/web/assets/{shopping-shipping-box-parcel-package.svg-DV5YYoia.js → shopping-shipping-box-parcel-package.svg-CKYzVuYA.js} +1 -1
- package/web/assets/{src-CZvpZlaR.js → src-EWso2a1V.js} +1 -1
- package/web/assets/{src-mw3qp820.js → src-_-zc3-Cp.js} +1 -1
- package/web/assets/{tabpanel-Gp2kHree.js → tabpanel-BWhVX5cc.js} +1 -1
- package/web/assets/{tag-new-circle.svg-BHRX-TYk.js → tag-new-circle.svg-JFLA4g9w.js} +1 -1
- package/web/assets/{travel-map-earth-globe.svg-CmrszNdx.js → travel-map-earth-globe.svg-DdQN4a7G.js} +1 -1
- package/web/assets/trpc-BZfo9Cw2.js +1 -0
- package/web/assets/{tsMode-CjoWwALS.js → tsMode-Cii9XdsR.js} +1 -1
- package/web/assets/{typescript-BpONFNP8.js → typescript-zoLusRa0.js} +1 -1
- package/web/assets/useAiChatDrawer-CHmnbpKl.js +1 -0
- package/web/assets/{useCloudOrg-BEGIZ5Sw.css → useCloudOrg-CHCwXrRm.css} +1 -1
- package/web/assets/useCloudOrg-JZ6DFHrG.js +1 -0
- package/web/assets/{xml-CmjkohVQ.js → xml-BhaXJtQn.js} +1 -1
- package/web/assets/{yaml-CKv_rPtX.js → yaml-CDzjwB43.js} +1 -1
- package/web/favicon.svg +5 -0
- package/web/index.html +3 -3
- package/agent-manager-2P4THUVA.js +0 -7
- package/chunk-Y2R42AXQ.js.map +0 -1
- package/src-RMLLDYCE.js.map +0 -1
- package/web/assets/AiChatPage-CFc7KbNG.js +0 -1
- package/web/assets/CloudAccountPage-HTRjahHK.js +0 -1
- package/web/assets/KanbanBoardPage-BDzDCbzp.css +0 -1
- package/web/assets/KanbanBoardPage-Ca7RBQtm.js +0 -4
- package/web/assets/WikiPage-BEAjl3sE.js +0 -1
- package/web/assets/auth-errors-ePzxFx8g.js +0 -1
- package/web/assets/cloud-client-BNiN622M.js +0 -1
- package/web/assets/interface-content-folder.svg-CPgJrZEE.js +0 -1
- package/web/assets/modal-WUB9U4Dm.js +0 -1
- package/web/assets/process.store-f7QERgRI.js +0 -1
- package/web/assets/router-Ckd39-Uf.js +0 -1
- package/web/assets/trpc-C-XGFhkf.js +0 -1
- package/web/assets/useAiChatDrawer-DTJO3AGB.js +0 -1
- package/web/assets/useCloudOrg-Bbpui8U3.js +0 -1
- /package/{agent-manager-2P4THUVA.js.map → agent-manager-KGITN4AE.js.map} +0 -0
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
stableEncryptValue,
|
|
59
59
|
traefikManager,
|
|
60
60
|
writeEntity
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-PZHVJHTC.js";
|
|
62
62
|
|
|
63
63
|
// ../server/src/create-server.ts
|
|
64
64
|
import express from "express";
|
|
@@ -3440,7 +3440,7 @@ var RUNEYA_CAPABILITIES = [
|
|
|
3440
3440
|
},
|
|
3441
3441
|
{
|
|
3442
3442
|
name: "kanban_get_board",
|
|
3443
|
-
description: "Read one kanban board: its columns, and the cards in each (id, title, markdown body, assignees, comment count). Use the exact column names it returns when moving or adding a card.",
|
|
3443
|
+
description: "Read one kanban board: its columns, and the cards in each (id, title, markdown body, assignees, comment count, and attachment metadata \u2014 use kanban_download_attachment to fetch the bytes of a file). Use the exact column names it returns when moving or adding a card.",
|
|
3444
3444
|
route: "kanban.getBoard",
|
|
3445
3445
|
method: "GET",
|
|
3446
3446
|
params: [
|
|
@@ -3464,6 +3464,16 @@ var RUNEYA_CAPABILITIES = [
|
|
|
3464
3464
|
...p.limit ? { limit: Number(p.limit) } : {}
|
|
3465
3465
|
})
|
|
3466
3466
|
},
|
|
3467
|
+
{
|
|
3468
|
+
name: "kanban_download_attachment",
|
|
3469
|
+
description: "Download a kanban card attachment (image, PDF, any file) onto this machine and return its local path, so it can be opened with file-reading tools. Attachment ids come from the card context or from kanban_get_board.",
|
|
3470
|
+
route: "kanban.downloadAttachment",
|
|
3471
|
+
method: "POST",
|
|
3472
|
+
params: [
|
|
3473
|
+
{ name: "attachmentId", description: "The attachment ID, as listed on the card", required: true }
|
|
3474
|
+
],
|
|
3475
|
+
buildInput: (p) => ({ attachmentId: p.attachmentId })
|
|
3476
|
+
},
|
|
3467
3477
|
{
|
|
3468
3478
|
name: "kanban_move_card",
|
|
3469
3479
|
description: "Move a kanban card to another column. Use the exact column name.",
|
|
@@ -5571,7 +5581,8 @@ async function cloudFetch(path, init = {}) {
|
|
|
5571
5581
|
...init.body !== void 0 ? { "Content-Type": "application/json" } : {}
|
|
5572
5582
|
},
|
|
5573
5583
|
...init.body !== void 0 ? { body: JSON.stringify(init.body) } : {},
|
|
5574
|
-
|
|
5584
|
+
// 15s suits a JSON call; attachment downloads pass a longer budget.
|
|
5585
|
+
signal: AbortSignal.timeout(init.timeoutMs ?? 15e3)
|
|
5575
5586
|
});
|
|
5576
5587
|
}
|
|
5577
5588
|
var PROXY_PREFIXES = ["/organization/", "/project/", "/chat/", "/kanban/", "/user/prefs"];
|
|
@@ -5676,10 +5687,54 @@ var KanbanStore = class {
|
|
|
5676
5687
|
const res = await callCloud(`/kanban/board/list${query}`);
|
|
5677
5688
|
return res.data?.boards ?? [];
|
|
5678
5689
|
}
|
|
5679
|
-
|
|
5680
|
-
|
|
5690
|
+
/**
|
|
5691
|
+
* Un tableau. Sans les journaux de ses cartes par défaut : c'est la moitié
|
|
5692
|
+
* lourde du document, et presque aucun appelant n'en a besoin — un agent qui
|
|
5693
|
+
* liste des cartes ne lit pas les commentaires. `withHistory` les redemande
|
|
5694
|
+
* pour les rares cas qui les veulent tous d'un coup.
|
|
5695
|
+
*/
|
|
5696
|
+
async get(id, opts = {}) {
|
|
5697
|
+
const query = `?id=${encodeURIComponent(id)}${opts.withHistory ? "&withHistory=true" : ""}`;
|
|
5698
|
+
const res = await callCloud(`/kanban/board/get${query}`);
|
|
5681
5699
|
return res.data?.board ?? null;
|
|
5682
5700
|
}
|
|
5701
|
+
/** Le journal d'une seule carte — ce que le contexte d'un agent demande. */
|
|
5702
|
+
async cardHistory(boardId, cardId) {
|
|
5703
|
+
const res = await callCloud(
|
|
5704
|
+
`/kanban/card/history?boardId=${encodeURIComponent(boardId)}&cardId=${encodeURIComponent(cardId)}`
|
|
5705
|
+
);
|
|
5706
|
+
return res.data?.history ?? [];
|
|
5707
|
+
}
|
|
5708
|
+
/**
|
|
5709
|
+
* Commenter une carte, sans réécrire le tableau.
|
|
5710
|
+
*
|
|
5711
|
+
* C'est le geste que l'IA répète le plus, et souvent avec de longs textes :
|
|
5712
|
+
* le faire passer par une sauvegarde de tableau faisait transiter tout le
|
|
5713
|
+
* graphe de cartes à chaque phrase.
|
|
5714
|
+
*/
|
|
5715
|
+
async addComment(boardId, cardId, detail, conversationId) {
|
|
5716
|
+
const res = await callCloud("/kanban/card/comment/add", {
|
|
5717
|
+
method: "POST",
|
|
5718
|
+
body: { boardId, cardId, detail, author: "ai", ...conversationId ? { conversationId } : {} }
|
|
5719
|
+
});
|
|
5720
|
+
return res.ok;
|
|
5721
|
+
}
|
|
5722
|
+
/** Poser une entrée de journal non-commentaire (une conversation qui s'ouvre). */
|
|
5723
|
+
async addCardEvent(boardId, cardId, type, detail) {
|
|
5724
|
+
const res = await callCloud("/kanban/card/event/add", {
|
|
5725
|
+
method: "POST",
|
|
5726
|
+
body: { boardId, cardId, type, detail }
|
|
5727
|
+
});
|
|
5728
|
+
return res.ok;
|
|
5729
|
+
}
|
|
5730
|
+
/** Déplacer une carte, sans réécrire le tableau. */
|
|
5731
|
+
async moveCard(boardId, cardId, toColumnId) {
|
|
5732
|
+
const res = await callCloud("/kanban/card/move", {
|
|
5733
|
+
method: "POST",
|
|
5734
|
+
body: { boardId, cardId, toColumnId }
|
|
5735
|
+
});
|
|
5736
|
+
return res.ok;
|
|
5737
|
+
}
|
|
5683
5738
|
async create(input) {
|
|
5684
5739
|
const organizationId = await resolveOrganizationId();
|
|
5685
5740
|
if (!organizationId) return null;
|
|
@@ -5728,17 +5783,27 @@ async function executeKanbanCommands(boardId, cardId, commands, conversationId)
|
|
|
5728
5783
|
return;
|
|
5729
5784
|
}
|
|
5730
5785
|
}
|
|
5786
|
+
let pendingBoardWrite = false;
|
|
5731
5787
|
for (const cmd of commands) {
|
|
5732
5788
|
if (cmd.type === "move_card" && cmd.columnTitle) {
|
|
5733
|
-
const
|
|
5734
|
-
|
|
5789
|
+
const target = board.columns.find(
|
|
5790
|
+
(c) => c.title.toLowerCase() === cmd.columnTitle.toLowerCase()
|
|
5791
|
+
);
|
|
5792
|
+
if (!target) {
|
|
5793
|
+
console.warn(`[kanban-commands] Target column "${cmd.columnTitle}" not found. Available: ${board.columns.map((c) => c.title).join(", ")}`);
|
|
5794
|
+
continue;
|
|
5795
|
+
}
|
|
5796
|
+
const ok = await kanbanStore.moveCard(board.id, cardId, target.id);
|
|
5797
|
+
if (!ok) console.warn(`[kanban-commands] move_card failed: card=${cardId} target="${cmd.columnTitle}"`);
|
|
5735
5798
|
} else if (cmd.type === "add_comment" && cmd.comment) {
|
|
5736
|
-
addComment(board, cardId, cmd.comment, conversationId);
|
|
5799
|
+
const ok = await kanbanStore.addComment(board.id, cardId, cmd.comment, conversationId);
|
|
5800
|
+
if (!ok) console.warn(`[kanban-commands] add_comment failed: card=${cardId}`);
|
|
5737
5801
|
} else if (cmd.type === "add_card" && cmd.columnTitle && cmd.cardTitle) {
|
|
5738
5802
|
addCardToColumn(board, cmd.columnTitle, cmd.cardTitle, cmd.cardContent);
|
|
5803
|
+
pendingBoardWrite = true;
|
|
5739
5804
|
}
|
|
5740
5805
|
}
|
|
5741
|
-
await kanbanStore.update({ id: board.id, columns: board.columns });
|
|
5806
|
+
if (pendingBoardWrite) await kanbanStore.update({ id: board.id, columns: board.columns });
|
|
5742
5807
|
}
|
|
5743
5808
|
async function executeKanbanBoardCommands(boardId, commands) {
|
|
5744
5809
|
if (commands.length === 0) return;
|
|
@@ -5751,43 +5816,6 @@ async function executeKanbanBoardCommands(boardId, commands) {
|
|
|
5751
5816
|
}
|
|
5752
5817
|
await kanbanStore.update({ id: board.id, columns: board.columns });
|
|
5753
5818
|
}
|
|
5754
|
-
function moveCard(board, cardId, targetColTitle) {
|
|
5755
|
-
let sourceCol = "";
|
|
5756
|
-
let card = null;
|
|
5757
|
-
let sourceColIdx = -1;
|
|
5758
|
-
let cardIdx = -1;
|
|
5759
|
-
for (let ci = 0; ci < board.columns.length; ci++) {
|
|
5760
|
-
const col = board.columns[ci];
|
|
5761
|
-
const idx = col.cards.findIndex((c) => c.id === cardId);
|
|
5762
|
-
if (idx !== -1) {
|
|
5763
|
-
sourceCol = col.title;
|
|
5764
|
-
card = col.cards[idx];
|
|
5765
|
-
sourceColIdx = ci;
|
|
5766
|
-
cardIdx = idx;
|
|
5767
|
-
break;
|
|
5768
|
-
}
|
|
5769
|
-
}
|
|
5770
|
-
if (!card || sourceColIdx === -1) return false;
|
|
5771
|
-
const targetCol = board.columns.find(
|
|
5772
|
-
(c) => c.title.toLowerCase() === targetColTitle.toLowerCase()
|
|
5773
|
-
);
|
|
5774
|
-
if (!targetCol) {
|
|
5775
|
-
console.warn(`[kanban-commands] Target column "${targetColTitle}" not found. Available: ${board.columns.map((c) => c.title).join(", ")}`);
|
|
5776
|
-
return false;
|
|
5777
|
-
}
|
|
5778
|
-
if (targetCol.id === board.columns[sourceColIdx].id) return true;
|
|
5779
|
-
board.columns[sourceColIdx].cards.splice(cardIdx, 1);
|
|
5780
|
-
card.order = targetCol.cards.length;
|
|
5781
|
-
card.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5782
|
-
card.history = [...card.history ?? [], {
|
|
5783
|
-
type: "moved",
|
|
5784
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5785
|
-
detail: `"${sourceCol}" \u2192 "${targetCol.title}"`,
|
|
5786
|
-
author: "ai"
|
|
5787
|
-
}];
|
|
5788
|
-
targetCol.cards.push(card);
|
|
5789
|
-
return true;
|
|
5790
|
-
}
|
|
5791
5819
|
function addCardToColumn(board, columnTitle, cardTitle, cardContent) {
|
|
5792
5820
|
const col = board.columns.find((c) => c.title.toLowerCase() === columnTitle.toLowerCase());
|
|
5793
5821
|
if (!col) return;
|
|
@@ -5804,23 +5832,12 @@ function addCardToColumn(board, columnTitle, cardTitle, cardContent) {
|
|
|
5804
5832
|
};
|
|
5805
5833
|
col.cards.push(card);
|
|
5806
5834
|
}
|
|
5807
|
-
function
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
card.history = [...card.history ?? [], {
|
|
5812
|
-
type: "comment",
|
|
5813
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5814
|
-
detail: comment,
|
|
5815
|
-
author: "ai",
|
|
5816
|
-
...conversationId ? { conversationId } : {}
|
|
5817
|
-
}];
|
|
5818
|
-
card.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5819
|
-
return;
|
|
5820
|
-
}
|
|
5821
|
-
}
|
|
5835
|
+
function formatSize(bytes) {
|
|
5836
|
+
if (bytes < 1024) return `${bytes} o`;
|
|
5837
|
+
if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} Ko`;
|
|
5838
|
+
return `${(bytes / (1024 * 1024)).toFixed(1).replace(".", ",")} Mo`;
|
|
5822
5839
|
}
|
|
5823
|
-
function generateKanbanSystemPrompt(board, cardId) {
|
|
5840
|
+
function generateKanbanSystemPrompt(board, cardId, history) {
|
|
5824
5841
|
let currentColTitle = "";
|
|
5825
5842
|
let card = null;
|
|
5826
5843
|
for (const col of board.columns) {
|
|
@@ -5850,16 +5867,33 @@ function generateKanbanSystemPrompt(board, cardId) {
|
|
|
5850
5867
|
}
|
|
5851
5868
|
lines.push("");
|
|
5852
5869
|
if (card) {
|
|
5853
|
-
const
|
|
5870
|
+
const events = history ?? card.history ?? [];
|
|
5871
|
+
const comments = events.filter((e) => e.type === "comment");
|
|
5854
5872
|
if (comments.length > 0) {
|
|
5855
5873
|
lines.push("### Commentaires existants sur cette carte :");
|
|
5856
5874
|
lines.push("");
|
|
5857
5875
|
for (const c of comments.slice(-20)) {
|
|
5858
5876
|
const who = c.author === "ai" ? "AI" : "Utilisateur";
|
|
5859
5877
|
const date = new Date(c.timestamp).toLocaleString("fr-FR", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" });
|
|
5860
|
-
|
|
5878
|
+
const files = (c.attachments ?? []).map((f) => `\`${f.id}\` ${f.name}`).join(", ");
|
|
5879
|
+
lines.push(`- **${who}** (${date}) : ${c.detail}${files ? ` \u2014 pi\xE8ces jointes : ${files}` : ""}`);
|
|
5880
|
+
}
|
|
5881
|
+
lines.push("");
|
|
5882
|
+
}
|
|
5883
|
+
}
|
|
5884
|
+
if (card) {
|
|
5885
|
+
const files = card.attachments ?? [];
|
|
5886
|
+
const commentFiles = (history ?? card.history ?? []).flatMap((e) => e.attachments ?? []);
|
|
5887
|
+
const all = [...files, ...commentFiles];
|
|
5888
|
+
if (all.length > 0) {
|
|
5889
|
+
lines.push(`### Pi\xE8ces jointes disponibles (${all.length})`);
|
|
5890
|
+
lines.push("");
|
|
5891
|
+
for (const f of all) {
|
|
5892
|
+
lines.push(`- \`${f.id}\` \u2014 ${f.name} (${f.contentType}, ${formatSize(f.size)})`);
|
|
5861
5893
|
}
|
|
5862
5894
|
lines.push("");
|
|
5895
|
+
lines.push("> Ces fichiers ne sont **pas** dans ce prompt. Appelle `kanban_download_attachment(attachmentId)` pour en r\xE9cup\xE9rer un sur le disque, puis ouvre le chemin renvoy\xE9 avec tes outils de lecture de fichiers.");
|
|
5896
|
+
lines.push("");
|
|
5863
5897
|
}
|
|
5864
5898
|
}
|
|
5865
5899
|
lines.push("### Outils Kanban disponibles");
|
|
@@ -5870,6 +5904,7 @@ function generateKanbanSystemPrompt(board, cardId) {
|
|
|
5870
5904
|
lines.push("Tu disposes des outils suivants pour interagir avec le board :");
|
|
5871
5905
|
lines.push("- `kanban_move_card(boardId, cardId, targetColumn)` \u2014 D\xE9placer la carte vers une autre colonne");
|
|
5872
5906
|
lines.push("- `kanban_add_comment(boardId, cardId, comment)` \u2014 Ajouter un commentaire sur la carte");
|
|
5907
|
+
lines.push("- `kanban_download_attachment(attachmentId)` \u2014 T\xE9l\xE9charger une pi\xE8ce jointe et obtenir son chemin local");
|
|
5873
5908
|
lines.push("");
|
|
5874
5909
|
lines.push("### OBLIGATOIRE \u2014 D\xE9cision Kanban");
|
|
5875
5910
|
lines.push("");
|
|
@@ -6096,7 +6131,7 @@ function tailTranscript(opts) {
|
|
|
6096
6131
|
|
|
6097
6132
|
// ../server/src/services/ai-runners/claude-pty-runner.ts
|
|
6098
6133
|
async function getAgentManager() {
|
|
6099
|
-
const { agentManager: agentManager2 } = await import("./agent-manager-
|
|
6134
|
+
const { agentManager: agentManager2 } = await import("./agent-manager-KGITN4AE.js");
|
|
6100
6135
|
return agentManager2;
|
|
6101
6136
|
}
|
|
6102
6137
|
function buildPtyArgs(params, sessionId, opts) {
|
|
@@ -6749,7 +6784,7 @@ async function shutdownCodexAppServer() {
|
|
|
6749
6784
|
}
|
|
6750
6785
|
}
|
|
6751
6786
|
async function getAgentManager2() {
|
|
6752
|
-
const { agentManager: agentManager2 } = await import("./agent-manager-
|
|
6787
|
+
const { agentManager: agentManager2 } = await import("./agent-manager-KGITN4AE.js");
|
|
6753
6788
|
return agentManager2;
|
|
6754
6789
|
}
|
|
6755
6790
|
function parseRuneyaCurlCommand(command) {
|
|
@@ -7433,7 +7468,13 @@ async function buildCliSystemContext(conv, jwt) {
|
|
|
7433
7468
|
if (conv?.kanbanBoardId) {
|
|
7434
7469
|
const kanbanBoard = await kanbanStore.get(conv.kanbanBoardId);
|
|
7435
7470
|
if (kanbanBoard) {
|
|
7436
|
-
systemContext += "\n\n" + (conv.kanbanCardId ? generateKanbanSystemPrompt(
|
|
7471
|
+
systemContext += "\n\n" + (conv.kanbanCardId ? generateKanbanSystemPrompt(
|
|
7472
|
+
kanbanBoard,
|
|
7473
|
+
conv.kanbanCardId,
|
|
7474
|
+
// Le journal ne vient plus avec le tableau : le contexte de l'agent
|
|
7475
|
+
// le demande pour la seule carte qui le concerne.
|
|
7476
|
+
await kanbanStore.cardHistory(kanbanBoard.id, conv.kanbanCardId)
|
|
7477
|
+
) : generateKanbanPopulatePrompt(kanbanBoard));
|
|
7437
7478
|
}
|
|
7438
7479
|
}
|
|
7439
7480
|
return systemContext;
|
|
@@ -7834,7 +7875,13 @@ ${input.prompt}` : input.prompt;
|
|
|
7834
7875
|
if (conv.kanbanBoardId) {
|
|
7835
7876
|
const kanbanBoard = await kanbanStore.get(conv.kanbanBoardId);
|
|
7836
7877
|
if (kanbanBoard) {
|
|
7837
|
-
systemContext += "\n\n" + (conv.kanbanCardId ? generateKanbanSystemPrompt(
|
|
7878
|
+
systemContext += "\n\n" + (conv.kanbanCardId ? generateKanbanSystemPrompt(
|
|
7879
|
+
kanbanBoard,
|
|
7880
|
+
conv.kanbanCardId,
|
|
7881
|
+
// Le journal ne vient plus avec le tableau : le contexte de l'agent
|
|
7882
|
+
// le demande pour la seule carte qui le concerne.
|
|
7883
|
+
await kanbanStore.cardHistory(kanbanBoard.id, conv.kanbanCardId)
|
|
7884
|
+
) : generateKanbanPopulatePrompt(kanbanBoard));
|
|
7838
7885
|
}
|
|
7839
7886
|
}
|
|
7840
7887
|
const mcpServerPath = fileURLToPath(new URL("../mcp-server/index.js", import.meta.url));
|
|
@@ -7949,7 +7996,13 @@ ${input.prompt}` : input.prompt;
|
|
|
7949
7996
|
if (conv.kanbanBoardId) {
|
|
7950
7997
|
const kanbanBoard = await kanbanStore.get(conv.kanbanBoardId);
|
|
7951
7998
|
if (kanbanBoard) {
|
|
7952
|
-
systemContext += "\n\n" + (conv.kanbanCardId ? generateKanbanSystemPrompt(
|
|
7999
|
+
systemContext += "\n\n" + (conv.kanbanCardId ? generateKanbanSystemPrompt(
|
|
8000
|
+
kanbanBoard,
|
|
8001
|
+
conv.kanbanCardId,
|
|
8002
|
+
// Le journal ne vient plus avec le tableau : le contexte de l'agent
|
|
8003
|
+
// le demande pour la seule carte qui le concerne.
|
|
8004
|
+
await kanbanStore.cardHistory(kanbanBoard.id, conv.kanbanCardId)
|
|
8005
|
+
) : generateKanbanPopulatePrompt(kanbanBoard));
|
|
7953
8006
|
}
|
|
7954
8007
|
}
|
|
7955
8008
|
const resolvedImages = input.imageIds && input.imageIds.length > 0 ? await resolveImagesToBase64(input.imageIds.map((id) => ({ imageId: id, mimeType: "" })), input.conversationId) : [];
|
|
@@ -8042,7 +8095,13 @@ ${input.prompt}` : input.prompt;
|
|
|
8042
8095
|
if (conv && conv.kanbanBoardId) {
|
|
8043
8096
|
const kanbanBoard = await kanbanStore.get(conv.kanbanBoardId);
|
|
8044
8097
|
if (kanbanBoard) {
|
|
8045
|
-
system += "\n\n" + (conv.kanbanCardId ? generateKanbanSystemPrompt(
|
|
8098
|
+
system += "\n\n" + (conv.kanbanCardId ? generateKanbanSystemPrompt(
|
|
8099
|
+
kanbanBoard,
|
|
8100
|
+
conv.kanbanCardId,
|
|
8101
|
+
// Le journal ne vient plus avec le tableau : le contexte de l'agent
|
|
8102
|
+
// le demande pour la seule carte qui le concerne.
|
|
8103
|
+
await kanbanStore.cardHistory(kanbanBoard.id, conv.kanbanCardId)
|
|
8104
|
+
) : generateKanbanPopulatePrompt(kanbanBoard));
|
|
8046
8105
|
}
|
|
8047
8106
|
}
|
|
8048
8107
|
const resolvedImages = input.imageIds && input.imageIds.length > 0 ? await resolveImagesToBase64(input.imageIds.map((id) => ({ imageId: id, mimeType: "" })), input.conversationId) : [];
|
|
@@ -10736,19 +10795,8 @@ var KanbanQueueService = class extends EventEmitter4 {
|
|
|
10736
10795
|
this.running.push(runItem);
|
|
10737
10796
|
this.emit("changed");
|
|
10738
10797
|
const eventType = item.scenarioId ? "scenario_started" : "conversation_started";
|
|
10739
|
-
|
|
10740
|
-
|
|
10741
|
-
if (target) {
|
|
10742
|
-
target.history = [...target.history ?? [], {
|
|
10743
|
-
type: eventType,
|
|
10744
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10745
|
-
detail: conv.id
|
|
10746
|
-
}];
|
|
10747
|
-
kanbanStore.update({ id: board.id, columns: board.columns }).catch(() => {
|
|
10748
|
-
});
|
|
10749
|
-
break;
|
|
10750
|
-
}
|
|
10751
|
-
}
|
|
10798
|
+
kanbanStore.addCardEvent(board.id, item.cardId, eventType, conv.id).catch(() => {
|
|
10799
|
+
});
|
|
10752
10800
|
if (item.scenarioId) {
|
|
10753
10801
|
void runScenario(conv.id, item.scenarioId, cardContent, {
|
|
10754
10802
|
runnerOverride: item.runner,
|
|
@@ -10855,7 +10903,12 @@ var kanbanQueueRouter = router({
|
|
|
10855
10903
|
});
|
|
10856
10904
|
|
|
10857
10905
|
// ../server/src/trpc/routers/kanban.ts
|
|
10906
|
+
import { mkdir as mkdir14, readdir as readdir5, rm as rm2, stat as stat3, writeFile as writeFile11 } from "fs/promises";
|
|
10907
|
+
import { createHash } from "crypto";
|
|
10908
|
+
import { tmpdir } from "os";
|
|
10909
|
+
import { join as join16 } from "path";
|
|
10858
10910
|
import { z as z20 } from "zod";
|
|
10911
|
+
import { TRPCError as TRPCError17 } from "@trpc/server";
|
|
10859
10912
|
function summarizeCard(card, boardId, columnTitle) {
|
|
10860
10913
|
return {
|
|
10861
10914
|
boardId,
|
|
@@ -10864,8 +10917,15 @@ function summarizeCard(card, boardId, columnTitle) {
|
|
|
10864
10917
|
title: card.title,
|
|
10865
10918
|
markdown: card.markdown ?? "",
|
|
10866
10919
|
assignees: (card.assignees ?? []).map((a) => a.name),
|
|
10867
|
-
commentCount: (card.history ?? []).filter((e) => e.type === "comment").length,
|
|
10920
|
+
commentCount: card.commentCount ?? (card.history ?? []).filter((e) => e.type === "comment").length,
|
|
10868
10921
|
attachmentCount: (card.attachments ?? []).length,
|
|
10922
|
+
// Metadata only — the bytes are fetched on demand by `downloadAttachment`.
|
|
10923
|
+
attachments: (card.attachments ?? []).map((f) => ({
|
|
10924
|
+
id: f.id,
|
|
10925
|
+
name: f.name,
|
|
10926
|
+
contentType: f.contentType,
|
|
10927
|
+
size: f.size
|
|
10928
|
+
})),
|
|
10869
10929
|
createdAt: card.createdAt,
|
|
10870
10930
|
updatedAt: card.updatedAt
|
|
10871
10931
|
};
|
|
@@ -10887,6 +10947,49 @@ function boardCounts(board) {
|
|
|
10887
10947
|
function normalize(value) {
|
|
10888
10948
|
return value.normalize("NFD").replace(new RegExp("\\p{Diacritic}", "gu"), "").toLowerCase();
|
|
10889
10949
|
}
|
|
10950
|
+
var ATTACHMENT_ID_REGEX = /^[A-Za-z0-9_-]{1,128}$/;
|
|
10951
|
+
var MAX_ATTACHMENT_BYTES = 55 * 1024 * 1024;
|
|
10952
|
+
function attachmentCacheDir() {
|
|
10953
|
+
return join16(tmpdir(), "runeya-kanban-attachments");
|
|
10954
|
+
}
|
|
10955
|
+
var ATTACHMENT_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
10956
|
+
async function purgeStaleAttachments(dir, ttlMs = ATTACHMENT_CACHE_TTL_MS) {
|
|
10957
|
+
try {
|
|
10958
|
+
const cutoff = Date.now() - ttlMs;
|
|
10959
|
+
for (const name of await readdir5(dir)) {
|
|
10960
|
+
const path = join16(dir, name);
|
|
10961
|
+
const info = await stat3(path).catch(() => null);
|
|
10962
|
+
if (info && info.mtimeMs < cutoff) await rm2(path, { force: true });
|
|
10963
|
+
}
|
|
10964
|
+
} catch {
|
|
10965
|
+
}
|
|
10966
|
+
}
|
|
10967
|
+
function attachmentCacheDirs() {
|
|
10968
|
+
return [attachmentCacheDir(), join16(env.DATA_DIR, "kanban-attachments")];
|
|
10969
|
+
}
|
|
10970
|
+
async function storeAttachment(id, name, body, dirs = attachmentCacheDirs()) {
|
|
10971
|
+
const refusals = [];
|
|
10972
|
+
for (const dir of dirs) {
|
|
10973
|
+
try {
|
|
10974
|
+
await mkdir14(dir, { recursive: true });
|
|
10975
|
+
const path = join16(dir, safeLocalName(id, name));
|
|
10976
|
+
await writeFile11(path, body);
|
|
10977
|
+
void purgeStaleAttachments(dir);
|
|
10978
|
+
return path;
|
|
10979
|
+
} catch (err) {
|
|
10980
|
+
refusals.push(`${dir} (${err instanceof Error ? err.message : String(err)})`);
|
|
10981
|
+
}
|
|
10982
|
+
}
|
|
10983
|
+
throw new TRPCError17({
|
|
10984
|
+
code: "INTERNAL_SERVER_ERROR",
|
|
10985
|
+
message: `Impossible d'\xE9crire la pi\xE8ce jointe sur cette machine. Emplacements essay\xE9s : ${refusals.join(" ; ")}. V\xE9rifiez les droits d'\xE9criture, ou l'espace disque.`
|
|
10986
|
+
});
|
|
10987
|
+
}
|
|
10988
|
+
function safeLocalName(id, name) {
|
|
10989
|
+
const base = createHash("sha256").update(id).digest("hex").slice(0, 32);
|
|
10990
|
+
const ext = /\.([A-Za-z0-9]{1,12})$/.exec(name)?.[1];
|
|
10991
|
+
return ext ? `${base}.${ext.toLowerCase()}` : base;
|
|
10992
|
+
}
|
|
10890
10993
|
var kanbanRouter = router({
|
|
10891
10994
|
/**
|
|
10892
10995
|
* The organization's boards, without their cards — a board carries its whole
|
|
@@ -10976,12 +11079,46 @@ var kanbanRouter = router({
|
|
|
10976
11079
|
{ type: "add_card", columnTitle: input.column, cardTitle: input.title, cardContent: input.content }
|
|
10977
11080
|
]);
|
|
10978
11081
|
return { ok: true };
|
|
11082
|
+
}),
|
|
11083
|
+
/**
|
|
11084
|
+
* Fetch one card attachment from the cloud and drop it on this machine, so an
|
|
11085
|
+
* agent can open it with its own file tools. The bytes never go through the
|
|
11086
|
+
* prompt: the card context lists the attachments, this returns a path.
|
|
11087
|
+
*/
|
|
11088
|
+
downloadAttachment: protectedProcedure.input(z20.object({ attachmentId: z20.string().max(128) })).mutation(async ({ input }) => {
|
|
11089
|
+
const id = input.attachmentId;
|
|
11090
|
+
if (!ATTACHMENT_ID_REGEX.test(id)) {
|
|
11091
|
+
throw new TRPCError17({ code: "BAD_REQUEST", message: "Invalid attachment id" });
|
|
11092
|
+
}
|
|
11093
|
+
const res = await cloudFetch(`/api/kanban/file/${id}`, { timeoutMs: 12e4 });
|
|
11094
|
+
if (res.status === 404) {
|
|
11095
|
+
throw new TRPCError17({ code: "NOT_FOUND", message: `Attachment ${id} not found` });
|
|
11096
|
+
}
|
|
11097
|
+
if (!res.ok) {
|
|
11098
|
+
throw new TRPCError17({
|
|
11099
|
+
code: res.status === 403 ? "FORBIDDEN" : "INTERNAL_SERVER_ERROR",
|
|
11100
|
+
message: `Cloud refused the attachment (HTTP ${res.status})`
|
|
11101
|
+
});
|
|
11102
|
+
}
|
|
11103
|
+
const declared = Number(res.headers.get("content-length") ?? 0);
|
|
11104
|
+
if (declared > MAX_ATTACHMENT_BYTES) {
|
|
11105
|
+
throw new TRPCError17({ code: "PAYLOAD_TOO_LARGE", message: "Attachment too large to download" });
|
|
11106
|
+
}
|
|
11107
|
+
const body = Buffer.from(await res.arrayBuffer());
|
|
11108
|
+
if (body.length > MAX_ATTACHMENT_BYTES) {
|
|
11109
|
+
throw new TRPCError17({ code: "PAYLOAD_TOO_LARGE", message: "Attachment too large to download" });
|
|
11110
|
+
}
|
|
11111
|
+
const contentType = res.headers.get("content-type") ?? "application/octet-stream";
|
|
11112
|
+
const disposition = res.headers.get("content-disposition") ?? "";
|
|
11113
|
+
const name = /filename="([^"]*)"/.exec(disposition)?.[1] || id;
|
|
11114
|
+
const path = await storeAttachment(id, name, body);
|
|
11115
|
+
return { path, name, contentType, size: body.length };
|
|
10979
11116
|
})
|
|
10980
11117
|
});
|
|
10981
11118
|
|
|
10982
11119
|
// ../server/src/trpc/routers/terminal.ts
|
|
10983
11120
|
import { z as z21 } from "zod";
|
|
10984
|
-
import { TRPCError as
|
|
11121
|
+
import { TRPCError as TRPCError18 } from "@trpc/server";
|
|
10985
11122
|
var terminalRouter = router({
|
|
10986
11123
|
/** Create a PTY shell session on the target agent */
|
|
10987
11124
|
create: protectedProcedure.input(z21.object({
|
|
@@ -11066,7 +11203,7 @@ var terminalRouter = router({
|
|
|
11066
11203
|
}
|
|
11067
11204
|
);
|
|
11068
11205
|
} catch (err) {
|
|
11069
|
-
throw new
|
|
11206
|
+
throw new TRPCError18({
|
|
11070
11207
|
code: "BAD_REQUEST",
|
|
11071
11208
|
message: `Cannot subscribe to terminal: ${err.message}`
|
|
11072
11209
|
});
|
|
@@ -11101,9 +11238,9 @@ var utilityRouter = router({
|
|
|
11101
11238
|
|
|
11102
11239
|
// ../server/src/trpc/routers/wiki.ts
|
|
11103
11240
|
import { z as z23 } from "zod";
|
|
11104
|
-
import { TRPCError as
|
|
11105
|
-
import { readFile as readFile13, readdir as
|
|
11106
|
-
import { resolve as resolvePath, join as
|
|
11241
|
+
import { TRPCError as TRPCError19 } from "@trpc/server";
|
|
11242
|
+
import { readFile as readFile13, readdir as readdir6, stat as stat4, realpath, writeFile as writeFile12, mkdir as mkdir15, rename as rename10, rm as rm3 } from "fs/promises";
|
|
11243
|
+
import { resolve as resolvePath, join as join17, relative, sep as sep3, dirname as dirname3 } from "path";
|
|
11107
11244
|
var SCOPE_SCHEMA = z23.union([
|
|
11108
11245
|
z23.literal("global"),
|
|
11109
11246
|
z23.string().regex(/^service:[A-Za-z0-9_-]{1,128}$/, "Invalid service scope")
|
|
@@ -11137,27 +11274,27 @@ async function resolveScope(scope) {
|
|
|
11137
11274
|
const settings = await settingsManager.getSettings();
|
|
11138
11275
|
const sub = (settings.globalDocsPath?.trim() || "wiki").replace(/^[\\/]+|[\\/]+$/g, "");
|
|
11139
11276
|
if (sub.includes("..") || sub.includes("\0")) {
|
|
11140
|
-
throw new
|
|
11277
|
+
throw new TRPCError19({ code: "BAD_REQUEST", message: "Sous-chemin invalide" });
|
|
11141
11278
|
}
|
|
11142
11279
|
const dataDirAbs = resolvePath(env.DATA_DIR);
|
|
11143
|
-
await
|
|
11280
|
+
await mkdir15(dataDirAbs, { recursive: true });
|
|
11144
11281
|
const base = dirname3(await realpath(dataDirAbs));
|
|
11145
11282
|
const target = resolvePath(base, sub);
|
|
11146
11283
|
if (target !== base && !(target + sep3).startsWith(base + sep3)) {
|
|
11147
|
-
throw new
|
|
11284
|
+
throw new TRPCError19({ code: "FORBIDDEN", message: "Hors du dossier de donn\xE9es du serveur" });
|
|
11148
11285
|
}
|
|
11149
|
-
await
|
|
11286
|
+
await mkdir15(target, { recursive: true });
|
|
11150
11287
|
const root = await realpath(target);
|
|
11151
11288
|
if (root !== base && !(root + sep3).startsWith(base + sep3)) {
|
|
11152
|
-
throw new
|
|
11289
|
+
throw new TRPCError19({ code: "FORBIDDEN", message: "Le dossier wiki r\xE9sout hors du dossier de donn\xE9es" });
|
|
11153
11290
|
}
|
|
11154
11291
|
return { mode: "local", root };
|
|
11155
11292
|
}
|
|
11156
11293
|
const serviceId = scope.slice("service:".length);
|
|
11157
11294
|
const service = await serviceStore.get(serviceId);
|
|
11158
|
-
if (!service) throw new
|
|
11295
|
+
if (!service) throw new TRPCError19({ code: "NOT_FOUND", message: "Service introuvable" });
|
|
11159
11296
|
const agentId = await resolveEffectiveAgentId(service);
|
|
11160
|
-
if (!agentId) throw new
|
|
11297
|
+
if (!agentId) throw new TRPCError19({ code: "BAD_REQUEST", message: "Aucun agent configur\xE9 pour ce service" });
|
|
11161
11298
|
const cwd = (service.docsPath?.trim() || service.cwd || ".").toString();
|
|
11162
11299
|
return { mode: "agent", agentId, cwd };
|
|
11163
11300
|
}
|
|
@@ -11165,7 +11302,7 @@ async function walkLocal(root, dir, depth, counter) {
|
|
|
11165
11302
|
if (depth > MAX_DEPTH || counter.n >= MAX_FILES) return [];
|
|
11166
11303
|
let entries;
|
|
11167
11304
|
try {
|
|
11168
|
-
entries = await
|
|
11305
|
+
entries = await readdir6(dir, { withFileTypes: true });
|
|
11169
11306
|
} catch {
|
|
11170
11307
|
return [];
|
|
11171
11308
|
}
|
|
@@ -11173,7 +11310,7 @@ async function walkLocal(root, dir, depth, counter) {
|
|
|
11173
11310
|
for (const e of entries) {
|
|
11174
11311
|
if (counter.n >= MAX_FILES) break;
|
|
11175
11312
|
if (e.name.startsWith(".") && e.name !== ".") continue;
|
|
11176
|
-
const abs =
|
|
11313
|
+
const abs = join17(dir, e.name);
|
|
11177
11314
|
const rel = relative(root, abs).split(sep3).join("/");
|
|
11178
11315
|
if (e.isDirectory()) {
|
|
11179
11316
|
if (IGNORED_DIRS.has(e.name)) continue;
|
|
@@ -11192,7 +11329,7 @@ async function walkLocal(root, dir, depth, counter) {
|
|
|
11192
11329
|
}
|
|
11193
11330
|
async function resolveSafeLocal(root, relPath, requireExist) {
|
|
11194
11331
|
if (relPath.includes("..") || relPath.startsWith("/")) {
|
|
11195
|
-
throw new
|
|
11332
|
+
throw new TRPCError19({ code: "BAD_REQUEST", message: "Chemin invalide" });
|
|
11196
11333
|
}
|
|
11197
11334
|
const target = resolvePath(root, relPath);
|
|
11198
11335
|
if (requireExist) {
|
|
@@ -11200,10 +11337,10 @@ async function resolveSafeLocal(root, relPath, requireExist) {
|
|
|
11200
11337
|
try {
|
|
11201
11338
|
real = await realpath(target);
|
|
11202
11339
|
} catch {
|
|
11203
|
-
throw new
|
|
11340
|
+
throw new TRPCError19({ code: "NOT_FOUND", message: "Chemin introuvable" });
|
|
11204
11341
|
}
|
|
11205
11342
|
if (real !== root && !(real + sep3).startsWith(root + sep3)) {
|
|
11206
|
-
throw new
|
|
11343
|
+
throw new TRPCError19({ code: "FORBIDDEN", message: "Hors du dossier autoris\xE9" });
|
|
11207
11344
|
}
|
|
11208
11345
|
return real;
|
|
11209
11346
|
}
|
|
@@ -11215,7 +11352,7 @@ async function resolveSafeLocal(root, relPath, requireExist) {
|
|
|
11215
11352
|
realParent = parent;
|
|
11216
11353
|
}
|
|
11217
11354
|
if (realParent !== root && !(realParent + sep3).startsWith(root + sep3)) {
|
|
11218
|
-
throw new
|
|
11355
|
+
throw new TRPCError19({ code: "FORBIDDEN", message: "Hors du dossier autoris\xE9" });
|
|
11219
11356
|
}
|
|
11220
11357
|
return resolvePath(realParent, target.slice(parent.length).replace(/^[\\/]+/, ""));
|
|
11221
11358
|
}
|
|
@@ -11231,35 +11368,35 @@ var wikiRouter = router({
|
|
|
11231
11368
|
}),
|
|
11232
11369
|
read: protectedProcedure.input(z23.object({ scope: SCOPE_SCHEMA, path: REL_PATH_SCHEMA })).output(z23.object({ path: z23.string(), content: z23.string() })).query(async ({ input }) => {
|
|
11233
11370
|
if (!/\.(md|markdown)$/i.test(input.path)) {
|
|
11234
|
-
throw new
|
|
11371
|
+
throw new TRPCError19({ code: "BAD_REQUEST", message: "Seuls les .md/.markdown sont autoris\xE9s" });
|
|
11235
11372
|
}
|
|
11236
11373
|
const target = await resolveScope(input.scope);
|
|
11237
11374
|
if (target.mode === "agent") {
|
|
11238
11375
|
return agentManager.agentQuery(target.agentId, "wiki.readRepoMarkdown", { cwd: target.cwd, path: input.path });
|
|
11239
11376
|
}
|
|
11240
11377
|
const file = await resolveSafeLocal(target.root, input.path, true);
|
|
11241
|
-
const s = await
|
|
11242
|
-
if (!s.isFile()) throw new
|
|
11243
|
-
if (s.size > MAX_FILE_BYTES) throw new
|
|
11378
|
+
const s = await stat4(file);
|
|
11379
|
+
if (!s.isFile()) throw new TRPCError19({ code: "BAD_REQUEST", message: "Pas un fichier" });
|
|
11380
|
+
if (s.size > MAX_FILE_BYTES) throw new TRPCError19({ code: "PAYLOAD_TOO_LARGE", message: "Fichier trop volumineux" });
|
|
11244
11381
|
const content = await readFile13(file, "utf-8");
|
|
11245
11382
|
return { path: input.path, content };
|
|
11246
11383
|
}),
|
|
11247
11384
|
write: protectedProcedure.input(z23.object({ scope: SCOPE_SCHEMA, path: REL_PATH_SCHEMA, content: z23.string().max(5e6) })).mutation(async ({ input }) => {
|
|
11248
11385
|
if (!/\.(md|markdown)$/i.test(input.path)) {
|
|
11249
|
-
throw new
|
|
11386
|
+
throw new TRPCError19({ code: "BAD_REQUEST", message: "Seuls les .md/.markdown sont autoris\xE9s" });
|
|
11250
11387
|
}
|
|
11251
11388
|
const target = await resolveScope(input.scope);
|
|
11252
11389
|
if (target.mode === "agent") {
|
|
11253
11390
|
return agentManager.agentMutation(target.agentId, "wiki.writeMarkdown", { cwd: target.cwd, path: input.path, content: input.content });
|
|
11254
11391
|
}
|
|
11255
11392
|
const file = await resolveSafeLocal(target.root, input.path, false);
|
|
11256
|
-
await
|
|
11257
|
-
await
|
|
11393
|
+
await mkdir15(dirname3(file), { recursive: true });
|
|
11394
|
+
await writeFile12(file, input.content, "utf-8");
|
|
11258
11395
|
return { path: input.path, ok: true };
|
|
11259
11396
|
}),
|
|
11260
11397
|
createFile: protectedProcedure.input(z23.object({ scope: SCOPE_SCHEMA, path: REL_PATH_SCHEMA })).mutation(async ({ input }) => {
|
|
11261
11398
|
if (!/\.(md|markdown)$/i.test(input.path)) {
|
|
11262
|
-
throw new
|
|
11399
|
+
throw new TRPCError19({ code: "BAD_REQUEST", message: "Seuls les .md/.markdown sont autoris\xE9s" });
|
|
11263
11400
|
}
|
|
11264
11401
|
const target = await resolveScope(input.scope);
|
|
11265
11402
|
if (target.mode === "agent") {
|
|
@@ -11267,13 +11404,13 @@ var wikiRouter = router({
|
|
|
11267
11404
|
}
|
|
11268
11405
|
const file = await resolveSafeLocal(target.root, input.path, false);
|
|
11269
11406
|
try {
|
|
11270
|
-
await
|
|
11271
|
-
throw new
|
|
11407
|
+
await stat4(file);
|
|
11408
|
+
throw new TRPCError19({ code: "CONFLICT", message: "Fichier d\xE9j\xE0 existant" });
|
|
11272
11409
|
} catch (err) {
|
|
11273
|
-
if (err instanceof
|
|
11410
|
+
if (err instanceof TRPCError19) throw err;
|
|
11274
11411
|
}
|
|
11275
|
-
await
|
|
11276
|
-
await
|
|
11412
|
+
await mkdir15(dirname3(file), { recursive: true });
|
|
11413
|
+
await writeFile12(file, "", "utf-8");
|
|
11277
11414
|
return { path: input.path, ok: true };
|
|
11278
11415
|
}),
|
|
11279
11416
|
createDir: protectedProcedure.input(z23.object({ scope: SCOPE_SCHEMA, path: REL_PATH_SCHEMA })).mutation(async ({ input }) => {
|
|
@@ -11282,7 +11419,7 @@ var wikiRouter = router({
|
|
|
11282
11419
|
return agentManager.agentMutation(target.agentId, "wiki.createDir", { cwd: target.cwd, path: input.path });
|
|
11283
11420
|
}
|
|
11284
11421
|
const dir = await resolveSafeLocal(target.root, input.path, false);
|
|
11285
|
-
await
|
|
11422
|
+
await mkdir15(dir, { recursive: true });
|
|
11286
11423
|
return { path: input.path, ok: true };
|
|
11287
11424
|
}),
|
|
11288
11425
|
rename: protectedProcedure.input(z23.object({ scope: SCOPE_SCHEMA, fromPath: REL_PATH_SCHEMA, toPath: REL_PATH_SCHEMA })).mutation(async ({ input }) => {
|
|
@@ -11293,12 +11430,12 @@ var wikiRouter = router({
|
|
|
11293
11430
|
const from = await resolveSafeLocal(target.root, input.fromPath, true);
|
|
11294
11431
|
const to = await resolveSafeLocal(target.root, input.toPath, false);
|
|
11295
11432
|
try {
|
|
11296
|
-
await
|
|
11297
|
-
throw new
|
|
11433
|
+
await stat4(to);
|
|
11434
|
+
throw new TRPCError19({ code: "CONFLICT", message: "La cible existe d\xE9j\xE0" });
|
|
11298
11435
|
} catch (err) {
|
|
11299
|
-
if (err instanceof
|
|
11436
|
+
if (err instanceof TRPCError19) throw err;
|
|
11300
11437
|
}
|
|
11301
|
-
await
|
|
11438
|
+
await mkdir15(dirname3(to), { recursive: true });
|
|
11302
11439
|
await rename10(from, to);
|
|
11303
11440
|
return { fromPath: input.fromPath, toPath: input.toPath, ok: true };
|
|
11304
11441
|
}),
|
|
@@ -11309,9 +11446,9 @@ var wikiRouter = router({
|
|
|
11309
11446
|
}
|
|
11310
11447
|
const serviceId = input.scope.slice("service:".length);
|
|
11311
11448
|
const service = await serviceStore.get(serviceId);
|
|
11312
|
-
if (!service) throw new
|
|
11449
|
+
if (!service) throw new TRPCError19({ code: "NOT_FOUND", message: "Service introuvable" });
|
|
11313
11450
|
const agentId = await resolveEffectiveAgentId(service);
|
|
11314
|
-
if (!agentId) throw new
|
|
11451
|
+
if (!agentId) throw new TRPCError19({ code: "BAD_REQUEST", message: "Aucun agent configur\xE9" });
|
|
11315
11452
|
const cwd = (service.docsPath?.trim() || service.cwd || ".").toString();
|
|
11316
11453
|
return agentManager.agentMutation(agentId, "wiki.ensureRoot", { cwd });
|
|
11317
11454
|
}),
|
|
@@ -11321,8 +11458,8 @@ var wikiRouter = router({
|
|
|
11321
11458
|
return agentManager.agentMutation(target.agentId, "wiki.deletePath", { cwd: target.cwd, path: input.path });
|
|
11322
11459
|
}
|
|
11323
11460
|
const fp = await resolveSafeLocal(target.root, input.path, true);
|
|
11324
|
-
if (fp === target.root) throw new
|
|
11325
|
-
await
|
|
11461
|
+
if (fp === target.root) throw new TRPCError19({ code: "FORBIDDEN", message: "Impossible de supprimer la racine" });
|
|
11462
|
+
await rm3(fp, { recursive: true, force: true });
|
|
11326
11463
|
return { path: input.path, ok: true };
|
|
11327
11464
|
})
|
|
11328
11465
|
});
|
|
@@ -11337,17 +11474,17 @@ var configRouter = router({
|
|
|
11337
11474
|
|
|
11338
11475
|
// ../server/src/trpc/routers/cloud-sync.ts
|
|
11339
11476
|
import { z as z24 } from "zod";
|
|
11340
|
-
import { TRPCError as
|
|
11477
|
+
import { TRPCError as TRPCError20 } from "@trpc/server";
|
|
11341
11478
|
|
|
11342
11479
|
// ../server/src/services/cloud-sync-store.ts
|
|
11343
|
-
import { readFile as readFile14, writeFile as
|
|
11344
|
-
import { join as
|
|
11480
|
+
import { readFile as readFile14, writeFile as writeFile13, rename as rename11, mkdir as mkdir16, chmod as chmod9 } from "fs/promises";
|
|
11481
|
+
import { join as join18 } from "path";
|
|
11345
11482
|
var FILENAME5 = "cloud-sync.json";
|
|
11346
11483
|
var CloudSyncStore = class {
|
|
11347
11484
|
links = /* @__PURE__ */ new Map();
|
|
11348
11485
|
loaded = false;
|
|
11349
11486
|
getFilePath() {
|
|
11350
|
-
return
|
|
11487
|
+
return join18(env.DATA_DIR, FILENAME5);
|
|
11351
11488
|
}
|
|
11352
11489
|
async load() {
|
|
11353
11490
|
if (this.loaded) return;
|
|
@@ -11360,11 +11497,11 @@ var CloudSyncStore = class {
|
|
|
11360
11497
|
this.loaded = true;
|
|
11361
11498
|
}
|
|
11362
11499
|
async save() {
|
|
11363
|
-
await
|
|
11500
|
+
await mkdir16(env.DATA_DIR, { recursive: true });
|
|
11364
11501
|
const filePath = this.getFilePath();
|
|
11365
11502
|
const tmpPath = filePath + ".tmp";
|
|
11366
11503
|
const data = JSON.stringify(Array.from(this.links.values()), null, 2);
|
|
11367
|
-
await
|
|
11504
|
+
await writeFile13(tmpPath, data, "utf-8");
|
|
11368
11505
|
await rename11(tmpPath, filePath);
|
|
11369
11506
|
await chmod9(filePath, 384);
|
|
11370
11507
|
}
|
|
@@ -11760,8 +11897,8 @@ var cloudSyncBridge = new CloudSyncBridge();
|
|
|
11760
11897
|
|
|
11761
11898
|
// ../server/src/services/master-password.ts
|
|
11762
11899
|
import { randomBytes as randomBytes4, createCipheriv, createDecipheriv } from "crypto";
|
|
11763
|
-
import { readFile as readFile15, writeFile as
|
|
11764
|
-
import { join as
|
|
11900
|
+
import { readFile as readFile15, writeFile as writeFile14, chmod as chmod10, stat as stat5, rename as rename12 } from "fs/promises";
|
|
11901
|
+
import { join as join19 } from "path";
|
|
11765
11902
|
import { Entry } from "@napi-rs/keyring";
|
|
11766
11903
|
import { hashRaw as argon2HashRaw } from "@node-rs/argon2";
|
|
11767
11904
|
var KEYRING_SERVICE = "runeya";
|
|
@@ -11773,7 +11910,7 @@ var CANARY_PLAINTEXT = "runeya:v1:key-verification";
|
|
|
11773
11910
|
var MAX_KEY_FILE_SIZE = 1024;
|
|
11774
11911
|
var ARGON2_OPTIONS = { memoryCost: 65536, timeCost: 3, parallelism: 4, outputLen: 32 };
|
|
11775
11912
|
async function readKeyFile(filePath) {
|
|
11776
|
-
const s = await
|
|
11913
|
+
const s = await stat5(filePath);
|
|
11777
11914
|
if (s.size > MAX_KEY_FILE_SIZE) throw new Error(`Fichier suspect : ${filePath} (${s.size} octets)`);
|
|
11778
11915
|
return readFile15(filePath);
|
|
11779
11916
|
}
|
|
@@ -11794,7 +11931,7 @@ function aesDecrypt(key, data) {
|
|
|
11794
11931
|
}
|
|
11795
11932
|
async function getPepperFromFile(dataDir) {
|
|
11796
11933
|
try {
|
|
11797
|
-
const raw = await readKeyFile(
|
|
11934
|
+
const raw = await readKeyFile(join19(dataDir, PEPPER_FILENAME));
|
|
11798
11935
|
const hex = raw.toString("utf-8").trim();
|
|
11799
11936
|
if (/^[0-9a-f]{64}$/i.test(hex)) return Buffer.from(hex, "hex");
|
|
11800
11937
|
} catch {
|
|
@@ -11802,9 +11939,9 @@ async function getPepperFromFile(dataDir) {
|
|
|
11802
11939
|
return null;
|
|
11803
11940
|
}
|
|
11804
11941
|
async function writePepperToFile(dataDir, pepper) {
|
|
11805
|
-
const filePath =
|
|
11942
|
+
const filePath = join19(dataDir, PEPPER_FILENAME);
|
|
11806
11943
|
const tmpPath = filePath + ".tmp";
|
|
11807
|
-
await
|
|
11944
|
+
await writeFile14(tmpPath, pepper.toString("hex"), "utf-8");
|
|
11808
11945
|
await chmod10(tmpPath, 384);
|
|
11809
11946
|
await rename12(tmpPath, filePath);
|
|
11810
11947
|
}
|
|
@@ -11853,14 +11990,14 @@ async function writeEncryptedKey(dataDir, masterPassword, encryptionKey) {
|
|
|
11853
11990
|
const payload = aesEncrypt(derivedKey, encryptionKey);
|
|
11854
11991
|
const fileContent = Buffer.concat([salt, payload]);
|
|
11855
11992
|
const encoded = fileContent.toString("base64");
|
|
11856
|
-
const filePath =
|
|
11993
|
+
const filePath = join19(dataDir, ENCRYPTED_KEY_FILENAME);
|
|
11857
11994
|
const tmpPath = filePath + ".tmp";
|
|
11858
|
-
await
|
|
11995
|
+
await writeFile14(tmpPath, encoded, "utf-8");
|
|
11859
11996
|
await chmod10(tmpPath, 384);
|
|
11860
11997
|
await rename12(tmpPath, filePath);
|
|
11861
11998
|
}
|
|
11862
11999
|
async function readEncryptedKey(dataDir, masterPassword) {
|
|
11863
|
-
const filePath =
|
|
12000
|
+
const filePath = join19(dataDir, ENCRYPTED_KEY_FILENAME);
|
|
11864
12001
|
const raw = await readKeyFile(filePath);
|
|
11865
12002
|
const fileContent = Buffer.from(raw.toString("utf-8").trim(), "base64");
|
|
11866
12003
|
const salt = fileContent.subarray(0, 16);
|
|
@@ -11880,13 +12017,13 @@ async function getPepperFromKeychain(dataDir) {
|
|
|
11880
12017
|
}
|
|
11881
12018
|
async function writeVerifyFile(dataDir, encryptionKey) {
|
|
11882
12019
|
const payload = aesEncrypt(encryptionKey, Buffer.from(CANARY_PLAINTEXT, "utf-8"));
|
|
11883
|
-
const filePath =
|
|
12020
|
+
const filePath = join19(dataDir, VERIFY_FILENAME);
|
|
11884
12021
|
const tmpPath = filePath + ".tmp";
|
|
11885
|
-
await
|
|
12022
|
+
await writeFile14(tmpPath, payload.toString("base64"), "utf-8");
|
|
11886
12023
|
await rename12(tmpPath, filePath);
|
|
11887
12024
|
}
|
|
11888
12025
|
async function verifyEncryptionKey(dataDir, encryptionKey) {
|
|
11889
|
-
const filePath =
|
|
12026
|
+
const filePath = join19(dataDir, VERIFY_FILENAME);
|
|
11890
12027
|
const raw = await readKeyFile(filePath);
|
|
11891
12028
|
if (!matchesCanary(raw.toString("utf-8"), encryptionKey)) {
|
|
11892
12029
|
throw new Error("Cl\xE9 d'encryption incorrecte");
|
|
@@ -11902,14 +12039,14 @@ function matchesCanary(canaryBase64, encryptionKey) {
|
|
|
11902
12039
|
}
|
|
11903
12040
|
async function readVerifyFile(dataDir) {
|
|
11904
12041
|
try {
|
|
11905
|
-
return (await readKeyFile(
|
|
12042
|
+
return (await readKeyFile(join19(dataDir, VERIFY_FILENAME))).toString("utf-8").trim();
|
|
11906
12043
|
} catch {
|
|
11907
12044
|
return null;
|
|
11908
12045
|
}
|
|
11909
12046
|
}
|
|
11910
12047
|
async function hasVerifyFile(dataDir) {
|
|
11911
12048
|
try {
|
|
11912
|
-
await
|
|
12049
|
+
await stat5(join19(dataDir, VERIFY_FILENAME));
|
|
11913
12050
|
return true;
|
|
11914
12051
|
} catch {
|
|
11915
12052
|
return false;
|
|
@@ -11917,7 +12054,7 @@ async function hasVerifyFile(dataDir) {
|
|
|
11917
12054
|
}
|
|
11918
12055
|
async function hasEncryptedKeyFile(dataDir) {
|
|
11919
12056
|
try {
|
|
11920
|
-
await
|
|
12057
|
+
await stat5(join19(dataDir, ENCRYPTED_KEY_FILENAME));
|
|
11921
12058
|
return true;
|
|
11922
12059
|
} catch {
|
|
11923
12060
|
return false;
|
|
@@ -11928,25 +12065,25 @@ async function hasEncryptedKeyFile(dataDir) {
|
|
|
11928
12065
|
async function reconcileOrgCanary(orgId) {
|
|
11929
12066
|
const key = getEncryptionKey();
|
|
11930
12067
|
if (!key) {
|
|
11931
|
-
throw new
|
|
12068
|
+
throw new TRPCError20({ code: "PRECONDITION_FAILED", message: "Encryption key not loaded." });
|
|
11932
12069
|
}
|
|
11933
12070
|
const local = await readVerifyFile(env.DATA_DIR);
|
|
11934
12071
|
if (!local) {
|
|
11935
|
-
throw new
|
|
12072
|
+
throw new TRPCError20({ code: "PRECONDITION_FAILED", message: "This machine has no key canary yet." });
|
|
11936
12073
|
}
|
|
11937
12074
|
const res = await cloudFetch("/api/auth/organization/canary", {
|
|
11938
12075
|
method: "POST",
|
|
11939
12076
|
body: { organizationId: orgId, canary: local }
|
|
11940
12077
|
});
|
|
11941
12078
|
if (!res.ok) {
|
|
11942
|
-
throw new
|
|
12079
|
+
throw new TRPCError20({ code: "BAD_GATEWAY", message: "Could not reach the organization on the cloud." });
|
|
11943
12080
|
}
|
|
11944
12081
|
const { canary } = await res.json();
|
|
11945
12082
|
if (typeof canary !== "string") {
|
|
11946
|
-
throw new
|
|
12083
|
+
throw new TRPCError20({ code: "BAD_GATEWAY", message: "The cloud returned no key canary." });
|
|
11947
12084
|
}
|
|
11948
12085
|
if (!matchesCanary(canary, key)) {
|
|
11949
|
-
throw new
|
|
12086
|
+
throw new TRPCError20({
|
|
11950
12087
|
code: "FORBIDDEN",
|
|
11951
12088
|
message: "This organization uses a different encryption key. Ask a member for the key already in use, then set it up on this machine before syncing."
|
|
11952
12089
|
});
|
|
@@ -12050,8 +12187,8 @@ var MigrationEngine = class {
|
|
|
12050
12187
|
var migrationEngine = new MigrationEngine();
|
|
12051
12188
|
|
|
12052
12189
|
// ../server/src/services/file-security.ts
|
|
12053
|
-
import { chmod as chmod11, stat as
|
|
12054
|
-
import { join as
|
|
12190
|
+
import { chmod as chmod11, stat as stat6 } from "fs/promises";
|
|
12191
|
+
import { join as join20 } from "path";
|
|
12055
12192
|
var SENSITIVE_FILES = [
|
|
12056
12193
|
"agents.json",
|
|
12057
12194
|
"settings.json",
|
|
@@ -12063,9 +12200,9 @@ var SENSITIVE_FILES = [
|
|
|
12063
12200
|
var SECURE_MODE = 384;
|
|
12064
12201
|
async function ensureFilePermissions() {
|
|
12065
12202
|
for (const filename of SENSITIVE_FILES) {
|
|
12066
|
-
const filepath =
|
|
12203
|
+
const filepath = join20(env.DATA_DIR, filename);
|
|
12067
12204
|
try {
|
|
12068
|
-
const stats = await
|
|
12205
|
+
const stats = await stat6(filepath);
|
|
12069
12206
|
const mode = stats.mode & 511;
|
|
12070
12207
|
if (mode !== SECURE_MODE) {
|
|
12071
12208
|
console.warn("[security] File", filename, "has mode", mode.toString(8) + ", fixing to 600");
|
|
@@ -12080,8 +12217,8 @@ async function ensureFilePermissions() {
|
|
|
12080
12217
|
}
|
|
12081
12218
|
|
|
12082
12219
|
// ../server/src/utils/ensure-data-gitignore.ts
|
|
12083
|
-
import { writeFile as
|
|
12084
|
-
import { join as
|
|
12220
|
+
import { writeFile as writeFile15 } from "fs/promises";
|
|
12221
|
+
import { join as join21 } from "path";
|
|
12085
12222
|
var GITIGNORE_CONTENT = `
|
|
12086
12223
|
#################
|
|
12087
12224
|
# Do not edit this file #
|
|
@@ -12118,8 +12255,8 @@ conversations.private.json
|
|
|
12118
12255
|
*.log.*
|
|
12119
12256
|
`;
|
|
12120
12257
|
async function ensureDataGitignore(dataDir) {
|
|
12121
|
-
const gitignorePath =
|
|
12122
|
-
await
|
|
12258
|
+
const gitignorePath = join21(dataDir, ".gitignore");
|
|
12259
|
+
await writeFile15(gitignorePath, GITIGNORE_CONTENT, "utf-8");
|
|
12123
12260
|
}
|
|
12124
12261
|
|
|
12125
12262
|
// ../server/src/migrations/migrate-from-legacy.ts
|
|
@@ -12128,13 +12265,13 @@ import { randomBytes as randomBytes5, createCipheriv as createCipheriv2, createD
|
|
|
12128
12265
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
12129
12266
|
import {
|
|
12130
12267
|
readFile as readFile16,
|
|
12131
|
-
writeFile as
|
|
12268
|
+
writeFile as writeFile16,
|
|
12132
12269
|
rename as rename13,
|
|
12133
|
-
mkdir as
|
|
12270
|
+
mkdir as mkdir17,
|
|
12134
12271
|
access as access2,
|
|
12135
|
-
readdir as
|
|
12272
|
+
readdir as readdir7
|
|
12136
12273
|
} from "fs/promises";
|
|
12137
|
-
import { join as
|
|
12274
|
+
import { join as join22 } from "path";
|
|
12138
12275
|
var _require = createRequire(import.meta.url);
|
|
12139
12276
|
var PARSER_ID_MAP = {
|
|
12140
12277
|
"stack-monitor-parser-jsons": "native:json",
|
|
@@ -12263,14 +12400,14 @@ async function decryptLegacyFile(filePath, key, sodium) {
|
|
|
12263
12400
|
}
|
|
12264
12401
|
async function atomicWrite(path, data) {
|
|
12265
12402
|
const tmp = path + ".tmp";
|
|
12266
|
-
await
|
|
12403
|
+
await writeFile16(tmp, JSON.stringify(data, null, 2), "utf-8");
|
|
12267
12404
|
await rename13(tmp, path);
|
|
12268
12405
|
}
|
|
12269
12406
|
async function runLegacyMigration(dataDir) {
|
|
12270
12407
|
const { resolve: resolve6 } = await import("path");
|
|
12271
12408
|
const abCwd = resolve6(process.cwd());
|
|
12272
|
-
const legacyRoot =
|
|
12273
|
-
const legacyKeyPath =
|
|
12409
|
+
const legacyRoot = join22(abCwd, env.DATA_DIR);
|
|
12410
|
+
const legacyKeyPath = join22(legacyRoot, "dbs", "encryption-key.json");
|
|
12274
12411
|
try {
|
|
12275
12412
|
await access2(legacyKeyPath);
|
|
12276
12413
|
} catch {
|
|
@@ -12278,20 +12415,20 @@ async function runLegacyMigration(dataDir) {
|
|
|
12278
12415
|
}
|
|
12279
12416
|
console.log("[legacy-migration] Legacy Runeya data detected, starting migration\u2026");
|
|
12280
12417
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").substring(0, 19);
|
|
12281
|
-
const legacyTmp =
|
|
12418
|
+
const legacyTmp = join22(abCwd, ".runeya-tmp");
|
|
12282
12419
|
await rename13(legacyRoot, legacyTmp);
|
|
12283
|
-
await
|
|
12284
|
-
const legacyOld =
|
|
12420
|
+
await mkdir17(dataDir, { recursive: true });
|
|
12421
|
+
const legacyOld = join22(dataDir, `backup-${timestamp}`);
|
|
12285
12422
|
await rename13(legacyTmp, legacyOld);
|
|
12286
12423
|
console.log(`[legacy-migration] Legacy data backed up to ${legacyOld}`);
|
|
12287
|
-
const keyJson = JSON.parse(await readFile16(
|
|
12424
|
+
const keyJson = JSON.parse(await readFile16(join22(legacyOld, "dbs", "encryption-key.json"), "utf-8"));
|
|
12288
12425
|
const sodium = await getSodium();
|
|
12289
12426
|
const sodiumKey = sodium.from_base64(keyJson.encryptionKey);
|
|
12290
12427
|
const keyBuffer = Buffer.from(sodiumKey);
|
|
12291
12428
|
const runyeaKeyHex = keyBuffer.toString("hex");
|
|
12292
12429
|
await setEncryptionKey(runyeaKeyHex);
|
|
12293
12430
|
console.log("[legacy-migration] Encryption key loaded in memory (temporary)");
|
|
12294
|
-
const dbsDir =
|
|
12431
|
+
const dbsDir = join22(legacyOld, "dbs");
|
|
12295
12432
|
async function readEncrypted(filePath) {
|
|
12296
12433
|
try {
|
|
12297
12434
|
return await decryptLegacyFile(filePath, sodiumKey, sodium);
|
|
@@ -12300,29 +12437,29 @@ async function runLegacyMigration(dataDir) {
|
|
|
12300
12437
|
return null;
|
|
12301
12438
|
}
|
|
12302
12439
|
}
|
|
12303
|
-
const envsDir =
|
|
12304
|
-
const envFiles = (await
|
|
12440
|
+
const envsDir = join22(dbsDir, "envs");
|
|
12441
|
+
const envFiles = (await readdir7(envsDir).catch(() => [])).filter((f) => f.endsWith(".encrypted.json"));
|
|
12305
12442
|
const legacyEnvs = {};
|
|
12306
12443
|
for (const file of envFiles) {
|
|
12307
12444
|
const name = file.replace(".encrypted.json", "");
|
|
12308
|
-
legacyEnvs[name] = await readEncrypted(
|
|
12445
|
+
legacyEnvs[name] = await readEncrypted(join22(envsDir, file));
|
|
12309
12446
|
}
|
|
12310
|
-
const servicesDir =
|
|
12311
|
-
const serviceFiles = (await
|
|
12447
|
+
const servicesDir = join22(dbsDir, "services");
|
|
12448
|
+
const serviceFiles = (await readdir7(servicesDir).catch(() => [])).filter((f) => f.endsWith(".encrypted.json"));
|
|
12312
12449
|
const legacyServices = {};
|
|
12313
12450
|
for (const file of serviceFiles) {
|
|
12314
12451
|
const name = file.replace(".encrypted.json", "");
|
|
12315
12452
|
if (!name) continue;
|
|
12316
|
-
const data = await readEncrypted(
|
|
12453
|
+
const data = await readEncrypted(join22(servicesDir, file));
|
|
12317
12454
|
if (data?.label) legacyServices[name] = data;
|
|
12318
12455
|
}
|
|
12319
|
-
const overridesDir =
|
|
12320
|
-
const overrideFiles = (await
|
|
12456
|
+
const overridesDir = join22(dbsDir, "overrides");
|
|
12457
|
+
const overrideFiles = (await readdir7(overridesDir).catch(() => [])).filter((f) => f.endsWith(".encrypted.json"));
|
|
12321
12458
|
const legacyServiceOverrides = {};
|
|
12322
12459
|
const legacyEnvOverrides = {};
|
|
12323
12460
|
for (const file of overrideFiles) {
|
|
12324
12461
|
const baseName = file.replace(".encrypted.json", "");
|
|
12325
|
-
const data = await readEncrypted(
|
|
12462
|
+
const data = await readEncrypted(join22(overridesDir, file));
|
|
12326
12463
|
if (!data) continue;
|
|
12327
12464
|
if (baseName.endsWith("-envs")) {
|
|
12328
12465
|
legacyServiceOverrides[baseName.slice(0, -5)] = data;
|
|
@@ -12330,11 +12467,11 @@ async function runLegacyMigration(dataDir) {
|
|
|
12330
12467
|
legacyEnvOverrides[baseName.slice(0, -12)] = data;
|
|
12331
12468
|
}
|
|
12332
12469
|
}
|
|
12333
|
-
const parsersDir =
|
|
12334
|
-
const parserFiles = (await
|
|
12470
|
+
const parsersDir = join22(dbsDir, "parsers");
|
|
12471
|
+
const parserFiles = (await readdir7(parsersDir).catch(() => [])).filter((f) => f.endsWith(".encrypted.json"));
|
|
12335
12472
|
const legacyParsers = [];
|
|
12336
12473
|
for (const file of parserFiles) {
|
|
12337
|
-
const data = await readEncrypted(
|
|
12474
|
+
const data = await readEncrypted(join22(parsersDir, file));
|
|
12338
12475
|
if (data?.id) legacyParsers.push(data);
|
|
12339
12476
|
}
|
|
12340
12477
|
const projectMonoId = randomUUID12();
|
|
@@ -12675,7 +12812,7 @@ async function runLegacyMigration(dataDir) {
|
|
|
12675
12812
|
}
|
|
12676
12813
|
let existingSettings = {};
|
|
12677
12814
|
try {
|
|
12678
|
-
existingSettings = JSON.parse(await readFile16(
|
|
12815
|
+
existingSettings = JSON.parse(await readFile16(join22(dataDir, "settings.json"), "utf-8"));
|
|
12679
12816
|
} catch {
|
|
12680
12817
|
}
|
|
12681
12818
|
const migratedParsers = legacyParsers.map((p) => ({
|
|
@@ -12696,11 +12833,11 @@ ${p.transform ?? ""}`,
|
|
|
12696
12833
|
...migratedParsers
|
|
12697
12834
|
]
|
|
12698
12835
|
};
|
|
12699
|
-
await atomicWrite(
|
|
12700
|
-
await atomicWrite(
|
|
12701
|
-
await atomicWrite(
|
|
12702
|
-
await atomicWrite(
|
|
12703
|
-
await atomicWrite(
|
|
12836
|
+
await atomicWrite(join22(dataDir, "projects.json"), runeProjects);
|
|
12837
|
+
await atomicWrite(join22(dataDir, "services.json"), runeServices);
|
|
12838
|
+
await atomicWrite(join22(dataDir, "environments.json"), runeEnvs);
|
|
12839
|
+
await atomicWrite(join22(dataDir, "environment-overrides.json"), flatOverrides);
|
|
12840
|
+
await atomicWrite(join22(dataDir, "settings.json"), newSettings);
|
|
12704
12841
|
const svcEnvCount = runeEnvs.filter((e) => e.scope === "service").length;
|
|
12705
12842
|
console.log(`[legacy-migration] Written: ${runeProjects.length} projects, ${runeServices.length} services, ${runeEnvs.length} environments (${svcEnvCount} service-scoped)`);
|
|
12706
12843
|
console.log(`[legacy-migration] Overrides: ${Object.keys(flatOverrides).length}, custom parsers: ${migratedParsers.length} (all disabled \u2014 rewrite required)`);
|
|
@@ -12711,10 +12848,10 @@ ${p.transform ?? ""}`,
|
|
|
12711
12848
|
}
|
|
12712
12849
|
async function findLegacyKeyInBackup(dataDir) {
|
|
12713
12850
|
try {
|
|
12714
|
-
const entries = await
|
|
12851
|
+
const entries = await readdir7(dataDir);
|
|
12715
12852
|
const backupDirs = entries.filter((e) => e.startsWith("backup-")).sort((a, b) => a < b ? -1 : a > b ? 1 : 0).reverse();
|
|
12716
12853
|
for (const dir of backupDirs) {
|
|
12717
|
-
const keyJsonPath =
|
|
12854
|
+
const keyJsonPath = join22(dataDir, dir, "dbs", "encryption-key.json");
|
|
12718
12855
|
try {
|
|
12719
12856
|
const raw = await readFile16(keyJsonPath, "utf-8");
|
|
12720
12857
|
const parsed = JSON.parse(raw);
|
|
@@ -12738,14 +12875,14 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
12738
12875
|
const abDataDir = resolve6(dataDir);
|
|
12739
12876
|
const abCwd = resolve6(process.cwd());
|
|
12740
12877
|
const candidateDirs = [
|
|
12741
|
-
|
|
12742
|
-
|
|
12878
|
+
join22(abCwd, ".runeya", "dbs", "overrides"),
|
|
12879
|
+
join22(abDataDir, "dbs", "overrides")
|
|
12743
12880
|
];
|
|
12744
12881
|
let overridesDir = null;
|
|
12745
12882
|
let overrideFiles = [];
|
|
12746
12883
|
for (const dir of candidateDirs) {
|
|
12747
12884
|
try {
|
|
12748
|
-
const files = (await
|
|
12885
|
+
const files = (await readdir7(dir)).filter((f) => f.endsWith(".encrypted.json"));
|
|
12749
12886
|
if (files.length > 0) {
|
|
12750
12887
|
overridesDir = dir;
|
|
12751
12888
|
overrideFiles = files;
|
|
@@ -12755,7 +12892,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
12755
12892
|
}
|
|
12756
12893
|
}
|
|
12757
12894
|
if (!overridesDir || overrideFiles.length === 0) return false;
|
|
12758
|
-
const legacyKeyPath =
|
|
12895
|
+
const legacyKeyPath = join22(overridesDir, "..", "encryption-key.json");
|
|
12759
12896
|
try {
|
|
12760
12897
|
await access2(legacyKeyPath);
|
|
12761
12898
|
return false;
|
|
@@ -12773,7 +12910,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
12773
12910
|
const envNameToId = {};
|
|
12774
12911
|
let envsRaw;
|
|
12775
12912
|
try {
|
|
12776
|
-
envsRaw = JSON.parse(await readFile16(
|
|
12913
|
+
envsRaw = JSON.parse(await readFile16(join22(abDataDir, "environments.json"), "utf-8"));
|
|
12777
12914
|
for (const _env of envsRaw) {
|
|
12778
12915
|
const env2 = _env;
|
|
12779
12916
|
if (env2["name"] && env2["id"]) {
|
|
@@ -12792,7 +12929,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
12792
12929
|
let servicesRaw = [];
|
|
12793
12930
|
const serviceNameToId = {};
|
|
12794
12931
|
try {
|
|
12795
|
-
servicesRaw = JSON.parse(await readFile16(
|
|
12932
|
+
servicesRaw = JSON.parse(await readFile16(join22(abDataDir, "services.json"), "utf-8"));
|
|
12796
12933
|
for (const _svc of servicesRaw) {
|
|
12797
12934
|
const svc = _svc;
|
|
12798
12935
|
if (svc["name"] && svc["id"]) serviceNameToId[svc["name"]] = svc["id"];
|
|
@@ -12809,7 +12946,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
12809
12946
|
const envName = baseName.slice(0, -"-environment".length);
|
|
12810
12947
|
let data;
|
|
12811
12948
|
try {
|
|
12812
|
-
data = await decryptLegacyFile(
|
|
12949
|
+
data = await decryptLegacyFile(join22(overridesDir, file), sodiumKey, sodium);
|
|
12813
12950
|
} catch (err) {
|
|
12814
12951
|
console.warn(`[override-migration] Failed to decrypt ${file}: ${err.message}`);
|
|
12815
12952
|
continue;
|
|
@@ -12836,7 +12973,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
12836
12973
|
}
|
|
12837
12974
|
}
|
|
12838
12975
|
if (Object.keys(flatOverrides).length > 0) {
|
|
12839
|
-
await atomicWrite(
|
|
12976
|
+
await atomicWrite(join22(abDataDir, "environment-overrides.json"), flatOverrides);
|
|
12840
12977
|
console.log(`[override-migration] Written ${Object.keys(flatOverrides).length} override(s) to environment-overrides.json`);
|
|
12841
12978
|
}
|
|
12842
12979
|
let envsModified = false;
|
|
@@ -12846,7 +12983,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
12846
12983
|
const serviceName = baseName.slice(0, -"-envs".length);
|
|
12847
12984
|
let data;
|
|
12848
12985
|
try {
|
|
12849
|
-
data = await decryptLegacyFile(
|
|
12986
|
+
data = await decryptLegacyFile(join22(overridesDir, file), sodiumKey, sodium);
|
|
12850
12987
|
} catch (err) {
|
|
12851
12988
|
console.warn(`[override-migration] Failed to decrypt ${file}: ${err.message}`);
|
|
12852
12989
|
continue;
|
|
@@ -12905,7 +13042,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
12905
13042
|
}
|
|
12906
13043
|
}
|
|
12907
13044
|
if (envsModified) {
|
|
12908
|
-
await atomicWrite(
|
|
13045
|
+
await atomicWrite(join22(abDataDir, "environments.json"), envsRaw);
|
|
12909
13046
|
console.log("[override-migration] Merged service overrides into environments.json");
|
|
12910
13047
|
}
|
|
12911
13048
|
const migratedDir = overridesDir.replace(/overrides$/, "overrides-migrated");
|
|
@@ -12920,8 +13057,8 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
12920
13057
|
}
|
|
12921
13058
|
|
|
12922
13059
|
// ../server/src/services/server-state.ts
|
|
12923
|
-
import { join as
|
|
12924
|
-
import { stat as
|
|
13060
|
+
import { join as join23 } from "path";
|
|
13061
|
+
import { stat as stat7 } from "fs/promises";
|
|
12925
13062
|
var ENCRYPTED_KEY_FILENAME2 = ".encryption.key.enc";
|
|
12926
13063
|
var VERIFY_FILENAME2 = ".runeya-verify";
|
|
12927
13064
|
async function getServerState() {
|
|
@@ -12930,17 +13067,17 @@ async function getServerState() {
|
|
|
12930
13067
|
let hasVerify = false;
|
|
12931
13068
|
let hasData = false;
|
|
12932
13069
|
try {
|
|
12933
|
-
await
|
|
13070
|
+
await stat7(join23(dataDir, ENCRYPTED_KEY_FILENAME2));
|
|
12934
13071
|
hasEncFile = true;
|
|
12935
13072
|
} catch {
|
|
12936
13073
|
}
|
|
12937
13074
|
try {
|
|
12938
|
-
await
|
|
13075
|
+
await stat7(join23(dataDir, VERIFY_FILENAME2));
|
|
12939
13076
|
hasVerify = true;
|
|
12940
13077
|
} catch {
|
|
12941
13078
|
}
|
|
12942
13079
|
try {
|
|
12943
|
-
await
|
|
13080
|
+
await stat7(join23(dataDir, "projects.json"));
|
|
12944
13081
|
hasData = true;
|
|
12945
13082
|
} catch {
|
|
12946
13083
|
}
|
|
@@ -13232,7 +13369,7 @@ function getOpenApiDocument() {
|
|
|
13232
13369
|
// ../server/src/create-server.ts
|
|
13233
13370
|
import rateLimit from "express-rate-limit";
|
|
13234
13371
|
import { existsSync as existsSync2, createReadStream } from "fs";
|
|
13235
|
-
import { mkdir as
|
|
13372
|
+
import { mkdir as mkdir18 } from "fs/promises";
|
|
13236
13373
|
import multer from "multer";
|
|
13237
13374
|
|
|
13238
13375
|
// ../server/src/services/image-cleanup.service.ts
|
|
@@ -13338,7 +13475,7 @@ async function createLocalServer() {
|
|
|
13338
13475
|
console.log("[server] Premier lancement \u2014 setup requis");
|
|
13339
13476
|
}
|
|
13340
13477
|
}
|
|
13341
|
-
if (!existsSync2(env.DATA_DIR)) await
|
|
13478
|
+
if (!existsSync2(env.DATA_DIR)) await mkdir18(env.DATA_DIR);
|
|
13342
13479
|
const absoluteDataDir = resolve5(env.DATA_DIR);
|
|
13343
13480
|
console.log(`[server] Data directory: ${absoluteDataDir}`);
|
|
13344
13481
|
await ensureDataGitignore(env.DATA_DIR);
|
|
@@ -14090,4 +14227,4 @@ export {
|
|
|
14090
14227
|
createLocalServer,
|
|
14091
14228
|
pullEnv
|
|
14092
14229
|
};
|
|
14093
|
-
//# sourceMappingURL=src-
|
|
14230
|
+
//# sourceMappingURL=src-W64XJTN5.js.map
|