@runeya/runeya 2.0.92 → 2.0.93

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.
Files changed (198) hide show
  1. package/agent/index.js +14 -10
  2. package/agent/index.js.map +1 -1
  3. package/agent-manager-WEFGEFRT.js +7 -0
  4. package/{chunk-PDRWT47K.js → chunk-6Y24763Y.js} +13 -3
  5. package/{chunk-PDRWT47K.js.map → chunk-6Y24763Y.js.map} +1 -1
  6. package/index.js +2 -2
  7. package/index.js.map +1 -1
  8. package/package.json +1 -1
  9. package/{src-K5L5HTKP.js → src-QDQ5AT4C.js} +9 -7
  10. package/src-QDQ5AT4C.js.map +1 -0
  11. package/web/assets/{AgentScalarChatInterface.vue-BaIR1ZwL.js → AgentScalarChatInterface.vue-BlRhaFfk.js} +1 -1
  12. package/web/assets/{AgentTerminalPage-Chql5o8h.js → AgentTerminalPage-Bgz6cN1-.js} +1 -1
  13. package/web/assets/AiChatPage-B2ZLntQV.js +1 -0
  14. package/web/assets/{AppLayout-DRQiJFAe.js → AppLayout-CwaLgkBP.js} +1 -1
  15. package/web/assets/{AuditPage-DBrGkmq6.js → AuditPage-qw3Fsus7.js} +1 -1
  16. package/web/assets/{CloudAccountPage-Bz5yu3CN.js → CloudAccountPage-BLOaK1nf.js} +1 -1
  17. package/web/assets/CloudAccountPage-DTs4O-ua.js +1 -0
  18. package/web/assets/{CloudMessagingPage-D1uKwcxg.js → CloudMessagingPage-Cz1EQr91.js} +1 -1
  19. package/web/assets/{DashboardPage-BBFsMFk3.js → DashboardPage-B5HHqw9m.js} +1 -1
  20. package/web/assets/{DirectoryPickerDialog-DMUrjQdd.js → DirectoryPickerDialog-DjpBVTYW.js} +1 -1
  21. package/web/assets/{EditorIcon-c_3UtFYp.js → EditorIcon-Bi1br5gY.js} +1 -1
  22. package/web/assets/{EnvironmentForm-D7Cq-8MZ.js → EnvironmentForm-C9NbiSRH.js} +1 -1
  23. package/web/assets/{EnvironmentFormPage-Dgcm1IXC.js → EnvironmentFormPage-DWbL-D3Z.js} +1 -1
  24. package/web/assets/{EnvironmentListPage-kQY6ZGA3.js → EnvironmentListPage-rdeHc34g.js} +1 -1
  25. package/web/assets/{KanbanBoardPage-B5xNcvmj.js → KanbanBoardPage-CbHeyK8M.js} +3 -3
  26. package/web/assets/{KanbanListPage-D-hG5Ag0.js → KanbanListPage-xIqiBmTe.js} +1 -1
  27. package/web/assets/{LaunchProjectPage-BPbq8Mqg.js → LaunchProjectPage-D04ok35N.js} +1 -1
  28. package/web/assets/{LaunchServicesPage-CKt_9IHU.js → LaunchServicesPage-Bkhxe7Ko.js} +1 -1
  29. package/web/assets/{LogViewer-BCvltLuS.js → LogViewer-BHlGDB4l.js} +1 -1
  30. package/web/assets/{OrgKeyPrompt-_pg1asnX.js → OrgKeyPrompt-CnIY4K5s.js} +1 -1
  31. package/web/assets/{ProcessControls-BXu0aujq.js → ProcessControls-BOkCKqGc.js} +1 -1
  32. package/web/assets/{ProcessDetailPage-ClzLOqgt.js → ProcessDetailPage-BQCvKU0O.js} +1 -1
  33. package/web/assets/{ProcessMetrics-D-40_Bx4.js → ProcessMetrics-DgnpYxXh.js} +1 -1
  34. package/web/assets/{ProjectDetailPage-XVg6xk7_.js → ProjectDetailPage-Cjf4eBYS.js} +1 -1
  35. package/web/assets/{ProjectListPage-BW4wrm6E.js → ProjectListPage-DQH1VC3U.js} +1 -1
  36. package/web/assets/{RandomJobTestPage-DZ75Nh-v.js → RandomJobTestPage-BMc4Qb-3.js} +1 -1
  37. package/web/assets/{ScenarioEditorPage-uH-7yybT.js → ScenarioEditorPage-ClH3vxG9.js} +1 -1
  38. package/web/assets/{SendToChatDialog-nfy9y-Ji.js → SendToChatDialog-5TxDHf96.js} +1 -1
  39. package/web/assets/{ServiceControlsBar-hNxsBv7d.js → ServiceControlsBar-D0nrwVz7.js} +1 -1
  40. package/web/assets/{ServiceDetailPage-DxSGMGDF.js → ServiceDetailPage-DLTZ2bjR.js} +1 -1
  41. package/web/assets/{ServiceFormPage-QkfjrWmq.js → ServiceFormPage-BoUHidR5.js} +1 -1
  42. package/web/assets/{SettingsPage-DJLCo3L_.js → SettingsPage-B6jM9W4h.js} +4 -4
  43. package/web/assets/{UnlockPage-BhHpc9pz.js → UnlockPage-boIYvNg3.js} +1 -1
  44. package/web/assets/{VariablesTable-N_1OjM81.js → VariablesTable-Eyqi7OJN.js} +1 -1
  45. package/web/assets/{VaultMigrationPage-DVrzZhP0.js → VaultMigrationPage-CqKla89B.js} +1 -1
  46. package/web/assets/{VersionBadge-C8SWxB0u.js → VersionBadge-CnU3z5Rl.js} +1 -1
  47. package/web/assets/WikiPage-Cbdxhr9G.js +1 -0
  48. package/web/assets/{WikiView-Bh4Rc1_F.js → WikiView-BeWVPGaR.js} +1 -1
  49. package/web/assets/{add-scalar-classes-DreMq9eS.js → add-scalar-classes-CG8bn7uZ.js} +3 -3
  50. package/web/assets/auth-errors-CZibvB1j.js +1 -0
  51. package/web/assets/{autocomplete-CdduMsds.js → autocomplete-CFCpVybl.js} +1 -1
  52. package/web/assets/{basic-shape-diamond.svg-J1CPrYKJ.js → basic-shape-diamond.svg-1nuR3NBd.js} +1 -1
  53. package/web/assets/{basic-shape-hexagon.svg-D9pZpKRd.js → basic-shape-hexagon.svg-Be-pZrVb.js} +1 -1
  54. package/web/assets/{basic-shape-primary-circle-ellipse-round.svg-GoFZOez-.js → basic-shape-primary-circle-ellipse-round.svg-9-zHtg8B.js} +1 -1
  55. package/web/assets/{basic-shape-primary-square-rectangle.svg-5sAWcFH7.js → basic-shape-primary-square-rectangle.svg-CRTdnGnv.js} +1 -1
  56. package/web/assets/{basic-shape-shield.svg-BBhZF-nU.js → basic-shape-shield.svg-D9JPqU4l.js} +1 -1
  57. package/web/assets/{browser-D9PR5ryM.js → browser-B6dstq4l.js} +1 -1
  58. package/web/assets/{browser-CGF8J-d2.js → browser-BdPlaU7e.js} +1 -1
  59. package/web/assets/{card-wcB3LVu3.js → card-D8XCM024.js} +1 -1
  60. package/web/assets/{checkbox-BGl4zewJ.js → checkbox-C_jx73WS.js} +1 -1
  61. package/web/assets/{chip-BeU7R8v5.js → chip-CQdqiw0W.js} +1 -1
  62. package/web/assets/{client-mw7vk2NS.js → client-B_gN8XJ7.js} +1 -1
  63. package/web/assets/{cloud-chat.store-DteZIY7A.js → cloud-chat.store-BB8XNnvp.js} +1 -1
  64. package/web/assets/{cloud-session-PX6MlRl9.js → cloud-session-f2IzlmYY.js} +1 -1
  65. package/web/assets/{column-D_CDh4mf.js → column-BaNiShA4.js} +1 -1
  66. package/web/assets/{computer-device-desktop-monitor.svg-DvELTXaq.js → computer-device-desktop-monitor.svg-CGh6MdTp.js} +1 -1
  67. package/web/assets/{computer-device-desktop.svg-Cy5MNLjy.js → computer-device-desktop.svg-CSnagCeX.js} +1 -1
  68. package/web/assets/{computer-device-laptop.svg-CeTHd2Gz.js → computer-device-laptop.svg-BI_ZVURQ.js} +1 -1
  69. package/web/assets/{computer-device-mobile-phone-android-samsung-back.svg-U357QLLy.js → computer-device-mobile-phone-android-samsung-back.svg-DM3ubsFX.js} +1 -1
  70. package/web/assets/{computer-device-mobile-phone-android-samsung.svg-BxWQ3WQu.js → computer-device-mobile-phone-android-samsung.svg-CzDW3wBE.js} +1 -1
  71. package/web/assets/{computer-device-mobile-phone-iphone-x-back.svg-JTaGwsMH.js → computer-device-mobile-phone-iphone-x-back.svg-B41GuLoA.js} +1 -1
  72. package/web/assets/{computer-device-mobile-phone-iphone-x.svg-CG2NhvNR.js → computer-device-mobile-phone-iphone-x.svg-Cd1cIH5V.js} +1 -1
  73. package/web/assets/{computer-device-mobile-tablet-touch.svg-0RIIeEQE.js → computer-device-mobile-tablet-touch.svg-rLuvpYQb.js} +1 -1
  74. package/web/assets/{computer-device-mobile-tablet.svg-BpEHWNNy.js → computer-device-mobile-tablet.svg-DjBMAEhJ.js} +1 -1
  75. package/web/assets/{computer-device-network-ethernet-cat6.svg-ekymSTiB.js → computer-device-network-ethernet-cat6.svg-BeYjyXJh.js} +1 -1
  76. package/web/assets/{computer-device-network-lan-www.svg-DQ7DjA-N.js → computer-device-network-lan-www.svg-DIR2TMun.js} +1 -1
  77. package/web/assets/{computer-device-network-wifi-connection.svg-Chlu-E0n.js → computer-device-network-wifi-connection.svg-DhI5VT5g.js} +1 -1
  78. package/web/assets/{computer-device-network-wifi-router.svg-sXuKxg3H.js → computer-device-network-wifi-router.svg-BO0V5pTE.js} +1 -1
  79. package/web/assets/{cssMode-CmAJhlK2.js → cssMode-CdzA9M1t.js} +1 -1
  80. package/web/assets/{divider-CIEeFsQF.js → divider-Cijz8TDb.js} +1 -1
  81. package/web/assets/{docx-preview-BzWsyqjd.js → docx-preview-B8bBf__c.js} +1 -1
  82. package/web/assets/{ecology-science-erlenmeyer-flask.svg-DBWUyVvG.js → ecology-science-erlenmeyer-flask.svg-BuQW5h4a.js} +1 -1
  83. package/web/assets/{fieldset-DbVZGmxF.js → fieldset-DnZ-YI4V.js} +1 -1
  84. package/web/assets/{freemarker2-CpZwjOiK.js → freemarker2-Bp9032QT.js} +1 -1
  85. package/web/assets/{handlebars-BF01Ro6D.js → handlebars-CdVx92lU.js} +1 -1
  86. package/web/assets/{html-y42MG6La.js → html-CkCZL9gx.js} +1 -1
  87. package/web/assets/{htmlMode-BiFUKM7B.js → htmlMode-CW62-ie1.js} +1 -1
  88. package/web/assets/{image-flash-lightning.svg-D8MQjxej.js → image-flash-lightning.svg-DeCuJWFT.js} +1 -1
  89. package/web/assets/{image-picture-flower.svg-DhtjWeFt.js → image-picture-flower.svg-2ZzZbPy5.js} +1 -1
  90. package/web/assets/{index-K4MHcRkt.js → index-DXGQcaBP.js} +5 -5
  91. package/web/assets/{interface-alert-exclamation-diamond.svg-BnuBbqzl.js → interface-alert-exclamation-diamond.svg-D9th7CAp.js} +1 -1
  92. package/web/assets/{interface-alert-exclamation-triangle-warning.svg-CLIWOLdf.js → interface-alert-exclamation-triangle-warning.svg-Dq9CWWQ3.js} +1 -1
  93. package/web/assets/{interface-alert-information-circle.svg--CM4LBgr.js → interface-alert-information-circle.svg-FaG159xA.js} +1 -1
  94. package/web/assets/{interface-award-crown.svg-CwUcjE17.js → interface-award-crown.svg-B_-NjgUX.js} +1 -1
  95. package/web/assets/{interface-bookmark.svg-C-WYwhpR.js → interface-bookmark-tag.svg-CKjw2WEc.js} +1 -1
  96. package/web/assets/{interface-bookmark-tag.svg-BYkbHYcm.js → interface-bookmark.svg--yRnhMMQ.js} +1 -1
  97. package/web/assets/{interface-calendar-date-one.svg-BEV_BtWR.js → interface-calendar-date-one.svg-BCrvSyS9.js} +1 -1
  98. package/web/assets/{interface-content-book-open-pages.svg-DklVPzGE.js → interface-content-book-open-pages.svg-BGIlAwyt.js} +1 -1
  99. package/web/assets/{interface-content-book-page.svg-DtEixblx.js → interface-content-book-page.svg-DeLfK2OR.js} +1 -1
  100. package/web/assets/{interface-content-file.svg-CbdR0tUT.js → interface-content-file.svg-DUdYkC8Y.js} +1 -1
  101. package/web/assets/interface-content-folder.svg-C0OEvuKX.js +1 -0
  102. package/web/assets/{interface-content-folder.svg-Bb6W8S8_.js → interface-content-folder.svg-Ccx-IYD-.js} +1 -1
  103. package/web/assets/{interface-copy-clipboard.svg-cy8mE1ku.js → interface-copy-clipboard.svg-DIR-oOPG.js} +1 -1
  104. package/web/assets/{interface-edit-attachment.svg-ujlWFwop.js → interface-edit-attachment.svg-B9CSuzCn.js} +1 -1
  105. package/web/assets/{interface-edit-binocular.svg-DdndLqEe.js → interface-edit-binocular.svg-6WTqf985.js} +1 -1
  106. package/web/assets/{interface-edit-magic-wand.svg-D3PbWjw6.js → interface-edit-magic-wand.svg-BiB-GwoX.js} +1 -1
  107. package/web/assets/{interface-edit-tool-paint-roller.svg-DEJvhvns.js → interface-edit-tool-paint-roller.svg-Dh0uneh4.js} +1 -1
  108. package/web/assets/{interface-edit-tool-pencil.svg-CSwy7Tpt.js → interface-edit-tool-pencil.svg-C9HQOHce.js} +1 -1
  109. package/web/assets/{interface-favorite-award.svg-Ct3aGvri.js → interface-favorite-award.svg-Cj_1Qy9M.js} +1 -1
  110. package/web/assets/{interface-favorite-flag.svg-Dt2tGcDG.js → interface-favorite-flag.svg-BniwQaep.js} +1 -1
  111. package/web/assets/{interface-favorite-heart.svg-BCAdec7C.js → interface-favorite-heart.svg-CYJO0Ggb.js} +1 -1
  112. package/web/assets/{interface-favorite-star.svg-Dcen2Unz.js → interface-favorite-star.svg-CeFb37gO.js} +1 -1
  113. package/web/assets/{interface-favorite-stars-sparkles.svg-BptG3dBN.js → interface-favorite-stars-sparkles.svg-CGeIzi4_.js} +1 -1
  114. package/web/assets/{interface-hierarchy-flowchart.svg-CG8rKwV2.js → interface-hierarchy-flowchart.svg-Bd0q_y82.js} +1 -1
  115. package/web/assets/{interface-home-house.svg-EjYsHgjY.js → interface-home-house.svg-BqSaaLzz.js} +1 -1
  116. package/web/assets/{interface-hyperlink.svg-R0Inwsnr.js → interface-hyperlink.svg-DTtVOw8L.js} +1 -1
  117. package/web/assets/{interface-lighting-brightness.svg-82wRZ7U5.js → interface-lighting-brightness.svg-CVNVwF9w.js} +1 -1
  118. package/web/assets/{interface-lock-closed.svg-CKCtxTSF.js → interface-lock-closed.svg-CKiXr8tU.js} +1 -1
  119. package/web/assets/{interface-lock-open-unlock.svg-25bZt-jb.js → interface-lock-open-unlock.svg-DU7sOeAE.js} +1 -1
  120. package/web/assets/{interface-login-key.svg-C1nVpqWu.js → interface-login-key.svg-tuWEt_tn.js} +1 -1
  121. package/web/assets/{interface-search.svg-Db9i4fOU.js → interface-search.svg-CMDkllvr.js} +1 -1
  122. package/web/assets/{interface-setting-cog.svg-C2juGx3i.js → interface-setting-cog.svg-BRM5rRrt.js} +1 -1
  123. package/web/assets/{interface-share-megaphone-bullhorn.svg-DWKTYrRq.js → interface-share-megaphone-bullhorn.svg-BgC_SP2r.js} +1 -1
  124. package/web/assets/{interface-share-rocket.svg-D9L6uhiQ.js → interface-share-rocket.svg-C-XkIKh-.js} +1 -1
  125. package/web/assets/{interface-share-satellite.svg-Dt-PZyoP.js → interface-share-satellite.svg-BKE0N18S.js} +1 -1
  126. package/web/assets/{interface-share-space-ship.svg-DbJpVjTn.js → interface-share-space-ship.svg-B8QuVt2r.js} +1 -1
  127. package/web/assets/{interface-share.svg-9Bxtnx5d.js → interface-share.svg-bp3wJyGc.js} +1 -1
  128. package/web/assets/{interface-signal-square.svg-CYGdCItu.js → interface-signal-square.svg-D8XH70Ue.js} +1 -1
  129. package/web/assets/{interface-time-clock-circle.svg-0lffJ7tQ.js → interface-time-clock-circle.svg-2DN-SbMe.js} +1 -1
  130. package/web/assets/{interface-time-hour-glass.svg-BtZTqD1b.js → interface-time-hour-glass.svg-l0_r1j5d.js} +1 -1
  131. package/web/assets/{interface-users-multiple.svg-B7F73V4j.js → interface-users-multiple.svg-RRlj9uIH.js} +1 -1
  132. package/web/assets/{interface-weather-moon.svg-Co0IUTf8.js → interface-weather-moon.svg-BmdUGPZe.js} +1 -1
  133. package/web/assets/{javascript-iLWmo9Qr.js → javascript-edU55dwl.js} +1 -1
  134. package/web/assets/{jsonMode-D3SRxnAF.js → jsonMode-CdE3cdJ3.js} +1 -1
  135. package/web/assets/{liquid-D5C_hJy7.js → liquid-DCimUdoJ.js} +1 -1
  136. package/web/assets/{lspLanguageFeatures-DeXbFx7Z.js → lspLanguageFeatures-BKbLLFFb.js} +1 -1
  137. package/web/assets/{mail-chat-bubble-square.svg-Cnn1sRtD.js → mail-chat-bubble-square.svg-VF1duUdO.js} +1 -1
  138. package/web/assets/{mail-send-email-paper-airplane.svg-CqK1oWPg.js → mail-send-email-paper-airplane.svg-CdSpwALk.js} +1 -1
  139. package/web/assets/{mail-send-envelope.svg-DIvASWH1.js → mail-send-envelope.svg-DZVjejiO.js} +1 -1
  140. package/web/assets/{mdx-wnkKJwKX.js → mdx-Hv_NSA7I.js} +1 -1
  141. package/web/assets/{minus-BGc58rrM.js → minus-CQh_GdvM.js} +1 -1
  142. package/web/assets/modal-BO4YZ0Od.js +1 -0
  143. package/web/assets/{modal-CVEyxr-0.js → modal-DUYd78Dq.js} +1 -1
  144. package/web/assets/{money-cashier-receipt.svg-CzJyKfSy.js → money-cashier-receipt.svg-CWHgfD-x.js} +1 -1
  145. package/web/assets/{money-currency-dollar-pay.svg-CwjHgCC1.js → money-currency-dollar-pay.svg-XPcb5aF0.js} +1 -1
  146. package/web/assets/{money-graph-arrow-increase.svg-C2VxjTpX.js → money-graph-arrow-increase.svg-DhPujH9x.js} +1 -1
  147. package/web/assets/{money-graph-bar-chart-increase.svg-CI6bcxy-.js → money-graph-bar-chart-increase.svg-BPOlqEDC.js} +1 -1
  148. package/web/assets/{multiselect-DYHLYL35.js → multiselect-DJ80nRN0.js} +1 -1
  149. package/web/assets/{nature-ecology-leaf.svg-DlkkijsA.js → nature-ecology-leaf.svg-DZNsVAVa.js} +1 -1
  150. package/web/assets/{password-CknBOa6c.js → password-DlR3LzLg.js} +1 -1
  151. package/web/assets/{phone-telephone.svg-DB57c0uQ.js → phone-telephone.svg-B7vr6N8Z.js} +1 -1
  152. package/web/assets/{plus-vTZ3EI82.js → plus-BDDTopKC.js} +1 -1
  153. package/web/assets/process.store-Dq6j8zkt.js +1 -0
  154. package/web/assets/{programming-bug.svg-Bpzz6qqz.js → programming-bug.svg-DzlGVlKX.js} +1 -1
  155. package/web/assets/{programming-cloud.svg-Bu_Znc8m.js → programming-cloud.svg-QHMLI7Md.js} +1 -1
  156. package/web/assets/{programming-computer-database-server.svg-BzyehrHn.js → programming-computer-database-server.svg-CjsFgYWn.js} +1 -1
  157. package/web/assets/{programming-computer-database.svg-jGG7yJ-F.js → programming-computer-database.svg-vah-tira.js} +1 -1
  158. package/web/assets/{programming-module-four-layout.svg-BUt4Ml7K.js → programming-module-four-layout.svg-Cpk_lyys.js} +1 -1
  159. package/web/assets/{programming-module-three.svg-DTbRPYAb.js → programming-module-three.svg-DPfLaBLh.js} +1 -1
  160. package/web/assets/{programming-module.svg-z4xhH8Dl.js → programming-module.svg-X3KTc78b.js} +1 -1
  161. package/web/assets/{programming-script-code.svg-CnJWv1-9.js → programming-script-code.svg-Btq5sYVs.js} +1 -1
  162. package/web/assets/{python-rG_OzRqj.js → python-7W62NPSS.js} +1 -1
  163. package/web/assets/{razor-D3sCDiqd.js → razor-B-cp1S_J.js} +1 -1
  164. package/web/assets/router-BzVLWWlf.js +1 -0
  165. package/web/assets/settings-scope-B2XSViBz.js +1 -0
  166. package/web/assets/{settings.store-Ci_N5bWL.js → settings.store-DvVMtpRN.js} +1 -1
  167. package/web/assets/{shopping-cart.svg-BKfZC1qE.js → shopping-cart.svg-CrAdOGHj.js} +1 -1
  168. package/web/assets/{shopping-gift-present.svg-t023rdyN.js → shopping-gift-present.svg-D6lzCq46.js} +1 -1
  169. package/web/assets/{shopping-shipping-box-parcel-package.svg-BwzwfQ_c.js → shopping-shipping-box-parcel-package.svg-CvE0Deq6.js} +1 -1
  170. package/web/assets/{src-3tEmDkie.js → src-DB1mNeZv.js} +1 -1
  171. package/web/assets/{src-DPqmktmn.js → src-KOvSDAsA.js} +1 -1
  172. package/web/assets/{tabpanel-B40ITuTH.js → tabpanel-DnsLaWEk.js} +1 -1
  173. package/web/assets/{tag-new-circle.svg-BIfD1F_x.js → tag-new-circle.svg-K7X6DVeY.js} +1 -1
  174. package/web/assets/{toggleswitch-Dt_ptl6t.js → toggleswitch-BIl5_ynN.js} +1 -1
  175. package/web/assets/{travel-map-earth-globe.svg-CXUdwwcu.js → travel-map-earth-globe.svg-CGHyssIY.js} +1 -1
  176. package/web/assets/trpc-BT4fWDYZ.js +1 -0
  177. package/web/assets/{tsMode-tZ7zzelW.js → tsMode-Ch-xMRFe.js} +1 -1
  178. package/web/assets/{typescript-FIjOqkFs.js → typescript-DaR3W1ZS.js} +1 -1
  179. package/web/assets/useAiChatDrawer-Bn5BBHr2.js +1 -0
  180. package/web/assets/{useCloudOrg-DnZamx1M.js → useCloudOrg-CCXszfIX.js} +3 -3
  181. package/web/assets/{useProjectCatalog-B4PXCnXu.js → useProjectCatalog-CHgbaNsn.js} +1 -1
  182. package/web/assets/{xml-CdxscNq-.js → xml-DGHPJrA4.js} +1 -1
  183. package/web/assets/{yaml-D6DcoEmu.js → yaml-Bt6S3avV.js} +1 -1
  184. package/web/index.html +1 -1
  185. package/agent-manager-U454MXAX.js +0 -7
  186. package/src-K5L5HTKP.js.map +0 -1
  187. package/web/assets/AiChatPage-DijdhDBJ.js +0 -1
  188. package/web/assets/CloudAccountPage-CtaTO5Dr.js +0 -1
  189. package/web/assets/WikiPage-rOxWNgKc.js +0 -1
  190. package/web/assets/auth-errors-BOBaCbd9.js +0 -1
  191. package/web/assets/interface-content-folder.svg-BiARWOa_.js +0 -1
  192. package/web/assets/modal-DmCFgP0y.js +0 -1
  193. package/web/assets/process.store-CeybR5VK.js +0 -1
  194. package/web/assets/router-Dx2pV4zI.js +0 -1
  195. package/web/assets/settings-scope-DVqLTAzI.js +0 -1
  196. package/web/assets/trpc-BkrN7NiU.js +0 -1
  197. package/web/assets/useAiChatDrawer-DFAtVCez.js +0 -1
  198. /package/{agent-manager-U454MXAX.js.map → agent-manager-WEFGEFRT.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../server/src/create-server.ts","../../server/src/trpc/trpc.ts","../../server/src/services/auth-token.ts","../../server/src/services/api-key-store.ts","../../server/src/trpc/routers/health.ts","../../server/src/config/app-version.ts","../../server/src/trpc/routers/app-update.ts","../../server/src/trpc/routers/project.ts","../../server/src/services/project-store.ts","../../server/src/utils/ensure-data-gitignore.ts","../../server/src/services/project-path-store.ts","../../server/src/services/environment-overrides-store.ts","../../server/src/services/environment-resolver.ts","../../server/src/services/audit-service.ts","../../server/src/services/org-keys.ts","../../server/src/services/master-password.ts","../../server/src/trpc/routers/service.ts","../../server/src/services/log-parser-store.ts","../../server/src/services/settings-manager.ts","../../server/src/services/service-builtins.ts","../../server/src/services/workspace-cwd.ts","../../server/src/services/conversation-store.ts","../../server/src/trpc/routers/agent.ts","../../server/src/trpc/routers/process.ts","../../server/src/trpc/routers/audit.ts","../../server/src/trpc/routers/setup.ts","../../server/src/services/cloud-session-store.ts","../../server/src/services/cloud-api.ts","../../server/src/trpc/routers/environment.ts","../../server/src/trpc/routers/settings.ts","../../server/src/services/settings-scope.ts","../../server/src/services/lan-mode.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/chat.ts","../../../packages/ai-capabilities/src/capabilities.ts","../../../packages/ai-capabilities/src/adapters/anthropic.ts","../../../packages/ai-capabilities/src/adapters/openai.ts","../../../packages/ai-capabilities/src/adapters/prompt.ts","../../../packages/ai-capabilities/src/trpc-caller.ts","../../server/src/services/ai-runners/runeya-api-docs.ts","../../server/src/services/claude-transcript-sync.ts","../../server/src/services/codex-sessions.ts","../../server/src/trpc/shared-schemas.ts","../../server/src/services/llms-txt-generator.ts","../../server/src/services/chat-tools.ts","../../server/src/services/claude-usage.ts","../../server/src/services/codex-usage.ts","../../server/src/services/active-session-registry.ts","../../server/src/services/scenario-store.ts","../../server/src/services/scenario-run-store.ts","../../server/src/services/run-store-utils.ts","../../server/src/services/ai-provider-utils.ts","../../server/src/services/image-storage.service.ts","../../server/src/services/message-images.ts","../../server/src/trpc/routers/cloud-auth.ts","../../server/src/services/kanban-store.ts","../../server/src/services/kanban-commands.ts","../../server/src/services/ai-runners/claude-code-runner.ts","../../server/src/services/ai-runners/scenario-tokens.ts","../../server/src/services/ai-runners/claude-pty-runner.ts","../../server/src/services/ai-runners/claude-pty-tail.ts","../../server/src/services/ai-runners/codex-app-server-client.ts","../../../packages/mcp-server/src/launch.ts","../../server/src/services/ai-runners/codex-runner.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/org-lock.ts","../../server/src/services/key-adoption.ts","../../server/src/trpc/routers/filesystem.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"],"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 { 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 { 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 } from './services/vault-resolver.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\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 await cloudSessionStore.set(getCloudApiUrl(), sessionToken);\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 const token = await cloudSessionStore.getToken();\n if (!token) {\n res.status(401).end();\n return;\n }\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 `${getCloudApiUrl()}${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 const token = await cloudSessionStore.getToken();\n if (!token) {\n res.status(401).end();\n return;\n }\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 `${getCloudApiUrl()}/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 const token = await cloudSessionStore.getToken();\n if (!token) {\n res.status(401).end();\n return;\n }\n try {\n const upstream = await fetch(\n `${getCloudApiUrl()}/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 const token = await cloudSessionStore.getToken();\n if (!token) {\n res.status(401).end();\n return;\n }\n try {\n const upstream = await fetch(\n `${getCloudApiUrl()}/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 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 imageCleanupService.stop();\n 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 return { app, server, wss, shutdown };\n}\n","import { initTRPC, TRPCError } from '@trpc/server';\nimport type { OpenApiMeta } from 'trpc-to-openapi';\nimport type { CreateExpressContextOptions } from '@trpc/server/adapters/express';\nimport { verifyJwt } from '../services/auth-token.js';\nimport { hasEncryptionKey, isCiMode } from '../utils/encryption-key.js';\nimport { apiKeyStore } from '../services/api-key-store.js';\nimport type { ApiKey, ApiServiceAction, ApiEnvAction } from '@runeya/packages-shared';\n\ntype CallerType = 'app' | 'api';\n\nexport function createContext({ req }: CreateExpressContextOptions) {\n return {\n authorization: req.headers.authorization ?? null,\n // L'adresse de la socket, et non `req.ip` : celle-ci ne dépend d'aucun\n // en-tête, donc d'aucune valeur qu'un appelant distant puisse forger.\n remoteAddress: req.socket.remoteAddress ?? null,\n };\n}\n\n// `remoteAddress` est optionnel : le contexte WebSocket, lui, n'en fournit pas,\n// et aucune route servie par socket ne demande la boucle locale.\ntype Context = Omit<Awaited<ReturnType<typeof createContext>>, 'remoteAddress'> & {\n remoteAddress?: string | null;\n};\n\nexport type AuthContext = Context & {\n callerType: CallerType;\n apiKey: ApiKey | null;\n};\n\nconst t = initTRPC.context<Context>().meta<OpenApiMeta>().create({\n errorFormatter({ shape, error }) {\n return {\n ...shape,\n data: {\n ...shape.data,\n message: error.message,\n },\n };\n },\n});\n\nexport const router = t.router;\n/** Appeler une route sans passer par HTTP — les tests s'en servent. */\nexport const createCallerFactory = t.createCallerFactory;\nexport const publicProcedure = t.procedure;\n\nconst API_KEY_REGEX = /^[0-9a-f]{64}$/i;\n\nconst authMiddleware = t.middleware(async ({ ctx, next }) => {\n const { authorization } = ctx;\n\n // API API key: 64 hex chars — checked before the JWT/encryption-key bypass\n if (authorization?.startsWith('Bearer ') && API_KEY_REGEX.test(authorization.slice(7))) {\n if (!hasEncryptionKey()) {\n throw new TRPCError({ code: 'PRECONDITION_FAILED', message: 'Server is locked — master password must be unlocked before using API API keys' });\n }\n const token = authorization.slice(7);\n const apiKey = await apiKeyStore.validateKey(token);\n if (!apiKey) {\n throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Invalid API API key' });\n }\n return next({ ctx: { ...ctx, callerType: 'api' as CallerType, apiKey } });\n }\n\n // CI mode: key loaded from RUNEYA_ENCRYPTION_KEY env var — no JWT in circulation, bypass auth.\n if (isCiMode()) {\n return next({ ctx: { ...ctx, callerType: 'app' as CallerType, apiKey: null } });\n }\n\n if (!authorization?.startsWith('Bearer ')) {\n throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Missing or invalid Authorization header' });\n }\n\n const token = authorization.slice(7);\n\n try {\n await verifyJwt(token);\n } catch {\n throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Invalid or expired token' });\n }\n\n return next({ ctx: { ...ctx, callerType: 'app' as CallerType, apiKey: null } });\n});\n\nexport const protectedProcedure = t.procedure.use(authMiddleware);\n\nconst LOOPBACK = new Set(['127.0.0.1', '::1', '::ffff:127.0.0.1']);\n\n/**\n * Refuse tout appel qui ne vient pas de la machine elle-même.\n *\n * Pour le peu de routes qui doivent répondre AVANT le déverrouillage — il n'y a\n * alors pas de jeton en circulation, et exiger l'en-tête reviendrait à les\n * rendre inatteignables depuis l'écran de déverrouillage, précisément là où\n * elles servent. Le mode LAN ouvre l'écoute à d'autres postes : la boucle\n * locale reste ce qui distingue l'utilisateur assis devant la machine.\n */\nexport function requireLoopback(ctx: Context): void {\n if (!ctx.remoteAddress || !LOOPBACK.has(ctx.remoteAddress)) {\n throw new TRPCError({ code: 'FORBIDDEN', message: 'This route only answers the local machine.' });\n }\n}\n\n/**\n * La machine elle-même, OU un appelant qui a déjà passé le déverrouillage.\n *\n * `requireLoopback` seul convient à ce qui doit répondre AVANT tout jeton. Mais\n * une route qui doit aussi rester joignable une fois l'application ouverte n'a\n * pas à être réservée au poste : en mode LAN, l'onglet qui la pilote est sur une\n * autre machine, et il détient un jeton — c'est précisément la preuve que la\n * boucle locale servait à remplacer.\n *\n * Le jeton d'application seulement : une clé d'API porte des droits sur des\n * services et des environnements, jamais sur l'installation elle-même. Élargir\n * ici reviendrait à donner à une clé de service un pouvoir qu'aucune de ses\n * portées ne nomme.\n */\nexport async function requireLoopbackOrToken(ctx: Context): Promise<void> {\n if (ctx.remoteAddress && LOOPBACK.has(ctx.remoteAddress)) return;\n // Le mode CI n'a pas de jeton en circulation, comme pour `protectedProcedure`.\n if (isCiMode()) return;\n\n const authorization = ctx.authorization;\n if (!authorization?.startsWith('Bearer ')) {\n throw new TRPCError({\n code: 'FORBIDDEN',\n message: 'This route answers the local machine, or a signed-in app.',\n });\n }\n try {\n await verifyJwt(authorization.slice(7));\n } catch {\n throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Invalid or expired token' });\n }\n}\n\n// ---------------------------------------------------------------------------\n// API scope enforcement helpers\n// Call these at the top of route handlers that API callers can reach.\n// App callers (callerType === 'app') always pass through.\n// ---------------------------------------------------------------------------\n\n/** Throw FORBIDDEN if an API caller lacks `action` on `serviceId`. */\nexport function requireServiceAction(\n ctx: AuthContext,\n serviceId: string,\n action: ApiServiceAction,\n): void {\n if (ctx.callerType !== 'api') return;\n const perm = ctx.apiKey!.scopes.services.find(p => p.serviceId === serviceId);\n if (!perm?.actions.includes(action)) {\n throw new TRPCError({\n code: 'FORBIDDEN',\n message: `API key lacks '${action}' permission on service ${serviceId}`,\n });\n }\n}\n\n/**\n * Return the set of service IDs an API caller is allowed to see.\n * Returns null for app callers (= all services allowed).\n */\nexport function getAllowedServiceIds(ctx: AuthContext): Set<string> | null {\n if (ctx.callerType !== 'api') return null;\n return new Set(ctx.apiKey!.scopes.services.map(p => p.serviceId));\n}\n\n/**\n * Throw FORBIDDEN if an API caller lacks `action` on `environmentId`.\n * Returns whether secrets are allowed (always true for app callers).\n *\n * @param serviceId - when provided, the check is restricted to the permission entry for that\n * specific service. This prevents cross-service escalation: a global env ID shared across\n * multiple services cannot grant access via a different service's permission entry.\n */\nexport function requireEnvAction(\n ctx: AuthContext,\n environmentId: string,\n action: ApiEnvAction,\n serviceId?: string,\n): { includeSecrets: boolean } {\n if (ctx.callerType !== 'api') return { includeSecrets: true };\n const permsToCheck = serviceId\n ? ctx.apiKey!.scopes.services.filter(p => p.serviceId === serviceId)\n : ctx.apiKey!.scopes.services;\n for (const svcPerm of permsToCheck) {\n const envPerm = svcPerm.environments.find(e => e.environmentId === environmentId);\n if (envPerm?.actions.includes(action)) {\n return { includeSecrets: envPerm.includeSecrets };\n }\n }\n throw new TRPCError({\n code: 'FORBIDDEN',\n message: `API key lacks '${action}' permission on environment ${environmentId}`,\n });\n}\n","import { randomBytes } from 'node:crypto';\nimport { SignJWT, jwtVerify } from 'jose';\n\nlet jwtSecret: Uint8Array | null = null;\nlet jwtSecretGeneratedAt: number = 0; // Unix timestamp seconds\n\nexport function generateJwtSecret(): void {\n jwtSecret = new Uint8Array(randomBytes(32));\n jwtSecretGeneratedAt = Math.floor(Date.now() / 1000);\n}\n\nexport function getJwtSecretGeneratedAt(): number {\n return jwtSecretGeneratedAt;\n}\n\nfunction getJwtSecret(): Uint8Array {\n if (!jwtSecret) throw new Error('JWT secret not yet generated');\n return jwtSecret;\n}\n\n/** Sign a JWT valid for 8 hours */\nexport async function signJwt(): Promise<string> {\n const secret = getJwtSecret();\n return new SignJWT({ sub: 'app' })\n .setProtectedHeader({ alg: 'HS256' })\n .setIssuedAt()\n .setExpirationTime('8h')\n .sign(secret);\n}\n\nexport interface JwtPayload {\n exp: number;\n iat: number;\n}\n\n/** Verify a JWT — throws if invalid/expired */\nexport async function verifyJwt(token: string): Promise<JwtPayload> {\n const secret = getJwtSecret();\n const { payload } = await jwtVerify(token, secret);\n return { exp: payload.exp as number, iat: payload.iat as number };\n}\n","import { randomBytes, randomUUID, timingSafeEqual } from 'node:crypto';\nimport { readFile, writeFile, rename, mkdir, chmod } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { keyedFilePath, orgVaultRoot, listOrgVaults } from './vault-resolver.js';\nimport { ApiKeysFileSchema, type ApiKey, type ApiKeyScope, type MaskedApiKey } from '@runeya/packages-shared';\nimport { encryptValue, decryptValue, isEncryptedValue } from './crypto-helpers.js';\nimport { rememberFile, hasChangedSinceRead, wasRead } from './disk-freshness.js';\n\n/** Strips the secret from a key before it leaves the store. */\nexport function maskApiKey(apiKey: ApiKey): MaskedApiKey {\n const { key, ...rest } = apiKey;\n return { ...rest, keyPreview: key.slice(-4) };\n}\n\nconst FILE_PUBLIC = 'api-keys.json';\nconst FILE_PRIVATE = 'api-keys.private.json';\n\n/**\n * À qui appartient une clé d'API : une organisation, ou la machine.\n *\n * Une clé nomme des services et des environnements dans ses portées — donc des\n * choses qui appartiennent à un projet, donc à une organisation. La ranger au\n * niveau du poste faisait décrire l'hôte à un fait qui décrit la chose\n * partagée. `null` reste la machine, pour une clé qui ne vise que des projets\n * locaux.\n */\nexport type ApiKeyOwner = string | null;\n\nclass ApiKeyStore {\n private keys: Map<string, ApiKey> = new Map();\n /** Le propriétaire de chaque clé, d'après le coffre où elle a été lue. */\n private owners: Map<string, ApiKeyOwner> = new Map();\n /** Tous les coffres rencontrés — voir `AgentStore.knownOwners`, même raison. */\n private knownOwners: Set<ApiKeyOwner> = new Set([null]);\n /**\n * Les clés que ce poste n'a pas su déchiffrer, gardées sous leur forme de\n * disque.\n *\n * Le store tient le secret en clair en mémoire et le re-chiffre à chaque\n * écriture : une clé absente de la mémoire est donc une clé effacée du\n * fichier à la première sauvegarde. Or « je ne sais pas l'ouvrir » n'est pas\n * « elle n'existe plus » — le chiffré d'origine repart tel quel, et redevient\n * lisible le jour où la bonne clé est adoptée.\n */\n private unreadable: Map<ApiKeyOwner, Map<string, unknown>> = new Map();\n private loaded = false;\n\n /**\n * Encrypted at rest, so the file sits beside the key that opens it — read\n * under a different key it would decrypt to blanks, then be saved back blank.\n */\n /**\n * Le fichier d'un propriétaire. Côté machine il reste collé à la clé qui\n * l'ouvre (`keyedFilePath`) ; côté organisation, c'est son coffre.\n */\n private filePath(isPublic: boolean, owner: ApiKeyOwner): Promise<string> {\n const name = isPublic ? FILE_PUBLIC : FILE_PRIVATE;\n if (owner === null) return keyedFilePath(name);\n return Promise.resolve(join(orgVaultRoot(owner), name));\n }\n\n private async persistFile(isPublic: boolean, owner: ApiKeyOwner): Promise<void> {\n const path = await this.filePath(isPublic, owner);\n // Réparé en dehors du serveur depuis qu'on l'a lu : on n'y touche pas.\n // Réécrire notre copie déferait la réparation, l'omettre effacerait les\n // clés qu'elle protège.\n if (this.unreadable.get(owner)?.size && wasRead(path) && await hasChangedSinceRead(path)) {\n console.warn(\n `[api-key-store] ${path} a changé depuis sa lecture — écriture ignorée`\n + ' pour ne pas écraser une réparation faite en dehors du serveur.',\n );\n return;\n }\n await mkdir(dirname(path), { recursive: true });\n // Le secret est chiffré au repos, comme partout ailleurs dans le serveur :\n // le mode 0600 protège des autres utilisateurs, pas d'une copie du dataDir.\n const keys: unknown[] = Array.from(this.keys.values())\n .filter(k => k.isPublic === isPublic && (this.owners.get(k.id) ?? null) === owner)\n // Chiffrée par la clé du coffre où la clé d'API est rangée.\n .map(k => ({ ...k, key: encryptValue(k.key, owner ?? undefined) }));\n // Puis ce qui ne s'était pas ouvert, inchangé. Rien n'est re-chiffré ici :\n // le chiffré est déjà le bon, sous une clé que ce poste n'a simplement pas.\n for (const raw of this.unreadable.get(owner)?.values() ?? []) {\n if ((raw as { isPublic?: boolean }).isPublic === isPublic) keys.push(raw);\n }\n const tmp = path + '.tmp';\n await writeFile(tmp, JSON.stringify({ keys }, null, 2), 'utf-8');\n await rename(tmp, path);\n await chmod(path, 0o600);\n await rememberFile(path);\n }\n\n /**\n * Réécrire ce fichier pour chaque propriétaire connu.\n *\n * Y compris ceux qui n'ont plus de clé : sinon une clé supprimée — ou dont le\n * propriétaire a changé — survivrait dans son ancien coffre.\n */\n private async persist(isPublic: boolean): Promise<void> {\n for (const owner of this.knownOwners) await this.persistFile(isPublic, owner);\n }\n\n private async loadFile(path: string, owner: ApiKeyOwner): Promise<void> {\n try {\n const raw = await readFile(path, 'utf-8');\n await rememberFile(path);\n const parsed = ApiKeysFileSchema.safeParse(JSON.parse(raw));\n if (parsed.success) {\n // Le coffre est connu dès que son fichier se lit, avant tout\n // déchiffrement : c'est ce qui garantit qu'une réécriture ultérieure\n // repassera bien par lui.\n this.knownOwners.add(owner);\n for (const k of parsed.data.keys) {\n // Une clé par une : le `catch` du fichier entier abandonnait toutes\n // les suivantes dès la première illisible, et la sauvegarde d'après\n // les effaçait.\n try {\n // Les fichiers écrits avant le chiffrement contiennent le secret en\n // clair : on les accepte et le prochain persist les rechiffrera.\n const key = isEncryptedValue(k.key) ? decryptValue(k.key, owner ?? undefined) : k.key;\n this.keys.set(k.id, { ...k, key });\n this.owners.set(k.id, owner);\n } catch {\n console.error(`[api-key-store] Clé d'API ${k.id} illisible sous la clé de ce coffre — conservée telle quelle sur le disque`);\n const bucket = this.unreadable.get(owner) ?? new Map<string, unknown>();\n bucket.set(k.id, k);\n this.unreadable.set(owner, bucket);\n }\n }\n }\n } catch {\n // File doesn't exist yet — start empty\n }\n }\n\n /** La machine, puis chaque organisation dont un coffre existe sur ce disque. */\n async load(): Promise<void> {\n if (this.loaded) return;\n this.loaded = true;\n // Même raison qu'ailleurs : la liste des illisibles décrit cette lecture-ci.\n this.unreadable.clear();\n const owners: ApiKeyOwner[] = [null, ...await listOrgVaults()];\n for (const owner of owners) {\n await this.loadFile(await this.filePath(true, owner), owner);\n await this.loadFile(await this.filePath(false, owner), owner);\n }\n }\n\n /**\n * Oublier ce qui a été lu, pour tout relire sous la clé courante.\n *\n * Appelé après l'adoption d'une clé d'organisation : le disque vient d'être\n * re-chiffré sous les pieds du store, si bien que sa mémoire décrit un état\n * qui n'existe plus. La laisser en place n'affichait pas seulement des\n * comptes périmés — la sauvegarde suivante réécrivait l'ancien chiffré\n * par-dessus le nouveau, et défaisait l'adoption.\n */\n resetCache(): void {\n this.keys.clear();\n this.owners.clear();\n this.knownOwners = new Set([null]);\n this.unreadable.clear();\n this.loaded = false;\n }\n\n /**\n * Combien de clés d'API ce coffre garde sans savoir les lire.\n *\n * Remonté à l'interface : une donnée conservée mais illisible n'est visible\n * nulle part autrement, et un silence se lit comme « il n'y a rien ».\n */\n async unreadableCount(owner: ApiKeyOwner): Promise<number> {\n await this.load();\n return this.unreadable.get(owner)?.size ?? 0;\n }\n\n /**\n * Keys as exposed to callers — secrets stripped. Use `reveal` to obtain one\n * deliberately; never hand the whole set of secrets out at once.\n */\n async list(): Promise<MaskedApiKey[]> {\n await this.load();\n return Array.from(this.keys.values()).map(maskApiKey);\n }\n\n /** The plaintext secret of a single key, or null when unknown. */\n async reveal(id: string): Promise<string | null> {\n await this.load();\n return this.keys.get(id)?.key ?? null;\n }\n\n async create(\n name: string,\n scopes: ApiKeyScope,\n isPublic: boolean,\n owner: ApiKeyOwner = null,\n ): Promise<ApiKey> {\n await this.load();\n const apiKey: ApiKey = {\n id: `apikey-${randomUUID()}`,\n name,\n key: randomBytes(32).toString('hex'),\n scopes,\n createdAt: new Date().toISOString(),\n isPublic,\n };\n this.keys.set(apiKey.id, apiKey);\n this.owners.set(apiKey.id, owner);\n this.knownOwners.add(owner);\n await this.persist(isPublic);\n return apiKey;\n }\n\n async update(id: string, name: string, scopes: ApiKeyScope, isPublic: boolean): Promise<ApiKey | null> {\n await this.load();\n const existing = this.keys.get(id);\n if (!existing) return null;\n const updated: ApiKey = { ...existing, name, scopes, isPublic };\n this.keys.set(id, updated);\n // If isPublic changed, persist both files (remove from old, add to new)\n if (existing.isPublic !== isPublic) {\n await this.persist(existing.isPublic);\n await this.persist(isPublic);\n } else {\n await this.persist(isPublic);\n }\n return updated;\n }\n\n async remove(id: string): Promise<boolean> {\n await this.load();\n const existing = this.keys.get(id);\n if (!existing) return false;\n this.keys.delete(id);\n this.owners.delete(id);\n await this.persist(existing.isPublic);\n return true;\n }\n\n async renewKey(id: string): Promise<ApiKey | null> {\n await this.load();\n const existing = this.keys.get(id);\n if (!existing) return null;\n const renewed: ApiKey = { ...existing, key: randomBytes(32).toString('hex') };\n this.keys.set(id, renewed);\n await this.persist(renewed.isPublic);\n return renewed;\n }\n\n async validateKey(candidateHex: string): Promise<ApiKey | null> {\n await this.load();\n if (!/^[0-9a-f]{64}$/i.test(candidateHex)) return null;\n const candidate = Buffer.from(candidateHex, 'hex');\n for (const apiKey of this.keys.values()) {\n const stored = Buffer.from(apiKey.key, 'hex');\n if (candidate.length === stored.length && timingSafeEqual(candidate, stored)) {\n return apiKey;\n }\n }\n return null;\n }\n}\n\nexport const apiKeyStore = new ApiKeyStore();\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\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 .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 () => {\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 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 return { current: appVersion, latest: null, status: 'unknown' as const };\n }\n const parsed = z.object({ version: z.string().max(64) }).safeParse(await res.json());\n if (!parsed.success) {\n return { current: appVersion, latest: null, status: 'unknown' as const };\n }\n const latest = parsed.data.version;\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 } catch {\n return { current: appVersion, latest: null, status: 'unknown' as const };\n }\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","declare const __RUNEYA_VERSION__: string;\n\n/**\n * Version de cette app, telle qu'annoncée au cloud et affichée dans l'UI.\n *\n * Injectée au build par tsup (`define`) ; vaut `dev` depuis le monorepo, ce que\n * le cloud accepte toujours.\n */\nexport const appVersion = process.env['RUNEYA_VERSION']\n ?? (typeof __RUNEYA_VERSION__ !== 'undefined' ? __RUNEYA_VERSION__ : 'dev');\n\n/** En-tête où l'app annonce sa version à chaque appel au cloud. */\nexport const APP_VERSION_HEADER = 'X-Runeya-Version';\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 env: process.env,\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 { TRPCError } from '@trpc/server';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { projectStore, LocalProjectExistsError } from '../../services/project-store.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';\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 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('local', 'update', 'project', input.id, { localPath: input.path });\n return { path: input.path };\n }),\n});\n","import { randomUUID } from 'node:crypto';\nimport { EventEmitter } from 'node:events';\nimport { readFile, writeFile, rename, mkdir, chmod, rm } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Project, CreateProject, UpdateProject } from '@runeya/packages-shared';\nimport { ProjectSchema } from '@runeya/packages-shared';\nimport { environmentStore } from './environment-store.js';\nimport { serviceStore } from './service-store.js';\nimport { ensureDataGitignore } from '../utils/ensure-data-gitignore.js';\nimport { localVaultRoot, listCloudVaults, vaultFor, ensureLocalVault } from './vault-resolver.js';\nimport { registerProjectLoader, setProjectVault, setProjectServices, forgetProject } from './vault-registry.js';\nimport { projectKey, AmbiguousProjectError, type ProjectRef } from './project-key.js';\nimport { projectPathStore } from './project-path-store.js';\n\n/**\n * One project per vault, so the file holds a single object — in the local vault\n * as in a cloud one.\n */\nconst FILENAME = 'project.json';\n/**\n * The local file before a vault meant one project. Read once, migrated to\n * `project.json`, and kept on disk under a `.bak` name rather than deleted:\n * nothing is thrown away on the user's behalf.\n */\nconst LEGACY_FILENAME = 'projects.json';\n\n/**\n * A project as persisted: `activeEnvironmentId` is runtime-only and never hits\n * disk. This is also exactly what the cloud mirrors — the sync shares what git\n * shares, so \"is it persisted?\" is the only question that decides it.\n */\nfunction toDiskForm(project: Project): Omit<Project, 'activeEnvironmentId'> {\n const { activeEnvironmentId: _runtimeOnly, ...rest } = project;\n return rest;\n}\n\n/**\n * What the launch directory holds: its own project, plus any cloud projects an\n * older version left in the legacy list.\n *\n * Reads `project.json`, and falls back to the `projects.json` of older versions\n * so an existing directory keeps working. A legacy file describing several\n * local projects has no valid placement under one-project-per-vault, so it is\n * refused loudly instead of being silently narrowed to its first entry — losing\n * a project quietly is worse than refusing to start.\n *\n * Cloud projects found in that list are handed back too, so they can be moved\n * into their own vault rather than quietly dropped from the machine.\n */\nasync function readLocalProject(): Promise<{ local: Project | null; strayCloud: Project[] }> {\n const root = localVaultRoot();\n let current: Project | null = null;\n try {\n const raw = await readFile(join(root, FILENAME), 'utf-8');\n const parsed = ProjectSchema.safeParse(JSON.parse(raw));\n if (parsed.success) current = parsed.data;\n } catch {\n // Fall through to the legacy list.\n }\n\n let legacy: Project[];\n try {\n legacy = JSON.parse(await readFile(join(root, LEGACY_FILENAME), 'utf-8')) as Project[];\n } catch {\n return { local: current, strayCloud: [] };\n }\n\n const strayCloud = legacy.filter((p) => p.orgId);\n if (current) return { local: current, strayCloud };\n\n // Cloud projects in the legacy list live in their own vault now; only the\n // local ones compete for this directory.\n const locals = legacy.filter((p) => !p.orgId);\n if (locals.length > 1) {\n const names = locals.map((p) => `\"${p.name}\" (${p.id})`).join(', ');\n throw new Error(\n `${join(root, LEGACY_FILENAME)} holds ${locals.length} local projects: ${names}. ` +\n 'A directory now holds a single local project — move the others to their own directory, ' +\n 'or into an organization, then start again.',\n );\n }\n return { local: locals[0] ?? null, strayCloud };\n}\n\n/**\n * The cloud projects materialized on this machine, read from their vaults.\n *\n * The id and org come from the path, not from the file: the directory layout is\n * what the rest of the system trusts, so a file whose contents disagree with\n * where it sits must not win.\n */\nasync function readCloudProjects(): Promise<{ project: Project; root: string }[]> {\n const found: { project: Project; root: string }[] = [];\n for (const { orgId, projectId, root } of await listCloudVaults()) {\n try {\n const raw = await readFile(join(root, FILENAME), 'utf-8');\n const parsed = ProjectSchema.safeParse({ ...JSON.parse(raw), id: projectId, orgId });\n if (parsed.success) found.push({ project: parsed.data, root });\n } catch {\n // Not a readable project vault — ignore it.\n }\n }\n return found;\n}\n\n/**\n * A directory already holds its local project.\n *\n * Carries a stable `code` alongside the sentence: the sentence is for logs and\n * for API consumers, the code is what the UI translates — a message built here\n * could only ever be in one language.\n */\nexport class LocalProjectExistsError extends Error {\n readonly code = 'LOCAL_PROJECT_EXISTS';\n\n constructor(readonly projectName: string) {\n super(\n `This directory already holds the local project \"${projectName}\". ` +\n 'A directory holds one local project: use another directory, or create the project in an organization.',\n );\n this.name = 'LocalProjectExistsError';\n }\n}\n\nclass ProjectStore {\n /**\n * Keyed by the (organization, project) couple, never by the project id alone:\n * the same id can name a different project in each organization, and keying\n * by id let the second one read from disk overwrite the first — then `save()`\n * wrote that survivor back into both vaults.\n */\n private projects: Map<string, Project> = new Map();\n private loaded = false;\n /** Emits `'saved'` after every persisted mutation, for the cloud sync bridge. */\n readonly events = new EventEmitter();\n\n private getFilePath(root: string = localVaultRoot()): string {\n return join(root, FILENAME);\n }\n\n private async writeAtomic(filePath: string, data: string): Promise<void> {\n const tmpPath = filePath + '.tmp';\n await writeFile(tmpPath, data, 'utf-8');\n await rename(tmpPath, filePath);\n await chmod(filePath, 0o600);\n }\n\n /** Adopt a project read from disk, remembering which vault it came from. */\n private async absorb(p: Project, root: string): Promise<void> {\n const projectEnvs = await environmentStore.getByProjectId(p.id).catch(() => []);\n const defaultEnv = projectEnvs.find(e => e.default);\n this.projects.set(projectKey(p), {\n ...p,\n environmentIds: p.environmentIds ?? [],\n groupOrder: p.groupOrder ?? [],\n // Prefer the env marked default, fall back to first env\n activeEnvironmentId: defaultEnv?.id ?? p.environmentIds?.[0],\n });\n setProjectVault(p, root);\n setProjectServices(p, p.serviceIds ?? []);\n }\n\n /**\n * Read every vault: the launch directory, then each organization's projects.\n *\n * Cloud vaults are discovered by walking `~/.runeya/orgs/*&#47;projects/*` rather\n * than from an index. An index is one more thing that can disagree with the\n * disk — and a project present on disk but missing from it is exactly the\n * \"already here, still shown as downloadable\" bug.\n */\n private async load(): Promise<void> {\n if (this.loaded) return;\n // Marked before the awaits below: absorbing a project reads environments,\n // which can come back through the registry and re-enter this method.\n this.loaded = true;\n const { local, strayCloud } = await readLocalProject();\n if (local) await this.absorb(local, localVaultRoot());\n // Cloud projects an older version kept in the launch directory. Absorbed\n // first so that a vault holding the same project — necessarily fresher —\n // overrides them just below.\n let migrated = false;\n for (const project of strayCloud) {\n try {\n await this.absorb(project, vaultFor(project).root);\n migrated = true;\n } catch {\n // An id that cannot form a vault path: leave it in the legacy file.\n }\n }\n for (const { project, root } of await readCloudProjects()) {\n // A cloud project left over in the local vault by an older version is\n // superseded by the copy in its own vault.\n await this.absorb(project, root);\n }\n\n // Carry the launch directory over in one go rather than on the next edit:\n // a cloud project half-moved — its record in the vault, its services still\n // in `.runeya` — is the confusing state this migration exists to avoid.\n if (migrated) {\n await this.save();\n await serviceStore.relocateAll();\n await environmentStore.relocateAll();\n }\n }\n\n /**\n * Persist every vault this store knows about.\n *\n * Writing all of them rather than only the one that changed keeps a project\n * that moved between vaults — a local project adopted by an org, a cloud\n * project pulled for the first time — from lingering in the vault it left.\n */\n private async save(): Promise<void> {\n const locals: Project[] = [];\n const cloud: { project: Project; root: string }[] = [];\n for (const project of this.projects.values()) {\n if (!project.orgId) locals.push(project);\n else cloud.push({ project, root: vaultFor(project).root });\n }\n\n if (locals.length > 1) {\n // Nothing here can place a second local project, and writing the first\n // while dropping the rest would lose data without a word. The refusal\n // mirrors the one at load time.\n const names = locals.map((p) => `\"${p.name}\" (${p.id})`).join(', ');\n throw new Error(\n `Refusing to save ${locals.length} local projects in one directory: ${names}. ` +\n 'A directory holds a single local project.',\n );\n }\n\n const [local] = locals;\n if (local) {\n // Writing a local project is what brings `.runeya` into existence.\n await ensureLocalVault();\n await ensureDataGitignore(localVaultRoot());\n await this.writeAtomic(this.getFilePath(), JSON.stringify(toDiskForm(local), null, 2));\n } else {\n // No local project left: the file would otherwise keep describing one.\n await rm(this.getFilePath(), { force: true }).catch(() => {});\n }\n // The legacy list has been carried over — park it rather than delete it.\n await rename(join(localVaultRoot(), LEGACY_FILENAME), join(localVaultRoot(), LEGACY_FILENAME + '.bak'))\n .catch(() => {});\n\n for (const { project, root } of cloud) {\n await mkdir(root, { recursive: true });\n await this.writeAtomic(this.getFilePath(root), JSON.stringify(toDiskForm(project), null, 2));\n setProjectVault(project, root);\n }\n\n this.events.emit('saved');\n }\n\n /**\n * The project a caller means, from a couple or from a bare id.\n *\n * A ref carrying its `orgId` — even an explicit `null` for a local project —\n * names exactly one project and is looked up directly. A bare id is what a\n * contained entity (an environment, a conversation) still carries, and it is\n * resolved only while it answers for a single project: electing one of two\n * would write into the wrong organization's vault.\n */\n private resolveKey(target: ProjectRef | string): string | null {\n if (typeof target !== 'string' && target.orgId !== undefined) return projectKey(target);\n const id = typeof target === 'string' ? target : target.id;\n const matches = Array.from(this.projects.values()).filter((p) => p.id === id);\n if (matches.length > 1) {\n throw new AmbiguousProjectError(id, matches.map((p) => p.orgId ?? null));\n }\n return matches[0] ? projectKey(matches[0]) : null;\n }\n\n private find(target: ProjectRef | string): { key: string; project: Project } | null {\n const key = this.resolveKey(target);\n const project = key ? this.projects.get(key) : undefined;\n return key && project ? { key, project } : null;\n }\n\n async list(): Promise<Project[]> {\n await this.load();\n return Array.from(this.projects.values());\n }\n\n async get(target: ProjectRef | string): Promise<Project | null> {\n await this.load();\n return this.find(target)?.project ?? null;\n }\n\n async create(input: CreateProject): Promise<Project> {\n await this.load();\n if (!input.orgId) {\n // A local vault *is* its project: the directory holds the code the\n // project describes. A second one here would have nowhere of its own to\n // live, and \"local\" would go back to meaning \"in this folder\" rather than\n // \"on this machine\" — the ambiguity vaults exist to remove.\n const existing = Array.from(this.projects.values()).find((p) => !p.orgId);\n if (existing) {\n throw new LocalProjectExistsError(existing.name);\n }\n }\n const project: Project = {\n id: randomUUID(),\n orgId: input.orgId ?? null,\n name: input.name,\n description: input.description ?? '',\n serviceIds: input.serviceIds ?? [],\n environmentIds: input.environmentIds ?? [],\n activeEnvironmentId: input.activeEnvironmentId,\n groupOrder: input.groupOrder ?? [],\n };\n this.projects.set(projectKey(project), project);\n setProjectVault(project, vaultFor(project).root);\n setProjectServices(project, project.serviceIds);\n await this.save();\n return project;\n }\n\n /**\n * `input.orgId` names which project is being updated, it does not move it:\n * a project is born local or in an organization and stays there, so treating\n * it as a new value would silently relocate a vault instead of editing it.\n */\n async update(input: UpdateProject): Promise<Project | null> {\n await this.load();\n const found = this.find(input);\n if (!found) return null;\n const { key, project: existing } = found;\n const updated: Project = {\n ...existing,\n ...(input.name !== undefined && { name: input.name }),\n ...(input.description !== undefined && { description: input.description }),\n ...(input.serviceIds !== undefined && { serviceIds: input.serviceIds }),\n ...(input.environmentIds !== undefined && { environmentIds: input.environmentIds }),\n ...(input.activeEnvironmentId !== undefined && { activeEnvironmentId: input.activeEnvironmentId }),\n ...(input.groupOrder !== undefined && { groupOrder: input.groupOrder }),\n };\n this.projects.set(key, updated);\n setProjectVault(updated, vaultFor(updated).root);\n setProjectServices(updated, updated.serviceIds);\n await this.save();\n return updated;\n }\n\n /**\n * Faire passer le projet local de ce dossier dans une organisation.\n *\n * Le seul déplacement de coffre qu'on s'autorise, et il ne va que dans ce\n * sens : le projet quitte `<cwd>/.runeya` pour\n * `~/.runeya/orgs/<org>/projects/<id>/`, en gardant son identifiant. Il n'y a\n * donc jamais deux copies à réconcilier — c'est ce qui rendait « publier »\n * dangereux tant que le projet restait aussi local.\n *\n * Refusé si l'organisation porte déjà ce projet : la copie d'ici écraserait\n * celle du cloud, et ces deux histoires ne sont pas à nous de les fusionner.\n *\n * Ce qui suit le projet est écrit par les stores eux-mêmes : `save()` réécrit\n * chaque coffre — le fichier local disparaît, celui de l'org apparaît — puis\n * les contenus sont relogés depuis le registre, qui pointe désormais ailleurs.\n */\n async moveToOrg(projectId: string, orgId: string): Promise<Project> {\n await this.load();\n const local = this.projects.get(projectKey({ id: projectId, orgId: null }));\n if (!local) throw new Error('PROJECT_NOT_LOCAL');\n if (this.projects.get(projectKey({ id: projectId, orgId }))) {\n throw new Error('PROJECT_ALREADY_IN_ORG');\n }\n\n const moved: Project = { ...local, orgId };\n this.projects.delete(projectKey(local));\n forgetProject(local);\n this.projects.set(projectKey(moved), moved);\n setProjectVault(moved, vaultFor(moved).root);\n setProjectServices(moved, moved.serviceIds ?? []);\n await this.save();\n\n // Les services nomment leur organisation ; les environnements et les\n // conversations, non — eux suivent le coffre de leur projet.\n await serviceStore.reassignOrg(moved.serviceIds ?? [], orgId);\n await environmentStore.relocateAll();\n return moved;\n }\n\n async delete(target: ProjectRef | string): Promise<boolean> {\n await this.load();\n const found = this.find(target);\n if (!found) return false;\n const { key, project } = found;\n this.projects.delete(key);\n await this.save();\n await this.discardVault(project);\n // Le répertoire cesse d'être réservé. `projectAt` s'en sert pour interdire\n // que deux projets partagent un dossier : une entrée laissée derrière un\n // projet supprimé continuait de le retenir, et le refus qui en découlait\n // nommait un projet qui n'existe plus.\n await projectPathStore.clear(project);\n return true;\n }\n\n /**\n * Remove what a deleted cloud project left behind.\n *\n * Its vault is a directory of its own, so dropping the project means dropping\n * the directory — otherwise `readCloudVaults` would resurrect it on the next\n * load. Local projects share their vault with the directory's own files and\n * are only removed from the list.\n */\n private async discardVault(project: Project): Promise<void> {\n forgetProject(project);\n if (!project.orgId) return;\n await rm(vaultFor(project).root, { recursive: true, force: true }).catch(() => {});\n }\n\n /**\n * Stop holding a project on this machine, leaving the doc alone.\n *\n * Memory only: the caller removes the vault itself. Its contents are dropped\n * too, because a service or environment surviving in memory would be written\n * back on the next save — and, its project being unknown by then, into the\n * local vault.\n */\n async forgetLocally(target: ProjectRef | string): Promise<void> {\n await this.load();\n const found = this.find(target);\n if (!found) return;\n const { key, project } = found;\n this.projects.delete(key);\n forgetProject(project);\n await serviceStore.forgetLocally(project.serviceIds ?? []);\n await environmentStore.forgetByProject(project.id);\n // Ce poste ne tient plus ce projet — son coffre vient d'être effacé — donc\n // il ne réserve plus de répertoire non plus. Le seul appelant est le\n // retrait volontaire d'un projet suivi, jamais un état transitoire.\n await projectPathStore.clear(project);\n }\n\n /** All projects linked to a given organization (for the sync bridge). */\n async listByOrg(orgId: string): Promise<Project[]> {\n await this.load();\n return Array.from(this.projects.values()).filter((p) => p.orgId === orgId);\n }\n\n /** Projects of an organization in their on-disk form (what the cloud mirrors). */\n async listDiskFormByOrg(orgId: string): Promise<Omit<Project, 'activeEnvironmentId'>[]> {\n return (await this.listByOrg(orgId)).map(toDiskForm);\n }\n\n /**\n * Apply a project received from the cloud, in its on-disk form.\n *\n * Validated rather than trusted: a peer on another version — or a tampered\n * doc — must not be able to write arbitrary shapes into `projects.json`.\n * `activeEnvironmentId` is runtime-only and stays whatever it is locally.\n * Diff-guarded: an identical project neither saves nor emits (loop-safe).\n * Returns whether a new local project was created, so the caller can\n * bootstrap project-local state (e.g. a default environment).\n */\n async applyRemoteUpsert(\n id: string,\n fields: unknown,\n ): Promise<{ project: Project; created: boolean } | null> {\n await this.load();\n const parsed = ProjectSchema.safeParse({ ...(fields as object), id });\n if (!parsed.success) {\n console.error('[project-store] Rejected remote project %s:', id, parsed.error.message);\n return null;\n }\n const incoming = toDiskForm(parsed.data);\n // The couple, taken from the validated project itself: the bridge stamps\n // the org of the connection that carried it, so this key names the vault\n // the doc actually belongs to.\n const key = projectKey(parsed.data);\n const existing = this.projects.get(key);\n if (existing) {\n if (JSON.stringify(toDiskForm(existing)) === JSON.stringify(incoming)) {\n return { project: existing, created: false };\n }\n const updated: Project = { ...incoming, activeEnvironmentId: existing.activeEnvironmentId };\n this.projects.set(key, updated);\n setProjectVault(updated, vaultFor(updated).root);\n setProjectServices(updated, updated.serviceIds);\n await this.save();\n return { project: updated, created: false };\n }\n const project: Project = { ...incoming, activeEnvironmentId: undefined };\n this.projects.set(key, project);\n setProjectVault(project, vaultFor(project).root);\n setProjectServices(project, project.serviceIds);\n await this.save();\n return { project, created: true };\n }\n\n /** Delete a project that was removed on another peer. */\n async applyRemoteDelete(target: ProjectRef | string): Promise<boolean> {\n await this.load();\n const found = this.find(target);\n if (!found) return false;\n const { key, project } = found;\n this.projects.delete(key);\n await this.save();\n await this.discardVault(project);\n return true;\n }\n\n async addService(target: ProjectRef | string, serviceId: string): Promise<Project | null> {\n await this.load();\n const found = this.find(target);\n if (!found) return null;\n const { key, project } = found;\n if (project.serviceIds.includes(serviceId)) return project;\n const updated = { ...project, serviceIds: [...project.serviceIds, serviceId] };\n this.projects.set(key, updated);\n setProjectServices(updated, updated.serviceIds);\n await this.save();\n return updated;\n }\n\n async removeService(target: ProjectRef | string, serviceId: string): Promise<Project | null> {\n await this.load();\n const found = this.find(target);\n if (!found) return null;\n const { key, project } = found;\n const updated = { ...project, serviceIds: project.serviceIds.filter(id => id !== serviceId) };\n this.projects.set(key, updated);\n setProjectServices(updated, updated.serviceIds);\n await this.save();\n return updated;\n }\n\n async addEnvironment(target: ProjectRef | string, environmentId: string): Promise<Project | null> {\n await this.load();\n const found = this.find(target);\n if (!found) return null;\n const { key, project } = found;\n if (project.environmentIds?.includes(environmentId)) return project;\n const updated = {\n ...project,\n environmentIds: [...(project.environmentIds ?? []), environmentId],\n };\n this.projects.set(key, updated);\n await this.save();\n return updated;\n }\n\n async removeEnvironment(target: ProjectRef | string, environmentId: string): Promise<Project | null> {\n await this.load();\n const found = this.find(target);\n if (!found) return null;\n const { key, project } = found;\n const updated = {\n ...project,\n environmentIds: (project.environmentIds ?? []).filter(id => id !== environmentId),\n // Clear activeEnvironmentId if it was the removed environment\n ...(project.activeEnvironmentId === environmentId && { activeEnvironmentId: undefined }),\n };\n this.projects.set(key, updated);\n await this.save();\n return updated;\n }\n\n async setActiveEnvironment(target: ProjectRef | string, environmentId: string): Promise<Project | null> {\n await this.load();\n const found = this.find(target);\n if (!found) return null;\n const { key, project } = found;\n\n // Update activeEnvironmentId in memory only (not persisted to JSON)\n // Do NOT update updatedAt since this is a runtime preference, not a project modification\n const updated: Project = {\n ...project,\n activeEnvironmentId: environmentId,\n };\n\n this.projects.set(key, updated);\n // No save() call - activeEnvironmentId is runtime-only\n return updated;\n }\n}\n\nexport const projectStore = new ProjectStore();\n\n// Content stores resolve an entity's vault through the registry, which only\n// knows what the projects say — so it must be able to make them load first.\nregisterProjectLoader(() => projectStore.list().then(() => undefined));\n","import { writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nconst GITIGNORE_CONTENT = `\n#################\n# Do not edit this file #\n#################\n\n\n# Encryption key (contains secrets — never commit)\n.encryption.key\n.encryption.key.enc\n\n\n# Key verification canary — MUST be committed so new team members can validate their encryption key\n!.runeya-verify\n\n# This machine's cloud session token (encrypted, and specific to this install)\ncloud-session.json\n\n# Backup in local only\nbackup-*\n\n# Per-user environment overrides (never commit — each dev has their own)\nenvironment-overrides.json\n\n# Private user data (conversations, personal state — never commit)\n*.private\n*.private.json*\nconversations/\nconversations.private.json\n\n\n\n# Runtime logs\n*.log\n*.log.*\n`;\n\n/**\n * Writes data/.gitignore on every startup to keep it in sync with the codebase.\n */\nexport async function ensureDataGitignore(dataDir: string): Promise<void> {\n const gitignorePath = join(dataDir, '.gitignore');\n await writeFile(gitignorePath, GITIGNORE_CONTENT, 'utf-8');\n}\n","import { readFile, writeFile, rename, mkdir, chmod, stat } from 'node:fs/promises';\nimport { isAbsolute, join, resolve } from 'node:path';\nimport { machineFilePath, machineRoot } from './vault-resolver.js';\nimport { projectKey, type ProjectRef } from './project-key.js';\n\nconst FILENAME = 'project-paths.json';\n\n/**\n * Where each cloud project lives on THIS machine.\n *\n * A cloud project is materialized from its document, which holds no path — and\n * must not: a directory of mine means nothing on a teammate's machine, and the\n * sync pushes `projects`, `services` and `environments` wholesale, so a path\n * added to any of them would travel. Hence a file of its own, machine-local and\n * outside every synced collection.\n *\n * Without it, a service whose `cwd` is relative falls back to `'.'` — the\n * directory Runeya was launched from. Every cloud project opened from the same\n * place would then run in the same directory, which is precisely what this is\n * here to prevent.\n */\n\n/**\n * `${orgId ?? 'local'}:${projectId}` → absolute directory on this machine.\n *\n * Keyed by the couple, because a project id alone can name a different project\n * in each organization — two of them would then share one directory, which is\n * exactly what this file exists to prevent. Entries written by older versions\n * are keyed by the bare id; they are still read, and rewritten under the couple\n * the next time the project is placed.\n */\ntype PathMap = Record<string, string>;\n\nclass ProjectPathStore {\n private paths: PathMap | null = null;\n\n private async load(): Promise<PathMap> {\n if (this.paths) return this.paths;\n try {\n const raw = await readFile(machineFilePath(FILENAME), 'utf-8');\n const parsed = JSON.parse(raw) as unknown;\n this.paths = isPathMap(parsed) ? parsed : {};\n } catch {\n // Absent or unreadable: no project has been placed yet.\n this.paths = {};\n }\n return this.paths;\n }\n\n private async persist(): Promise<void> {\n await mkdir(machineRoot(), { recursive: true });\n const filePath = machineFilePath(FILENAME);\n const tmpPath = `${filePath}.tmp`;\n await writeFile(tmpPath, JSON.stringify(this.paths ?? {}, null, 2), 'utf-8');\n await rename(tmpPath, filePath);\n await chmod(filePath, 0o600);\n }\n\n /** The directory chosen for this project, or null while it has none. */\n async get(ref: ProjectRef): Promise<string | null> {\n const paths = await this.load();\n return paths[projectKey(ref)] ?? paths[ref.id] ?? null;\n }\n\n async all(): Promise<PathMap> {\n return { ...(await this.load()) };\n }\n\n /**\n * The project already placed in this directory, if any other one is.\n *\n * Answers with the key as stored — the couple, or the bare id for an entry an\n * older version wrote — which is enough to say \"taken\" and to name it.\n */\n async projectAt(path: string, exclude?: ProjectRef): Promise<string | null> {\n const target = resolve(path);\n const excluded = exclude ? [projectKey(exclude), exclude.id] : [];\n for (const [key, dir] of Object.entries(await this.load())) {\n if (!excluded.includes(key) && resolve(dir) === target) return key;\n }\n return null;\n }\n\n async set(ref: ProjectRef, path: string): Promise<void> {\n if (!isAbsolute(path)) throw new Error('Le chemin du projet doit être absolu');\n const paths = await this.load();\n // The legacy entry goes with it: leaving it behind would keep answering for\n // a project that has since been placed somewhere else.\n delete paths[ref.id];\n paths[projectKey(ref)] = resolve(path);\n await this.persist();\n }\n\n /**\n * Faire suivre le répertoire quand un projet change d'organisation.\n *\n * La clé est le couple `(organisation, projet)` : publier un projet local le\n * fait passer de `local:<id>` à `<org>:<id>`, et l'entrée d'avant cesse alors\n * de répondre — `get` ne retombe que sur l'identifiant nu, forme héritée, pas\n * sur `local:<id>`. Le projet se retrouvait donc sans emplacement connu juste\n * après avoir été publié, alors que ses sources n'avaient pas bougé d'un\n * octet.\n */\n async relocate(from: ProjectRef, to: ProjectRef): Promise<void> {\n const paths = await this.load();\n const previous = paths[projectKey(from)] ?? paths[from.id];\n if (!previous) return;\n delete paths[projectKey(from)];\n delete paths[from.id];\n paths[projectKey(to)] = previous;\n await this.persist();\n }\n\n async clear(ref: ProjectRef): Promise<void> {\n const paths = await this.load();\n const keys = [projectKey(ref), ref.id].filter((k) => k in paths);\n if (keys.length === 0) return;\n for (const key of keys) delete paths[key];\n await this.persist();\n }\n\n /** Test seam: forget what was read from disk. */\n reset(): void {\n this.paths = null;\n }\n}\n\nfunction isPathMap(value: unknown): value is PathMap {\n return (\n !!value\n && typeof value === 'object'\n && !Array.isArray(value)\n && Object.values(value as Record<string, unknown>).every((v) => typeof v === 'string')\n );\n}\n\n/**\n * Whether a directory already holds a Runeya project.\n *\n * Two projects sharing a directory is the very situation that makes services\n * run against the wrong code, so it is refused rather than warned about.\n */\nexport async function holdsRuneyaProject(path: string): Promise<boolean> {\n for (const candidate of ['project.json', 'projects.json']) {\n try {\n await stat(join(path, '.runeya', candidate));\n return true;\n } catch {\n // Keep looking.\n }\n }\n return false;\n}\n\nexport const projectPathStore = new ProjectPathStore();\n","import { readFile, writeFile, rename, mkdir, chmod } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { getEncryptionKey } from '../utils/encryption-key.js';\nimport { allVaultRoots, keyedFilePath, legacyMachineFilePath , vaultIdOfRoot } from './vault-resolver.js';\nimport { environmentStore } from './environment-store.js';\nimport { ensureProjectsLoaded } from './vault-registry.js';\nimport {\n encryptVariableSlots,\n decryptVariableSlots,\n extractEncryptedVariableSlots,\n} from './crypto-helpers.js';\nimport type { VariableOverride, VariableSlot } from '@runeya/packages-shared';\n\nconst FILENAME = 'environment-overrides.json';\n\n// On disk: flat Record<variableId, VariableOverride>\n// An override holds only a value slot — the env var name always comes from the\n// variable definition, resolved by variable ID.\ntype OverridesData = Record<string, VariableOverride>;\n\nclass EnvironmentOverridesStore {\n private data: OverridesData = {};\n private loaded = false;\n private diskEncryptedSlots: Record<string, string> = {};\n /**\n * Les surcharges dont le secret ne s'est pas ouvert.\n *\n * Vides en mémoire, elles doivent repartir chiffrées : sans cela, la\n * sauvegarde suivante remplacerait par du blanc une valeur dont il ne\n * manquait que la clé.\n */\n private unreadableSecrets: Set<string> = new Set();\n private saveQueue: Promise<void> = Promise.resolve();\n /** Which vault each override was read from, until its project is known. */\n private roots: Map<string, string> = new Map();\n\n /**\n * An override belongs to the project whose variable it answers.\n *\n * Nothing in an override says so — they are keyed by variable id alone — so\n * the owning project is resolved through the environment that defines the\n * variable. Overrides are never synced: they stay in the project's vault on\n * this machine, and no other machine sees them.\n *\n * An override whose variable no longer exists (a deleted environment, a row\n * left behind) has no project to belong to. It stays wherever it was read,\n * falling back to the key's own directory — never dropped, since the variable\n * may simply not be loaded yet.\n */\n private async rootFor(variableId: string): Promise<string> {\n // Le coffre de l'environnement qui définit la variable, plutôt que l'id de\n // son projet : cet id peut nommer un projet dans chaque organisation, le\n // coffre en désigne un seul.\n const root = await environmentStore.rootOfVariable(variableId);\n if (root) return root;\n return this.roots.get(variableId) ?? dirname(await keyedFilePath(FILENAME));\n }\n\n /** Where earlier versions kept them: read once, rewritten to their vaults. */\n private getLegacyFilePath(): string {\n return legacyMachineFilePath(FILENAME);\n }\n\n /**\n * Read every vault, then the places older versions used.\n *\n * Variable ids are unique, so merging the files cannot collide; a vault read\n * later simply wins over a legacy copy of the same override.\n */\n private async load(): Promise<void> {\n if (this.loaded) return;\n if (!getEncryptionKey()) return;\n this.loaded = true;\n // Les projets d'abord : tant qu'ils sont inconnus, tout se résoudrait vers\n // le coffre de lancement et y serait réécrit à la première sauvegarde —\n // hors de l'organisation propriétaire.\n await ensureProjectsLoaded();\n\n const roots = await allVaultRoots();\n const sources = [\n this.getLegacyFilePath(),\n await keyedFilePath(FILENAME),\n ...roots.map((root) => join(root, FILENAME)),\n ];\n\n for (const path of sources) {\n let parsed: OverridesData;\n try {\n parsed = JSON.parse(await readFile(path, 'utf-8')) as OverridesData;\n } catch {\n continue;\n }\n\n // Cache encrypted slots then decrypt\n Object.assign(\n this.diskEncryptedSlots,\n extractEncryptedVariableSlots(parsed as Record<string, { value: VariableSlot }>),\n );\n const decrypted = decryptVariableSlots(\n parsed as Record<string, { value: VariableSlot }>,\n 'environment-overrides',\n (variableId) => this.unreadableSecrets.add(variableId),\n vaultIdOfRoot(dirname(path)),\n ) as Record<string, { value: VariableSlot }>;\n\n for (const [id, override] of Object.entries(decrypted)) {\n // Drop any legacy `key` field written by older versions: it has no\n // authority and goes stale when the variable is renamed.\n this.data[id] = { value: override.value };\n this.roots.set(id, dirname(path));\n }\n }\n }\n\n private save(): Promise<void> {\n this.saveQueue = this.saveQueue.then(() => this.doSave()).catch(() => this.doSave());\n return this.saveQueue;\n }\n\n /**\n * Write each vault that holds — or held — an override.\n *\n * A vault emptied by this save is still written, as an empty object: an\n * override that moved to its project's vault must not survive in the one it\n * came from.\n */\n private async doSave(): Promise<void> {\n const byRoot = new Map<string, OverridesData>();\n for (const root of this.roots.values()) byRoot.set(root, {});\n\n for (const [variableId, override] of Object.entries(this.data)) {\n const root = await this.rootFor(variableId);\n this.roots.set(variableId, root);\n const bucket = byRoot.get(root) ?? {};\n bucket[variableId] = override;\n byRoot.set(root, bucket);\n }\n\n for (const [root, overrides] of byRoot) {\n const encrypted = this.keepUnreadableSecrets(encryptVariableSlots(\n overrides as Record<string, { value: VariableSlot }>,\n this.diskEncryptedSlots,\n vaultIdOfRoot(root),\n ) as OverridesData);\n Object.assign(\n this.diskEncryptedSlots,\n extractEncryptedVariableSlots(encrypted as Record<string, { value: VariableSlot }>),\n );\n\n await mkdir(root, { recursive: true });\n const path = join(root, FILENAME);\n const tmpPath = path + '.tmp';\n await writeFile(tmpPath, JSON.stringify(encrypted, null, 2), 'utf-8');\n await rename(tmpPath, path);\n await chmod(path, 0o600);\n }\n }\n\n /**\n * Rendre au disque le chiffré d'une surcharge illisible, plutôt qu'un blanc.\n *\n * Pendant du garde-fou du store des environnements : tant que la valeur en\n * mémoire est vide, c'est que personne n'a retouché la variable et que son\n * chiffré fait toujours foi.\n */\n private keepUnreadableSecrets(overrides: OverridesData): OverridesData {\n if (this.unreadableSecrets.size === 0) return overrides;\n const result = { ...overrides };\n for (const variableId of this.unreadableSecrets) {\n const ciphertext = this.diskEncryptedSlots[variableId];\n const override = result[variableId];\n if (!ciphertext || !override || override.value.value) continue;\n result[variableId] = { ...override, value: { ...override.value, value: ciphertext } };\n }\n return result;\n }\n\n async getOverride(variableId: string): Promise<VariableOverride | null> {\n await this.load();\n return this.data[variableId] ?? null;\n }\n\n async setOverride(variableId: string, override: VariableOverride): Promise<void> {\n await this.load();\n this.data[variableId] = { value: override.value };\n await this.save();\n }\n\n async removeOverride(variableId: string): Promise<void> {\n await this.load();\n if (!this.data[variableId]) return;\n delete this.data[variableId];\n this.unreadableSecrets.delete(variableId);\n await this.save();\n }\n\n async getAll(): Promise<Record<string, VariableOverride>> {\n await this.load();\n return { ...this.data };\n }\n\n async removeOverridesForVariables(variableIds: string[]): Promise<void> {\n await this.load();\n let changed = false;\n for (const id of variableIds) {\n if (this.data[id]) {\n delete this.data[id];\n this.unreadableSecrets.delete(id);\n changed = true;\n }\n }\n if (changed) await this.save();\n }\n}\n\nexport const environmentOverridesStore = new EnvironmentOverridesStore();\n","import type { Variable, VariableOverride, ResolvedEnvironment } from '@runeya/packages-shared';\nimport { environmentStore } from './environment-store.js';\nimport { environmentOverridesStore } from './environment-overrides-store.js';\n\ninterface VariableSource {\n environmentId: string;\n environmentName: string;\n overridden: boolean;\n resolvedFrom?: { environmentId: string; environmentName: string };\n /** Environment carrying the machine-local override that won for this key */\n overriddenBy?: { environmentId: string; environmentName: string };\n}\n\n/** Winning override for a variable key, plus the environment it comes from */\ninterface WinningOverride {\n variable: Variable;\n source?: { environmentId: string; environmentName: string };\n}\n\ninterface DagResult {\n variables: Record<string, Variable>;\n sources: Record<string, VariableSource>;\n /** Concrete parent values keyed by variable key (pre-dedup), used for interpolation context */\n parentEnv: Record<string, string>;\n /** Keys in parentEnv that are secret */\n parentSecretKeys: Set<string>;\n /** Maps variable key → source environment info for parent variables (before child override) */\n parentKeySources: Record<string, { environmentId: string; environmentName: string }>;\n}\n\n/**\n * Interpolate {{environment.KEY}} references in a value string.\n * envContext is the flat dict of resolved environment values.\n * Returns the interpolated string.\n * Missing keys are left as-is ({{environment.MISSING}} -> unchanged).\n */\nfunction interpolateValue(raw: string, envContext: Record<string, string>): string {\n return raw.replace(/\\{\\{environment\\.([^}]+)\\}\\}/g, (match, key) => {\n return envContext[key] !== undefined ? envContext[key] : match;\n });\n}\n\n/**\n * Resolve a Variable to its final string value.\n * Uses variable.value slot, computes interpolate(pre + value + post).\n *\n * The three parts are interpolated, not just `value`: a prefix like\n * `postgres://{{environment.DB_USER}}@` is as legitimate a reference as the\n * value itself, and the parts are concatenated into one string anyway. They\n * are interpolated separately so that a reference cannot be formed by the\n * seam between two parts (a `pre` ending in `{{environment.` completed by a\n * `value` starting with `KEY}}`), which would let a prefix reach a variable\n * the author never named.\n */\nfunction resolveVariable(\n variable: Variable,\n envContext: Record<string, string>,\n): { value: string; isSecret: boolean } {\n const slot = variable.value;\n const finalValue = interpolateValue(slot.pre, envContext)\n + interpolateValue(slot.value, envContext)\n + interpolateValue(slot.post, envContext);\n return { value: finalValue, isSecret: slot.isSecret };\n}\n\n/** Every part of a slot that may carry `{{environment.KEY}}` references. */\nfunction slotReferenceText(variable: Variable): string {\n const slot = variable.value;\n // Séparateur : deux parties voisines ne doivent pas former une référence\n // qu'aucune ne contient — même raison que l'interpolation partie par partie.\n return `${slot.pre}\\n${slot.value}\\n${slot.post}`;\n}\n\nclass EnvironmentResolver {\n async resolveForService(ctx: { serviceId: string; activeEnvironmentId: string }): Promise<{ env: Record<string, string>; envSecrets: string[] }> {\n if (!ctx.activeEnvironmentId) {\n return { env: {}, envSecrets: [] };\n }\n\n // Find the service-scoped environment for this service + active global env\n const serviceEnv = await environmentStore.findServiceEnvironment(ctx.serviceId, ctx.activeEnvironmentId);\n\n if (!serviceEnv) {\n // No service env: resolve just the global env\n return this.resolveEnvironment(ctx.activeEnvironmentId);\n }\n\n // Resolve the service env (which inherits from global via parentIds)\n return this.resolveEnvironment(serviceEnv.id);\n }\n\n async resolveEnvironment(environmentId: string): Promise<{ env: Record<string, string>; envSecrets: string[] }> {\n const visited = new Set<string>();\n const result = await this.resolveDag(environmentId, visited);\n\n // Apply overrides, resolved as their own chain (see resolveOverridesByKey)\n const overridesByKey = await this.resolveOverridesByKey(environmentId);\n for (const [varId, variable] of Object.entries(result.variables)) {\n const override = overridesByKey[variable.key];\n if (override) {\n result.variables[varId] = { ...variable, value: override.variable.value };\n }\n }\n\n // First pass: build raw env dict (no interpolation yet)\n const rawEnv: Record<string, string> = {};\n for (const [_varId, variable] of Object.entries(result.variables)) {\n const slot = variable.value;\n rawEnv[variable.key] = slot.pre + slot.value + slot.post;\n }\n\n // Build interpolation context:\n // Start from parent concrete values, then overlay with current concrete values.\n // This ensures {{environment.KEY}} resolves against parent values when the child\n // redefines KEY as an interpolation reference.\n const { ctx: interpolationCtx, secretKeys: ctxSecretKeys } = await this.buildInterpolationContext(environmentId, rawEnv, result.parentEnv, result.parentSecretKeys, result.parentKeySources);\n const secretKeys = this.collectSecretKeys(result.variables, ctxSecretKeys);\n\n // Second pass: interpolate and build final env dict\n const env: Record<string, string> = {};\n const envSecrets: string[] = [];\n for (const [_varId, variable] of Object.entries(result.variables)) {\n const { value, isSecret } = resolveVariable(variable, interpolationCtx);\n env[variable.key] = value;\n if (isSecret || secretKeys.has(variable.key)) {\n envSecrets.push(variable.key);\n }\n }\n\n return { env, envSecrets };\n }\n\n /**\n * Resolve an environment (with inheritance) and return only the variables\n * flagged `injectIntoAi`, as a flat KEY→value dict ready to be injected into\n * the process environment of an AI agent spawn.\n */\n async resolveAiInjectedEnv(environmentId: string): Promise<Record<string, string>> {\n if (!environmentId) return {};\n\n const visited = new Set<string>();\n const result = await this.resolveDag(environmentId, visited);\n\n // Apply overrides (same as resolveEnvironment)\n const overridesByKey = await this.resolveOverridesByKey(environmentId);\n for (const [varId, variable] of Object.entries(result.variables)) {\n const override = overridesByKey[variable.key];\n if (override) {\n result.variables[varId] = { ...variable, value: override.variable.value };\n }\n }\n\n // Build raw env for interpolation context\n const rawEnv: Record<string, string> = {};\n for (const variable of Object.values(result.variables)) {\n const slot = variable.value;\n rawEnv[variable.key] = slot.pre + slot.value + slot.post;\n }\n const { ctx: interpolationCtx } = await this.buildInterpolationContext(\n environmentId,\n rawEnv,\n result.parentEnv,\n result.parentSecretKeys,\n result.parentKeySources,\n );\n\n // Keep only flagged variables, interpolating their final value.\n const injected: Record<string, string> = {};\n for (const variable of Object.values(result.variables)) {\n if (!variable.value.injectIntoAi) continue;\n const { value } = resolveVariable(variable, interpolationCtx);\n injected[variable.key] = value;\n }\n return injected;\n }\n\n async resolveEnvironmentWithSources(environmentId: string): Promise<ResolvedEnvironment> {\n const visited = new Set<string>();\n const result = await this.resolveDag(environmentId, visited);\n\n // Apply overrides, resolved as their own chain (see resolveOverridesByKey)\n const overridesByKey = await this.resolveOverridesByKey(environmentId);\n for (const [varId, variable] of Object.entries(result.variables)) {\n const override = overridesByKey[variable.key];\n if (override) {\n result.variables[varId] = { ...variable, value: override.variable.value };\n result.sources[varId] = {\n ...result.sources[varId],\n overridden: true,\n ...(override.source ? { overriddenBy: override.source } : {}),\n };\n }\n }\n\n // First pass: build raw env dict (no interpolation yet)\n const rawEnv: Record<string, string> = {};\n for (const [_varId, variable] of Object.entries(result.variables)) {\n const slot = variable.value;\n rawEnv[variable.key] = slot.pre + slot.value + slot.post;\n }\n\n // Build interpolation context\n const { ctx: interpolationCtx, secretKeys: ctxSecretKeys, keySources } = await this.buildInterpolationContext(environmentId, rawEnv, result.parentEnv, result.parentSecretKeys, result.parentKeySources);\n const secretKeys = this.collectSecretKeys(result.variables, ctxSecretKeys);\n\n // Second pass: interpolate and build final env dict\n const env: Record<string, string> = {};\n const envSecrets: string[] = [];\n for (const [_varId, variable] of Object.entries(result.variables)) {\n const { value, isSecret } = resolveVariable(variable, interpolationCtx);\n env[variable.key] = value;\n if (isSecret || secretKeys.has(variable.key)) {\n envSecrets.push(variable.key);\n }\n }\n\n // Post-process: for pure interpolation references, annotate `resolvedFrom`\n // so the frontend knows where the resolved value actually comes from,\n // while keeping the source pointing to where the variable is defined.\n const refPattern = /^\\{\\{environment\\.([^}]+)\\}\\}$/;\n for (const [varId, variable] of Object.entries(result.variables)) {\n const match = variable.value.value.match(refPattern);\n if (match) {\n const refSource = keySources[match[1]];\n if (refSource && result.sources[varId]?.environmentId !== refSource.environmentId) {\n result.sources[varId] = {\n ...result.sources[varId],\n resolvedFrom: refSource,\n };\n }\n }\n }\n\n return {\n variables: result.variables,\n env,\n envSecrets,\n sources: result.sources,\n };\n }\n\n /** Check if a raw value string interpolates any key that is secret in the context */\n /**\n * Toutes les clés dont la valeur est, directement ou par interpolation, un\n * secret.\n *\n * Le contexte d'interpolation ne connaît que les secrets *hérités* : les\n * secrets définis dans le même environnement n'y figurent pas, si bien qu'un\n * `AUTH='Bearer {{environment.TOKEN}}'` voisin de son propre `TOKEN` secret\n * ressortait non marqué — et donc non masqué par toute la chaîne en aval.\n *\n * On part des secrets hérités plus ceux déclarés ici, puis on propage\n * jusqu'au point fixe : une valeur qui référence une clé secrète devient\n * secrète à son tour, y compris en chaîne (A secret → B cite A → C cite B).\n */\n private collectSecretKeys(\n variables: Record<string, Variable>,\n parentSecretKeys: Set<string>,\n ): Set<string> {\n const secretKeys = new Set(parentSecretKeys);\n for (const variable of Object.values(variables)) {\n if (variable.value.isSecret) secretKeys.add(variable.key);\n }\n let changed = true;\n while (changed) {\n changed = false;\n for (const variable of Object.values(variables)) {\n if (secretKeys.has(variable.key)) continue;\n if (this.interpolatesSecretKey(slotReferenceText(variable), secretKeys)) {\n secretKeys.add(variable.key);\n changed = true;\n }\n }\n }\n return secretKeys;\n }\n\n private interpolatesSecretKey(rawValue: string, ctxSecretKeys: Set<string>): boolean {\n const refs = [...rawValue.matchAll(/\\{\\{environment\\.([^}]+)\\}\\}/g)].map(m => m[1]);\n return refs.some(ref => ctxSecretKeys.has(ref));\n }\n\n /**\n * Build the interpolation context for an environment.\n *\n * For inheriting envs (has parents): start from parent concrete values,\n * then overlay with current concrete values. This ensures that\n * {{environment.KEY}} resolves against the parent's value when the child\n * redefines KEY as an interpolation reference.\n *\n * For isolated service envs (scope=service, activateOn set, no parents):\n * the global env is resolved and used as fallback.\n */\n private async buildInterpolationContext(\n environmentId: string,\n rawEnv: Record<string, string>,\n parentEnv: Record<string, string>,\n parentSecretKeys: Set<string>,\n parentKeySources: Record<string, { environmentId: string; environmentName: string }>,\n ): Promise<{ ctx: Record<string, string>; secretKeys: Set<string>; keySources: Record<string, { environmentId: string; environmentName: string }> }> {\n const environment = await environmentStore.get(environmentId);\n\n // Isolated service env: resolve global env for interpolation context\n if (\n environment\n && environment.scope === 'service'\n && environment.activateOn\n && (!environment.parentIds || environment.parentIds.length === 0)\n ) {\n const globalResolved = await this.resolveEnvironmentWithSources(environment.activateOn);\n const secretKeys = new Set(globalResolved.envSecrets);\n // Build keySources from global env variables\n const keySources: Record<string, { environmentId: string; environmentName: string }> = {};\n for (const [varId, variable] of Object.entries(globalResolved.variables)) {\n const source = globalResolved.sources[varId];\n if (source) {\n keySources[variable.key] = { environmentId: source.environmentId, environmentName: source.environmentName };\n }\n }\n // Start with global values, then override with local values that are\n // concrete (not themselves interpolation references)\n const ctx = { ...globalResolved.env };\n for (const [key, value] of Object.entries(rawEnv)) {\n if (!/\\{\\{environment\\.[^}]+\\}\\}/.test(value)) {\n ctx[key] = value;\n }\n }\n return { ctx, secretKeys, keySources };\n }\n\n // Inheriting env: start from parent concrete values, overlay with concrete rawEnv values\n const ctx = { ...parentEnv };\n for (const [key, value] of Object.entries(rawEnv)) {\n if (!/\\{\\{environment\\.[^}]+\\}\\}/.test(value)) {\n ctx[key] = value;\n }\n }\n return { ctx, secretKeys: parentSecretKeys, keySources: parentKeySources };\n }\n\n /**\n * For service-scoped envs, compute effective parentIds by also including\n * the service-scoped envs of ancestor global environments.\n *\n * Example: \"Server (test)\" has parentIds=[test-global]. test-global has\n * parentIds=[Local-global]. This method adds \"Server (Local)\" to the\n * effective parents so service-specific variables from ancestor envs\n * are inherited correctly.\n */\n private async getEffectiveParentIds(environment: { scope?: string; reference?: string; activateOn?: string; parentIds: string[] }): Promise<string[]> {\n if (environment.scope !== 'service' || !environment.reference || !environment.activateOn) {\n return environment.parentIds;\n }\n\n // Walk each global parent and find the service-scoped env for the same service\n const additionalIds: string[] = [];\n for (const parentId of environment.parentIds) {\n const parentEnv = await environmentStore.get(parentId);\n if (!parentEnv || parentEnv.scope !== 'global') continue;\n\n for (const grandparentGlobalId of parentEnv.parentIds) {\n const ancestorServiceEnv = await environmentStore.findServiceEnvironment(environment.reference, grandparentGlobalId);\n if (ancestorServiceEnv && !environment.parentIds.includes(ancestorServiceEnv.id)) {\n additionalIds.push(ancestorServiceEnv.id);\n }\n }\n }\n\n if (additionalIds.length === 0) return environment.parentIds;\n return [...environment.parentIds, ...additionalIds];\n }\n\n /**\n * Project an environment's variables onto their overrides: keep only the\n * variables that have one, and swap in the override's value slot. The key\n * always comes from the definition.\n *\n * Feeding this projection back through `resolveDag` resolves the override\n * chain with the exact same inheritance and dedup-by-key rules as the value\n * chain — so an override set on a parent env is no longer swallowed when a\n * child (or a service env) redeclares the same key.\n */\n private projectOverrides(\n variables: Record<string, Variable>,\n overrides: Record<string, VariableOverride>,\n ): Record<string, Variable> {\n const projected: Record<string, Variable> = {};\n for (const [varId, variable] of Object.entries(variables)) {\n const override = overrides[varId];\n if (override) {\n projected[varId] = { key: variable.key, value: override.value };\n }\n }\n return projected;\n }\n\n /**\n * Resolve the override chain independently of the value chain and return the\n * winning override per variable key (empty when nothing is overridden).\n */\n private async resolveOverridesByKey(environmentId: string): Promise<Record<string, WinningOverride>> {\n const allOverrides = await environmentOverridesStore.getAll();\n if (Object.keys(allOverrides).length === 0) return {};\n\n const result = await this.resolveDag(environmentId, new Set(), (variables) =>\n this.projectOverrides(variables, allOverrides),\n );\n\n const byKey: Record<string, WinningOverride> = {};\n for (const [varId, variable] of Object.entries(result.variables)) {\n const source = result.sources[varId];\n byKey[variable.key] = {\n variable,\n ...(source ? { source: { environmentId: source.environmentId, environmentName: source.environmentName } } : {}),\n };\n }\n return byKey;\n }\n\n private async resolveDag(\n environmentId: string,\n visited: Set<string>,\n project?: (variables: Record<string, Variable>) => Record<string, Variable>,\n ): Promise<DagResult> {\n if (visited.has(environmentId)) {\n throw new Error(`Circular dependency detected in environment inheritance for ${environmentId}`);\n }\n\n const environment = await environmentStore.get(environmentId);\n if (!environment) {\n throw new Error(`Environment \"${environmentId}\" not found`);\n }\n\n visited.add(environmentId);\n\n // For service-scoped envs: ensure we also inherit from ancestor service-scoped envs.\n // When a service env's global parent itself has parent globals, we need to include\n // the service-scoped envs of those ancestor globals in the resolution chain.\n const effectiveParentIds = await this.getEffectiveParentIds(environment);\n\n // Resolve all parents first\n const parentResults: DagResult[] = [];\n for (const parentId of effectiveParentIds) {\n const parentVisited = new Set(visited);\n const parentResult = await this.resolveDag(parentId, parentVisited, project);\n parentResults.push(parentResult);\n }\n\n // Merge parent variables (left-to-right, later parents override earlier)\n const mergedVariables: Record<string, Variable> = {};\n const sources: Record<string, VariableSource> = {};\n\n for (const result of parentResults) {\n // Dedup by key: if a later parent has a variable with the same key, remove the earlier one\n for (const [varId, variable] of Object.entries(result.variables)) {\n for (const [existingId, existingVar] of Object.entries(mergedVariables)) {\n if (existingVar.key === variable.key && existingId !== varId) {\n delete mergedVariables[existingId];\n delete sources[existingId];\n }\n }\n mergedVariables[varId] = variable;\n sources[varId] = result.sources[varId] ?? sources[varId];\n }\n }\n\n // Build parentEnv: concrete values from parents BEFORE child dedup/override\n // Used as interpolation context so {{environment.KEY}} resolves against parent values\n const parentEnv: Record<string, string> = {};\n const parentSecretKeys = new Set<string>();\n const parentKeySources: Record<string, { environmentId: string; environmentName: string }> = {};\n for (const [varId, variable] of Object.entries(mergedVariables)) {\n const slot = variable.value;\n parentEnv[variable.key] = slot.pre + slot.value + slot.post;\n if (slot.isSecret) {\n parentSecretKeys.add(variable.key);\n }\n const source = sources[varId];\n if (source) {\n parentKeySources[variable.key] = { environmentId: source.environmentId, environmentName: source.environmentName };\n }\n }\n // Also include parent-of-parent values for deeper chains.\n // Prefer concrete values over interpolation references: if parentEnv already has a\n // raw {{environment.KEY}} ref for a key, replace it with a concrete value if found.\n const isInterpRef = (v: string) => /\\{\\{environment\\.[^}]+\\}\\}/.test(v);\n for (const result of parentResults) {\n for (const [key, value] of Object.entries(result.parentEnv)) {\n const existingIsRef = key in parentEnv && isInterpRef(parentEnv[key]);\n const newIsConcrete = !isInterpRef(value);\n if (!(key in parentEnv) || (existingIsRef && newIsConcrete)) {\n parentEnv[key] = value;\n }\n }\n for (const key of result.parentSecretKeys) {\n parentSecretKeys.add(key);\n }\n for (const [key, source] of Object.entries(result.parentKeySources)) {\n if (!(key in parentKeySources)) {\n parentKeySources[key] = source;\n }\n }\n }\n // Une variable héritée qui interpole un secret est elle-même un secret, et\n // doit le rester pour les descendants — sans ça le caractère secret se perd\n // dès qu'on descend d'un niveau.\n for (const key of this.collectSecretKeys(mergedVariables, parentSecretKeys)) {\n parentSecretKeys.add(key);\n }\n\n // Apply current environment's own variables\n const ownVariables = project ? project(environment.variables) : environment.variables;\n for (const [varId, variable] of Object.entries(ownVariables)) {\n // Remove any parent variable with the same key but different variableId (dedup by key)\n let wasInherited = varId in mergedVariables;\n for (const [existingId, existingVar] of Object.entries(mergedVariables)) {\n if (existingVar.key === variable.key && existingId !== varId) {\n delete mergedVariables[existingId];\n delete sources[existingId];\n wasInherited = true;\n }\n }\n mergedVariables[varId] = variable;\n sources[varId] = {\n environmentId: environment.id,\n environmentName: environment.name,\n overridden: wasInherited,\n };\n }\n\n return {\n variables: mergedVariables,\n sources,\n parentEnv,\n parentSecretKeys,\n parentKeySources,\n };\n }\n}\n\nexport const environmentResolver = new EnvironmentResolver();\n","import { appendFile, readFile, stat, rename, unlink, readdir, mkdir } from 'node:fs/promises';\nimport { machineFilePath, machineRoot } from './vault-resolver.js';\n\nexport interface AuditEntry {\n timestamp: string;\n userId: string;\n action: string;\n entityType: string;\n entityId: string;\n metadata?: Record<string, unknown>;\n}\n\nconst AUDIT_FILENAME = 'audit.log';\nconst MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB\nconst MAX_AGE_DAYS = 30;\n\nclass AuditService {\n private getFilePath(): string {\n return machineFilePath(AUDIT_FILENAME);\n }\n\n private getRotatedPath(): string {\n return machineFilePath(`audit.log.${Date.now()}.bak`);\n }\n\n /** Append an audit entry (newline-delimited JSON) */\n async log(entry: Omit<AuditEntry, 'timestamp'>): Promise<void> {\n const record: AuditEntry = {\n ...entry,\n timestamp: new Date().toISOString(),\n };\n const line = JSON.stringify(record) + '\\n';\n const filepath = this.getFilePath();\n\n try {\n await mkdir(machineRoot(), { recursive: true });\n await appendFile(filepath, line, 'utf-8');\n await this.rotateIfNeeded();\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error('[audit] Failed to write audit log:', message);\n }\n }\n\n /** Read audit entries, optionally filtered */\n async list(options?: {\n action?: string;\n entityType?: string;\n entityId?: string;\n limit?: number;\n offset?: number;\n }): Promise<{ entries: AuditEntry[]; total: number }> {\n const filepath = this.getFilePath();\n let lines: string[];\n try {\n const content = await readFile(filepath, 'utf-8');\n lines = content.trim().split('\\n').filter(Boolean);\n } catch {\n return { entries: [], total: 0 };\n }\n\n let entries: AuditEntry[] = lines\n .map((line) => {\n try { return JSON.parse(line) as AuditEntry; } catch { return null; }\n })\n .filter((e): e is AuditEntry => e !== null)\n .reverse(); // newest first\n\n // Apply filters\n if (options?.action) {\n entries = entries.filter((e) => e.action === options.action);\n }\n if (options?.entityType) {\n entries = entries.filter((e) => e.entityType === options.entityType);\n }\n if (options?.entityId) {\n entries = entries.filter((e) => e.entityId === options.entityId);\n }\n\n const total = entries.length;\n const offset = options?.offset ?? 0;\n const limit = options?.limit ?? 50;\n entries = entries.slice(offset, offset + limit);\n\n return { entries, total };\n }\n\n /** Rotate log file if it exceeds MAX_FILE_SIZE */\n private async rotateIfNeeded(): Promise<void> {\n const filepath = this.getFilePath();\n try {\n const stats = await stat(filepath);\n if (stats.size > MAX_FILE_SIZE) {\n await rename(filepath, this.getRotatedPath());\n }\n } catch {\n // File doesn't exist, nothing to rotate\n }\n }\n\n /** Clean up old rotated logs (older than MAX_AGE_DAYS) */\n async cleanup(): Promise<void> {\n const files = await readdir(machineRoot());\n const cutoff = Date.now() - MAX_AGE_DAYS * 24 * 60 * 60 * 1000;\n\n for (const file of files) {\n if (file.startsWith('audit.log.') && file.endsWith('.bak')) {\n const tsStr = file.replace('audit.log.', '').replace('.bak', '');\n const ts = Number.parseInt(tsStr, 10);\n if (!Number.isNaN(ts) && ts < cutoff) {\n try {\n await unlink(machineFilePath(file));\n } catch {\n // Ignore\n }\n }\n }\n }\n }\n}\n\nexport const auditService = new AuditService();\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 { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { HealthCheckSchema, RestartStrategySchema } from '@runeya/packages-shared';\nimport type { ProcessStatus } from '@runeya/packages-shared';\nimport { router, protectedProcedure, requireServiceAction, getAllowedServiceIds } from '../trpc.js';\nimport type { AuthContext } from '../trpc.js';\nimport { serviceStore } from '../../services/service-store.js';\nimport { agentManager } from '../../services/agent-manager.js';\nimport { auditService } from '../../services/audit-service.js';\nimport { projectStore } from '../../services/project-store.js';\nimport { environmentResolver } from '../../services/environment-resolver.js';\nimport { environmentStore } from '../../services/environment-store.js';\nimport { logParserStore } from '../../services/log-parser-store.js';\nimport { nativeParsers } from '@runeya/packages-shared';\nimport { ServiceShortcutSchema, ServiceCommandSchema, DockerConfigSchema, LogSourceConfigSchema, AGENT_STOP_FETCH_TIMEOUT } from '@runeya/packages-shared';\nimport type { ServiceConfig } from '@runeya/packages-shared';\nimport { interpolateBuiltinsInEnv } from '@runeya/packages-shared';\nimport { buildServerBuiltins } from '../../services/service-builtins.js';\nimport { env } from '../../config/env.js';\nimport { isAbsolute } from 'node:path';\nimport { resolveWorkspaceCwd } from '../../services/workspace-cwd.js';\nimport { agentStore } from '../../services/agent-store.js';\n\n\n/**\n * Resolve the effective agentId for a service.\n * Priority: service.agentId (explicit override) → activeEnvironment.agentId →\n * l'agent local de ce poste.\n *\n * Le dernier recours n'est pas une commodité, c'est ce qui rend un projet\n * récupéré du cloud utilisable. Un service synchronisé porte l'agent de la\n * machine qui l'a publié — un identifiant qui ne désigne rien ici — et les\n * environnements, eux, ne voyagent pas : ils portent des secrets et restent\n * locaux. Le nouvel arrivant se retrouvait donc devant « aucun agent assigné »\n * sur chacun de ses services, sans rien avoir fait de travers.\n *\n * Un agent nommé mais inconnu de ce poste vaut donc absence : le garder\n * reviendrait à déployer vers un agent qui n'existe pas, pour une erreur plus\n * obscure encore.\n */\nexport async function resolveEffectiveAgentId(service: ServiceConfig): Promise<string | null> {\n // Les agents connectés, pas ceux persistés : l'agent local d'un poste est\n // enregistré « en mémoire seulement » (voir `agentManager.registerLocal`) et\n // n'apparaît donc jamais dans `agentStore`. S'y fier revenait à ignorer le\n // seul agent que la machine possède à coup sûr.\n const known = new Set([\n ...agentManager.listAgents().map((a) => a.config.id),\n ...(await agentStore.list()).map((a) => a.id),\n ]);\n if (service.agentId && known.has(service.agentId)) return service.agentId;\n\n const projects = await projectStore.list();\n const project = projects.find(p => p.serviceIds.includes(service.id));\n if (project?.activeEnvironmentId) {\n const activeEnv = await environmentStore.get(project.activeEnvironmentId);\n if (activeEnv?.agentId && known.has(activeEnv.agentId)) return activeEnv.agentId;\n }\n\n // L'agent local du poste, ou à défaut le premier connecté. Nommer un autre\n // agent reste un choix explicite, jamais une supposition.\n return agentManager.getDefaultAgentId();\n}\n\n/**\n * Helper to resolve service variables to env dict before deployment.\n * Finds the project containing this service and uses its activeEnvironmentId.\n * Also resolves parserIds to full parser definitions.\n */\nexport async function resolveServiceVariables(service: ServiceConfig): Promise<ServiceConfig> {\n // Find the project containing this service\n const projects = await projectStore.list();\n const project = projects.find(p => p.serviceIds.includes(service.id));\n\n let resolvedService: ServiceConfig = service;\n\n // Anchor a cloud project's services to where that project lives on this\n // machine. A cloud project is materialized from a document that holds no\n // path, so without this a relative cwd falls back to '.' — the directory\n // Runeya was launched from — and every cloud project opened from the same\n // place would run against whatever code happens to be there.\n // Only set when the project actually places the service somewhere: an\n // untouched `cwd` must keep reaching the agent as-is, since a relative one is\n // resolved against the agent's own directory — possibly on another machine.\n const anchored = await resolveWorkspaceCwd({ serviceId: service.id });\n if (anchored !== (service.cwd ?? '').trim() && isAbsolute(anchored)) {\n resolvedService = { ...resolvedService, resolvedCwd: anchored };\n }\n\n // Resolve parser IDs to full parser definitions (always, regardless of environment)\n try {\n if (service.parserIds && service.parserIds.length > 0) {\n // Dans le coffre du projet : un service d'organisation référence des\n // parseurs qui appartiennent à cette organisation. Les chercher au niveau\n // du poste rendrait une liste vide chez tout membre qui ne les a pas\n // écrits lui-même — et le service partirait à l'agent sans parseur, sans\n // que rien ne le signale.\n const vault = project?.orgId ?? undefined;\n const parsers = await logParserStore.list(vault);\n const allParsers = [...nativeParsers, ...parsers];\n const resolvedParsers = service.parserIds\n .map(id => allParsers.find(p => p.id === id))\n .filter((p) => p !== undefined);\n resolvedService = { ...resolvedService, resolvedLogParsers: resolvedParsers };\n }\n } catch (err) {\n console.error('[service-router] Failed to resolve parsers for service', service.id + ':', (err as Error).message);\n }\n\n if (!project || !project.activeEnvironmentId) {\n // No project or no active environment — nothing more to resolve\n return resolvedService;\n }\n\n // Resolve variables to env dict\n try {\n const resolved = await environmentResolver.resolveForService({\n serviceId: service.id,\n activeEnvironmentId: project.activeEnvironmentId,\n });\n\n // Interpolate the server-side builtins the environment resolver left alone.\n // The agent-side ones ({{agent.*}}, {{service.CWD}}) are deliberately NOT\n // resolved here: they belong to the machine that runs the service, not to\n // the one that deploys it — see `BUILTIN_VARIABLES`.\n const [environment, agentId, siblings] = await Promise.all([\n environmentStore.get(project.activeEnvironmentId),\n resolveEffectiveAgentId(service),\n Promise.all(project.serviceIds.filter((id) => id !== service.id).map((id) => serviceStore.get(id))),\n ]);\n const agent = agentId ? await agentStore.get(agentId) : null;\n\n const builtins = buildServerBuiltins({\n service,\n siblings: siblings.filter((sibling) => sibling !== null),\n projectName: project.name,\n environmentName: environment?.name,\n agentName: agent?.name,\n host: env.HOST,\n });\n\n resolvedService = {\n ...resolvedService,\n env: interpolateBuiltinsInEnv(resolved.env, builtins),\n envSecrets: [...resolved.envSecrets],\n };\n } catch (err) {\n console.error('[service-router] Failed to resolve variables for service', service.id + ':', (err as Error).message);\n }\n\n return resolvedService;\n}\n\n\nconst DockerConfigInput = DockerConfigSchema;\n\nexport const serviceRouter = router({\n list: protectedProcedure\n .meta({ openapi: { method: 'GET', path: '/services', tags: ['services'], summary: 'List all services', protect: true } })\n .output(z.any())\n .query(async ({ ctx }) => {\n const all = await serviceStore.list();\n const allowedIds = getAllowedServiceIds(ctx as AuthContext);\n const filtered = allowedIds ? all.filter(s => allowedIds.has(s.id)) : all;\n return Promise.all(filtered.map(async (s) => ({\n ...s,\n effectiveAgentId: await resolveEffectiveAgentId(s),\n })));\n }),\n\n get: protectedProcedure\n .meta({ openapi: { method: 'GET', path: '/services/{id}', tags: ['services'], summary: 'Get a service by ID', protect: true } })\n .input(z.object({ 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 service = await serviceStore.get(input.id);\n if (!service) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Service ${input.id} not found` });\n }\n return service;\n }),\n\n create: protectedProcedure\n .meta({ openapi: { method: 'POST', path: '/services', tags: ['services'], summary: 'Create a new service', protect: true } })\n .output(z.any())\n .input(\n z.object({\n agentId: z.string().max(128).optional(),\n name: z.string().min(1).max(200),\n commands: z.array(ServiceCommandSchema).max(50).optional(),\n cwd: z.string().max(4096).optional(),\n ports: z.array(z.number().int().min(1).max(65535)).max(20).optional(),\n groups: z.array(z.string().max(200)).max(20).optional(),\n description: z.string().max(2000).optional(),\n docsPath: z.string().max(4096).optional(),\n url: z.string().max(2048).optional(),\n localUrls: z.array(z.object({\n url: z.string().max(253),\n port: z.number().int().min(1).max(65535),\n })).max(20).optional(),\n openapiUrl: z.string().max(2048).optional(),\n git: z.object({ remote: z.string().max(2048).optional(), home: z.string().max(2048).optional() }).optional(),\n meta: z.record(z.string().max(256), z.string().max(2000)).optional()\n .refine((obj) => !obj || Object.keys(obj).length <= 100, { message: 'Too many meta keys (max 100)' }),\n runner: z.enum(['native', 'docker']).optional().default('native'),\n dockerConfig: DockerConfigInput.optional(),\n healthCheck: HealthCheckSchema.optional(),\n autoRestart: z.boolean().optional().default(false),\n restartStrategy: RestartStrategySchema.optional(),\n maxRestarts: z.number().int().nonnegative().optional(),\n restartBackoffMs: z.number().int().positive().optional().default(1000),\n orgId: z.string().max(128).nullable().optional(),\n shortcuts: z.array(ServiceShortcutSchema).max(50).optional(),\n parserIds: z.array(z.string().max(128)).max(50).optional(),\n }),\n )\n .mutation(async ({ input }) => {\n // Validate agent exists (only if explicitly provided)\n if (input.agentId) {\n const status = agentManager.getStatus(input.agentId);\n if (!status) {\n throw new TRPCError({\n code: 'NOT_FOUND',\n message: `Agent ${input.agentId} not found`\n });\n }\n }\n\n if (input.runner === 'docker') {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Docker runner is not yet supported. Use \"native\" runner.' });\n }\n const service = await serviceStore.create({\n ...input,\n agentId: input.agentId,\n });\n await auditService.log({ userId: 'local', action: 'create', entityType: 'service', entityId: service.id, metadata: { name: input.name } });\n return service;\n }),\n\n update: protectedProcedure\n .meta({ openapi: { method: 'PATCH', path: '/services/{id}', tags: ['services'], summary: 'Update a service', protect: true } })\n .output(z.any())\n .input(\n z.object({\n id: z.string().max(128),\n agentId: z.string().max(128).nullable().optional(), // null = clear (inherit from env)\n name: z.string().min(1).max(200).optional(),\n commands: z.array(ServiceCommandSchema).max(50).optional(),\n cwd: z.string().max(4096).nullable().optional(),\n ports: z.array(z.number().int().min(1).max(65535)).max(20).optional(),\n groups: z.array(z.string().max(200)).max(20).optional(),\n description: z.string().max(2000).optional(),\n docsPath: z.string().max(4096).optional(),\n url: z.string().max(2048).optional(),\n localUrls: z.array(z.object({\n url: z.string().max(253),\n port: z.number().int().min(1).max(65535),\n })).max(20).optional(),\n openapiUrl: z.string().max(2048).optional(),\n git: z.object({ remote: z.string().max(2048).optional(), home: z.string().max(2048).optional() }).nullable().optional(),\n meta: z.record(z.string().max(256), z.string().max(2000)).nullable().optional()\n .refine((obj) => !obj || Object.keys(obj).length <= 100, { message: 'Too many meta keys (max 100)' }),\n runner: z.enum(['native', 'docker']).optional(),\n dockerConfig: DockerConfigInput.optional(),\n healthCheck: HealthCheckSchema.nullable().optional(),\n autoRestart: z.boolean().optional(),\n clearLogsOnStart: z.boolean().optional(),\n restartStrategy: RestartStrategySchema.optional(),\n maxRestarts: z.number().int().nonnegative().optional(),\n restartBackoffMs: z.number().int().positive().optional(),\n orgId: z.string().max(128).nullable().optional(),\n shortcuts: z.array(ServiceShortcutSchema).max(50).optional(),\n parserIds: z.array(z.string().max(128)).max(50).optional(),\n logSources: z.array(LogSourceConfigSchema).max(20).optional(),\n }),\n )\n .mutation(async ({ input }) => {\n const existing = await serviceStore.get(input.id);\n if (!existing) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Service ${input.id} not found` });\n }\n\n // If changing agentId (including clearing it), stop the service on the old agent if running\n let stoppedForAgentChange = false;\n if (input.agentId !== undefined && input.agentId !== existing.agentId && existing.agentId) {\n const oldAgentStatus = agentManager.getStatus(existing.agentId);\n if (oldAgentStatus?.connected) {\n try {\n const processes = await agentManager.agentQuery<ProcessStatus[]>(existing.agentId, 'process.list');\n const proc = processes.find((p) => p.serviceId === input.id);\n if (proc && (proc.state === 'running' || proc.state === 'starting')) {\n await agentManager.agentMutation(existing.agentId, 'process.stop', { id: input.id }, AGENT_STOP_FETCH_TIMEOUT);\n stoppedForAgentChange = true;\n }\n } catch {\n // Agent unreachable or stop failed — allow the config change anyway\n }\n }\n\n // Validate new agent exists (only when setting a non-null agentId)\n if (input.agentId) {\n const newAgentStatus = agentManager.getStatus(input.agentId);\n if (!newAgentStatus) {\n throw new TRPCError({\n code: 'NOT_FOUND',\n message: `Agent ${input.agentId} not found`\n });\n }\n }\n }\n\n const service = await serviceStore.update(input);\n if (!service) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Service ${input.id} not found` });\n }\n\n // If service was renamed, cascade to service-scoped environment names\n if (input.name && input.name !== existing.name) {\n await environmentStore.renameByReference(input.id, input.name);\n }\n\n // Propagate config to assigned agent (only if service has an explicit agentId)\n if (service.agentId) {\n const agentStatus = agentManager.getStatus(service.agentId);\n if (agentStatus?.connected) {\n try {\n const resolvedService = await resolveServiceVariables(service);\n await agentManager.agentMutation(service.agentId, 'process.updateConfig', {\n serviceId: service.id,\n config: resolvedService,\n });\n } catch (err) {\n console.debug('[service-router] Failed to propagate config to agent', service.agentId + ':', (err as Error).message);\n }\n }\n }\n\n await auditService.log({ userId: 'local', action: 'update', entityType: 'service', entityId: input.id });\n return { ...service, effectiveAgentId: await resolveEffectiveAgentId(service), stoppedForAgentChange };\n }),\n\n delete: protectedProcedure\n .meta({ openapi: { method: 'DELETE', path: '/services/{id}', tags: ['services'], summary: 'Delete a service', protect: true } })\n .input(z.object({ id: z.string().max(128) }))\n .output(z.object({ success: z.literal(true) }))\n .mutation(async ({ input }) => {\n const deleted = await serviceStore.delete(input.id);\n if (!deleted) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Service ${input.id} not found` });\n }\n await auditService.log({ userId: 'local', action: 'delete', entityType: 'service', entityId: input.id });\n return { success: true as const };\n }),\n\n checkCwd: protectedProcedure\n .input(z.object({ id: z.string().max(128), checkReachability: z.boolean().optional() }))\n .query(async ({ input }) => {\n const service = await serviceStore.get(input.id);\n if (!service) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Service ${input.id} not found` });\n }\n const effectiveAgentId = await resolveEffectiveAgentId(service);\n if (!effectiveAgentId) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'No agent configured for this service' });\n }\n\n // Delegate entirely to the agent — it resolves $VAR from its own process.env\n const agentResult = await agentManager.agentQuery<{\n exists: boolean;\n actualRemote: string | null;\n remoteMatches?: boolean;\n unreachable: boolean;\n resolvedCwd: string;\n unresolvedVars: string[];\n }>(effectiveAgentId, 'git.checkCwd', {\n // Anchored on the project, so the check answers about the directory the\n // service will actually run in.\n cwd: await resolveWorkspaceCwd({ serviceId: service.id }),\n remote: service.git?.remote,\n checkReachability: input.checkReachability,\n });\n\n const { exists, actualRemote, remoteMatches, unreachable, resolvedCwd, unresolvedVars } = agentResult;\n\n if (unresolvedVars.length > 0) {\n return { exists: false, canClone: false, unresolvedVars, resolvedCwd, gitMismatch: null };\n }\n\n const canClone = !!service.git?.remote && (!exists || actualRemote === null);\n\n let gitMismatch: { actual: string | null; configured: string; unreachable?: boolean } | null = null;\n if (exists && service.git?.remote && !canClone) {\n if (actualRemote === null) {\n gitMismatch = { actual: null, configured: service.git.remote };\n // `remoteMatches` absent : agent plus ancien, on retombe sur l'égalité stricte.\n } else if (remoteMatches === undefined ? actualRemote !== service.git.remote : !remoteMatches) {\n gitMismatch = { actual: actualRemote, configured: service.git.remote };\n } else if (unreachable) {\n gitMismatch = { actual: actualRemote, configured: service.git.remote, unreachable: true };\n }\n }\n\n return { exists, canClone, unresolvedVars: [], resolvedCwd, gitMismatch };\n }),\n\n cloneRepository: protectedProcedure\n .input(z.object({ id: z.string().max(128) }))\n .mutation(async ({ input }) => {\n const service = await serviceStore.get(input.id);\n if (!service) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Service ${input.id} not found` });\n }\n if (!service.git?.remote) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Service has no git remote configured' });\n }\n const effectiveAgentId = await resolveEffectiveAgentId(service);\n if (!effectiveAgentId) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'No agent configured for this service' });\n }\n\n // Delegate entirely to the agent — it resolves $VAR from its own process.env\n await agentManager.agentMutation(effectiveAgentId, 'git.clone', {\n remote: service.git.remote,\n // Clones WRITE: landing this in the launch directory instead of the\n // project's is how a repository ends up in the wrong place.\n cwd: await resolveWorkspaceCwd({ serviceId: service.id }),\n }, 5 * 60 * 1000);\n\n return { success: true as const };\n }),\n});\n","import { randomUUID } from 'node:crypto';\nimport { JSLogParserSchema, type JSLogParserDef } from '@runeya/packages-shared';\nimport { settingsManager } from './settings-manager.js';\n\n/**\n * Les parseurs de logs, rangés dans le coffre de ce qu'ils décrivent.\n *\n * Un parseur décrit le format des logs d'un service, et les services\n * appartiennent à des organisations : le parseur qui lit « nos logs Symfony »\n * décrit le travail d'une équipe, pas la machine d'une personne. Il vit donc\n * dans le coffre de l'organisation, d'où la synchronisation le porte aux autres\n * membres — sans quoi un service partagé arrive chez un collègue en référençant\n * (`ServiceConfig.parserIds`) un parseur qu'il n'a pas, et ses logs cessent\n * d'être lus sans que rien ne le dise.\n *\n * Le coffre sans organisation reste possible : une machine qui ne travaille\n * pour personne garde ses parseurs pour elle.\n *\n * Ce store existe pour une seconde raison : donner un point d'écoute. Les\n * réglages n'en avaient pas, et la synchronisation a besoin de savoir qu'un\n * parseur a changé pour le porter dans le document de l'organisation.\n */\n\ntype Listener = () => void;\n/** Reçoit le coffre touché : l'interface n'écoute que celui qu'elle affiche. */\ntype VaultListener = (vault: string | undefined) => void;\n\n/**\n * Un parseur natif ne se partage pas.\n *\n * Les natifs sont livrés avec l'application : chaque poste a déjà les siens,\n * dans la version de son binaire. En pousser une copie dans le document d'une\n * organisation en ferait un doublon qui vieillit — figé au jour où il est\n * parti, pendant que le natif, lui, suit les mises à jour — et il reviendrait\n * s'ajouter à la liste de tout le monde à côté de son original.\n *\n * Le garde porte sur les deux marques, parce qu'elles ne disent pas la même\n * chose : `builtin` est ce que le schéma expose, le préfixe d'identifiant est\n * ce que `nativeParsers` produit, et le routeur refuse déjà de toucher au\n * second. Un parseur qui porte l'une ou l'autre reste ici.\n */\nfunction isShareable(parser: { id: string; builtin?: boolean }): boolean {\n return parser.builtin !== true && !parser.id.startsWith('native:');\n}\n\n/** Champs qu'un appelant fournit ; l'id et les dates appartiennent au store. */\nexport type LogParserInput = Omit<JSLogParserDef, 'id' | 'createdAt' | 'updatedAt'>;\n\nclass LogParserStore {\n private readonly localListeners = new Set<Listener>();\n private readonly changeListeners = new Set<VaultListener>();\n\n /**\n * S'abonner aux écritures *locales* — celles nées ici.\n *\n * C'est ce qu'écoute la synchronisation : réagir aussi à ce qui arrive du\n * document la ferait repartir aussitôt vers ce document, en boucle.\n */\n onLocalChange(fn: Listener): () => void {\n this.localListeners.add(fn);\n return () => this.localListeners.delete(fn);\n }\n\n /**\n * S'abonner à toute écriture, d'où qu'elle vienne.\n *\n * C'est ce qu'écoute l'interface : un parseur écrit par un collègue arrive\n * par le document, donc silencieusement pour la synchronisation — mais un\n * écran qui ne l'apprend qu'au prochain montage montre une liste fausse\n * pendant tout ce temps, alors même que les services, eux, se rafraîchissent.\n */\n onChanged(fn: VaultListener): () => void {\n this.changeListeners.add(fn);\n return () => this.changeListeners.delete(fn);\n }\n\n private notify(vault: string | undefined, local: boolean): void {\n if (local) {\n for (const fn of this.localListeners) {\n try {\n fn();\n } catch (err) {\n console.error('[log-parser-store] listener failed:', (err as Error).message);\n }\n }\n }\n for (const fn of this.changeListeners) {\n try {\n fn(vault);\n } catch (err) {\n console.error('[log-parser-store] listener failed:', (err as Error).message);\n }\n }\n }\n\n /** Les parseurs d'un coffre — ceux de l'organisation, ou ceux du poste. */\n async list(vault?: string): Promise<JSLogParserDef[]> {\n const settings = await settingsManager.getSettings(vault);\n return settings.logParsers ?? [];\n }\n\n async get(id: string, vault?: string): Promise<JSLogParserDef | null> {\n return (await this.list(vault)).find((p) => p.id === id) ?? null;\n }\n\n private async write(parsers: JSLogParserDef[], vault?: string, silent = false): Promise<void> {\n const settings = await settingsManager.getSettings(vault);\n await settingsManager.saveSettings({ ...settings, logParsers: parsers }, vault);\n this.notify(vault, !silent);\n }\n\n async create(input: LogParserInput, vault?: string): Promise<JSLogParserDef> {\n const now = new Date();\n if (input.builtin) {\n throw new Error('A parser created here is never a built-in one');\n }\n const parser = JSLogParserSchema.parse({\n ...input,\n id: randomUUID(),\n createdAt: now,\n updatedAt: now,\n });\n await this.write([...(await this.list(vault)), parser], vault);\n return parser;\n }\n\n async update(\n id: string,\n patch: Partial<LogParserInput>,\n vault?: string,\n ): Promise<JSLogParserDef | null> {\n const parsers = await this.list(vault);\n const index = parsers.findIndex((p) => p.id === id);\n if (index === -1) return null;\n const updated = JSLogParserSchema.parse({\n ...parsers[index],\n ...patch,\n id,\n updatedAt: new Date(),\n });\n const next = [...parsers];\n next[index] = updated;\n await this.write(next, vault);\n return updated;\n }\n\n async delete(id: string, vault?: string): Promise<boolean> {\n const parsers = await this.list(vault);\n const next = parsers.filter((p) => p.id !== id);\n if (next.length === parsers.length) return false;\n await this.write(next, vault);\n return true;\n }\n\n // ---- Synchronisation --------------------------------------------------\n\n /**\n * Écrire ce que le document de l'organisation porte.\n *\n * Silencieux et gardé par une comparaison : réveiller les écoutants ici\n * relancerait la réconciliation qui vient de produire cette écriture, et un\n * document identique au disque ne mérite pas un fichier réécrit.\n */\n async applyRemoteUpsert(id: string, fields: unknown, orgId: string): Promise<void> {\n const parsed = JSLogParserSchema.safeParse({ ...(fields as object), id });\n if (!parsed.success) {\n console.warn('[log-parser-store] rejected a remote parser %s: %s', id, parsed.error.message);\n return;\n }\n // Un natif arrivé par le document vient d'une version qui ne gardait pas\n // encore la porte ; le laisser entrer doublerait la liste locale.\n if (!isShareable(parsed.data)) return;\n const parsers = await this.list(orgId);\n const index = parsers.findIndex((p) => p.id === id);\n if (index !== -1 && sameParser(parsers[index]!, parsed.data)) return;\n const next = [...parsers];\n if (index === -1) next.push(parsed.data);\n else next[index] = parsed.data;\n await this.write(next, orgId, true);\n }\n\n async applyRemoteDelete(id: string, orgId: string): Promise<void> {\n const parsers = await this.list(orgId);\n const next = parsers.filter((p) => p.id !== id);\n if (next.length === parsers.length) return;\n await this.write(next, orgId, true);\n }\n\n /**\n * Remonter les parseurs du poste dans les organisations de cette machine.\n *\n * Un déplacement, pas une copie : le même parseur des deux côtés ferait deux\n * vérités qui divergent au premier changement, et la liste du poste\n * ressusciterait à chaque connexion celui qu'un membre vient de supprimer\n * pour toute l'équipe. Une fois la machine vidée, il n'y a plus rien à\n * remonter — l'opération peut donc être rejouée sans dégât.\n *\n * Vers *toutes* les organisations liées, chacune recevant sa copie : les\n * coffres ne communiquent pas, et rien ne dit laquelle des deux était visée.\n */\n async migrateMachineParsersInto(orgIds: string[]): Promise<void> {\n if (orgIds.length === 0) return;\n const all = await this.list();\n if (all.length === 0) return;\n const machineParsers = all.filter(isShareable);\n\n for (const orgId of orgIds) {\n const existing = await this.list(orgId);\n const known = new Set(existing.map((p) => p.id));\n const added = machineParsers.filter((p) => !known.has(p.id));\n if (added.length === 0) continue;\n await this.write([...existing, ...added], orgId, true);\n }\n\n // Ce qui n'était pas partageable reste sur le poste : il n'a pas été\n // remonté, le vider l'effacerait.\n await this.write(all.filter((p) => !isShareable(p)), undefined, true);\n if (machineParsers.length > 0) {\n console.log(\n '[log-parser-store] moved %d machine parser(s) into organization(s): %s',\n machineParsers.length,\n orgIds.join(', '),\n );\n }\n }\n}\n\n/** Deux parseurs portent-ils la même chose ? Les dates comptent, l'ordre non. */\nfunction sameParser(a: JSLogParserDef, b: JSLogParserDef): boolean {\n return (\n a.name === b.name\n && a.code === b.code\n && a.enabled === b.enabled\n && (a.description ?? '') === (b.description ?? '')\n && a.updatedAt.getTime() === b.updatedAt.getTime()\n );\n}\n\nexport const logParserStore = new LogParserStore();\nexport { isShareable as isShareableParser };\n","import { readFile, writeFile, rename, mkdir, chmod } from 'node:fs/promises';\nimport { env } from '../config/env.js';\nimport { join } from 'node:path';\nimport { machineFilePath, legacyMachineFilePath, machineRoot, orgVaultRoot } from './vault-resolver.js';\nimport { SettingsSchema, SchemaVersionSchema, SettingsPrivateSchema } from '@runeya/packages-shared';\nimport type { Settings, SchemaVersion, SettingsPrivate } from '@runeya/packages-shared';\n\nconst SETTINGS_FILE = 'settings.json';\nconst SETTINGS_PRIVATE_FILE = 'settings.private.json';\nconst SCHEMA_VERSION_FILE = 'schema-version.json';\nconst CURRENT_SCHEMA_VERSION = 4;\n\n/**\n * Les réglages vivent dans le coffre de ce qu'ils configurent.\n *\n * Ils étaient au niveau machine — un fichier pour tout le poste — alors qu'ils\n * décrivent des choses qui appartiennent à des organisations différentes : les\n * fournisseurs d'IA qui paient le travail d'une équipe, les scénarios qui\n * décrivent ses services. Un réglage global obligeait donc à partager la clé\n * machine pour partager un secret d'organisation.\n *\n * `vault` désigne le coffre : l'identifiant d'une organisation, ou l'absence\n * pour le répertoire de lancement — celui d'un projet local, qui n'appartient à\n * personne d'autre. Rien ne reste au niveau machine sinon la session cloud,\n * irréductible puisque c'est elle qui donne accès aux organisations.\n */\nclass SettingsManager {\n private settings = new Map<string, Settings>();\n private settingsPrivate = new Map<string, SettingsPrivate>();\n private schemaVersion: SchemaVersion | null = null;\n\n /**\n * Le coffre visé, sous forme de racine sur le disque.\n *\n * Sans organisation, la racine machine — pas le répertoire de lancement. Ce\n * n'est pas un reste de l'ancien monde : y écrire forcerait un `.runeya` à\n * exister chez quelqu'un qui ne travaille que sur des projets cloud, ce que\n * les coffres ont justement supprimé (et ce qu'un test garde).\n */\n private rootOf(vault?: string): string {\n return vault ? orgVaultRoot(vault) : machineRoot();\n }\n\n private cacheKey(vault?: string): string {\n return vault ?? '';\n }\n\n private async atomicWrite(filename: string, data: unknown, vault?: string): Promise<void> {\n const root = this.rootOf(vault);\n await mkdir(root, { recursive: true });\n const filePath = join(root, filename);\n const tmpPath = filePath + '.tmp';\n await writeFile(tmpPath, JSON.stringify(data, null, 2), 'utf-8');\n await rename(tmpPath, filePath);\n await chmod(filePath, 0o600);\n }\n\n /**\n * Lire le fichier de CE coffre, et rien d'autre.\n *\n * Pas de repli sur un autre emplacement : un réglage lu ailleurs que là où il\n * est écrit fait deux vérités pour un même fait, et l'accord entre les deux\n * devient une chose de plus à tenir. Ce que les versions précédentes ont\n * écrit ailleurs est déplacé une fois pour toutes par\n * `migrateSettingsIntoVaults`, pas relu indéfiniment.\n */\n private async readJson<T>(filename: string, vault?: string): Promise<T | null> {\n try {\n return JSON.parse(await readFile(join(this.rootOf(vault), filename), 'utf-8')) as T;\n } catch {\n return null;\n }\n }\n\n /** Vide les caches — après un déplacement de fichiers sous nos pieds. */\n forget(): void {\n this.settings.clear();\n this.settingsPrivate.clear();\n }\n\n /** Un fichier qui appartient au poste, pas à un coffre. */\n private async readMachineJson<T>(filename: string): Promise<T | null> {\n for (const path of [machineFilePath(filename), legacyMachineFilePath(filename)]) {\n try {\n return JSON.parse(await readFile(path, 'utf-8')) as T;\n } catch {\n // Try the next location.\n }\n }\n return null;\n }\n\n async getSettings(vault?: string): Promise<Settings> {\n const key = this.cacheKey(vault);\n let current = this.settings.get(key);\n if (!current) {\n const raw = await this.readJson<unknown>(SETTINGS_FILE, vault);\n const parsed = raw ? SettingsSchema.safeParse(raw) : null;\n if (parsed?.success) {\n current = parsed.data;\n this.settings.set(key, current);\n } else {\n current = SettingsSchema.parse({ mode: env.MODE, cloudUrl: env.CLOUD_URL ?? null });\n await this.saveSettings(current, vault);\n }\n }\n return current;\n }\n\n async saveSettings(settings: Settings, vault?: string): Promise<void> {\n this.settings.set(this.cacheKey(vault), settings);\n await this.atomicWrite(SETTINGS_FILE, settings, vault);\n }\n\n async getPrivateSettings(vault?: string): Promise<SettingsPrivate> {\n const key = this.cacheKey(vault);\n let current = this.settingsPrivate.get(key);\n if (!current) {\n const raw = await this.readJson<unknown>(SETTINGS_PRIVATE_FILE, vault);\n const parsed = raw ? SettingsPrivateSchema.safeParse(raw) : null;\n if (parsed?.success) {\n current = parsed.data;\n this.settingsPrivate.set(key, current);\n } else {\n current = SettingsPrivateSchema.parse({});\n await this.savePrivateSettings(current, vault);\n }\n }\n return current;\n }\n\n async savePrivateSettings(settings: SettingsPrivate, vault?: string): Promise<void> {\n this.settingsPrivate.set(this.cacheKey(vault), settings);\n await this.atomicWrite(SETTINGS_PRIVATE_FILE, settings, vault);\n }\n\n /**\n * La version de schéma reste au niveau machine, et ce n'est pas un oubli :\n * elle ne configure rien, elle date les migrations des données de ce poste.\n */\n async getSchemaVersion(): Promise<SchemaVersion> {\n if (!this.schemaVersion) {\n const raw = await this.readMachineJson<unknown>(SCHEMA_VERSION_FILE);\n const parsed = raw ? SchemaVersionSchema.safeParse(raw) : null;\n if (parsed?.success) {\n this.schemaVersion = parsed.data;\n } else {\n this.schemaVersion = { version: CURRENT_SCHEMA_VERSION, migratedAt: new Date() };\n await this.saveSchemaVersion(this.schemaVersion);\n }\n }\n return this.schemaVersion;\n }\n\n async saveSchemaVersion(sv: SchemaVersion): Promise<void> {\n this.schemaVersion = sv;\n await mkdir(machineRoot(), { recursive: true });\n const filePath = machineFilePath(SCHEMA_VERSION_FILE);\n const tmpPath = filePath + '.tmp';\n await writeFile(tmpPath, JSON.stringify(sv, null, 2), 'utf-8');\n await rename(tmpPath, filePath);\n await chmod(filePath, 0o600);\n }\n\n getCurrentSchemaVersion(): number {\n return CURRENT_SCHEMA_VERSION;\n }\n}\n\nexport const settingsManager = new SettingsManager();\n","import {\n crossServiceValues,\n servicePortValues,\n serviceSlug,\n serviceUrlValues,\n urlHostFor,\n withDeprecatedAliases,\n} from '@runeya/packages-shared';\nimport type { ServiceConfig } from '@runeya/packages-shared';\n\nexport interface ServerBuiltinsInput {\n service: ServiceConfig;\n /** Les autres services du même projet, tels que chargés par l'appelant */\n siblings: ServiceConfig[];\n projectName?: string;\n /** Nom de l'environnement actif */\n environmentName?: string;\n /** Nom de l'agent qui exécutera le service */\n agentName?: string;\n /** Adresse d'écoute du serveur (`env.HOST`) */\n host: string;\n}\n\n/**\n * Les builtins que le serveur sait produire, au moment où il prépare la\n * configuration à déployer : ce qui vient de la configuration elle-même.\n *\n * Volontairement pur — aucun store, aucun accès disque — pour que la règle qui\n * compte ici (quel nom rend quelle valeur) se teste sans monter un serveur.\n * Les builtins de portée `agent` ne sont PAS produits ici : ils décrivent la\n * machine d'exécution, et le faire à sa place graverait celle qui déploie.\n */\nexport function buildServerBuiltins(input: ServerBuiltinsInput): Record<string, string> {\n const { service, siblings, projectName, environmentName, agentName, host } = input;\n\n // `runeya.HOST` reste l'adresse d'écoute telle quelle — c'est ce qu'un service\n // met dans son propre bind, `0.0.0.0` compris. Une URL, elle, doit être\n // joignable et lisible : la boucle locale s'y écrit `localhost`, et en mode\n // LAN on laisse une référence que l'agent résoudra en son IP locale, au\n // lancement, plutôt que d'écrire `http://0.0.0.0:3000`.\n const urlHost = urlHostFor(host) ?? '{{agent.HOST_LAN}}';\n\n const values: Record<string, string> = {\n 'service.NAME': service.name,\n 'service.ID': service.id,\n 'runeya.HOST': host,\n ...servicePortValues(service.ports),\n ...serviceUrlValues(service, urlHost),\n };\n\n // L'« URL de base » saisie par l'utilisateur : ni un port, ni un domaine\n // local — souvent l'adresse publique du service.\n if (service.url) values['service.BASE_URL'] = service.url;\n if (projectName !== undefined) values['project.NAME'] = projectName;\n if (environmentName !== undefined) values['runeya.ENV_NAME'] = environmentName;\n if (agentName !== undefined) values['agent.NAME'] = agentName;\n\n // Un slug ambigu — deux services du projet portant le même nom — n'est\n // exposé pour aucun des deux : rendre l'un d'eux arbitrairement serait pire\n // qu'une référence qui reste visible telle quelle dans la valeur.\n const slugCounts = new Map<string, number>();\n for (const sibling of siblings) {\n const slug = serviceSlug(sibling.name);\n if (slug) slugCounts.set(slug, (slugCounts.get(slug) ?? 0) + 1);\n }\n for (const sibling of siblings) {\n if ((slugCounts.get(serviceSlug(sibling.name)) ?? 0) !== 1) continue;\n Object.assign(values, crossServiceValues({\n name: sibling.name,\n id: sibling.id,\n ports: sibling.ports,\n localUrls: sibling.localUrls,\n url: sibling.url,\n }, urlHost));\n }\n\n return withDeprecatedAliases(values);\n}\n","import { isAbsolute, join, dirname } from 'node:path';\nimport { projectStore } from './project-store.js';\nimport { serviceStore } from './service-store.js';\nimport { projectPathStore } from './project-path-store.js';\nimport type { ProjectRef } from './project-key.js';\nimport { conversationStore } from './conversation-store.js';\nimport { localVaultRoot } from './vault-resolver.js';\n\n/**\n * The one place that answers \"which directory does this work happen in?\".\n *\n * Terminals, the AI chat, git and the editor each used to answer it themselves,\n * and each fell back to `'.'` or `process.cwd()` — the directory Runeya was\n * launched from. For a cloud project, materialized from a document that holds no\n * path, that meant every project ran against whatever code happened to sit\n * there. Four copies of the same fallback are four chances to forget one, so\n * they now share this.\n *\n * Deliberately NOT a process-wide `chdir`: Runeya orchestrates several projects\n * in one process and hands execution to an agent that may not even be on this\n * machine. A working directory belongs to an operation, not to the server.\n *\n * The order is narrowest-first: a service knows better than its project, and a\n * project better than wherever the server was started.\n */\n\nexport interface WorkspaceTarget {\n serviceId?: string | undefined;\n projectId?: string | undefined;\n /**\n * L'organisation du projet visé. Sans elle, un id partagé par plusieurs\n * organisations désignerait un projet au hasard — et donc un répertoire de\n * travail au hasard.\n */\n orgId?: string | null | undefined;\n /**\n * A directory to use instead of the service's own `cwd`, anchored the same way.\n *\n * For paths a service carries besides its working directory — the wiki's\n * `docsPath`, say. Relative ones anchor on the project; absolute ones, and\n * those the agent expands, pass through untouched.\n */\n override?: string | undefined;\n}\n\n/**\n * Where a project lives on this machine, or null when nothing places it.\n *\n * Only cloud projects carry a path: a local project IS its directory, so the\n * launch directory is already the right answer for it.\n */\nasync function projectRoot(ref: ProjectRef): Promise<string | null> {\n const project = await projectStore.get(ref);\n if (!project?.orgId) return null;\n return projectPathStore.get(project);\n}\n\n/**\n * The absolute directory an operation should run in.\n *\n * A cwd that is already absolute, or that the agent expands itself (`~`, `$VAR`),\n * is returned untouched — prefixing those would produce a path that exists\n * nowhere.\n */\nexport async function resolveWorkspaceCwd(target: WorkspaceTarget): Promise<string> {\n const launchDir = localVaultRootParent();\n\n if (target.serviceId) {\n const service = await serviceStore.get(target.serviceId);\n if (service) {\n const raw = (target.override ?? service.cwd ?? '').trim();\n const projects = await projectStore.list();\n const owner = projects.find((p) => p.serviceIds.includes(service.id));\n const root = owner ? await projectRoot(owner) : null;\n // No project directory: hand back what the service holds, untouched. The\n // agent resolves relative paths against ITS OWN directory, and it may not\n // even be on this machine — absolutising here would send it somewhere that\n // does not exist.\n return root ? anchor(root, raw) : (raw || '.');\n }\n }\n\n if (target.projectId) {\n const root = await projectRoot({ id: target.projectId, orgId: target.orgId });\n const raw = (target.override ?? '').trim();\n return root ? anchor(root, raw) : (raw || launchDir);\n }\n\n return anchor(launchDir, (target.override ?? '').trim());\n}\n\n/** Join a relative path onto its base, leaving absolute and agent-expanded ones alone. */\nfunction anchor(base: string, raw: string): string {\n if (!raw || raw === '.') return base;\n if (raw.startsWith('~') || raw.startsWith('$') || isAbsolute(raw)) return raw;\n return join(base, raw);\n}\n\n/**\n * The directory Runeya was launched in — the vault's parent.\n *\n * Derived from the vault rather than read from `process.cwd()`, so it stays put\n * even if something changes the process's directory.\n */\nfunction localVaultRootParent(): string {\n return dirname(localVaultRoot());\n}\n\n/**\n * The directory to hand an AGENT, or undefined when there is nothing to anchor.\n *\n * Distinct from `resolveWorkspaceCwd` on purpose. That one always answers with an\n * absolute path, which is right for work the SERVER does on its own disk. An\n * agent is another process — possibly on another machine — and resolves relative\n * paths against its own directory: handing it this machine's launch directory\n * would send it somewhere that need not exist there.\n *\n * So it only speaks when a project actually places the work somewhere; otherwise\n * it stays silent and the caller keeps whatever default it had.\n */\nexport async function resolveAgentCwd(target: WorkspaceTarget): Promise<string | undefined> {\n if (target.serviceId) {\n const service = await serviceStore.get(target.serviceId);\n if (service) {\n const projects = await projectStore.list();\n const owner = projects.find((p) => p.serviceIds.includes(service.id));\n const root = owner ? await projectRoot(owner) : null;\n if (!root) return undefined;\n return anchor(root, (target.override ?? service.cwd ?? '').trim());\n }\n }\n\n if (target.projectId) {\n const root = await projectRoot({ id: target.projectId, orgId: target.orgId });\n if (!root) return undefined;\n return anchor(root, (target.override ?? '').trim());\n }\n\n return undefined;\n}\n\n/**\n * Le répertoire d'une conversation — celui du projet à qui elle appartient.\n *\n * Une conversation porte déjà son projet : le chat et les scénarios n'ont donc\n * rien à se faire passer de main en main jusqu'au lancement du CLI. Chacun le\n * demandait pourtant à sa façon, et la file kanban, qui lance un scénario hors\n * de toute requête, ne transmettait rien : le CLI travaillait alors dans le\n * répertoire de lancement de Runeya, pas dans celui du projet de la carte.\n *\n * Muette quand rien ne place la conversation, comme `resolveAgentCwd`.\n */\nexport async function resolveConversationCwd(conversationId: string): Promise<string | undefined> {\n const conv = await conversationStore.get(conversationId);\n const ref = conv ? await conversationStore.projectRefOf(conv) : null;\n if (!ref) return resolveAgentCwd({});\n return resolveAgentCwd({ projectId: ref.id, orgId: ref.orgId });\n}\n","import { randomUUID } from 'node:crypto';\nimport { readFile, writeFile, rename, mkdir, chmod } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { EventEmitter } from 'node:events';\nimport { allVaultRoots, keyedFilePath, legacyMachineFilePath, vaultFor , vaultIdOfRoot, orgIdOfRoot } from './vault-resolver.js';\nimport { rememberFile, hasChangedSinceRead, wasRead } from './disk-freshness.js';\nimport { rootOfProjectAmong, refOfProjectAmong, rootOfProjectRef, ensureProjectsLoaded } from './vault-registry.js';\nimport { projectStore } from './project-store.js';\nimport { getEncryptionKey } from '../utils/encryption-key.js';\nimport { encryptValue, decryptValue } from './crypto-helpers.js';\n\nconst FILENAME = 'conversations.private.json';\n\n// ─── Types ─────────────────────────────────────────────────────────────────\n\nexport type MessagePart =\n | { type: 'thinking'; text: string }\n | { type: 'text'; text: string }\n | { type: 'tool'; id: string; name: string; input?: Record<string, unknown>; rawInput?: string; result?: unknown; isError?: boolean; pending: boolean }\n | { type: 'image'; imageId: string; url: string; mimeType: string; altText?: string };\n\nexport interface Message {\n role: 'user' | 'assistant';\n content: string;\n parts?: MessagePart[];\n contextNote?: string;\n}\n\ninterface ContextUsage {\n inputTokens: number;\n contextWindow: number;\n}\n\ntype WorkflowType = 'scenario';\n\nexport interface Conversation {\n id: string;\n /**\n * The project this conversation belongs to.\n *\n * Optional only for conversations written before the field existed, and for\n * those a migration could not attribute: they stay visible from everywhere\n * rather than being hidden under a project picked at random.\n */\n projectId?: string;\n title: string;\n messages: Message[];\n isCli: boolean;\n runner?: 'claude-code' | 'codex';\n providerId?: string;\n codexThreadId?: string;\n contextUsage?: ContextUsage;\n workflowId?: string;\n workflowType?: WorkflowType;\n kanbanBoardId?: string;\n kanbanCardId?: string;\n archived?: boolean;\n createdAt: number;\n updatedAt: number;\n}\n\nexport type ConversationChangeEvent =\n | { type: 'created'; conversation: Conversation }\n | { type: 'updated'; conversation: Conversation }\n | { type: 'deleted'; id: string }\n /**\n * Tout est à relire — le disque a changé sous le store (adoption d'une clé).\n *\n * Sans conversation à porter : ce n'est pas une conversation qui a bougé,\n * c'est l'ensemble qui n'est plus celui que le client détient. L'abonnement\n * répond en renvoyant un instantané complet, le chemin que le client sait\n * déjà traiter.\n */\n | { type: 'reloaded' };\n\ninterface ConversationOnDisk {\n id: string;\n projectId?: string;\n title: string;\n encryptedMessages: string;\n isCli?: boolean;\n isClaudeCode?: boolean;\n runner?: 'claude-code' | 'codex';\n providerId?: string;\n codexThreadId?: string;\n contextUsage?: ContextUsage;\n workflowId?: string;\n workflowType?: WorkflowType;\n kanbanBoardId?: string;\n kanbanCardId?: string;\n // Legacy field from before workflowType was introduced — used only for migration in fromDisk\n scenarioId?: string;\n archived?: boolean;\n createdAt: number;\n updatedAt: number;\n}\n\n/** The project of the launch directory, if it has one. */\nasync function localProjectId(): Promise<string | null> {\n const projects = await projectStore.list().catch(() => []);\n return projects.find((p) => !p.orgId)?.id ?? null;\n}\n\n// ─── Store ─────────────────────────────────────────────────────────────────\n\nclass ConversationStore {\n private conversations: Map<string, Conversation> = new Map();\n /** Which vault each conversation was read from, until its project is known. */\n private roots: Map<string, string> = new Map();\n /**\n * Les conversations qu'on n'a pas su déchiffrer, par coffre, sous leur forme\n * de disque.\n *\n * Une entrée illisible était simplement ignorée. Tant qu'aucune de ses\n * voisines ne se chargeait, le fichier n'était jamais réécrit et la donnée\n * survivait par accident ; dès qu'une seule s'ouvrait, la sauvegarde suivante\n * réécrivait le fichier avec elle seule — et effaçait les autres. Elles sont\n * donc gardées ici, telles quelles, et réémises à l'identique.\n */\n private unreadable: Map<string, ConversationOnDisk[]> = new Map();\n private loaded = false;\n private readonly events = new EventEmitter().setMaxListeners(0);\n private saveQueue: Promise<void> = Promise.resolve();\n\n private snapshotConversation(conv: Conversation): Conversation {\n return structuredClone(conv);\n }\n\n /**\n * Encrypted, so it lives beside the key that opens it — usually the machine\n * root, but a launch directory owning its own key keeps both together.\n */\n private getFilePath(): Promise<string> {\n return keyedFilePath(FILENAME);\n }\n\n /** Where older versions kept it — read only, so an older Runeya keeps working. */\n private getLegacyFilePath(): string {\n return legacyMachineFilePath(FILENAME);\n }\n\n /**\n * Read the machine file, falling back to the launch directory of old.\n *\n * The legacy file is left in place: the next save writes the new location,\n * and a directory still opened by an older Runeya keeps working meanwhile.\n */\n private async readFromDisk(): Promise<string> {\n try {\n return await readFile(await this.getFilePath(), 'utf-8');\n } catch {\n return readFile(this.getLegacyFilePath(), 'utf-8');\n }\n }\n\n private async ensureDir(): Promise<void> {\n await mkdir(dirname(await this.getFilePath()), { recursive: true });\n }\n\n private encryptMessages(messages: Message[], vault?: string): string {\n return encryptValue(JSON.stringify(messages), vault);\n }\n\n private decryptMessages(encrypted: string, vault?: string): Message[] {\n const json = decryptValue(encrypted, vault);\n return JSON.parse(json) as Message[];\n }\n\n /**\n * Refuser d'écrire dans le coffre d'une organisation sans nommer sa clé.\n *\n * `getEncryptionKey(undefined)` rend la clé machine, et c'est le bon défaut\n * pour le coffre local. Appliqué à un fichier rangé sous `orgs/<org>/`, il\n * produit un chiffré que ce coffre n'emploie pas — lisible par personne à la\n * relecture, et impossible à distinguer d'une corruption.\n *\n * Le cas a été observé plusieurs fois sans qu'on parvienne à nommer le\n * chemin fautif : les garde-fous en place traitent le coffre fermé, le\n * coffre mal résolu et la copie périmée, aucun ne couvrait « coffre non\n * précisé ». Ces écritures-là n'ont jamais fonctionné — elles échouaient en\n * silence, ce qui est pire. On les saute désormais en le disant, avec la\n * pile d'appels qui manquait pour remonter au chemin fautif.\n */\n private isVaultNamed(root: string, vault: string | undefined): boolean {\n const orgId = orgIdOfRoot(root);\n if (!orgId || vault) return true;\n // Signalé avec sa pile — c'est elle qu'on cherche — mais sans jeter : une\n // exception ici avorterait la sauvegarde entière, coffres corrects\n // compris. Une conversation mal aiguillée ne doit pas en empêcher vingt\n // autres d'être écrites.\n console.error(\n `[conversation-store] Écriture ignorée dans le coffre de l'organisation ${orgId}`\n + ` (${root}) : aucune clé d'organisation nommée, le contenu serait chiffré par la`\n + ` clé machine et illisible à la relecture.\\n${new Error('trace').stack}`,\n );\n return false;\n }\n\n private toDisk(conv: Conversation, vault?: string): ConversationOnDisk {\n return {\n id: conv.id,\n projectId: conv.projectId,\n title: conv.title,\n encryptedMessages: this.encryptMessages(conv.messages, vault),\n isCli: conv.isCli,\n runner: conv.runner,\n providerId: conv.providerId,\n codexThreadId: conv.codexThreadId,\n contextUsage: conv.contextUsage,\n workflowId: conv.workflowId,\n workflowType: conv.workflowType,\n kanbanBoardId: conv.kanbanBoardId,\n kanbanCardId: conv.kanbanCardId,\n archived: conv.archived,\n createdAt: conv.createdAt,\n updatedAt: conv.updatedAt,\n };\n }\n\n private fromDisk(disk: ConversationOnDisk, vault?: string): Conversation {\n // Derive workflowType from legacy fields for conversations created before this field existed\n const workflowType: WorkflowType | undefined =\n (disk.workflowType === 'scenario' ? 'scenario' : undefined)\n ?? (disk.scenarioId ? 'scenario' : undefined);\n\n return {\n id: disk.id,\n projectId: disk.projectId,\n title: disk.title,\n messages: this.decryptMessages(disk.encryptedMessages, vault),\n isCli: disk.isCli ?? disk.isClaudeCode ?? false,\n runner: disk.runner,\n providerId: disk.providerId,\n codexThreadId: disk.codexThreadId,\n contextUsage: disk.contextUsage,\n workflowId: disk.workflowId ?? disk.scenarioId,\n workflowType,\n kanbanBoardId: disk.kanbanBoardId,\n kanbanCardId: disk.kanbanCardId,\n archived: disk.archived,\n createdAt: disk.createdAt,\n updatedAt: disk.updatedAt,\n };\n }\n\n /**\n * Read every project vault, then the homes older versions used.\n *\n * A conversation found in a legacy file is attributed to the local project of\n * that directory — which is what it was about, back when one directory meant\n * one project. With no local project to point at, it is left unattributed\n * rather than filed under a project picked at random.\n */\n private async load(): Promise<void> {\n if (this.loaded) return;\n if (!getEncryptionKey()) {\n return;\n }\n this.loaded = true;\n // Ce qu'un chargement précédent n'avait pas su lire n'a pas à s'ajouter à\n // celui-ci : la liste décrit le disque tel qu'on vient de le lire, et\n // l'empiler doublait le compte à chaque relecture.\n this.unreadable.clear();\n // Les projets d'abord : tant qu'ils sont inconnus, tout se résoudrait vers\n // le coffre de lancement et y serait réécrit à la première sauvegarde —\n // hors de l'organisation propriétaire.\n await ensureProjectsLoaded();\n\n const vaults = await allVaultRoots();\n const legacyPaths = [this.getLegacyFilePath(), await keyedFilePath(FILENAME)];\n const sources: { path: string; legacy: boolean }[] = [\n ...legacyPaths.map((path) => ({ path, legacy: true })),\n ...vaults.map((root) => ({ path: join(root, FILENAME), legacy: false })),\n ];\n\n for (const { path, legacy } of sources) {\n let data: ConversationOnDisk[];\n try {\n data = JSON.parse(await readFile(path, 'utf-8')) as ConversationOnDisk[];\n } catch {\n continue;\n }\n const inherited = legacy ? await localProjectId() : null;\n const root = dirname(path);\n // L'empreinte du fichier tel qu'on vient de le lire : ce qu'on garde de\n // côté ne vaut que tant qu'il n'a pas bougé.\n await rememberFile(path);\n for (const item of data) {\n try {\n const conv = this.fromDisk(item, vaultIdOfRoot(root));\n if (!conv.projectId && inherited) conv.projectId = inherited;\n this.conversations.set(item.id, conv);\n this.roots.set(item.id, root);\n } catch {\n // Illisible ici — pas perdue pour autant. L'entrée brute est mise de\n // côté pour repartir intacte dans le fichier dont elle vient.\n const bucket = this.unreadable.get(root) ?? [];\n bucket.push(item);\n this.unreadable.set(root, bucket);\n }\n }\n }\n }\n\n /**\n * Oublier ce qui a été lu, pour tout relire sous la clé courante.\n *\n * Appelé après l'adoption d'une clé d'organisation : le disque vient d'être\n * re-chiffré sous les pieds du store, si bien que sa mémoire décrit un état\n * qui n'existe plus. La laisser en place n'affichait pas seulement des\n * comptes périmés — la sauvegarde suivante réécrivait l'ancien chiffré\n * par-dessus le nouveau, et défaisait l'adoption.\n */\n resetCache(): void {\n this.conversations.clear();\n this.roots.clear();\n this.unreadable.clear();\n this.loaded = false;\n this.events.emit('changed', { type: 'reloaded' } as ConversationChangeEvent);\n }\n\n /**\n * Combien de conversations ce coffre garde sans savoir les lire, par\n * organisation. La machine elle-même est rangée sous `null`.\n */\n async unreadableByVault(): Promise<Map<string | null, number>> {\n await this.load();\n const out = new Map<string | null, number>();\n for (const [root, items] of this.unreadable) {\n const vault = vaultIdOfRoot(root) ?? null;\n out.set(vault, (out.get(vault) ?? 0) + items.length);\n }\n return out;\n }\n\n /**\n * Write each vault that holds — or held — a conversation.\n *\n * A vault emptied by this save is still written, as an empty list: a\n * conversation that found its project must not survive in the file it was\n * read from.\n */\n private async saveInternal(): Promise<void> {\n if (!getEncryptionKey()) return;\n\n const byRoot = new Map<string, ConversationOnDisk[]>();\n for (const root of this.roots.values()) byRoot.set(root, []);\n\n for (const conv of this.conversations.values()) {\n const root = await this.rootFor(conv);\n this.roots.set(conv.id, root);\n const bucket = byRoot.get(root) ?? [];\n // Chiffré par la clé du coffre où la conversation atterrit : celle de son\n // organisation quand elle appartient à un projet synchronisé.\n const vault = vaultIdOfRoot(root);\n if (!this.isVaultNamed(root, vault)) continue;\n bucket.push(this.toDisk(conv, vault));\n byRoot.set(root, bucket);\n }\n\n // Ce qui ne s'était pas ouvert repart d'abord, inchangé : un coffre qui ne\n // contient plus que des illisibles doit être réécrit lui aussi, sans quoi\n // le vidage plus haut le laisserait à sa forme d'origine par chance et non\n // par décision.\n for (const [root, items] of this.unreadable) {\n byRoot.set(root, [...items, ...(byRoot.get(root) ?? [])]);\n }\n\n // Les coffres réparés sous nos pieds — une clé adoptée, une conversion\n // menée à la main — ne sont pas réécrits du tout. Réémettre notre copie\n // déferait la réparation ; l'omettre effacerait ce qu'elle protège. Ne pas\n // toucher au fichier est la seule issue qui ne perd rien.\n const stale = new Set<string>();\n for (const root of byRoot.keys()) {\n // Connu ET modifié : un coffre encore vierge n'a rien à protéger, et le\n // sauter reviendrait à ne jamais écrire son premier fichier.\n const path = join(root, FILENAME);\n if (wasRead(path) && await hasChangedSinceRead(path)) stale.add(root);\n }\n\n for (const [root, data] of byRoot) {\n const filePath = join(root, FILENAME);\n if (stale.has(root)) {\n console.warn(\n `[conversation-store] ${filePath} a changé depuis sa lecture —`\n + ' écriture ignorée pour ne pas écraser une réparation faite en dehors du serveur.',\n );\n continue;\n }\n await mkdir(root, { recursive: true });\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 // Notre écriture devient la référence, sinon la suivante la prendrait\n // pour une modification extérieure.\n await rememberFile(filePath);\n }\n }\n\n /**\n * The vault a conversation is written to: its project's.\n *\n * One that names no project stays where it was read, falling back to the\n * key's own directory — never lost for want of an owner.\n */\n private async rootFor(conv: Conversation): Promise<string> {\n const known = this.roots.get(conv.id) ?? null;\n // Le coffre de lecture tranche quand l'id du projet répond pour plusieurs\n // organisations : c'est le couple, écrit par l'arborescence.\n if (conv.projectId) return rootOfProjectAmong(conv.projectId, known);\n return known ?? dirname(await keyedFilePath(FILENAME));\n }\n\n /**\n * Le projet d'une conversation, organisation comprise.\n *\n * Ce que la conversation ne dit pas d'elle-même : elle ne nomme que l'id.\n * Le coffre d'où elle vient fournit l'organisation, et c'est ce couple qu'il\n * faut pour retrouver le répertoire de travail du projet.\n */\n async projectRefOf(conv: Conversation): Promise<{ id: string; orgId: string | null } | null> {\n if (!conv.projectId) return null;\n const known = this.roots.get(conv.id) ?? null;\n const ref = refOfProjectAmong(conv.projectId, known);\n return { id: ref.id, orgId: ref.orgId ?? null };\n }\n\n /**\n * Réécrire chaque coffre, en déplaçant ce qui appartient désormais ailleurs.\n *\n * Appelé quand un projet a changé de coffre : ses conversations sont écrites\n * dans le nouveau, et le fichier d'où elles viennent est réécrit sans elles.\n */\n async relocateAll(): Promise<void> {\n await this.load();\n await this.save();\n }\n\n private async save(): Promise<void> {\n const write = this.saveQueue.then(() => this.saveInternal());\n this.saveQueue = write.catch(() => {});\n return write;\n }\n\n async list(): Promise<Conversation[]> {\n await this.load();\n return Array.from(this.conversations.values())\n .sort((a, b) => b.updatedAt - a.updatedAt);\n }\n\n /**\n * Les conversations d'un projet.\n *\n * Celle qui ne nomme aucun projet — écrite avant le champ, ou qu'une\n * migration n'a pas su attribuer — n'est rendue que dans les projets de son\n * propre coffre : elle reste atteignable là où elle a été écrite, sans se\n * déverser dans toutes les organisations de la machine.\n */\n async listForProject(ref: { id: string; orgId?: string | null }): Promise<Conversation[]> {\n const belongs = await this.matcherForProject(ref);\n return (await this.list()).filter(belongs);\n }\n\n /**\n * Le test d'appartenance à un projet, préparé une fois.\n *\n * Le flux temps réel en a besoin autant que la liste : une conversation qui\n * arrive par événement doit passer le même filtre, sans quoi elle se\n * réinvite dans un projet qui ne l'a jamais demandée.\n */\n async matcherForProject(ref: { id: string; orgId?: string | null }): Promise<(conv: Conversation) => boolean> {\n await this.load();\n let projectRoot: string | null = null;\n try {\n projectRoot = ref.orgId === undefined\n ? rootOfProjectAmong(ref.id, null)\n : rootOfProjectRef({ id: ref.id, orgId: ref.orgId ?? null });\n } catch {\n // Id ambigu sans organisation : aucun coffre ne tranche, on ne cache rien.\n projectRoot = null;\n }\n return (conv: Conversation) => {\n if (conv.projectId) return conv.projectId === ref.id;\n if (!projectRoot) return true;\n return this.roots.get(conv.id) === projectRoot;\n };\n }\n\n async get(id: string): Promise<Conversation | null> {\n await this.load();\n return this.conversations.get(id) ?? null;\n }\n\n async create(title?: string, isCli = false, workflowId?: string, workflowType?: WorkflowType, runner?: 'claude-code' | 'codex', kanbanBoardId?: string, kanbanCardId?: string, providerId?: string, projectId?: string, orgId?: string | null): Promise<Conversation> {\n await this.load();\n const now = Date.now();\n const conv: Conversation = {\n id: randomUUID(),\n projectId,\n title: title ?? 'New conversation',\n messages: [],\n isCli,\n runner,\n providerId,\n workflowId,\n workflowType,\n kanbanBoardId,\n kanbanCardId,\n createdAt: now,\n updatedAt: now,\n };\n this.conversations.set(conv.id, conv);\n // `orgId` ne fait pas partie de la conversation : il dit dans quel coffre la\n // poser. Une conversation neuve n'a pas de provenance, et l'id du projet\n // seul peut répondre pour une organisation comme pour l'autre.\n if (projectId && orgId !== undefined) {\n this.roots.set(conv.id, vaultFor({ id: projectId, orgId }).root);\n }\n await this.save();\n this.events.emit('changed', { type: 'created', conversation: this.snapshotConversation(conv) } as ConversationChangeEvent);\n return conv;\n }\n\n async update(id: string, patch: { title?: string; messages?: Message[]; contextUsage?: ContextUsage; workflowId?: string; archived?: boolean; codexThreadId?: string }, options?: { silent?: boolean; touch?: boolean }): Promise<Conversation | null> {\n await this.load();\n const conv = this.conversations.get(id);\n if (!conv) return null;\n if (patch.title !== undefined) conv.title = patch.title;\n if (patch.messages !== undefined) conv.messages = patch.messages;\n if (patch.contextUsage !== undefined) conv.contextUsage = patch.contextUsage;\n if (patch.workflowId !== undefined) conv.workflowId = patch.workflowId;\n if (patch.archived !== undefined) conv.archived = patch.archived;\n if (patch.codexThreadId !== undefined) conv.codexThreadId = patch.codexThreadId;\n if (options?.touch !== false) conv.updatedAt = Date.now();\n await this.save();\n if (!options?.silent) {\n this.events.emit('changed', { type: 'updated', conversation: this.snapshotConversation(conv) } as ConversationChangeEvent);\n }\n return conv;\n }\n\n /**\n * Synchronously update the last assistant message content in memory, then schedule a save.\n * Used by activeSessionRegistry.persistNow() to avoid the async get() → .then() race.\n */\n updateLastAssistantContent(id: string, content: string, parts?: MessagePart[]): void {\n const conv = this.conversations.get(id);\n if (!conv) return;\n const lastMsg = conv.messages[conv.messages.length - 1];\n if (!lastMsg || lastMsg.role !== 'assistant') return;\n lastMsg.content = content;\n if (parts !== undefined) lastMsg.parts = parts;\n conv.updatedAt = Date.now();\n this.save().catch(() => {});\n }\n\n async listByKanbanBoardId(boardId: string): Promise<Conversation[]> {\n await this.load();\n return Array.from(this.conversations.values()).filter(c => c.kanbanBoardId === boardId);\n }\n\n async listByKanbanCardId(cardId: string): Promise<Conversation[]> {\n await this.load();\n return Array.from(this.conversations.values()).filter(c => c.kanbanCardId === cardId);\n }\n\n async delete(id: string): Promise<void> {\n await this.load();\n const existed = this.conversations.delete(id);\n await this.save();\n if (existed) {\n this.events.emit('changed', { type: 'deleted', id } as ConversationChangeEvent);\n }\n }\n\n onChanged(handler: (event: ConversationChangeEvent) => void): void {\n this.events.on('changed', handler);\n }\n\n offChanged(handler: (event: ConversationChangeEvent) => void): void {\n this.events.off('changed', handler);\n }\n}\n\nexport const conversationStore = new ConversationStore();\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, AGENT_STOP_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 { resolveServiceVariables, resolveEffectiveAgentId } 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(async () => {\n const agents = agentManager.listAgents();\n const results: Array<ProcessStatus & { agentId: string }> = [];\n\n await Promise.allSettled(\n agents\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) {\n results.push({ ...proc, agentId: a.config.id });\n }\n } catch {\n // Agent unreachable, skip\n }\n }),\n );\n\n return results;\n }),\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 const service = await serviceStore.get(input.processId);\n\n // Resolve effective agentId: service.agentId > environment.agentId > explicit input (fallback)\n // Service/environment config always wins so that changing the agent takes effect immediately.\n const effectiveAgentId = (service ? await resolveEffectiveAgentId(service) : null) ?? input.agentId ?? null;\n if (!effectiveAgentId) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'No agent assigned to this service. Set an agent on the service or on the active environment.' });\n }\n\n // Always deploy first (idempotent — creates process if missing, updates config if exists)\n if (service) {\n try {\n const resolved = await resolveServiceVariables(service);\n await agentManager.agentMutation(effectiveAgentId, 'process.deploy', resolved);\n } catch (err) {\n console.debug('[process-router] Failed to deploy before start for', input.processId + ':', (err as Error).message);\n }\n }\n\n if (service?.clearLogsOnStart) {\n try {\n await agentManager.agentMutation(effectiveAgentId, 'process.clearLogBuffer', { id: input.processId });\n agentManager.emit('process:log', { agentId: effectiveAgentId, batch: [{ processId: input.processId, __clearLogBuffer: true }] });\n } catch (err) {\n console.debug('[process-router] Failed to clear logs before start for', input.processId + ':', (err as Error).message);\n }\n }\n\n let result: ProcessStatus;\n try {\n result = await agentManager.agentMutation<ProcessStatus>(effectiveAgentId, 'process.start', { id: input.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\n ? `Cannot reach agent — make sure the agent is running`\n : (err_?.message ?? 'Failed to start process'),\n });\n }\n await auditService.log({ userId: 'local', action: 'start', entityType: 'process', entityId: input.processId, metadata: { agentId: effectiveAgentId } });\n return { ...result, agentId: effectiveAgentId };\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 const result = await agentManager.agentMutation<ProcessStatus>(input.agentId, 'process.stop', { id: input.processId }, AGENT_STOP_FETCH_TIMEOUT);\n await auditService.log({ userId: 'local', action: 'stop', entityType: 'process', entityId: input.processId, metadata: { agentId: input.agentId } });\n return { ...result, agentId: 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 const service = await serviceStore.get(input.processId);\n\n // Resolve effective agentId: service.agentId > environment.agentId > explicit input (fallback)\n // Service/environment config always wins so that changing the agent takes effect immediately.\n const effectiveAgentId = (service ? await resolveEffectiveAgentId(service) : null) ?? input.agentId ?? null;\n if (!effectiveAgentId) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'No agent assigned to this service. Set an agent on the service or on the active environment.' });\n }\n\n // 1. Stop the process (ignore \"not found\" — process may not exist on this agent yet)\n try {\n await agentManager.agentMutation<{ success: true }>(effectiveAgentId, 'process.stop', { id: input.processId }, AGENT_STOP_FETCH_TIMEOUT);\n } catch (err) {\n console.debug('[process-router] Stop before restart ignored (process not found on agent?):', (err as Error).message);\n }\n\n // 2. Re-deploy with latest config (idempotent — updates config now that process is stopped)\n if (service) {\n try {\n const resolved = await resolveServiceVariables(service);\n await agentManager.agentMutation(effectiveAgentId, 'process.deploy', resolved);\n } catch (err) {\n console.debug('[process-router] Failed to deploy before restart for', input.processId + ':', (err as Error).message);\n }\n }\n\n // 3. Clear logs if configured\n if (service?.clearLogsOnStart) {\n try {\n await agentManager.agentMutation(effectiveAgentId, 'process.clearLogBuffer', { id: input.processId });\n agentManager.emit('process:log', { agentId: effectiveAgentId, batch: [{ processId: input.processId, __clearLogBuffer: true }] });\n } catch (err) {\n console.debug('[process-router] Failed to clear logs before restart for', input.processId + ':', (err as Error).message);\n }\n }\n\n // 4. Start with updated config\n const result = await agentManager.agentMutation<ProcessStatus>(effectiveAgentId, 'process.start', { id: input.processId });\n await auditService.log({ userId: 'local', action: 'restart', entityType: 'process', entityId: input.processId, metadata: { agentId: effectiveAgentId } });\n return { ...result, agentId: effectiveAgentId };\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","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';\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 // 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 = cloudUrl !== currentCloud;\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 { readFile, writeFile, rename, mkdir, chmod, unlink } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { randomBytes, timingSafeEqual } from 'node:crypto';\nimport { keyedFilePath, legacyMachineFilePath } from './vault-resolver.js';\nimport { encryptValue, decryptValue } from './crypto-helpers.js';\n\nconst FILENAME = 'cloud-session.json';\n\n/** How long a pending login may sit between `start` and the browser callback. */\nconst STATE_TTL_MS = 5 * 60 * 1000;\n\ninterface StoredSession {\n cloudUrl: string;\n encryptedToken: string;\n}\n\n/**\n * Holds this machine's cloud session token.\n *\n * The token is obtained through the local-login flow: the browser authorizes on\n * the cloud origin (where its session cookie is same-site and works), receives a\n * single-use token, and hands it to this server, which exchanges it for a\n * session token. The token then lives here — never in the browser — and every\n * cloud call is proxied through this server with `Authorization: Bearer`.\n *\n * That is what lets the cloud refuse localhost origins entirely: no page served\n * on any local port can act on the cloud session, and an XSS in the web UI has\n * no token to steal.\n *\n * Encrypted at rest with the data-dir key, same mechanism as agents.json.\n */\nclass CloudSessionStore {\n private session: StoredSession | null = null;\n private loaded = false;\n /** Pending login states (CSRF binding between `start` and the callback). */\n private pending = new Map<string, { expiresAt: number; returnTo: string }>();\n\n /**\n * Encrypted, so it lives beside the key that opens it — usually the machine\n * root, but a launch directory owning its own key keeps both together.\n */\n private getFilePath(): Promise<string> {\n return keyedFilePath(FILENAME);\n }\n\n /** Where older versions kept it — read only, so an older Runeya keeps working. */\n private getLegacyFilePath(): string {\n return legacyMachineFilePath(FILENAME);\n }\n\n /**\n * Read the machine file, falling back to the launch directory of old.\n *\n * The legacy file is left in place: the next save writes the new location,\n * and a directory still opened by an older Runeya keeps working meanwhile.\n */\n private async readFromDisk(): Promise<string> {\n try {\n return await readFile(await this.getFilePath(), 'utf-8');\n } catch {\n return readFile(this.getLegacyFilePath(), 'utf-8');\n }\n }\n\n private async load(): Promise<void> {\n if (this.loaded) return;\n try {\n const raw = await this.readFromDisk();\n this.session = JSON.parse(raw) as StoredSession;\n } catch {\n // No file yet — not logged in.\n }\n this.loaded = true;\n }\n\n /**\n * Mint a state value binding a login attempt to this server. Returned to the\n * cloud page and echoed back on the callback, so a redirect we never\n * initiated cannot install a token.\n */\n createState(returnTo: string): string {\n this.sweepStates();\n const state = randomBytes(32).toString('hex');\n this.pending.set(state, { expiresAt: Date.now() + STATE_TTL_MS, returnTo });\n return state;\n }\n\n /**\n * Consume a state — single use, constant-time compare, TTL enforced. Returns\n * the URL to send the browser back to, or null when the state is unknown or\n * expired (i.e. a callback this server never initiated).\n */\n consumeState(candidate: string): string | null {\n this.sweepStates();\n for (const [state, entry] of this.pending) {\n const a = Buffer.from(state);\n const b = Buffer.from(candidate);\n if (a.length === b.length && timingSafeEqual(a, b)) {\n this.pending.delete(state);\n return entry.expiresAt > Date.now() ? entry.returnTo : null;\n }\n }\n return null;\n }\n\n private sweepStates(): void {\n const now = Date.now();\n for (const [state, entry] of this.pending) {\n if (entry.expiresAt <= now) this.pending.delete(state);\n }\n }\n\n private async save(): Promise<void> {\n await mkdir(dirname(await this.getFilePath()), { recursive: true });\n const filePath = await this.getFilePath();\n const tmpPath = filePath + '.tmp';\n await writeFile(tmpPath, JSON.stringify(this.session, null, 2), 'utf-8');\n await rename(tmpPath, filePath);\n await chmod(filePath, 0o600);\n }\n\n /** Store the session token obtained from the one-time-token exchange. */\n async set(cloudUrl: string, token: string): Promise<void> {\n await this.load();\n this.session = { cloudUrl, encryptedToken: encryptValue(token) };\n await this.save();\n }\n\n /** The decrypted session token, or null when not logged in. */\n async getToken(): Promise<string | null> {\n await this.load();\n if (!this.session) return null;\n try {\n return decryptValue(this.session.encryptedToken);\n } catch {\n // Key rotated or file tampered with — treat as logged out.\n return null;\n }\n }\n\n /**\n * The cloud this machine is signed into, or null when not linked.\n *\n * Needed to tell \"an org I am not a member of\" apart from \"an org of another\n * cloud instance entirely\" — the ids of two clouds share no namespace, so\n * comparing them without this would call every foreign-cloud project a\n * permission problem.\n */\n async getCloudUrl(): Promise<string | null> {\n await this.load();\n return this.session?.cloudUrl ?? null;\n }\n\n async isLinked(): Promise<boolean> {\n return (await this.getToken()) !== null;\n }\n\n /** Forget the session (sign-out). */\n async clear(): Promise<void> {\n await this.load();\n this.session = null;\n this.pending.clear();\n try {\n await unlink(await this.getFilePath());\n } catch {\n // Already gone.\n }\n }\n}\n\nexport const cloudSessionStore = new CloudSessionStore();\n","import { env } from '../config/env.js';\nimport { APP_VERSION_HEADER, appVersion } from '../config/app-version.js';\nimport { cloudSessionStore } from './cloud-session-store.js';\n\n/**\n * Where this installation's cloud lives, and how to call it.\n *\n * One cloud per installation: the URL comes from the environment, not from\n * anything stored per organization. It used to be carried alongside each sync\n * link, which made two records of one fact — and the stored one could outlive\n * the truth.\n *\n * Lives in a service rather than in the cloud-auth router because the sync\n * bridge needs it too, and a service must not import a router.\n */\n\nconst DEFAULT_CLOUD_API_URL = 'https://api.runeya.dev';\nconst DEFAULT_CLOUD_APP_URL = 'https://runeya.dev';\n\nexport function getCloudApiUrl(): string {\n return (env.CLOUD_URL ?? DEFAULT_CLOUD_API_URL).replace(/\\/+$/, '');\n}\n\nexport function getCloudAppUrl(): string {\n return (env.CLOUD_APP_URL ?? DEFAULT_CLOUD_APP_URL).replace(/\\/+$/, '');\n}\n\n/** No cloud session on this machine — a state of the machine, not a verdict on the caller. */\nexport class CloudNotLinkedError extends Error {\n readonly code = 'CLOUD_NOT_LINKED';\n constructor() {\n super('Not linked to the Runeya cloud.');\n this.name = 'CloudNotLinkedError';\n }\n}\n\n/**\n * Call the cloud with this machine's session, read fresh on every request so signing\n * back in resumes everything without a restart.\n */\nexport async function cloudFetch(\n path: string,\n init: { method?: string; body?: unknown; timeoutMs?: number } = {},\n): Promise<Response> {\n const token = await cloudSessionStore.getToken();\n if (!token) throw new CloudNotLinkedError();\n return fetch(`${getCloudApiUrl()}${path}`, {\n method: init.method ?? 'GET',\n headers: {\n Authorization: `Bearer ${token}`,\n // Le cloud refuse (426) les apps trop anciennes pour son schéma courant.\n [APP_VERSION_HEADER]: appVersion,\n ...(init.body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n },\n ...(init.body !== undefined ? { body: JSON.stringify(init.body) } : {}),\n // 15s suits a JSON call; attachment downloads pass a longer budget.\n signal: AbortSignal.timeout(init.timeoutMs ?? 15_000),\n });\n}\n","import { z } from 'zod';\nimport { TRPCError } from '@trpc/server';\nimport { protectedProcedure, router, requireEnvAction } 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 } 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 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 { resolve } from 'node:path';\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';\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 * 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 { ensureProjectsLoaded, refsOfProjectId } from './vault-registry.js';\n\n/**\n * À quelle organisation appartiennent les réglages qui s'appliquent ici.\n *\n * Les fournisseurs d'IA, les scénarios et les préférences de notification\n * décrivent le travail d'une organisation, pas le poste : il faut donc, à\n * chaque lecture, savoir de laquelle on parle. La réponse ne vient jamais d'un\n * « projet courant » global — il n'en existe pas, et un état partagé de ce\n * genre se désynchronise dès que deux requêtes se croisent — mais du projet que\n * l'action concerne, qui voyage déjà dans les paramètres de chaque appel.\n *\n * `undefined` désigne le poste : un projet local n'appartient à aucune\n * organisation, et ses réglages restent là où personne d'autre ne les lit.\n */\nexport async function vaultOfProject(projectId?: string | null): Promise<string | undefined> {\n if (!projectId) return undefined;\n await ensureProjectsLoaded();\n const refs = refsOfProjectId(projectId);\n // Le même id peut répondre pour un projet dans plusieurs organisations. Sans\n // quoi trancher, on ne choisit pas : mieux vaut lire les réglages du poste\n // que ceux d'une organisation prise au hasard.\n if (refs.length !== 1) return undefined;\n return refs[0]?.orgId ?? undefined;\n}\n","import type { Server } from 'node:http';\nimport { networkInterfaces } from 'node:os';\nimport { readFile, writeFile, rename, mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { z } from 'zod';\nimport { env } from '../config/env.js';\nimport { machineRoot } from './vault-resolver.js';\n\n/**\n * Exposer Runeya sur le réseau local, depuis l'interface.\n *\n * C'est ce que fait `--lan` au démarrage : écouter sur `0.0.0.0` au lieu de la\n * seule boucle locale, et desserrer CORS/CSRF pour les origines qui visent le\n * port du serveur. Le drapeau reste la voie du lancement ; ce module est la\n * même bascule, à chaud, mémorisée dans les réglages.\n *\n * Le réglage appartient à CETTE instance, pas au poste. Deux stacks ouvertes\n * côte à côte n'ont aucune raison d'être exposées ensemble — l'exposition\n * réseau est précisément ce qu'on ne veut pas voir s'étendre par héritage.\n *\n * Il est pourtant écrit dans la racine machine, et non dans le dossier de\n * données de l'instance : celui-ci peut très bien ne jamais exister (une Runeya\n * qui ne travaille que sur des projets cloud n'écrit rien dans son répertoire\n * de lancement, et ce n'est pas une bascule réseau qui doit l'y forcer). Le\n * fichier est donc un dictionnaire indexé par dossier de données — ce qui\n * distingue une instance d'une autre — et non un réglage unique pour le poste.\n *\n * Rien n'est recalculé ailleurs : `env.HOST` et `env.RUNEYA_LAN_PROXY` sont lus\n * à l'usage (CORS, CSRF, `{{service.HOST}}`), donc les modifier suffit — reste\n * à rouvrir la socket d'écoute, ce que `rebind` fait sans couper les\n * connexions en cours (l'onglet qui a demandé la bascule survit).\n */\n\nconst LOOPBACK = '127.0.0.1';\nconst ANY = '0.0.0.0';\n\nconst NETWORK_FILE = 'network.json';\nconst NetworkFileSchema = z.object({\n instances: z.record(z.string(), z.object({ lanEnabled: z.boolean().default(false) })).default({}),\n});\ntype NetworkFile = z.infer<typeof NetworkFileSchema>;\n\nlet httpServer: Server | null = null;\n\n/** L'instance, c'est son dossier de données — résolu en absolu dès le démarrage. */\nfunction instanceKey(): string {\n return env.DATA_DIR;\n}\n\nfunction networkFilePath(): string {\n return join(machineRoot(), NETWORK_FILE);\n}\n\nasync function readFileState(): Promise<NetworkFile> {\n try {\n return NetworkFileSchema.parse(JSON.parse(await readFile(networkFilePath(), 'utf-8')));\n } catch {\n return { instances: {} };\n }\n}\n\nasync function readPersisted(): Promise<boolean> {\n const state = await readFileState();\n return state.instances[instanceKey()]?.lanEnabled ?? false;\n}\n\n/**\n * Écriture atomique, en relisant d'abord : plusieurs Runeya partagent ce\n * fichier, et écraser l'entrée d'une voisine reviendrait à la remettre en\n * écoute locale à son prochain démarrage sans que personne ne l'ait demandé.\n */\nasync function writePersisted(lanEnabled: boolean): Promise<void> {\n const root = machineRoot();\n await mkdir(root, { recursive: true });\n const state = await readFileState();\n state.instances[instanceKey()] = { lanEnabled };\n const filePath = networkFilePath();\n const tmpPath = filePath + '.tmp';\n await writeFile(tmpPath, JSON.stringify(state, null, 2), 'utf-8');\n await rename(tmpPath, filePath);\n}\n\n/** Appelé une fois par `createLocalServer`, avant l'écoute. */\nexport function registerHttpServer(server: Server): void {\n httpServer = server;\n}\n\nexport interface NetworkInfo {\n /** Adresse sur laquelle le serveur écoute. */\n host: string;\n port: number;\n lanEnabled: boolean;\n /** URLs joignables depuis les autres machines, vides hors mode LAN. */\n lanUrls: string[];\n}\n\n/** Adresses IPv4 non locales de cette machine. */\nexport function lanIps(): string[] {\n const found: string[] = [];\n for (const nets of Object.values(networkInterfaces())) {\n for (const net of nets ?? []) {\n if (net.family === 'IPv4' && !net.internal) found.push(net.address);\n }\n }\n return found;\n}\n\nfunction currentPort(): number {\n const address = httpServer?.address();\n return typeof address === 'object' && address ? address.port : env.PORT;\n}\n\nexport function networkInfo(): NetworkInfo {\n const port = currentPort();\n return {\n host: env.HOST,\n port,\n lanEnabled: env.RUNEYA_LAN_PROXY,\n lanUrls: env.RUNEYA_LAN_PROXY ? lanIps().map((ip) => `http://${ip}:${port}`) : [],\n };\n}\n\n/** Un seul endroit met à jour l'hôte : `env` et `process.env` ne peuvent pas diverger. */\nfunction setHost(host: string, enabled: boolean): void {\n env.HOST = host;\n env.RUNEYA_HOST = host;\n env.RUNEYA_LAN_PROXY = enabled;\n process.env.RUNEYA_HOST = host;\n process.env.RUNEYA_LAN_PROXY = enabled ? 'true' : 'false';\n}\n\n/**\n * Rouvrir la socket d'écoute sur une autre adresse.\n *\n * `close()` ferme le descripteur d'écoute tout de suite et ne rappelle qu'une\n * fois les connexions terminées — on ne l'attend donc pas, sans quoi la requête\n * qui a demandé la bascule s'attendrait elle-même. En cas d'échec, on revient à\n * l'adresse précédente : un serveur qui n'écoute plus nulle part serait pire\n * que la bascule refusée.\n */\nasync function rebind(host: string, previousHost: string): Promise<void> {\n const server = httpServer;\n if (!server?.listening) return;\n const port = currentPort();\n\n const listenOn = (target: string) =>\n new Promise<void>((resolve, reject) => {\n const onError = (err: Error) => {\n server.removeListener('listening', onListening);\n reject(err);\n };\n const onListening = () => {\n server.removeListener('error', onError);\n resolve();\n };\n server.once('error', onError);\n server.once('listening', onListening);\n server.listen(port, target);\n });\n\n server.close(() => { /* les connexions en cours finissent d'elles-mêmes */ });\n\n try {\n await listenOn(host);\n } catch (err) {\n setHost(previousHost, previousHost === ANY);\n await listenOn(previousHost).catch(() => { /* plus rien à sauver ici */ });\n throw err;\n }\n}\n\n/**\n * Réglage mémorisé, appliqué au démarrage — avant que le serveur n'écoute.\n *\n * Ce qui a été demandé au lancement passe devant : `--lan` (ou `--host`) est un\n * choix explicite de cette session, le réglage n'est qu'un défaut.\n */\nexport async function applyPersistedLanMode(): Promise<void> {\n if (env.RUNEYA_LAN_PROXY) return;\n if (env.HOST !== LOOPBACK && env.HOST !== 'localhost') return;\n if (!(await readPersisted())) return;\n setHost(ANY, true);\n console.log('[server] LAN mode: activé par les réglages — écoute sur 0.0.0.0');\n}\n\n/** Bascule à chaud, mémorisée pour les démarrages suivants. */\nexport async function setLanMode(enabled: boolean): Promise<NetworkInfo> {\n await writePersisted(enabled);\n\n const previousHost = env.HOST;\n const host = enabled ? ANY : LOOPBACK;\n setHost(host, enabled);\n if (host !== previousHost) await rebind(host, previousHost);\n\n console.log(`[server] LAN mode: ${enabled ? 'activé' : 'désactivé'} — écoute sur ${host}`);\n return networkInfo();\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 { 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('which', [command], { timeout: 5_000 }, (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 const child = spawn(editor.command, [resolvedPath], {\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 const child = spawn(editor.command, [filePath], {\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 Anthropic from '@anthropic-ai/sdk';\nimport OpenAI from 'openai';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { fileURLToPath } from 'node:url';\nimport { buildApiDocs } from '../../services/ai-runners/runeya-api-docs.js';\nimport {\n claudeSessionExists,\n readClaudeTranscript,\n syncConversationFromClaudeTranscript,\n getLastTranscriptActivity,\n} from '../../services/claude-transcript-sync.js';\nimport { codexSessionExists } from '../../services/codex-sessions.js';\n\nimport { TRPCError } from '@trpc/server';\nimport { router, protectedProcedure } from '../trpc.js';\nimport type { AuthContext } from '../trpc.js';\nimport {\n ConversationIdSchema,\n Id128Schema,\n ShortString200Schema,\n} from '../shared-schemas.js';\nimport { projectStore } from '../../services/project-store.js';\nimport { serviceStore } from '../../services/service-store.js';\nimport { resolveWorkspaceCwd, resolveAgentCwd, resolveConversationCwd } from '../../services/workspace-cwd.js';\nimport { environmentResolver } from '../../services/environment-resolver.js';\nimport { generateLlmsTxt, generateAdminLlmsTxt } from '../../services/llms-txt-generator.js';\nimport { CHAT_TOOLS, CHAT_TOOLS_OPENAI, TOOL_SAFETY_INSTRUCTION, executeTool } from '../../services/chat-tools.js';\nimport { env } from '../../config/env.js';\nimport { resolveServiceVariables } from './service.js';\nimport { conversationStore } from '../../services/conversation-store.js';\nimport type { ConversationChangeEvent, MessagePart } from '../../services/conversation-store.js';\nimport type { ApiKey } from '@runeya/packages-shared';\nimport { getClaudeUsageEntries } from '../../services/claude-usage.js';\nimport { getCodexUsageEntries } from '../../services/codex-usage.js';\nimport { activeSessionRegistry } from '../../services/active-session-registry.js';\nimport type { ActiveSession, QueueItem } from '../../services/active-session-registry.js';\nimport { scenarioStore } from '../../services/scenario-store.js';\nimport { scenarioRunStore } from '../../services/scenario-run-store.js';\nimport {\n DEFAULT_MODELS,\n OPENAI_COMPAT_BASE_URLS,\n fetchProviderModels,\n getActiveProvider,\n} from '../../services/ai-provider-utils.js';\nimport { vaultOfProject } from '../../services/settings-scope.js';\nimport { resolveImagesToBase64 } from '../../services/message-images.js';\nimport { imageStorageService } from '../../services/image-storage.service.js';\nimport { buildKanbanCardPrompt, generateKanbanPopulatePrompt } from '../../services/kanban-commands.js';\nimport { kanbanStore } from '../../services/kanban-store.js';\nimport { ClaudeCodeRunner } from '../../services/ai-runners/claude-code-runner.js';\nimport { CodexRunner } from '../../services/ai-runners/codex-runner.js';\nimport { agentManager } from '../../services/agent-manager.js';\n\nconst execFileAsync = promisify(execFile);\n\nconst MessageSchema = z.object({\n role: z.enum(['user', 'assistant']),\n content: z.string().max(100_000),\n});\n\nconst ImagePartSchema = z.object({\n type: z.literal('image'),\n imageId: z.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i),\n url: z.string().max(500),\n mimeType: z.string().max(100),\n altText: z.string().max(500).optional(),\n});\nconst ImagePartsSchema = z.array(ImagePartSchema).max(5).optional();\n\nconst LANGUAGE_INSTRUCTION = 'Always respond in the same language the user writes in.';\n\n\nasync function buildSystemPrompt(apiKey: ApiKey | null): Promise<string> {\n const allServices = await serviceStore.list();\n const resolvedServices = await Promise.all(allServices.map(resolveServiceVariables));\n const context = apiKey\n ? generateLlmsTxt(apiKey, resolvedServices.filter(s => apiKey.scopes.services.some(p => p.serviceId === s.id)))\n : generateAdminLlmsTxt(resolvedServices);\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 const envSection = runeya_ai_vars ? `\\n\\n## Environment\\n\\n${runeya_ai_vars}` : '';\n return `${LANGUAGE_INSTRUCTION}\\n\\n${context}${envSection}`;\n}\n\n// ─── Event types yielded by the subscription ─────────────────────────────────\n\ntype ChatEvent =\n | { type: 'delta'; text: string }\n | { type: 'tool_call'; id: string; name: string; input: Record<string, unknown> }\n | { type: 'tool_result'; id: string; name: string; result: unknown; isError: boolean }\n | { type: 'done'; text: '' };\n\n// ─── Anthropic tool-use loop ──────────────────────────────────────────────────\n\nasync function* runAnthropic(\n client: Anthropic,\n model: string,\n system: string,\n initialMessages: Anthropic.MessageParam[],\n apiKey: ApiKey | null,\n authToken: string,\n signal?: AbortSignal,\n): AsyncGenerator<ChatEvent> {\n const messages: Anthropic.MessageParam[] = [...initialMessages];\n const MAX_TOOL_ROUNDS = 10;\n\n for (let round = 0; round < MAX_TOOL_ROUNDS; round++) {\n // Buffer tool_use blocks; stream text deltas live\n const toolUseBlocks: Anthropic.ToolUseBlock[] = [];\n // Accumulate partial JSON for each tool use block (keyed by block index)\n const partialJson = new Map<number, string>();\n let assistantText = '';\n\n if (signal?.aborted) return;\n const stream = client.messages.stream({\n model,\n max_tokens: 16384,\n system,\n tools: CHAT_TOOLS as Anthropic.Tool[],\n messages,\n }, { signal });\n\n for await (const event of stream) {\n if (event.type === 'content_block_start' && event.content_block.type === 'tool_use') {\n toolUseBlocks.push({ ...event.content_block, input: {} } as Anthropic.ToolUseBlock);\n } else if (event.type === 'content_block_delta') {\n if (event.delta.type === 'text_delta') {\n assistantText += event.delta.text;\n yield { type: 'delta', text: event.delta.text };\n } else if (event.delta.type === 'input_json_delta') {\n const idx = toolUseBlocks.length - 1;\n if (idx >= 0) {\n partialJson.set(idx, (partialJson.get(idx) ?? '') + event.delta.partial_json);\n }\n }\n } else if (event.type === 'content_block_stop') {\n const idx = toolUseBlocks.length - 1;\n const last = toolUseBlocks[idx];\n const partial = partialJson.get(idx);\n if (last && partial !== undefined) {\n try { last.input = JSON.parse(partial); } catch { last.input = {}; }\n partialJson.delete(idx);\n }\n }\n }\n\n const finalMsg = await stream.finalMessage();\n\n // No tool calls → done\n if (finalMsg.stop_reason !== 'tool_use' || toolUseBlocks.length === 0) {\n yield { type: 'done', text: '' };\n return;\n }\n\n // Build assistant message with all content blocks\n const assistantContent: Anthropic.MessageParam['content'] = [];\n if (assistantText) assistantContent.push({ type: 'text', text: assistantText } as Anthropic.TextBlockParam);\n assistantContent.push(...toolUseBlocks);\n messages.push({ role: 'assistant', content: assistantContent });\n\n // Execute each tool and collect results\n const toolResults: Anthropic.ToolResultBlockParam[] = [];\n for (const block of toolUseBlocks) {\n yield { type: 'tool_call', id: block.id, name: block.name, input: block.input as Record<string, unknown> };\n let result: unknown;\n let isError = false;\n try {\n result = await executeTool(block.name, block.input as Record<string, unknown>, apiKey, authToken);\n } catch (err) {\n result = (err as Error).message;\n isError = true;\n }\n yield { type: 'tool_result', id: block.id, name: block.name, result, isError };\n toolResults.push({\n type: 'tool_result',\n tool_use_id: block.id,\n content: typeof result === 'string' ? result : JSON.stringify(result, null, 2),\n is_error: isError,\n });\n }\n\n messages.push({ role: 'user', content: toolResults });\n // Loop: send tool results back to AI\n }\n yield { type: 'done', text: '' };\n}\n\n// ─── OpenAI tool-use loop ─────────────────────────────────────────────────────\n\nasync function* runOpenAI(\n client: OpenAI,\n model: string,\n initialMessages: OpenAI.Chat.ChatCompletionMessageParam[],\n apiKey: ApiKey | null,\n authToken: string,\n signal?: AbortSignal,\n): AsyncGenerator<ChatEvent> {\n const messages: OpenAI.Chat.ChatCompletionMessageParam[] = [...initialMessages];\n const MAX_TOOL_ROUNDS = 10;\n\n for (let round = 0; round < MAX_TOOL_ROUNDS; round++) {\n type ToolCallAcc = { id: string; name: string; args: string };\n const toolCallsAcc: Record<number, ToolCallAcc> = {};\n\n if (signal?.aborted) return;\n const stream = await client.chat.completions.create({\n model,\n messages,\n tools: CHAT_TOOLS_OPENAI,\n stream: true,\n max_tokens: 16384,\n temperature: 0,\n }, { signal });\n\n for await (const chunk of stream) {\n const choice = chunk.choices[0];\n if (!choice) continue;\n\n if (choice.delta?.content) {\n yield { type: 'delta', text: choice.delta.content };\n }\n\n // Accumulate tool call deltas\n for (const tc of choice.delta?.tool_calls ?? []) {\n const acc = toolCallsAcc[tc.index] ?? { id: '', name: '', args: '' };\n if (tc.id) acc.id = tc.id;\n if (tc.function?.name) acc.name = tc.function.name;\n if (tc.function?.arguments) acc.args += tc.function.arguments;\n toolCallsAcc[tc.index] = acc;\n }\n }\n\n // Some Ollama models return finish_reason 'stop' even when they made tool calls.\n // Fall back to checking if any tool calls were accumulated.\n if (Object.keys(toolCallsAcc).length === 0) {\n yield { type: 'done', text: '' };\n return;\n }\n\n // Build assistant message with tool calls\n const toolCallsList = Object.values(toolCallsAcc);\n messages.push({\n role: 'assistant',\n tool_calls: toolCallsList.map(tc => ({\n id: tc.id,\n type: 'function' as const,\n function: { name: tc.name, arguments: tc.args },\n })),\n });\n\n // Execute tools\n for (const tc of toolCallsList) {\n let input: Record<string, unknown> = {};\n try { input = JSON.parse(tc.args); } catch { /* empty */ }\n\n yield { type: 'tool_call', id: tc.id, name: tc.name, input };\n\n let result: unknown;\n let isError = false;\n try {\n result = await executeTool(tc.name, input, apiKey, authToken);\n } catch (err) {\n result = (err as Error).message;\n isError = true;\n }\n\n yield { type: 'tool_result', id: tc.id, name: tc.name, result, isError };\n messages.push({\n role: 'tool',\n tool_call_id: tc.id,\n content: typeof result === 'string' ? result : JSON.stringify(result, null, 2),\n });\n }\n // Loop\n }\n yield { type: 'done', text: '' };\n}\n\n// ─── Session drainer (shared by new-message and reconnect) ───────────────────\n\nasync function* drainSession(\n session: ActiveSession,\n signal: AbortSignal | undefined,\n isReconnect: boolean,\n): AsyncGenerator<\n | { type: 'delta'; text: string }\n | { type: 'status'; text: string }\n | { type: 'thinking'; text: string }\n | { type: 'context_usage'; inputTokens: number; contextWindow: number }\n | { type: 'tool_call'; id: string; name: string; input: Record<string, unknown> }\n | { type: 'tool_result'; id: string; name: string; result: unknown; isError: boolean }\n | { type: 'done'; text: '' }\n> {\n if(process.env.RUNEYA_DEBUG) console.log('[chat]: drainSession')\n // On reconnect, replay accumulated parts + current status\n if (isReconnect) {\n for (const part of session.parts) {\n if (part.type === 'thinking') {\n yield { type: 'thinking', text: part.text };\n } else if (part.type === 'text') {\n yield { type: 'delta', text: part.text };\n } else if (part.type === 'tool') {\n yield { type: 'tool_call', id: part.id, name: part.name, input: part.input ?? {} };\n if (!part.pending) yield { type: 'tool_result', id: part.id, name: part.name, result: part.result, isError: part.isError ?? false };\n }\n }\n if (session.lastStatus) {\n yield { type: 'status', text: session.lastStatus };\n }\n // If session already finished, yield done immediately\n if (session.status === 'done') {\n yield { type: 'done', text: '' };\n return;\n }\n }\n\n // Consumer cursor: skip buffered items, start receiving only NEW events\n // On reconnect we already replayed fullContent, so skip all existing buffer items\n let cursor = isReconnect ? session.totalProduced : (session.totalProduced - session.buffer.length);\n\n while (true) {\n // Drain any pending items\n while (cursor < session.totalProduced) {\n const idx = cursor - (session.totalProduced - session.buffer.length);\n const item: QueueItem | undefined = idx >= 0 ? session.buffer[idx] : undefined;\n cursor++;\n if (!item) continue;\n\n if (item.type === 'done') {\n yield { type: 'done', text: '' };\n return;\n }\n if (item.type === 'error') {\n yield { type: 'delta', text: `\\n\\n⚠️ ${item.message}` };\n continue;\n }\n if (item.type === 'status') {\n yield { type: 'status', text: item.text };\n continue;\n }\n if (item.type === 'thinking') {\n yield { type: 'thinking', text: item.text };\n continue;\n }\n if (item.type === 'context_usage') {\n yield { type: 'context_usage', inputTokens: item.inputTokens, contextWindow: item.contextWindow };\n continue;\n }\n if (item.type === 'tool_call') {\n yield { type: 'tool_call', id: item.id, name: item.name, input: item.input };\n continue;\n }\n if (item.type === 'tool_result') {\n yield { type: 'tool_result', id: item.id, name: item.name, result: item.result, isError: item.isError };\n continue;\n }\n yield item;\n }\n\n // If signal aborted, just stop yielding — process survives\n if (signal?.aborted) return;\n\n // Wait for next event from the registry, or signal abort\n await new Promise<void>(r => {\n if (cursor < session.totalProduced) { r(); return; }\n session.notify.add(r);\n const cleanup = () => { session.notify.delete(r); r(); };\n signal?.addEventListener('abort', cleanup, { once: true });\n });\n if (signal?.aborted) return;\n }\n}\n\n// ─── Shared CLI session starters (used by tRPC handlers + kanban queue) ──────\n\nasync function buildCliSystemContext(conv: Awaited<ReturnType<typeof conversationStore.get>>, jwt: string | undefined): Promise<string> {\n // Les services du projet de la conversation, pas ceux de la machine. Un CLI\n // lancé sur une carte du projet A recevait la description de tous les\n // services de tous les projets — à commencer par ceux de Runeya lui-même,\n // dont l'URL d'API — et travaillait donc avec le mauvais inventaire.\n const allServices = await serviceStore.list();\n const ref = conv ? await conversationStore.projectRefOf(conv) : null;\n const project = ref ? await projectStore.get(ref) : null;\n const ownServices = project\n ? allServices.filter((svc) => project.serviceIds.includes(svc.id))\n : allServices;\n const resolvedServices = await Promise.all(ownServices.map(resolveServiceVariables));\n let systemContext = generateAdminLlmsTxt(resolvedServices, jwt);\n\n if (conv?.kanbanBoardId) {\n const kanbanBoard = await kanbanStore.get(conv.kanbanBoardId);\n if (kanbanBoard) {\n systemContext += '\\n\\n' + (conv.kanbanCardId\n ? await buildKanbanCardPrompt(kanbanBoard, conv.kanbanCardId)\n : generateKanbanPopulatePrompt(kanbanBoard));\n }\n }\n return systemContext;\n}\n\n/**\n * Resolve the variables flagged `injectIntoAi` for the given active environment\n * (with inheritance) into a flat env dict. Returns undefined when nothing to inject.\n */\nasync function resolveInjectedEnv(environmentId?: string): Promise<Record<string, string> | undefined> {\n if (!environmentId) return undefined;\n try {\n const injected = await environmentResolver.resolveAiInjectedEnv(environmentId);\n return Object.keys(injected).length > 0 ? injected : undefined;\n } catch (err) {\n console.warn('[chat] resolveInjectedEnv failed:', (err as Error).message);\n return undefined;\n }\n}\n\nexport interface StartCliSessionOpts {\n model?: string;\n effort?: 'low' | 'medium' | 'high' | 'normal';\n jwt?: string;\n /** Extra metadata stored on the user message (for UI display) */\n userMessageParts?: MessagePart[];\n userMessageContextNote?: string;\n /** Active environment id: variables flagged `injectIntoAi` are injected into the process env. */\n environmentId?: string;\n}\n\n/**\n * Start a Claude Code session for a conversation.\n * Registers the session in activeSessionRegistry (so the frontend can subscribe),\n * builds the system context (services + kanban), and fires the runner.\n * Returns `{ session, done }` where `done` resolves when the runner finishes.\n * Throws if a session is already running for this conversation.\n */\nexport async function startClaudeCodeSession(\n convId: string,\n prompt: string,\n opts: StartCliSessionOpts = {},\n): Promise<{ session: ActiveSession; done: Promise<void> }> {\n const conv = await conversationStore.get(convId);\n if (!conv) throw new Error(`Conversation ${convId} not found`);\n\n const isResume = conv.messages.length > 0;\n conv.messages.push({\n role: 'user',\n content: prompt,\n parts: opts.userMessageParts,\n contextNote: opts.userMessageContextNote,\n });\n conv.messages.push({ role: 'assistant', content: '' });\n conversationStore.update(conv.id, { messages: conv.messages }, { silent: true }).catch(() => {});\n\n const systemContext = await buildCliSystemContext(conv, opts.jwt);\n\n const mcpServerPath = fileURLToPath(new URL('../mcp-server/index.js', import.meta.url));\n const mcpConfig = JSON.stringify({\n mcpServers: {\n runeya: {\n command: 'node',\n args: [mcpServerPath],\n env: { RUNEYA_BASE_URL: `http://localhost:${env.PORT}`, ...(opts.jwt ? { RUNEYA_API_TOKEN: opts.jwt } : {}) },\n },\n },\n });\n\n const ac = new AbortController();\n const session = activeSessionRegistry.registerProviderApiSession(convId, ac);\n let capturedFinalResult = '';\n\n const resolvedAgentId = agentManager.getDefaultAgentId();\n if (resolvedAgentId) {\n session.agentId = resolvedAgentId;\n }\n\n const injectedEnv = await resolveInjectedEnv(opts.environmentId);\n\n const done = new ClaudeCodeRunner().run({\n agentId: resolvedAgentId ?? undefined,\n // The conversation's project, not the server's launch directory.\n cwd: await conversationCwd(conv),\n sessionId: conv.id,\n prompt,\n isResume,\n systemContext,\n apiBaseUrl: `http://localhost:${env.PORT}`,\n apiToken: opts.jwt ?? '',\n model: opts.model ?? 'claude-opus-4-6',\n effort: opts.effort ?? 'normal',\n signal: ac.signal,\n skipTokenInstructions: true,\n mcpConfig,\n injectedEnv,\n onDelta: (text) => activeSessionRegistry.pushEvent(convId, { type: 'delta', text }),\n onStatus: (text) => activeSessionRegistry.pushEvent(convId, { type: 'status', text }),\n onThinking: (text) => activeSessionRegistry.pushEvent(convId, { type: 'thinking', text }),\n onToolCall: (id, name, input_) => activeSessionRegistry.pushEvent(convId, { type: 'tool_call', id, name, input: input_ }),\n onToolResult: (id, result, isError) => activeSessionRegistry.pushEvent(convId, { type: 'tool_result', id, name: '', result, isError }),\n onContextUsage: (inputTokens, contextWindow) => activeSessionRegistry.pushEvent(convId, { type: 'context_usage', inputTokens, contextWindow }),\n onResult: (result) => { if (result) capturedFinalResult = result; },\n }).then(() => {\n if (process.env.RUNEYA_DEBUG) console.log('[chat]: claude end...');\n if (activeSessionRegistry.get(convId) !== session) return;\n if (capturedFinalResult && capturedFinalResult.length > session.fullContent.length) {\n const missing = capturedFinalResult.slice(session.fullContent.length);\n activeSessionRegistry.pushEvent(convId, { type: 'delta', text: missing });\n }\n activeSessionRegistry.pushEvent(convId, { type: 'done', text: '' });\n activeSessionRegistry.markDone(convId);\n }).catch((err: Error) => {\n if (process.env.RUNEYA_DEBUG) console.error('[chat]: error...', err?.message, err);\n if (activeSessionRegistry.get(convId) !== session) return;\n activeSessionRegistry.pushEvent(convId, { type: 'error', message: `Claude Code error: ${err.message}` });\n activeSessionRegistry.pushEvent(convId, { type: 'done', text: '' });\n activeSessionRegistry.markDone(convId);\n });\n\n return { session, done };\n}\n\nexport interface StartCodexSessionOpts {\n model?: string;\n jwt?: string;\n images?: { imageId: string; base64: string; mimeType: string; altText?: string }[];\n userMessageParts?: MessagePart[];\n userMessageContextNote?: string;\n /** Active environment id: variables flagged `injectIntoAi` are injected into the process env. */\n environmentId?: string;\n}\n\n/**\n * Start a Codex session for a conversation.\n * Same contract as startClaudeCodeSession.\n */\nexport async function startCodexSession(\n convId: string,\n prompt: string,\n opts: StartCodexSessionOpts = {},\n): Promise<{ session: ActiveSession; done: Promise<void> }> {\n const conv = await conversationStore.get(convId);\n if (!conv) throw new Error(`Conversation ${convId} not found`);\n\n const isResume = !!conv.codexThreadId;\n conv.messages.push({\n role: 'user',\n content: prompt,\n parts: opts.userMessageParts,\n contextNote: opts.userMessageContextNote,\n });\n conv.messages.push({ role: 'assistant', content: '' });\n conversationStore.update(conv.id, { messages: conv.messages }, { silent: true }).catch(() => {});\n\n const systemContext = await buildCliSystemContext(conv, opts.jwt);\n\n const ac = new AbortController();\n const session = activeSessionRegistry.registerProviderApiSession(convId, ac);\n\n const resolvedAgentId = agentManager.getDefaultAgentId();\n if (resolvedAgentId) {\n session.agentId = resolvedAgentId;\n }\n\n const injectedEnv = await resolveInjectedEnv(opts.environmentId);\n\n const done = new CodexRunner().run({\n agentId: resolvedAgentId ?? undefined,\n cwd: await conversationCwd(conv),\n sessionId: conv.codexThreadId ?? '',\n prompt,\n isResume,\n systemContext,\n apiBaseUrl: `http://localhost:${env.PORT}`,\n apiToken: opts.jwt ?? '',\n model: opts.model ?? '',\n effort: 'normal',\n signal: ac.signal,\n skipTokenInstructions: true,\n images: opts.images,\n injectedEnv,\n onThreadId: (threadId) => conversationStore.update(conv.id, { codexThreadId: threadId }).catch(() => {}),\n onDelta: (text) => activeSessionRegistry.pushEvent(convId, { type: 'delta', text }),\n onStatus: (text) => activeSessionRegistry.pushEvent(convId, { type: 'status', text }),\n onThinking: (text) => activeSessionRegistry.pushEvent(convId, { type: 'thinking', text }),\n onToolCall: (id, name, input_) => activeSessionRegistry.pushEvent(convId, { type: 'tool_call', id, name, input: input_ }),\n onToolResult: (id, result, isError) => activeSessionRegistry.pushEvent(convId, { type: 'tool_result', id, name: '', result, isError }),\n }).then(() => {\n if (activeSessionRegistry.get(convId) !== session) return;\n activeSessionRegistry.pushEvent(convId, { type: 'done', text: '' });\n activeSessionRegistry.markDone(convId);\n }).catch((err: Error) => {\n if (activeSessionRegistry.get(convId) !== session) return;\n activeSessionRegistry.pushEvent(convId, { type: 'error', message: `Codex error: ${err.message}` });\n activeSessionRegistry.pushEvent(convId, { type: 'done', text: '' });\n activeSessionRegistry.markDone(convId);\n });\n\n return { session, done };\n}\n\n// ─── Router ───────────────────────────────────────────────────────────────────\n\nconst MessagePartSchema = z.discriminatedUnion('type', [\n z.object({ type: z.literal('thinking'), text: z.string().max(100_000) }),\n z.object({ type: z.literal('text'), text: z.string().max(100_000) }),\n z.object({\n type: z.literal('tool'),\n id: Id128Schema,\n name: Id128Schema,\n input: z.record(z.string(), z.unknown()).optional(),\n rawInput: z.string().max(10_000).optional(),\n result: z.unknown().optional(),\n isError: z.boolean().optional(),\n pending: z.boolean(),\n }),\n]);\n\nconst StoredMessageSchema = z.object({\n role: z.enum(['user', 'assistant']),\n content: z.string().max(100_000),\n parts: z.array(MessagePartSchema).max(200).optional(),\n});\n\n/**\n * Le répertoire de travail d'une conversation.\n *\n * Une conversation ne nomme que l'id de son projet, et cet id peut désigner un\n * projet dans chaque organisation ; le store retrouve le couple à partir du\n * coffre d'où la conversation a été lue, et c'est ce couple qui place le\n * répertoire.\n */\nasync function conversationCwd(conv: { id: string; projectId?: string | null }): Promise<string | undefined> {\n return resolveConversationCwd(conv.id);\n}\n\nexport const chatRouter = router({\n conversations: router({\n /**\n * Le flux des conversations du projet ouvert.\n *\n * Filtré comme `list` : l'instantané initial remplace la liste du client,\n * et sans le même filtre il y reversait toutes les conversations de la\n * machine, une seconde après un chargement pourtant filtré.\n */\n onChanged: protectedProcedure\n .input(z.object({\n projectId: Id128Schema.optional(),\n orgId: Id128Schema.nullable().optional(),\n }).optional())\n .subscription(async function* ({ input }) {\n const belongs = input?.projectId\n ? await conversationStore.matcherForProject({ id: input.projectId, orgId: input.orgId })\n : () => true;\n const initial = (await conversationStore.list()).filter(belongs);\n yield { type: 'initial' as const, conversations: initial };\n\n const queue: ConversationChangeEvent[] = [];\n let resolve: (() => void) | null = null;\n\n const handler = (event: ConversationChangeEvent) => {\n // Une suppression passe toujours : son id ne dit pas le projet, et\n // retirer un id inconnu du client ne coûte rien. Un rechargement\n // aussi : il ne porte aucune conversation à filtrer.\n if (event.type !== 'deleted' && event.type !== 'reloaded' && !belongs(event.conversation)) return;\n if (queue.length >= 500) queue.shift();\n queue.push(event);\n if (resolve) {\n resolve();\n resolve = null;\n }\n };\n\n conversationStore.onChanged(handler);\n\n try {\n while (true) {\n if (queue.length > 0) {\n const event = queue.shift()!;\n // Le store a tout relu : ce que le client détient est périmé dans\n // son ensemble, donc on lui renvoie l'instantané plutôt qu'un\n // delta qui ne dirait pas ce qui a disparu.\n if (event.type === 'reloaded') {\n yield { type: 'initial' as const, conversations: (await conversationStore.list()).filter(belongs) };\n continue;\n }\n yield event;\n } else {\n await new Promise<void>((r) => { resolve = r; });\n }\n }\n } finally {\n conversationStore.offChanged(handler);\n }\n }),\n\n /**\n * Conversations of one project.\n *\n * A conversation belongs to the project it was opened from, so the caller\n * says which one it is looking at. Ones that name no project — written\n * before the field existed, or that a migration could not attribute — are\n * returned only for the projects of the vault they were read from: still\n * reachable where they were written, without leaking into every other\n * organization's projects.\n */\n list: protectedProcedure\n .input(z.object({\n projectId: Id128Schema.optional(),\n orgId: Id128Schema.nullable().optional(),\n }).optional())\n .query(async ({ input }) => {\n const projectId = input?.projectId;\n if (!projectId) return conversationStore.list();\n return conversationStore.listForProject({ id: projectId, orgId: input?.orgId });\n }),\n\n get: protectedProcedure\n .input(z.object({ id: Id128Schema }))\n .query(async ({ input }) => {\n const conv = await conversationStore.get(input.id);\n if (!conv) throw new TRPCError({ code: 'NOT_FOUND', message: 'Conversation not found' });\n return conv;\n }),\n\n create: protectedProcedure\n .input(z.object({\n title: ShortString200Schema.optional(),\n isCli: z.boolean().optional(),\n runner: z.enum(['claude-code', 'codex']).optional(),\n providerId: Id128Schema.optional(),\n scenarioId: Id128Schema.optional(),\n scenarioInput: z.string().max(100_000).optional(),\n kanbanBoardId: Id128Schema.optional(),\n kanbanCardId: Id128Schema.optional(),\n // The project the conversation is about: only the caller knows which\n // one it is looking at.\n projectId: Id128Schema.optional(),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .mutation(async ({ input }) => {\n let scenario = null;\n if (input.scenarioId) {\n scenario = await scenarioStore.get(\n input.scenarioId,\n input.orgId ?? await vaultOfProject(input.projectId),\n );\n if (!scenario) throw new TRPCError({ code: 'NOT_FOUND', message: 'Scenario not found' });\n }\n\n const conv = await conversationStore.create(\n input.title,\n input.isCli ?? false,\n input.scenarioId,\n input.scenarioId ? 'scenario' : undefined,\n input.runner,\n input.kanbanBoardId,\n input.kanbanCardId,\n input.providerId,\n input.projectId,\n input.orgId,\n );\n\n if (scenario) {\n await scenarioRunStore.initializeConversationWorkspace(\n conv.id,\n scenario,\n input.scenarioInput ?? '',\n );\n }\n\n return conv;\n }),\n\n update: protectedProcedure\n .input(z.object({\n id: Id128Schema,\n title: ShortString200Schema.optional(),\n messages: z.array(StoredMessageSchema).max(500).optional(),\n contextUsage: z.object({\n inputTokens: z.number().int().nonnegative(),\n contextWindow: z.number().int().positive(),\n }).optional(),\n }))\n .mutation(async ({ input }) => {\n const conv = await conversationStore.update(input.id, { title: input.title, messages: input.messages, contextUsage: input.contextUsage });\n if (!conv) throw new TRPCError({ code: 'NOT_FOUND', message: 'Conversation not found' });\n return conv;\n }),\n\n delete: protectedProcedure\n .input(z.object({ id: Id128Schema }))\n .mutation(async ({ input }) => {\n const existing = await conversationStore.get(input.id);\n if (!existing) throw new TRPCError({ code: 'NOT_FOUND', message: 'Conversation not found' });\n\n // Kill any interactive PTY still running for this conversation before we\n // drop it. PTY sessions are spawned with sessionId === conversation id and\n // never exit on their own, so without this they'd leak a concurrency slot.\n // Fire-and-forget across every connected agent (we don't track which one\n // hosts the session on the conversation record).\n for (const agent of agentManager.listAgents()) {\n const agentId = agent.config.id;\n agentManager\n .agentQuery<{ spawnId: string; status: string } | null>(\n agentId,\n 'ai.findPtyBySession',\n { sessionId: input.id },\n )\n .then((pty) => {\n if (pty?.status === 'running') {\n return agentManager.agentMutation(agentId, 'ai.kill', { spawnId: pty.spawnId });\n }\n })\n .catch(() => { /* agent unreachable or no session — best-effort */ });\n }\n\n await conversationStore.delete(input.id);\n await scenarioRunStore.deleteRunDir(input.id);\n // Fire-and-forget: delete the whole conversation images directory\n imageStorageService.deleteByContextId(input.id).catch((err) =>\n console.error('[chat.delete] Image cleanup error:', err),\n );\n }),\n\n archive: protectedProcedure\n .input(z.object({ id: Id128Schema, archived: z.boolean() }))\n .mutation(async ({ input }) => {\n const conv = await conversationStore.update(input.id, { archived: input.archived });\n if (!conv) throw new TRPCError({ code: 'NOT_FOUND', message: 'Conversation not found' });\n return conv;\n }),\n }),\n\n listModels: protectedProcedure\n .input(z.object({\n providerId: Id128Schema.optional(),\n // Le projet dit de quelle organisation lire les fournisseurs ; absent,\n // ce sont ceux du poste.\n projectId: Id128Schema.optional(),\n orgId: z.string().max(128).nullable().optional(),\n }).optional())\n .query(async ({ input }) => {\n const active = await getActiveProvider(\n input?.providerId,\n input?.orgId ?? await vaultOfProject(input?.projectId),\n );\n if (!active) return [];\n try {\n return await fetchProviderModels(active.provider, active.plaintextKey);\n } catch {\n return [];\n }\n }),\n\n checkCliAvailability: protectedProcedure\n .input(z.object({ agentId: Id128Schema.optional() }).optional())\n .query(async ({ input }) => {\n if (input?.agentId) {\n try {\n const res = await agentManager.agentQuery<{ claudeAvailable: boolean; codexAvailable: boolean }>(\n input.agentId,\n 'health.checkCli',\n );\n return { available: res.claudeAvailable, codexAvailable: res.codexAvailable };\n } catch {\n return { available: false, codexAvailable: false };\n }\n }\n const [claudeOk, codexOk] = await Promise.all([\n execFileAsync('claude', ['--version'], { timeout: 5000, shell: false }).then(() => true).catch(() => false),\n execFileAsync('codex', ['--version'], { timeout: 5000, shell: false }).then(() => true).catch(() => false),\n ]);\n return { available: claudeOk, codexAvailable: codexOk };\n }),\n\n enhanceScenarioPrompt: protectedProcedure\n .input(z.object({\n text: z.string().max(10_000),\n providerId: Id128Schema.optional(),\n model: z.string().max(200).optional(),\n projectId: Id128Schema.optional(),\n orgId: z.string().max(128).nullable().optional(),\n }))\n .mutation(async ({ input }) => {\n const active = await getActiveProvider(\n input.providerId,\n input.orgId ?? await vaultOfProject(input.projectId),\n );\n if (!active) throw new TRPCError({ code: 'BAD_REQUEST', message: 'No AI provider configured' });\n\n const systemPrompt = `You are an expert at writing clear, concise user request briefs for AI-powered workflows.\nWhen given a rough user request, rewrite it to be:\n- Clear and well-structured\n- Specific about the expected outcome\n- Written in the same language as the input\n- Concise but complete (no fluff)\nReturn ONLY the improved text, no explanation, no preamble.`;\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: 2048,\n system: systemPrompt,\n messages: [{ role: 'user', content: input.text }],\n });\n const block = res.content[0];\n return { enhanced: block?.type === 'text' ? block.text : input.text };\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: input.text },\n ],\n });\n return { enhanced: res.choices[0]?.message?.content ?? input.text };\n }\n\n return { enhanced: input.text };\n }),\n\n listClaudeCodeModels: protectedProcedure\n .query(() => ['opus', 'sonnet', 'haiku']),\n\n getClaudeUsage: protectedProcedure\n .query(async () => {\n try {\n return await getClaudeUsageEntries();\n } catch {\n return null;\n }\n }),\n\n getCodexUsage: protectedProcedure\n .query(async () => {\n try {\n return await getCodexUsageEntries();\n } catch {\n return null;\n }\n }),\n\n getStreamingStatus: protectedProcedure\n .query(() => activeSessionRegistry.listActive()),\n\n stopSession: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .mutation(({ input }) => {\n if(process.env.RUNEYA_DEBUG) console.log('[chat]: stopSession')\n const killed = activeSessionRegistry.kill(input.conversationId);\n if (!killed) throw new TRPCError({ code: 'NOT_FOUND', message: 'No active session for this conversation' });\n return { ok: true };\n }),\n\n streamViaClaudeCode: protectedProcedure\n .input(z.object({\n conversationId: ConversationIdSchema,\n prompt: z.string().max(100_000),\n contextNote: z.string().max(200_000).optional(),\n model: ShortString200Schema.optional(),\n effort: z.enum(['low', 'medium', 'high']).optional(),\n reconnect: z.boolean().optional(),\n agentId: Id128Schema.optional(),\n environmentId: z.string().max(128).optional(),\n imageIds: z.array(z.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)).max(5).optional(),\n imageParts: ImagePartsSchema,\n }))\n .subscription(async function* ({ input, ctx, signal }) {\n // ── Reconnect path: attach to an existing session ───────────────────\n if(process.env.RUNEYA_DEBUG) console.log('[chat]: Reconnect')\n const existingSession = activeSessionRegistry.get(input.conversationId);\n if (input.reconnect && existingSession) {\n yield* drainSession(existingSession, signal, true);\n return;\n }\n\n // ── New message path ────────────────────────────────────────────────\n if (!input.prompt) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Prompt is required for new messages' });\n\n const conv = await conversationStore.get(input.conversationId);\n if (!conv) throw new TRPCError({ code: 'NOT_FOUND', message: 'Conversation not found' });\n\n console.log(`[kanban-debug] streamViaClaudeCode start — convId=${conv.id} kanbanBoardId=${conv.kanbanBoardId ?? 'null'}`);\n\n const isResume = conv.messages.length > 0;\n\n const userParts = input.imageParts && input.imageParts.length > 0\n ? [...(input.prompt.trim() ? [{ type: 'text' as const, text: input.prompt }] : []), ...input.imageParts]\n : undefined;\n conv.messages.push({ role: 'user', content: input.prompt, parts: userParts, contextNote: input.contextNote });\n conv.messages.push({ role: 'assistant', content: '' });\n if(process.env.RUNEYA_DEBUG) console.log('[chat]: update')\n conversationStore.update(conv.id, { messages: conv.messages }, { silent: true }).catch(() => { });\n\n const cliPrompt = input.contextNote ? `${input.contextNote}\\n\\n${input.prompt}` : input.prompt;\n\n const allServices = await serviceStore.list();\n const resolvedServices = await Promise.all(allServices.map(resolveServiceVariables));\n const jwt = ctx.authorization?.startsWith('Bearer ') ? ctx.authorization.slice(7) : undefined;\n let systemContext = generateAdminLlmsTxt(resolvedServices, jwt);\n\n if (conv.kanbanBoardId) {\n const kanbanBoard = await kanbanStore.get(conv.kanbanBoardId);\n if (kanbanBoard) {\n systemContext += '\\n\\n' + (conv.kanbanCardId\n ? await buildKanbanCardPrompt(kanbanBoard, conv.kanbanCardId)\n : generateKanbanPopulatePrompt(kanbanBoard));\n }\n }\n\n const mcpServerPath = fileURLToPath(new URL('../mcp-server/index.js', import.meta.url));\n const mcpConfig = JSON.stringify({\n mcpServers: {\n runeya: {\n command: 'node',\n args: [mcpServerPath],\n env: { RUNEYA_BASE_URL: `http://localhost:${env.PORT}`, ...(jwt ? { RUNEYA_API_TOKEN: jwt } : {}) },\n },\n },\n });\n\n // Claude Code has filesystem access — pass image paths directly in the prompt\n const imagePaths: string[] = [];\n if (input.imageIds && input.imageIds.length > 0) {\n for (const id of input.imageIds) {\n // Scopé à la conversation : sinon un imageId d'une autre conversation\n // se glisse dans le prompt et fuit par ce chemin.\n const result = await imageStorageService.getImagePath(id, input.conversationId);\n if (result) imagePaths.push(result.filePath);\n }\n }\n const promptWithImages = imagePaths.length > 0\n ? `${cliPrompt}\\n\\n${imagePaths.map(p => `Image: ${p}`).join('\\n')}`\n : cliPrompt;\n\n const convId = input.conversationId;\n const ac = new AbortController();\n let session: ActiveSession;\n try {\n session = activeSessionRegistry.registerProviderApiSession(convId, ac);\n } catch {\n throw new TRPCError({ code: 'CONFLICT', message: 'A session is already running for this conversation. Stop it first.' });\n }\n let capturedFinalResult = '';\n\n const resolvedAgentId = input.agentId ?? agentManager.getDefaultAgentId();\n if (resolvedAgentId) {\n session.agentId = resolvedAgentId;\n }\n\n if(process.env.RUNEYA_DEBUG) console.log('[chat]: claude run...')\n const injectedEnv = await resolveInjectedEnv(input.environmentId);\n new ClaudeCodeRunner().run({\n agentId: resolvedAgentId ?? undefined,\n cwd: await conversationCwd(conv),\n sessionId: conv.id,\n prompt: promptWithImages,\n isResume,\n systemContext,\n apiBaseUrl: `http://localhost:${env.PORT}`,\n apiToken: jwt ?? '',\n model: input.model ?? 'claude-opus-4-6',\n effort: input.effort ?? 'normal',\n signal: ac.signal,\n skipTokenInstructions: true,\n mcpConfig,\n injectedEnv,\n onDelta: (text) => {\n activeSessionRegistry.pushEvent(convId, { type: 'delta', text });\n },\n onStatus: (text) => activeSessionRegistry.pushEvent(convId, { type: 'status', text }),\n onThinking: (text) => activeSessionRegistry.pushEvent(convId, { type: 'thinking', text }),\n onToolCall: (id, name, input_) => activeSessionRegistry.pushEvent(convId, { type: 'tool_call', id, name, input: input_ }),\n onToolResult: (id, result, isError) => activeSessionRegistry.pushEvent(convId, { type: 'tool_result', id, name: '', result, isError }),\n onContextUsage: (inputTokens: number, contextWindow: number) => activeSessionRegistry.pushEvent(convId, { type: 'context_usage', inputTokens, contextWindow }),\n onResult: (result: string) => { if (result) capturedFinalResult = result; },\n }).then(() => {\n if (activeSessionRegistry.get(convId) !== session) return;\n\n // Reconcile: push any content captured in the result event but missed by text_delta\n if (capturedFinalResult && capturedFinalResult.length > session.fullContent.length) {\n const missing = capturedFinalResult.slice(session.fullContent.length);\n activeSessionRegistry.pushEvent(convId, { type: 'delta', text: missing });\n }\n\n activeSessionRegistry.pushEvent(convId, { type: 'done', text: '' });\n activeSessionRegistry.markDone(convId);\n }).catch((err: Error) => {\n if (activeSessionRegistry.get(convId) !== session) return;\n activeSessionRegistry.pushEvent(convId, { type: 'error', message: `Claude Code error: ${err.message}` });\n activeSessionRegistry.pushEvent(convId, { type: 'done', text: '' });\n activeSessionRegistry.markDone(convId);\n });\n\n if(process.env.RUNEYA_DEBUG) console.log('[chat]: drainSession...')\n yield* drainSession(session, signal, false);\n }),\n\n streamViaCodex: protectedProcedure\n .input(z.object({\n conversationId: ConversationIdSchema,\n prompt: z.string().max(100_000),\n contextNote: z.string().max(200_000).optional(),\n model: ShortString200Schema.optional(),\n reconnect: z.boolean().optional(),\n agentId: Id128Schema.optional(),\n environmentId: z.string().max(128).optional(),\n imageIds: z.array(z.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)).max(5).optional(),\n imageParts: ImagePartsSchema,\n }))\n .subscription(async function* ({ input, ctx, signal }) {\n // ── Reconnect path ───────────────────────────────────────────────────\n const existingSession = activeSessionRegistry.get(input.conversationId);\n if (input.reconnect && existingSession) {\n yield* drainSession(existingSession, signal, true);\n return;\n }\n\n if (!input.prompt) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Prompt is required' });\n\n const conv = await conversationStore.get(input.conversationId);\n if (!conv) throw new TRPCError({ code: 'NOT_FOUND', message: 'Conversation not found' });\n\n const isResume = !!conv.codexThreadId;\n\n const codexUserParts = input.imageParts && input.imageParts.length > 0\n ? [...(input.prompt.trim() ? [{ type: 'text' as const, text: input.prompt }] : []), ...input.imageParts]\n : undefined;\n conv.messages.push({ role: 'user', content: input.prompt, parts: codexUserParts, contextNote: input.contextNote });\n conv.messages.push({ role: 'assistant', content: '' });\n conversationStore.update(conv.id, { messages: conv.messages }, { silent: true }).catch(() => {});\n\n const cliPrompt = input.contextNote ? `${input.contextNote}\\n\\n${input.prompt}` : input.prompt;\n\n const allServices = await serviceStore.list();\n const resolvedServices = await Promise.all(allServices.map(resolveServiceVariables));\n const jwt = ctx.authorization?.startsWith('Bearer ') ? ctx.authorization.slice(7) : undefined;\n let systemContext = generateAdminLlmsTxt(resolvedServices, jwt);\n\n if (conv.kanbanBoardId) {\n const kanbanBoard = await kanbanStore.get(conv.kanbanBoardId);\n if (kanbanBoard) {\n systemContext += '\\n\\n' + (conv.kanbanCardId\n ? await buildKanbanCardPrompt(kanbanBoard, conv.kanbanCardId)\n : generateKanbanPopulatePrompt(kanbanBoard));\n }\n }\n\n const resolvedImages = input.imageIds && input.imageIds.length > 0\n ? await resolveImagesToBase64(input.imageIds.map(id => ({ imageId: id, mimeType: '' })), input.conversationId)\n : [];\n\n const convId = input.conversationId;\n const ac = new AbortController();\n let session: ActiveSession;\n try {\n session = activeSessionRegistry.registerProviderApiSession(convId, ac);\n } catch {\n throw new TRPCError({ code: 'CONFLICT', message: 'A session is already running for this conversation. Stop it first.' });\n }\n\n const resolvedAgentId = input.agentId ?? agentManager.getDefaultAgentId();\n if (resolvedAgentId) {\n session.agentId = resolvedAgentId;\n }\n\n const injectedEnv = await resolveInjectedEnv(input.environmentId);\n new CodexRunner().run({\n agentId: resolvedAgentId ?? undefined,\n cwd: await conversationCwd(conv),\n sessionId: conv.codexThreadId ?? '',\n prompt: cliPrompt,\n isResume,\n systemContext,\n apiBaseUrl: `http://localhost:${env.PORT}`,\n apiToken: jwt ?? '',\n model: input.model ?? '',\n effort: 'normal',\n signal: ac.signal,\n skipTokenInstructions: true,\n images: resolvedImages,\n injectedEnv,\n onThreadId: (threadId) => conversationStore.update(conv.id, { codexThreadId: threadId }).catch(() => {}),\n onDelta: (text) => activeSessionRegistry.pushEvent(convId, { type: 'delta', text }),\n onStatus: (text) => activeSessionRegistry.pushEvent(convId, { type: 'status', text }),\n onThinking: (text) => activeSessionRegistry.pushEvent(convId, { type: 'thinking', text }),\n onToolCall: (id, name, input_) => activeSessionRegistry.pushEvent(convId, { type: 'tool_call', id, name, input: input_ }),\n onToolResult: (id, result, isError) => activeSessionRegistry.pushEvent(convId, { type: 'tool_result', id, name: '', result, isError }),\n }).then(() => {\n if (activeSessionRegistry.get(convId) !== session) return;\n activeSessionRegistry.pushEvent(convId, { type: 'done', text: '' });\n activeSessionRegistry.markDone(convId);\n }).catch((err: Error) => {\n if (activeSessionRegistry.get(convId) !== session) return;\n activeSessionRegistry.pushEvent(convId, { type: 'error', message: `Codex error: ${err.message}` });\n activeSessionRegistry.pushEvent(convId, { type: 'done', text: '' });\n activeSessionRegistry.markDone(convId);\n });\n\n yield* drainSession(session, signal, false);\n }),\n\n send: protectedProcedure\n .input(z.object({\n conversationId: ConversationIdSchema,\n messages: z.array(MessageSchema).min(0).max(100),\n model: ShortString200Schema.optional(),\n contextNote: z.string().max(200_000).optional(),\n reconnect: z.boolean().optional(),\n imageIds: z.array(z.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)).max(5).optional(),\n imageParts: ImagePartsSchema,\n }))\n .subscription(async function* ({ input, ctx, signal }) {\n // ── Reconnect path: attach to an existing session ───────────────────\n const existingSession = activeSessionRegistry.get(input.conversationId);\n if (input.reconnect && existingSession) {\n yield* drainSession(existingSession, signal, true);\n return;\n }\n\n // ── New message path ────────────────────────────────────────────────\n if (input.messages.length === 0) {\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Messages are required for new messages' });\n }\n\n // Persist user message immediately — don't wait for the frontend\n const conv = await conversationStore.get(input.conversationId);\n\n // La conversation nomme son projet, donc son organisation : les\n // fournisseurs lus sont ceux de l'équipe à qui appartient ce travail.\n const convRef = conv ? await conversationStore.projectRefOf(conv) : null;\n const active = await getActiveProvider(conv?.providerId, convRef?.orgId ?? undefined);\n\n if (!active) {\n throw new TRPCError({\n code: 'PRECONDITION_FAILED',\n message: 'No AI provider configured for this conversation. Please select one when starting a new chat.',\n });\n }\n if (conv) {\n const lastUserMsg = input.messages[input.messages.length - 1];\n if (lastUserMsg) {\n const sendUserParts = input.imageParts && input.imageParts.length > 0\n ? [...(lastUserMsg.content.trim() ? [{ type: 'text' as const, text: lastUserMsg.content }] : []), ...input.imageParts]\n : undefined;\n conv.messages.push({ role: lastUserMsg.role, content: lastUserMsg.content, parts: sendUserParts, contextNote: input.contextNote });\n conv.messages.push({ role: 'assistant', content: '' });\n await conversationStore.update(conv.id, { messages: conv.messages }, { silent: true });\n }\n }\n\n const { provider, plaintextKey } = active;\n const model = input.model ?? provider.model ?? DEFAULT_MODELS[provider.provider] ?? 'gpt-4o';\n const apiKey = (ctx as AuthContext).apiKey ?? null;\n const authToken = ctx.authorization?.replace(/^Bearer\\s+/i, '') ?? '';\n let system = await buildSystemPrompt(apiKey);\n system += '\\n\\n' + TOOL_SAFETY_INSTRUCTION;\n\n // Append kanban context if this conversation is linked to a kanban board/card\n if (conv && conv.kanbanBoardId) {\n const kanbanBoard = await kanbanStore.get(conv.kanbanBoardId);\n if (kanbanBoard) {\n system += '\\n\\n' + (conv.kanbanCardId\n ? await buildKanbanCardPrompt(kanbanBoard, conv.kanbanCardId)\n : generateKanbanPopulatePrompt(kanbanBoard));\n }\n }\n\n // Resolve images if any imageIds provided\n const resolvedImages = input.imageIds && input.imageIds.length > 0\n ? await resolveImagesToBase64(input.imageIds.map(id => ({ imageId: id, mimeType: '' })), input.conversationId)\n : [];\n\n // Register in the session registry — stream survives WS disconnection\n let session: ActiveSession;\n try {\n session = activeSessionRegistry.registerDirectProviderApiSession(input.conversationId);\n } catch {\n throw new TRPCError({ code: 'CONFLICT', message: 'A session is already running for this conversation. Stop it first.' });\n }\n const apiSignal = session.abortController!.signal;\n\n // Fire-and-forget: run the API stream, pushing events into the registry\n const runStream = async () => {\n try {\n let gen: AsyncGenerator<ChatEvent>;\n\n if (provider.provider === 'anthropic') {\n const client = new Anthropic({ apiKey: plaintextKey });\n const msgs: Anthropic.MessageParam[] = input.messages.map((m, i) => {\n const isLast = i === input.messages.length - 1;\n if (isLast && resolvedImages.length > 0) {\n const content: Anthropic.ContentBlockParam[] = resolvedImages.map(img => ({\n type: 'image' as const,\n source: { type: 'base64' as const, media_type: img.mimeType as Anthropic.Base64ImageSource['media_type'], data: img.base64 },\n }));\n content.push({ type: 'text', text: m.content });\n return { role: m.role, content };\n }\n return { role: m.role, content: m.content };\n });\n gen = runAnthropic(client, model, system, msgs, apiKey, authToken, apiSignal);\n } else 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 msgs: OpenAI.Chat.ChatCompletionMessageParam[] = [\n { role: 'system', content: system },\n ...input.messages.map((m, i) => {\n const isLast = i === input.messages.length - 1;\n if (isLast && resolvedImages.length > 0) {\n const content: OpenAI.Chat.ChatCompletionContentPart[] = resolvedImages.map(img => ({\n type: 'image_url' as const,\n image_url: { url: `data:${img.mimeType};base64,${img.base64}` },\n }));\n content.push({ type: 'text', text: m.content });\n return { role: m.role, content } as OpenAI.Chat.ChatCompletionMessageParam;\n }\n return { role: m.role, content: m.content } as OpenAI.Chat.ChatCompletionMessageParam;\n }),\n ];\n gen = runOpenAI(client, model, msgs, apiKey, authToken, apiSignal);\n } else {\n activeSessionRegistry.pushEvent(input.conversationId, { type: 'error', message: `Provider \"${provider.provider}\" is not supported.` });\n activeSessionRegistry.pushEvent(input.conversationId, { type: 'done', text: '' });\n activeSessionRegistry.markDone(input.conversationId);\n return;\n }\n\n for await (const event of gen) {\n if (event.type === 'delta') {\n activeSessionRegistry.pushEvent(input.conversationId, { type: 'delta', text: event.text });\n } else if (event.type === 'tool_call') {\n activeSessionRegistry.pushEvent(input.conversationId, { type: 'tool_call', id: event.id, name: event.name, input: event.input });\n } else if (event.type === 'tool_result') {\n activeSessionRegistry.pushEvent(input.conversationId, { type: 'tool_result', id: event.id, name: event.name, result: event.result, isError: event.isError });\n } else if (event.type === 'done') {\n activeSessionRegistry.pushEvent(input.conversationId, { type: 'done', text: '' });\n }\n }\n } catch (err) {\n if (!apiSignal.aborted) {\n activeSessionRegistry.pushEvent(input.conversationId, { type: 'error', message: (err as Error).message });\n activeSessionRegistry.pushEvent(input.conversationId, { type: 'done', text: '' });\n }\n } finally {\n activeSessionRegistry.markDone(input.conversationId);\n }\n };\n\n // Start the stream in the background — it won't be cancelled by tRPC signal\n void runStream();\n\n // Drain from registry (WS disconnection stops yielding but stream continues)\n yield* drainSession(session, signal, false);\n }),\n\n // ── PTY passthrough (interactive Claude Code session) ────────────────────\n pty: router({\n /** Start a PTY session running `claude --resume <sessionId>` (or fresh). */\n start: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128).optional(),\n sessionId: z.string().max(128).optional(),\n runner: z.enum(['claude-code', 'codex']).default('claude-code'),\n resume: z.boolean().default(false),\n model: z.string().max(128).optional(),\n cwd: z.string().max(4096).optional(),\n /** Anchors the session when no explicit cwd is given. */\n serviceId: z.string().max(128).optional(),\n projectId: Id128Schema.optional(),\n orgId: z.string().max(128).nullable().optional(),\n cols: z.number().int().min(1).max(1000).default(120),\n rows: z.number().int().min(1).max(1000).default(30),\n enableMcp: z.boolean().default(false),\n apiBaseUrl: z.string().max(512).optional(),\n environmentId: z.string().max(128).optional(),\n attachedContexts: z.array(z.object({\n label: z.string().max(200),\n text: z.string().max(1_000_000),\n })).max(20).optional(),\n }))\n .mutation(async ({ input, ctx }) => {\n // Where the terminal's startup time actually goes. Kept behind the debug\n // flag but written once, here: the browser only sees one long mutation,\n // so without these laps \"the terminal takes forever\" cannot be pinned on\n // the agent lookup, the system prompt, or the spawn itself.\n const t0 = Date.now();\n const lap = (label: string) => {\n if (process.env.RUNEYA_DEBUG) console.log('[chat.pty.start] %s +%dms', label, Date.now() - t0);\n };\n const agentId = input.agentId ?? agentManager.getDefaultAgentId();\n if (!agentId) throw new TRPCError({ code: 'PRECONDITION_FAILED', message: 'No agent available' });\n\n // If a PTY is already alive for this sessionId, re-attach to it instead\n // of spawning a fresh `claude` (so the process survives navigation).\n if (input.sessionId) {\n try {\n const existing = await agentManager.agentQuery<{ spawnId: string; status: string } | null>(\n agentId,\n 'ai.findPtyBySession',\n { sessionId: input.sessionId },\n );\n if (existing && existing.status === 'running') {\n // Resize to current viewport so the reattached terminal looks right.\n await agentManager.agentMutation(agentId, 'ai.resizePty', {\n spawnId: existing.spawnId,\n cols: input.cols,\n rows: input.rows,\n }).catch(() => {});\n lap('reattached to existing pty');\n return { spawnId: existing.spawnId, agentId, reattached: true };\n }\n } catch {\n // best-effort — fall back to spawning a fresh PTY\n }\n }\n\n lap('findPtyBySession (no reattach)');\n const isCodex = input.runner === 'codex';\n const cli = isCodex ? 'codex' : 'claude';\n const args: string[] = [];\n if (isCodex) {\n // Codex resume is a positional subcommand: `codex resume <id>`. Only\n // attempt it when the rollout file actually exists on disk, otherwise\n // the CLI errors out instead of starting fresh. The app-server reuses\n // the rollout id as the threadId, so an existing conversation usually\n // resumes — but a session born purely in the app-server may not have a\n // matching rollout, in which case we start a clean session.\n if (input.sessionId && await codexSessionExists(input.sessionId)) {\n args.push('resume', input.sessionId);\n }\n if (input.model) args.push('--model', input.model);\n args.push('--dangerously-bypass-approvals-and-sandbox');\n } else {\n if (input.sessionId) {\n // Auto-detect whether the session already exists on disk: Claude refuses\n // `--session-id <id>` when the ID is already known. Override the caller's\n // hint so a returning conversation always resumes cleanly.\n const sessionExists = await claudeSessionExists(input.sessionId);\n if (input.resume || sessionExists) {\n args.push('--resume', input.sessionId);\n } else {\n args.push('--session-id', input.sessionId);\n }\n }\n if (input.model) args.push('--model', input.model);\n args.push('--dangerously-skip-permissions');\n }\n\n // Build the system prompt (services llms.txt + kanban + API docs) and\n // inject it via `--append-system-prompt` so Claude treats it as a real\n // system prompt instead of a user message. Codex has no equivalent\n // append-system-prompt flag, so this is skipped for the codex runner\n // (only the attached-context bracketed paste below applies to it).\n const jwt = ctx.authorization?.startsWith('Bearer ') ? ctx.authorization.slice(7) : undefined;\n if (!isCodex && input.sessionId) {\n try {\n const conv = await conversationStore.get(input.sessionId);\n if (conv) {\n const systemContext = await buildCliSystemContext(conv, jwt);\n const apiBase = input.apiBaseUrl ?? `http://localhost:${env.PORT}`;\n const apiDocs = buildApiDocs(apiBase, jwt ?? '');\n const fullSystemPrompt = apiDocs ? `${systemContext}\\n\\n${apiDocs}` : systemContext;\n if (fullSystemPrompt.trim().length > 0) {\n args.push('--append-system-prompt', fullSystemPrompt);\n }\n }\n } catch (err) {\n console.warn('[chat.pty.start] buildCliSystemContext failed:', (err as Error).message);\n }\n lap('buildCliSystemContext');\n }\n\n // Inject flagged variables from the active environment into the AI\n // process env (opt-in per variable via `injectIntoAi`).\n const injectedEnv = await resolveInjectedEnv(input.environmentId);\n lap('resolveInjectedEnv');\n\n const res = await agentManager.agentMutation<{ spawnId: string }>(\n agentId,\n 'ai.spawnPty',\n {\n cli,\n args,\n env: injectedEnv,\n // An explicit cwd wins; then le projet de la conversation, s'il y en\n // a une : c'est elle que ce terminal poursuit, et son projet n'est\n // pas forcément celui ouvert dans l'onglet — ouvrir le terminal\n // d'une carte kanban depuis ailleurs lançait le CLI dans le\n // répertoire de lancement de Runeya. Sinon le service, puis le\n // projet actif — jamais le répertoire du serveur.\n cwd: input.cwd\n ?? (input.sessionId ? await resolveConversationCwd(input.sessionId) : undefined)\n ?? await resolveAgentCwd({\n serviceId: input.serviceId, projectId: input.projectId, orgId: input.orgId,\n }),\n cols: input.cols,\n rows: input.rows,\n sessionId: input.sessionId,\n enableMcp: input.enableMcp,\n mcpApiBaseUrl: input.apiBaseUrl ?? `http://localhost:${env.PORT}`,\n mcpApiToken: jwt,\n },\n );\n\n lap('agent ai.spawnPty');\n const contexts = input.attachedContexts ?? [];\n if (contexts.length > 0) {\n const body = contexts\n .map((c) => `### ${c.label}\\n${c.text}`)\n .join('\\n\\n');\n // Bracketed paste: Claude's TUI collapses this to \"[Pasted text #N +X lines]\"\n // but keeps the full content in the message it sends.\n const injection = `\\x1b[200~---------\\nContext:\\n\\x1b[201~\\x1b[200~${body}\\x1b[201~\\x1b[200~\\n---------\\n\\x1b[201~`;\n\n const doInject = (): void => {\n agentManager\n .agentMutation(agentId, 'ai.writePty', { spawnId: res.spawnId, data: injection })\n .catch((err) => {\n console.warn('[chat.pty.start] deferred context writePty failed:', (err as Error).message);\n });\n };\n\n // There is no explicit \"ready for input\" signal from Claude Code or\n // Codex, so we combine a floor with output-quiescence detection:\n // - MIN_MS: never inject before this — the known-good fixed delay that\n // guarantees the TUI has reached its input prompt (a plain quiescence\n // check alone can fire during an early boot pause and drop the paste,\n // which is what broke larger contexts like logs).\n // - then wait for a quiet gap (no new bytes) so a slow boot pushes the\n // injection later rather than earlier.\n // - MAX_MS: hard safety net if output never settles (blinking cursor).\n const startedAt = Date.now();\n const MIN_MS = input.runner === 'codex' ? 500 : 1200;\n const QUIET_MS = 400;\n const MAX_MS = 8000;\n let injected = false;\n let quietTimer: ReturnType<typeof setTimeout> | null = null;\n let maxTimer: ReturnType<typeof setTimeout> | null = null;\n let unsub: (() => void) | null = null;\n const cleanup = (): void => {\n if (quietTimer) clearTimeout(quietTimer);\n if (maxTimer) clearTimeout(maxTimer);\n unsub?.();\n };\n const inject = (): void => {\n if (injected) return;\n injected = true;\n cleanup();\n doInject();\n };\n const scheduleQuiet = (): void => {\n if (quietTimer) clearTimeout(quietTimer);\n const wait = Math.max(QUIET_MS, MIN_MS - (Date.now() - startedAt));\n quietTimer = setTimeout(inject, wait);\n };\n maxTimer = setTimeout(inject, MAX_MS);\n unsub = agentManager.agentSubscribe(\n agentId,\n 'ai.stream',\n { spawnId: res.spawnId, fromOffset: 0 },\n (data: unknown) => {\n const chunk = (data as { chunk?: { type?: string } }).chunk;\n if (chunk?.type === 'exit') { injected = true; cleanup(); return; } // process gone\n scheduleQuiet();\n },\n () => { /* stream ended before ready — nothing to inject into */ },\n );\n }\n\n return { spawnId: res.spawnId, agentId, reattached: false };\n }),\n\n /** Subscribe to PTY output stream (raw text with ANSI). */\n stream: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128).optional(),\n spawnId: z.string().max(128),\n fromOffset: z.number().int().min(0).default(0),\n }))\n .subscription(async function* ({ input, signal }) {\n const agentId = input.agentId ?? agentManager.getDefaultAgentId();\n if (!agentId) throw new TRPCError({ code: 'PRECONDITION_FAILED', message: 'No agent available' });\n\n // Time to the terminal's first visible byte: the gap people describe as\n // \"the PTY does not even show claude\" lives between this subscribe and\n // the agent's first chunk.\n const tSub = Date.now();\n let firstChunk = true;\n const queue: Array<{ offset: number; chunk: { type: string; data: string; code?: number } }> = [];\n let resolve: (() => void) | null = null;\n let stopped = false;\n\n const unsub = agentManager.agentSubscribe(\n agentId,\n 'ai.stream',\n { spawnId: input.spawnId, fromOffset: input.fromOffset },\n (data: unknown) => {\n if (firstChunk) {\n firstChunk = false;\n if (process.env.RUNEYA_DEBUG) console.log('[chat.pty.stream] first chunk +%dms', Date.now() - tSub);\n }\n queue.push(data as { offset: number; chunk: { type: string; data: string; code?: number } });\n if (resolve) { resolve(); resolve = null; }\n },\n () => { stopped = true; if (resolve) { resolve(); resolve = null; } },\n );\n\n try {\n while (!signal?.aborted && !stopped) {\n while (queue.length > 0) {\n const item = queue.shift()!;\n yield item;\n if (item.chunk.type === 'exit') { stopped = true; break; }\n }\n if (stopped) break;\n await new Promise<void>((r) => { resolve = r; });\n }\n } finally {\n unsub();\n }\n }),\n\n /** Write input to a PTY session (keystrokes from xterm). */\n write: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128).optional(),\n spawnId: z.string().max(128),\n data: z.string().max(1_000_000),\n }))\n .mutation(async ({ input }) => {\n const agentId = input.agentId ?? agentManager.getDefaultAgentId();\n if (!agentId) throw new TRPCError({ code: 'PRECONDITION_FAILED', message: 'No agent available' });\n return agentManager.agentMutation<{ ok: boolean }>(agentId, 'ai.writePty', {\n spawnId: input.spawnId,\n data: input.data,\n });\n }),\n\n /** Resize a PTY session. */\n resize: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128).optional(),\n spawnId: z.string().max(128),\n cols: z.number().int().min(1).max(1000),\n rows: z.number().int().min(1).max(1000),\n }))\n .mutation(async ({ input }) => {\n const agentId = input.agentId ?? agentManager.getDefaultAgentId();\n if (!agentId) throw new TRPCError({ code: 'PRECONDITION_FAILED', message: 'No agent available' });\n return agentManager.agentMutation<{ ok: boolean }>(agentId, 'ai.resizePty', {\n spawnId: input.spawnId,\n cols: input.cols,\n rows: input.rows,\n });\n }),\n\n /**\n * Upload a pasted image to the agent. The agent saves it to a tmp file and\n * tries to populate its system clipboard so Claude's native paste detection\n * picks it up. Returns the tmp path and which clipboard method succeeded\n * (null if none — caller should inject `@<path>` instead of Ctrl+V).\n */\n pasteImage: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128).optional(),\n sessionId: z.string().max(128).optional(),\n mimeType: z.string().max(64),\n base64: z.string().max(15_000_000),\n }))\n .mutation(async ({ input }) => {\n const agentId = input.agentId ?? agentManager.getDefaultAgentId();\n if (!agentId) throw new TRPCError({ code: 'PRECONDITION_FAILED', message: 'No agent available' });\n const res = await agentManager.agentMutation<{\n tmpPath: string;\n clipboardMethod: 'xclip' | 'wl-copy' | 'pbcopy' | 'powershell' | null;\n clipboardError?: string;\n }>(agentId, 'ai.pasteImage', {\n sessionId: input.sessionId,\n mimeType: input.mimeType,\n base64: input.base64,\n });\n if (!res.clipboardMethod) {\n console.warn('[chat.pty.pasteImage] clipboard spoof failed, using @path fallback:', res.clipboardError);\n }\n return res;\n }),\n\n /**\n * Read the transcript Claude Code stores on disk for a given session.\n * Returns parsed JSONL entries (user / assistant messages, tool uses, etc.).\n */\n transcript: protectedProcedure\n .input(z.object({ sessionId: z.string().max(128) }))\n .query(async ({ input }) => {\n return readClaudeTranscript(input.sessionId);\n }),\n\n /**\n * Lightweight liveness probe: is a PTY running for this session, and\n * when was the transcript JSONL last touched? Used by the non-PTY view\n * to show a \"Claude is thinking…\" indicator while output streams.\n */\n activity: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128).optional(),\n sessionId: z.string().max(128),\n }))\n .query(async ({ input }) => {\n const agentId = input.agentId ?? agentManager.getDefaultAgentId();\n let running = false;\n let lastChunkAt: number | null = null;\n if (agentId) {\n try {\n const existing = await agentManager.agentQuery<{ spawnId: string; status: string; lastChunkAt: number | null } | null>(\n agentId,\n 'ai.findPtyBySession',\n { sessionId: input.sessionId },\n );\n running = existing?.status === 'running';\n lastChunkAt = existing?.lastChunkAt ?? null;\n } catch {\n // agent unreachable — treat as not running\n }\n }\n // PTY data (every byte streamed by the agent) is the most accurate\n // signal; JSONL writes are a coarser fallback if the agent didn't\n // surface a chunk timestamp yet.\n const transcriptActivityAt = getLastTranscriptActivity(input.sessionId);\n const lastActivityAt = lastChunkAt && transcriptActivityAt\n ? Math.max(lastChunkAt, transcriptActivityAt)\n : (lastChunkAt ?? transcriptActivityAt);\n return { running, lastActivityAt };\n }),\n\n /**\n * Convert the on-disk Claude transcript into Runeya Message[] and persist\n * them on the conversation, so the non-PTY chat view stays in sync.\n * Uses the conversation id as session id (PTY sessions are spawned that way).\n */\n syncTranscript: protectedProcedure\n .input(z.object({ conversationId: ConversationIdSchema }))\n .mutation(async ({ input }) => {\n const conv = await conversationStore.get(input.conversationId);\n if (!conv) {\n throw new TRPCError({ code: 'NOT_FOUND', message: `Conversation ${input.conversationId} not found` });\n }\n const synced = await syncConversationFromClaudeTranscript(conv.id);\n const after = await conversationStore.get(conv.id);\n return { synced, messageCount: after?.messages.length ?? 0 };\n }),\n\n /**\n * Debug-only: spawn a PTY that emits random data at a chosen rate, tagged\n * with the given sessionId. Used to benchmark the PTY → tRPC → xterm.js\n * pipeline. Open the conversation in PTY mode to attach to it.\n */\n debugStress: protectedProcedure\n .input(z.object({\n sessionId: z.string().max(128),\n agentId: z.string().max(128).optional(),\n bytesPerSec: z.number().int().min(100).max(10_000_000).default(50_000),\n chunkSize: z.number().int().min(1).max(65_536).default(256),\n durationMs: z.number().int().min(0).max(3_600_000).default(0),\n cols: z.number().int().min(1).max(1000).default(120),\n rows: z.number().int().min(1).max(1000).default(30),\n }))\n .mutation(async ({ input }) => {\n const agentId = input.agentId ?? agentManager.getDefaultAgentId();\n if (!agentId) throw new TRPCError({ code: 'PRECONDITION_FAILED', message: 'No agent available' });\n\n // Use a synthetic sessionId so we don't collide with the conversation's\n // real Claude PTY — that would make the overlay re-attach to Claude\n // instead of the stress generator.\n const stressSessionId = `${input.sessionId}-stress-${Date.now().toString(36)}`;\n\n // Resolve the script. Try a few likely locations because import.meta.url\n // depth depends on whether the server runs from src (dev) or dist (prod\n // bundle) and tsup can split into chunks.\n const { existsSync } = await import('node:fs');\n const candidates = [\n new URL('../../../../scripts/pty-stress-gen.mjs', import.meta.url),\n new URL('../../../../../scripts/pty-stress-gen.mjs', import.meta.url),\n new URL('../../../scripts/pty-stress-gen.mjs', import.meta.url),\n ];\n let scriptPath: string | null = null;\n for (const c of candidates) {\n const p = fileURLToPath(c);\n if (existsSync(p)) { scriptPath = p; break; }\n }\n if (!scriptPath) {\n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message: `pty-stress-gen.mjs not found near ${fileURLToPath(import.meta.url)}`,\n });\n }\n const res = await agentManager.agentMutation<{ spawnId: string }>(\n agentId,\n 'ai.spawnPty',\n {\n cli: 'node',\n args: [scriptPath],\n // Was `process.cwd()` — the SERVER's directory, handed to an agent\n // that may not even run on this machine.\n cwd: await resolveWorkspaceCwd({}),\n cols: input.cols,\n rows: input.rows,\n sessionId: stressSessionId,\n env: {\n BYTES_PER_SEC: String(input.bytesPerSec),\n CHUNK_SIZE: String(input.chunkSize),\n DURATION_MS: String(input.durationMs),\n },\n },\n );\n return { spawnId: res.spawnId, agentId, stressSessionId };\n }),\n\n /** Kill a PTY session. */\n kill: protectedProcedure\n .input(z.object({\n agentId: z.string().max(128).optional(),\n spawnId: z.string().max(128),\n }))\n .mutation(async ({ input }) => {\n const agentId = input.agentId ?? agentManager.getDefaultAgentId();\n if (!agentId) throw new TRPCError({ code: 'PRECONDITION_FAILED', message: 'No agent available' });\n return agentManager.agentMutation<{ ok: boolean }>(agentId, 'ai.kill', {\n spawnId: input.spawnId,\n });\n }),\n }),\n});\n","// ─── Runeya AI Capabilities — Single Source of Truth ─────────────────────────\n//\n// Adding a new capability:\n// 1. Add an entry to RUNEYA_CAPABILITIES below.\n// 2. Done. Anthropic tools, OpenAI tools, runner prompt docs, and MCP routes\n// are all generated automatically from this list.\n\nexport interface CapabilityParam {\n name: string;\n description: string;\n required: boolean;\n}\n\nexport interface RuneyaCapability {\n /** Tool name (snake_case, used as function name by LLMs). */\n name: string;\n /** Human-readable description shown to the LLM. */\n description: string;\n /** tRPC route segment, e.g. \"service.list\" or \"process.start\". */\n route: string;\n /** HTTP method for the tRPC call. */\n method: 'GET' | 'POST';\n /** Input parameters exposed to the LLM. */\n params: CapabilityParam[];\n /** Build the tRPC input object from raw LLM params. */\n buildInput: (params: Record<string, string | undefined>) => Record<string, unknown> | undefined;\n /** If true, safety instructions will warn the LLM to require explicit user intent. */\n destructive?: boolean;\n /**\n * Optional usage hint injected into the system prompt so the LLM knows when to use this tool.\n * Example: '\"wait 5s\" or \"pause for 10 seconds\" → call wait'\n */\n usageHint?: string;\n}\n\n/**\n * Une liste, telle qu'un modèle l'écrit.\n *\n * Il envoie du JSON quand il y pense, une énumération séparée par des virgules\n * quand il n'y pense pas. Refuser la seconde ferait échouer l'appel sans que\n * rien n'explique pourquoi.\n */\nfunction toList(raw: string | undefined): string[] {\n if (!raw) return [];\n const text = raw.trim();\n if (text.startsWith('[')) {\n try {\n const parsed: unknown = JSON.parse(text);\n if (Array.isArray(parsed)) return parsed.map((v) => String(v).trim()).filter(Boolean);\n } catch {\n // Un JSON malformé se lit comme une énumération : mieux vaut retenir les\n // noms qu'il contient que de tout perdre sur une virgule en trop.\n }\n }\n return text.split(',').map((v) => v.trim().replace(/^[\"'[]+|[\"'\\]]+$/g, '')).filter(Boolean);\n}\n\n/**\n * Un champ qu'on peut soit changer, soit effacer, soit laisser tranquille.\n *\n * Absent : on n'y touche pas. `null` ou vide : on l'efface — c'est ce que le\n * cloud attend, et la seule façon pour un agent de retirer une échéance.\n */\nfunction clearable(\n raw: string | undefined,\n parse: (value: string) => unknown,\n key: string,\n): Record<string, unknown> {\n if (raw === undefined) return {};\n const text = String(raw).trim();\n if (!text || text === 'null') return { [key]: null };\n return { [key]: parse(text) };\n}\n\nexport const RUNEYA_CAPABILITIES: RuneyaCapability[] = [\n {\n name: 'list_services',\n description: 'List all available services. Returns serviceId and agentId for each — use these exact fields in other calls.',\n route: 'service.list',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'get_service_status',\n description: 'Get the current status (running, stopped, etc.) of a service.',\n route: 'process.get',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'The service ID', required: true },\n { name: 'agentId', description: 'The agent ID hosting this service', required: true },\n ],\n buildInput: (p) => ({ agentId: p.agentId, id: p.serviceId }),\n },\n {\n name: 'get_logs',\n description: 'Get the recent buffered logs for a service.',\n route: 'process.logs',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'The service ID', required: true },\n { name: 'agentId', description: 'The agent ID hosting this service', required: true },\n ],\n buildInput: (p) => ({ agentId: p.agentId, processId: p.serviceId }),\n },\n {\n name: 'start_service',\n description: 'Start a service on an agent.',\n route: 'process.start',\n method: 'POST',\n params: [\n { name: 'serviceId', description: 'The service ID to start', required: true },\n { name: 'agentId', description: 'The agent ID hosting this service', required: true },\n ],\n buildInput: (p) => ({ agentId: p.agentId, processId: p.serviceId }),\n destructive: true,\n },\n {\n name: 'stop_service',\n description: 'Stop a running service on an agent.',\n route: 'process.stop',\n method: 'POST',\n params: [\n { name: 'serviceId', description: 'The service ID to stop', required: true },\n { name: 'agentId', description: 'The agent ID hosting this service', required: true },\n ],\n buildInput: (p) => ({ agentId: p.agentId, processId: p.serviceId }),\n destructive: true,\n },\n {\n name: 'restart_service',\n description: 'Restart a service on an agent (stop → redeploy → start).',\n route: 'process.restart',\n method: 'POST',\n params: [\n { name: 'serviceId', description: 'The service ID to restart', required: true },\n { name: 'agentId', description: 'The agent ID hosting this service', required: true },\n ],\n buildInput: (p) => ({ agentId: p.agentId, processId: p.serviceId }),\n destructive: true,\n },\n\n // ─── Utility ─────────────────────────────────────────────────────────────\n\n {\n name: 'wait',\n description: 'Wait for a given number of milliseconds before continuing.',\n route: 'utility.wait',\n method: 'POST',\n params: [\n { name: 'ms', description: 'Number of MILLISECONDS to wait. Convert from seconds: 1s=1000, 10s=10000, 1min=60000. Max 300000.', required: true },\n ],\n buildInput: (p) => ({ ms: Number(p.ms) }),\n usageHint: '\"wait 5s\" → wait(ms=5000), \"pause 10 seconds\" → wait(ms=10000), \"attends 3 secondes\" → wait(ms=3000). Always convert to milliseconds.',\n },\n\n // ─── Kanban ───────────────────────────────────────────────────────────────\n\n {\n name: 'kanban_list_boards',\n description: 'List the kanban boards of the organization. Returns the organizationId actually queried, the boardId to use in the other kanban tools, plus column and card counts. Cards themselves are not included — use kanban_get_board for those. An empty list means that organization really has no board: a failure to reach the cloud is reported as an error instead, never as an empty list.',\n route: 'kanban.listBoards',\n method: 'GET',\n params: [\n { name: 'includeArchived', description: 'Set to \"true\" to include archived boards. Default: false.', required: false },\n { name: 'organizationId', description: 'Which organization to read. Optional: needed only when the account belongs to several and the error message asks for it.', required: false },\n ],\n buildInput: (p) => ({\n includeArchived: p.includeArchived === 'true',\n ...(p.organizationId ? { organizationId: p.organizationId } : {}),\n }),\n },\n {\n name: 'kanban_get_board',\n description: 'Read one kanban board: its columns, and the cards in each (id, title, markdown body, assignees, comment count, and attachment metadata — use kanban_download_attachment to fetch the bytes of a file). Use the exact column names it returns when moving or adding a card.',\n route: 'kanban.getBoard',\n method: 'GET',\n params: [\n { name: 'boardId', description: 'The kanban board ID, from kanban_list_boards', required: true },\n ],\n buildInput: (p) => ({ boardId: p.boardId }),\n },\n {\n name: 'kanban_get_card_comments',\n description: \"Read the comment thread of one kanban card, newest last: who wrote each comment (ai or user, with the person's name), when, its text, and its attachments. The comments in your task context are a snapshot taken when the task started — call this to see anything written since, whenever someone tells you a comment was added or kanban_get_board reports a higher commentCount than you have.\",\n route: 'kanban.getCardComments',\n method: 'GET',\n params: [\n { name: 'boardId', description: 'The kanban board ID', required: true },\n { name: 'cardId', description: 'The card ID whose comments to read', required: true },\n { name: 'limit', description: 'How many of the most recent comments to return (1-200). Default: 50.', required: false },\n ],\n buildInput: (p) => ({\n boardId: p.boardId,\n cardId: p.cardId,\n ...(p.limit ? { limit: Number(p.limit) } : {}),\n }),\n usageHint: '\"le support a ajouté un commentaire\" / \"regarde les nouveaux commentaires\" → kanban_get_card_comments(boardId, cardId). Never answer from the snapshot in your context when fresh comments are mentioned.',\n },\n {\n name: 'kanban_search_cards',\n description: 'Search kanban cards by free text, matched against their title, body and comments (accent- and case-insensitive). Archived cards are included. Searches every board of the organization unless boardId narrows it down.',\n route: 'kanban.searchCards',\n method: 'GET',\n params: [\n { name: 'query', description: 'Text to look for in card titles, bodies and comments', required: true },\n { name: 'boardId', description: 'Restrict the search to this board. Omit to search all boards.', required: false },\n { name: 'limit', description: 'Maximum number of cards to return (1-100). Default: 25.', required: false },\n { name: 'organizationId', description: 'Which organization to search. Optional: needed only when the account belongs to several and the error message asks for it.', required: false },\n ],\n buildInput: (p) => ({\n query: p.query,\n ...(p.boardId ? { boardId: p.boardId } : {}),\n ...(p.limit ? { limit: Number(p.limit) } : {}),\n ...(p.organizationId ? { organizationId: p.organizationId } : {}),\n }),\n },\n {\n name: 'kanban_download_attachment',\n 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, from kanban_get_board, or from kanban_get_card_comments — a file attached to a comment downloads exactly like one attached to the card.',\n route: 'kanban.downloadAttachment',\n method: 'POST',\n params: [\n { name: 'attachmentId', description: 'The attachment ID, as listed on the card', required: true },\n ],\n buildInput: (p) => ({ attachmentId: p.attachmentId }),\n },\n {\n name: 'kanban_move_card',\n description: 'Move a kanban card to another column. Use the exact column name.',\n route: 'kanban.moveCard',\n method: 'POST',\n params: [\n { name: 'boardId', description: 'The kanban board ID', required: true },\n { name: 'cardId', description: 'The card ID to move', required: true },\n { name: 'targetColumn', description: 'Exact name of the target column', required: true },\n ],\n buildInput: (p) => ({ boardId: p.boardId, cardId: p.cardId, targetColumn: p.targetColumn }),\n },\n {\n name: 'kanban_add_comment',\n description: 'Add a comment to a kanban card.',\n route: 'kanban.addComment',\n method: 'POST',\n params: [\n { name: 'boardId', description: 'The kanban board ID', required: true },\n { name: 'cardId', description: 'The card ID', required: true },\n { name: 'comment', description: 'The comment text (markdown supported)', required: true },\n ],\n buildInput: (p) => ({ boardId: p.boardId, cardId: p.cardId, comment: p.comment }),\n },\n {\n name: 'kanban_get_card_links',\n description: 'Read the filiation of a board: which card depends on which. Returns one entry per link (child card ↔ parent card), plus the title, board, column, assignees and comment count of any linked card living on another board. Use it when a card context says it has a parent or sub-cards and you need their ids to read them.',\n route: 'kanban.getCardLinks',\n method: 'GET',\n params: [\n { name: 'boardId', description: 'The kanban board ID whose links to read', required: true },\n ],\n buildInput: (p) => ({ boardId: p.boardId }),\n },\n {\n name: 'kanban_set_card_parent',\n description: 'Link a kanban card to a parent card, or detach it. The parent is the card the other one depends on — an epic and its tasks, a bug and its follow-ups. A card has at most one parent, and setting a new one replaces it. Omit parentCardId to detach. kanban_get_board reports the current filiation as parentCardId / childCardIds on each card.',\n route: 'kanban.setCardParent',\n method: 'POST',\n params: [\n { name: 'boardId', description: 'The kanban board ID of the card being linked', required: true },\n { name: 'cardId', description: 'The card that depends on the parent (the child)', required: true },\n { name: 'parentCardId', description: 'The parent card ID. Omit to detach the card from its parent.', required: false },\n { name: 'parentBoardId', description: \"The parent's board, when it lives on another board of the same organization. Defaults to boardId.\", required: false },\n ],\n buildInput: (p) => ({\n boardId: p.boardId,\n cardId: p.cardId,\n ...(p.parentCardId ? { parentCardId: p.parentCardId } : {}),\n ...(p.parentBoardId ? { parentBoardId: p.parentBoardId } : {}),\n }),\n },\n {\n name: 'kanban_add_card',\n description: 'Add a new card to a kanban column.',\n route: 'kanban.addCard',\n method: 'POST',\n params: [\n { name: 'boardId', description: 'The kanban board ID', required: true },\n { name: 'column', description: 'Exact name of the target column', required: true },\n { name: 'title', description: 'Card title', required: true },\n { name: 'content', description: 'Card content in markdown', required: false },\n ],\n buildInput: (p) => ({ boardId: p.boardId, column: p.column, title: p.title, content: p.content }),\n },\n {\n name: 'kanban_get_card',\n description: 'Read one kanban card by id, including archived ones. Cheaper than fetching the whole board, and the only way to read a card that has been archived.',\n route: 'kanban.getCard',\n method: 'GET',\n params: [\n { name: 'boardId', description: 'The kanban board ID', required: true },\n { name: 'cardId', description: 'The card ID', required: true },\n ],\n buildInput: (p) => ({ boardId: p.boardId, cardId: p.cardId }),\n },\n {\n name: 'kanban_update_card',\n description: 'Update an existing kanban card. Only the fields you pass are changed; passing null to priority, color or deadline clears it. Prefer this over creating a second card when something needs correcting.',\n route: 'kanban.updateCard',\n method: 'POST',\n params: [\n { name: 'boardId', description: 'The kanban board ID', required: true },\n { name: 'cardId', description: 'The card ID', required: true },\n { name: 'title', description: 'New title', required: false },\n { name: 'content', description: 'New card content, in markdown', required: false },\n { name: 'priority', description: 'Priority from 1 to 10, or null to clear it', required: false },\n { name: 'color', description: 'Card colour, or null to clear it', required: false },\n { name: 'groups', description: 'Labels, as a list of strings. Replaces the current ones.', required: false },\n { name: 'deadline', description: 'Due date as YYYY-MM-DD, or null to clear it', required: false },\n { name: 'assignees', description: 'User ids to assign, as a list. Replaces the current ones; use kanban_list_members to find the ids.', required: false },\n ],\n buildInput: (p) => ({\n boardId: p.boardId,\n cardId: p.cardId,\n ...(p.title !== undefined ? { title: p.title } : {}),\n ...(p.content !== undefined ? { content: p.content } : {}),\n // Tout arrive en chaîne : un modèle n'écrit pas des nombres, des listes\n // ni des `null` typés. `clearable` distingue « efface » de « ne touche\n // pas » — sans quoi vider une couleur serait impossible à exprimer, et\n // changer un titre risquerait de vider le reste.\n ...(clearable(p.priority, (v) => Number(v), 'priority')),\n ...(clearable(p.color, (v) => v, 'color')),\n ...(clearable(p.deadline, (v) => v, 'deadline')),\n ...(p.groups !== undefined ? { groups: toList(p.groups) } : {}),\n ...(p.assignees !== undefined ? { assignees: toList(p.assignees) } : {}),\n }),\n },\n {\n name: 'kanban_set_card_archived',\n description: 'Archive a kanban card (it leaves the board but is not deleted) or bring it back. An unarchived card returns to the column it left.',\n route: 'kanban.setCardArchived',\n method: 'POST',\n params: [\n { name: 'boardId', description: 'The kanban board ID', required: true },\n { name: 'cardId', description: 'The card ID', required: true },\n { name: 'archived', description: 'true to archive, false to bring the card back', required: true },\n ],\n buildInput: (p) => ({ boardId: p.boardId, cardId: p.cardId, archived: p.archived === 'true' }),\n },\n {\n name: 'kanban_list_members',\n description: 'List the people of the organization who can be assigned to a card, with their ids. Needed before assigning anyone with kanban_update_card.',\n route: 'kanban.listMembers',\n method: 'GET',\n params: [\n { name: 'organizationId', description: 'Which organization. Optional: needed only when the account belongs to several and the error message asks for it.', required: false },\n ],\n buildInput: (p) => (p.organizationId ? { organizationId: p.organizationId } : {}),\n },\n];\n","import type { RuneyaCapability } from '../capabilities.js';\n\nexport interface AnthropicTool {\n name: string;\n description: string;\n input_schema: {\n type: 'object';\n properties: Record<string, { type: string; description: string }>;\n required: string[];\n [k: string]: unknown;\n };\n}\n\nexport function buildAnthropicTools(capabilities: RuneyaCapability[]): AnthropicTool[] {\n return capabilities.map(cap => ({\n name: cap.name,\n description: cap.description,\n input_schema: {\n type: 'object' as const,\n properties: Object.fromEntries(\n cap.params.map(p => [p.name, { type: 'string', description: p.description }]),\n ),\n required: cap.params.filter(p => p.required).map(p => p.name),\n },\n }));\n}\n","import type { RuneyaCapability } from '../capabilities.js';\n\nexport interface OpenAITool {\n type: 'function';\n function: {\n name: string;\n description: string;\n parameters: {\n type: 'object';\n properties: Record<string, { type: string; description: string }>;\n required: string[];\n };\n };\n}\n\nexport function buildOpenAITools(capabilities: RuneyaCapability[]): OpenAITool[] {\n return capabilities.map(cap => ({\n type: 'function' as const,\n function: {\n name: cap.name,\n description: cap.description,\n parameters: {\n type: 'object' as const,\n properties: Object.fromEntries(\n cap.params.map(p => [p.name, { type: 'string', description: p.description }]),\n ),\n required: cap.params.filter(p => p.required).map(p => p.name),\n },\n },\n }));\n}\n","import type { RuneyaCapability } from '../capabilities.js';\nexport type { RuneyaCapability };\n\n/**\n * Build the tool safety instruction block injected into cloud provider system prompts.\n * Generated from capabilities so it stays in sync automatically.\n */\nexport function buildToolSafetyInstruction(capabilities: RuneyaCapability[]): string {\n const destructive = capabilities.filter(c => c.destructive).map(c => c.name);\n const withHints = capabilities.filter(c => c.usageHint);\n\n const lines = ['## Tool use safety rules'];\n\n if (destructive.length > 0) {\n lines.push(`CRITICAL: Never call ${destructive.join(', ')} unless the user has EXPLICITLY and UNAMBIGUOUSLY requested it.`);\n lines.push(`- Only call destructive tools (${destructive.join(', ')}) when the user explicitly uses action words for a specific service.`);\n }\n\n if (withHints.length > 0) {\n lines.push('');\n lines.push('## Tool usage hints');\n for (const cap of withHints) {\n lines.push(`- ${cap.usageHint}`);\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Build a markdown documentation block injected into runner system prompts.\n * Runners (ClaudeCodeRunner, CodexRunner) use this to know how to call the Runeya API.\n *\n * The generated doc is the single source of truth for all runner-facing API docs —\n * no need to maintain a separate runeya-api-docs.ts.\n */\nexport function buildPromptDocs(baseUrl: string, token: string, capabilities: RuneyaCapability[]): string {\n if (!token) return '';\n\n const lines: string[] = [\n '## Runeya API',\n '',\n `Tu peux interagir avec Runeya via l'API HTTP tRPC ci-dessous.`,\n `Base URL : ${baseUrl}/api/trpc`,\n 'Auth header : Authorization: Bearer $RUNEYA_API_TOKEN',\n '',\n ];\n\n const gets = capabilities.filter(c => c.method === 'GET');\n const posts = capabilities.filter(c => c.method === 'POST');\n\n if (gets.length > 0) {\n lines.push('### GET routes (paramètres en query string ?input=<JSON encodé>)', '');\n for (const cap of gets) {\n const example = cap.params.length > 0\n ? `?input=${JSON.stringify(Object.fromEntries(cap.params.map(p => [p.name === 'serviceId' ? 'id' : p.name, '...'])))}`\n : '';\n lines.push(`- \\`${cap.route}${example}\\` — ${cap.description}`);\n }\n lines.push('');\n }\n\n if (posts.length > 0) {\n lines.push('### POST routes (body JSON)', '');\n for (const cap of posts) {\n const bodyExample = cap.params.length > 0\n ? JSON.stringify(Object.fromEntries(cap.params.map(p => [p.name === 'serviceId' ? 'processId' : p.name, '...'])))\n : '{}';\n lines.push(`- \\`${cap.route}\\` — \\`${bodyExample}\\``);\n }\n lines.push('');\n }\n\n const hints = capabilities.filter(c => c.usageHint);\n if (hints.length > 0) {\n lines.push('### Usage hints', '');\n for (const cap of hints) {\n lines.push(`- ${cap.usageHint}`);\n }\n lines.push('');\n }\n\n lines.push(\n '### Exemple curl',\n '',\n '```bash',\n `curl -H \"Authorization: Bearer $RUNEYA_API_TOKEN\" \\\\`,\n ` \"${baseUrl}/api/trpc/service.list\"`,\n '',\n `curl -X POST -H \"Authorization: Bearer $RUNEYA_API_TOKEN\" \\\\`,\n ' -H \"Content-Type: application/json\" \\\\',\n ` -d '{\"agentId\":\"local\",\"processId\":\"my-service\"}' \\\\`,\n ` \"${baseUrl}/api/trpc/process.start\"`,\n '```',\n '',\n 'La réponse est de la forme `{\"result\":{\"data\":<résultat>}}`.',\n );\n\n return lines.join('\\n');\n}\n","/**\n * Shared tRPC HTTP caller used by:\n * - Server-side cloud tool executor (proxies cloud LLM tool calls to local tRPC)\n * - MCP server (calls tRPC on behalf of CLI runners)\n */\nexport async function callTrpc(\n baseUrl: string,\n route: string,\n method: 'GET' | 'POST',\n input: Record<string, unknown> | undefined,\n authToken: string,\n): Promise<unknown> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${authToken}`,\n };\n\n const url = method === 'GET' && input\n ? `${baseUrl}/api/trpc/${route}?input=${encodeURIComponent(JSON.stringify(input))}`\n : `${baseUrl}/api/trpc/${route}`;\n\n const res = await fetch(url, {\n method,\n headers,\n ...(method === 'POST' ? { body: JSON.stringify(input ?? {}) } : {}),\n signal: AbortSignal.timeout(15_000),\n });\n\n const json = await res.json() as Record<string, unknown>;\n if (json['error']) throw new Error(JSON.stringify(json['error']));\n const result = json['result'] as Record<string, unknown> | undefined;\n return result?.['data'] ?? result ?? json;\n}\n","import { RUNEYA_CAPABILITIES, buildPromptDocs } from '@runeya/packages-ai-capabilities';\n\nexport function buildApiDocs(apiBaseUrl: string, apiToken: string): string {\n return buildPromptDocs(apiBaseUrl, apiToken, RUNEYA_CAPABILITIES);\n}\n","import { readdir, access, readFile } from 'node:fs/promises';\nimport { watch, type FSWatcher } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { conversationStore, type Message, type MessagePart } from './conversation-store.js';\n\nexport interface ClaudeTranscriptEntry {\n type: string;\n uuid?: string;\n timestamp?: string;\n message?: {\n role?: string;\n content?: unknown;\n usage?: unknown;\n model?: string;\n };\n toolUseResult?: unknown;\n}\n\nconst PROJECTS_DIR = join(homedir(), '.claude', 'projects');\nconst DEFAULT_TITLES = new Set(['', 'New conversation', 'Nouvelle conversation']);\n\nexport async function findClaudeSessionFile(sessionId: string): Promise<string | null> {\n let entries: string[];\n try {\n entries = await readdir(PROJECTS_DIR);\n } catch {\n return null;\n }\n const filename = `${sessionId}.jsonl`;\n for (const dir of entries) {\n const candidate = join(PROJECTS_DIR, dir, filename);\n try {\n await access(candidate);\n return candidate;\n } catch {\n // try next\n }\n }\n return null;\n}\n\nexport async function claudeSessionExists(sessionId: string): Promise<boolean> {\n return (await findClaudeSessionFile(sessionId)) !== null;\n}\n\nexport async function readClaudeTranscript(sessionId: string): Promise<{\n found: boolean;\n path: string | null;\n entries: ClaudeTranscriptEntry[];\n}> {\n const path = await findClaudeSessionFile(sessionId);\n if (!path) return { found: false, path: null, entries: [] };\n const raw = await readFile(path, 'utf-8');\n const entries: ClaudeTranscriptEntry[] = [];\n for (const line of raw.split('\\n')) {\n if (!line.trim()) continue;\n try {\n entries.push(JSON.parse(line) as ClaudeTranscriptEntry);\n } catch {\n // skip malformed line\n }\n }\n return { found: true, path, entries };\n}\n\nfunction claudeEntriesToMessages(entries: ClaudeTranscriptEntry[]): Message[] {\n const messages: Message[] = [];\n const toolPartById = new Map<string, MessagePart & { type: 'tool' }>();\n\n for (const entry of entries) {\n if (entry.type !== 'user' && entry.type !== 'assistant') continue;\n const msg = entry.message;\n if (!msg) continue;\n const role: 'user' | 'assistant' =\n msg.role === 'user' || msg.role === 'assistant'\n ? msg.role\n : (entry.type as 'user' | 'assistant');\n const content = msg.content;\n\n const texts: string[] = [];\n const parts: MessagePart[] = [];\n let consumedByToolResult = false;\n\n if (typeof content === 'string') {\n texts.push(content);\n } else if (Array.isArray(content)) {\n for (const block of content) {\n if (typeof block === 'string') {\n texts.push(block);\n continue;\n }\n if (!block || typeof block !== 'object') continue;\n const b = block as {\n type?: string;\n text?: string;\n id?: string;\n name?: string;\n input?: Record<string, unknown>;\n tool_use_id?: string;\n content?: unknown;\n is_error?: boolean;\n };\n if (b.type === 'text' && typeof b.text === 'string') {\n texts.push(b.text);\n parts.push({ type: 'text', text: b.text });\n } else if (b.type === 'tool_use' && b.id) {\n const part: MessagePart & { type: 'tool' } = {\n type: 'tool',\n id: b.id,\n name: b.name ?? 'tool',\n input: b.input,\n pending: true,\n };\n parts.push(part);\n toolPartById.set(b.id, part);\n } else if (b.type === 'tool_result' && b.tool_use_id) {\n const target = toolPartById.get(b.tool_use_id);\n if (target) {\n target.result = b.content;\n target.isError = b.is_error;\n target.pending = false;\n }\n consumedByToolResult = true;\n }\n }\n }\n\n if (role === 'user' && consumedByToolResult && texts.length === 0) continue;\n\n // Merge into the previous message when it has the same role — Claude\n // emits one transcript entry per assistant turn (text / tool_use /\n // tool_result), so consecutive assistant entries are part of the same\n // logical reply and should render as one bubble.\n const last = messages[messages.length - 1];\n if (last && last.role === role) {\n const joinedText = [last.content, texts.join('\\n').trim()]\n .filter(Boolean)\n .join('\\n');\n last.content = joinedText;\n if (parts.length > 0) {\n last.parts = [...(last.parts ?? []), ...parts];\n }\n continue;\n }\n\n messages.push({\n role,\n content: texts.join('\\n').trim(),\n parts: parts.length > 0 ? parts : undefined,\n });\n }\n\n return messages;\n}\n\n/**\n * Sync a Runeya conversation with its on-disk Claude JSONL transcript.\n * Skips if nothing changed; derives title from first user message on first sync.\n * Returns true when the conversation was actually updated.\n */\nexport async function syncConversationFromClaudeTranscript(conversationId: string): Promise<boolean> {\n const conv = await conversationStore.get(conversationId);\n if (!conv) return false;\n const transcript = await readClaudeTranscript(conversationId);\n if (!transcript.found) return false;\n\n const messages = claudeEntriesToMessages(transcript.entries);\n const isDefaultTitle = !conv.title || DEFAULT_TITLES.has(conv.title);\n\n const sameLength = messages.length === conv.messages.length;\n const sameLastContent =\n sameLength && (messages.at(-1)?.content ?? '') === (conv.messages.at(-1)?.content ?? '');\n if (sameLength && sameLastContent && !isDefaultTitle) {\n return false;\n }\n\n const patch: { messages: Message[]; title?: string } = { messages };\n if (isDefaultTitle) {\n const firstUserMsg = messages.find((m) => m.role === 'user' && m.content.trim().length > 0);\n if (firstUserMsg) {\n const firstLine = firstUserMsg.content.split('\\n')[0].trim();\n patch.title = firstLine.length > 80 ? firstLine.slice(0, 80) + '…' : firstLine;\n }\n }\n\n await conversationStore.update(conversationId, patch, { touch: false });\n return true;\n}\n\n// ─── Activity tracking ─────────────────────────────────────────────────────\n\n/** Last time we observed a write to a given session's JSONL. */\nconst lastTranscriptActivity = new Map<string, number>();\n\nexport function getLastTranscriptActivity(sessionId: string): number | null {\n return lastTranscriptActivity.get(sessionId) ?? null;\n}\n\n// ─── Realtime watcher ──────────────────────────────────────────────────────\n\nlet started = false;\nconst watchers: FSWatcher[] = [];\nconst pendingResyncs = new Map<string, NodeJS.Timeout>();\nconst RESYNC_DEBOUNCE_MS = 250;\n\nfunction scheduleResync(sessionId: string): void {\n const existing = pendingResyncs.get(sessionId);\n if (existing) clearTimeout(existing);\n pendingResyncs.set(\n sessionId,\n setTimeout(() => {\n pendingResyncs.delete(sessionId);\n syncConversationFromClaudeTranscript(sessionId).catch((err) => {\n console.warn('[claude-transcript-sync] resync failed for', sessionId, err);\n });\n }, RESYNC_DEBOUNCE_MS),\n );\n}\n\nfunction handleFsEvent(filename: string | null): void {\n if (!filename) return;\n if (!filename.endsWith('.jsonl')) return;\n // filename may be \"<projectDir>/<sessionId>.jsonl\" or just \"<sessionId>.jsonl\"\n const base = filename.split('/').pop()!;\n const sessionId = base.slice(0, -'.jsonl'.length);\n if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId)) return;\n lastTranscriptActivity.set(sessionId, Date.now());\n scheduleResync(sessionId);\n}\n\n/**\n * Watch ~/.claude/projects/ recursively. Whenever a `<sessionId>.jsonl` file\n * is touched, re-sync the matching Runeya conversation (if any) so the\n * non-PTY message view stays live.\n */\nexport async function startClaudeTranscriptWatcher(): Promise<void> {\n if (started) return;\n started = true;\n\n let topLevel: string[];\n try {\n topLevel = await readdir(PROJECTS_DIR);\n } catch {\n // ~/.claude/projects doesn't exist yet — watch parent for creation.\n return;\n }\n\n // Prefer a single recursive watcher when supported, otherwise watch each\n // project dir individually.\n try {\n const w = watch(PROJECTS_DIR, { recursive: true }, (_event, filename) => {\n handleFsEvent(filename ? filename.toString() : null);\n });\n w.on('error', (err) => console.warn('[claude-transcript-sync] watcher error:', err));\n watchers.push(w);\n return;\n } catch {\n // Fallback below.\n }\n\n for (const dir of topLevel) {\n try {\n const w = watch(join(PROJECTS_DIR, dir), (_event, filename) => {\n handleFsEvent(filename ? filename.toString() : null);\n });\n w.on('error', () => {});\n watchers.push(w);\n } catch {\n // ignore\n }\n }\n}\n\nexport function stopClaudeTranscriptWatcher(): void {\n for (const w of watchers) {\n try {\n w.close();\n } catch {\n // ignore\n }\n }\n watchers.length = 0;\n for (const t of pendingResyncs.values()) clearTimeout(t);\n pendingResyncs.clear();\n started = false;\n}\n","import { readdir } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst SESSIONS_DIR = join(homedir(), '.codex', 'sessions');\n\n/**\n * Codex persists each interactive session as a rollout file:\n * ~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-<ISO>-<sessionId>.jsonl\n *\n * The app-server reuses the same session id as the rollout file, so a\n * conversation's `codexThreadId` can be passed to `codex resume <id>` — but\n * only if the rollout actually exists on disk, otherwise the CLI errors out.\n */\nasync function findCodexSessionFile(sessionId: string): Promise<string | null> {\n // Filenames end with `-<sessionId>.jsonl`; scan the date-bucketed tree.\n const suffix = `-${sessionId}.jsonl`;\n async function walk(dir: string): Promise<string | null> {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return null;\n }\n for (const entry of entries) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n const found = await walk(full);\n if (found) return found;\n } else if (entry.name.endsWith(suffix)) {\n return full;\n }\n }\n return null;\n }\n return walk(SESSIONS_DIR);\n}\n\nexport async function codexSessionExists(sessionId: string): Promise<boolean> {\n return (await findCodexSessionFile(sessionId)) !== null;\n}\n","import { z } from 'zod';\n\nexport const Id128Schema = z.string().max(128);\nexport const ConversationIdSchema = z.string().max(128);\nexport const NameSchema = z.string().min(1).max(200);\nexport const ShortString200Schema = z.string().max(200);\nexport const DescriptionSchema = z.string().max(2000);\nexport const OptionalProviderIdSchema = Id128Schema.optional();\n","import { env } from '../config/env.js';\nimport type { ApiKey, ApiServicePerm, ServiceConfig } from '@runeya/packages-shared';\n\n/**\n * Generate a llms.txt for a JWT-authenticated admin caller (full access, all services).\n * Pass a JWT so Claude Code can authenticate its HTTP calls against the Runeya API.\n */\nexport function generateAdminLlmsTxt(services: ServiceConfig[], jwt?: string): string {\n const baseUrl = `http://localhost:${env.PORT}`;\n const trpcBase = `${baseUrl}/api/trpc`;\n\n const lines: string[] = [];\n\n lines.push('# Runeya — Service Management API');\n lines.push('');\n lines.push('> You are operating as an authenticated admin with full access to all services.');\n lines.push(`> Base URL: ${trpcBase}`);\n if (jwt) {\n // Token is injected via RUNEYA_API_TOKEN env var — do not embed raw value in CLI args.\n lines.push('> Authentication: pass `Authorization: Bearer $RUNEYA_API_TOKEN` on all tRPC requests.');\n }\n lines.push('');\n\n if (services.length === 0) {\n lines.push('No services configured.');\n return lines.join('\\n');\n }\n\n lines.push('## Services');\n lines.push('');\n\n for (const svc of services) {\n lines.push(`### ${svc.name}`);\n lines.push(`- **ID**: \\`${svc.id}\\``);\n if (svc.agentId) lines.push(`- **Agent ID**: \\`${svc.agentId}\\``);\n if (svc.description) lines.push(`- **Description**: ${svc.description}`);\n if (svc.cwd) lines.push(`- **Working directory**: \\`${svc.cwd}\\``);\n lines.push('- **Permitted actions**: all');\n lines.push('');\n }\n\n lines.push('## MCP Tools');\n lines.push('');\n lines.push('You have access to Runeya MCP tools to manage services. **Always prefer MCP tools** over raw HTTP calls.');\n lines.push('Available tools: `list_services`, `get_service_status`, `start_service`, `stop_service`, `restart_service`, `get_logs`.');\n lines.push('');\n if (jwt) {\n lines.push('**Important**: Pass the `authToken` parameter with value `$RUNEYA_API_TOKEN` (from environment) on every MCP tool call for authentication.');\n lines.push('');\n }\n lines.push('Use the service IDs and agent IDs listed above when calling these tools.');\n lines.push('');\n\n lines.push('## API Reference (fallback)');\n lines.push('');\n lines.push('Only use raw HTTP calls if MCP tools are unavailable.');\n lines.push('All endpoints use tRPC v11 over HTTP (`Content-Type: application/json`).');\n lines.push('');\n lines.push('**tRPC v11 request format:**');\n lines.push('- **GET queries**: `?input={\"id\":\"abc\"}`');\n lines.push('- **POST mutations**: JSON body `{\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}`');\n lines.push('');\n lines.push(`### List services\\n\\`GET ${trpcBase}/service.list\\``);\n lines.push('');\n lines.push(`### Get service\\n\\`GET ${trpcBase}/service.get?input={\"agentId\":\"<agentId>\",\"id\":\"<serviceId>\"}\\``);\n lines.push('');\n lines.push(`### Read logs\\n\\`GET ${trpcBase}/process.logs?input={\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}\\``);\n lines.push('');\n lines.push(`### Start service\\n\\`POST ${trpcBase}/process.start\\`\\nBody: \\`{\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}\\``);\n lines.push('');\n lines.push(`### Stop service\\n\\`POST ${trpcBase}/process.stop\\`\\nBody: \\`{\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}\\``);\n lines.push('');\n lines.push(`### Restart service\\n\\`POST ${trpcBase}/process.restart\\`\\nBody: \\`{\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}\\``);\n lines.push('');\n lines.push(`### Get service status\\n\\`GET ${trpcBase}/process.status?input={\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}\\``);\n lines.push('');\n\n return lines.join('\\n');\n}\n\n/**\n * Generate a llms.txt document describing the available API endpoints\n * for this key's scopes. Services are pre-filtered by the caller.\n */\nexport function generateLlmsTxt(\n apiKey: ApiKey,\n services: ServiceConfig[],\n): string {\n const { scopes } = apiKey;\n const baseUrl = `http://localhost:${env.PORT}`;\n const trpcBase = `${baseUrl}/api/trpc`;\n\n const lines: string[] = [];\n\n lines.push('# Runeya — Service Management API');\n lines.push('');\n lines.push('> This file describes the API surface available for this key.');\n lines.push(`> Base URL: ${trpcBase}`);\n lines.push(`> Authentication: pass this key as \\`Authorization: Bearer ${apiKey.key}\\` on all tRPC requests.`);\n lines.push('');\n\n if (services.length === 0) {\n lines.push('No services accessible with this key.');\n return lines.join('\\n');\n }\n\n // Build a quick lookup: serviceId → permission\n const permByServiceId = new Map<string, ApiServicePerm>(\n scopes.services.map(p => [p.serviceId, p]),\n );\n\n // --- Services ---\n lines.push('## Services');\n lines.push('');\n\n for (const svc of services) {\n const perm = permByServiceId.get(svc.id);\n const actions = perm?.actions ?? [];\n\n lines.push(`### ${svc.name}`);\n lines.push(`- **ID**: \\`${svc.id}\\``);\n if (svc.agentId) lines.push(`- **Agent ID**: \\`${svc.agentId}\\``);\n if (svc.description) lines.push(`- **Description**: ${svc.description}`);\n if (svc.cwd) lines.push(`- **Working directory**: \\`${svc.cwd}\\``);\n\n lines.push('- **Permitted actions**:');\n if (actions.length === 0) {\n lines.push(' - _(none)_');\n } else {\n for (const a of actions) lines.push(` - \\`${a}\\``);\n }\n\n const envPerms = perm?.environments ?? [];\n if (envPerms.length > 0) {\n lines.push('- **Environment access**:');\n for (const ep of envPerms) {\n const envActions = ep.actions.join(', ');\n const secrets = ep.includeSecrets ? ' _(includes secrets)_' : '';\n lines.push(` - \\`${ep.environmentId}\\`: ${envActions}${secrets}`);\n }\n }\n\n lines.push('');\n }\n\n // --- API Reference ---\n lines.push('## API Reference');\n lines.push('');\n lines.push('All endpoints use tRPC v11 over HTTP (`Content-Type: application/json`).');\n lines.push('');\n lines.push('**Important — tRPC v11 request format:**');\n lines.push('- **GET queries**: pass input as a plain JSON-encoded string in the `input` query param (no `{\"json\":...}` wrapper).');\n lines.push(' Example: `?input={\"id\":\"abc\"}`');\n lines.push('- **POST mutations**: send the input object as a plain JSON body (no `{\"json\":...}` wrapper).');\n lines.push(' Example body: `{\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}`');\n lines.push('- The `agentId` is listed per service above.');\n lines.push('- The `processId` is the same as the service `ID` listed above.');\n lines.push('');\n\n // Collect union of actions across all services for the reference section\n const allActions = new Set(scopes.services.flatMap(p => p.actions));\n const hasEnvRead = scopes.services.some(p => p.environments.some(e => e.actions.includes('env:read')));\n const hasEnvWrite = scopes.services.some(p => p.environments.some(e => e.actions.includes('env:write')));\n\n if (allActions.has('service:read')) {\n lines.push('### List services');\n lines.push(`\\`GET ${trpcBase}/service.list\\``);\n lines.push('');\n lines.push('### Get service');\n lines.push(`\\`GET ${trpcBase}/service.get?input={\"agentId\":\"<agentId>\",\"id\":\"<serviceId>\"}\\``);\n lines.push('');\n }\n\n if (allActions.has('logs:read')) {\n lines.push('### Read logs');\n lines.push(`\\`GET ${trpcBase}/process.logs?input={\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}\\``);\n lines.push('');\n }\n\n if (allActions.has('service:start')) {\n lines.push('### Start service');\n lines.push(`\\`POST ${trpcBase}/process.start\\``);\n lines.push('Body: `{\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}`');\n lines.push('');\n }\n\n if (allActions.has('service:stop')) {\n lines.push('### Stop service');\n lines.push(`\\`POST ${trpcBase}/process.stop\\``);\n lines.push('Body: `{\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}`');\n lines.push('');\n }\n\n if (allActions.has('service:restart')) {\n lines.push('### Restart service');\n lines.push(`\\`POST ${trpcBase}/process.restart\\``);\n lines.push('Body: `{\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}`');\n lines.push('');\n }\n\n if (allActions.has('service:status')) {\n lines.push('### Get service status');\n lines.push(`\\`GET ${trpcBase}/process.status?input={\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}\\``);\n lines.push('');\n }\n\n if (allActions.has('service:healthcheck')) {\n lines.push('### Get service health');\n lines.push(`\\`GET ${trpcBase}/process.health?input={\"agentId\":\"<agentId>\",\"processId\":\"<serviceId>\"}\\``);\n lines.push('');\n }\n\n if (hasEnvRead) {\n lines.push('### Read environment variables (flat KEY=VALUE — secrets shown as *****)');\n lines.push(`\\`GET ${trpcBase}/environment.resolveFlat?input={\"environmentId\":\"<environmentId>\"}\\``);\n lines.push('Returns a flat `Record<string, string>`. Secret variables you are not authorized to see are shown as `*****`.');\n lines.push('');\n }\n\n if (hasEnvWrite) {\n lines.push('### Write environment variable');\n lines.push(`\\`POST ${trpcBase}/environment.upsertVariable\\``);\n lines.push('Body: `{\"environmentId\":\"<environmentId>\",\"key\":\"<key>\",\"value\":\"<value>\"}`');\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n","import {\n RUNEYA_CAPABILITIES,\n buildAnthropicTools,\n buildOpenAITools,\n buildToolSafetyInstruction,\n callTrpc,\n} from '@runeya/packages-ai-capabilities';\nimport type { ApiKey, ApiServiceAction } from '@runeya/packages-shared';\nimport { env } from '../config/env.js';\n\n// ─── Tool definitions (generated from capabilities) ───────────────────────────\n\nexport const CHAT_TOOLS = buildAnthropicTools(RUNEYA_CAPABILITIES);\nexport const CHAT_TOOLS_OPENAI = buildOpenAITools(RUNEYA_CAPABILITIES);\nexport const TOOL_SAFETY_INSTRUCTION = buildToolSafetyInstruction(RUNEYA_CAPABILITIES);\n\n// ─── Scope check ──────────────────────────────────────────────────────────────\n\nfunction hasServiceAction(apiKey: ApiKey | null, serviceId: string, action: ApiServiceAction): boolean {\n if (!apiKey) return true; // JWT = full access\n const perm = apiKey.scopes.services.find(p => p.serviceId === serviceId);\n return perm?.actions.includes(action) ?? false;\n}\n\n// ─── Tool name normalization ─────────────────────────────────────────────────\n// Some models (Groq, Ollama, …) hallucinate suffixes like `<|channel|>commentary`\n// after the real tool name. Match against known names to recover gracefully.\n\nconst KNOWN_TOOL_NAMES = RUNEYA_CAPABILITIES.map(c => c.name);\n\nfunction normalizeToolName(raw: string): string {\n if (KNOWN_TOOL_NAMES.includes(raw)) return raw;\n const match = KNOWN_TOOL_NAMES.find(t => raw.startsWith(t));\n return match ?? raw;\n}\n\n// ─── Tool executor — proxies to local tRPC API ────────────────────────────────\n//\n// Cloud LLMs cannot reach localhost directly, so the server acts as a proxy:\n// cloud tool_call → executeTool() → HTTP → /api/trpc/...\n//\n// This keeps the execution path identical to what runners (ClaudeCode, Codex)\n// do when they call the API themselves.\n\nexport async function executeTool(\n rawName: string,\n input: Record<string, unknown>,\n apiKey: ApiKey | null,\n authToken: string,\n): Promise<unknown> {\n const name = normalizeToolName(rawName);\n const cap = RUNEYA_CAPABILITIES.find(c => c.name === name);\n if (!cap) throw new Error(`Unknown tool: ${name}`);\n\n // Scope check for service-level actions\n const serviceId = (input['serviceId'] ?? input['id'] ?? input['processId']) as string | undefined;\n if (serviceId) {\n const actionMap: Record<string, ApiServiceAction> = {\n get_service_status: 'service:status',\n get_logs: 'logs:read',\n start_service: 'service:start',\n stop_service: 'service:stop',\n restart_service: 'service:restart',\n };\n const action = actionMap[name];\n if (action && !hasServiceAction(apiKey, serviceId, action)) {\n throw new Error(`No '${action}' permission for service ${serviceId}`);\n }\n }\n\n const params = Object.fromEntries(\n Object.entries(input).map(([k, v]) => [\n k,\n v != null ? (typeof v === 'object' ? JSON.stringify(v) : String(v as string | number | boolean | bigint)) : undefined,\n ]),\n ) as Record<string, string | undefined>;\n\n const baseUrl = `http://localhost:${env.PORT}`;\n return callTrpc(baseUrl, cap.route, cap.method, cap.buildInput(params), authToken);\n}\n","import pty from '@lydell/node-pty';\nimport { execSync } from 'child_process';\n\nexport interface CliUsageEntry {\n label: string;\n percentage: number | null;\n next_reset: string | null;\n}\n\ninterface UsageEntry {\n percent: number | null;\n resetsAt: string | null;\n}\n\ninterface ExtraUsage extends UsageEntry {\n spent: number | null;\n limit: number | null;\n}\n\ninterface ClaudeUsage {\n current_session?: UsageEntry;\n current_week_all?: UsageEntry;\n current_week_sonnet?: UsageEntry;\n extra_usage?: ExtraUsage;\n}\n\nconst MONTHS: Record<string, number> = {\n jan: 0, feb: 1, mar: 2, apr: 3, may: 4, jun: 5,\n jul: 6, aug: 7, sep: 8, oct: 9, nov: 10, dec: 11,\n};\n\nfunction parseResetsAt(str: string): string {\n const tzMatch = str.match(/\\(([^)]+)\\)/);\n const tz = tzMatch?.[1] ?? 'UTC';\n const dateStr = str.replace(/\\([^)]+\\)/, '').replaceAll('·', '').trim();\n\n const withTime = dateStr.match(/^([A-Za-z]{3})(\\d+),(\\d+)(am|pm)$/i);\n const withoutTime = dateStr.match(/^([A-Za-z]{3})(\\d+)$/i);\n // Time-only format: \"7:59am\" or \"10am\" — means today/tomorrow in the given tz\n const timeOnly = dateStr.match(/^(\\d+)(?::(\\d+))?(am|pm)$/i);\n\n let month: number, day: number, hour = 0, minute = 0; // minute used for timeOnly format\n\n const year = new Date().getFullYear();\n\n if (withTime) {\n month = MONTHS[withTime[1].toLowerCase()] ?? 0;\n day = Number.parseInt(withTime[2]);\n hour = Number.parseInt(withTime[3]);\n if (withTime[4].toLowerCase() === 'pm' && hour !== 12) hour += 12;\n if (withTime[4].toLowerCase() === 'am' && hour === 12) hour = 0;\n } else if (withoutTime) {\n month = MONTHS[withoutTime[1].toLowerCase()] ?? 0;\n day = Number.parseInt(withoutTime[2]);\n } else if (timeOnly) {\n hour = Number.parseInt(timeOnly[1]);\n minute = timeOnly[2] ? Number.parseInt(timeOnly[2]) : 0;\n if (timeOnly[3].toLowerCase() === 'pm' && hour !== 12) hour += 12;\n if (timeOnly[3].toLowerCase() === 'am' && hour === 12) hour = 0;\n // Use today's local date in the target timezone\n const now = new Date();\n const parts = new Intl.DateTimeFormat('en', { timeZone: tz, year: 'numeric', month: '2-digit', day: '2-digit' }).formatToParts(now);\n month = Number.parseInt(parts.find(p => p.type === 'month')!.value) - 1;\n day = Number.parseInt(parts.find(p => p.type === 'day')!.value);\n } else {\n return str;\n }\n const approxUtc = new Date(Date.UTC(year, month, day, hour, 0));\n const offsetStr = new Intl.DateTimeFormat('en', {\n timeZone: tz,\n timeZoneName: 'shortOffset',\n }).formatToParts(approxUtc).find(p => p.type === 'timeZoneName')?.value ?? 'GMT+0';\n\n const offsetMatch = offsetStr.match(/GMT([+-])(\\d+)(?::(\\d+))?/);\n const sign = offsetMatch?.[1] === '-' ? -1 : 1;\n const offsetMinutes = sign * (Number.parseInt(offsetMatch?.[2] ?? '0') * 60 + Number.parseInt(offsetMatch?.[3] ?? '0'));\n\n const utc = new Date(Date.UTC(year, month, day, hour, minute) - offsetMinutes * 60000);\n return utc.toISOString();\n}\n\nfunction extractSection(text: string, startPattern: RegExp, endPattern: RegExp | null): string | null {\n const start = text.search(startPattern);\n if (start === -1) return null;\n const after = text.slice(start);\n const end = endPattern ? after.search(endPattern) : after.length;\n return end === -1 ? after : after.slice(0, end);\n}\n\nfunction extractPercent(section: string | null): number | null {\n const m = section?.match(/(\\d+)%\\s*used/i);\n return m ? Number.parseInt(m[1]) : null;\n}\n\nfunction extractResets(section: string | null): string | null {\n const m = section?.match(/Rese[ts]+\\s*(.+?)(?=Current|Extra|$)/is);\n return m ? m[1].replaceAll(/\\s+/g, ' ').trim() : null;\n}\n\nfunction parse(text: string): ClaudeUsage {\n // Flatten to single line for cross-line regex matching (handles Windows ConPTY output)\n const flat = text.replaceAll('\\n', ' ').replaceAll(/\\s+/g, ' ');\n const result: ClaudeUsage = {};\n\n const sessionSec = extractSection(flat, /Current\\s*session/i, /Current\\s*week|Extra\\s*usage/i);\n if (sessionSec) {\n const resets = extractResets(sessionSec);\n result.current_session = {\n percent: extractPercent(sessionSec),\n resetsAt: resets ? parseResetsAt(resets) : null,\n };\n }\n\n const weekAllSec = extractSection(flat, /Current\\s*week\\s*\\(all\\s*models?\\)/i, /Current\\s*week\\s*\\(Sonnet/i);\n if (weekAllSec) {\n const resets = extractResets(weekAllSec);\n result.current_week_all = {\n percent: extractPercent(weekAllSec),\n resetsAt: resets ? parseResetsAt(resets) : null,\n };\n }\n\n const weekSonnetSec = extractSection(flat, /Current\\s*week\\s*\\(Sonnet\\s*only\\)/i, /Extra\\s*usage/i);\n if (weekSonnetSec) {\n const resets = extractResets(weekSonnetSec);\n result.current_week_sonnet = {\n percent: extractPercent(weekSonnetSec),\n resetsAt: resets ? parseResetsAt(resets) : null,\n };\n }\n\n const extraSec = extractSection(flat, /Extra\\s*usage(?!\\s*not)/i, null);\n if (extraSec && !/not\\s*enabled/i.test(extraSec.slice(0, 40))) {\n const spent = extraSec.match(/\\$([\\d.]+)\\s*\\/\\s*\\$([\\d.]+)\\s*spent/i);\n const resets = extractResets(extraSec);\n result.extra_usage = {\n percent: extractPercent(extraSec),\n spent: spent ? Number.parseFloat(spent[1]) : null,\n limit: spent ? Number.parseFloat(spent[2]) : null,\n resetsAt: resets ? parseResetsAt(resets) : null,\n };\n }\n\n return result;\n}\n\nfunction getClaudeUsage(): Promise<ClaudeUsage> {\n return new Promise((resolve, reject) => {\n const env = { ...process.env };\n delete env['CLAUDECODE'];\n\n let claudeBin = 'claude';\n try {\n const cmd = process.platform === 'win32' ? 'where claude' : 'which claude';\n claudeBin = execSync(cmd, { encoding: 'utf8' }).trim().split('\\n')[0].trim();\n } catch { /* fallback to 'claude' */ }\n\n let term: ReturnType<typeof pty.spawn> | null = null;\n try {\n term = pty.spawn(claudeBin, ['/usage'], {\n name: 'xterm-256color',\n cols: 200,\n rows: 40,\n env,\n });\n } catch (err) {\n reject(err);\n return;\n }\n\n let buffer = '';\n let done = false;\n let debounce: ReturnType<typeof setTimeout> | null = null;\n\n function finish() {\n if (done) return;\n done = true;\n if (debounce) clearTimeout(debounce);\n clearTimeout(hardTimeout);\n term?.kill();\n const clean = buffer\n .replaceAll(/\\x1b\\[[0-9;]*X/g, '\\n') // ECH separators on Windows ConPTY\n .replaceAll(/\\x1b\\[[0-9;]*[mGKHFABCDJsu]/g, '')\n .replaceAll(/\\x1b[^a-zA-Z]*[a-zA-Z]/g, '')\n .replaceAll('\\r', '');\n resolve(parse(clean));\n }\n\n const hardTimeout = setTimeout(() => {\n if (!done) finish();\n }, 15_000);\n\n term.onData((data: string) => {\n buffer += data;\n // Start debounce only after actual usage data has arrived\n if (buffer.includes('%')) {\n if (debounce) clearTimeout(debounce);\n debounce = setTimeout(finish, 800);\n }\n });\n\n term.onExit(() => {\n finish();\n });\n });\n}\n\nexport async function getClaudeUsageEntries(): Promise<CliUsageEntry[]> {\n const usage = await getClaudeUsage();\n const entries: CliUsageEntry[] = [];\n\n if (usage.current_session) {\n entries.push({\n label: 'Session',\n percentage: usage.current_session.percent,\n next_reset: usage.current_session.resetsAt,\n });\n }\n\n if (usage.current_week_all) {\n entries.push({\n label: 'Week',\n percentage: usage.current_week_all.percent,\n next_reset: usage.current_week_all.resetsAt,\n });\n }\n\n if (usage.current_week_sonnet) {\n entries.push({\n label: 'Sonnet',\n percentage: usage.current_week_sonnet.percent,\n next_reset: usage.current_week_sonnet.resetsAt,\n });\n }\n\n if (usage.extra_usage) {\n entries.push({\n label: 'Extra',\n percentage: usage.extra_usage.percent,\n next_reset: usage.extra_usage.resetsAt,\n });\n }\n\n return entries;\n}\n","import pty from '@lydell/node-pty';\nimport type { CliUsageEntry } from './claude-usage.js';\n\nconst MONTHS: Record<string, number> = {\n jan: 0, feb: 1, mar: 2, apr: 3, may: 4, jun: 5,\n jul: 6, aug: 7, sep: 8, oct: 9, nov: 10, dec: 11,\n};\n\nfunction parseResetToIso(raw: string): string | null {\n const value = raw\n .replace(/^\\(*/, '')\n .replace(/\\)*$/, '')\n .replace(/^resets?\\s*/i, '')\n .trim();\n\n const now = new Date();\n\n const timeOnly = value.match(/^(\\d{1,2}):(\\d{2})$/);\n if (timeOnly) {\n const hour = Number.parseInt(timeOnly[1], 10);\n const minute = Number.parseInt(timeOnly[2], 10);\n const date = new Date(now);\n date.setHours(hour, minute, 0, 0);\n if (date.getTime() <= now.getTime()) {\n date.setDate(date.getDate() + 1);\n }\n return date.toISOString();\n }\n\n const withDate = value.match(/^(\\d{1,2}):(\\d{2})\\s+on\\s+(\\d{1,2})\\s+([A-Za-z]{3})$/i);\n if (withDate) {\n const hour = Number.parseInt(withDate[1], 10);\n const minute = Number.parseInt(withDate[2], 10);\n const day = Number.parseInt(withDate[3], 10);\n const month = MONTHS[withDate[4].toLowerCase()];\n if (month === undefined) return null;\n\n let year = now.getFullYear();\n let date = new Date(year, month, day, hour, minute, 0, 0);\n if (date.getTime() <= now.getTime()) {\n year += 1;\n date = new Date(year, month, day, hour, minute, 0, 0);\n }\n return date.toISOString();\n }\n\n return null;\n}\n\nfunction stripAnsi(text: string): string {\n return text\n .replace(/[\\u001b\\u009b][[\\]()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '')\n .replaceAll('\\r', '');\n}\n\nexport function parseCodexStatusText(text: string): CliUsageEntry[] {\n const clean = stripAnsi(text);\n const normalizedLines = clean\n .replace(/[│╭╰╮╯─]/g, ' ')\n .split('\\n')\n .map((line) => line.replace(/\\s+/g, ' ').trim())\n .filter(Boolean);\n\n const entries: CliUsageEntry[] = [];\n let pendingIndex: number | null = null;\n\n for (const line of normalizedLines) {\n const sameLine = line.match(/^(.+?limit)\\s*:\\s*(?:\\[[^\\]]*\\]\\s*)?(\\d+)%\\s*left(?:\\s*\\((?:resets?\\s+)?([^)]+)\\))?$/i);\n if (sameLine) {\n const label = sameLine[1].trim();\n const left = Number.parseInt(sameLine[2], 10);\n const used = Number.isNaN(left) ? null : Math.max(0, Math.min(100, 100 - left));\n const nextReset = sameLine[3] ? (parseResetToIso(sameLine[3]) ?? null) : null;\n entries.push({ label, percentage: used, next_reset: nextReset });\n pendingIndex = nextReset ? null : entries.length - 1;\n continue;\n }\n\n const splitReset = line.match(/^\\(?\\s*resets?\\s+([^)]+)\\)?$/i);\n if (splitReset && pendingIndex !== null) {\n entries[pendingIndex].next_reset = parseResetToIso(splitReset[1]) ?? null;\n pendingIndex = null;\n }\n }\n\n if (entries.length === 0) {\n // Fallback: parse statusline format \"· X% left\" emitted by codex bottom bar\n // e.g. \"gpt-5.4 default · 43% left · ~/Projects/runeya-rust\"\n const statuslineMatch = clean.match(/·\\s*(\\d+)%\\s*left/i);\n if (statuslineMatch) {\n const left = Number.parseInt(statuslineMatch[1], 10);\n const used = Number.isNaN(left) ? null : Math.max(0, Math.min(100, 100 - left));\n entries.push({ label: 'Usage', percentage: used, next_reset: null });\n }\n }\n\n return entries;\n}\n\nexport function getCodexUsageEntries(): Promise<CliUsageEntry[]> {\n return new Promise((resolve, reject) => {\n let term: ReturnType<typeof pty.spawn> | null = null;\n try {\n term = pty.spawn('codex', [], {\n name: 'xterm-256color',\n cols: 220,\n rows: 40,\n env: process.env,\n });\n } catch (err) {\n reject(err);\n return;\n }\n\n let buffer = '';\n let done = false;\n const queuedInputs = ['/status', '/status', '/status', '/exit'];\n let queuedIndex = 0;\n let inputDrainDebounce: ReturnType<typeof setTimeout> | null = null;\n let promptSeen = false;\n\n const finish = () => {\n if (done) return;\n done = true;\n if (inputDrainDebounce) clearTimeout(inputDrainDebounce);\n clearTimeout(initialTrigger);\n clearTimeout(hardTimeout);\n term?.kill();\n if (process.env['CODEX_USAGE_DEBUG'] === '1') {\n const debugClean = stripAnsi(buffer).slice(-6000);\n process.stdout.write('[codex-usage] raw tail:\\n' + debugClean + '\\n');\n }\n resolve(parseCodexStatusText(buffer));\n };\n\n const hardTimeout = setTimeout(() => {\n finish();\n }, 25_000);\n\n const sendNextInputIfReady = () => {\n if (done) return;\n if (!promptSeen) return;\n if (queuedIndex >= queuedInputs.length) return;\n const value = queuedInputs[queuedIndex];\n queuedIndex += 1;\n promptSeen = false;\n term?.write(`${value}\\r`);\n };\n\n const initialTrigger = setTimeout(() => {\n promptSeen = true;\n sendNextInputIfReady();\n }, 6_000);\n\n term.onData((data: string) => {\n buffer += data;\n if (data.includes('\\x1b[6n')) {\n // Answer DSR (cursor position report), matching pty-runner behavior.\n term?.write('\\x1b[25;1R');\n }\n\n if (data.includes('›')) {\n promptSeen = true;\n }\n\n if (inputDrainDebounce) clearTimeout(inputDrainDebounce);\n inputDrainDebounce = setTimeout(sendNextInputIfReady, 120);\n\n if (/(\\d+)\\s*h\\s+limit\\s*:/i.test(buffer) && /weekly\\s+limit\\s*:/i.test(buffer)) {\n setTimeout(finish, 800);\n }\n\n // Codex hasn't loaded limits yet — no point waiting the full 25s\n if (/data not available yet/i.test(buffer) && queuedIndex >= queuedInputs.length - 1) {\n setTimeout(finish, 400);\n }\n });\n\n term.onExit(() => {\n clearTimeout(initialTrigger);\n finish();\n });\n });\n}\n","import type { ChildProcess } from 'node:child_process';\nimport { conversationStore } from './conversation-store.js';\nimport { agentManager } from './agent-manager.js';\n\ntype SessionPart =\n | { type: 'thinking'; text: string }\n | { type: 'text'; text: string }\n | { type: 'tool'; id: string; name: string; input?: Record<string, unknown>; rawInput?: string; result?: unknown; isError?: boolean; pending: boolean };\n\n// ─── Types ─────────────────────────────────────────────────────────────────\n\nexport type QueueItem =\n | { type: 'delta'; text: string }\n | { type: 'status'; text: string }\n | { type: 'thinking'; text: string }\n | { type: 'context_usage'; inputTokens: number; contextWindow: number }\n | { type: 'tool_call'; id: string; name: string; input: Record<string, unknown>; rawInput?: string }\n | { type: 'tool_result'; id: string; name: string; result: unknown; isError: boolean }\n | { type: 'done'; text: '' }\n | { type: 'error'; message: string };\n\ntype AiRunnerType = 'claude-code' | 'provider-api';\n\nexport interface ActiveSession {\n proc: ChildProcess | null;\n abortController: AbortController | null;\n sessionType: AiRunnerType;\n conversationId: string;\n buffer: QueueItem[];\n totalProduced: number;\n fullContent: string;\n parts: SessionPart[];\n lastStatus: string;\n status: 'running' | 'done';\n persistTimer: ReturnType<typeof setTimeout> | null;\n cleanupTimer: ReturnType<typeof setTimeout> | null;\n notify: Set<() => void>;\n /** Agent ID when the AI CLI runs on a remote agent. */\n agentId?: string;\n /** Spawn ID on the remote agent (for kill / reconnect). */\n agentSpawnId?: string;\n}\n\n// ─── Constants ─────────────────────────────────────────────────────────────\n\nconst MAX_BUFFER = 5_000;\nconst PERSIST_DEBOUNCE_MS = 100;\n\n// ─── Registry ──────────────────────────────────────────────────────────────\n\nclass ActiveSessionRegistry {\n private sessions = new Map<string, ActiveSession>();\n\n registerClaudeCodeSession(conversationId: string, proc: ChildProcess): ActiveSession {\n this.assertNoActiveSession(conversationId);\n\n const session: ActiveSession = {\n proc,\n abortController: null,\n sessionType: 'claude-code',\n conversationId,\n buffer: [],\n totalProduced: 0,\n fullContent: '',\n parts: [],\n lastStatus: '',\n status: 'running',\n persistTimer: null,\n cleanupTimer: null,\n notify: new Set(),\n };\n\n this.sessions.set(conversationId, session);\n return session;\n }\n\n registerProviderApiSession(conversationId: string, ac: AbortController): ActiveSession {\n this.assertNoActiveSession(conversationId);\n\n const session: ActiveSession = {\n proc: null,\n abortController: ac,\n sessionType: 'provider-api',\n conversationId,\n buffer: [],\n totalProduced: 0,\n fullContent: '',\n parts: [],\n lastStatus: '',\n status: 'running',\n persistTimer: null,\n cleanupTimer: null,\n notify: new Set(),\n };\n\n this.sessions.set(conversationId, session);\n return session;\n }\n\n registerDirectProviderApiSession(conversationId: string): ActiveSession {\n this.assertNoActiveSession(conversationId);\n\n const session: ActiveSession = {\n proc: null,\n abortController: new AbortController(),\n sessionType: 'provider-api',\n conversationId,\n buffer: [],\n totalProduced: 0,\n fullContent: '',\n parts: [],\n lastStatus: '',\n status: 'running',\n persistTimer: null,\n cleanupTimer: null,\n notify: new Set(),\n };\n\n this.sessions.set(conversationId, session);\n return session;\n }\n\n private assertNoActiveSession(conversationId: string): void {\n const existing = this.sessions.get(conversationId);\n if (existing && existing.status === 'running') {\n throw new Error(`A session is already running for conversation ${conversationId}. Stop it first.`);\n }\n }\n\n pushEvent(conversationId: string, event: QueueItem): void {\n if(process.env.RUNEYA_DEBUG) console.log('[chat]: event - ', event.type)\n const session = this.sessions.get(conversationId);\n if (!session) return;\n if(process.env.RUNEYA_DEBUG) console.log('[chat]: event - ', event.type, 'session', session.conversationId)\n\n // Accumulate parts for replay/persist\n if (event.type === 'delta') {\n session.fullContent += event.text;\n const last = session.parts[session.parts.length - 1];\n if (last?.type === 'text') last.text += event.text;\n else session.parts.push({ type: 'text', text: event.text });\n this.schedulePersist(session);\n }\n if (event.type === 'tool_call') {\n const existing = session.parts.find(p => p.type === 'tool' && p.id === event.id) as Extract<SessionPart, { type: 'tool' }> | undefined;\n if (existing) { existing.name = event.name; existing.input = event.input; }\n else session.parts.push({ type: 'tool', id: event.id, name: event.name, input: event.input, rawInput: event.rawInput, pending: true });\n this.schedulePersist(session);\n }\n if (event.type === 'tool_result') {\n const te = session.parts.find(p => p.type === 'tool' && p.id === event.id) as Extract<SessionPart, { type: 'tool' }> | undefined;\n if (te) {\n te.result = event.result;\n te.isError = event.isError;\n te.pending = false;\n } else {\n session.parts.push({ type: 'tool', id: event.id, name: event.name, result: event.result, isError: event.isError, pending: false });\n }\n this.schedulePersist(session);\n }\n if (event.type === 'thinking') {\n const last = session.parts[session.parts.length - 1];\n if (last?.type === 'thinking') last.text += event.text;\n else session.parts.push({ type: 'thinking', text: event.text });\n }\n if (event.type === 'status') {\n session.lastStatus = event.text;\n }\n\n // Cap buffer size — drop oldest if full\n if (session.buffer.length >= MAX_BUFFER) {\n session.buffer.shift();\n }\n if(process.env.RUNEYA_DEBUG) console.log('[chat]: event - ', event.type, 'push buffer')\n session.buffer.push(event);\n session.totalProduced++;\n\n // Wake all consumers (multiple tabs/windows)\n if(process.env.RUNEYA_DEBUG) console.log('[chat]: event - ', event.type, 'notify', session.notify.size)\n for (const cb of session.notify) cb();\n session.notify.clear();\n }\n\n markDone(conversationId: string): void {\n if(process.env.RUNEYA_DEBUG) console.log('[chat]: markdone....', conversationId)\n const session = this.sessions.get(conversationId);\n if (!session) return;\n\n session.status = 'done';\n\n // Persist final content immediately\n this.persistNow(session);\n }\n\n get(conversationId: string): ActiveSession | undefined {\n return this.sessions.get(conversationId);\n }\n\n listActive(): { conversationId: string; status: 'running' | 'done'; sessionType: AiRunnerType }[] {\n const result: { conversationId: string; status: 'running' | 'done'; sessionType: AiRunnerType }[] = [];\n for (const session of this.sessions.values()) {\n result.push({ conversationId: session.conversationId, status: session.status, sessionType: session.sessionType });\n }\n return result;\n }\n\n kill(conversationId: string): boolean {\n const session = this.sessions.get(conversationId);\n if (!session) return false;\n\n if (session.status === 'running') {\n // Remote agent kill\n if (session.agentId && session.agentSpawnId) {\n agentManager.agentMutation(session.agentId, 'ai.kill', { spawnId: session.agentSpawnId }).catch(() => { /* best-effort */ });\n }\n if (session.proc) {\n try { session.proc.kill(); } catch { /* already dead */ }\n }\n if (session.abortController) {\n session.abortController.abort();\n }\n }\n return true;\n }\n\n // ── Internal helpers ────────────────────────────────────────────────────\n\n private schedulePersist(session: ActiveSession): void {\n if (session.persistTimer) return;\n session.persistTimer = setTimeout(() => {\n session.persistTimer = null;\n this.persistNow(session);\n }, PERSIST_DEBOUNCE_MS);\n }\n\n private persistNow(session: ActiveSession): void {\n if (session.persistTimer) {\n clearTimeout(session.persistTimer);\n session.persistTimer = null;\n }\n\n const fullContent = session.fullContent;\n const parts = session.parts.length > 0 ? [...session.parts] : undefined;\n // Synchronous mutation + async save — avoids the async get()→.then() race where a\n // debounced partial-persist .then() could run after a markDone full-persist .then()\n // and overwrite the complete content with stale partial content.\n conversationStore.updateLastAssistantContent(session.conversationId, fullContent, parts);\n }\n\n private cleanupTimers(session: ActiveSession): void {\n if (session.persistTimer) {\n clearTimeout(session.persistTimer);\n session.persistTimer = null;\n }\n if (session.cleanupTimer) {\n clearTimeout(session.cleanupTimer);\n session.cleanupTimer = null;\n }\n }\n}\n\nexport const activeSessionRegistry = new ActiveSessionRegistry();\n","import { settingsManager } from './settings-manager.js';\nimport { ScenarioSchema } from '@runeya/packages-shared';\nimport type { Scenario, ScenarioNode } from '@runeya/packages-shared';\n\nfunction normalizeNode(raw: ScenarioNode & { parentId?: string | null }): ScenarioNode {\n const aiCli = raw.aiCli ?? 'claude-code';\n const defaultModel = aiCli === 'codex' ? '' : 'sonnet';\n // Migrate legacy parentId → parentIds\n let parentIds = raw.parentIds ?? [];\n if (raw.parentId && !parentIds.includes(raw.parentId)) {\n parentIds = [raw.parentId, ...parentIds];\n }\n return {\n ...raw,\n parentIds,\n groupId: raw.groupId ?? null,\n label: raw.label?.trim() ?? '',\n prompt: raw.prompt ?? '',\n autoGenerated: raw.autoGenerated ?? true,\n canAddNode: raw.canAddNode ?? false,\n aiCli,\n model: raw.model?.trim() || defaultModel,\n };\n}\n\n/**\n * `vault` désigne l'organisation dont on lit les scénarios — ils décrivent ses\n * services, donc ils lui appartiennent. Absent : ceux du poste, pour un projet\n * local qui n'est l'affaire de personne d'autre.\n */\nclass ScenarioStore {\n async list(vault?: string): Promise<Scenario[]> {\n const [settings, priv] = await Promise.all([\n settingsManager.getSettings(vault),\n settingsManager.getPrivateSettings(vault),\n ]);\n return [...(settings.scenarios ?? []), ...(priv.scenarios ?? [])];\n }\n\n async get(id: string, vault?: string): Promise<Scenario | null> {\n const list = await this.list(vault);\n return list.find((e) => e.id === id) ?? null;\n }\n\n async create(scenario: Scenario, vault?: string): Promise<Scenario> {\n const normalized = this.normalizeScenario(scenario);\n const parsed = ScenarioSchema.parse(normalized);\n this.validateHierarchy(parsed);\n\n if (parsed.isPublished) {\n const settings = await settingsManager.getSettings(vault);\n await settingsManager.saveSettings({ ...settings, scenarios: [...(settings.scenarios ?? []), parsed] }, vault);\n } else {\n const priv = await settingsManager.getPrivateSettings(vault);\n await settingsManager.savePrivateSettings({ ...priv, scenarios: [...(priv.scenarios ?? []), parsed] }, vault);\n }\n\n return parsed;\n }\n\n async update(id: string, patch: Partial<Scenario>, vault?: string): Promise<Scenario | null> {\n const [settings, priv] = await Promise.all([\n settingsManager.getSettings(vault),\n settingsManager.getPrivateSettings(vault),\n ]);\n\n const publicScenarios = [...(settings.scenarios ?? [])];\n const privateScenarios = [...(priv.scenarios ?? [])];\n\n const publicIdx = publicScenarios.findIndex((e) => e.id === id);\n const privateIdx = privateScenarios.findIndex((e) => e.id === id);\n\n const existing = publicIdx !== -1 ? publicScenarios[publicIdx] : privateIdx !== -1 ? privateScenarios[privateIdx] : null;\n if (!existing) return null;\n\n const merged = { ...existing, ...patch, id, updatedAt: Date.now() } as Scenario;\n const normalized = this.normalizeScenario(merged);\n const parsed = ScenarioSchema.parse(normalized);\n this.validateHierarchy(parsed);\n\n const wasPublic = publicIdx !== -1;\n const isNowPublic = parsed.isPublished;\n\n if (wasPublic && isNowPublic) {\n publicScenarios[publicIdx] = parsed;\n await settingsManager.saveSettings({ ...settings, scenarios: publicScenarios }, vault);\n } else if (!wasPublic && !isNowPublic) {\n privateScenarios[privateIdx] = parsed;\n await settingsManager.savePrivateSettings({ ...priv, scenarios: privateScenarios }, vault);\n } else if (wasPublic && !isNowPublic) {\n // moved public → private\n publicScenarios.splice(publicIdx, 1);\n await Promise.all([\n settingsManager.saveSettings({ ...settings, scenarios: publicScenarios }, vault),\n settingsManager.savePrivateSettings({ ...priv, scenarios: [...privateScenarios, parsed] }, vault),\n ]);\n } else {\n // moved private → public\n privateScenarios.splice(privateIdx, 1);\n await Promise.all([\n settingsManager.savePrivateSettings({ ...priv, scenarios: privateScenarios }, vault),\n settingsManager.saveSettings({ ...settings, scenarios: [...publicScenarios, parsed] }, vault),\n ]);\n }\n\n return parsed;\n }\n\n async delete(id: string, vault?: string): Promise<boolean> {\n const [settings, priv] = await Promise.all([\n settingsManager.getSettings(vault),\n settingsManager.getPrivateSettings(vault),\n ]);\n\n const publicFiltered = (settings.scenarios ?? []).filter((e) => e.id !== id);\n const privateFiltered = (priv.scenarios ?? []).filter((e) => e.id !== id);\n\n const removedFromPublic = publicFiltered.length < (settings.scenarios ?? []).length;\n const removedFromPrivate = privateFiltered.length < (priv.scenarios ?? []).length;\n\n if (!removedFromPublic && !removedFromPrivate) return false;\n\n await Promise.all([\n removedFromPublic ? settingsManager.saveSettings({ ...settings, scenarios: publicFiltered }, vault) : Promise.resolve(),\n removedFromPrivate ? settingsManager.savePrivateSettings({ ...priv, scenarios: privateFiltered }, vault) : Promise.resolve(),\n ]);\n\n return true;\n }\n\n private normalizeScenario(scenario: Scenario): Scenario {\n const nodes = scenario.nodes.map((p) => normalizeNode(p));\n let leaderId = scenario.leaderId;\n if (!nodes.some((p) => p.id === leaderId)) {\n leaderId = nodes[0]?.id ?? leaderId;\n }\n\n return {\n ...scenario,\n leaderId,\n groups: scenario.groups ?? [],\n nodes,\n };\n }\n\n private validateHierarchy(scenario: Scenario): void {\n const groupIds = new Set<string>();\n for (const group of scenario.groups) {\n if (groupIds.has(group.id)) {\n throw new Error(`Duplicate group id: ${group.id}`);\n }\n groupIds.add(group.id);\n }\n\n const nodeIds = new Set<string>();\n for (const node of scenario.nodes) {\n if (nodeIds.has(node.id)) {\n throw new Error(`Duplicate node id: ${node.id}`);\n }\n nodeIds.add(node.id);\n }\n\n const nodesById = new Map(scenario.nodes.map((p) => [p.id, p]));\n if (!nodesById.has(scenario.leaderId)) {\n throw new Error('Leader must be a valid node in the scenario');\n }\n\n for (const node of scenario.nodes) {\n for (const pid of (node.parentIds ?? [])) {\n if (!nodesById.has(pid)) {\n throw new Error(`Node ${node.id} references unknown parent ${pid}`);\n }\n if (node.id === pid) {\n throw new Error(`Node ${node.id} cannot be their own parent`);\n }\n }\n if (node.groupId && !groupIds.has(node.groupId)) {\n throw new Error(`Node ${node.id} references unknown group ${node.groupId}`);\n }\n }\n\n const visited = new Set<string>();\n const inPath = new Set<string>();\n\n const walk = (nodeId: string): void => {\n if (inPath.has(nodeId)) throw new Error('Scenario hierarchy contains a cycle');\n if (visited.has(nodeId)) return;\n inPath.add(nodeId);\n const node = nodesById.get(nodeId);\n for (const pid of (node?.parentIds ?? [])) walk(pid);\n inPath.delete(nodeId);\n visited.add(nodeId);\n };\n\n for (const p of scenario.nodes) walk(p.id);\n }\n}\n\nexport const scenarioStore = new ScenarioStore();\n","import { mkdir, rm, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Scenario } from '@runeya/packages-shared';\nimport {\n atomicWriteJsonSecure,\n atomicWriteSecure,\n readJsonFileSafe,\n resolveConversationRunDir,\n} from './run-store-utils.js';\n\nfunction sanitizeSlug(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 60) || 'member';\n}\n\nfunction sanitizeFilePart(value: string, fallback: string): string {\n const sanitized = value\n .toLowerCase()\n .replace(/[^a-z0-9_-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 80);\n return sanitized || fallback;\n}\n\nexport type NodeState = 'idle' | 'running' | 'waiting' | 'waiting_input' | 'done' | 'synthesized' | 'error';\n\nexport interface RunState {\n nodeStates: Record<string, NodeState>;\n nodeOutputs: Record<string, string>;\n /** Claude Code session ID per node — used by the debug PTY drawer (--resume). */\n nodeSessionIds: Record<string, string>;\n /** Agent that ran each node (needed to spawn the resume PTY on the right host). */\n nodeAgentIds: Record<string, string>;\n activeNodeId?: string;\n waitingInputs: Record<string, string>;\n}\n\nexport interface PersistedRunState {\n nodeStates: Record<string, NodeState>;\n nodeOutputs: Record<string, string>;\n nodeSessionIds?: Record<string, string>;\n nodeAgentIds?: Record<string, string>;\n waitingInputs?: Record<string, string>;\n}\n\nclass ScenarioRunStore {\n private static readonly SCENARIO_SNAPSHOT_FILE = 'SCENARIO.json';\n private activeRuns = new Map<string, RunState>();\n\n private getRunDir(conversationId: string): string {\n return resolveConversationRunDir('scenario-runs', conversationId);\n }\n\n async initializeConversationWorkspace(conversationId: string, scenario: Scenario, userInput: string): Promise<void> {\n const dir = this.getRunDir(conversationId);\n await mkdir(dir, { recursive: true });\n await this.saveScenarioSnapshot(conversationId, scenario);\n\n const nodesById = new Map(scenario.nodes.map((p) => [p.id, p]));\n\n const teamMap = new Map(scenario.groups.map((t) => [t.id, t.name]));\n const leader = nodesById.get(scenario.leaderId) ?? scenario.nodes[0];\n\n const overview = [\n `# Scenario Conversation Workspace`,\n '',\n `- Scenario: ${scenario.name}`,\n `- Conversation ID: ${conversationId}`,\n `- Leader: ${leader?.label ?? ''}`,\n '',\n '## Members',\n ...scenario.nodes.map((p) => {\n const parent = p.parentIds[0] ? nodesById.get(p.parentIds[0]) : null;\n const group = p.groupId ? (teamMap.get(p.groupId) ?? p.groupId) : 'No group';\n return `- ${p.label} (${p.id}) | Group: ${group} | Reports to: ${parent ? parent.label : 'None'}`;\n }),\n '',\n '## Rules',\n '- Every node writes in their own markdown file.',\n '- Responses should be sent back to the requester.',\n '- Use read-only references from linked upstream files as context.',\n '',\n ].join('\\n');\n\n await atomicWriteSecure(join(dir, 'README.md'), overview);\n await atomicWriteSecure(join(dir, 'USER_REQUEST.md'), `# User request\\n\\n${userInput.trim() || '(empty)'}\\n`);\n\n for (const node of scenario.nodes) {\n const nodeName = node.label.trim();\n const safeNodeId = sanitizeFilePart(node.id, 'node');\n const fileName = `${sanitizeSlug(nodeName || node.id)}_${safeNodeId}.md`;\n const parent = node.parentIds[0] ? nodesById.get(node.parentIds[0]) : null;\n const reports = scenario.nodes.filter((p) => p.parentIds[0] === node.id);\n const teamName = node.groupId ? (teamMap.get(node.groupId) ?? node.groupId) : 'No group';\n const content = [\n `# ${nodeName || node.id}`,\n '',\n `- ID: ${node.id}`,\n `- Group: ${teamName}`,\n `- Reports to: ${parent ? parent.label : 'None'}`,\n `- Manages: ${reports.length ? reports.map((r) => r.label).join(', ') : 'No direct reports'}`,\n '',\n '## Prompt',\n node.prompt || '(No prompt defined)',\n '',\n '## Work Log',\n '- Waiting for assignment.',\n '',\n ].join('\\n');\n await atomicWriteSecure(join(dir, fileName), content);\n }\n }\n\n async deleteRunDir(conversationId: string): Promise<void> {\n await rm(this.getRunDir(conversationId), { recursive: true, force: true });\n this.activeRuns.delete(conversationId);\n }\n\n private ensureRunState(conversationId: string): RunState {\n let runState = this.activeRuns.get(conversationId);\n if (!runState) {\n runState = { nodeStates: {}, nodeOutputs: {}, nodeSessionIds: {}, nodeAgentIds: {}, waitingInputs: {} };\n this.activeRuns.set(conversationId, runState);\n }\n return runState;\n }\n\n setNodeSession(conversationId: string, nodeId: string, sessionId: string, agentId: string): void {\n const rs = this.ensureRunState(conversationId);\n rs.nodeSessionIds[nodeId] = sessionId;\n rs.nodeAgentIds[nodeId] = agentId;\n }\n\n getNodeSession(conversationId: string, nodeId: string): { sessionId: string; agentId: string } | null {\n const rs = this.activeRuns.get(conversationId);\n const sessionId = rs?.nodeSessionIds[nodeId];\n const agentId = rs?.nodeAgentIds[nodeId];\n if (sessionId && agentId) return { sessionId, agentId };\n return null;\n }\n\n async getNodeSessionPersistent(conversationId: string, nodeId: string): Promise<{ sessionId: string; agentId: string } | null> {\n const live = this.getNodeSession(conversationId, nodeId);\n if (live) return live;\n const persisted = await this.loadPersistedRunState(conversationId);\n const sessionId = persisted?.nodeSessionIds?.[nodeId];\n const agentId = persisted?.nodeAgentIds?.[nodeId];\n if (sessionId && agentId) return { sessionId, agentId };\n return null;\n }\n\n setNodeState(conversationId: string, nodeId: string, state: NodeState): void {\n this.ensureRunState(conversationId).nodeStates[nodeId] = state;\n }\n\n setNodeOutput(conversationId: string, nodeId: string, output: string): void {\n this.ensureRunState(conversationId).nodeOutputs[nodeId] = output;\n }\n\n setActiveNodeId(conversationId: string, nodeId?: string): void {\n this.ensureRunState(conversationId).activeNodeId = nodeId;\n }\n\n setWaitingInput(conversationId: string, nodeId: string, question: string): void {\n this.ensureRunState(conversationId).waitingInputs[nodeId] = question;\n }\n\n clearWaitingInput(conversationId: string, nodeId: string): void {\n const runState = this.activeRuns.get(conversationId);\n if (runState?.waitingInputs) delete runState.waitingInputs[nodeId];\n }\n\n getRunState(conversationId: string): RunState | null {\n return this.activeRuns.get(conversationId) ?? null;\n }\n\n async persistRunState(conversationId: string): Promise<void> {\n const runState = this.activeRuns.get(conversationId);\n if (!runState) return;\n try {\n const dir = this.getRunDir(conversationId);\n await mkdir(dir, { recursive: true });\n const data: PersistedRunState = {\n nodeStates: { ...runState.nodeStates },\n nodeOutputs: { ...runState.nodeOutputs },\n ...(Object.keys(runState.nodeSessionIds).length > 0 ? { nodeSessionIds: { ...runState.nodeSessionIds } } : {}),\n ...(Object.keys(runState.nodeAgentIds).length > 0 ? { nodeAgentIds: { ...runState.nodeAgentIds } } : {}),\n ...(Object.keys(runState.waitingInputs).length > 0 ? { waitingInputs: { ...runState.waitingInputs } } : {}),\n };\n await atomicWriteJsonSecure(join(dir, 'run-state.json'), data);\n } catch {\n // Non-fatal\n }\n }\n\n async loadPersistedRunState(conversationId: string): Promise<PersistedRunState | null> {\n const dir = this.getRunDir(conversationId);\n return readJsonFileSafe<PersistedRunState>(join(dir, 'run-state.json'));\n }\n\n async readUserRequest(conversationId: string): Promise<string | null> {\n try {\n const dir = this.getRunDir(conversationId);\n const content = await readFile(join(dir, 'USER_REQUEST.md'), 'utf-8');\n return content.replace(/^#\\s*User request\\s*\\n+/, '').trim() || null;\n } catch {\n return null;\n }\n }\n\n async readReadme(conversationId: string): Promise<string | null> {\n try {\n const dir = this.getRunDir(conversationId);\n return await readFile(join(dir, 'README.md'), 'utf-8');\n } catch {\n return null;\n }\n }\n\n async saveScenarioSnapshot(conversationId: string, scenario: Scenario): Promise<void> {\n const dir = this.getRunDir(conversationId);\n await mkdir(dir, { recursive: true });\n await atomicWriteJsonSecure(\n join(dir, ScenarioRunStore.SCENARIO_SNAPSHOT_FILE),\n scenario,\n true,\n );\n }\n\n async loadScenarioSnapshot(conversationId: string): Promise<Scenario | null> {\n const dir = this.getRunDir(conversationId);\n return readJsonFileSafe<Scenario>(join(dir, ScenarioRunStore.SCENARIO_SNAPSHOT_FILE));\n }\n}\n\nexport const scenarioRunStore = new ScenarioRunStore();\n","import { chmod, mkdir, rename, writeFile, readFile } from 'node:fs/promises';\nimport { dirname, resolve, sep } from 'node:path';\nimport { machineRoot } from './vault-resolver.js';\n\nconst SAFE_PATH_SEGMENT_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/;\n\nexport function resolveConversationRunDir(rootDirName: string, conversationId: string): string {\n if (!SAFE_PATH_SEGMENT_RE.test(conversationId)) {\n throw new Error('Invalid conversationId');\n }\n // Machine-wide, like the conversations these runs belong to: using the launch\n // directory would put a `.runeya` in a repository just for asking the AI a\n // question about a cloud project.\n const base = resolve(machineRoot(), rootDirName);\n const dir = resolve(base, conversationId);\n if (!dir.startsWith(base + sep)) {\n throw new Error('Invalid conversationId');\n }\n return dir;\n}\n\nexport async function atomicWriteSecure(filePath: string, content: string): Promise<void> {\n await mkdir(dirname(filePath), { recursive: true });\n const tmpPath = `${filePath}.tmp`;\n await writeFile(tmpPath, content, 'utf-8');\n await rename(tmpPath, filePath);\n await chmod(filePath, 0o600);\n}\n\nexport async function atomicWriteJsonSecure(filePath: string, data: unknown, pretty = false): Promise<void> {\n await atomicWriteSecure(filePath, JSON.stringify(data, null, pretty ? 2 : 0));\n}\n\nexport async function readJsonFileSafe<T>(filePath: string): Promise<T | null> {\n try {\n const raw = await readFile(filePath, 'utf-8');\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n}\n","import Anthropic from '@anthropic-ai/sdk';\nimport OpenAI from 'openai';\nimport type { AIProvider } from '@runeya/packages-shared';\nimport { settingsManager } from './settings-manager.js';\nimport { decryptValue } from './crypto-helpers.js';\n\nexport const OPENAI_COMPAT_BASE_URLS: Record<string, string> = {\n openai: 'https://api.openai.com/v1',\n groq: 'https://api.groq.com/openai/v1',\n mistral: 'https://api.mistral.ai/v1',\n ollama: 'http://localhost:11434/v1',\n};\n\nexport const DEFAULT_MODELS: Record<string, string> = {\n anthropic: 'claude-opus-4-6',\n openai: 'gpt-4o',\n groq: 'llama-3.3-70b-versatile',\n mistral: 'mistral-large-latest',\n ollama: 'llama3',\n};\n\n/**\n * Le fournisseur actif de l'organisation concernée.\n *\n * `vault` est son identifiant, ou l'absence pour les réglages du poste — un\n * projet local n'appartenant à personne d'autre. La clé d'API est déchiffrée\n * par la clé de ce coffre : c'est ce qui permet à une équipe de partager le\n * fournisseur qu'elle paie sans partager la clé de chacune de ses machines.\n */\nexport async function getActiveProvider(\n providerId?: string,\n vault?: string,\n): Promise<{ provider: AIProvider; plaintextKey: string } | null> {\n const priv = await settingsManager.getPrivateSettings(vault);\n const providers = priv.aiProviders ?? [];\n const selected = providerId\n ? providers.find((p: AIProvider) => p.id === providerId)\n : providers.find((p: AIProvider) => p.active);\n if (!selected) return null;\n const plaintextKey = selected.encryptedApiKey ? decryptValue(selected.encryptedApiKey, vault) : '';\n return { provider: selected, plaintextKey };\n}\n\nexport async function fetchProviderModels(provider: AIProvider, plaintextKey: string): Promise<string[]> {\n if (provider.provider === 'anthropic') {\n const client = new Anthropic({ apiKey: plaintextKey });\n const res = await client.models.list();\n return res.data.map(m => m.id).sort((a, b) => a.localeCompare(b));\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.models.list();\n return res.data.map(m => m.id).sort((a, b) => a.localeCompare(b));\n }\n\n return [];\n}\n","import { randomUUID } from 'node:crypto';\nimport { mkdir, writeFile, readFile, unlink, readdir } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { join, extname, resolve, sep } from 'node:path';\nimport { machineRoot } from './vault-resolver.js';\n\nexport const ALLOWED_MIME_TYPES = new Set([\n 'image/png',\n 'image/jpeg',\n 'image/webp',\n 'image/gif',\n]);\n\nconst ALLOWED_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.webp', '.gif']);\nexport const MAX_IMAGE_SIZE_BYTES = 5 * 1024 * 1024; // 5 MB\nexport const IMAGE_TTL_MS = 24 * 60 * 60 * 1000; // 24h\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nexport interface StoredImage {\n imageId: string;\n filePath: string;\n mimeType: string;\n originalName: string;\n createdAt: number;\n /** Optional tag for grouping (e.g. conversationId, kanban cardId) */\n contextId?: string;\n}\n\nexport class ImageStorageService {\n private dir: string;\n\n constructor(dir: string) {\n this.dir = dir;\n }\n\n async ensureTmpDir(): Promise<void> {\n await mkdir(this.dir, { recursive: true, mode: 0o700 });\n }\n\n async saveImage(buffer: Buffer, originalName: string, mimeType: string, contextId?: string): Promise<StoredImage> {\n if (!ALLOWED_MIME_TYPES.has(mimeType)) {\n throw new Error(`Unsupported MIME type: ${mimeType}. Allowed: ${[...ALLOWED_MIME_TYPES].join(', ')}`);\n }\n if (buffer.length > MAX_IMAGE_SIZE_BYTES) {\n throw new Error(`Image too large: ${buffer.length} bytes (max ${MAX_IMAGE_SIZE_BYTES})`);\n }\n if (!checkMagicBytes(buffer, mimeType)) {\n throw new Error('File content does not match declared MIME type');\n }\n\n const ext = extname(originalName).toLowerCase() || mimeToExt(mimeType);\n if (!ALLOWED_EXTENSIONS.has(ext)) {\n throw new Error(`Unsupported extension: ${ext}`);\n }\n\n await this.ensureTmpDir();\n\n const imageId = randomUUID();\n const safeExt = ext.replace(/[^a-z.]/g, '');\n const fileName = `${imageId}${safeExt}`;\n const filePath = join(this.dir, fileName);\n const resolvedPath = resolve(filePath);\n const resolvedDir = resolve(this.dir);\n if (resolvedPath !== resolvedDir && !resolvedPath.startsWith(resolvedDir + sep)) {\n throw new Error('Invalid file path');\n }\n\n await writeFile(filePath, buffer, { mode: 0o600 });\n const meta: StoredImage = { imageId, filePath, mimeType, originalName, createdAt: Date.now(), contextId };\n await writeFile(`${filePath}.meta.json`, JSON.stringify(meta), { encoding: 'utf-8', mode: 0o600 });\n return meta;\n }\n\n /**\n * Resolve an image on disk.\n *\n * `expectedContextId` scopes the lookup: when given, an image stored under a\n * different context (or under none at all) is reported as missing. Callers\n * that serve an image through a context-scoped URL MUST pass it — the id\n * alone is not an authorization, and without the check any imageId could be\n * fetched under any conversation.\n */\n async getImagePath(\n imageId: string,\n expectedContextId?: string,\n ): Promise<{ filePath: string; mimeType: string; contextId?: string } | null> {\n if (!UUID_RE.test(imageId)) return null;\n try {\n const files = await readdir(this.dir);\n const metaFile = files.find(f => f.startsWith(imageId) && f.endsWith('.meta.json'));\n if (!metaFile) return null;\n const raw = JSON.parse(await readFile(join(this.dir, metaFile), 'utf-8')) as StoredImage;\n if (expectedContextId !== undefined && raw.contextId !== expectedContextId) return null;\n if (!existsSync(raw.filePath)) return null;\n return { filePath: raw.filePath, mimeType: raw.mimeType, contextId: raw.contextId };\n } catch {\n return null;\n }\n }\n\n async deleteImage(imageId: string): Promise<void> {\n const result = await this.getImagePath(imageId);\n if (!result) return;\n await unlink(result.filePath).catch(() => {});\n await unlink(`${result.filePath}.meta.json`).catch(() => {});\n }\n\n async deleteByContextId(contextId: string): Promise<void> {\n let files: string[];\n try {\n files = await readdir(this.dir);\n } catch {\n return;\n }\n await Promise.all(\n files\n .filter(f => f.endsWith('.meta.json'))\n .map(async (file) => {\n try {\n const raw = JSON.parse(await readFile(join(this.dir, file), 'utf-8')) as StoredImage;\n if (raw.contextId === contextId) {\n await unlink(raw.filePath).catch(() => {});\n await unlink(`${raw.filePath}.meta.json`).catch(() => {});\n }\n } catch {\n // skip malformed\n }\n }),\n );\n }\n\n async readImageAsBase64(imageId: string, expectedContextId?: string): Promise<{ base64: string; mimeType: string } | null> {\n const result = await this.getImagePath(imageId, expectedContextId);\n if (!result) return null;\n const buffer = await readFile(result.filePath);\n return { base64: buffer.toString('base64'), mimeType: result.mimeType };\n }\n\n async listExpiredImages(ttlMs = IMAGE_TTL_MS): Promise<StoredImage[]> {\n const expired: StoredImage[] = [];\n let files: string[];\n try {\n files = await readdir(this.dir);\n } catch {\n return [];\n }\n const now = Date.now();\n for (const file of files) {\n if (!file.endsWith('.meta.json')) continue;\n try {\n const raw = JSON.parse(await readFile(join(this.dir, file), 'utf-8')) as StoredImage;\n if (now - raw.createdAt > ttlMs) expired.push(raw);\n } catch {\n // skip malformed\n }\n }\n return expired;\n }\n}\n\nlet _singleton: ImageStorageService | undefined;\nfunction getSingleton(): ImageStorageService {\n if (!_singleton) {\n // Images pasted into a chat belong to the machine, not to a project: the\n // conversations they illustrate are machine-wide, and a cloud-only session\n // must not grow a `.runeya` in the directory it was started from.\n _singleton = new ImageStorageService(resolve(machineRoot(), 'images'));\n }\n return _singleton;\n}\nexport const imageStorageService = new Proxy({} as ImageStorageService, {\n get(_target, prop: string | symbol) {\n const svc = getSingleton();\n const val = (svc as unknown as Record<string | symbol, unknown>)[prop];\n return typeof val === 'function' ? (val as (...args: unknown[]) => unknown).bind(svc) : val;\n },\n});\n\nfunction checkMagicBytes(buf: Buffer, mime: string): boolean {\n if (buf.length < 12) return false;\n switch (mime) {\n case 'image/png':\n return buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4E && buf[3] === 0x47;\n case 'image/jpeg':\n return buf[0] === 0xFF && buf[1] === 0xD8 && buf[2] === 0xFF;\n case 'image/gif':\n return buf.slice(0, 6).toString('ascii') === 'GIF87a' || buf.slice(0, 6).toString('ascii') === 'GIF89a';\n case 'image/webp':\n return buf.slice(0, 4).toString('ascii') === 'RIFF' && buf.slice(8, 12).toString('ascii') === 'WEBP';\n default:\n return false;\n }\n}\n\nfunction mimeToExt(mime: string): string {\n const map: Record<string, string> = {\n 'image/png': '.png',\n 'image/jpeg': '.jpg',\n 'image/webp': '.webp',\n 'image/gif': '.gif',\n };\n return map[mime] ?? '.bin';\n}\n","import { imageStorageService } from './image-storage.service.js';\n\nexport interface MessageImageRef {\n imageId: string;\n mimeType: string;\n altText?: string;\n}\n\n/**\n * Extracts all image parts from a message's parts array.\n * Parts come from the stored conversation messages.\n */\nexport function extractImagesFromMessage(parts: Array<{ type: string; [key: string]: unknown }>): MessageImageRef[] {\n const images: MessageImageRef[] = [];\n for (const part of parts) {\n if (\n part['type'] === 'image' &&\n typeof part['imageId'] === 'string' &&\n typeof part['mimeType'] === 'string'\n ) {\n images.push({\n imageId: part['imageId'] as string,\n mimeType: part['mimeType'] as string,\n altText: typeof part['altText'] === 'string' ? part['altText'] : undefined,\n });\n }\n }\n return images;\n}\n\n/**\n * Resolves a single image ref to base64, returning null if not found.\n *\n * `contextId` scopes the lookup to the conversation the image was uploaded\n * under; ids that belong elsewhere resolve to null.\n */\nexport async function resolveImageToBase64(\n imageId: string,\n contextId?: string,\n): Promise<{ base64: string; mimeType: string } | null> {\n return imageStorageService.readImageAsBase64(imageId, contextId);\n}\n\n/**\n * Resolves all image refs to base64, skipping missing ones (with a warning).\n *\n * `contextId` scopes the lookup — see `resolveImageToBase64`.\n */\nexport async function resolveImagesToBase64(\n images: MessageImageRef[],\n contextId?: string,\n): Promise<Array<{ imageId: string; base64: string; mimeType: string; altText?: string }>> {\n const results = await Promise.all(\n images.map(async (img) => {\n const resolved = await imageStorageService.readImageAsBase64(img.imageId, contextId);\n if (!resolved) {\n console.warn('[message-images] Image not found (imageId redacted from log)');\n return null;\n }\n return { imageId: img.imageId, base64: resolved.base64, mimeType: resolved.mimeType, altText: img.altText };\n }),\n );\n return results.filter((r): r is NonNullable<typeof r> => r !== null);\n}\n","import { z } from 'zod';\nimport { hostname } from 'node:os';\nimport { basename } from 'node:path';\nimport { TRPCError } from '@trpc/server';\nimport { router, protectedProcedure } from '../trpc.js';\nimport { cloudSessionStore } from '../../services/cloud-session-store.js';\nimport { env } from '../../config/env.js';\nimport { lanIps } from '../../services/lan-mode.js';\nimport {\n getCloudApiUrl,\n getCloudAppUrl,\n cloudFetch as callCloud,\n CloudNotLinkedError,\n} from '../../services/cloud-api.js';\n\n// Le bridge de sync en a besoin aussi, et un service ne doit pas importer un\n// routeur : l'implémentation vit dans `services/cloud-api.ts`, réexportée ici\n// pour tout ce qui appelait déjà depuis les routeurs.\nexport { getCloudApiUrl };\n\n/**\n * The label this machine carries in the cloud's \"linked machines\" screen.\n *\n * The hostname alone is ambiguous once a host runs several instances — which is\n * the whole point of separate data dirs — so a non-default data dir is appended.\n * `RUNEYA_DEVICE_NAME` overrides both.\n */\nexport function getDeviceName(): string {\n if (env.DEVICE_NAME) return env.DEVICE_NAME.slice(0, 64);\n const host = hostname() || 'runeya';\n const dir = basename(env.DATA_DIR);\n const suffix = dir && dir !== '.runeya' ? ` · ${dir}` : '';\n return `${host}${suffix}`.slice(0, 64);\n}\n\n/**\n * Où le navigateur a le droit de revenir — et donc où poser le callback.\n *\n * `returnTo` vient de l'interface : sans liste close, cette route deviendrait\n * une redirection ouverte. La boucle locale est toujours acceptée.\n *\n * En mode LAN, l'onglet qui pilote Runeya est sur une IP de cette machine, pas\n * sur `localhost` : refuser cette origine revenait à exposer toute l'app au\n * réseau sauf l'écran de connexion. On accepte donc aussi les adresses des\n * interfaces de CETTE machine, sur le port du serveur — la même règle que le\n * CSRF applique déjà. La liste reste calculée ici, jamais déduite de ce que le\n * client annonce.\n *\n * Le callback suit l'origine retenue : figé sur `127.0.0.1`, il renvoyait la\n * tablette vers sa propre boucle locale, où il n'y a rien. RFC 8252 §7.3\n * n'ignore le port que pour les IP littérales, jamais pour le nom « localhost » —\n * d'où le port explicite dans les deux cas.\n */\nexport function callbackForReturnTo(url: string): string | null {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return null;\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return null;\n\n const { hostname, port } = parsed;\n if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]') {\n return `http://127.0.0.1:${env.PORT}/api/cloud/callback`;\n }\n if (!env.RUNEYA_LAN_PROXY) return null;\n\n const effectivePort = port || (parsed.protocol === 'https:' ? '443' : '80');\n if (effectivePort !== String(env.PORT)) return null;\n if (!lanIps().includes(hostname)) return null;\n return `${parsed.origin}/api/cloud/callback`;\n}\n\n/**\n * Calls the cloud API on behalf of this machine's stored session token.\n *\n * This is the only place a cloud call is authenticated: the token never leaves\n * the server, so the browser holds no cloud credential at all.\n */\nexport async function cloudFetch(\n path: string,\n init: { method?: string; body?: unknown; timeoutMs?: number } = {},\n): Promise<Response> {\n try {\n return await callCloud(path, init);\n } catch (err) {\n if (!(err instanceof CloudNotLinkedError)) throw err;\n // Deliberately NOT UNAUTHORIZED: tRPC would turn that into a 401, which the\n // web client reads as \"the local session died\" — it would then drop a\n // perfectly valid JWT and bounce the user back to the unlock page. Having no\n // cloud link is a state of this machine, not a verdict on the caller.\n throw new TRPCError({ code: 'PRECONDITION_FAILED', message: err.message });\n }\n}\n\n/**\n * Cloud endpoints the web UI may reach through this proxy.\n *\n * An allowlist, not a passthrough: the proxy speaks with this machine's cloud\n * token, so an unconstrained `path` would let any caller drive the whole cloud\n * API (including sign-out or account changes) with our credential.\n */\nconst PROXY_PREFIXES = ['/organization/', '/project/', '/chat/', '/kanban/', '/user/prefs'];\n\nfunction isAllowedProxyPath(path: string): boolean {\n if (!path.startsWith('/') || path.includes('..')) return false;\n const [pathname] = path.split('?');\n return PROXY_PREFIXES.some((p) => pathname === p || pathname.startsWith(p));\n}\n\n/** One row of the \"linked machines\" list, as the cloud returns it. */\nexport interface CloudDevice {\n id: string;\n name: string;\n kind: 'device' | 'browser';\n current: boolean;\n createdAt: string;\n lastSeenAt: string;\n expiresAt: string;\n ipAddress: string | null;\n}\n\n/**\n * Cloud account link for this machine.\n *\n * The browser authorizes on the cloud origin (its session cookie is same-site\n * there, so it just works), and hands back a single-use token that this server\n * exchanges for a session token. Nothing cloud-related is ever authenticated\n * from the browser, which is why the cloud can refuse localhost origins.\n */\nexport const cloudAuthRouter = router({\n /** Build the cloud authorization URL to open in the browser. */\n startLogin: protectedProcedure\n .input(z.object({ returnTo: z.string().url().max(2048) }))\n .mutation(async ({ input }) => {\n const callback = callbackForReturnTo(input.returnTo);\n if (!callback) {\n throw new TRPCError({\n code: 'BAD_REQUEST',\n message: env.RUNEYA_LAN_PROXY\n ? 'returnTo must be this machine, on the server port.'\n : 'returnTo must be a local origin.',\n });\n }\n const state = cloudSessionStore.createState(input.returnTo);\n const url = `${getCloudAppUrl()}/link-local`\n + `?callback=${encodeURIComponent(callback)}`\n + `&state=${encodeURIComponent(state)}`;\n return { url };\n }),\n\n /** Whether this machine holds a cloud session, and against which cloud. */\n status: protectedProcedure.query(async () => {\n const linked = await cloudSessionStore.isLinked();\n return { linked, cloudUrl: linked ? await cloudSessionStore.getCloudUrl() : null };\n }),\n\n /** The cloud session (user + org), fetched with the stored token. */\n session: protectedProcedure.query(async () => {\n if (!(await cloudSessionStore.isLinked())) return null;\n const res = await cloudFetch('/api/auth/get-session');\n if (!res.ok) {\n // 401 means the session backing this machine is gone — revoked from\n // another machine, or expired. Forget it, so the UI offers a fresh link\n // instead of a link that silently fails on every call.\n if (res.status === 401) await cloudSessionStore.clear();\n return null;\n }\n return (await res.json()) as unknown;\n }),\n\n /**\n * Every session of the cloud account: the machines linked to it and the\n * browsers signed into it. No token material — the cloud only ever returns\n * ids and labels here.\n */\n devices: protectedProcedure.query(async () => {\n if (!(await cloudSessionStore.isLinked())) return { devices: [] as CloudDevice[] };\n const res = await cloudFetch('/api/auth/device/list');\n if (!res.ok) {\n if (res.status === 401) await cloudSessionStore.clear();\n return { devices: [] as CloudDevice[] };\n }\n return (await res.json()) as { devices: CloudDevice[] };\n }),\n\n /**\n * Revoke one session of the cloud account.\n *\n * Revoking THIS machine is allowed and is the honest way to unlink: the cloud\n * drops the session, and the local token is dropped here too, so nothing is\n * left holding a dead credential.\n */\n revokeDevice: protectedProcedure\n .input(z.object({ id: z.string().min(1).max(128) }))\n .mutation(async ({ input }) => {\n const res = await cloudFetch('/api/auth/device/revoke', { method: 'POST', body: { id: input.id } });\n if (!res.ok) {\n if (res.status === 401) await cloudSessionStore.clear();\n throw new TRPCError({ code: 'BAD_REQUEST', message: 'Could not revoke this session.' });\n }\n const { self } = (await res.json()) as { self?: boolean };\n if (self) await cloudSessionStore.clear();\n return { success: true as const, self: self === true };\n }),\n\n /**\n * Forward a cloud API call, authenticated with this machine's token.\n *\n * This is what replaces the browser's direct, cookie-authenticated calls to\n * the cloud: the web UI asks its own server, which holds the credential.\n */\n proxy: protectedProcedure\n .input(\n z.object({\n path: z.string().min(1).max(512),\n method: z.enum(['GET', 'POST']).default('GET'),\n query: z.record(z.string().max(128), z.string().max(2048)).optional(),\n body: z.unknown().optional(),\n }),\n )\n .mutation(async ({ input }) => {\n if (!isAllowedProxyPath(input.path)) {\n throw new TRPCError({ code: 'FORBIDDEN', message: `Path not allowed: ${input.path}` });\n }\n const qs = input.query ? `?${new URLSearchParams(input.query).toString()}` : '';\n const res = await cloudFetch(`/api/auth${input.path}${qs}`, {\n method: input.method,\n ...(input.method === 'POST' ? { body: input.body ?? {} } : {}),\n });\n const text = await res.text();\n let data: unknown = null;\n try {\n data = text ? JSON.parse(text) : null;\n } catch {\n data = text;\n }\n // Mirrors Better Auth's client shape ({ data } / { error }) so callers can\n // keep the same handling they had when they talked to the cloud directly.\n if (!res.ok) return { data: null, error: { status: res.status, ...(data as object) } };\n return { data, error: null };\n }),\n\n /**\n * Unlink this machine: drop the session here and on the cloud.\n *\n * Since the machine holds a session of its own, this no longer touches the\n * browser's session — signing out here leaves the web app signed in, and vice\n * versa.\n */\n signOut: protectedProcedure.mutation(async () => {\n if (await cloudSessionStore.isLinked()) {\n try {\n await cloudFetch('/api/auth/sign-out', { method: 'POST', body: {} });\n } catch {\n // Revoking server-side is best-effort — forget the token regardless.\n }\n }\n await cloudSessionStore.clear();\n return { success: true as const };\n }),\n});\n","import type {\n KanbanBoard,\n KanbanCard,\n KanbanCardEvent,\n KanbanCardLink,\n KanbanCardRef,\n CreateKanbanBoardInput,\n UpdateKanbanBoardInput,\n} from '@runeya/packages-shared';\nimport { cloudFetch } from '../trpc/routers/cloud-auth.js';\n\n/**\n * Kanban boards, read and written on the Runeya cloud.\n *\n * Boards belong to an organization, not to a machine: they are shared with the\n * team and gated on a paid plan, so there is no local copy and no local file.\n * This module keeps the store-shaped API its callers (the MCP kanban commands,\n * the AI queue, the chat router) were already written against — only the\n * backing store moved.\n *\n * Every call goes through `cloudFetch`, which attaches this machine's cloud\n * token. A machine that is not linked to the cloud therefore has no boards at\n * all: reads come back empty and writes report failure, rather than silently\n * accumulating work nobody else will ever see.\n */\n\n/** A cloud board, as the API serializes it. */\ninterface CloudBoard extends KanbanBoard {\n organizationId: string;\n}\n\ninterface CloudCall<T> {\n ok: boolean;\n data: T | null;\n /** Pourquoi l'appel a échoué — vide quand il a réussi. */\n reason: string | null;\n /**\n * Le code HTTP, quand il y en a eu un. Ce qui permet de distinguer « ce cloud\n * ne connaît pas cette route » (404) d'un refus — un cloud auto-hébergé plus\n * ancien que cette app n'a pas forcément les routes qu'elle a apprises.\n */\n status: number | null;\n}\n\n/**\n * Un tableau introuvable et un cloud qui refuse de répondre ne se ressemblent\n * pas, mais rendaient tous deux une liste vide.\n *\n * C'est ce qui a coûté le plus cher : un agent annonçait « aucun tableau » avec\n * aplomb alors que la question n'avait jamais atteint le cloud. Une lecture qui\n * échoue lève désormais, avec la raison ; seule une vraie absence rend du vide.\n */\nexport class KanbanUnavailableError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'KanbanUnavailableError';\n }\n}\n\nfunction planGateMessage(status: number, path: string): string {\n if (status === 402 || status === 403) {\n return `Le cloud a refusé l'accès aux tableaux (HTTP ${status}) : le plan de l'organisation ne le permet pas, ou ce compte n'y a pas droit.`;\n }\n if (status === 426) {\n return 'Le cloud refuse cette version de Runeya (HTTP 426) : mettez l\\'application à jour.';\n }\n return `Le cloud a répondu HTTP ${status} sur ${path}.`;\n}\n\nasync function callCloud<T>(path: string, init: { method?: string; body?: unknown } = {}): Promise<CloudCall<T>> {\n try {\n const res = await cloudFetch(`/api/auth${path}`, init);\n if (!res.ok) {\n // 402/403 here is the plan gate (Solo is read-only) — worth surfacing,\n // since the caller is usually an AI agent whose write just vanished.\n console.error('[kanban-store] cloud call failed: %s %s', res.status, path);\n return { ok: false, data: null, reason: planGateMessage(res.status, path), status: res.status };\n }\n return { ok: true, data: (await res.json()) as T, reason: null, status: res.status };\n } catch (err) {\n console.error('[kanban-store] cloud call errored:', err);\n return { ok: false, data: null, reason: `Appel au cloud impossible : ${(err as Error).message}`, status: null };\n }\n}\n\n/** Lecture obligatoire : ce qui n'a pas abouti ne doit pas passer pour du vide. */\nfunction must<T>(res: CloudCall<T>): T {\n if (!res.ok || res.data === null) {\n throw new KanbanUnavailableError(res.reason ?? 'Le cloud n\\'a pas répondu.');\n }\n return res.data;\n}\n\n/**\n * L'organisation dont on lit les tableaux.\n *\n * Dans l'ordre : celle que l'appelant nomme, puis celle que porte la session\n * cloud de cette machine, puis — et seulement si le compte n'en a qu'une — la\n * sienne. Au-delà, on refuse de choisir.\n *\n * L'ancien repli prenait « la première de la liste ». Le sélecteur du web agit\n * sur la session du NAVIGATEUR, pas sur celle de la machine : les deux vues\n * divergeaient donc en silence, et un compte à plusieurs organisations voyait\n * les tableaux d'une autre — ou rien du tout, sans que rien ne le dise.\n *\n * Résolu à chaque appel plutôt que mis en cache : changer d'organisation prend\n * effet aussitôt.\n */\nasync function resolveOrganizationId(explicit?: string): Promise<string> {\n if (explicit) return explicit;\n\n const session = await callCloud<{ session?: { activeOrganizationId?: string | null } }>('/get-session');\n const active = session.data?.session?.activeOrganizationId;\n if (active) return active;\n\n const orgs = must(await callCloud<{ id: string; name?: string }[]>('/organization/list'));\n if (orgs.length === 1) return orgs[0]!.id;\n if (orgs.length === 0) {\n throw new KanbanUnavailableError(\n \"Ce compte cloud n'appartient à aucune organisation : il n'y a aucun tableau à lire.\",\n );\n }\n\n const listed = orgs.map((o) => `${o.name ?? '(sans nom)'} — ${o.id}`).join(', ');\n throw new KanbanUnavailableError(\n `Ce compte appartient à ${orgs.length} organisations et la session de cette machine n'en désigne aucune comme active. `\n + `Précisez organizationId parmi : ${listed}.`,\n );\n}\n\nclass KanbanStore {\n /**\n * Les tableaux d'une organisation, et laquelle a répondu.\n *\n * L'organisation fait partie du résultat parce qu'elle faisait partie du\n * problème : une liste vide ne disait pas à qui la question avait été posée.\n */\n async list(\n includeArchived = false,\n organizationId?: string,\n ): Promise<{ organizationId: string; boards: KanbanBoard[] }> {\n const orgId = await resolveOrganizationId(organizationId);\n const query = `?organizationId=${encodeURIComponent(orgId)}`\n + (includeArchived ? '&includeArchived=true' : '');\n const res = must(await callCloud<{ boards: KanbanBoard[] }>(`/kanban/board/list${query}`));\n return { organizationId: orgId, boards: res.boards ?? [] };\n }\n\n /**\n * Un tableau. Sans les journaux de ses cartes par défaut : c'est la moitié\n * lourde du document, et presque aucun appelant n'en a besoin — un agent qui\n * liste des cartes ne lit pas les commentaires. `withHistory` les redemande\n * pour les rares cas qui les veulent tous d'un coup.\n */\n async get(id: string, opts: { withHistory?: boolean } = {}): Promise<KanbanBoard | null> {\n const query = `?id=${encodeURIComponent(id)}${opts.withHistory ? '&withHistory=true' : ''}`;\n // `must` : un cloud muet lève, alors qu'un `board` absent de la réponse est\n // une vraie réponse — ce tableau n'existe pas.\n const res = must(await callCloud<{ board: CloudBoard | null }>(`/kanban/board/get${query}`));\n return res.board ?? null;\n }\n\n /** Le journal d'une seule carte — ce que le contexte d'un agent demande. */\n async cardHistory(boardId: string, cardId: string): Promise<KanbanCardEvent[]> {\n const res = await callCloud<{ history: KanbanCardEvent[] }>(\n `/kanban/card/history?boardId=${encodeURIComponent(boardId)}&cardId=${encodeURIComponent(cardId)}`,\n );\n return res.data?.history ?? [];\n }\n\n /**\n * Commenter une carte, sans réécrire le tableau.\n *\n * C'est le geste que l'IA répète le plus, et souvent avec de longs textes :\n * le faire passer par une sauvegarde de tableau faisait transiter tout le\n * graphe de cartes à chaque phrase.\n */\n async addComment(\n boardId: string,\n cardId: string,\n detail: string,\n conversationId?: string,\n ): Promise<boolean> {\n const res = await callCloud<{ event: KanbanCardEvent }>('/kanban/card/comment/add', {\n method: 'POST',\n body: { boardId, cardId, detail, author: 'ai', ...(conversationId ? { conversationId } : {}) },\n });\n return res.ok;\n }\n\n /** Poser une entrée de journal non-commentaire (une conversation qui s'ouvre). */\n async addCardEvent(\n boardId: string,\n cardId: string,\n type: 'conversation_started' | 'scenario_started',\n detail?: string,\n ): Promise<boolean> {\n const res = await callCloud<{ event: KanbanCardEvent }>('/kanban/card/event/add', {\n method: 'POST',\n body: { boardId, cardId, type, detail },\n });\n return res.ok;\n }\n\n /**\n * Ajouter une carte, sans réécrire le tableau.\n *\n * La colonne se nomme par son titre : c'est ce que connaît une IA qui lit un\n * tableau, et le cloud le résout. Deux ajouts qui se croisent se rangent tous\n * les deux, ce qu'une sauvegarde de tableau entier ne garantissait pas.\n */\n async addCard(\n boardId: string,\n input: { column: string; title: string; markdown?: string },\n ): Promise<{ card: KanbanCard | null; unsupported: boolean }> {\n const res = await callCloud<{ card: KanbanCard }>('/kanban/card/add', {\n method: 'POST',\n body: { boardId, ...input },\n });\n // Un cloud qui ne connaît pas la route n'est pas un cloud qui refuse : il est\n // plus ancien que cette app. L'appelant a de quoi se rabattre, et le dire est\n // ce qui l'en rend capable.\n return { card: res.data?.card ?? null, unsupported: res.status === 404 };\n }\n\n /** Une carte, par son identifiant — archivée comprise. */\n async card(boardId: string, cardId: string): Promise<{ card: KanbanCard; columnId: string } | null> {\n const res = await callCloud<{ card: KanbanCard; columnId: string }>(\n `/kanban/card/get?boardId=${encodeURIComponent(boardId)}&cardId=${encodeURIComponent(cardId)}`,\n );\n return res.data ?? null;\n }\n\n /**\n * Modifier une carte.\n *\n * L'absence d'un champ ne le touche pas ; `null` l'efface. C'est le contrat du\n * cloud, et le distinguer ici évite qu'un agent vide une couleur en voulant\n * simplement changer un titre.\n */\n async updateCard(\n boardId: string,\n cardId: string,\n patch: Record<string, unknown>,\n ): Promise<KanbanCard | null> {\n const res = await callCloud<{ card: KanbanCard }>('/kanban/card/update', {\n method: 'POST',\n body: { boardId, cardId, ...patch },\n });\n return res.data?.card ?? null;\n }\n\n /** Ranger une carte, ou la reprendre. */\n async setCardArchived(boardId: string, cardId: string, archived: boolean): Promise<boolean> {\n const res = await callCloud(`/kanban/card/${archived ? 'archive' : 'unarchive'}`, {\n method: 'POST',\n body: { boardId, cardId },\n });\n return res.ok;\n }\n\n /**\n * Les membres de l'organisation — sans quoi assigner reviendrait à deviner\n * un identifiant.\n */\n async members(organizationId?: string): Promise<{ id: string; name: string; email: string }[]> {\n const orgId = await resolveOrganizationId(organizationId);\n // Better Auth n'a pas de route « les membres » : c'est l'organisation\n // entière qui les porte. Les écrans du cloud lisent la même.\n const res = must(\n await callCloud<{ members?: { userId: string; user?: { name?: string; email?: string } }[] }>(\n `/organization/get-full-organization?organizationId=${encodeURIComponent(orgId)}`,\n ),\n );\n return (res.members ?? []).map((m) => ({\n id: m.userId,\n name: m.user?.name?.trim() || m.user?.email || m.userId,\n email: m.user?.email ?? '',\n }));\n }\n\n /**\n * Chercher des cartes — dans le cloud, pas ici.\n *\n * Cette recherche téléchargeait autrefois **tous les tableaux** de\n * l'organisation, entiers, pour filtrer ensuite en mémoire sur le titre et le\n * corps. Elle coûtait donc le poids du kanban complet à chaque appel, ne\n * voyait pas les commentaires — ils ne voyagent plus avec le tableau — et\n * ignorait les cartes rangées, absentes des colonnes.\n *\n * Le cloud fait la même recherche que ses propres écrans : titre, corps et\n * commentaires, sans casse ni accents.\n */\n async searchCards(input: {\n query: string;\n boardId?: string;\n limit?: number;\n organizationId?: string;\n }): Promise<{ cards: Record<string, unknown>[]; total: number; truncated: boolean }> {\n const orgId = await resolveOrganizationId(input.organizationId);\n const query = new URLSearchParams({ organizationId: orgId, q: input.query });\n if (input.boardId) query.set('boardId', input.boardId);\n if (input.limit) query.set('limit', String(input.limit));\n const res = must(\n await callCloud<{ cards: Record<string, unknown>[]; total: number; truncated: boolean }>(\n `/kanban/card/search?${query.toString()}`,\n ),\n );\n return { cards: res.cards ?? [], total: res.total ?? 0, truncated: Boolean(res.truncated) };\n }\n\n /** Déplacer une carte, sans réécrire le tableau. */\n async moveCard(boardId: string, cardId: string, toColumnId: string): Promise<boolean> {\n const res = await callCloud<{ board: CloudBoard }>('/kanban/card/move', {\n method: 'POST',\n body: { boardId, cardId, toColumnId },\n });\n return res.ok;\n }\n\n /**\n * La filiation des cartes d'un tableau, dans les deux sens.\n *\n * Elle vit hors du tableau — une sauvegarde de tableau ne la transporte pas —\n * donc elle se demande à part. `cards` nomme les cartes liées qui vivent sur\n * un autre tableau ; celles d'ici sont déjà dans le tableau.\n */\n async cardLinks(boardId: string): Promise<{ links: KanbanCardLink[]; cards: KanbanCardRef[] }> {\n const res = await callCloud<{ links: KanbanCardLink[]; cards: KanbanCardRef[] }>(\n `/kanban/card-link/list?boardId=${encodeURIComponent(boardId)}`,\n );\n return { links: res.data?.links ?? [], cards: res.data?.cards ?? [] };\n }\n\n /**\n * Rattacher une carte à un parent, ou l'en détacher avec `parent: null`.\n *\n * Le parent peut vivre sur un autre tableau de la même organisation. Le cloud\n * refuse un parent qui descendrait déjà de la carte : l'arbre reste un arbre.\n */\n async setCardParent(\n boardId: string,\n cardId: string,\n parent: { boardId: string; cardId: string } | null,\n ): Promise<boolean> {\n const res = await callCloud<{ link: KanbanCardLink | null }>('/kanban/card-link/set', {\n method: 'POST',\n body: {\n boardId,\n cardId,\n parentBoardId: parent?.boardId ?? null,\n parentCardId: parent?.cardId ?? null,\n },\n });\n return res.ok;\n }\n\n async create(input: CreateKanbanBoardInput): Promise<KanbanBoard | null> {\n const organizationId = await resolveOrganizationId();\n if (!organizationId) return null;\n const res = await callCloud<{ board: CloudBoard }>('/kanban/board/create', {\n method: 'POST',\n body: {\n organizationId,\n name: input.name,\n description: input.description ?? '',\n instructions: input.instructions ?? '',\n },\n });\n return res.data?.board ?? null;\n }\n\n async update(input: UpdateKanbanBoardInput): Promise<KanbanBoard | null> {\n const res = await callCloud<{ board: CloudBoard }>('/kanban/board/update', {\n method: 'POST',\n body: input,\n });\n return res.data?.board ?? null;\n }\n\n async delete(id: string): Promise<boolean> {\n const res = await callCloud<{ success: boolean }>('/kanban/board/delete', {\n method: 'POST',\n body: { id },\n });\n return res.data?.success ?? false;\n }\n}\n\nexport const kanbanStore = new KanbanStore();\n","import { randomUUID } from 'node:crypto';\nimport { kanbanStore } from './kanban-store.js';\nimport type { KanbanBoard, KanbanCardEvent, KanbanCardLink } from '@runeya/packages-shared';\n\n// ─── Command parsing ────────────────────────────────────────────────────────\n\nexport interface KanbanCommand {\n type: 'move_card' | 'add_comment' | 'add_card';\n /** Target column title (for move_card, add_card) */\n columnTitle?: string;\n /** Comment text (for add_comment) */\n comment?: string;\n /** Card title (for add_card) */\n cardTitle?: string;\n /** Card content / markdown (for add_card) */\n cardContent?: string;\n}\n\n// ─── Command execution ──────────────────────────────────────────────────────\n\nexport async function executeKanbanCommands(\n boardId: string,\n cardId: string,\n commands: KanbanCommand[],\n conversationId?: string,\n): Promise<void> {\n if (commands.length === 0) return;\n\n // Retry loading the board a few times — the card may not have been persisted yet\n // when the conversation was launched before the card was fully saved.\n let board = await kanbanStore.get(boardId);\n if (!board) {\n console.warn(`[kanban-commands] Board ${boardId} not found, skipping ${commands.length} command(s)`);\n return;\n }\n\n // Check if card exists in the board; if not, retry a few times with a short delay\n const cardExistsInBoard = () => board!.columns.some(col => col.cards.some(c => c.id === cardId));\n if (!cardExistsInBoard()) {\n for (let attempt = 1; attempt <= 5; attempt++) {\n console.warn(`[kanban-commands] Card ${cardId} not found in board, retry ${attempt}/5...`);\n await new Promise(r => setTimeout(r, 500 * attempt));\n board = await kanbanStore.get(boardId);\n if (!board) return;\n if (cardExistsInBoard()) break;\n }\n if (!cardExistsInBoard()) {\n console.error(`[kanban-commands] Card ${cardId} still not found after retries, skipping ${commands.length} command(s)`);\n return;\n }\n }\n\n // Plus aucune commande ne réécrit le tableau : chacune passe par sa route\n // ciblée, qui ne fait pas circuler le graphe — et ne l'écrase donc pas.\n for (const cmd of commands) {\n if (cmd.type === 'move_card' && cmd.columnTitle) {\n const target = board.columns.find(\n (c) => c.title.toLowerCase() === cmd.columnTitle!.toLowerCase(),\n );\n if (!target) {\n console.warn(`[kanban-commands] Target column \"${cmd.columnTitle}\" not found. Available: ${board.columns.map(c => c.title).join(', ')}`);\n continue;\n }\n // Route ciblée : trois identifiants montent, le graphe ne bouge pas.\n const ok = await kanbanStore.moveCard(board.id, cardId, target.id);\n if (!ok) console.warn(`[kanban-commands] move_card failed: card=${cardId} target=\"${cmd.columnTitle}\"`);\n } else if (cmd.type === 'add_comment' && cmd.comment) {\n const ok = await kanbanStore.addComment(board.id, cardId, cmd.comment, conversationId);\n if (!ok) console.warn(`[kanban-commands] add_comment failed: card=${cardId}`);\n } else if (cmd.type === 'add_card' && cmd.columnTitle && cmd.cardTitle) {\n // Route ciblée, comme le déplacement : la carte s'ajoute seule, sans que\n // le tableau que cette conversation a lu au début reparte l'écraser.\n await addCardOrFallback(board, cmd.columnTitle, cmd.cardTitle, cmd.cardContent);\n }\n }\n}\n\n/**\n * Execute board-level commands (no card context needed).\n * Used by the AI populate feature.\n */\nexport async function executeKanbanBoardCommands(\n boardId: string,\n commands: KanbanCommand[],\n): Promise<void> {\n if (commands.length === 0) return;\n\n const board = await kanbanStore.get(boardId);\n if (!board) return;\n\n for (const cmd of commands) {\n if (cmd.type === 'add_card' && cmd.columnTitle && cmd.cardTitle) {\n await addCardOrFallback(board, cmd.columnTitle, cmd.cardTitle, cmd.cardContent);\n }\n }\n}\n\n\n/**\n * Poser une carte demandée par l'IA.\n *\n * Il y avait ici un repli pour un cloud sans `/kanban/card/add` : réécrire le\n * tableau entier avec la carte en plus. Il ne pouvait déjà plus rien faire — le\n * cloud n'accepte plus `columns` sur `board/update`, et Zod le retirait en\n * silence. Il est retiré pour de bon maintenant que les cartes vivent dans leur\n * propre collection : ce chemin n'écrirait plus dans le vide, il écrirait à\n * côté, dans un champ que plus aucune lecture ne regarde.\n *\n * Un cloud trop ancien pour la route ciblée n'est donc plus rattrapable ici, et\n * c'est honnête : il faut le mettre à jour, pas le contourner.\n */\nasync function addCardOrFallback(\n board: KanbanBoard,\n columnTitle: string,\n cardTitle: string,\n cardContent?: string,\n): Promise<void> {\n const { card, unsupported } = await kanbanStore.addCard(board.id, {\n column: columnTitle,\n title: cardTitle,\n markdown: cardContent,\n });\n if (card) return;\n console.warn(\n unsupported\n ? `[kanban-commands] cloud sans /kanban/card/add — carte « ${cardTitle} » non créée`\n : `[kanban-commands] add_card failed: column=\"${columnTitle}\"`,\n );\n}\n\n// ─── System prompt for kanban context ───────────────────────────────────────\n\n/** \"240 Ko\" / \"1,2 Mo\" — the agent only needs the order of magnitude. */\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} o`;\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} Ko`;\n return `${(bytes / (1024 * 1024)).toFixed(1).replace('.', ',')} Mo`;\n}\n\nexport function generateKanbanSystemPrompt(\n board: KanbanBoard,\n cardId: string,\n /**\n * Le journal de la carte, lu à part. Les lectures de tableau ne le portent\n * plus — il grossit sans fin — alors l'appelant le demande pour la seule\n * carte dont il parle. Absent, on retombe sur celui que la carte porte, ce\n * qui garde les anciens appels honnêtes.\n */\n history?: KanbanCardEvent[],\n /**\n * Les liens de filiation du tableau. Seul le *nombre* entre dans le prompt :\n * un agent doit savoir qu'une carte en attend une autre, pas relire l'arbre\n * — s'il en a besoin, il le demande avec `kanban_get_card_links`.\n */\n links?: KanbanCardLink[],\n): string {\n let currentColTitle = '';\n let card = null;\n for (const col of board.columns) {\n const found = col.cards.find(c => c.id === cardId);\n if (found) {\n currentColTitle = col.title;\n card = found;\n break;\n }\n }\n\n const sortedColumns = [...board.columns].sort((a, b) => a.order - b.order);\n\n const lines: string[] = [];\n lines.push('## Kanban Board Context');\n lines.push('');\n lines.push(`Tu travailles dans le contexte d'une carte Kanban.`);\n lines.push(`- **Board** : ${board.name}`);\n if (card) {\n lines.push(`- **Carte** : ${card.title}`);\n lines.push(`- **Colonne actuelle** : \\`${currentColTitle}\\``);\n }\n lines.push('');\n\n // Le mode d'emploi écrit par l'équipe. Il passe avant les règles génériques\n // plus bas : c'est lui qui dit ce que veulent dire les colonnes de *ce*\n // tableau, et quand une carte a le droit d'avancer.\n if (board.description) {\n lines.push(`### Description du tableau`);\n lines.push('');\n lines.push(board.description);\n lines.push('');\n }\n if (board.instructions) {\n lines.push('### Fonctionnement de ce tableau (consignes de l\\'équipe)');\n lines.push('');\n lines.push('> Ces consignes priment sur les règles générales plus bas en cas de conflit.');\n lines.push('');\n lines.push(board.instructions);\n lines.push('');\n }\n\n // List columns explicitly so the AI knows the exact names to use\n lines.push('### Colonnes disponibles (noms exacts à utiliser) :');\n for (const col of sortedColumns) {\n const cardCount = col.cards.length;\n const isCurrent = card && col.cards.some(c => c.id === cardId);\n lines.push(`- \\`${col.title}\\` (${cardCount} carte${cardCount !== 1 ? 's' : ''})${isCurrent ? ' ← **colonne actuelle**' : ''}`);\n }\n lines.push('');\n\n // Inject existing comments\n if (card) {\n const events = history ?? card.history ?? [];\n const comments = events.filter(e => e.type === 'comment');\n if (comments.length > 0) {\n lines.push('### Commentaires existants sur cette carte :');\n lines.push('');\n lines.push('> Instantané pris au lancement de cette tâche. Si on te dit qu\\'un commentaire a été ajouté depuis, relis le fil avec `kanban_get_card_comments` — ne réponds pas depuis cette liste.');\n lines.push('');\n for (const c of comments.slice(-20)) { // Last 20 comments max\n const who = c.author === 'ai' ? 'AI' : 'Utilisateur';\n const date = new Date(c.timestamp).toLocaleString('fr-FR', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' });\n const files = (c.attachments ?? []).map(f => `\\`${f.id}\\` ${f.name}`).join(', ');\n lines.push(`- **${who}** (${date}) : ${c.detail}${files ? ` — pièces jointes : ${files}` : ''}`);\n }\n lines.push('');\n }\n }\n\n // Attachments are stored out of band: the prompt lists what exists, and the\n // agent pulls the bytes itself with `kanban_download_attachment`.\n if (card) {\n const files = card.attachments ?? [];\n const commentFiles = (history ?? card.history ?? []).flatMap(e => e.attachments ?? []);\n const all = [...files, ...commentFiles];\n if (all.length > 0) {\n lines.push(`### Pièces jointes disponibles (${all.length})`);\n lines.push('');\n for (const f of all) {\n lines.push(`- \\`${f.id}\\` — ${f.name} (${f.contentType}, ${formatSize(f.size)})`);\n }\n lines.push('');\n lines.push('> Ces fichiers ne sont **pas** dans ce prompt. Appelle `kanban_download_attachment(attachmentId)` pour en récupérer un sur le disque, puis ouvre le chemin renvoyé avec tes outils de lecture de fichiers.');\n lines.push('');\n }\n }\n\n // La filiation : annoncée, jamais dépliée. Un parent et ses sous-cartes\n // peuvent porter des pages entières ; les recopier ici gonflerait le prompt\n // de tout ce que l'agent n'a pas demandé. Le compte suffit à lui faire lever\n // la tête, et l'outil est là pour la suite.\n if (card && links?.length) {\n const parent = links.find(l => l.childCardId === card.id);\n const children = links.filter(l => l.parentCardId === card.id);\n if (parent || children.length) {\n lines.push('### Cartes liées');\n lines.push('');\n if (parent) lines.push('- Cette carte **dépend d\\'une carte parente**.');\n if (children.length) {\n lines.push(`- **${children.length} sous-carte${children.length !== 1 ? 's' : ''}** dépend${children.length !== 1 ? 'ent' : ''} de cette carte.`);\n }\n lines.push('');\n lines.push('> Leur contenu n\\'est **pas** dans ce prompt. Appelle `kanban_get_card_links(boardId)` pour obtenir les identifiants des cartes liées, puis lis-les avec `kanban_get_board` ou `kanban_get_card_comments`.');\n lines.push('');\n }\n }\n\n lines.push('### Outils Kanban disponibles');\n lines.push('');\n lines.push(`- **boardId** (à passer dans tous les outils) : \\`${board.id}\\``);\n if (card) lines.push(`- **cardId** (carte actuelle) : \\`${card.id}\\``);\n lines.push('');\n lines.push('Tu disposes des outils suivants pour interagir avec le board :');\n lines.push('- `kanban_move_card(boardId, cardId, targetColumn)` — Déplacer la carte vers une autre colonne');\n lines.push('- `kanban_add_comment(boardId, cardId, comment)` — Ajouter un commentaire sur la carte');\n lines.push('- `kanban_get_card_comments(boardId, cardId)` — **Relire** le fil de commentaires à jour');\n lines.push('- `kanban_download_attachment(attachmentId)` — Télécharger une pièce jointe et obtenir son chemin local');\n lines.push('- `kanban_get_card_links(boardId)` — Lire la filiation des cartes du tableau (parent ↔ sous-cartes)');\n lines.push('- `kanban_set_card_parent(boardId, cardId, parentCardId?)` — Rattacher une carte à une carte parente, ou l\\'en détacher');\n lines.push('');\n lines.push('### OBLIGATOIRE — Décision Kanban');\n lines.push('');\n lines.push('À chaque réponse, tu DOIS obligatoirement faire les deux actions suivantes :');\n lines.push('');\n lines.push('**1. Évaluer et déplacer la carte si nécessaire** via `kanban_move_card` :');\n lines.push(' - **Au début** si tu sais déjà que tu vas travailler activement (ex. tu passes en `In progress`).');\n lines.push(' - **À la fin** pour une décision forte après analyse complète (ex. tu conclus que c\\'est `Done`).');\n lines.push(' - Si tu ne fais qu\\'analyser ou poser des questions → **ne pas déplacer**.');\n lines.push('');\n lines.push(' > ⚠️ **CRITIQUE** : En fin de réponse, tu DOIS TOUJOURS évaluer si la colonne actuelle est encore correcte.');\n lines.push('');\n lines.push('**2. Appeler `kanban_add_comment`** résumant ce que tu as fait ou constaté (**à la fin** de ta réponse).');\n lines.push('');\n lines.push('> 🚫 **INTERDIT** : Terminer une réponse sans appeler `kanban_add_comment`. C\\'est non négociable.');\n lines.push('');\n\n return lines.join('\\n');\n}\n\n/**\n * Le contexte d'une carte, tel que l'agent le reçoit.\n *\n * Rassemble ici ce que le tableau ne transporte plus — le journal de la carte,\n * la filiation — pour que les quatre endroits qui lancent un agent n'aient pas\n * à se souvenir chacun de les demander (ni à oublier l'un des deux).\n */\nexport async function buildKanbanCardPrompt(board: KanbanBoard, cardId: string): Promise<string> {\n const [history, links] = await Promise.all([\n kanbanStore.cardHistory(board.id, cardId),\n kanbanStore.cardLinks(board.id).then(r => r.links),\n ]);\n return generateKanbanSystemPrompt(board, cardId, history, links);\n}\n\n// ─── Board-level populate prompt ─────────────────────────────────────────────\n\nexport function generateKanbanPopulatePrompt(board: KanbanBoard): string {\n const lines: string[] = [];\n lines.push('## Kanban Board — Mode Populate');\n lines.push('');\n lines.push(`Tu es en mode **populate** sur le tableau Kanban **\"${board.name}\"**.`);\n lines.push('Tu es un outil de gestion de projet. Quand l\\'utilisateur dit \"créer une card\", \"ajouter une tâche\", \"créer une carte\", ou toute demande similaire, il parle EXCLUSIVEMENT d\\'une carte Kanban à ajouter au tableau — PAS d\\'un composant UI, PAS de code HTML ou CSS, PAS d\\'un composant React/Vue/Angular.');\n lines.push('');\n lines.push('Ton UNIQUE rôle est de créer des cartes Kanban pertinentes en réponse à la demande de l\\'utilisateur.');\n lines.push('Tu ne dois PAS répondre à la question, ni donner d\\'explication, ni écrire du code, ni montrer de composant.');\n lines.push('Tu dois UNIQUEMENT produire des tags XML `<kanban_add_card>` pour créer des cartes dans le tableau.');\n if (board.description) {\n lines.push('');\n lines.push(`Description du board : ${board.description}`);\n }\n if (board.instructions) {\n lines.push('');\n lines.push('### Fonctionnement de ce tableau (consignes de l\\'équipe)');\n lines.push('');\n lines.push('> Ces consignes priment sur les règles générales en cas de conflit — sauf sur l\\'interdiction de répondre autrement que par des cartes.');\n lines.push('');\n lines.push(board.instructions);\n }\n lines.push('');\n\n const sortedCols = [...board.columns].sort((a, b) => a.order - b.order);\n\n lines.push('### Colonnes existantes (noms exacts à utiliser) :');\n for (const col of sortedCols) {\n const cardCount = col.cards.length;\n lines.push(`- \\`${col.title}\\` (${cardCount} carte${cardCount !== 1 ? 's' : ''})`);\n for (const card of col.cards) {\n lines.push(` - ${card.title}`);\n }\n }\n lines.push('');\n\n lines.push('### Outil disponible');\n lines.push('');\n lines.push(`- **boardId** (à passer dans tous les outils) : \\`${board.id}\\``);\n lines.push('');\n lines.push('Pour chaque carte à créer, appelle l\\'outil `kanban_add_card(boardId, column, title, content)` :');\n lines.push('- `column` : nom exact de la colonne cible');\n lines.push('- `title` : titre concis de la carte');\n lines.push('- `content` : contenu markdown détaillé et actionnable');\n lines.push('');\n lines.push('### Règles STRICTES');\n lines.push('');\n lines.push('1. **NE RÉPONDS PAS** à la question de l\\'utilisateur. Ne donne aucune explication, aucun texte libre.');\n lines.push('2. **Appelle uniquement** `kanban_add_card`, rien d\\'autre.');\n lines.push('3. Tu ne peux PAS créer de nouvelles colonnes. Dispatch les cartes dans les colonnes existantes listées ci-dessus.');\n lines.push('4. Utilise les noms **exacts** des colonnes.');\n lines.push('5. Chaque carte doit avoir un titre concis et un contenu markdown détaillé et actionnable.');\n lines.push('6. Décompose la demande de l\\'utilisateur en tâches concrètes, chacune étant une carte.');\n lines.push('7. Dispatch chaque carte dans la colonne la plus appropriée selon sa nature.');\n lines.push('');\n\n return lines.join('\\n');\n}\n","import { spawn } from 'node:child_process';\nimport { buildApiDocs } from './runeya-api-docs.js';\nimport { parseEndToken, TOKEN_INSTRUCTIONS } from './scenario-tokens.js';\nimport { runClaudeViaPty } from './claude-pty-runner.js';\nimport type { AiRunner, AiRunnerParams, NodeResult } from './ai-runner.js';\n\n// ─── Claude stream parser ──────────────────────────────────────────────────\n\ninterface ClaudeStreamState {\n fullContent: string;\n thinkingEmitted: boolean;\n textDeltaReceived: boolean;\n currentToolName: string;\n currentToolId: string;\n currentToolInputJson: string;\n toolInputAccumulator: Map<string, { name: string; json: string }>;\n actualSessionId: string | undefined;\n}\n\nfunction createClaudeStreamState(): ClaudeStreamState {\n return {\n fullContent: '',\n thinkingEmitted: false,\n textDeltaReceived: false,\n currentToolName: '',\n currentToolId: '',\n currentToolInputJson: '',\n toolInputAccumulator: new Map(),\n actualSessionId: undefined,\n };\n}\n\ninterface ClaudeStreamCallbacks {\n onDelta: (text: string) => void;\n onStatus: (text: string) => void;\n onThinking?: (text: string) => void;\n onToolCall?: (id: string, name: string, input: Record<string, unknown>) => void;\n onToolResult?: (id: string, name: string, result: string, isError: boolean) => void;\n onContextUsage?: (inputTokens: number, contextWindow: number) => void;\n onResult?: (result: string, sessionId: string | undefined, isError: boolean) => void;\n}\n\nfunction parseClaudeStreamLine(\n line: string,\n state: ClaudeStreamState,\n cb: ClaudeStreamCallbacks,\n): Record<string, unknown> | null {\n const trimmed = line.trim();\n if (!trimmed) return null;\n let event: Record<string, unknown>;\n try { event = JSON.parse(trimmed) as Record<string, unknown>; } catch { return null; }\n\n if (event['type'] === 'stream_event') {\n const ev = event['event'] as Record<string, unknown> | undefined;\n const evType = ev?.['type'];\n const delta = ev?.['delta'] as Record<string, unknown> | undefined;\n const contentBlock = ev?.['content_block'] as Record<string, unknown> | undefined;\n\n if (delta?.['type'] === 'thinking_delta' && typeof delta['thinking'] === 'string') {\n if (!state.thinkingEmitted) {\n state.thinkingEmitted = true;\n cb.onStatus('💭 En réflexion…');\n }\n cb.onThinking?.(delta['thinking'] as string);\n }\n\n if (evType === 'content_block_start' && contentBlock?.['type'] === 'tool_use') {\n state.currentToolName = typeof contentBlock['name'] === 'string' ? contentBlock['name'] : 'tool';\n state.currentToolId = typeof contentBlock['id'] === 'string' ? contentBlock['id'] : '';\n state.currentToolInputJson = '';\n if (state.currentToolId) {\n state.toolInputAccumulator.set(state.currentToolId, { name: state.currentToolName, json: '' });\n }\n cb.onStatus(`🔧 ${state.currentToolName}`);\n }\n\n if (delta?.['type'] === 'input_json_delta' && typeof delta['partial_json'] === 'string') {\n state.currentToolInputJson += delta['partial_json'] as string;\n if (state.currentToolId) {\n const acc = state.toolInputAccumulator.get(state.currentToolId);\n if (acc) acc.json = state.currentToolInputJson;\n }\n }\n\n if (evType === 'content_block_stop' && state.currentToolId && state.toolInputAccumulator.has(state.currentToolId)) {\n const acc = state.toolInputAccumulator.get(state.currentToolId)!;\n let parsedInput: Record<string, unknown> = {};\n try { parsedInput = JSON.parse(acc.json || '{}') as Record<string, unknown>; } catch { /* keep empty */ }\n cb.onToolCall?.(state.currentToolId, acc.name, parsedInput);\n state.currentToolId = '';\n state.currentToolInputJson = '';\n }\n\n if (delta?.['type'] === 'text_delta' && typeof delta['text'] === 'string') {\n state.textDeltaReceived = true;\n state.thinkingEmitted = false;\n state.fullContent += delta['text'];\n cb.onStatus('');\n cb.onDelta(delta['text']);\n }\n\n if (evType === 'message_start') {\n const msg = ev?.['message'] as Record<string, unknown> | undefined;\n const usage = msg?.['usage'] as Record<string, unknown> | undefined;\n if (usage && typeof usage['input_tokens'] === 'number' && cb.onContextUsage) {\n const inputTokens = (usage['input_tokens'] as number)\n + (typeof usage['cache_read_input_tokens'] === 'number' ? usage['cache_read_input_tokens'] : 0)\n + (typeof usage['cache_creation_input_tokens'] === 'number' ? usage['cache_creation_input_tokens'] : 0);\n const modelName = typeof msg?.['model'] === 'string' ? msg['model'] : '';\n const contextWindow = /claude-instant/i.test(modelName) ? 100_000 : 200_000;\n cb.onContextUsage(inputTokens, contextWindow);\n }\n }\n }\n\n if (event['type'] === 'user') {\n const msg = event['message'] as Record<string, unknown> | undefined;\n const content = msg?.['content'];\n const blocks = Array.isArray(content) ? content as Record<string, unknown>[] : [];\n for (const block of blocks) {\n if (block['type'] === 'tool_result' && typeof block['tool_use_id'] === 'string') {\n const id = block['tool_use_id'] as string;\n const isError = block['is_error'] === true;\n const blockContent = block['content'];\n let result = '';\n if (typeof blockContent === 'string') {\n result = blockContent;\n } else if (Array.isArray(blockContent)) {\n result = (blockContent as Record<string, unknown>[])\n .filter(b => b['type'] === 'text')\n .map(b => b['text'] as string)\n .join('');\n }\n const toolName = state.toolInputAccumulator.get(id)?.name ?? '';\n cb.onToolResult?.(id, toolName, result, isError);\n }\n }\n }\n\n if (event['type'] === 'result') {\n if (typeof event['session_id'] === 'string' && event['session_id']) {\n state.actualSessionId = event['session_id'];\n }\n const isError = event['is_error'] === true;\n const resultText = typeof event['result'] === 'string' ? event['result'] : '';\n if (!state.textDeltaReceived && resultText) {\n state.fullContent += resultText;\n cb.onStatus('');\n cb.onDelta(resultText);\n }\n cb.onResult?.(resultText, state.actualSessionId, isError);\n }\n\n return event;\n}\n\nconst EFFORT_THINKING_BUDGET: Record<string, number> = {\n low: 0,\n normal: 5000,\n high: 10000,\n};\n\n/** Build CLI args, env, and stdinData from runner params. Shared by runLocal and runViaAgent.\n * When `excludeMcp` is true, omit --mcp-config from args (agent builds it locally). */\nfunction buildClaudeSpawnConfig(params: AiRunnerParams, opts?: { excludeMcp?: boolean }) {\n const { sessionId, prompt, isResume, systemContext, apiBaseUrl, apiToken, model, effort, images, mcpConfig, skipTokenInstructions, injectedEnv } = params;\n\n const hasImages = images && images.length > 0;\n const sessionArg = isResume\n ? ['--resume', sessionId]\n : (sessionId ? ['--session-id', sessionId] : []);\n\n const thinkingBudget = EFFORT_THINKING_BUDGET[effort] ?? 0;\n const thinkingArgs = thinkingBudget > 0 ? ['--thinking', 'enabled'] : [];\n\n const apiDocs = buildApiDocs(apiBaseUrl, apiToken);\n const fullSystemContext = apiDocs ? `${systemContext}\\n\\n${apiDocs}` : systemContext;\n const systemPrompt = skipTokenInstructions\n ? fullSystemContext\n : `${fullSystemContext}\\n\\n${TOKEN_INSTRUCTIONS}`;\n\n const inputArgs = hasImages\n ? ['--input-format', 'stream-json']\n : ['-p', prompt];\n\n // Runeya declares its own MCP server; the CLI additionally loads whatever the\n // user has in ~/.claude.json. That costs a few seconds of boot per message on\n // a machine with many servers, but keeping the user's tools available is worth\n // it — do NOT add `--strict-mcp-config` here without a way to opt out.\n const mcpArgs = (mcpConfig && !opts?.excludeMcp) ? ['--mcp-config', mcpConfig] : [];\n\n // Modèle vide = on laisse le CLI utiliser celui configuré par l'utilisateur.\n const modelArgs = model ? ['--model', model] : [];\n\n const args = [\n ...sessionArg,\n '--output-format', 'stream-json',\n '--verbose',\n '--include-partial-messages',\n '--dangerously-skip-permissions',\n ...modelArgs,\n ...thinkingArgs,\n '--append-system-prompt', systemPrompt,\n ...mcpArgs,\n ...inputArgs,\n ];\n\n // Env: unset CLAUDECODE, pass apiToken via env var\n const env: Record<string, string> = {\n ...Object.fromEntries(Object.entries(process.env).filter(([k]) => k !== 'CLAUDECODE')) as Record<string, string>,\n ...injectedEnv,\n ...(apiToken ? { RUNEYA_API_TOKEN: apiToken } : {}),\n };\n\n // Build stdin data for images\n let stdinData: string | undefined;\n if (hasImages) {\n const contentBlocks: unknown[] = [{ type: 'text', text: prompt }];\n for (const img of images!) {\n contentBlocks.push({\n type: 'image',\n source: { type: 'base64', media_type: img.mimeType, data: img.base64 },\n });\n }\n stdinData = JSON.stringify({ role: 'user', content: contentBlocks }) + '\\n';\n }\n\n return { args, env, stdinData, sessionArg, hasImages };\n}\n\n/** Mutable state shared across stdout processing calls. */\ninterface ClaudeProcessingCtx {\n settled: boolean;\n earlyResult: NodeResult | null;\n lastResultError: string;\n rawStdoutLines: string[];\n}\n\n/** Process raw stdout lines from the claude CLI stream. Shared by runLocal and runViaAgent. */\nfunction processClaudeStdoutLines(\n lines: string[],\n streamState: ClaudeStreamState,\n params: AiRunnerParams,\n ctx: ClaudeProcessingCtx,\n): void {\n const { onDelta, onStatus, onThinking, onToolCall, onToolResult, skipTokenInstructions } = params;\n\n const settle = (result: NodeResult) => {\n if (ctx.settled) return;\n ctx.settled = true;\n ctx.earlyResult = result;\n // For local runs, don't remove abort listener here — let the process finish\n // to capture actualSessionId from the result event.\n };\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n ctx.rawStdoutLines.push(trimmed);\n if (ctx.rawStdoutLines.length > 50) ctx.rawStdoutLines.shift();\n\n if (ctx.settled) {\n try {\n const ev = JSON.parse(trimmed) as Record<string, unknown>;\n if (ev['type'] === 'result' && typeof ev['session_id'] === 'string') {\n streamState.actualSessionId = ev['session_id'];\n }\n if (ev['type'] === 'result' && ev['is_error'] === true) {\n const errMsg = typeof ev['error'] === 'string' ? ev['error']\n : typeof (ev['error'] as Record<string, unknown>)?.['message'] === 'string' ? (ev['error'] as Record<string, unknown>)['message'] as string : '';\n if (errMsg) ctx.lastResultError = errMsg.slice(-2000);\n }\n } catch { /* ignore */ }\n continue;\n }\n\n const event = parseClaudeStreamLine(line, streamState, {\n onDelta: (text) => {\n onDelta(text);\n if (!skipTokenInstructions) {\n const { status, message, branchChoice } = parseEndToken(streamState.fullContent);\n if (status !== 'none') {\n settle({ output: streamState.fullContent, tokenStatus: status, tokenMessage: message, branchChoice, actualSessionId: streamState.actualSessionId });\n }\n }\n },\n onStatus,\n onThinking,\n onToolCall: (id, name, input) => onToolCall?.(id, name, input),\n onToolResult: (id, _name, result, isError) => onToolResult?.(id, result, isError),\n onContextUsage: params.onContextUsage,\n onResult: (result, _sessionId, isError) => {\n if (isError) {\n const errMsg = typeof result === 'string' ? result : '';\n if (errMsg) ctx.lastResultError = errMsg.slice(-2000);\n }\n if (result) params.onResult?.(result);\n },\n });\n\n if (!event) {\n if (!ctx.lastResultError) ctx.lastResultError = trimmed.slice(-2000);\n }\n }\n}\n\nexport class ClaudeCodeRunner implements AiRunner {\n run(params: AiRunnerParams): Promise<NodeResult> {\n // The CLI always runs in an interactive PTY — there is no headless `-p`\n // mode anymore (it would switch billing from the subscription to the API).\n // The PTY lives on the agent (it owns node-pty); without an agent we can\n // only fall back to the local spawn path.\n if (params.agentId) {\n return runClaudeViaPty(params);\n }\n return this.runLocal(params);\n }\n\n // ── Run locally (original implementation) ───────────────────────────────\n\n private runLocal(params: AiRunnerParams): Promise<NodeResult> {\n const { signal, skipTokenInstructions } = params;\n const { args, env, stdinData, sessionArg, hasImages: _hasImages } = buildClaudeSpawnConfig(params);\n\n return new Promise<NodeResult>((resolve, reject) => {\n const totalArgSize = args.reduce((s, a) => s + a.length + 1, 0);\n console.log(`[claude-code-runner] arg size: ${totalArgSize} bytes (${(totalArgSize / 1024 / 1024).toFixed(2)} MB), session: ${sessionArg.join(' ')}, images: ${params.images?.length ?? 0}`);\n const displayArgs = args.map(a => {\n if (a === params.prompt) return '<prompt>';\n if (a.includes(TOKEN_INSTRUCTIONS)) return '<system-context>';\n return a;\n });\n params.onCommand?.(`claude ${displayArgs.join(' ')}`);\n const proc = spawn('claude', args, {\n stdio: ['pipe', 'pipe', 'pipe'],\n shell: false,\n env,\n });\n\n if (stdinData) {\n proc.stdin!.write(stdinData);\n proc.stdin!.end();\n } else {\n proc.stdin!.end();\n }\n\n const streamState = createClaudeStreamState();\n const ctx: ClaudeProcessingCtx = { settled: false, earlyResult: null, lastResultError: '', rawStdoutLines: [] };\n let stdoutBuffer = '';\n\n const onAbort = () => {\n try { proc.kill('SIGTERM'); } catch { /* ignore */ }\n };\n signal.addEventListener('abort', onAbort, { once: true });\n\n let stderrBuffer = '';\n\n proc.stdout!.on('data', (chunk: Buffer) => {\n stdoutBuffer += chunk.toString('utf-8');\n const lines = stdoutBuffer.split('\\n');\n stdoutBuffer = lines.pop() ?? '';\n processClaudeStdoutLines(lines, streamState, params, ctx);\n });\n\n proc.stderr!.on('data', (chunk: Buffer) => { stderrBuffer += chunk.toString('utf-8'); });\n\n proc.on('close', (code) => {\n if (ctx.earlyResult) { resolve({ ...ctx.earlyResult, actualSessionId: streamState.actualSessionId }); return; }\n\n signal.removeEventListener('abort', onAbort);\n if (signal.aborted) { reject(new Error('Aborted')); return; }\n if (code !== 0 && !streamState.fullContent) {\n const stderr = stderrBuffer.trim().slice(-2000);\n const rawStdout = ctx.rawStdoutLines.slice(-10).join('\\n').trim();\n console.error(`[claude-code-runner] exit code ${code} | stderr: ${stderr || '(empty)'} | last stdout lines: ${rawStdout || '(empty)'}`);\n const detail = ctx.lastResultError || stderr || rawStdout;\n reject(new Error(`Claude Code exited with code ${code}${detail ? `: ${detail}` : ''}`));\n return;\n }\n const { status, message, branchChoice } = skipTokenInstructions\n ? { status: 'none' as const, message: '', branchChoice: undefined }\n : parseEndToken(streamState.fullContent);\n resolve({ output: streamState.fullContent, tokenStatus: status, tokenMessage: message, branchChoice, actualSessionId: streamState.actualSessionId });\n });\n\n proc.on('error', (err) => {\n if (ctx.settled) return;\n signal.removeEventListener('abort', onAbort);\n reject(err);\n });\n });\n }\n}\n\n","// ─── Token-based node completion signals ──────────────────────────────────\n//\n// Shared between all runners (ClaudeCodeRunner, CodexRunner) and the scenario\n// runner orchestration layer. Not used in chat mode.\n\nexport function parseEndToken(output: string): { status: 'pass' | 'error' | 'ask_user' | 'none'; message: string; branchChoice?: number } {\n const tail = output.trimEnd().slice(-2000);\n\n // <pass branch=\"N\" />\n const branchMatch = tail.match(/<pass\\s+branch=\"(\\d+)\"\\s*\\/>/);\n if (branchMatch) {\n return { status: 'pass', message: '', branchChoice: Number.parseInt(branchMatch[1], 10) };\n }\n\n // <pass />\n if (/<pass\\s*\\/>/.test(tail)) {\n return { status: 'pass', message: '' };\n }\n\n // <error>message</error>\n const errorMatch = tail.match(/<error>([\\s\\S]*?)<\\/error>/);\n if (errorMatch) {\n return { status: 'error', message: errorMatch[1].trim() };\n }\n\n // <ask_user>question</ask_user>\n const askMatch = tail.match(/<ask_user>([\\s\\S]*?)<\\/ask_user>/);\n if (askMatch) {\n return { status: 'ask_user', message: askMatch[1].trim() };\n }\n\n return { status: 'none', message: '' };\n}\n\nexport const TOKEN_INSTRUCTIONS = `\n## Instructions de signalisation (OBLIGATOIRE)\n\nÀ la fin de CHAQUE réponse, tu DOIS terminer par exactement l'un de ces tags XML :\n\n- Si tu as terminé avec succès (chemin par défaut) : \\`<pass />\\`\n- Si le nœud propose plusieurs branches de sortie numérotées : \\`<pass branch=\"1\" />\\`, \\`<pass branch=\"2\" />\\`, etc. (choisis la branche qui correspond le mieux au résultat)\n- Si tu as rencontré une erreur bloquante : \\`<error>description courte</error>\\`\n- Si tu es bloqué par une information que personne dans l'équipe ne peut fournir (secret, décision business, credential externe) : \\`<ask_user>ta question</ask_user>\\` — NE PAS utiliser pour demander une confirmation ou un accord (\"es-tu prêt ?\", \"puis-je continuer ?\")\n\nNe jamais omettre ce tag. Il doit être la toute dernière ligne de ta réponse.\n`.trim();\n","import { randomUUID } from 'node:crypto';\nimport { buildApiDocs } from './runeya-api-docs.js';\nimport { parseEndToken, TOKEN_INSTRUCTIONS } from './scenario-tokens.js';\nimport { tailTranscript, type TranscriptEntry } from './claude-pty-tail.js';\nimport type { AiRunnerParams, NodeResult } from './ai-runner.js';\n\nasync function getAgentManager() {\n const { agentManager } = await import('../agent-manager.js');\n return agentManager;\n}\n\ninterface ToolAcc { id: string; name: string }\n\n/**\n * Build claude argv for interactive (PTY) mode. The prompt is passed as a\n * positional argument so claude opens the TUI with it as the first message.\n * `-p` is intentionally omitted: that's the whole point of this runner —\n * stay on the subscription pricing tier.\n */\nfunction buildPtyArgs(params: AiRunnerParams, sessionId: string, opts: { excludeMcp: boolean }) {\n const { isResume, systemContext, apiBaseUrl, apiToken, model, mcpConfig, skipTokenInstructions, prompt } = params;\n\n const sessionArg = isResume ? ['--resume', sessionId] : ['--session-id', sessionId];\n\n const apiDocs = buildApiDocs(apiBaseUrl, apiToken);\n const fullSystemContext = apiDocs ? `${systemContext}\\n\\n${apiDocs}` : systemContext;\n const systemPrompt = skipTokenInstructions\n ? fullSystemContext\n : `${fullSystemContext}\\n\\n${TOKEN_INSTRUCTIONS}`;\n\n // Runeya declares its own MCP server; the CLI additionally loads whatever the\n // user has in ~/.claude.json. That costs a few seconds of boot per message on\n // a machine with many servers, but keeping the user's tools available is worth\n // it — do NOT add `--strict-mcp-config` here without a way to opt out.\n const mcpArgs = (mcpConfig && !opts.excludeMcp) ? ['--mcp-config', mcpConfig] : [];\n\n // Modèle vide = on laisse le CLI utiliser celui configuré par l'utilisateur.\n const modelArgs = model ? ['--model', model] : [];\n\n const args = [\n ...sessionArg,\n '--dangerously-skip-permissions',\n ...modelArgs,\n '--append-system-prompt', systemPrompt,\n ...mcpArgs,\n prompt,\n ];\n\n return args;\n}\n\n/**\n * Extract a delta of text/tool/thinking events from a JSONL entry written by\n * claude (interactive mode). Each entry is either a user / assistant message\n * or a system event. We fire callbacks similar to the headless stream-json\n * parser but at message granularity instead of token granularity.\n */\nfunction dispatchEntry(\n entry: TranscriptEntry,\n state: { assistantText: string; tools: Map<string, ToolAcc> },\n cbs: {\n onDelta: (text: string) => void;\n onStatus: (text: string) => void;\n onThinking?: (text: string) => void;\n onToolCall?: (id: string, name: string, input: Record<string, unknown>) => void;\n onToolResult?: (id: string, result: string, isError: boolean) => void;\n },\n): void {\n if (entry.type !== 'user' && entry.type !== 'assistant') return;\n const msg = entry.message;\n if (!msg) return;\n const role = msg.role ?? entry.type;\n const content = msg.content;\n\n if (typeof content === 'string') {\n if (role === 'assistant' && content) {\n state.assistantText += content;\n cbs.onStatus('');\n cbs.onDelta(content);\n }\n return;\n }\n if (!Array.isArray(content)) return;\n\n for (const raw of content) {\n if (!raw || typeof raw !== 'object') continue;\n const block = raw as {\n type?: string;\n text?: string;\n thinking?: string;\n id?: string;\n name?: string;\n input?: Record<string, unknown>;\n tool_use_id?: string;\n content?: unknown;\n is_error?: boolean;\n };\n if (block.type === 'text' && typeof block.text === 'string' && role === 'assistant') {\n state.assistantText += block.text;\n cbs.onStatus('');\n cbs.onDelta(block.text);\n } else if (block.type === 'thinking' && typeof block.thinking === 'string') {\n cbs.onStatus('💭 En réflexion…');\n cbs.onThinking?.(block.thinking);\n } else if (block.type === 'tool_use' && block.id) {\n const name = block.name ?? 'tool';\n state.tools.set(block.id, { id: block.id, name });\n cbs.onStatus(`🔧 ${name}`);\n cbs.onToolCall?.(block.id, name, block.input ?? {});\n } else if (block.type === 'tool_result' && typeof block.tool_use_id === 'string') {\n const c = block.content;\n let result = '';\n if (typeof c === 'string') result = c;\n else if (Array.isArray(c)) {\n result = (c as Array<Record<string, unknown>>)\n .filter((b) => b['type'] === 'text')\n .map((b) => (b['text'] as string) ?? '')\n .join('');\n }\n cbs.onToolResult?.(block.tool_use_id, result, block.is_error === true);\n }\n }\n}\n\n/**\n * Run a single node turn via an interactive claude PTY.\n *\n * Flow:\n * 1. Generate a fresh session-id (or reuse params.sessionId on resume).\n * 2. Spawn `claude <args> \"<prompt>\"` in a PTY on the agent.\n * 3. Tail the JSONL transcript Claude writes to ~/.claude/projects/.\n * 4. Re-emit each new entry as onDelta/onThinking/onToolCall/onToolResult.\n * 5. parseEndToken() on accumulated assistant text. On token → kill PTY,\n * resolve. Without TOKEN_INSTRUCTIONS, resolve on transcript settling.\n */\nexport async function runClaudeViaPty(params: AiRunnerParams): Promise<NodeResult> {\n const { agentId, signal, skipTokenInstructions } = params;\n if (!agentId) throw new Error('runClaudeViaPty requires an agentId');\n\n const sessionId = params.sessionId && params.sessionId.length > 0\n ? params.sessionId\n : randomUUID();\n const args = buildPtyArgs(params, sessionId, { excludeMcp: true });\n\n const agentMgr = await getAgentManager();\n\n const displayArgs = args.map((a) => {\n if (a === params.prompt) return '<prompt>';\n if (a.includes(TOKEN_INSTRUCTIONS)) return '<system-context>';\n return a;\n });\n params.onCommand?.(`claude ${displayArgs.join(' ')}`);\n\n return new Promise<NodeResult>((resolve, reject) => {\n let settled = false;\n let spawnId: string | null = null;\n const state = { assistantText: '', tools: new Map<string, ToolAcc>() };\n\n const innerAbort = new AbortController();\n const onParentAbort = () => innerAbort.abort();\n signal.addEventListener('abort', onParentAbort, { once: true });\n\n const cleanup = () => {\n signal.removeEventListener('abort', onParentAbort);\n innerAbort.abort();\n };\n\n const killSpawn = async () => {\n if (!spawnId) return;\n try { await agentMgr.agentMutation(agentId, 'ai.kill', { spawnId }); } catch { /* best-effort */ }\n };\n\n const settle = (result: NodeResult) => {\n if (settled) return;\n settled = true;\n cleanup();\n void killSpawn();\n resolve(result);\n };\n\n const fail = (err: Error) => {\n if (settled) return;\n settled = true;\n cleanup();\n void killSpawn();\n reject(err);\n };\n\n // Tail JSONL → dispatch entries → detect end-token.\n const tail = tailTranscript({\n sessionId,\n signal: innerAbort.signal,\n onEntry: (entry) => {\n try {\n dispatchEntry(entry, state, {\n onDelta: params.onDelta,\n onStatus: params.onStatus,\n onThinking: params.onThinking,\n onToolCall: params.onToolCall,\n onToolResult: params.onToolResult,\n });\n } catch { /* never break the tail on a malformed event */ }\n\n // Sans token de fin, rien ne disait qu'un tour était terminé : le PTY\n // reste ouvert en attente d'une autre instruction, `whenDone` ne se\n // résout que sur abandon, et l'appelant attendait pour toujours — une\n // carte de la file kanban restait « en cours » indéfiniment, bloquant\n // les suivantes. Le transcript, lui, le dit : `end_turn`.\n if (skipTokenInstructions\n && entry.type === 'assistant'\n && entry.message?.stop_reason === 'end_turn') {\n settle({\n output: state.assistantText,\n tokenStatus: 'none',\n tokenMessage: '',\n actualSessionId: sessionId,\n });\n return;\n }\n\n if (!skipTokenInstructions) {\n const { status, message, branchChoice } = parseEndToken(state.assistantText);\n if (status !== 'none') {\n settle({\n output: state.assistantText,\n tokenStatus: status,\n tokenMessage: message,\n branchChoice,\n actualSessionId: sessionId,\n });\n }\n }\n },\n });\n\n // Spawn PTY on the agent.\n agentMgr.agentMutation<{ spawnId: string }>(agentId, 'ai.spawnPty', {\n cli: 'claude',\n args,\n env: params.injectedEnv && Object.keys(params.injectedEnv).length > 0 ? params.injectedEnv : undefined,\n // Le répertoire que l'appelant a résolu — celui du projet de la\n // conversation. Sans lui, le PTY naissait dans le répertoire de l'agent,\n // c'est-à-dire là où Runeya a été lancé : une carte kanban du projet A\n // faisait travailler le CLI dans le code de Runeya.\n cwd: params.cwd || undefined,\n cols: 120,\n rows: 30,\n sessionId,\n enableMcp: !!params.mcpConfig,\n mcpApiBaseUrl: params.apiBaseUrl || undefined,\n // Sans lui, l'agent lance le CLI et son serveur MCP sans RUNEYA_API_TOKEN :\n // toutes les tools répondent « No auth token available », et `$RUNEYA_API_TOKEN`\n // ne résout à rien dans le shell du CLI. Le jeton est déjà là — la file le\n // signe elle-même, faute de requête HTTP d'où le tirer.\n mcpApiToken: params.apiToken || undefined,\n }).then(({ spawnId: id }) => {\n spawnId = id;\n if (signal.aborted) { fail(new Error('Aborted')); return; }\n }).catch((err) => {\n fail(new Error(`Failed to spawn claude PTY: ${(err as Error).message}`));\n });\n\n // Abort handling: parent signal → stop tail + kill.\n signal.addEventListener('abort', () => fail(new Error('Aborted')), { once: true });\n\n // If skipTokenInstructions, we have no end-token; rely on tail completion\n // (which only happens on abort). For scenarios we always use the token.\n void tail.whenDone.then(() => {\n if (settled) return;\n // Tail ended without a token — likely the PTY exited or user aborted.\n if (skipTokenInstructions) {\n settle({\n output: state.assistantText,\n tokenStatus: 'none',\n tokenMessage: '',\n actualSessionId: sessionId,\n });\n } else {\n fail(new Error('Claude PTY ended before producing an end token'));\n }\n });\n });\n}\n","import { open, type FileHandle } from 'node:fs/promises';\nimport { watch, type FSWatcher } from 'node:fs';\nimport { findClaudeSessionFile } from '../claude-transcript-sync.js';\n\nexport interface TranscriptEntry {\n type: string;\n uuid?: string;\n timestamp?: string;\n message?: {\n role?: string;\n content?: unknown;\n usage?: unknown;\n model?: string;\n /** `end_turn` quand Claude a fini de parler ; `tool_use` quand il enchaîne. */\n stop_reason?: string | null;\n };\n toolUseResult?: unknown;\n}\n\nexport interface TailOptions {\n sessionId: string;\n signal: AbortSignal;\n /** Max wait for the JSONL file to appear on disk before yielding control. */\n fileAppearTimeoutMs?: number;\n onEntry: (entry: TranscriptEntry) => void;\n}\n\n/** Wait until the JSONL transcript file for `sessionId` exists on disk. */\nasync function waitForFile(sessionId: string, signal: AbortSignal, timeoutMs: number): Promise<string> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n if (signal.aborted) throw new Error('Aborted');\n const path = await findClaudeSessionFile(sessionId);\n if (path) return path;\n await new Promise((r) => setTimeout(r, 150));\n }\n throw new Error(`Transcript file for session ${sessionId} never appeared (timeout ${timeoutMs}ms)`);\n}\n\n/**\n * Tail a Claude JSONL transcript: yield each new entry as it is appended.\n * Returns a `stop()` function and a `whenDone` promise that resolves on stop.\n *\n * NOTE: Reads `~/.claude/projects/<slug>/<sessionId>.jsonl` from the local\n * filesystem. This assumes the agent runs on the same host as the server\n * (local-simple mode). For remote agents, expose a tail route on the agent.\n */\nexport function tailTranscript(opts: TailOptions): { stop: () => void; whenDone: Promise<void> } {\n const { sessionId, signal, onEntry, fileAppearTimeoutMs = 30_000 } = opts;\n let stopped = false;\n let watcher: FSWatcher | null = null;\n let fh: FileHandle | null = null;\n let offset = 0;\n let pendingBuf = '';\n let reading = false;\n let queuedRead = false;\n\n const cleanup = async () => {\n stopped = true;\n if (watcher) { try { watcher.close(); } catch { /* ignore */ } watcher = null; }\n if (fh) { try { await fh.close(); } catch { /* ignore */ } fh = null; }\n };\n\n const drainBuffer = () => {\n let idx;\n while ((idx = pendingBuf.indexOf('\\n')) >= 0) {\n const line = pendingBuf.slice(0, idx).trim();\n pendingBuf = pendingBuf.slice(idx + 1);\n if (!line) continue;\n try {\n const entry = JSON.parse(line) as TranscriptEntry;\n onEntry(entry);\n } catch { /* skip malformed line */ }\n }\n };\n\n const readMore = async () => {\n if (!fh || stopped) return;\n if (reading) { queuedRead = true; return; }\n reading = true;\n try {\n while (!stopped) {\n const st = await fh.stat();\n if (st.size <= offset) break;\n const len = st.size - offset;\n const buf = Buffer.alloc(len);\n const { bytesRead } = await fh.read(buf, 0, len, offset);\n if (bytesRead <= 0) break;\n offset += bytesRead;\n pendingBuf += buf.slice(0, bytesRead).toString('utf-8');\n drainBuffer();\n }\n } finally {\n reading = false;\n if (queuedRead && !stopped) { queuedRead = false; void readMore(); }\n }\n };\n\n const whenDone = (async () => {\n const onAbort = () => { void cleanup(); };\n signal.addEventListener('abort', onAbort, { once: true });\n try {\n const path = await waitForFile(sessionId, signal, fileAppearTimeoutMs);\n if (stopped) return;\n fh = await open(path, 'r');\n // Initial drain (handles content already written between spawn and watcher).\n await readMore();\n if (stopped) return;\n watcher = watch(path, { persistent: false }, () => { void readMore(); });\n watcher.on('error', () => { /* best-effort */ });\n // Polling fallback at low cadence — fs.watch can miss events on some FS.\n const poll = setInterval(() => { void readMore(); }, 500);\n // Keep alive until stopped.\n await new Promise<void>((resolve) => {\n const tick = setInterval(() => { if (stopped) { clearInterval(tick); clearInterval(poll); resolve(); } }, 100);\n });\n } finally {\n signal.removeEventListener('abort', onAbort);\n await cleanup();\n }\n })();\n\n return {\n stop: () => { void cleanup(); },\n whenDone,\n };\n}\n","import { spawn, type ChildProcess } from 'node:child_process';\nimport { createInterface, type Interface as ReadlineInterface } from 'node:readline';\nimport { EventEmitter } from 'node:events';\nimport { codexMcpArgs } from '@runeya/packages-mcp-server/launch';\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\ntype NotificationHandler = (method: string, params: Record<string, unknown>) => void;\n\ninterface PendingRequest {\n resolve: (result: unknown) => void;\n reject: (error: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\n// ─── Client ─────────────────────────────────────────────────────────────────\n\n/**\n * Surcharges `-c` qui branchent le serveur MCP Runeya sur `codex app-server`.\n *\n * Le pendant de ce que `ai-spawn-manager` fait pour `claude` : rien n'est écrit\n * dans le `~/.codex/config.toml` de l'utilisateur, la config ne vit que le temps\n * du process. Les surcharges doivent précéder la sous-commande.\n *\n * Sans jeton Runeya, le serveur MCP ne pourrait rien appeler : on n'injecte donc\n * rien plutôt que de faire démarrer un serveur inutile à chaque lancement.\n */\nfunction resolveMcpArgs(env: NodeJS.ProcessEnv): string[] {\n if (!env['RUNEYA_API_TOKEN']) return [];\n try {\n return codexMcpArgs({\n RUNEYA_BASE_URL: env['RUNEYA_BASE_URL'],\n RUNEYA_API_TOKEN: env['RUNEYA_API_TOKEN'],\n });\n } catch (err) {\n console.warn('[codex-app-server] Failed to resolve MCP server path:', (err as Error).message);\n return [];\n }\n}\n\nexport class CodexAppServerClient extends EventEmitter {\n private proc: ChildProcess | null = null;\n private rl: ReadlineInterface | null = null;\n private nextId = 1;\n private pending = new Map<number, PendingRequest>();\n private notificationHandlers = new Map<string, NotificationHandler[]>();\n private catchAllHandlers: NotificationHandler[] = [];\n private requestTimeoutMs: number;\n\n constructor(opts?: { requestTimeoutMs?: number }) {\n super();\n this.requestTimeoutMs = opts?.requestTimeoutMs ?? 120_000;\n }\n\n /**\n * Spawn codex app-server, perform initialize handshake, return server info.\n *\n * `runeyaEnv` porte les identifiants Runeya : ils vont à la fois dans l'env du\n * process (le CLI y résout `$RUNEYA_API_TOKEN`) et dans la config du serveur\n * MCP dérivée de cet env — un seul canal, comme côté agent.\n */\n async connect(runeyaEnv?: Record<string, string>): Promise<Record<string, unknown>> {\n const env = { ...process.env, ...runeyaEnv };\n\n this.proc = spawn('codex', [...resolveMcpArgs(env), 'app-server'], {\n stdio: ['pipe', 'pipe', 'pipe'],\n env,\n });\n\n this.rl = createInterface({ input: this.proc.stdout! });\n this.rl.on('line', (line) => this.handleLine(line));\n\n this.proc.on('exit', (code, signal) => {\n this.rejectAllPending(new Error(`codex app-server exited (code=${code}, signal=${signal})`));\n this.emit('exit', code, signal);\n });\n\n this.proc.on('error', (err) => {\n this.rejectAllPending(err);\n this.emit('error', err);\n });\n\n // Initialize handshake\n const result = await this.sendRequest('initialize', {\n clientInfo: { name: 'runeya', title: 'Runeya', version: '1.0.0' },\n capabilities: { experimentalApi: false },\n }, 0) as Record<string, unknown>;\n\n // Send initialized notification\n this.sendNotification('initialized', {});\n\n return result;\n }\n\n /** Send a JSON-RPC request and return a promise for the result. */\n sendRequest(method: string, params?: Record<string, unknown>, forceId?: number): Promise<unknown> {\n const id = forceId ?? this.nextId++;\n // If forceId was used and equals nextId range, bump to avoid collision\n if (forceId !== undefined && forceId >= this.nextId) {\n this.nextId = forceId + 1;\n }\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new Error(`Request ${method} (id=${id}) timed out after ${this.requestTimeoutMs}ms`));\n }, this.requestTimeoutMs);\n\n this.pending.set(id, { resolve, reject, timer });\n this.writeLine({ jsonrpc: '2.0', method, id, params: params ?? {} });\n });\n }\n\n /** Send a JSON-RPC notification (no id, no response expected). */\n sendNotification(method: string, params: Record<string, unknown>): void {\n this.writeLine({ jsonrpc: '2.0', method, params });\n }\n\n /** Respond to a server-initiated request (e.g. approval workflow). */\n respond(id: number, result: unknown): void {\n this.writeLine({ jsonrpc: '2.0', id, result });\n }\n\n respondError(id: number, code: number, message: string): void {\n this.writeLine({ jsonrpc: '2.0', id, error: { code, message } });\n }\n\n /** Register a handler for a specific notification method. */\n onNotification(method: string, handler: NotificationHandler): void {\n const list = this.notificationHandlers.get(method) ?? [];\n list.push(handler);\n this.notificationHandlers.set(method, list);\n }\n\n /** Register a catch-all notification handler. */\n onAnyNotification(handler: NotificationHandler): void {\n this.catchAllHandlers.push(handler);\n }\n\n /** Gracefully shut down the child process. */\n async shutdown(): Promise<void> {\n if (!this.proc) return;\n this.rl?.close();\n this.rl = null;\n\n const proc = this.proc;\n this.proc = null;\n\n return new Promise<void>((resolve) => {\n proc.on('exit', () => resolve());\n proc.kill('SIGTERM');\n // Force kill after 5s\n const forceTimer = setTimeout(() => {\n proc.kill('SIGKILL');\n }, 5000);\n proc.on('exit', () => clearTimeout(forceTimer));\n });\n }\n\n // ─── Internal ───────────────────────────────────────────────────────────\n\n private writeLine(obj: Record<string, unknown>): void {\n if (!this.proc?.stdin?.writable) {\n throw new Error('codex app-server stdin not writable');\n }\n this.proc.stdin.write(JSON.stringify(obj) + '\\n');\n }\n\n private handleLine(line: string): void {\n const trimmed = line.trim();\n if (!trimmed) return;\n\n let msg: Record<string, unknown>;\n try {\n msg = JSON.parse(trimmed);\n } catch {\n return; // ignore malformed lines\n }\n\n // Response to a pending request\n if ('id' in msg && typeof msg['id'] === 'number' && ('result' in msg || 'error' in msg)) {\n const pending = this.pending.get(msg['id'] as number);\n if (pending) {\n this.pending.delete(msg['id'] as number);\n clearTimeout(pending.timer);\n if ('error' in msg && msg['error']) {\n const err = msg['error'] as { code: number; message: string };\n pending.reject(new Error(`JSON-RPC error ${err.code}: ${err.message}`));\n } else {\n pending.resolve(msg['result']);\n }\n }\n return;\n }\n\n // Server-initiated request (has id + method, no result/error)\n if ('id' in msg && 'method' in msg && typeof msg['method'] === 'string') {\n this.emit('server-request', msg);\n return;\n }\n\n // Notification (method, no id)\n if ('method' in msg && typeof msg['method'] === 'string' && !('id' in msg)) {\n const method = msg['method'] as string;\n const params = (msg['params'] ?? {}) as Record<string, unknown>;\n\n const handlers = this.notificationHandlers.get(method);\n if (handlers) {\n for (const h of handlers) h(method, params);\n }\n for (const h of this.catchAllHandlers) h(method, params);\n }\n }\n\n private rejectAllPending(error: Error): void {\n for (const [id, pending] of this.pending) {\n clearTimeout(pending.timer);\n pending.reject(error);\n this.pending.delete(id);\n }\n }\n}\n","import { fileURLToPath } from 'node:url';\nimport { createRequire } from 'node:module';\nimport { existsSync } from 'node:fs';\n\n/**\n * Comment brancher le serveur MCP Runeya sur un CLI d'IA.\n *\n * Runeya n'installe rien dans la configuration de la machine : il passe sa\n * config MCP en ligne de commande, au moment où il lance lui-même le CLI. Le\n * `~/.claude.json` ou le `~/.codex/config.toml` de l'utilisateur reste intact,\n * et un CLI lancé à la main depuis un terminal ne voit pas ce serveur.\n *\n * Chaque CLI a sa syntaxe — d'où ce module, seule source de vérité partagée par\n * les deux points de lancement (l'agent, et le serveur en mode local).\n */\n\n/** Variables d'environnement que le serveur MCP attend pour joindre Runeya. */\nexport interface RuneyaMcpEnv {\n RUNEYA_BASE_URL?: string;\n RUNEYA_API_TOKEN?: string;\n}\n\n/**\n * Chemin du point d'entrée du serveur MCP, à lancer avec `node`.\n *\n * Ne PAS se fier à `import.meta.url` pour viser `./index.js` : ce module est\n * bundlé dans l'agent et dans le serveur (tsup y bundle les paquets @runeya\n * via `noExternal`), donc\n * `import.meta.url` y désigne le bundle hôte, pas ce paquet. On résout donc le\n * paquet, puis on sonde les emplacements de la version packagée, où les liens\n * symboliques de l'espace de travail n'existent plus.\n */\nexport function resolveMcpServerPath(): string {\n try {\n const req = createRequire(import.meta.url);\n return req.resolve('@runeya/packages-mcp-server');\n } catch { /* pas de node_modules résolvable : on sonde le disque */ }\n\n const candidates = [\n // Build packagé du CLI : dist/agent/index.js et dist/index.js côtoient\n // dist/mcp-server/, copié là par le post-build.\n new URL('../mcp-server/index.js', import.meta.url),\n new URL('./mcp-server/index.js', import.meta.url),\n // Monorepo, depuis un dist d'app.\n new URL('../../../packages/mcp-server/dist/index.js', import.meta.url),\n new URL('../../../../packages/mcp-server/dist/index.js', import.meta.url),\n ];\n for (const c of candidates) {\n const p = fileURLToPath(c);\n if (existsSync(p)) return p;\n }\n throw new Error('Could not locate @runeya/packages-mcp-server (built dist not found)');\n}\n\n/** Ne garde que les variables renseignées : une valeur vide n'aide personne. */\nfunction pickEnv(env: RuneyaMcpEnv): Record<string, string> {\n return {\n ...(env.RUNEYA_BASE_URL ? { RUNEYA_BASE_URL: env.RUNEYA_BASE_URL } : {}),\n ...(env.RUNEYA_API_TOKEN ? { RUNEYA_API_TOKEN: env.RUNEYA_API_TOKEN } : {}),\n };\n}\n\n/**\n * Arguments `--mcp-config` pour le CLI `claude`, qui attend du JSON.\n *\n * Volontairement non strict : le CLI démarre aussi les serveurs MCP de la\n * machine. Cela coûte quelques secondes par lancement, mais l'utilisateur garde\n * ses propres outils.\n */\nexport function claudeMcpArgs(env: RuneyaMcpEnv): string[] {\n const config = JSON.stringify({\n mcpServers: {\n runeya: {\n command: 'node',\n args: [resolveMcpServerPath()],\n env: pickEnv(env),\n },\n },\n });\n return ['--mcp-config', config];\n}\n\n/**\n * Arguments `-c` pour le CLI `codex`, qui attend du TOML.\n *\n * Codex n'a pas d'équivalent de `--mcp-config` : il expose des surcharges de\n * configuration en TOML (`-c chemin.pointé=valeur`), à placer AVANT la\n * sous-commande. Une table inline décrit le serveur en une seule surcharge.\n */\nexport function codexMcpArgs(env: RuneyaMcpEnv): string[] {\n const fields = [\n `command=${tomlString('node')}`,\n `args=[${tomlString(resolveMcpServerPath())}]`,\n ];\n\n const entries = Object.entries(pickEnv(env));\n if (entries.length > 0) {\n const inline = entries.map(([k, v]) => `${k}=${tomlString(v)}`).join(',');\n fields.push(`env={${inline}}`);\n }\n\n return ['-c', `mcp_servers.runeya={${fields.join(',')}}`];\n}\n\n/**\n * Chaîne TOML de base : seuls la contre-oblique et le guillemet doivent être\n * échappés. Les caractères de contrôle, eux, sont interdits par le format — un\n * chemin ou un jeton qui en contiendrait casserait la config en silence.\n */\nfunction tomlString(value: string): string {\n const escaped = value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/[\\u0000-\\u001f\\u007f]/g, (c) => `\\\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`);\n return `\"${escaped}\"`;\n}\n","import { buildApiDocs } from './runeya-api-docs.js';\nimport { parseEndToken, TOKEN_INSTRUCTIONS } from './scenario-tokens.js';\nimport type { AiRunner, AiRunnerParams, NodeResult } from './ai-runner.js';\nimport { CodexAppServerClient } from './codex-app-server-client.js';\n\n// ─── Singleton app-server client ───────────────────────────────────────────\n\nlet appServerClient: CodexAppServerClient | null = null;\nlet appServerConnecting: Promise<void> | null = null;\n\n/**\n * Le client est un singleton : les identifiants du PREMIER appel sont ceux du\n * process `codex app-server`, y compris pour son serveur MCP. Même contrat que\n * le manager côté agent, dont l'`extraEnv` n'est lu qu'au spawn.\n */\nasync function getAppServerClient(runeyaEnv?: Record<string, string>): Promise<CodexAppServerClient> {\n if (appServerClient) return appServerClient;\n if (appServerConnecting) {\n await appServerConnecting;\n return appServerClient!;\n }\n const client = new CodexAppServerClient({ requestTimeoutMs: 300_000 });\n appServerConnecting = client.connect(runeyaEnv).then(() => {\n appServerClient = client;\n appServerConnecting = null;\n }).catch((err) => {\n appServerConnecting = null;\n throw err;\n });\n // Handle unexpected exit — reset singleton so next call reconnects\n client.on('exit', () => {\n if (appServerClient === client) {\n appServerClient = null;\n }\n });\n await appServerConnecting;\n return appServerClient!;\n}\n\n/** Gracefully shut down the singleton codex app-server process. */\nexport async function shutdownCodexAppServer(): Promise<void> {\n if (appServerClient) {\n const client = appServerClient;\n appServerClient = null;\n await client.shutdown();\n }\n}\n\nasync function getAgentManager() {\n const { agentManager } = await import('../agent-manager.js');\n return agentManager;\n}\n\n// ─── Codex CLI runner ──────────────────────────────────────────────────────\n//\n// Local mode: uses `codex app-server` (persistent JSON-RPC 2.0 process).\n// Agent mode: uses agent-side `codex app-server` via ai.codexRequest/ai.codexNotifications tRPC routes.\n//\n// Both modes use the app-server protocol for thread management (start/resume)\n// and turn execution with structured notifications.\n\n/** Extract route name + parsed input from a curl command targeting the Runeya tRPC API. */\nfunction parseRuneyaCurlCommand(command: string): { route: string; input: Record<string, unknown> } | null {\n // Match /api/trpc/<route> in URL\n const routeMatch = command.match(/\\/api\\/trpc\\/([\\w.]+)/);\n if (!routeMatch) return null;\n const route = routeMatch[1];\n // Try to extract JSON body from -d '...' or -d \"...\"\n let input: Record<string, unknown> = {};\n const bodyMatch = command.match(/-d\\s+'([^']+)'/) ?? command.match(/-d\\s+\"((?:[^\"\\\\]|\\\\.)*)\"/);\n if (bodyMatch) {\n try { input = JSON.parse(bodyMatch[1]) as Record<string, unknown>; } catch { /* keep empty */ }\n }\n // Also check ?input= for GET requests\n const inputQsMatch = command.match(/[?&]input=([^&\\s'\"]+)/);\n if (inputQsMatch) {\n try { input = JSON.parse(decodeURIComponent(inputQsMatch[1])) as Record<string, unknown>; } catch { /* keep empty */ }\n }\n return { route, input };\n}\n\nfunction getCommandExecutionInput(item: Record<string, unknown> | undefined): Record<string, unknown> {\n if (!item) return {};\n const command = typeof item['command'] === 'string' ? item['command'] : '';\n const parsed = command ? parseRuneyaCurlCommand(command) : null;\n if (parsed) return parsed.input;\n const input: Record<string, unknown> = {};\n if (command) input.command = command;\n if (typeof item['status'] === 'string' && item['status']) input.status = item['status'];\n if (typeof item['exit_code'] === 'number') input.exit_code = item['exit_code'];\n return input;\n}\n\nfunction getCommandExecutionName(item: Record<string, unknown> | undefined): string {\n if (!item) return 'command_execution';\n const command = typeof item['command'] === 'string' ? item['command'] : '';\n const parsed = command ? parseRuneyaCurlCommand(command) : null;\n return parsed ? parsed.route : 'command_execution';\n}\n\nfunction getCommandExecutionResult(item: Record<string, unknown> | undefined): string {\n if (!item) return '';\n if (typeof item['aggregated_output'] === 'string' && item['aggregated_output']) {\n return item['aggregated_output'] as string;\n }\n const fallback = {\n command: typeof item['command'] === 'string' ? item['command'] : undefined,\n status: typeof item['status'] === 'string' ? item['status'] : undefined,\n exit_code: typeof item['exit_code'] === 'number' ? item['exit_code'] : undefined,\n };\n return JSON.stringify(fallback, null, 2);\n}\n\n/** Map Runeya effort levels to Codex app-server effort values. */\nfunction mapEffort(effort: string): string | undefined {\n const map: Record<string, string> = { low: 'low', normal: 'medium', medium: 'medium', high: 'high' };\n return map[effort];\n}\n\nexport class CodexRunner implements AiRunner {\n /** Codex thread_id captured from `thread.started`, used for resume. */\n private lastThreadId: string | null = null;\n\n run(params: AiRunnerParams): Promise<NodeResult> {\n if (params.agentId) {\n return this.runViaAgent(params);\n }\n return this.runLocal(params);\n }\n\n // ── Run via agent (app-server JSON-RPC via agent tRPC routes) ───────────\n\n private async runViaAgent(params: AiRunnerParams): Promise<NodeResult> {\n const { agentId, prompt, systemContext, signal, model, effort, isResume, images, skipTokenInstructions, apiBaseUrl, apiToken, injectedEnv } = params;\n const agentMgr = await getAgentManager();\n\n if (isResume && params.sessionId && !this.lastThreadId) {\n this.lastThreadId = params.sessionId;\n }\n\n params.onStatus('🔧 Codex en cours…');\n params.onCommand?.('codex app-server (agent JSON-RPC)');\n\n // Env vars to inject into the agent-side app-server process:\n // active-environment variables flagged `injectIntoAi` + the Runeya API token.\n // `RUNEYA_BASE_URL` accompagne le jeton : le serveur MCP lancé à côté de\n // l'app-server en a besoin pour savoir QUI appeler, pas seulement avec quoi.\n const codexEnv = (injectedEnv && Object.keys(injectedEnv).length > 0) || apiToken\n ? {\n ...injectedEnv,\n ...(apiToken ? { RUNEYA_API_TOKEN: apiToken } : {}),\n ...(apiToken && apiBaseUrl ? { RUNEYA_BASE_URL: apiBaseUrl } : {}),\n }\n : undefined;\n\n // 1. Start or resume thread on agent-side app-server\n let threadId: string;\n if (isResume && this.lastThreadId) {\n const res = await agentMgr.agentMutation<{ result: { thread: { id: string } } }>(agentId!, 'ai.codexRequest', {\n method: 'thread/resume',\n params: { threadId: this.lastThreadId },\n env: codexEnv,\n });\n threadId = res.result.thread.id;\n } else {\n const res = await agentMgr.agentMutation<{ result: { thread: { id: string } } }>(agentId!, 'ai.codexRequest', {\n method: 'thread/start',\n params: {\n model: model || undefined,\n cwd: params.cwd ?? process.cwd(),\n approvalPolicy: 'never',\n sandbox: 'danger-full-access',\n },\n env: codexEnv,\n });\n threadId = res.result.thread.id;\n this.lastThreadId = threadId;\n params.onThreadId?.(threadId);\n }\n\n // 2. Build turn input (same as runLocal)\n const apiDocs = buildApiDocs(apiBaseUrl, apiToken);\n const systemParts = [systemContext, ...(skipTokenInstructions ? [] : [TOKEN_INSTRUCTIONS]), apiDocs].filter(Boolean);\n const fullSystemContext = systemParts.join('\\n\\n');\n const fullPrompt = (isResume && this.lastThreadId)\n ? prompt\n : `${fullSystemContext}\\n\\n---\\n\\n${prompt}`;\n\n const input: Array<Record<string, unknown>> = [];\n if (images && images.length > 0) {\n for (const img of images) {\n input.push({ type: 'image', url: `data:${img.mimeType};base64,${img.base64}` });\n }\n }\n input.push({ type: 'text', text: fullPrompt });\n\n // 3. Subscribe to notifications BEFORE starting the turn\n // Mutable ref so the notification handler can access turnId set after turn/start\n const turnRef: { id: string | null } = { id: null };\n\n return new Promise<NodeResult>((resolve, reject) => {\n let settled = false;\n let fullContent = '';\n let thinkingEmitted = false;\n const startedCommandExecutions = new Set<string>();\n const completedCommandExecutions = new Set<string>();\n\n const settle = (fn: () => void) => {\n if (settled) return;\n settled = true;\n signal.removeEventListener('abort', onAbort);\n if (unsubscribe) { unsubscribe(); unsubscribe = null; }\n fn();\n };\n\n const onAbort = () => {\n if (settled) return;\n if (turnRef.id) {\n agentMgr.agentMutation(agentId!, 'ai.codexRequest', {\n method: 'turn/interrupt',\n params: { threadId, turnId: turnRef.id },\n }).catch(() => { /* best-effort */ });\n }\n settle(() => reject(new Error('Aborted')));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n\n let unsubscribe: (() => void) | null = agentMgr.agentSubscribe(\n agentId!,\n 'ai.codexNotifications',\n { threadId },\n (data: unknown) => {\n if (settled) return;\n const notif = data as { method: string; params: Record<string, unknown> };\n const method = notif.method;\n const p = notif.params;\n\n // Filter by threadId\n const notifThreadId = p['threadId'] as string | undefined;\n if (notifThreadId && notifThreadId !== threadId) return;\n\n // Filter by turnId if present\n const notifTurnId = (p['turnId'] ?? (p['turn'] as Record<string, unknown> | undefined)?.['id']) as string | undefined;\n if (notifTurnId && turnRef.id && notifTurnId !== turnRef.id) return;\n\n if (method === 'item/agentMessage/delta') {\n const delta = p['delta'] as string;\n if (delta) {\n thinkingEmitted = false;\n fullContent += delta;\n params.onDelta(delta);\n const { status, message, branchChoice } = parseEndToken(fullContent);\n if (status !== 'none') {\n settle(() => resolve({ output: fullContent, tokenStatus: status, tokenMessage: message, branchChoice }));\n }\n }\n } else if (method === 'item/reasoning/summaryTextDelta' || method === 'item/reasoning/textDelta') {\n const delta = p['delta'] as string;\n if (delta) {\n if (!thinkingEmitted) {\n thinkingEmitted = true;\n params.onStatus('💭 En réflexion…');\n }\n params.onThinking?.(delta);\n }\n } else if (method === 'item/started') {\n const item = p['item'] as Record<string, unknown> | undefined;\n if (!item) return;\n const itemType = item['type'] as string;\n const itemId = item['id'] as string ?? '';\n\n if (itemType === 'commandExecution') {\n const command = typeof item['command'] === 'string' ? item['command'] as string : '';\n const cmdName = getCommandExecutionName(item);\n const effectiveId = itemId || (command ? `cmd-${command.slice(0, 80)}` : '');\n params.onStatus(`🔧 ${cmdName}`);\n if (effectiveId && !startedCommandExecutions.has(effectiveId)) {\n startedCommandExecutions.add(effectiveId);\n params.onToolCall?.(effectiveId, cmdName, getCommandExecutionInput(item));\n }\n } else if (itemType === 'mcpToolCall' || itemType === 'tool_call') {\n const rawName = typeof item['tool'] === 'string' ? item['tool'] as string\n : typeof item['name'] === 'string' ? item['name'] as string : 'tool';\n const server = typeof item['server'] === 'string' ? item['server'] as string : '';\n const displayName = server ? `${server}.${rawName}` : rawName;\n params.onStatus(`🔧 ${displayName}`);\n if (itemId) {\n let toolInput: Record<string, unknown> = {};\n const rawArgs = item['arguments'];\n if (typeof rawArgs === 'string') {\n try { toolInput = JSON.parse(rawArgs) as Record<string, unknown>; } catch { /* keep empty */ }\n } else if (rawArgs && typeof rawArgs === 'object') {\n toolInput = rawArgs as Record<string, unknown>;\n }\n params.onToolCall?.(itemId, displayName, toolInput);\n }\n }\n } else if (method === 'item/completed') {\n const item = p['item'] as Record<string, unknown> | undefined;\n if (!item) return;\n const itemType = item['type'] as string;\n const itemId = item['id'] as string ?? '';\n\n if (itemType === 'commandExecution') {\n const command = typeof item['command'] === 'string' ? item['command'] as string : '';\n const effectiveId = itemId || (command ? `cmd-${command.slice(0, 80)}` : '');\n if (effectiveId && !completedCommandExecutions.has(effectiveId)) {\n completedCommandExecutions.add(effectiveId);\n const exitCode = typeof item['exit_code'] === 'number' ? item['exit_code'] as number : 0;\n params.onToolResult?.(effectiveId, getCommandExecutionResult(item), exitCode !== 0);\n }\n } else if (itemType === 'mcpToolCall' || itemType === 'tool_call') {\n if (itemId) {\n const output = item['output'];\n const result = typeof output === 'string' ? output : (output ? JSON.stringify(output) : '');\n params.onToolResult?.(itemId, result, false);\n }\n }\n } else if (method === 'turn/completed') {\n const turn = p['turn'] as Record<string, unknown> | undefined;\n const error = turn?.['error'] as Record<string, unknown> | undefined;\n if (error) {\n const msg = typeof error['message'] === 'string' ? error['message'] as string : 'Codex turn failed';\n settle(() => reject(new Error(`Codex: ${msg}`)));\n return;\n }\n const { status, message, branchChoice } = parseEndToken(fullContent);\n settle(() => resolve({ output: fullContent, tokenStatus: status, tokenMessage: message, branchChoice }));\n } else if (method === 'turn/errored') {\n const error = p['error'] as Record<string, unknown> | undefined;\n const msg = typeof error?.['message'] === 'string' ? error['message'] as string : 'Codex turn errored';\n settle(() => reject(new Error(`Codex: ${msg}`)));\n }\n },\n () => {\n // onStop — WS disconnect\n },\n );\n\n // 4. Start turn on agent-side app-server\n agentMgr.agentMutation<{ result: { turn: { id: string; status: string } } }>(agentId!, 'ai.codexRequest', {\n method: 'turn/start',\n params: {\n threadId,\n input,\n model: model || undefined,\n effort: mapEffort(effort),\n approvalPolicy: 'never',\n sandboxPolicy: { type: 'dangerFullAccess' },\n },\n }).then((turnRes) => {\n turnRef.id = turnRes.result.turn.id;\n }).catch((err) => {\n settle(() => reject(new Error(`Failed to start codex turn on agent: ${(err as Error).message}`)));\n });\n });\n }\n\n // ── Run locally via app-server client ────────────────────────────────────\n\n private async runLocal(params: AiRunnerParams): Promise<NodeResult> {\n const { prompt, systemContext, signal, model, effort, isResume, images, skipTokenInstructions, apiBaseUrl, apiToken } = params;\n\n if (isResume && params.sessionId && !this.lastThreadId) {\n this.lastThreadId = params.sessionId;\n }\n\n params.onStatus('🔧 Codex en cours…');\n params.onCommand?.('codex app-server (JSON-RPC)');\n\n // 1. Get or create the singleton client\n const client = await getAppServerClient({\n ...(apiBaseUrl ? { RUNEYA_BASE_URL: apiBaseUrl } : {}),\n ...(apiToken ? { RUNEYA_API_TOKEN: apiToken } : {}),\n });\n\n // 2. Start or resume thread\n let threadId: string;\n if (isResume && this.lastThreadId) {\n const res = await client.sendRequest('thread/resume', { threadId: this.lastThreadId }) as { thread: { id: string } };\n threadId = res.thread.id;\n } else {\n const res = await client.sendRequest('thread/start', {\n model: model || undefined,\n cwd: params.cwd ?? process.cwd(),\n approvalPolicy: 'never',\n sandbox: 'danger-full-access',\n }) as { thread: { id: string } };\n threadId = res.thread.id;\n this.lastThreadId = threadId;\n params.onThreadId?.(threadId);\n }\n\n // 3. Build turn input\n const apiDocs = buildApiDocs(apiBaseUrl, apiToken);\n const systemParts = [systemContext, ...(skipTokenInstructions ? [] : [TOKEN_INSTRUCTIONS]), apiDocs].filter(Boolean);\n const fullSystemContext = systemParts.join('\\n\\n');\n const fullPrompt = (isResume && this.lastThreadId)\n ? prompt\n : `${fullSystemContext}\\n\\n---\\n\\n${prompt}`;\n\n const input: Array<Record<string, unknown>> = [];\n if (images && images.length > 0) {\n for (const img of images) {\n input.push({ type: 'image', url: `data:${img.mimeType};base64,${img.base64}` });\n }\n }\n input.push({ type: 'text', text: fullPrompt });\n\n // 4. Start turn\n const turnRes = await client.sendRequest('turn/start', {\n threadId,\n input,\n model: model || undefined,\n effort: mapEffort(effort),\n approvalPolicy: 'never',\n sandboxPolicy: { type: 'dangerFullAccess' },\n }) as { turn: { id: string; status: string } };\n const turnId = turnRes.turn.id;\n\n // 5. Listen for notifications and resolve on turn/completed\n return new Promise<NodeResult>((resolve, reject) => {\n let settled = false;\n let fullContent = '';\n let thinkingEmitted = false;\n const startedCommandExecutions = new Set<string>();\n const completedCommandExecutions = new Set<string>();\n\n const settle = (fn: () => void) => {\n if (settled) return;\n settled = true;\n signal.removeEventListener('abort', onAbort);\n fn();\n };\n\n const handler = (method: string, p: Record<string, unknown>) => {\n if (settled) return;\n\n // Filter by threadId to scope to this conversation\n const notifThreadId = p['threadId'] as string | undefined;\n if (notifThreadId && notifThreadId !== threadId) return;\n\n // Also filter by turnId if present\n const notifTurnId = (p['turnId'] ?? (p['turn'] as Record<string, unknown> | undefined)?.['id']) as string | undefined;\n if (notifTurnId && notifTurnId !== turnId) return;\n\n if (method === 'item/agentMessage/delta') {\n const delta = p['delta'] as string;\n if (delta) {\n thinkingEmitted = false;\n fullContent += delta;\n params.onDelta(delta);\n const { status, message, branchChoice } = parseEndToken(fullContent);\n if (status !== 'none') {\n settle(() => resolve({ output: fullContent, tokenStatus: status, tokenMessage: message, branchChoice }));\n }\n }\n } else if (method === 'item/reasoning/summaryTextDelta' || method === 'item/reasoning/textDelta') {\n const delta = p['delta'] as string;\n if (delta) {\n if (!thinkingEmitted) {\n thinkingEmitted = true;\n params.onStatus('💭 En réflexion…');\n }\n params.onThinking?.(delta);\n }\n } else if (method === 'item/started') {\n const item = p['item'] as Record<string, unknown> | undefined;\n if (!item) return;\n const itemType = item['type'] as string;\n const itemId = item['id'] as string ?? '';\n\n if (itemType === 'commandExecution') {\n const command = typeof item['command'] === 'string' ? item['command'] as string : '';\n const cmdName = getCommandExecutionName(item);\n const effectiveId = itemId || (command ? `cmd-${command.slice(0, 80)}` : '');\n params.onStatus(`🔧 ${cmdName}`);\n if (effectiveId && !startedCommandExecutions.has(effectiveId)) {\n startedCommandExecutions.add(effectiveId);\n params.onToolCall?.(effectiveId, cmdName, getCommandExecutionInput(item));\n }\n } else if (itemType === 'mcpToolCall' || itemType === 'tool_call') {\n const rawName = typeof item['tool'] === 'string' ? item['tool'] as string\n : typeof item['name'] === 'string' ? item['name'] as string : 'tool';\n const server = typeof item['server'] === 'string' ? item['server'] as string : '';\n const displayName = server ? `${server}.${rawName}` : rawName;\n params.onStatus(`🔧 ${displayName}`);\n if (itemId) {\n let toolInput: Record<string, unknown> = {};\n const rawArgs = item['arguments'];\n if (typeof rawArgs === 'string') {\n try { toolInput = JSON.parse(rawArgs) as Record<string, unknown>; } catch { /* keep empty */ }\n } else if (rawArgs && typeof rawArgs === 'object') {\n toolInput = rawArgs as Record<string, unknown>;\n }\n params.onToolCall?.(itemId, displayName, toolInput);\n }\n }\n } else if (method === 'item/completed') {\n const item = p['item'] as Record<string, unknown> | undefined;\n if (!item) return;\n const itemType = item['type'] as string;\n const itemId = item['id'] as string ?? '';\n\n if (itemType === 'commandExecution') {\n const command = typeof item['command'] === 'string' ? item['command'] as string : '';\n const effectiveId = itemId || (command ? `cmd-${command.slice(0, 80)}` : '');\n if (effectiveId && !completedCommandExecutions.has(effectiveId)) {\n completedCommandExecutions.add(effectiveId);\n const exitCode = typeof item['exit_code'] === 'number' ? item['exit_code'] as number : 0;\n params.onToolResult?.(effectiveId, getCommandExecutionResult(item), exitCode !== 0);\n }\n } else if (itemType === 'mcpToolCall' || itemType === 'tool_call') {\n if (itemId) {\n const output = item['output'];\n const result = typeof output === 'string' ? output : (output ? JSON.stringify(output) : '');\n params.onToolResult?.(itemId, result, false);\n }\n }\n } else if (method === 'turn/completed') {\n const turn = p['turn'] as Record<string, unknown> | undefined;\n const error = turn?.['error'] as Record<string, unknown> | undefined;\n if (error) {\n const msg = typeof error['message'] === 'string' ? error['message'] as string : 'Codex turn failed';\n settle(() => reject(new Error(`Codex: ${msg}`)));\n return;\n }\n // Turn finished normally — resolve with accumulated content\n const { status, message, branchChoice } = parseEndToken(fullContent);\n settle(() => resolve({ output: fullContent, tokenStatus: status, tokenMessage: message, branchChoice }));\n } else if (method === 'turn/errored') {\n const error = p['error'] as Record<string, unknown> | undefined;\n const msg = typeof error?.['message'] === 'string' ? error['message'] as string : 'Codex turn errored';\n settle(() => reject(new Error(`Codex: ${msg}`)));\n }\n };\n\n client.onAnyNotification(handler);\n\n const onAbort = () => {\n if (settled) return;\n client.sendRequest('turn/interrupt', { threadId, turnId }).catch(() => { /* best-effort */ });\n settle(() => reject(new Error('Aborted')));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n });\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 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 { startClaudeCodeSession, startCodexSession } from '../trpc/routers/chat.js';\nimport { signJwt } from './auth-token.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: { runner?: 'claude-code' | 'codex'; model?: string; scenarioId?: string },\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 return col.cards.map(card => this.add({ boardId, cardId: card.id, ...options }));\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 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 );\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 const starter = item.runner === 'codex' ? startCodexSession : startClaudeCodeSession;\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 starter(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 } 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({ attachmentId: z.string().max(128) }))\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}`, { timeoutMs: 120_000 });\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, stampOrgCloud, rememberOrgName, 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 } from '../../services/cloud-api.js';\nimport { describeInstance } from '../../services/instance-registry.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 } 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 */\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\n/**\n * Le Runeya qui tient le verrou de cette organisation, quand il y en a un.\n *\n * Rendu à côté de l'état `locked` : sans lui, l'interface ne peut que dire\n * « fermez l'autre Runeya », ce qui ne désigne rien sur un poste qui en fait\n * tourner trois. Le port est ce par quoi l'utilisateur les distingue.\n */\nasync function syncLockHolder(orgId: string): Promise<{ pid: number; port: number; cwd: string } | null> {\n const pid = cloudSyncBridge.states().find((s) => s.orgId === orgId)?.heldByPid;\n return pid ? describeInstance(pid) : null;\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 }),\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);\n await cloudSyncBridge.connect({ orgId: input.orgId, cloudUrl: input.cloudUrl });\n }\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), heldBy: await syncLockHolder(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 }),\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);\n await cloudSyncBridge.connect({ orgId: input.orgId, cloudUrl: input.cloudUrl });\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' },\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' },\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 });\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 });\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 });\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 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 const clouds = await readOrgClouds();\n let cached = 0;\n for (const orgId of input.orgIds) {\n const base = (clouds[orgId] ?? getCloudApiUrl()).replace(/\\/+$/, '');\n try {\n const res = await fetch(`${base}/api/org-logo/${encodeURIComponent(orgId)}`, {\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 Promise.all(links.map(async (l) => {\n const found = states.get(l.orgId);\n // Le verrou dit un pid ; l'utilisateur, lui, connaît ses Runeya par le\n // port sur lequel il les ouvre. « Fermez l'autre Runeya » n'aide personne\n // quand il y en a trois — le registre d'instances traduit.\n const heldBy = found?.heldByPid ? await describeInstance(found.heldByPid) : null;\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 heldBy,\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 } from './vault-resolver.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\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 different cloud is left out: its vault came from\n * another instance (a self-hosted one, or the hosted one), and connecting it to\n * ours would ask a cloud about an organization it knows nothing of. An unstamped\n * org is assumed to be ours — that is how vaults written before the stamp read.\n */\nexport async function orgsToSync(): Promise<OrgSyncTarget[]> {\n const cloudUrl = getCloudApiUrl();\n const stamps = await readOrgClouds();\n const orgIds = new Set<string>();\n\n for (const vault of await listCloudVaults()) {\n if (orgIds.has(vault.orgId)) continue;\n const stamped = stamps[vault.orgId];\n if (stamped && stamped.replace(/\\/+$/, '') !== cloudUrl) continue;\n if (await isMaterialized(vault.root)) orgIds.add(vault.orgId);\n }\n\n return Array.from(orgIds, (orgId) => ({ orgId, cloudUrl }));\n}\n","import { cloudFetch } 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 });\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 { acquireOrgLock, releaseOrgLock, releaseAllOrgLocksSync } from './org-lock.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';\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' | 'locked' | 'key-mismatch';\n\nexport interface SyncStateReport {\n orgId: string;\n state: SyncState;\n lastIncompatibleVersion: string | null;\n /**\n * Le pid du Runeya qui tient le verrou, pour le seul état `locked`.\n *\n * Un pid, pas un port : le pont sait qui détient, le registre d'instances sait\n * à quelle adresse. Résoudre ici obligerait cette méthode — appelée partout, y\n * compris pour un simple « est-ce connecté ? » — à lire le disque.\n */\n heldByPid: number | 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 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 void 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 void 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 // Seed the doc with current local state; the loop then pushes whatever the\n // cloud is missing and goes live. A rejected session does not abort the\n // start — the loop retries slowly and recovers on its own.\n await this.reconcileLocalToDoc();\n this.initializing = false;\n this.needsPush = true;\n void this.streamLoop();\n }\n\n stop(): void {\n this.stopped = true;\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 this.doc.destroy();\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 const token = await cloudSessionStore.getToken();\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 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 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 }\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 // 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 // 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 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) return;\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) writeEntity(collection, entity.id, entity);\n if (name === 'projects') continue;\n for (const id of Array.from(collection.keys())) {\n if (ids.has(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 another instance holds the lock on — reported, not retried blindly.\n *\n * Le pid du détenteur, et non un simple drapeau : « un autre Runeya de cette\n * machine » ne dit pas lequel fermer, et l'utilisateur en a souvent trois.\n * Le port se déduit du pid par le registre d'instances, au moment de rendre\n * l'état — jamais mémorisé ici, où il vieillirait.\n */\n private locked = new Map<string, number>();\n /**\n * Orgs whose key this machine does not have.\n *\n * Held here for the same reason as `locked`: the connection is never opened,\n * so there is nothing to ask for its state — and an org that cannot sync\n * until a human supplies a key must not read as merely \"stopped\".\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 heldByPid: null,\n }));\n // An org held by another instance has no connection to ask, and reporting\n // it as merely \"stopped\" would hide a cause the user can act on. On nomme\n // le détenteur par son port : « fermez l'autre Runeya » n'aide personne\n // quand il y en a trois.\n const locked = Array.from(this.locked)\n .filter(([orgId]) => !this.connections.has(orgId))\n .map(([orgId, pid]) => ({\n orgId,\n state: 'locked' as SyncState,\n lastIncompatibleVersion: null,\n heldByPid: pid,\n }));\n // Même raison que pour `locked` : sans cette entrée, une organisation dont\n // la clé ne correspond pas se lisait « arrêtée », et l'utilisateur n'avait\n // qu'une ligne de journal — 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 heldByPid: null,\n }));\n return [...live, ...locked, ...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 const lock = await acquireOrgLock(link.orgId).catch((err: Error) => {\n console.error('[cloud-sync] could not take the lock for org %s:', link.orgId, err.message);\n return { acquired: false as const, heldBy: 0 };\n });\n if (!lock.acquired) {\n console.error(\n '[cloud-sync] org %s is already being synced by another Runeya (pid %d) — not syncing it here',\n link.orgId, lock.heldBy,\n );\n this.locked.set(link.orgId, lock.heldBy);\n return;\n }\n this.locked.delete(link.orgId);\n\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 existing.stop();\n this.connections.delete(orgId);\n void releaseOrgLock(orgId);\n }\n }\n\n stopAll(): void {\n for (const conn of this.connections.values()) conn.stop();\n this.connections.clear();\n this.locked.clear();\n this.keyMismatch.clear();\n // Synchronous: shutdown does not wait for promises merely started here.\n releaseAllOrgLocksSync();\n }\n}\n\nexport const cloudSyncBridge = new CloudSyncBridge();\n","import { open, readFile, unlink, mkdir } from 'node:fs/promises';\nimport { readFileSync, unlinkSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { orgVaultRoot } from './vault-resolver.js';\n\n/**\n * One writer per organization, per machine.\n *\n * An org's vaults live under the user's home, so every Runeya on this machine\n * addresses the same directories whatever directory it was launched from. Two\n * instances syncing the same org would each hold their own Yjs doc and write\n * the same files from it — the last save winning, and the loser never learning\n * it lost. The doc merges concurrent edits; the filesystem does not.\n *\n * The lock is advisory and cheap: an exclusive create of `<orgId>.lock` holding\n * the owner's pid. A file left by a process that died is reclaimed, since a\n * crash must not lock a user out of their own org until they find the file.\n */\n\ninterface LockContents {\n pid: number;\n startedAt: string;\n}\n\n/** Orgs this process holds, so shutdown can drop them without awaiting. */\nconst held = new Set<string>();\n\nfunction lockPath(orgId: string): string {\n return join(orgVaultRoot(orgId), 'org.lock');\n}\n\n/** Whether a pid is a live process — `signal 0` tests without touching it. */\nfunction isRunning(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n // EPERM: alive but owned by someone else. Only ESRCH means \"gone\".\n return (err as NodeJS.ErrnoException).code === 'EPERM';\n }\n}\n\nasync function readLock(path: string): Promise<LockContents | null> {\n try {\n const parsed = JSON.parse(await readFile(path, 'utf-8')) as LockContents;\n return typeof parsed?.pid === 'number' ? parsed : null;\n } catch {\n // Missing, truncated, or garbage: nothing that names a live owner.\n return null;\n }\n}\n\n/**\n * Take the lock for an org, or report who holds it.\n *\n * Returns the holder's pid when it is already taken, so the caller can say\n * which process to look at rather than just refusing.\n */\nexport async function acquireOrgLock(orgId: string): Promise<{ acquired: true } | { acquired: false; heldBy: number }> {\n const path = lockPath(orgId);\n await mkdir(orgVaultRoot(orgId), { recursive: true });\n\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n // 'wx' fails when the file exists: the check and the claim are one step,\n // so two instances starting together cannot both succeed.\n const handle = await open(path, 'wx');\n try {\n const contents: LockContents = { pid: process.pid, startedAt: new Date().toISOString() };\n await handle.writeFile(JSON.stringify(contents), 'utf-8');\n } finally {\n await handle.close();\n }\n held.add(orgId);\n return { acquired: true };\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'EEXIST') throw err;\n }\n\n const holder = await readLock(path);\n if (holder && holder.pid !== process.pid && isRunning(holder.pid)) {\n return { acquired: false, heldBy: holder.pid };\n }\n // Stale — the owner is gone, or it is us from a previous life. Clear it and\n // make exactly one more attempt, so a race here cannot loop.\n await unlink(path).catch(() => {});\n }\n\n const holder = await readLock(path);\n return holder ? { acquired: false, heldBy: holder.pid } : { acquired: true };\n}\n\n/** Release the lock, if this process still owns it. */\nexport async function releaseOrgLock(orgId: string): Promise<void> {\n held.delete(orgId);\n const path = lockPath(orgId);\n const holder = await readLock(path);\n if (holder && holder.pid !== process.pid) return;\n await unlink(path).catch(() => {});\n}\n\n/**\n * Drop every lock this process holds, synchronously.\n *\n * Shutdown does not wait on promises that were merely started, and a lock file\n * outliving its process makes the next start take a detour through the stale\n * check. Cheap to do properly here.\n */\nexport function releaseAllOrgLocksSync(): void {\n for (const orgId of held) {\n const path = lockPath(orgId);\n try {\n const holder = JSON.parse(readFileSync(path, 'utf-8')) as LockContents;\n if (holder.pid === process.pid) unlinkSync(path);\n } catch {\n // Already gone, or owned by someone else: nothing to do either way.\n }\n }\n held.clear();\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 { router } from './trpc.js';\nimport { healthRouter } from './routers/health.js';\nimport { appUpdateRouter } from './routers/app-update.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';\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 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});\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 injectIntoAi: false,\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 injectIntoAi: false,\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 const legacyTmp = join(abCwd, '.runeya-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, injectIntoAi: false },\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, injectIntoAi: false },\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 all services',\n operationId: 'service.list',\n security: [{ BearerAuth: [] }],\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\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"],"mappings":"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","names":["resolve","randomBytes","randomBytes","token","execFile","promisify","dirname","join","z","TRPCError","execFileAsync","promisify","execFile","dirname","join","TRPCError","z","z","TRPCError","randomUUID","readFile","writeFile","rename","mkdir","chmod","join","writeFile","join","readFile","writeFile","rename","mkdir","chmod","join","readFile","mkdir","writeFile","rename","chmod","join","FILENAME","readFile","join","writeFile","rename","chmod","mkdir","randomUUID","readFile","writeFile","rename","mkdir","chmod","dirname","join","FILENAME","dirname","join","readFile","mkdir","writeFile","rename","chmod","env","ctx","readFile","stat","rename","mkdir","mkdir","readFile","entries","stat","rename","mkdir","randomBytes","readFile","writeFile","chmod","stat","rename","join","mkdir","TRPCError","z","z","TRPCError","randomUUID","readFile","writeFile","rename","mkdir","chmod","join","mkdir","join","writeFile","rename","chmod","readFile","randomUUID","isAbsolute","isAbsolute","join","dirname","randomUUID","readFile","writeFile","rename","mkdir","chmod","dirname","join","EventEmitter","FILENAME","EventEmitter","readFile","mkdir","dirname","join","writeFile","rename","chmod","projectRoot","randomUUID","isAbsolute","join","dirname","isAbsolute","z","TRPCError","exists","z","TRPCError","z","TRPCError","resolve","z","TRPCError","SUBSCRIPTION_QUEUE_MAX","resolve","z","TRPCError","z","z","z","readFile","writeFile","rename","mkdir","chmod","unlink","dirname","randomBytes","timingSafeEqual","FILENAME","readFile","randomBytes","timingSafeEqual","mkdir","dirname","writeFile","rename","chmod","unlink","z","z","TRPCError","z","env","TRPCError","z","TRPCError","readFile","writeFile","rename","mkdir","join","z","LOOPBACK","z","join","readFile","mkdir","writeFile","rename","resolve","maskApiKey","z","TRPCError","resolve","z","TRPCError","execFile","spawn","stat","resolve","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","Anthropic","OpenAI","execFile","promisify","fileURLToPath","parse","readdir","readFile","homedir","join","join","homedir","entries","readdir","readFile","t","readdir","homedir","join","entries","TRPCError","z","t","resolve","env","entries","pty","MONTHS","entries","resolve","mkdir","rm","readFile","join","chmod","mkdir","rename","writeFile","readFile","dirname","resolve","resolve","mkdir","dirname","writeFile","rename","chmod","readFile","mkdir","t","join","rm","readFile","randomUUID","mkdir","writeFile","readFile","unlink","readdir","existsSync","join","resolve","sep","mkdir","randomUUID","join","resolve","sep","writeFile","readdir","readFile","existsSync","unlink","z","TRPCError","hostname","cloudFetch","TRPCError","z","cloudFetch","spawn","randomUUID","watch","onEntry","watch","resolve","agentManager","randomUUID","resolve","env","resolve","spawn","spawn","EventEmitter","existsSync","env","env","entries","env","EventEmitter","spawn","resolve","getAgentManager","agentManager","resolve","execFileAsync","promisify","execFile","z","fileURLToPath","resolve","TRPCError","pty","Anthropic","OpenAI","startedAt","existsSync","z","TRPCError","Anthropic","OpenAI","z","TRPCError","Anthropic","OpenAI","resolve","randomUUID","TRPCError","z","TRPCError","TRPCError","Anthropic","OpenAI","Anthropic","OpenAI","TRPCError","mkdir","randomUUID","join","MAX_BUFFER","resolve","publish","t","randomUUID","buildSystemPrompt","result","join","mkdir","appendFile","isSubtreeComplete","startedAt","ScopeShape","z","scopeOf","randomUUID","TRPCError","randomUUID","TRPCError","z","MAX_BUFFER","resolve","z","randomUUID","TRPCError","z","TRPCError","EventEmitter","z","resolve","TRPCError","z","randomUUID","EventEmitter","EventEmitter","randomUUID","z","resolve","mkdir","readdir","rm","stat","writeFile","join","z","TRPCError","join","readdir","stat","rm","mkdir","writeFile","TRPCError","z","cloudFetch","z","TRPCError","z","resolve","TRPCError","z","z","resolve","z","TRPCError","readFile","readdir","stat","writeFile","mkdir","rename","rm","join","sep","dirname","z","TRPCError","mkdir","dirname","sep","entries","readdir","join","stat","readFile","writeFile","rename","rm","z","TRPCError","access","join","access","join","randomUUID","mkdir","rm","open","readFile","unlink","mkdir","join","join","readFile","mkdir","open","holder","unlink","randomUUID","mkdir","rm","readdir","readFile","writeFile","mkdir","rename","stat","join","createCipheriv","createDecipheriv","randomBytes","t","createDecipheriv","randomBytes","createCipheriv","entries","readdir","stat","join","readFile","mkdir","writeFile","rename","TRPCError","z","cloudFetch","readdir","stat","homedir","isAbsolute","join","resolve","dirname","basename","z","MAX_ENTRIES","z","join","homedir","isAbsolute","resolve","stat","readdir","entries","dirname","basename","chmod","stat","stat","chmod","readdir","readFile","writeFile","mkdir","copyFile","unlink","rename","stat","join","entries","readdir","exists","stat","join","mkdir","copyFile","readFile","writeFile","rename","unlink","readFile","writeFile","rename","unlink","mkdir","chmod","stat","join","SETTINGS_FILE","SETTINGS_PRIVATE_FILE","exists","stat","mkdir","join","readFile","writeFile","rename","chmod","unlink","createRequire","randomBytes","createCipheriv","createDecipheriv","randomUUID","readFile","writeFile","rename","mkdir","access","readdir","join","dirname","createRequire","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","resolvePath","resolve"]}