@runeya/runeya 2.0.132 → 2.0.133

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 (235) hide show
  1. package/agent/index.js +1 -1
  2. package/agent/index.js.map +1 -1
  3. package/{agent-manager-J75NZ6MN.js → agent-manager-TUFAFC6U.js} +3 -3
  4. package/{chat-ICUWJZEX.js → chat-37VHPDPJ.js} +6 -6
  5. package/{chunk-WN36W5OW.js → chunk-5EMEJNVU.js} +2 -2
  6. package/chunk-5EMEJNVU.js.map +1 -0
  7. package/{chunk-3HGTIUGB.js → chunk-7JAJSV4L.js} +2 -2
  8. package/{chunk-24UJRQRM.js → chunk-I7JHF5FE.js} +2 -2
  9. package/{chunk-RLLUJCPQ.js → chunk-JHJHU6UX.js} +14 -11
  10. package/chunk-JHJHU6UX.js.map +1 -0
  11. package/{chunk-PVLDFBL6.js → chunk-TG44C7QT.js} +6 -6
  12. package/{companion-IYK2652T.js → companion-27RCQRZV.js} +4 -4
  13. package/{desktop-launcher-GHCALSOS.js → desktop-launcher-3COY6F6H.js} +2 -2
  14. package/index.js +13 -5
  15. package/index.js.map +1 -1
  16. package/log-file-XAEHICMH.js +123 -0
  17. package/log-file-XAEHICMH.js.map +1 -0
  18. package/mcp-server/index.js +6 -4
  19. package/mcp-server/index.js.map +1 -1
  20. package/package.json +1 -1
  21. package/{settings-manager-3G5RHW3X.js → settings-manager-J4QBIU3T.js} +3 -3
  22. package/{src-FS7Y4DA7.js → src-PSJSIJN6.js} +10 -9
  23. package/src-PSJSIJN6.js.map +1 -0
  24. package/web/assets/{AgentScalarChatInterface.vue-CImJBBKk.js → AgentScalarChatInterface.vue-BMJAUTbn.js} +1 -1
  25. package/web/assets/{AgentTerminalPage-iRrYZG3N.js → AgentTerminalPage-DJny5leF.js} +1 -1
  26. package/web/assets/AiChatPage-Co5YwUra.js +1 -0
  27. package/web/assets/{AppLayout-CkZbU0SI.js → AppLayout-DhRnQ7sB.js} +1 -1
  28. package/web/assets/{AuditPage-C-yVNrOi.js → AuditPage-B87IuU2E.js} +1 -1
  29. package/web/assets/{CloudAccountPage-7XqPLVAS.js → CloudAccountPage-B9zHVg91.js} +1 -1
  30. package/web/assets/CloudAccountPage-ClRW-luH.js +1 -0
  31. package/web/assets/{CloudMessagingPage-CZBpneaV.js → CloudMessagingPage-Cil491lq.js} +1 -1
  32. package/web/assets/{DashboardPage-CBZZyVwY.js → DashboardPage-vQ69rIA_.js} +1 -1
  33. package/web/assets/{DirectoryPickerDialog-1MThX25G.js → DirectoryPickerDialog-BZG4wryg.js} +1 -1
  34. package/web/assets/{EditorIcon-BVisg2uv.js → EditorIcon-V_Fqyf2s.js} +1 -1
  35. package/web/assets/{EnvironmentForm-C82fYWhW.js → EnvironmentForm-qlF1EeZ2.js} +1 -1
  36. package/web/assets/{EnvironmentFormPage-BVOpMMJ7.js → EnvironmentFormPage-BrW-34oI.js} +1 -1
  37. package/web/assets/{EnvironmentListPage-CPRmFtVH.js → EnvironmentListPage-BdEPphrn.js} +1 -1
  38. package/web/assets/{KanbanBoardPage-pzBPUjj2.js → KanbanBoardPage-DQKqtxxI.js} +3 -3
  39. package/web/assets/KanbanBoardPage-cXyI-2uZ.css +1 -0
  40. package/web/assets/{KanbanListPage-Cy0eP5v1.js → KanbanListPage-5-yh2hO3.js} +1 -1
  41. package/web/assets/{LaunchProjectPage-Bn_wU_QT.js → LaunchProjectPage-g_5Wme1T.js} +1 -1
  42. package/web/assets/{LaunchServicesPage-BuxokNH7.js → LaunchServicesPage-BxUrOZ44.js} +1 -1
  43. package/web/assets/{LogViewer-DFPxgP8T.js → LogViewer-DhTTUJLn.js} +1 -1
  44. package/web/assets/{OrgKeyPrompt-B8qmru6I.js → OrgKeyPrompt-Bs08QGKq.js} +1 -1
  45. package/web/assets/{OrgLogo-9eOcBM3O.js → OrgLogo-CWXqzPiS.js} +1 -1
  46. package/web/assets/{ProcessControls-BA9IDUMF.js → ProcessControls-DIN7XQOl.js} +1 -1
  47. package/web/assets/{ProcessDetailPage-CnOdgJXS.js → ProcessDetailPage-DMFYdJO6.js} +1 -1
  48. package/web/assets/{ProcessMetrics-fFZhpyqE.js → ProcessMetrics-DED63acT.js} +1 -1
  49. package/web/assets/{RandomJobTestPage-Cw5KA5rW.js → RandomJobTestPage-CqOMbdjK.js} +1 -1
  50. package/web/assets/{ScenarioEditorPage-DY9Sfei7.js → ScenarioEditorPage-DPuYttHT.js} +1 -1
  51. package/web/assets/{SendToChatDialog-DLR7jXBG.js → SendToChatDialog-qbllbAWj.js} +1 -1
  52. package/web/assets/{ServiceControlsBar-szGNMHjF.js → ServiceControlsBar-DxPLkFTF.js} +1 -1
  53. package/web/assets/{ServiceDetailPage-BXZ2tvHn.js → ServiceDetailPage-Cp0zW4vF.js} +1 -1
  54. package/web/assets/{ServiceFormPage-B6oUWP9J.js → ServiceFormPage-COy2T7gp.js} +1 -1
  55. package/web/assets/{SettingsPage-95JC2bIP.js → SettingsPage-DsLaZJWX.js} +4 -4
  56. package/web/assets/{UnlockPage-P4gYB5LT.js → UnlockPage-shod0TOQ.js} +1 -1
  57. package/web/assets/{VaultMigrationPage-CQH54K0y.js → VaultMigrationPage-BDJIDUa6.js} +1 -1
  58. package/web/assets/{VersionBadge-D-Zv0XzJ.js → VersionBadge-V6I68xY-.js} +1 -1
  59. package/web/assets/WikiPage-CRPtaZ4n.js +1 -0
  60. package/web/assets/{WikiView-BLoRr_y4.js → WikiView-trPq-25v.js} +1 -1
  61. package/web/assets/{add-scalar-classes-Bpf67R_k.js → add-scalar-classes-CSUXL3L0.js} +3 -3
  62. package/web/assets/{autocomplete-B4ASWozR.js → autocomplete-DKHFlhhO.js} +1 -1
  63. package/web/assets/{basic-shape-diamond.svg-D96ayS7-.js → basic-shape-diamond.svg-DCxdtThm.js} +1 -1
  64. package/web/assets/{basic-shape-hexagon.svg-lBCgoQIf.js → basic-shape-hexagon.svg-BllqL52E.js} +1 -1
  65. package/web/assets/{basic-shape-primary-circle-ellipse-round.svg-BEzXT_e-.js → basic-shape-primary-circle-ellipse-round.svg-qsZEp39q.js} +1 -1
  66. package/web/assets/{basic-shape-primary-square-rectangle.svg-Bkzr23_8.js → basic-shape-primary-square-rectangle.svg-DrsT6mAT.js} +1 -1
  67. package/web/assets/{basic-shape-shield.svg-C3H6eT_i.js → basic-shape-shield.svg-Cbxs8_Nf.js} +1 -1
  68. package/web/assets/{browser-JZPiFr6p.js → browser-3Xde4kSz.js} +1 -1
  69. package/web/assets/{browser-C1dU95Eq.js → browser-pqiHj2Ya.js} +1 -1
  70. package/web/assets/{card-Carw-Smf.js → card-wrii-nrq.js} +1 -1
  71. package/web/assets/{checkbox-SY6iZYJT.js → checkbox-BcVCOcOx.js} +1 -1
  72. package/web/assets/{chip-jKPsBaDG.js → chip-DCUZHTdu.js} +1 -1
  73. package/web/assets/{client-CrX3je4X.js → client-B9hsmT1s.js} +1 -1
  74. package/web/assets/{cloud-chat.store-Cv-pkXPK.js → cloud-chat.store-o00oRsgO.js} +1 -1
  75. package/web/assets/cloud-client-TKLL1zwR.js +1 -0
  76. package/web/assets/{cloud-session-CY8qNDWs.js → cloud-session-B9wU6_5G.js} +2 -2
  77. package/web/assets/cloud-session-DloNvu91.js +1 -0
  78. package/web/assets/{column-Du74odg_.js → column-DA7ijaud.js} +1 -1
  79. package/web/assets/{composables-CAPumxhl.js → composables-DgWeyWnW.js} +1 -1
  80. package/web/assets/{computer-device-desktop-monitor.svg-CKfHZCAn.js → computer-device-desktop-monitor.svg-2AkCd4Vg.js} +1 -1
  81. package/web/assets/{computer-device-desktop.svg-FokfiMmI.js → computer-device-desktop.svg-BX6dDfTh.js} +1 -1
  82. package/web/assets/{computer-device-laptop.svg-u5TTufiX.js → computer-device-laptop.svg-DQot5tMG.js} +1 -1
  83. package/web/assets/{computer-device-mobile-phone-android-samsung-back.svg-D-4JYDXb.js → computer-device-mobile-phone-android-samsung-back.svg-BqQpExMo.js} +1 -1
  84. package/web/assets/{computer-device-mobile-phone-android-samsung.svg-CZGGF9sY.js → computer-device-mobile-phone-android-samsung.svg-uWqzS9ou.js} +1 -1
  85. package/web/assets/{computer-device-mobile-phone-iphone-x-back.svg-DA78gxI_.js → computer-device-mobile-phone-iphone-x-back.svg-lGlmpWrH.js} +1 -1
  86. package/web/assets/{computer-device-mobile-phone-iphone-x.svg-B4MANHvY.js → computer-device-mobile-phone-iphone-x.svg-BZkIeiFY.js} +1 -1
  87. package/web/assets/{computer-device-mobile-tablet-touch.svg-C8TQMpJm.js → computer-device-mobile-tablet-touch.svg-BIY2ojxF.js} +1 -1
  88. package/web/assets/{computer-device-mobile-tablet.svg-BwWJUi6h.js → computer-device-mobile-tablet.svg-EsUtZRCO.js} +1 -1
  89. package/web/assets/{computer-device-network-ethernet-cat6.svg-BbuOLgRf.js → computer-device-network-ethernet-cat6.svg-CFYKvBLS.js} +1 -1
  90. package/web/assets/{computer-device-network-lan-www.svg-Bus_xZ3r.js → computer-device-network-lan-www.svg-DD140-i0.js} +1 -1
  91. package/web/assets/{computer-device-network-wifi-connection.svg-D93e73Wq.js → computer-device-network-wifi-connection.svg-B6xlwqRF.js} +1 -1
  92. package/web/assets/{computer-device-network-wifi-router.svg-6qPxKjkZ.js → computer-device-network-wifi-router.svg-D2oEGuXL.js} +1 -1
  93. package/web/assets/{cssMode-BA6ryPYU.js → cssMode-CyhbxQFj.js} +1 -1
  94. package/web/assets/{divider-Nf1cI936.js → divider-bEPGnPmT.js} +1 -1
  95. package/web/assets/{docx-preview-Beq_uoGc.js → docx-preview-CPCu7gIi.js} +1 -1
  96. package/web/assets/{ecology-science-erlenmeyer-flask.svg-D60hNAZ7.js → ecology-science-erlenmeyer-flask.svg-C3Zo72lq.js} +1 -1
  97. package/web/assets/{fieldset-BO8ymcQg.js → fieldset-BSON_QE9.js} +1 -1
  98. package/web/assets/{freemarker2-u4uWoBOZ.js → freemarker2-764Mz1z9.js} +1 -1
  99. package/web/assets/{handlebars-Crco_whq.js → handlebars-BcplsCVf.js} +1 -1
  100. package/web/assets/{html-krzCI2Gx.js → html-Ab2Gwigb.js} +1 -1
  101. package/web/assets/{htmlMode-C9vDwT8E.js → htmlMode-D8yRZKkz.js} +1 -1
  102. package/web/assets/{image-flash-lightning.svg-B4xlEwgS.js → image-flash-lightning.svg-D-jM06gw.js} +1 -1
  103. package/web/assets/{image-picture-flower.svg-DXs_C4Eb.js → image-picture-flower.svg-X2opjZMU.js} +1 -1
  104. package/web/assets/{index-0Vd4ITAj.js → index-CI76mltd.js} +6 -6
  105. package/web/assets/{interface-alert-exclamation-diamond.svg-CQmiBFHu.js → interface-alert-exclamation-diamond.svg-B3xHmrw0.js} +1 -1
  106. package/web/assets/{interface-alert-exclamation-triangle-warning.svg-Ddp3S5kR.js → interface-alert-exclamation-triangle-warning.svg-BYsDqmTI.js} +1 -1
  107. package/web/assets/{interface-alert-information-circle.svg-CXZRx_eH.js → interface-alert-information-circle.svg-CC4CgbBo.js} +1 -1
  108. package/web/assets/{interface-award-crown.svg-BLjchqiv.js → interface-award-crown.svg-B08Pbh8m.js} +1 -1
  109. package/web/assets/{interface-bookmark.svg-BZXXPgVb.js → interface-bookmark-tag.svg-BcxMXdHY.js} +1 -1
  110. package/web/assets/{interface-bookmark-tag.svg-DykA4zk6.js → interface-bookmark.svg-CS29ZpkA.js} +1 -1
  111. package/web/assets/{interface-calendar-date-one.svg-DY5zquNe.js → interface-calendar-date-one.svg-QnK7dekM.js} +1 -1
  112. package/web/assets/{interface-content-book-open-pages.svg-BkhdueSK.js → interface-content-book-open-pages.svg-C4tNKeZR.js} +1 -1
  113. package/web/assets/{interface-content-book-page.svg-Do2xq5cr.js → interface-content-book-page.svg-6Rp1a1dk.js} +1 -1
  114. package/web/assets/{interface-content-file.svg-D-T9Y5v-.js → interface-content-file.svg-llFUOjLX.js} +1 -1
  115. package/web/assets/interface-content-folder.svg-D9afgGr0.js +1 -0
  116. package/web/assets/{interface-content-folder.svg-C7Xt4Hhi.js → interface-content-folder.svg-OI_omwbE.js} +1 -1
  117. package/web/assets/{interface-copy-clipboard.svg-CNChmFeI.js → interface-copy-clipboard.svg-Cz3_mRtM.js} +1 -1
  118. package/web/assets/{interface-edit-attachment.svg-BPFnKeJn.js → interface-edit-attachment.svg-DXOfVMyI.js} +1 -1
  119. package/web/assets/{interface-edit-binocular.svg-B15WWlwm.js → interface-edit-binocular.svg-Bx3DHzuZ.js} +1 -1
  120. package/web/assets/{interface-edit-magic-wand.svg-BOlpxpIl.js → interface-edit-magic-wand.svg-CAfIYJHR.js} +1 -1
  121. package/web/assets/{interface-edit-tool-paint-roller.svg-BAYfPrFg.js → interface-edit-tool-paint-roller.svg-FMiiT6dK.js} +1 -1
  122. package/web/assets/{interface-edit-tool-pencil.svg-BM5bmeTs.js → interface-edit-tool-pencil.svg-DbkLSbF0.js} +1 -1
  123. package/web/assets/{interface-favorite-award.svg-C2y2AP20.js → interface-favorite-award.svg-hIvxW1cg.js} +1 -1
  124. package/web/assets/{interface-favorite-flag.svg-XykDhXhn.js → interface-favorite-flag.svg-CXlWtfuy.js} +1 -1
  125. package/web/assets/{interface-favorite-heart.svg-CZPb5io9.js → interface-favorite-heart.svg-BzYW_bf1.js} +1 -1
  126. package/web/assets/{interface-favorite-star.svg-DpNTOpjf.js → interface-favorite-star.svg-C-Um6PkR.js} +1 -1
  127. package/web/assets/{interface-favorite-stars-sparkles.svg-7cCHSGs4.js → interface-favorite-stars-sparkles.svg-DO6EAdIZ.js} +1 -1
  128. package/web/assets/{interface-hierarchy-flowchart.svg-BjDJwof2.js → interface-hierarchy-flowchart.svg-CT5ujWQr.js} +1 -1
  129. package/web/assets/{interface-home-house.svg-PIM3QWnr.js → interface-home-house.svg-Inv2Er4f.js} +1 -1
  130. package/web/assets/{interface-hyperlink.svg-DGiT9LRd.js → interface-hyperlink.svg-6GygCg4m.js} +1 -1
  131. package/web/assets/{interface-lighting-brightness.svg-MFs_QAAQ.js → interface-lighting-brightness.svg-DWnle7Gq.js} +1 -1
  132. package/web/assets/{interface-lock-closed.svg-CjFqOV9n.js → interface-lock-closed.svg-D-wTtQo2.js} +1 -1
  133. package/web/assets/{interface-lock-open-unlock.svg-DTgPXrba.js → interface-lock-open-unlock.svg-B_c9nJ0x.js} +1 -1
  134. package/web/assets/{interface-login-key.svg-8cDLtR8c.js → interface-login-key.svg-UCNam9v0.js} +1 -1
  135. package/web/assets/{interface-search.svg-SJaqfmP-.js → interface-search.svg-BCkx6NFS.js} +1 -1
  136. package/web/assets/{interface-setting-cog.svg-CYAoV6-k.js → interface-setting-cog.svg-B72XaLKk.js} +1 -1
  137. package/web/assets/{interface-share-megaphone-bullhorn.svg-C6C8KuHc.js → interface-share-megaphone-bullhorn.svg-M_vr4ET6.js} +1 -1
  138. package/web/assets/{interface-share-rocket.svg-BgqOKppb.js → interface-share-rocket.svg-c3ZAv4Fq.js} +1 -1
  139. package/web/assets/{interface-share-satellite.svg-BhfjDwyA.js → interface-share-satellite.svg-C-cwO4ZJ.js} +1 -1
  140. package/web/assets/{interface-share-space-ship.svg-BUapB87z.js → interface-share-space-ship.svg-7YTjWYKO.js} +1 -1
  141. package/web/assets/{interface-share.svg-CwPC5e-3.js → interface-share.svg-DJwukuDM.js} +1 -1
  142. package/web/assets/{interface-signal-square.svg-BvC7799s.js → interface-signal-square.svg-BpoFub4k.js} +1 -1
  143. package/web/assets/{interface-time-clock-circle.svg-DYKRANoG.js → interface-time-clock-circle.svg-xsV2D_qB.js} +1 -1
  144. package/web/assets/{interface-time-hour-glass.svg-AYkRiFe-.js → interface-time-hour-glass.svg-4ENYolRr.js} +1 -1
  145. package/web/assets/{interface-users-multiple.svg-BXFBhgsj.js → interface-users-multiple.svg-eev_D0ig.js} +1 -1
  146. package/web/assets/{interface-weather-moon.svg-ZozvgB_v.js → interface-weather-moon.svg-CrLYHTyu.js} +1 -1
  147. package/web/assets/{javascript-CTdiuLav.js → javascript-DU1DQexv.js} +1 -1
  148. package/web/assets/{jsonMode-CLF3YN6s.js → jsonMode-CB8B-oHc.js} +1 -1
  149. package/web/assets/{liquid-CUugxlF_.js → liquid-Dumxg7oa.js} +1 -1
  150. package/web/assets/{lspLanguageFeatures-yWNYHr_2.js → lspLanguageFeatures-DQTWe8ey.js} +1 -1
  151. package/web/assets/{mail-chat-bubble-square.svg-BG2z_u4M.js → mail-chat-bubble-square.svg-DMcOjB2m.js} +1 -1
  152. package/web/assets/{mail-send-email-paper-airplane.svg-CUQDu7ep.js → mail-send-email-paper-airplane.svg-CKpmx979.js} +1 -1
  153. package/web/assets/{mail-send-envelope.svg-pk8Xd68w.js → mail-send-envelope.svg-C-WAmEPg.js} +1 -1
  154. package/web/assets/{mdx-BE-R90za.js → mdx-DNzXmMw3.js} +1 -1
  155. package/web/assets/{minus-DXcyjEvM.js → minus-CmvRtEQe.js} +1 -1
  156. package/web/assets/{modal-DEXm8R-m.js → modal-C0O2XBPJ.js} +1 -1
  157. package/web/assets/modal-DRUfpIPe.js +1 -0
  158. package/web/assets/{money-cashier-receipt.svg-CN9CzrqX.js → money-cashier-receipt.svg-DeL4SF6F.js} +1 -1
  159. package/web/assets/{money-currency-dollar-pay.svg-BUjSCFrb.js → money-currency-dollar-pay.svg-DCIbDsIr.js} +1 -1
  160. package/web/assets/{money-graph-arrow-increase.svg-B_90Bmbk.js → money-graph-arrow-increase.svg-NDD5MY4C.js} +1 -1
  161. package/web/assets/{money-graph-bar-chart-increase.svg-DEHprvsR.js → money-graph-bar-chart-increase.svg-CqFZrAkq.js} +1 -1
  162. package/web/assets/{multiselect-DHN-4dF5.js → multiselect-C3dGhKnP.js} +1 -1
  163. package/web/assets/{nature-ecology-leaf.svg-VzV83bka.js → nature-ecology-leaf.svg-C74TcBty.js} +1 -1
  164. package/web/assets/{password-Cn-GHrdR.js → password-Cf8j-GkJ.js} +1 -1
  165. package/web/assets/{phone-telephone.svg-B7K0iTF5.js → phone-telephone.svg-BeNULj1e.js} +1 -1
  166. package/web/assets/{plus-BavJPboa.js → plus-hUxz8lH_.js} +1 -1
  167. package/web/assets/process.store-TQsoI7AA.js +1 -0
  168. package/web/assets/{programming-bug.svg-BQArvDEk.js → programming-bug.svg-DSydJcD0.js} +1 -1
  169. package/web/assets/{programming-cloud.svg-Diup3d6q.js → programming-cloud.svg-2xUngU0S.js} +1 -1
  170. package/web/assets/{programming-computer-database-server.svg-Cry9WzIl.js → programming-computer-database-server.svg-TAX5z1tR.js} +1 -1
  171. package/web/assets/{programming-computer-database.svg-B2DIP4pU.js → programming-computer-database.svg-mO5bElVh.js} +1 -1
  172. package/web/assets/{programming-module-four-layout.svg-BGnmF15h.js → programming-module-four-layout.svg-Dr767G1Z.js} +1 -1
  173. package/web/assets/{programming-module-three.svg-Dlx8NKbv.js → programming-module-three.svg-D4oVsZl_.js} +1 -1
  174. package/web/assets/{programming-module.svg-1TSwsWTr.js → programming-module.svg-wdwopIvm.js} +1 -1
  175. package/web/assets/{programming-script-code.svg-DpNHCOrR.js → programming-script-code.svg-DBPWoki2.js} +1 -1
  176. package/web/assets/project-launch.store-CZsTY83m.js +1 -0
  177. package/web/assets/project.store-eIP8RM3Q.js +1 -0
  178. package/web/assets/{python-BfgnQ0Q-.js → python-BE5DaTS2.js} +1 -1
  179. package/web/assets/{radiobutton-1vkC7CQy.js → radiobutton-CImlBTBP.js} +1 -1
  180. package/web/assets/{razor-a5t1Ro53.js → razor-Cmx-7XPV.js} +1 -1
  181. package/web/assets/router-CVSY8aIb.js +1 -0
  182. package/web/assets/{selectbutton-DSr_ExzW.js → selectbutton-BhpYZyFl.js} +1 -1
  183. package/web/assets/settings-scope-CxYQcvAR.js +1 -0
  184. package/web/assets/{settings.store-BBQfvtZb.js → settings.store-DridR-ck.js} +1 -1
  185. package/web/assets/{shopping-cart.svg-16zfxHII.js → shopping-cart.svg-C3En9-vl.js} +1 -1
  186. package/web/assets/{shopping-gift-present.svg-DEDgwlxd.js → shopping-gift-present.svg-7p-hRdPX.js} +1 -1
  187. package/web/assets/{shopping-shipping-box-parcel-package.svg-CBOsBi-s.js → shopping-shipping-box-parcel-package.svg-BWbZhI8w.js} +1 -1
  188. package/web/assets/src-BM_sDDlr.css +1 -0
  189. package/web/assets/{src-wb0MqCTT.js → src-DTiDFW3B.js} +32 -32
  190. package/web/assets/{src-B_TK9M1Z.js → src-isLSni-N.js} +1 -1
  191. package/web/assets/{tabpanel-CqAq0gJE.js → tabpanel-Bfol4XTd.js} +1 -1
  192. package/web/assets/{tag-new-circle.svg-DN5XPkdR.js → tag-new-circle.svg-Spe566L2.js} +1 -1
  193. package/web/assets/theme-4th617B_.js +1 -0
  194. package/web/assets/{toggleswitch-Cr9zROI7.js → toggleswitch-CZCAv-jp.js} +1 -1
  195. package/web/assets/{travel-map-earth-globe.svg-CN8908SS.js → travel-map-earth-globe.svg-DKz5j-UT.js} +1 -1
  196. package/web/assets/trpc-CBXwYAMy.js +1 -0
  197. package/web/assets/{tsMode-D8tqTb6Z.js → tsMode-AQ4klRHU.js} +1 -1
  198. package/web/assets/{typescript-C2tUdKLU.js → typescript-yluvE--_.js} +1 -1
  199. package/web/assets/useAiChatDrawer-D_AzdjrA.js +1 -0
  200. package/web/assets/{useCloudOrg-C1-UCQOV.js → useCloudOrg-b-QnhnSc.js} +1 -1
  201. package/web/assets/{useEnvVarAutocomplete-5sTKensF.js → useEnvVarAutocomplete-Bj9GeijO.js} +1 -1
  202. package/web/assets/{useProjectCatalog-Dj4rYNAZ.js → useProjectCatalog-BGdTjXzH.js} +1 -1
  203. package/web/assets/{useProjectCloudOrg-B1KHG4Co.js → useProjectCloudOrg-DQJMaDXR.js} +1 -1
  204. package/web/assets/{useServiceUrlHost-CDiftJ5-.js → useServiceUrlHost-BezQuX2r.js} +1 -1
  205. package/web/assets/{xml-09bhQ5hy.js → xml-BEYNsHpr.js} +1 -1
  206. package/web/assets/{yaml-DE2l2UeT.js → yaml-CdJTW_Jy.js} +1 -1
  207. package/web/index.html +1 -1
  208. package/chunk-RLLUJCPQ.js.map +0 -1
  209. package/chunk-WN36W5OW.js.map +0 -1
  210. package/src-FS7Y4DA7.js.map +0 -1
  211. package/web/assets/AiChatPage-DWAuKlmg.js +0 -1
  212. package/web/assets/CloudAccountPage-Cxo7nX-K.js +0 -1
  213. package/web/assets/KanbanBoardPage-BmJwTFE8.css +0 -1
  214. package/web/assets/WikiPage-DzFvtMxw.js +0 -1
  215. package/web/assets/cloud-client-D01e8Pib.js +0 -1
  216. package/web/assets/cloud-session-DHJ2Dn0_.js +0 -1
  217. package/web/assets/interface-content-folder.svg-D8Pl9Ud7.js +0 -1
  218. package/web/assets/modal-DDtmE9ls.js +0 -1
  219. package/web/assets/process.store-BHtXNXJN.js +0 -1
  220. package/web/assets/project-launch.store-MjBfxlB3.js +0 -1
  221. package/web/assets/project.store-4LkhN_Kf.js +0 -1
  222. package/web/assets/router-D2CFZuT6.js +0 -1
  223. package/web/assets/settings-scope-Bfve93ym.js +0 -1
  224. package/web/assets/src-DXLPQX5t.css +0 -1
  225. package/web/assets/theme-BRinmkRN.js +0 -1
  226. package/web/assets/trpc-CGXr2as5.js +0 -1
  227. package/web/assets/useAiChatDrawer-1cmqYfrd.js +0 -1
  228. /package/{settings-manager-3G5RHW3X.js.map → agent-manager-TUFAFC6U.js.map} +0 -0
  229. /package/{companion-IYK2652T.js.map → chat-37VHPDPJ.js.map} +0 -0
  230. /package/{chunk-3HGTIUGB.js.map → chunk-7JAJSV4L.js.map} +0 -0
  231. /package/{chunk-24UJRQRM.js.map → chunk-I7JHF5FE.js.map} +0 -0
  232. /package/{chunk-PVLDFBL6.js.map → chunk-TG44C7QT.js.map} +0 -0
  233. /package/{chat-ICUWJZEX.js.map → companion-27RCQRZV.js.map} +0 -0
  234. /package/{desktop-launcher-GHCALSOS.js.map → desktop-launcher-3COY6F6H.js.map} +0 -0
  235. /package/{agent-manager-J75NZ6MN.js.map → settings-manager-J4QBIU3T.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../../ai-capabilities/src/capabilities.ts","../../ai-capabilities/src/adapters/json-schema.ts","../../ai-capabilities/src/adapters/anthropic.ts","../../ai-capabilities/src/adapters/openai.ts","../../ai-capabilities/src/adapters/prompt.ts","../../ai-capabilities/src/adapters/mcp.ts","../../ai-capabilities/src/trpc-caller.ts","../../ai-capabilities/src/project-anchor.ts","../../shared/src/schemas/user.schema.ts","../../shared/src/schemas/org.schema.ts","../../shared/src/schemas/project.schema.ts","../../shared/src/schemas/service.schema.ts","../../shared/src/schemas/settings.schema.ts","../../shared/src/schemas/scenario.schema.ts","../../shared/src/schemas/log-source.schema.ts","../../shared/src/schemas/process.schema.ts","../../shared/src/schemas/log.schema.ts","../../shared/src/schemas/agent.schema.ts","../../shared/src/schemas/permission.schema.ts","../../shared/src/schemas/sync.schema.ts","../../shared/src/schemas/audit.schema.ts","../../shared/src/schemas/metrics.schema.ts","../../shared/src/schemas/environment.schema.ts","../../shared/src/schemas/environment-overrides.schema.ts","../../shared/src/schemas/api-key.schema.ts","../../shared/src/schemas/image.schema.ts","../../shared/src/schemas/kanban.schema.ts","../../shared/src/schemas/cloud-api-key.schema.ts","../../shared/src/schemas/integration.schema.ts","../../shared/src/schemas/changelog.schema.ts","../../shared/src/utils/companion-markers.ts","../../shared/src/utils/launcher-identity.ts","../../shared/src/utils/log-source-secrets.ts","../../shared/src/utils/crypto.ts","../../shared/src/native-parsers.ts","../../shared/src/js-log-parser.ts","../../shared/src/builtins.ts","../../shared/src/constants/process-states.ts","../../shared/src/constants/log-levels.ts","../../shared/src/constants/roles.ts","../../shared/src/constants/intervals.ts","../../shared/src/constants/buffers.ts","../../shared/src/constants/timeouts.ts","../../shared/src/constants/editors.ts","../../shared/src/sync/json-crdt.ts","../../shared/src/utils/service-links.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport { RUNEYA_CAPABILITIES, applyProjectAnchor, buildMcpShape, runCapability, toRawParams } from '@runeya/packages-ai-capabilities';\n\nconst BASE_URL = process.env['RUNEYA_BASE_URL'] ?? 'http://localhost:4000';\nconst CONVERSATION_ID = process.env['RUNEYA_CONVERSATION_ID'] ?? '';\nconst INTERNAL_TOKEN = process.env['RUNEYA_INTERNAL_TOKEN'] ?? '';\nconst ENV_TOKEN = process.env['RUNEYA_API_TOKEN'] ?? '';\n// Le projet dans lequel Runeya a lancé ce CLI. Absent hors conversation\n// (un CLI démarré à la main), et alors rien n'est ancré.\nconst PROJECT_ANCHOR = {\n projectId: process.env['RUNEYA_PROJECT_ID'] || undefined,\n orgId: process.env['RUNEYA_ORG_ID'] || undefined,\n};\n\nconst server = new McpServer({ name: 'runeya', version: '1.0.0' });\n\n// ─── Register each capability as an MCP tool ─────────────────────────────────\n\nfor (const cap of RUNEYA_CAPABILITIES) {\n server.tool(cap.name, cap.description, buildMcpShape(cap), async (input) => {\n try {\n const rawParams = toRawParams(input as Record<string, unknown>, cap);\n const raw = rawParams['authToken'];\n const authToken = (raw && !raw.startsWith('$')) ? raw : (ENV_TOKEN || INTERNAL_TOKEN || undefined);\n if (!authToken) throw new Error('No auth token available');\n\n const params = applyProjectAnchor(cap, rawParams, PROJECT_ANCHOR);\n const result = await runCapability(cap, BASE_URL, params, authToken);\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: `Error: ${(err as Error).message}` }],\n isError: true,\n };\n }\n });\n}\n\n// ─── ask_user tool (scenario mode only) ─────────────────────────────────────\n\nif (CONVERSATION_ID && INTERNAL_TOKEN) {\n server.tool(\n 'ask_user',\n 'Ask the user a question and wait for their reply. Use this when you need clarification or input from the user to proceed.',\n { question: z.string().describe('The question to ask the user') },\n async ({ question }) => {\n try {\n const res = await fetch(`${BASE_URL}/api/trpc/scenario.requestInput`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${INTERNAL_TOKEN}`,\n },\n body: JSON.stringify({ conversationId: CONVERSATION_ID, question }),\n signal: AbortSignal.timeout(300_000), // 5 min\n });\n const json = await res.json() as Record<string, unknown>;\n const result = (json['result'] as Record<string, unknown> | undefined)?.['data'] ?? json;\n const text = typeof result === 'string' ? result : JSON.stringify(result);\n return { content: [{ type: 'text' as const, text }] };\n } catch (err) {\n return { content: [{ type: 'text' as const, text: `Error: ${(err as Error).message}` }], isError: true };\n }\n },\n );\n}\n\n// ─── Start the stdio transport ───────────────────────────────────────────────\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\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\nimport { z } from 'zod';\nimport {\n BootstrapCommandSchema, DockerConfigSchema, HealthCheckSchema, RestartStrategySchema,\n BUILTIN_VARIABLES, ServiceCommandSchema, ServiceConfigSchema, ServiceShortcutSchema, maskLogSourceSecrets,\n} from '@runeya/packages-shared';\nimport type { LogSourceConfig } from '@runeya/packages-shared';\n\nexport interface CapabilityParam {\n name: string;\n description: string;\n required: boolean;\n /**\n * Le type réel du paramètre. Absent : un texte. Présent, il est donné tel\n * quel au modèle (JSON Schema pour le chat, Zod pour le MCP) et relu contre\n * lui dans `buildInput`, qui reçoit toujours des chaînes.\n */\n schema?: z.ZodType;\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 * Filtre la réponse avant qu'elle n'atteigne le modèle — pour ce qu'une route\n * rend à l'interface et qu'une IA ne doit pas lire.\n */\n transformOutput?: (result: unknown) => unknown;\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\n/**\n * La cible d'une commande git : un service, ou à défaut un projet.\n *\n * Les quatre champs sont facultatifs côté route (`gitTargetShape`), qui résout\n * elle-même l'agent et le répertoire. On ne transmet que ce que le modèle a\n * réellement donné : un `serviceId` vide ferait échouer la résolution.\n */\nfunction gitTarget(p: Record<string, string | undefined>): Record<string, unknown> {\n return {\n ...(p.serviceId ? { serviceId: p.serviceId } : {}),\n ...(p.projectId ? { projectId: p.projectId } : {}),\n ...(p.agentId ? { agentId: p.agentId } : {}),\n ...(p.orgId ? { orgId: p.orgId } : {}),\n };\n}\n\nconst toBool = (raw: string) => raw.trim().toLowerCase() === 'true';\n\nconst newId = () => globalThis.crypto.randomUUID();\n\n/** Un élément de liste tel qu'un modèle l'énumère : `3000` est un nombre, `api` un texte. */\nfunction listItem(raw: string): unknown {\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return raw;\n }\n}\n\n/**\n * Lire un paramètre typé, arrivé en chaîne, contre son schéma.\n *\n * Dans l'ordre : la chaîne telle quelle (un texte), son JSON (un objet, un\n * nombre, `null`), puis une énumération à virgules (une liste). Le résultat est\n * la sortie du schéma, défauts compris. Une valeur refusée échoue avec le nom\n * du champ : l'agent sait quoi corriger au lieu de conclure le geste impossible.\n */\nfunction parseTyped(name: string, schema: z.ZodType, raw: string | undefined): unknown {\n if (raw === undefined) return undefined;\n // « null » efface quand le champ l'accepte, avant d'être lu comme le texte « null ».\n let result = raw.trim() === 'null' ? schema.safeParse(null) : schema.safeParse(raw);\n if (!result.success && raw.trim() === 'null') result = schema.safeParse(raw);\n if (!result.success) {\n const text = raw.trim();\n const json = listItem(text);\n if (json !== text) result = schema.safeParse(json);\n if (!result.success && !/^[[{]/.test(text)) {\n const list = schema.safeParse(toList(text).map(listItem));\n if (list.success) result = list;\n }\n }\n if (!result.success) throw new Error(`${name}: ${z.prettifyError(result.error)}`);\n return result.data;\n}\n\n/** Un id pour chaque élément qui n'en donne pas, comme l'interface le fait à l'ajout. */\nfunction withIds<T extends { id?: string }>(items: T[]): (T & { id: string })[] {\n return items.map((item) => ({ ...item, id: item.id || newId() }));\n}\n\nconst optionalId = <T extends z.ZodObject<{ id: z.ZodString }>>(schema: T) =>\n schema.extend({ id: z.string().min(1).max(64).optional() });\n\n/**\n * La configuration Docker, telle qu'un agent doit la donner pour que le\n * conteneur démarre : exactement une source d'image — `image` à tirer, ou un\n * `dockerfile` à construire. Le schéma partagé ne l'impose pas (l'interface\n * garde l'autre champ en mémoire pendant qu'on bascule), l'outil si.\n */\nconst DockerConfigInput = DockerConfigSchema.extend({\n bootstrapCommands: z.array(optionalId(BootstrapCommandSchema)).max(20).default([]),\n}).refine((c) => !!c.image !== !!c.dockerfile, {\n message: 'dockerConfig needs exactly one of \"image\" (an image to pull) or \"dockerfile\" (a Dockerfile to build)',\n});\n\ninterface ServiceField {\n name: string;\n description: string;\n /** Absent : un texte simple. */\n schema?: z.ZodType;\n /** `service.update` accepte `null` pour effacer ce champ. */\n clearable?: boolean;\n}\n\n/**\n * Chaque champ écrivable d'un service, typé par le schéma partagé\n * (`ServiceConfigSchema`). `capabilities-routes.test.ts` vérifie qu'il n'en\n * manque aucun de ceux que les routes acceptent.\n */\nconst SERVICE_FIELDS: ServiceField[] = [\n { name: 'description', description: 'What the service is, in a sentence' },\n { name: 'agentId', description: 'The agent that runs it, from list_agents. Omit to inherit from the environment.', clearable: true },\n { name: 'cwd', description: \"Working directory, RELATIVE to the project root (e.g. \\\"apps/web\\\", or omit for the root). The project is synced between machines and lives in a different folder on each: Runeya resolves a relative cwd against each machine's own project folder, while an absolute path (/home/you/…) breaks on every other machine. Use an absolute path only for something outside the project, written with ~ or an environment variable ($NAME) rather than a literal home directory.\", clearable: true },\n { name: 'command', description: 'Shortcut for a single command line (e.g. \"npm run dev\"). Replaces every existing command. Use commands for several.' },\n { name: 'commands', description: 'The processes of the service. They all start AT THE SAME TIME, in parallel, and the service runs while they run — not one after another. Use several for processes that live side by side (a web server and a worker). Steps that must follow each other (build, then install, then launch) go in ONE command chained with &&. A one-off action the user triggers by hand (build, deploy, read logs) is a shortcut, not a command. Each command runs in the service cwd, or its own \"cwd\", relative to the project root. No absolute paths of this machine: the service is synced to other machines. Replaces every existing command. \"id\" is generated when omitted; \"shell\" runs the line through a shell (default true).', schema: z.array(optionalId(ServiceCommandSchema)).max(50) },\n { name: 'ports', description: 'Ports the service listens on. Declare them: they become {{service.PORT}}, {{service.URL}} and {{services.<slug>.URL}} for the other services, which environment variables should reference instead of repeating the numbers.', schema: ServiceConfigSchema.shape.ports.unwrap().unwrap() },\n { name: 'groups', description: 'Groups the service belongs to. Replaces the current ones.', schema: ServiceConfigSchema.shape.groups.unwrap().unwrap() },\n { name: 'url', description: 'URL where the service is reached' },\n { name: 'localUrls', description: 'Local domain names routed to a port of the service (e.g. {\"url\":\"api.localhost.dev\",\"port\":3000})', schema: ServiceConfigSchema.shape.localUrls.unwrap().unwrap() },\n { name: 'openapiUrl', description: 'URL of its OpenAPI document' },\n { name: 'docsPath', description: \"Where its markdown docs live, relative to cwd or absolute. Defaults to cwd.\" },\n { name: 'git', description: 'Its git repository: \"remote\" URL and \"home\" page', schema: ServiceConfigSchema.shape.git.unwrap(), clearable: true },\n { name: 'meta', description: 'Free key/value metadata (strings)', schema: ServiceConfigSchema.shape.meta.unwrap(), clearable: true },\n { name: 'runner', description: '\"native\" runs the commands on the machine; \"docker\" runs the service in a container and then needs dockerConfig', schema: ServiceConfigSchema.shape.runner.unwrap().unwrap() },\n { name: 'dockerConfig', description: 'With runner \"docker\": the container. Exactly one of \"image\" (pull) or \"dockerfile\" (inline Dockerfile, built with \"buildContext\", \"buildArgs\", \"targetStage\"). Ports and volumes use Docker syntax (\"8080:80\", \"./data:/data\"); host paths in volumes relative to the service directory, never an absolute path of this machine. \"useNativeCommand\" runs the service commands inside the container instead of its CMD (\"nativeCommandMode\": one shared container or one per command). \"bootstrapCommands\" run once when the container starts. Replaces the whole Docker configuration: read it first with get_service to keep what you do not change.', schema: DockerConfigInput },\n { name: 'healthCheck', description: 'How to tell the service is ready: an HTTP \"path\" to call, or a \"command\" that must succeed', schema: HealthCheckSchema, clearable: true },\n { name: 'autoRestart', description: 'Restart the service when it crashes', schema: z.boolean() },\n { name: 'restartStrategy', description: 'When to restart it', schema: RestartStrategySchema.unwrap() },\n { name: 'maxRestarts', description: 'Give up after this many restarts', schema: ServiceConfigSchema.shape.maxRestarts.unwrap() },\n { name: 'restartBackoffMs', description: 'Delay before a restart, in milliseconds', schema: ServiceConfigSchema.shape.restartBackoffMs.unwrap().unwrap() },\n { name: 'clearLogsOnStart', description: 'Clear the logs each time the service starts', schema: z.boolean() },\n { name: 'shortcuts', description: 'One-click actions shown on the service, run on demand and independently of the running commands (build, deploy, migrate, read logs). Same path rules as commands: relative to the project root, never an absolute path of this machine. Replaces the current ones. \"id\" is generated when omitted.', schema: z.array(optionalId(ServiceShortcutSchema)).max(50) },\n { name: 'parserIds', description: 'Log parsers applied to its output, by id', schema: ServiceConfigSchema.shape.parserIds.unwrap() },\n { name: 'logSources', description: 'Extra log sources beyond the console output (files, databases…). Replaces the current ones. Credentials (mongo connectionString, mysql password) read as \"***\": send \"***\" back to keep the stored value, or the real value to change it.', schema: ServiceConfigSchema.shape.logSources.unwrap().unwrap() },\n];\n\nfunction serviceParams(clearable: boolean): CapabilityParam[] {\n return SERVICE_FIELDS.map((f) => {\n const nullable = clearable && f.clearable;\n const base = f.schema ?? (nullable ? z.string() : undefined);\n return {\n name: f.name,\n description: nullable ? `${f.description} null clears it.` : f.description,\n required: false,\n ...(base ? { schema: nullable ? base.nullable() : base } : {}),\n };\n });\n}\n\nfunction serviceFields(p: Record<string, string | undefined>, params: CapabilityParam[]): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const param of params) {\n if (p[param.name] === undefined || param.name === 'command') continue;\n out[param.name] = param.schema ? parseTyped(param.name, param.schema, p[param.name]) : p[param.name];\n }\n if (p.command !== undefined && p.commands === undefined) out['commands'] = [{ label: '', command: p.command, shell: true }];\n if (Array.isArray(out['commands'])) out['commands'] = withIds(out['commands'] as { id?: string }[]);\n if (Array.isArray(out['shortcuts'])) out['shortcuts'] = withIds(out['shortcuts'] as { id?: string }[]);\n const docker = out['dockerConfig'] as { bootstrapCommands?: { id?: string }[] } | undefined;\n if (docker?.bootstrapCommands) out['dockerConfig'] = { ...docker, bootstrapCommands: withIds(docker.bootstrapCommands) };\n return out;\n}\n\n/**\n * Un service, ou une liste de services, tels qu'une IA peut les lire : les\n * identifiants de leurs sources de logs masqués. `service.get` les rend en clair\n * parce que l'interface les édite ; `update_service` accepte le masque en retour\n * et garde la valeur en place (`restoreLogSourceSecrets`).\n */\nfunction maskServices(result: unknown): unknown {\n if (Array.isArray(result)) return result.map(maskServices);\n if (result && typeof result === 'object' && Array.isArray((result as { logSources?: unknown }).logSources)) {\n const service = result as { logSources: LogSourceConfig[] };\n return { ...service, logSources: maskLogSourceSecrets(service.logSources) };\n }\n return result;\n}\n\n/**\n * Les variables intégrées, telles qu'un modèle doit les connaître pour composer\n * une valeur : tirées de `BUILTIN_VARIABLES`, la seule déclaration, pour qu'un\n * ajout y parvienne sans que personne pense à la description.\n */\nconst refs = (scope: 'server' | 'agent') => BUILTIN_VARIABLES\n .filter((b) => b.scope === scope)\n .map((b) => `{{${b.name}}}`)\n .join(', ');\nconst BUILTINS_HELP = `Built-in references Runeya fills itself — filled when the service is deployed, from the service that receives the variable: ${refs('server')}, the numbered {{service.PORT_2}} / {{service.URL_2}}… for its other ports, and {{services.<slug>.PORT}}, .URL, .BASE_URL, .NAME, .ID for a sibling service of the project (slug = its name in lowercase-dashes). Filled on the machine when the service starts: ${refs('agent')}.`;\n\nconst CREATE_SERVICE_PARAMS = serviceParams(false);\nconst UPDATE_SERVICE_PARAMS = serviceParams(true);\n\nexport const RUNEYA_CAPABILITIES: RuneyaCapability[] = [\n {\n name: 'list_services',\n transformOutput: maskServices,\n description: \"List services, with the serviceId and agentId to use in other calls. Pass the projectId your context names to stay on the project the user is looking at, or another one from list_projects to look elsewhere. Called with no project, this can answer for every project of every organization on the machine — far more than the interface shows.\",\n route: 'service.list',\n method: 'GET',\n params: [\n { name: 'projectId', description: 'Restrict to this project, from list_projects. Omit to list every service on the machine.', required: false },\n { name: 'orgId', description: 'Its organization. Needed only when the same project id exists in several.', required: false },\n ],\n buildInput: (p) => (p.projectId\n ? { projectId: p.projectId, ...(p.orgId ? { orgId: p.orgId } : {}) }\n : undefined),\n },\n {\n name: 'get_service_status',\n description: \"Get the current status (running, stopped, etc.) of a service. A service that has never been started on this agent has no process yet, and this answers 404 Process not found — that means STOPPED, not forbidden and not missing. Start it, or read its configuration with get_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 { name: 'organizationId', description: 'Which organization the attachment belongs to. Optional: needed only when the account belongs to several and the error message asks for it.', required: false },\n ],\n buildInput: (p) => ({\n attachmentId: p.attachmentId,\n ...(p.organizationId ? { orgId: p.organizationId } : {}),\n }),\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_conversations',\n description: 'Read the customer support conversations (Intercom…) linked to one kanban card: for each, its title, provider, state (open/resolved), link, the opening message and the thread of messages (author name, customer or team, internal note or not, date, text, attached files — fetch their bytes with kanban_download_attachment), plus the other cards following the same conversation. These messages are NOT comments of the card — read them here.',\n route: 'kanban.getCardConversations',\n method: 'GET',\n params: [\n { name: 'boardId', description: 'The kanban board ID', required: true },\n { name: 'cardId', description: 'The card ID whose conversations to read', required: true },\n { name: 'limit', description: 'How many of the most recent messages to return per conversation (1-500). Default: 100.', required: false },\n ],\n buildInput: (p) => ({\n boardId: p.boardId,\n cardId: p.cardId,\n ...(p.limit ? { limit: Number(p.limit) } : {}),\n }),\n usageHint: '\"regarde la conversation Intercom de la carte\" / \"qu\\'a dit le client\" → kanban_get_card_conversations(boardId, cardId).',\n },\n {\n name: 'kanban_search_conversations',\n description: \"Search customer support conversations (Intercom…) at the providers connected to the board's organization, by words of the conversation title, or by conversation number or URL. Read-only at the provider. Each result gives connectionId and externalId (needed to link it), title, state, a preview and the cards already following it.\",\n route: 'kanban.searchConversations',\n method: 'GET',\n params: [\n { name: 'boardId', description: 'Any kanban board ID of the organization to search in', required: true },\n { name: 'query', description: 'Words of the conversation title, a conversation number, or a conversation URL', required: true },\n ],\n buildInput: (p) => ({ boardId: p.boardId, query: p.query }),\n },\n {\n name: 'kanban_link_conversation',\n description: 'Link a customer support conversation found with kanban_search_conversations to a kanban card. Its whole thread is imported and new messages keep arriving on the card. A conversation can be linked to several cards. Nothing is written at the provider.',\n route: 'kanban.linkConversation',\n method: 'POST',\n params: [\n { name: 'boardId', description: 'The kanban board ID of the card', required: true },\n { name: 'cardId', description: 'The card to link the conversation to', required: true },\n { name: 'connectionId', description: 'The connectionId of the search result', required: true },\n { name: 'externalId', description: 'The externalId of the search result', required: true },\n ],\n buildInput: (p) => ({ boardId: p.boardId, cardId: p.cardId, connectionId: p.connectionId, externalId: p.externalId }),\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 // ─── Lecture seule ───────────────────────────────────────────────────────\n //\n // Tout ce qui se consulte sans rien changer. Les écritures s'ajoutent au cas\n // par cas : aujourd'hui les services et leurs variables, plus bas.\n //\n // Volontairement absentes, et à ne pas ajouter sans y regarder à deux fois,\n // parce qu'elles rendent un secret : `environment.list` / `get` / `resolve` /\n // `resolveFlat` (un `Environment` porte ses variables, valeurs comprises),\n // `apiKeys.list` / `reveal`, `setup.getEncryptionKeyHex` et `getOrgKeys`\n // (clés de chiffrement), `settings.get` et `settings.listAIProviders` (clés\n // de fournisseurs d'IA — `settings.getPaths` et `getNetwork`, eux, ne\n // rendent que des chemins et une adresse, d'où leur présence ci-dessous),\n // `cloudAuth.session`, `agent.getPassthroughEnv`. Un agent n'a pas besoin de\n // ces valeurs pour travailler, et ce qu'il lit finit dans une transcription.\n //\n // La seule exception est `service.getEnv` (`get_service_env` ci-dessous),\n // et elle n'en est une que parce qu'elle filtre : les variables publiques, et\n // les seuls secrets que leur auteur a partagés avec les IA (`isSharedWithAi`\n // — « Lisible par l'IA », ou l'injection, qui vaut la lecture). Un secret non\n // partagé n'y apparaît pas, pas même par son nom.\n {\n name: 'list_processes',\n description: \"List every process across all agents with its current state (running, stopped, exit code, uptime). Use this to see the whole machine at once, rather than calling get_service_status service by service. An agent only learns about a service when it is first started, so this lists what is deployed, not what is configured: an empty list means nothing has been started, not that you cannot see them — list_services shows what exists.\",\n route: 'process.list',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'get_service',\n transformOutput: maskServices,\n description: 'Read the full configuration of one service: its commands, ports, groups, runner, log sources and restart policy. list_services gives the ids.',\n route: 'service.get',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'The service ID', required: true },\n ],\n buildInput: (p) => ({ id: p.serviceId }),\n },\n {\n name: 'get_service_env',\n description: \"Read the environment variables a service runs with, and the project's variable inventory. `env` lists every key the service receives; a value reads \\\"***\\\" when it is a secret whose author did not share it with AI (sharing = ticking \\\"AI read\\\", or injecting it into the agents\\u0027 environment, which grants reading too). `envSecrets` says which keys are secret, `hiddenKeys` which ones are masked. A masked key is set on the service: never treat it as missing, never suggest adding it, and never pass \\\"***\\\" as a value — ask the user for it. `variables` describes every variable of the project — which environment defines it and its scope, its description, its flags, whether this machine overrides it, and `inService: false` for the ones this service does not receive. Use it to say where a variable must be changed instead of guessing. On an overridden variable, `sharedValue` is what the machine-local override replaces (the team's value, masked as \\\"***\\\" when unreadable); no other value appears there. This is the resolver: the values are what the service would receive — inheritance, {{environment.KEY}} references, this machine's overrides and server built-ins applied; agent built-ins stay as written until the service starts. Use it to check a variable you just composed. `unresolvedReferences` lists references nothing will fill (a typo, a variable that does not exist): fix them.\",\n route: 'service.getEnv',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'The service ID', required: true },\n { name: 'environmentId', description: 'A global environment of the project to resolve in instead of the active one, without activating it (from list_environments). Omit for the active one.', required: false },\n ],\n buildInput: (p) => ({ id: p.serviceId, ...(p.environmentId ? { environmentId: p.environmentId } : {}) }),\n },\n // ─── Écrire un service et ses variables ────────────────────────────────────\n //\n // Les variables s'écrivent à l'aveugle (`environment.setVariableBlind`) : une\n // IA remplace la valeur d'un secret sans la lire, et ne peut ni le rendre\n // public, ni le partager avec les IA. La règle tient côté serveur, dans la\n // route ; ces outils ne passent jamais par une route qui renvoie des valeurs\n // (`upsertVariable`, `removeVariable`, `update` rendent l'environnement entier).\n {\n name: 'create_service',\n transformOutput: maskServices,\n description: \"Create a service, native or Docker, in a project: it joins the project and gets its environments in the same call. Pass the projectId your context names. Projects are synced between machines, so write paths relative to the project root and put machine-specific values (a device serial, a local token) in environment variables, referenced as $NAME in commands — see the cwd, commands and shortcuts parameters. Then set its variables with set_environment_variable.\",\n route: 'service.create',\n method: 'POST',\n params: [\n { name: 'name', description: 'The service name', required: true },\n { name: 'projectId', description: 'The project it joins: the one your context names, or another from list_projects. Without it, the service belongs to no project.', required: false },\n { name: 'orgId', description: 'Its organization. Needed only when the same project id exists in several.', required: false },\n ...CREATE_SERVICE_PARAMS,\n ],\n buildInput: (p) => {\n const fields = serviceFields(p, CREATE_SERVICE_PARAMS);\n if (fields['runner'] === 'docker' && !fields['dockerConfig']) {\n throw new Error('dockerConfig: required with runner \"docker\" — give an \"image\" or a \"dockerfile\"');\n }\n return {\n name: p.name,\n ...fields,\n ...(p.projectId ? { projectId: p.projectId } : {}),\n ...(p.orgId ? { orgId: p.orgId } : {}),\n };\n },\n },\n {\n name: 'add_service_to_project',\n description: \"Add an existing service to a project, and create its environments — one for each of the project's environments, where its own variables go. Not needed after create_service, which already does it; calling it again changes nothing.\",\n route: 'project.addService',\n method: 'POST',\n params: [\n { name: 'projectId', description: 'The project ID, from list_projects', required: true },\n { name: 'serviceId', description: 'The service ID', required: true },\n { name: 'orgId', description: 'Its organization. Needed only when the same project id exists in several.', required: false },\n ],\n buildInput: (p) => ({ projectId: p.projectId, serviceId: p.serviceId, ...(p.orgId ? { orgId: p.orgId } : {}) }),\n },\n {\n name: 'update_service',\n transformOutput: maskServices,\n description: 'Change any part of a service configuration — commands, ports, health check, restart policy, shortcuts, log sources, whether it runs natively or in Docker (runner, dockerConfig)… Only the fields you pass change; a list or an object you pass replaces the current one whole. Read the service first with get_service.',\n route: 'service.update',\n method: 'POST',\n params: [\n { name: 'serviceId', description: 'The service ID', required: true },\n { name: 'name', description: 'New name', required: false },\n { name: 'orgId', description: 'Move the service to this organization vault. Leave unset unless asked.', required: false, schema: z.string().max(128).nullable() },\n ...UPDATE_SERVICE_PARAMS,\n ],\n buildInput: (p) => ({\n id: p.serviceId,\n ...(p.name ? { name: p.name } : {}),\n ...(p.orgId !== undefined ? { orgId: parseTyped('orgId', z.string().max(128).nullable(), p.orgId) } : {}),\n ...serviceFields(p, UPDATE_SERVICE_PARAMS),\n }),\n },\n {\n name: 'list_environments',\n description: \"List the environments of a project, with no value: each one's id, name and scope (global = shared by the whole project, service = one service's own variables), which global environment is active, which service a service environment belongs to and which global environment activates it, its parents (it inherits their variables), `isolated` when a service environment does not inherit from its global one, and the variables it defines with their flags. Empty environments are listed too — a service you just created has one per global environment, where its own variables go. Use it to find the environmentId before set_environment_variable.\",\n route: 'environment.listForAi',\n method: 'GET',\n params: [\n { name: 'projectId', description: 'The project ID: the one your context names, or another from list_projects', required: true },\n { name: 'orgId', description: 'Its organization. Needed only when the same project id exists in several.', required: false },\n ],\n buildInput: (p) => ({ projectId: p.projectId, ...(p.orgId ? { orgId: p.orgId } : {}) }),\n },\n {\n name: 'resolve_environment',\n description: \"Resolve one environment alone — its variables with those inherited from its parents and this machine's overrides — as an AI may read it: secrets not shared with AI read \\\"***\\\". Built-in references ({{service.*}}, {{services.*}}, {{agent.*}}…) are NOT filled, since they depend on the service that receives the variable; use get_service_env for a service's final values. `unresolvedReferences` lists references nothing will fill: a misspelled {{environment.KEY}}, or a name that is no built-in.\",\n route: 'environment.resolveForAi',\n method: 'GET',\n params: [\n { name: 'environmentId', description: 'The environment, from list_environments', required: true },\n ],\n buildInput: (p) => ({ environmentId: p.environmentId }),\n },\n {\n name: 'set_environment_variable',\n description: `Create or change an environment variable, by name, in one environment — global or service, same rules for both. Find the environmentId with list_environments. Where it belongs: a value shared by several services (a database host, an API base URL) goes ONCE in the active global environment; services inherit it. A value only one service needs goes in that service's environment (scope service, activated by the active global one), where it also overrides a global variable of the same name. Never hardcode what Runeya already knows: a service's own port is {{service.PORT}}, its own URL {{service.URL}}, another service's address {{services.<slug>.URL}} — a copied \"3210\" or \"http://localhost:3211\" breaks as soon as a port changes or the project runs on another machine. If the port a variable needs is not declared on its service, declare it there (update_service, ports) instead of writing the number. When a written value contains a port or URL of a project service, the response lists \\`suggestions\\`: rewrite the value with those references. Compose instead of copying: a value can reference another variable of the resolved environment as {{environment.KEY}} (e.g. \"postgres://{{environment.DB_USER}}@{{environment.DB_HOST}}:5432\"). ${BUILTINS_HELP} After writing, check the result with get_service_env (a service, optionally in another global environment) or resolve_environment (an environment alone). References are substituted in one pass: a reference to a variable whose own value is only a reference may stay unexpanded, so point at the variable that holds the actual value. $NAME is not a reference here: it only expands inside a shell command. pre and post are concatenated around the value, each resolved separately. You can replace a secret's value without reading it, and create a variable as secret. You cannot make a secret public nor make it readable by AI: that stays the user's decision. Never pass \"***\" as a value. The response never contains the value.`,\n route: 'environment.setVariableBlind',\n method: 'POST',\n params: [\n { name: 'environmentId', description: 'The environment that holds the variable, from list_environments', required: true },\n { name: 'key', description: 'The variable name, e.g. DATABASE_URL', required: true },\n { name: 'value', description: 'The new value, possibly with {{environment.KEY}} references. Omit to leave it unchanged.', required: false },\n { name: 'pre', description: 'Text put before the value (e.g. \"https://\"). Omit to leave it unchanged.', required: false },\n { name: 'post', description: 'Text put after the value (e.g. \"/api\"). Omit to leave it unchanged.', required: false },\n { name: 'isSecret', description: '\"true\" to store it as a secret. On an existing public variable, makes it secret.', required: false },\n { name: 'description', description: 'What the variable is for, in markdown', required: false },\n ],\n buildInput: (p) => ({\n environmentId: p.environmentId,\n key: p.key,\n ...(p.value !== undefined ? { value: p.value } : {}),\n ...(p.pre !== undefined ? { pre: p.pre } : {}),\n ...(p.post !== undefined ? { post: p.post } : {}),\n ...(p.isSecret !== undefined ? { isSecret: toBool(p.isSecret) } : {}),\n ...(p.description !== undefined ? { description: p.description } : {}),\n }),\n },\n {\n name: 'set_environment_inheritance',\n description: \"Switch whether a service environment inherits the variables of the global environment that activates it (the default), or is isolated from it and receives only its own variables. list_environments shows this as `isolated`. Isolating a service is unusual: it loses every shared variable of the project. Do it only when the user asks, and never to work around a variable — override it in the service environment instead.\",\n route: 'environment.setInheritanceBlind',\n method: 'POST',\n params: [\n { name: 'environmentId', description: 'A service environment (scope service), from list_environments', required: true },\n { name: 'inherit', description: '\"true\" to inherit from the global environment, \"false\" to isolate', required: true, schema: z.boolean() },\n ],\n buildInput: (p) => ({ environmentId: p.environmentId, inherit: toBool(p.inherit ?? 'true') }),\n },\n {\n name: 'remove_environment_variable',\n description: 'Delete an environment variable, by name, from one environment. Its value is lost.',\n route: 'environment.removeVariableBlind',\n method: 'POST',\n params: [\n { name: 'environmentId', description: 'The environment that holds the variable', required: true },\n { name: 'key', description: 'The variable name', required: true },\n ],\n buildInput: (p) => ({ environmentId: p.environmentId, key: p.key }),\n destructive: true,\n },\n {\n name: 'get_service_metrics',\n description: 'Read the CPU and memory currently used by a running service.',\n route: 'process.metrics',\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: 'list_agents',\n description: 'List the agents connected to this Runeya, with their status and whether they run on this machine. Passphrases are never returned.',\n route: 'agent.list',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'list_projects',\n description: 'List the projects known to this Runeya, with their ids and the services they hold.',\n route: 'project.list',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'get_project',\n description: 'Read one project: its services, its active environment, its organization.',\n route: 'project.get',\n method: 'GET',\n params: [\n { name: 'projectId', description: 'The project ID, from list_projects', required: true },\n { name: 'orgId', description: 'Its organization. Needed only when the same project id exists in several.', required: false },\n ],\n buildInput: (p) => ({ id: p.projectId, ...(p.orgId ? { orgId: p.orgId } : {}) }),\n },\n {\n name: 'list_project_paths',\n description: 'Where each project lives on this machine. Use it to find the directory to work in before reading or editing files.',\n route: 'project.localPaths',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'git_status',\n description: 'Read the git working tree of a service or a project: staged, modified and untracked files, current branch, ahead/behind counts.',\n route: 'git.status',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'Target the repository of this service', required: false },\n { name: 'projectId', description: 'Target the repository of this project, when no service is given', required: false },\n { name: 'agentId', description: 'The agent hosting the repository', required: false },\n { name: 'orgId', description: 'Its organization, when a project id alone is ambiguous', required: false },\n ],\n buildInput: (p) => gitTarget(p),\n },\n {\n name: 'git_log',\n description: 'Read the recent commits of a service or project repository: hash, author, date, message.',\n route: 'git.log',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'Target the repository of this service', required: false },\n { name: 'projectId', description: 'Target the repository of this project, when no service is given', required: false },\n { name: 'agentId', description: 'The agent hosting the repository', required: false },\n { name: 'orgId', description: 'Its organization, when a project id alone is ambiguous', required: false },\n { name: 'limit', description: 'How many commits to return (1-200). Default: 50.', required: false },\n ],\n buildInput: (p) => ({ ...gitTarget(p), ...(p.limit ? { limit: Number(p.limit) } : {}) }),\n },\n {\n name: 'git_branches',\n description: 'List the local and remote branches of a service or project repository.',\n route: 'git.branches',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'Target the repository of this service', required: false },\n { name: 'projectId', description: 'Target the repository of this project, when no service is given', required: false },\n { name: 'agentId', description: 'The agent hosting the repository', required: false },\n { name: 'orgId', description: 'Its organization, when a project id alone is ambiguous', required: false },\n ],\n buildInput: (p) => gitTarget(p),\n },\n {\n name: 'git_diff',\n description: 'Read the diff of a service or project repository — everything, or one file. Use it to see what changed before describing or reviewing it.',\n route: 'git.diff',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'Target the repository of this service', required: false },\n { name: 'projectId', description: 'Target the repository of this project, when no service is given', required: false },\n { name: 'agentId', description: 'The agent hosting the repository', required: false },\n { name: 'orgId', description: 'Its organization, when a project id alone is ambiguous', required: false },\n { name: 'path', description: 'Restrict the diff to this file path', required: false },\n { name: 'staged', description: 'Set to \"true\" to read the staged diff instead of the working tree', required: false },\n { name: 'untracked', description: 'Set to \"true\" to include untracked files', required: false },\n ],\n buildInput: (p) => ({\n ...gitTarget(p),\n ...(p.path ? { path: p.path } : {}),\n ...(p.staged !== undefined ? { staged: p.staged === 'true' } : {}),\n ...(p.untracked !== undefined ? { untracked: p.untracked === 'true' } : {}),\n }),\n },\n {\n name: 'list_docs',\n description: 'List the markdown documentation files of a scope, as a tree. Pair it with read_doc to answer from the project\\'s own docs rather than from guesswork.',\n route: 'wiki.list',\n method: 'GET',\n params: [\n { name: 'scope', description: '\"global\" for this Runeya, or \"service:<serviceId>\" for one service\\'s repository', required: true },\n ],\n buildInput: (p) => ({ scope: p.scope }),\n },\n {\n name: 'read_doc',\n description: 'Read one markdown documentation file. Paths come from list_docs; only .md and .markdown can be read.',\n route: 'wiki.read',\n method: 'GET',\n params: [\n { name: 'scope', description: '\"global\" for this Runeya, or \"service:<serviceId>\" for one service\\'s repository', required: true },\n { name: 'path', description: 'Relative path of the file, as returned by list_docs', required: true },\n ],\n buildInput: (p) => ({ scope: p.scope, path: p.path }),\n },\n {\n name: 'get_server_logs',\n description: \"Read Runeya's own recent log entries. Use it to explain why Runeya itself misbehaved — not to read a service's output, which is get_logs.\",\n route: 'diagnostics.recentLogs',\n method: 'GET',\n params: [\n { name: 'limit', description: 'How many entries to return (1-2000). Default: 500.', required: false },\n ],\n buildInput: (p) => (p.limit ? { limit: Number(p.limit) } : undefined),\n },\n {\n name: 'get_kanban_queue_state',\n description: 'Read the state of the kanban task queue: what is running, what is waiting. Use it before queuing work, or to explain why a card has not started.',\n route: 'kanbanQueue.getState',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'export_project',\n description: \"Read a project and every service it holds in one call, with secrets stripped out. Cheaper and safer than calling get_service for each service — prefer it whenever you need the whole picture of a project.\",\n route: 'project.export',\n method: 'GET',\n params: [\n { name: 'projectId', description: 'The project ID, from list_projects', required: true },\n { name: 'orgId', description: 'Its organization. Needed only when the same project id exists in several.', required: false },\n ],\n buildInput: (p) => ({ id: p.projectId, ...(p.orgId ? { orgId: p.orgId } : {}) }),\n },\n {\n name: 'git_remotes',\n description: 'List the git remotes of a service or project repository, with their URLs.',\n route: 'git.remotes',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'Target the repository of this service', required: false },\n { name: 'projectId', description: 'Target the repository of this project, when no service is given', required: false },\n { name: 'agentId', description: 'The agent hosting the repository', required: false },\n { name: 'orgId', description: 'Its organization, when a project id alone is ambiguous', required: false },\n ],\n buildInput: (p) => gitTarget(p),\n },\n {\n name: 'git_stash_list',\n description: 'List the stashes of a service or project repository. Useful before assuming work was lost: it may simply be stashed.',\n route: 'git.stashList',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'Target the repository of this service', required: false },\n { name: 'projectId', description: 'Target the repository of this project, when no service is given', required: false },\n { name: 'agentId', description: 'The agent hosting the repository', required: false },\n { name: 'orgId', description: 'Its organization, when a project id alone is ambiguous', required: false },\n ],\n buildInput: (p) => gitTarget(p),\n },\n {\n name: 'get_runeya_version',\n description: 'Read the version of Runeya running here, the latest published one, and whether this install is up to date. Use it before blaming a bug on the code: the machine may simply be behind.',\n route: 'health.versionInfo',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'get_runeya_paths',\n description: \"Read where Runeya keeps its things on this machine: its launch directory, its data directory, and the machine-wide directory holding cloud projects.\",\n route: 'settings.getPaths',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'get_network_info',\n description: 'Read where this Runeya listens (host and port) and whether it is reachable from the local network, with the URLs to use. Use it to give someone a working link instead of guessing one.',\n route: 'settings.getNetwork',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'list_runeya_instances',\n description: 'List every Runeya answering on this machine, this one included, with its port and directory. Use it when a port is taken or when two instances seem to disagree.',\n route: 'diagnostics.instances',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'get_cloud_status',\n description: 'Say whether this Runeya is linked to a cloud account, and to which cloud. A kanban tool failing for lack of a cloud link is explained here.',\n route: 'cloudAuth.status',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n];\n","import { z } from 'zod';\nimport type { CapabilityParam } from '../capabilities.js';\n\n/** La propriété JSON Schema d'un paramètre : son schéma réel s'il en a un, une chaîne sinon. */\nexport function paramJsonSchema(param: CapabilityParam): Record<string, unknown> {\n if (!param.schema) return { type: 'string', description: param.description };\n const { $schema: _ignored, ...schema } = z.toJSONSchema(param.schema, { io: 'input', unrepresentable: 'any' }) as Record<string, unknown>;\n return { ...schema, description: param.description };\n}\n","import type { RuneyaCapability } from '../capabilities.js';\nimport { paramJsonSchema } from './json-schema.js';\n\nexport interface AnthropicTool {\n name: string;\n description: string;\n input_schema: {\n type: 'object';\n properties: Record<string, Record<string, unknown>>;\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, paramJsonSchema(p)]),\n ),\n required: cap.params.filter(p => p.required).map(p => p.name),\n },\n }));\n}\n","import type { RuneyaCapability } from '../capabilities.js';\nimport { paramJsonSchema } from './json-schema.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, Record<string, unknown>>;\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, paramJsonSchema(p)]),\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","import { z } from 'zod';\nimport type { RuneyaCapability } from '../capabilities.js';\n\n/**\n * Le schéma d'entrée d'un outil MCP : le schéma réel de chaque paramètre typé,\n * une chaîne pour les autres. Le client MCP le transmet au modèle tel quel,\n * types, énumérations et valeurs par défaut compris.\n */\nexport function buildMcpShape(cap: RuneyaCapability): Record<string, z.ZodType> {\n const shape: Record<string, z.ZodType> = {};\n for (const param of cap.params) {\n const base = (param.schema ?? z.string()).describe(param.description);\n shape[param.name] = param.required ? base : base.optional();\n }\n // authToken is MCP-specific: CLI runners pass the JWT here\n shape['authToken'] = z.string().describe('Bearer token for authentication').optional();\n return shape;\n}\n\n/**\n * Ce qu'un modèle envoie, ramené aux chaînes que `buildInput` lit : un objet ou\n * une liste en JSON, un nombre ou un booléen en texte. Les paramètres typés\n * sont relus contre leur schéma dans `buildInput` ; passer la capacité garde le\n * `null` qui les efface.\n */\nexport function toRawParams(input: Record<string, unknown>, cap?: RuneyaCapability): Record<string, string | undefined> {\n // `null` sur un paramètre typé efface le champ ; sur un texte, il vaut absence.\n const typed = new Set(cap?.params.filter((p) => p.schema).map((p) => p.name));\n return Object.fromEntries(Object.entries(input).map(([k, v]) => [\n k,\n v === null && typed.has(k) ? 'null'\n : v == null ? undefined\n : typeof v === 'object' ? JSON.stringify(v) : String(v as string | number | boolean | bigint),\n ]));\n}\n","import type { RuneyaCapability } from './capabilities.js';\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 fetchImpl: typeof fetch = fetch,\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 fetchImpl(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\n/**\n * Exécuter une capacité : l'appel tRPC, puis le filtre de sa réponse. Le seul\n * chemin du MCP comme du chat intégré — un filtre posé sur la capacité vaut\n * donc pour les deux.\n */\nexport async function runCapability(\n cap: RuneyaCapability,\n baseUrl: string,\n params: Record<string, string | undefined>,\n authToken: string,\n fetchImpl: typeof fetch = fetch,\n): Promise<unknown> {\n const result = await callTrpc(baseUrl, cap.route, cap.method, cap.buildInput(params), authToken, fetchImpl);\n return cap.transformOutput ? cap.transformOutput(result) : result;\n}\n","import type { RuneyaCapability } from './capabilities.js';\n\n/** Le projet de la conversation : celui où Runeya a lancé le serveur MCP, ou celui du chat intégré. */\nexport interface ProjectAnchor {\n projectId?: string;\n orgId?: string;\n}\n\n/**\n * Ancrer un appel sur le projet de la conversation.\n *\n * `service.list` rend tout le poste : chaque coffre, donc chaque projet de\n * chaque organisation de la machine. L'interface n'en montre qu'un, et le\n * prompt de l'agent ne décrit que celui-là — mais la tool, elle, répondait 88\n * services quand l'écran en montrait trois. L'agent citait alors des services\n * que l'utilisateur n'a jamais vus, et concluait à un problème de permissions.\n *\n * Le projet est donc posé par Runeya au lancement du serveur MCP, et complété\n * ici plutôt que laissé à la bonne lecture d'une consigne.\n *\n * Ne complète QUE ce que la capability déclare et que l'appelant a laissé vide :\n * un `projectId` donné explicitement gagne toujours, ce qui laisse l'agent\n * interroger un autre projet — `list_projects` les nomme tous.\n */\nexport function applyProjectAnchor(\n cap: Pick<RuneyaCapability, 'params'>,\n params: Record<string, string | undefined>,\n anchor: ProjectAnchor,\n): Record<string, string | undefined> {\n if (!anchor.projectId) return params;\n\n const accepts = (name: string) => cap.params.some((p) => p.name === name);\n if (!accepts('projectId') || params['projectId']) return params;\n\n return {\n ...params,\n projectId: anchor.projectId,\n // L'organisation n'accompagne le projet que si la capability la comprend :\n // ailleurs, ce serait un champ de trop, refusé par le schéma de la route.\n ...(anchor.orgId && accepts('orgId') && !params['orgId'] ? { orgId: anchor.orgId } : {}),\n };\n}\n","import { z } from 'zod';\n\nexport const UserSchema = z.object({\n id: z.string().max(128),\n email: z.string().email().max(320),\n name: z.string().min(1).max(500),\n avatar: z.string().url().max(2048).nullable().optional(),\n});\n\nexport type User = z.infer<typeof UserSchema>;\n","import { z } from 'zod';\n\nexport const OrgSchema = z.object({\n id: z.string().max(128),\n name: z.string().min(1).max(100),\n slug: z.string().min(1).max(100).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/),\n ownerId: z.string().max(128),\n});\n\nexport type Org = z.infer<typeof OrgSchema>;\n\nexport const OrgMemberSchema = z.object({\n id: z.string().max(128),\n orgId: z.string().max(128),\n userId: z.string().max(128),\n globalRole: z.enum(['owner', 'admin', 'member']),\n invitedAt: z.coerce.date(),\n joinedAt: z.coerce.date().nullable().optional(),\n});\n\nexport type OrgMember = z.infer<typeof OrgMemberSchema>;\n","import { z } from 'zod';\n\nexport const ProjectSchema = z.object({\n id: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n name: z.string().min(1).max(200),\n description: z.string().max(10000).optional().default(''),\n serviceIds: z.array(z.string().max(128)).max(10000).default([]),\n\n // Environment support\n // NOTE: activeEnvironmentId is runtime-only (not persisted to JSON)\n // It's initialized to 'local' by default at load time\n activeEnvironmentId: z.string().max(128).optional(),\n environmentIds: z.array(z.string().max(128)).max(100).default([]),\n\n // Ordre d'affichage des groupes de services dans la sidebar (noms de groupes).\n // Les groupes absents de cette liste sont affichés après, par ordre alphabétique.\n groupOrder: z.array(z.string().max(200)).max(100).default([]),\n});\n\nexport type Project = z.infer<typeof ProjectSchema>;\n\nexport const CreateProjectSchema = ProjectSchema.omit({ id: true }).partial().required({ name: true });\nexport type CreateProject = z.infer<typeof CreateProjectSchema>;\n\nexport const UpdateProjectSchema = ProjectSchema.partial().required({ id: true });\nexport type UpdateProject = z.infer<typeof UpdateProjectSchema>;\n","import { z } from 'zod';\nimport { JSLogParserSchema } from './settings.schema.js';\nimport { LogSourceConfigSchema } from './log-source.schema.js';\n\nexport const HealthCheckSchema = z.object({\n type: z.enum(['http', 'command']).default('http'),\n // HTTP-specific (required when type=http)\n path: z.string().min(1).max(500).startsWith('/').optional(),\n method: z.enum(['GET', 'HEAD', 'POST', 'PUT']).optional().default('GET'),\n expectedStatus: z.number().int().min(100).max(599).optional().default(200),\n // Command-specific (required when type=command)\n command: z.string().min(1).max(4096).optional(),\n // Shared\n interval: z.number().int().positive().default(1000),\n timeout: z.number().int().positive().default(1000),\n retries: z.number().int().nonnegative().default(3),\n initialDelay: z.number().int().nonnegative().optional().default(0),\n}).refine(\n (data) => data.type === 'http' ? !!data.path : !!data.command,\n { message: 'HTTP type requires path; command type requires command' },\n);\n\nexport type HealthCheck = z.infer<typeof HealthCheckSchema>;\n\nexport const BootstrapCommandSchema = z.object({\n id: z.string().min(1).max(64),\n label: z.string().max(200).default(''),\n entrypoint: z.string().max(4096).optional(),\n command: z.string().max(4096).default(''),\n user: z.string().max(256).optional(),\n});\n\nexport type BootstrapCommand = z.infer<typeof BootstrapCommandSchema>;\n\nexport const DockerConfigSchema = z.object({\n // Image mode (pull from registry) — mutually exclusive with build mode in UI\n image: z.string().min(1).max(1024).optional(),\n\n // Build mode — Dockerfile stored inline in services.json\n dockerfile: z.string().max(65536).optional(),\n buildContext: z.string().max(4096).optional(),\n buildArgs: z.record(z.string().max(256), z.string().max(4096)).default({}).refine(\n (obj) => Object.keys(obj).length <= 50,\n { message: 'Max 50 build args' },\n ),\n targetStage: z.string().max(256).optional(),\n\n // Runtime config\n networkMode: z.enum(['host', 'bridge']).default('host'),\n ports: z.array(z.string().max(64)).max(100).default([]),\n volumes: z.array(z.string().max(1024)).max(100).default([]),\n mountRootpath: z.boolean().default(false),\n entrypoint: z.string().max(4096).optional(),\n command: z.string().max(4096).optional(),\n user: z.string().max(256).optional(),\n useNativeCommand: z.boolean().default(false),\n nativeCommandMode: z.enum(['shared', 'isolated']).default('isolated'),\n nativeShell: z.string().max(256).default('sh'),\n bootstrapCommands: z.array(BootstrapCommandSchema).max(20).default([]),\n});\n\nexport type DockerConfig = z.infer<typeof DockerConfigSchema>;\n\nexport const RestartStrategySchema = z.enum(['none', 'on-failure', 'always', 'unless-stopped']).default('none');\nexport type RestartStrategy = z.infer<typeof RestartStrategySchema>;\n\nexport const ServiceShortcutSchema = z.object({\n id: z.string().min(1).max(64),\n label: z.string().max(200).default(''),\n command: z.string().max(4096).default(''),\n cwd: z.string().max(4096).optional(),\n});\n\nexport type ServiceShortcut = z.infer<typeof ServiceShortcutSchema>;\n\nexport const ServiceCommandSchema = z.object({\n id: z.string().min(1).max(64),\n label: z.string().max(200).default(''),\n command: z.string().max(4096).default(''),\n cwd: z.string().max(4096).optional(),\n shell: z.boolean().optional().default(true),\n});\n\nexport type ServiceCommand = z.infer<typeof ServiceCommandSchema>;\n\n// --- Variable Slot Schema ---\n// A VariableSlot represents a single value with optional pre/post concatenation.\n// The final resolved value is: pre + interpolate(value) + post\nexport const VariableSlotSchema = z.object({\n value: z.string().max(8192).default(''),\n pre: z.string().max(8192).default(''),\n post: z.string().max(8192).default(''),\n isSecret: z.boolean().default(false),\n // Deux décisions distinctes, et il ne faut pas les confondre :\n //\n // - `shareWithAi` est une permission de **lecture** : une IA (le chat de\n // Runeya, un agent par le serveur MCP) peut voir la valeur de ce secret.\n // Une variable publique est lisible de toute façon, le drapeau ne la\n // concerne pas.\n // - `injectIntoAi` est une **exécution** : la variable est posée dans\n // l'environnement du process des agents (Claude Code, Codex, …) lancés\n // depuis Runeya pendant que cet environnement est actif.\n //\n // Les deux sont opt-in : sans rien cocher, aucun secret ne part vers une IA.\n // Injecter implique lire (ce que le process reçoit, l'agent le voit), donc\n // la lecture accepte l'un OU l'autre : voir `isSharedWithAi`, qui est le seul\n // endroit où cette règle s'écrit.\n shareWithAi: z.boolean().default(false),\n injectIntoAi: z.boolean().default(false),\n // Une variable obligatoire doit avoir une valeur finale non vide avant qu'un\n // service de cet environnement puisse démarrer. Le démarrage est refusé\n // sinon, avec la liste des manquantes — l'assistant est le moyen de remplir.\n required: z.boolean().default(false),\n // Une variable « seulement surchargeable » n'a jamais de valeur partagée :\n // `value` reste vide dans le document synchronisé, et chaque poste DOIT\n // fournir sa propre surcharge machine-locale (chemin local, jeton personnel).\n // `pre` et `post` restent partagés — ils décrivent la forme, pas le secret.\n overrideOnly: z.boolean().default(false),\n // À quoi sert cette variable, pour quelqu'un qui doit la remplir. Affichée\n // par l'assistant de complétion et dans l'éditeur.\n //\n // Du **markdown**, pas du texte brut : une description gagne à pouvoir\n // pointer vers la console qui délivre le jeton. Écrite et relue par le même\n // éditeur Tiptap (`packages/editor-ui`), jamais injectée en HTML — Tiptap\n // analyse le markdown dans son propre schéma, si bien qu'une description\n // arrivée d'un autre poste par la synchronisation ne peut rien exécuter.\n description: z.string().max(2000).default(''),\n}).refine(\n (slot) => !slot.overrideOnly || slot.value === '',\n { message: 'An override-only variable cannot carry a shared value', path: ['value'] },\n);\n\nexport type VariableSlot = z.infer<typeof VariableSlotSchema>;\n\n/**\n * Son auteur a-t-il partagé cette variable avec les IA ?\n *\n * Deux cases mènent au même oui : `shareWithAi`, le partage en lecture, et\n * `injectIntoAi`, car une variable posée dans l'environnement du process d'un\n * agent est de fait lisible par lui — la lui refuser à la lecture tout en la\n * lui passant ne protégerait rien et rendrait l'interface menteuse.\n *\n * Le seul endroit où cette règle s'écrit. Deux précautions d'emploi :\n *\n * - Le drapeau ne décide que du sort des **secrets**. Une variable publique est\n * lisible de toute façon, et savoir laquelle est secrète n'est pas affaire de\n * définition : une variable non marquée qui référence un secret le devient à\n * la résolution. C'est donc au filtre de croiser les deux.\n * - Il se lit sur la **définition**, jamais sur un slot de surcharge : une\n * surcharge remplace le slot entier et n'en porte aucun drapeau (même piège\n * que `findMissingVariables`).\n */\nexport function isSharedWithAi(slot: Pick<VariableSlot, 'shareWithAi' | 'injectIntoAi'>): boolean {\n return slot.shareWithAi || slot.injectIntoAi;\n}\n\n/** Pourquoi une variable est réclamée par l'assistant de complétion. */\nexport const MissingVariableReasonSchema = z.enum(['required', 'overrideOnly']);\nexport type MissingVariableReason = z.infer<typeof MissingVariableReasonSchema>;\n\n/** Une variable qu'il faut remplir avant de démarrer. */\nexport const MissingVariableSchema = z.object({\n variableId: z.string().max(128),\n key: z.string().max(256),\n description: z.string().max(2000),\n reason: MissingVariableReasonSchema,\n isSecret: z.boolean(),\n environmentId: z.string().max(128),\n environmentName: z.string().max(200),\n});\n\nexport type MissingVariable = z.infer<typeof MissingVariableSchema>;\n\n// A Variable has a key (env var name) and a value slot.\nexport const VariableSchema = z.object({\n key: z.string().min(1).max(256),\n value: VariableSlotSchema,\n});\n\nexport type Variable = z.infer<typeof VariableSchema>;\n\n// Record of variableId → Variable. Max 200 entries.\n// The key is a unique variable ID (UUID), the Variable contains the env var name in `key`.\nexport const VariablesRecordSchema = z.record(\n z.string().max(128),\n VariableSchema,\n).refine(\n (obj) => Object.keys(obj).length <= 200,\n { message: 'Max 200 variables' },\n);\n\nexport type VariablesRecord = z.infer<typeof VariablesRecordSchema>;\n\n// Record of variable name → VariableSlot (used on disk for base values and overrides separately)\nexport const VariableSlotsRecordSchema = z.record(\n z.string().max(256),\n VariableSlotSchema,\n).refine(\n (obj) => Object.keys(obj).length <= 200,\n { message: 'Max 200 variable slots' },\n);\n\nexport type VariableSlotsRecord = z.infer<typeof VariableSlotsRecordSchema>;\n\nexport const ServiceConfigSchema = z.object({\n id: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n agentId: z.string().max(128).optional(), // Optional: if absent, inherited from active environment's agentId\n name: z.string().min(1).max(200),\n commands: z.array(ServiceCommandSchema).max(50).optional().default([]),\n cwd: z.string().max(4096).optional(),\n ports: z.array(z.number().int().positive().max(65535)).max(20).optional().default([]),\n\n // Metadata fields (migration from old Runeya)\n groups: z.array(z.string().max(200)).max(20).optional().default([]),\n description: z.string().max(2000).optional(),\n /** Path (relative to service.cwd or absolute) where the service's docs/wiki markdown files live. Optional — defaults to service.cwd. */\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).regex(/^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,}$/),\n port: z.number().int().min(1).max(65535),\n })).max(20).optional().default([]),\n openapiUrl: z.string().max(2048).optional(),\n git: z.object({\n remote: z.string().max(2048).optional(),\n home: z.string().max(2048).optional(),\n }).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\n // Transient env dict (resolved by server before deployment, used directly by agent runner — NOT persisted)\n env: z.record(z.string().max(256), z.string().max(8192)).default({}).refine(\n (obj) => Object.keys(obj).length <= 200,\n { message: 'Too many env vars (max 200)' },\n ),\n envSecrets: z.array(z.string().max(256)).max(200).default([]),\n\n // Transient: resolved JS log parsers (from parserIds, resolved by server before deployment — NOT persisted)\n resolvedLogParsers: z.array(JSLogParserSchema).default([]).optional(),\n\n // Transient: resolved working directory (cwd with env vars expanded — NOT persisted)\n resolvedCwd: z.string().optional(),\n\n runner: z.enum(['native', 'docker']).optional().default('native'),\n dockerConfig: DockerConfigSchema.optional(),\n healthCheck: HealthCheckSchema.optional(),\n parserIds: z.array(z.string().max(128)).max(50).default([]),\n shortcuts: z.array(ServiceShortcutSchema).max(50).optional().default([]),\n autoRestart: z.boolean().optional().default(false),\n clearLogsOnStart: 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\n // Log sources additionnelles (au-delà du stdout/stderr console par défaut)\n logSources: z.array(LogSourceConfigSchema).max(20).optional().default([]),\n});\n\nexport type ServiceConfig = z.infer<typeof ServiceConfigSchema>;\n\nexport const CreateServiceSchema = ServiceConfigSchema.omit({ id: true }).partial().required({ name: true });\nexport type CreateService = z.infer<typeof CreateServiceSchema>;\n\nexport const UpdateServiceSchema = ServiceConfigSchema.partial().required({ id: true }).extend({\n agentId: z.string().max(128).nullable().optional(), // null = clear (inherit from env), undefined = no change\n cwd: z.string().max(4096).nullable().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 healthCheck: HealthCheckSchema.nullable().optional(),\n});\nexport type UpdateService = z.infer<typeof UpdateServiceSchema>;\n","import { z } from 'zod';\nimport { ScenarioSchema } from './scenario.schema.js';\n\nexport const AI_PROVIDERS = ['anthropic', 'openai', 'mistral', 'groq', 'ollama'] as const;\nexport type AIProviderType = (typeof AI_PROVIDERS)[number];\n\nexport const AIProviderSchema = z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200),\n provider: z.enum(AI_PROVIDERS),\n encryptedApiKey: z.string().max(2000).default(''),\n model: z.string().max(200).optional(),\n active: z.boolean().default(false),\n createdAt: z.coerce.date(),\n updatedAt: z.coerce.date(),\n});\n\nexport type AIProvider = z.infer<typeof AIProviderSchema>;\n\nexport const JSLogParserSchema = z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200),\n description: z.string().max(2000).optional(),\n code: z.string().min(1).max(50000).refine(\n (s) => !s.includes('require(') && !s.includes('import ') && !s.includes('eval('),\n { message: 'Code must not contain require, import, or eval patterns' }\n ),\n enabled: z.boolean().default(true),\n builtin: z.boolean().optional(),\n createdAt: z.coerce.date(),\n updatedAt: z.coerce.date(),\n});\n\nexport type JSLogParser = z.infer<typeof JSLogParserSchema>;\n\nexport const NOTIFICATION_CATEGORIES = [\n 'scenario_waiting_input',\n 'ai_conversation_complete',\n 'ai_conversation_error',\n 'service_error_log',\n 'service_status_changed',\n 'service_health_changed',\n] as const;\nexport type NotificationCategory = (typeof NOTIFICATION_CATEGORIES)[number];\n\nexport const NotificationPreferencesSchema = z.object({\n scenario_waiting_input: z.boolean().default(true),\n ai_conversation_complete: z.boolean().default(true),\n ai_conversation_error: z.boolean().default(true),\n service_error_log: z.boolean().default(true),\n service_status_changed: z.boolean().default(true),\n service_health_changed: z.boolean().default(true),\n /** Service IDs excluded from error-log notifications */\n service_error_log_excluded: z.array(z.string().max(100)).max(500).default([]),\n /** Service IDs excluded from status-change notifications */\n service_status_changed_excluded: z.array(z.string().max(100)).max(500).default([]),\n /** Service IDs excluded from health-change notifications */\n service_health_changed_excluded: z.array(z.string().max(100)).max(500).default([]),\n});\nexport type NotificationPreferences = z.infer<typeof NotificationPreferencesSchema>;\n\n/**\n * Réglages du compagnon de relecture.\n *\n * Au niveau du POSTE, en clair, et non dans le coffre d'une organisation (§9) :\n * ce n'est pas un réglage d'équipe. Il décrit comment cette machine fait\n * travailler ses agents, il ne contient aucun secret, et le ranger dans un\n * coffre chiffré le rendrait dépendant de l'organisation qu'on regarde — un\n * même poste aurait autant de compagnons que d'organisations, sans raison.\n */\nexport const CompanionSettingsSchema = z.object({\n /** Activer le compagnon d'office sur les conversations créées ensuite. */\n enabledByDefault: z.boolean().default(false),\n /**\n * Spécificités ajoutées aux consignes Runeya.\n *\n * Vide — l'absence — signifie « aucune spécificité ». On ne recopie pas le\n * texte par défaut dans le réglage : les consignes Runeya restent dans le\n * code, pour profiter de leurs corrections.\n *\n * Rejeté au-delà de la borne plutôt que tronqué (§1) : un prompt coupé en\n * plein milieu produirait des relectures incohérentes sans rien signaler.\n */\n prompt: z.string().max(20_000).optional(),\n});\n\nexport type CompanionSettings = z.infer<typeof CompanionSettingsSchema>;\n\nexport const SettingsSchema = z.object({\n mode: z.enum(['local-simple', 'cloud']),\n cloudUrl: z.string().url().max(2048).nullable().optional(),\n logParsers: z.array(JSLogParserSchema).max(100).default([]),\n scenarios: z.array(ScenarioSchema).max(100).default([]),\n /** Absolute path to the folder where the global wiki/docs markdown files live. Optional. */\n globalDocsPath: z.string().max(4096).optional(),\n /**\n * Optionnel plutôt que défauté : un réglage absent est un réglage jamais\n * touché, et le rendre obligatoire dans le type forcerait chaque appelant qui\n * construit un objet de réglages à inventer une valeur.\n */\n companion: CompanionSettingsSchema.optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n\n\nexport const TraefikConfigSchema = z.object({\n enabled: z.boolean().default(false),\n acmeEmail: z.string().email().max(256).optional(),\n wildcardDomain: z.string().max(253).optional(),\n httpPort: z.number().int().min(1).max(65535).default(80),\n httpsPort: z.number().int().min(1).max(65535).default(443),\n dnsProvider: z.string().max(64).optional(),\n dnsCredentials: z.record(z.string().max(64), z.string().max(2048)).default({}),\n acmeStaging: z.boolean().default(false),\n encryptedCert: z.string().max(65536).optional(),\n encryptedCertKey: z.string().max(65536).optional(),\n});\n\nexport type TraefikConfig = z.infer<typeof TraefikConfigSchema>;\n\n\nexport const SettingsPrivateSchema = z.object({\n aiProviders: z.array(AIProviderSchema).max(50).default([]),\n scenarios: z.array(ScenarioSchema).max(100).default([]),\n notifications: NotificationPreferencesSchema.default(() => ({\n scenario_waiting_input: true,\n ai_conversation_complete: true,\n ai_conversation_error: true,\n service_error_log: true,\n service_status_changed: true,\n service_health_changed: true,\n service_error_log_excluded: [],\n service_status_changed_excluded: [],\n service_health_changed_excluded: [],\n })),\n traefikConfig: TraefikConfigSchema.optional(),\n});\n\nexport type SettingsPrivate = z.infer<typeof SettingsPrivateSchema>;\n\nexport const SchemaVersionSchema = z.object({\n version: z.number().int().positive(),\n migratedAt: z.coerce.date(),\n});\n\nexport type SchemaVersion = z.infer<typeof SchemaVersionSchema>;\n","import { z } from 'zod';\n\nconst PositionSchema = z.object({\n x: z.number(),\n y: z.number(),\n});\n\nexport const ScenarioGroupSchema = z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200),\n description: z.string().max(1000).optional(),\n color: z.string().max(32).optional(),\n position: PositionSchema.default({ x: 0, y: 0 }),\n width: z.number().default(300),\n height: z.number().default(200),\n});\n\nexport type ScenarioGroup = z.infer<typeof ScenarioGroupSchema>;\n\nexport const SCENARIO_ROLES = [\n 'manager',\n 'engineer',\n 'designer',\n 'analyst',\n 'qa',\n 'devops',\n 'product',\n 'writer',\n 'researcher',\n 'other',\n] as const;\n\nexport type ScenarioRole = typeof SCENARIO_ROLES[number];\n\n// --- Presets ---\n\nexport const ScenarioPresetRoleSchema = z.object({\n id: z.string().min(1).max(64),\n name: z.string().min(1).max(200),\n systemPrompt: z.string().max(10_000).default(''),\n prompt: z.string().max(10_000).default(''),\n});\n\nexport type ScenarioPresetRole = z.infer<typeof ScenarioPresetRoleSchema>;\n\nexport const ScenarioPresetInitialDataSchema = z.object({\n leaderId: z.string().min(1).max(128),\n groups: z.array(z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200),\n description: z.string().max(1000).optional(),\n color: z.string().max(32).optional(),\n position: z.object({ x: z.number(), y: z.number() }).default({ x: 0, y: 0 }),\n width: z.number().default(300),\n height: z.number().default(200),\n })).max(100).default([]),\n nodes: z.array(z.object({\n id: z.string().min(1).max(128),\n type: z.enum(['ai', 'ask']).default('ai'),\n parentIds: z.array(z.string().max(128)).default([]),\n groupId: z.string().max(128).nullable().default(null),\n label: z.string().max(240).default(''),\n role: z.string().max(64).default('other'),\n prompt: z.string().max(50_000).default(''),\n question: z.string().max(2_000).default(''),\n autoGenerated: z.boolean().default(true),\n canAddNode: z.boolean().default(false),\n aiCli: z.enum(['claude-code', 'codex']).default('claude-code'),\n model: z.string().max(128).default('sonnet'),\n position: z.object({ x: z.number(), y: z.number() }).default({ x: 0, y: 0 }),\n })).min(1).max(500),\n});\n\nexport type ScenarioPresetInitialData = z.infer<typeof ScenarioPresetInitialDataSchema>;\n\nconst LocalizedStringSchema = z.record(z.string(), z.string().max(100));\n\nexport const ScenarioPresetLabelsSchema = z.object({\n group: LocalizedStringSchema.optional(),\n node: LocalizedStringSchema.optional(),\n role: LocalizedStringSchema.optional(),\n leader: LocalizedStringSchema.optional(),\n});\n\nexport type ScenarioPresetLabels = z.infer<typeof ScenarioPresetLabelsSchema>;\n\nexport const ScenarioPresetSchema = z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200),\n icon: z.string().max(64).optional(),\n defaultTraversalMode: z.enum(['hierarchical', 'topological']).optional(),\n canChangeTraversalMode: z.boolean().default(true),\n roles: z.array(ScenarioPresetRoleSchema).min(1).max(100),\n initialData: ScenarioPresetInitialDataSchema.optional(),\n labels: ScenarioPresetLabelsSchema.optional(),\n});\n\nexport type ScenarioPreset = z.infer<typeof ScenarioPresetSchema>;\n\n// --- Node ---\n\nexport const ScenarioNodeSchema = z.object({\n id: z.string().min(1).max(128),\n type: z.enum(['ai', 'ask']).default('ai'),\n parentIds: z.array(z.string().max(128)).default([]),\n groupId: z.string().max(128).nullable().default(null),\n label: z.string().max(240).default(''),\n role: z.string().max(64).default('other'),\n prompt: z.string().max(50_000).default(''),\n question: z.string().max(2_000).default(''),\n autoGenerated: z.boolean().default(true),\n canAddNode: z.boolean().default(false),\n aiCli: z.enum(['claude-code', 'codex']).default('claude-code'),\n model: z.string().max(128).default('sonnet'),\n position: PositionSchema.default({ x: 0, y: 0 }),\n injectParentOutputs: z.boolean().default(false),\n injectedAncestorIds: z.array(z.string().max(128)).default([]),\n});\n\nexport type ScenarioNode = z.infer<typeof ScenarioNodeSchema>;\n\nexport const ScenarioSchema = z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200),\n icon: z.string().max(64).optional(),\n description: z.string().max(2000).optional(),\n leaderId: z.string().min(1).max(128),\n groups: z.array(ScenarioGroupSchema).max(100).default([]),\n nodes: z.array(ScenarioNodeSchema).min(1).max(500),\n traversalMode: z.enum(['hierarchical', 'topological']).default('hierarchical'),\n presetId: z.string().max(128).optional(),\n isPublished: z.boolean().default(false),\n createdAt: z.number(),\n updatedAt: z.number(),\n});\n\nexport type Scenario = z.infer<typeof ScenarioSchema>;\n","import { z } from 'zod';\n\nconst safePath = z\n .string()\n .min(1)\n .max(4096)\n .refine(\n (p) => !p.includes('\\0'),\n { message: 'path must not contain null bytes' },\n )\n .refine(\n (p) => !/(^|[/\\\\])\\.\\.([/\\\\]|$)/.test(p),\n { message: 'path must not contain path-traversal sequences (..)' },\n )\n;\n\nexport const ConsoleLogSourceSchema = z.object({\n type: z.literal('console'),\n});\nexport type ConsoleLogSource = z.infer<typeof ConsoleLogSourceSchema>;\n\nexport const FileLogSourceSchema = z.object({\n type: z.literal('file'),\n path: safePath,\n encoding: z.string().max(32).default('utf-8'),\n startFromEnd: z.boolean().default(true),\n createIfNotExists: z.boolean().default(false),\n});\nexport type FileLogSource = z.infer<typeof FileLogSourceSchema>;\n\nexport const MongoLogSourceSchema = z.object({\n type: z.literal('mongo'),\n /** @sensitive — stored encrypted (AES-256-GCM) on disk */\n connectionString: z.string().min(1).max(2048),\n database: z.string().min(1).max(256),\n collection: z.string().min(1).max(256),\n filter: z.record(z.string(), z.unknown()).optional(),\n timestampField: z.string().max(128).default('timestamp'),\n messageField: z.string().max(128).default('message'),\n levelField: z.string().max(128).optional(),\n});\nexport type MongoLogSource = z.infer<typeof MongoLogSourceSchema>;\n\nexport const MySQLLogSourceSchema = z.object({\n type: z.literal('mysql'),\n host: z.string().min(1).max(253),\n port: z.number().int().min(1).max(65535).default(3306),\n user: z.string().min(1).max(256),\n /** @sensitive — stored encrypted (AES-256-GCM) on disk */\n password: z.string().max(2048),\n database: z.string().min(1).max(256),\n table: z.string().min(1).max(256),\n query: z.string().max(8192).optional(),\n timestampColumn: z.string().max(128).default('created_at'),\n messageColumn: z.string().max(128).default('message'),\n levelColumn: z.string().max(128).optional(),\n pollIntervalMs: z.number().int().min(500).max(60000).default(2000),\n});\nexport type MySQLLogSource = z.infer<typeof MySQLLogSourceSchema>;\n\nexport const LogSourceConfigSchema = z.discriminatedUnion('type', [\n ConsoleLogSourceSchema,\n FileLogSourceSchema,\n MongoLogSourceSchema,\n MySQLLogSourceSchema,\n]);\nexport type LogSourceConfig = z.infer<typeof LogSourceConfigSchema>;\nexport type LogSourceType = LogSourceConfig['type'];\n","import { z } from 'zod';\n\nexport const ProcessStateSchema = z.enum(['starting', 'running', 'stopped', 'errored']);\nexport type ProcessState = z.infer<typeof ProcessStateSchema>;\n\nexport const HealthStatusSchema = z.enum(['healthy', 'unhealthy', 'unknown']);\nexport type HealthStatus = z.infer<typeof HealthStatusSchema>;\n\nexport const ProcessStatusSchema = z.object({\n id: z.string().max(128),\n serviceId: z.string().max(128),\n agentId: z.string().max(128),\n state: ProcessStateSchema,\n pid: z.number().int().nullable().optional(),\n pids: z.array(z.number().int()).optional().default([]),\n exitCode: z.number().int().nullable().optional(),\n startedAt: z.coerce.date().nullable().optional(),\n restartCount: z.number().int().nonnegative().default(0),\n uptime: z.number().nonnegative().default(0),\n healthStatus: HealthStatusSchema.default('unknown'),\n /**\n * Le répertoire où le processus s'exécute VRAIMENT, absolutisé par l'agent.\n *\n * Rapporté par l'agent plutôt que déduit de la config : entre le `cwd` de la\n * commande, celui du service, l'ancrage sur le projet et les variables que\n * l'agent étend lui-même, la valeur affichée n'aurait rien prouvé. Ce qui\n * intéresse quand un service tourne contre le mauvais dépôt, c'est le chemin\n * final — y compris quand il retombe sur le répertoire de l'agent.\n */\n cwd: z.string().max(4096).nullable().optional(),\n});\n\nexport type ProcessStatus = z.infer<typeof ProcessStatusSchema>;\n","import { z } from 'zod';\n\nexport const LogLevelSchema = z.enum(['debug', 'info', 'warn', 'error', 'fatal']);\nexport type LogLevel = z.infer<typeof LogLevelSchema>;\n\nexport const LogLineSchema = z.object({\n /** Raw log line as received from the process (immutable context) */\n raw: z.string(),\n /** Source stream (immutable context) */\n stream: z.enum(['stdout', 'stderr']),\n /** Severity level */\n level: LogLevelSchema,\n /** Parsed/enriched message to display */\n message: z.string(),\n /** When true, the line is hidden from the log view */\n hidden: z.boolean(),\n /** Arbitrary key/value pairs shown in the detail panel */\n metadata: z.record(z.string().max(256), z.unknown()).refine(\n (obj) => Object.keys(obj).length <= 100,\n { message: 'Too many metadata keys (max 100)' },\n ),\n /** Full parsed JSON object when the line is JSON */\n json: z.record(z.string(), z.unknown()).optional(),\n /** Custom header for the JSON log card (supports HTML, sanitized before display) */\n jsonHeader: z.string().max(256).optional(),\n});\n\nexport type LogLine = z.infer<typeof LogLineSchema>;\n\nexport const LogCardDirectiveSchema = z.object({\n id: z.string().max(128),\n type: z.string().max(64),\n header: z.string().max(256),\n collapsable: z.boolean().optional(),\n collapsed: z.boolean().optional(),\n state: z.enum(['open', 'append', 'close', 'self']),\n});\nexport type LogCardDirective = z.infer<typeof LogCardDirectiveSchema>;\n\nexport const ParsedLogSchema = z.object({\n id: z.string().max(128),\n processId: z.string().max(128),\n pid: z.number().int().nullable().optional(),\n timestamp: z.coerce.date(),\n level: LogLevelSchema.default('info'),\n message: z.string().max(16384),\n raw: z.string().max(16384),\n stream: z.enum(['stdout', 'stderr']).default('stdout'),\n hidden: z.boolean().optional().default(false),\n metadata: z.record(z.string().max(256), z.unknown()).optional().refine(\n (obj) => !obj || Object.keys(obj).length <= 100,\n { message: 'Too many metadata keys (max 100)' },\n ),\n json: z.record(z.string(), z.unknown()).optional(),\n logCard: LogCardDirectiveSchema.optional(),\n sourceType: z.enum(['console', 'file', 'mongo', 'mysql']).optional(),\n sourcePath: z.string().max(4096).optional(),\n});\n\nexport type ParsedLog = z.infer<typeof ParsedLogSchema>;\n","import { z } from 'zod';\n\n/** Regex for valid POSIX environment variable names */\nexport const ENV_VAR_NAME_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nexport const AgentConfigSchema = z.object({\n id: z.string().max(128),\n name: z.string().min(1).max(100),\n url: z.string().url().max(2048),\n passphrase: z.string().min(1).max(1024),\n passthroughEnv: z.array(\n z.string().regex(ENV_VAR_NAME_REGEX).max(256),\n ).max(100).default([]),\n});\n\nexport type AgentConfig = z.infer<typeof AgentConfigSchema>;\n\nexport const AgentStatusSchema = z.object({\n connected: z.boolean(),\n lastSeen: z.string().nullable().optional(),\n uptime: z.number().nonnegative().default(0),\n runnersAvailable: z.array(z.enum(['native', 'docker'])).default(['native']),\n lanIp: z.string().optional(),\n /**\n * Ce que la machine de l'agent vaut pour les builtins de portée `agent`.\n * Sert à PRÉVISUALISER — la valeur injectée reste calculée au lancement, par\n * l'agent lui-même : une IP change, un agent se déconnecte, et un statut\n * n'est qu'un cliché.\n */\n os: z.string().max(64).optional(),\n home: z.string().max(4096).optional(),\n cwd: z.string().max(4096).optional(),\n});\n\nexport type AgentStatus = z.infer<typeof AgentStatusSchema>;\n","import { z } from 'zod';\n\nexport const GlobalRoleSchema = z.enum(['owner', 'admin', 'member']);\nexport type GlobalRole = z.infer<typeof GlobalRoleSchema>;\n\nexport const ProjectRoleSchema = z.enum(['admin', 'editor', 'viewer']);\nexport type ProjectRole = z.infer<typeof ProjectRoleSchema>;\n\nexport const ProjectMemberRoleSchema = z.object({\n id: z.string().max(128),\n projectId: z.string().max(128),\n userId: z.string().max(128),\n role: ProjectRoleSchema,\n});\n\nexport type ProjectMemberRole = z.infer<typeof ProjectMemberRoleSchema>;\n","import { z } from 'zod';\n\nexport const ConfigVersionSchema = z.object({\n id: z.string().max(128),\n entityType: z.enum(['project', 'service']),\n entityId: z.string().max(128),\n version: z.string().max(128),\n parentVersion: z.string().max(128),\n data: z.record(z.string(), z.unknown()).refine(\n (obj) => Object.keys(obj).length <= 1000,\n 'Too many data keys (max 1000)',\n ),\n patch: z.array(z.record(z.string(), z.unknown())).max(1000),\n userId: z.string().max(128),\n timestamp: z.coerce.date(),\n resolved: z.boolean().default(false),\n});\n\nexport type ConfigVersion = z.infer<typeof ConfigVersionSchema>;\n\nexport const ConfigChangeSchema = z.object({\n entityType: z.enum(['project', 'service']),\n entityId: z.string().max(128),\n version: z.string().max(128),\n parentVersion: z.string().max(128),\n data: z.record(z.string(), z.unknown()).refine(\n (obj) => Object.keys(obj).length <= 1000,\n 'Too many data keys (max 1000)',\n ),\n patch: z.array(z.record(z.string(), z.unknown())).max(1000),\n});\n\nexport type ConfigChange = z.infer<typeof ConfigChangeSchema>;\n\nexport const SyncStatusSchema = z.object({\n connected: z.boolean(),\n lastSync: z.coerce.date().nullable().optional(),\n pendingChanges: z.number().int().nonnegative().default(0),\n conflicts: z.number().int().nonnegative().default(0),\n});\n\nexport type SyncStatus = z.infer<typeof SyncStatusSchema>;\n","import { z } from 'zod';\n\nexport const AuditActionSchema = z.enum([\n 'create', 'update', 'delete',\n 'invite', 'remove',\n 'deploy', 'start', 'stop',\n 'roleChange',\n]);\n\nexport type AuditAction = z.infer<typeof AuditActionSchema>;\n\nexport const AuditEntityTypeSchema = z.enum([\n 'org', 'project', 'service', 'member', 'permission',\n]);\n\nexport type AuditEntityType = z.infer<typeof AuditEntityTypeSchema>;\n\nexport const AuditLogSchema = z.object({\n id: z.string().max(128),\n orgId: z.string().max(128),\n userId: z.string().max(128),\n action: AuditActionSchema,\n entityType: AuditEntityTypeSchema,\n entityId: z.string().max(128),\n metadata: z.record(z.string().max(256), z.unknown()).default({}).refine(\n (obj) => Object.keys(obj).length <= 100,\n { message: 'Too many metadata keys (max 100)' },\n ),\n timestamp: z.coerce.date(),\n});\n\nexport type AuditLog = z.infer<typeof AuditLogSchema>;\n","import { z } from 'zod';\n\nexport const ProcessMetricsSchema = z.object({\n processId: z.string().max(128),\n cpu: z.number().nonnegative(),\n memory: z.number().int().nonnegative(),\n timestamp: z.string(),\n});\n\nexport type ProcessMetrics = z.infer<typeof ProcessMetricsSchema>;\n","import { z } from 'zod';\nimport { VariableSchema } from './service.schema.js';\n\n// Environment schema — uses VariablesRecord for variable storage\nexport const EnvironmentVariablesSchema = z.record(\n z.string().max(256),\n VariableSchema,\n).refine(\n (obj) => Object.keys(obj).length <= 200,\n { message: 'Max 200 variables' },\n);\n\nexport const EnvironmentSchema = z.object({\n id: z.string().max(128),\n projectId: z.string().max(128),\n name: z.string().min(1).max(200),\n description: z.string().max(2000).optional().default(''),\n parentIds: z.array(z.string().max(128)).max(10).default([]),\n variables: EnvironmentVariablesSchema.default({}),\n // Scope: 'global' = project-level env, 'service' = per-service env\n scope: z.enum(['global', 'service']).default('global'),\n // When scope='service': the serviceId this env belongs to\n reference: z.string().max(128).optional(),\n // When scope='service': the globalEnvId this env activates on\n activateOn: z.string().max(128).optional(),\n immutable: z.boolean().default(false),\n default: z.boolean().optional().default(false),\n color: z.string().max(20).optional(),\n bgColor: z.string().max(20).optional(),\n // When scope='global': the default agent used by services that don't have an explicit agentId\n agentId: z.string().max(128).optional(),\n});\n\nexport type Environment = z.infer<typeof EnvironmentSchema>;\n\n// Resolved environment: flattened env dict + secrets list + source tracking\nexport const ResolvedEnvironmentSchema = z.object({\n variables: z.record(z.string().max(256), VariableSchema)\n .refine((obj) => Object.keys(obj).length <= 500, { message: 'Max 500 resolved variables' }),\n env: z.record(z.string().max(256), z.string().max(8192))\n .refine((obj) => Object.keys(obj).length <= 500, { message: 'Max 500 resolved env vars' }),\n envSecrets: z.array(z.string().max(256)).max(500),\n sources: z.record(z.string().max(256), z.object({\n environmentId: z.string().max(128),\n environmentName: z.string().max(200),\n overridden: z.boolean(),\n resolvedFrom: z.object({\n environmentId: z.string().max(128),\n environmentName: z.string().max(200),\n }).optional(),\n // Set when a machine-local override was applied to this variable, pointing\n // at the environment that carries the winning override. Distinct from\n // `overridden`, which also covers \"shadows an inherited variable\".\n overriddenBy: z.object({\n environmentId: z.string().max(128),\n environmentName: z.string().max(200),\n }).optional(),\n })).refine((obj) => Object.keys(obj).length <= 500, { message: 'Max 500 source entries' }),\n});\n\nexport type ResolvedEnvironment = z.infer<typeof ResolvedEnvironmentSchema>;\n\nexport const CreateEnvironmentSchema = EnvironmentSchema.omit({ id: true }).extend({\n description: z.string().max(2000).optional().default(''),\n parentIds: z.array(z.string().max(128)).max(10).optional().default([]),\n variables: EnvironmentVariablesSchema.optional().default({}),\n scope: z.enum(['global', 'service']).optional().default('global'),\n reference: z.string().max(128).optional(),\n activateOn: z.string().max(128).optional(),\n immutable: z.boolean().optional().default(false),\n});\nexport type CreateEnvironment = z.input<typeof CreateEnvironmentSchema>;\n\n// IMPORTANT: Do NOT simplify this to `EnvironmentSchema.partial().required({ id: true })`.\n//\n// EnvironmentSchema has .default() on several fields (variables: {}, parentIds: [], description: '',\n// scope: 'global', immutable: false, default: false). When Zod parses a partial update input that\n// omits those fields, .partial() alone does NOT strip the defaults — Zod still fills them in.\n// The store checks `input.variables !== undefined` to decide whether to overwrite, so if Zod\n// silently injects `variables: {}`, the store wipes ALL existing variables on every save.\n//\n// The .extend() below overrides those fields without .default(), making them truly optional\n// (undefined when absent). DO NOT remove it or merge the .extend() back into EnvironmentSchema.\nexport const UpdateEnvironmentSchema = EnvironmentSchema\n .partial()\n .required({ id: true })\n .extend({\n description: z.string().max(2000).optional(),\n parentIds: z.array(z.string().max(128)).max(10).optional(),\n variables: EnvironmentVariablesSchema.optional(),\n scope: z.enum(['global', 'service']).optional(),\n immutable: z.boolean().optional(),\n default: z.boolean().optional(),\n agentId: z.string().max(128).nullable().optional(), // null = clear (no default agent)\n });\nexport type UpdateEnvironment = z.infer<typeof UpdateEnvironmentSchema>;\n","import { z } from 'zod';\nimport { VariableSlotSchema } from './service.schema.js';\n\n// An override carries ONLY a value slot: the env var name always comes from the\n// variable definition in `environments.json`, looked up by variable ID. Storing\n// a `key` here would go stale as soon as the variable is renamed in the UI.\nexport const VariableOverrideSchema = z.object({\n value: VariableSlotSchema,\n});\n\nexport type VariableOverride = z.infer<typeof VariableOverrideSchema>;\n\n// Environment overrides: Record<variableId, VariableOverride>\n// Flat structure — each override is keyed by the variable's unique ID.\nexport const EnvironmentOverridesSchema = z.record(\n z.string().max(128),\n VariableOverrideSchema,\n).refine(\n (obj) => Object.keys(obj).length <= 5000,\n { message: 'Max 5000 overrides' },\n);\n\nexport type EnvironmentOverrides = z.infer<typeof EnvironmentOverridesSchema>;\n","import { z } from 'zod';\n\nexport const ApiServiceActionSchema = z.enum([\n 'service:read',\n 'service:start',\n 'service:stop',\n 'service:restart',\n 'service:healthcheck',\n 'service:status',\n 'logs:read',\n]);\nexport type ApiServiceAction = z.infer<typeof ApiServiceActionSchema>;\n\nexport const ApiEnvActionSchema = z.enum(['env:read', 'env:write']);\nexport type ApiEnvAction = z.infer<typeof ApiEnvActionSchema>;\n\nexport const ApiEnvPermSchema = z.object({\n environmentId: z.string().max(128),\n actions: z.array(ApiEnvActionSchema).max(10).default(['env:read']),\n includeSecrets: z.boolean().default(false),\n});\nexport type ApiEnvPerm = z.infer<typeof ApiEnvPermSchema>;\n\nexport const ApiServicePermSchema = z.object({\n serviceId: z.string().max(128),\n actions: z.array(ApiServiceActionSchema).max(10).default(['service:read']),\n environments: z.array(ApiEnvPermSchema).max(100).default([]),\n});\nexport type ApiServicePerm = z.infer<typeof ApiServicePermSchema>;\n\nexport const ApiKeyScopeSchema = z.object({\n services: z.array(ApiServicePermSchema).max(500).default([]),\n});\nexport type ApiKeyScope = z.infer<typeof ApiKeyScopeSchema>;\n\nexport const ApiKeySchema = z.object({\n id: z.string().max(128),\n name: z.string().min(1).max(200),\n key: z.string().regex(/^[0-9a-f]{64}$/i),\n scopes: ApiKeyScopeSchema,\n createdAt: z.string().max(64),\n isPublic: z.boolean().default(false),\n});\nexport type ApiKey = z.infer<typeof ApiKeySchema>;\n\n/**\n * Shape of an API key as it sits on disk: `key` holds the *encrypted* secret,\n * so it no longer matches the 64-hex form the in-memory type guarantees.\n * Legacy files written before encryption still parse — the store decrypts only\n * what looks encrypted and re-persists.\n */\nexport const PersistedApiKeySchema = ApiKeySchema.extend({\n key: z.string().min(1).max(4096),\n});\nexport type PersistedApiKey = z.infer<typeof PersistedApiKeySchema>;\n\nexport const ApiKeysFileSchema = z.object({\n keys: z.array(PersistedApiKeySchema).max(100),\n});\n\n/** An API key as exposed by the API: the secret is never part of it. */\nexport const MaskedApiKeySchema = ApiKeySchema.omit({ key: true }).extend({\n /** Last 4 characters of the secret, for recognising a key in a list. */\n keyPreview: z.string().max(8),\n});\nexport type MaskedApiKey = z.infer<typeof MaskedApiKeySchema>;\n\n","import { z } from 'zod';\n\nexport const ALLOWED_IMAGE_MIME_TYPES = ['image/png', 'image/jpeg', 'image/webp', 'image/gif'] as const;\n\nexport const 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, 'Must be a valid UUID'),\n url: z.string().min(1),\n mimeType: z.enum(ALLOWED_IMAGE_MIME_TYPES),\n altText: z.string().max(500).optional(),\n});\n\nexport type ImagePart = z.infer<typeof ImagePartSchema>;\n\nexport const ImageUploadResponseSchema = z.object({\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, 'Must be a valid UUID'),\n url: z.string().min(1),\n mimeType: z.enum(ALLOWED_IMAGE_MIME_TYPES),\n originalName: z.string(),\n});\n\nexport type ImageUploadResponse = z.infer<typeof ImageUploadResponseSchema>;\n\nexport const ImageMetaSchema = z.object({\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, 'Must be a valid UUID'),\n filePath: z.string().min(1),\n mimeType: z.enum(ALLOWED_IMAGE_MIME_TYPES),\n originalName: z.string().min(1),\n createdAt: z.number().positive(),\n size: z.number().positive().optional(),\n});\n\nexport type ImageMeta = z.infer<typeof ImageMetaSchema>;\n","import { z } from 'zod';\n\n// --- Attachments ---\n/**\n * A file attached to a card. The bytes live in object storage; the card keeps\n * only this descriptor, so a board document stays small no matter how many\n * files it carries.\n */\nexport const KanbanAttachmentSchema = z.object({\n /** Server-issued id, also the storage key. */\n id: z.string().max(128),\n name: z.string().max(255),\n size: z.number().int().nonnegative(),\n contentType: z.string().max(128),\n});\nexport type KanbanAttachment = z.infer<typeof KanbanAttachmentSchema>;\n\n// --- Card History ---\nexport const KanbanCardEventSchema = z.object({\n type: z.enum(['created', 'edited', 'moved', 'image_added', 'image_removed', 'title_changed', 'conversation_started', 'scenario_started', 'comment', 'archived', 'unarchived']),\n timestamp: z.string(),\n /** Extra context: old/new column name, old/new title, comment text, etc. */\n /**\n * Le texte de l'entrée : le corps d'un commentaire, ou le contexte du geste.\n *\n * Borné comme le corps d'une carte (100 000), et non plus à 5 000 : un\n * commentaire est de la prose comme une description, et rien de technique ne\n * justifiait un écart de vingt fois. La borne étroite s'est vue à l'import\n * d'un Kanbanize, où des commentaires de 12 000 caractères passaient par\n * l'API publique — bornée, elle, à 20 000 — pour écrire en base une donnée que\n * ce schéma déclarait invalide, et qu'aucune reprise depuis l'interface\n * n'aurait ensuite pu enregistrer.\n */\n detail: z.string().max(100_000).optional(),\n /**\n * Stable identity of the event, used to tell an edit from an insertion when a\n * whole history is written back. Absent on events recorded before the field\n * existed; those fall back to (type, timestamp).\n */\n id: z.string().max(128).optional(),\n /**\n * La colonne où l'événement fait entrer la carte (`created`, `moved`,\n * `unarchived`). Le `detail` n'en porte que le titre, qu'un renommage rend\n * introuvable : l'identifiant, lui, tient. Absent des événements antérieurs\n * que la migration n'a pas pu rapprocher.\n */\n columnId: z.string().max(128).optional(),\n /** Who authored this event — 'ai' or 'user'. Only set for comment events. */\n author: z.enum(['ai', 'user']).optional(),\n /**\n * Qui est derrière l'événement, estampillé par le serveur — jamais pris du\n * client, sans quoi n'importe qui pourrait signer au nom d'un autre.\n *\n * Posé sur les commentaires (c'est ce qui rend « mon propre commentaire »\n * répondable ; `author` ne sépare que l'IA de l'humain) et sur les\n * déplacements. Absent des événements écrits avant qu'on l'estampille : un\n * lecteur doit donc afficher « on ne sait pas », pas un nom vide.\n *\n * Pour une clé d'API, c'est le nom de la clé et non son porteur : la clé\n * emprunte les droits de son créateur, pas son identité — personne ne doit\n * croire qu'un humain a déplacé ce qu'un robot de CI a déplacé.\n */\n authorUser: z.object({ id: z.string().max(128), name: z.string().max(200) }).optional(),\n /** Set when the author amended their comment, so the UI can say so. */\n editedAt: z.string().optional(),\n /** Files attached to a comment — same storage as a card's own attachments. */\n attachments: z.array(KanbanAttachmentSchema).max(20).optional(),\n /** Conversation that produced this event (comments only). Used to navigate back to the conversation. */\n conversationId: z.string().optional(),\n});\nexport type KanbanCardEvent = z.infer<typeof KanbanCardEventSchema>;\n\n// --- Card ---\nexport const KanbanCardSchema = z.object({\n id: z.string(),\n title: z.string().min(1).max(500),\n markdown: z.string().max(100_000).default(''),\n /**\n * Legacy inline images, kept so boards written before object storage still\n * render. New uploads go to `attachments` instead.\n */\n images: z.array(z.string()).default([]),\n /** Files attached to the card — stored out of band, referenced here. */\n attachments: z.array(KanbanAttachmentSchema).max(50).default([]),\n order: z.number().int(),\n /**\n * La priorité de la carte, de 1 à 10 — 10 étant le plus urgent.\n *\n * Facultative, et absente veut dire « pas de priorité », pas « la plus\n * basse » : une carte qu'on n'a pas encore arbitrée ne doit pas se ranger\n * d'office au fond de la pile.\n */\n priority: z.number().int().min(1).max(10).optional(),\n\n /**\n * Les groupes de la carte — des étiquettes libres, posées par l'équipe.\n *\n * Rien ne les déclare ailleurs : un groupe existe parce qu'une carte le\n * porte, et disparaît avec la dernière qui le portait. C'est ce qui permet\n * d'en créer un en le tapant, sans passer par un écran d'administration.\n */\n groups: z.array(z.string().min(1).max(60)).max(30).optional(),\n /**\n * L'échéance de la carte : le jour où elle est attendue, `AAAA-MM-JJ`.\n *\n * Un jour, pas un instant, et c'est une décision : une équipe se dit « pour\n * vendredi », jamais « pour vendredi 23:59:59 UTC ». Stocker un instant\n * ferait afficher une échéance au 4 mars comme le 3 mars à qui travaille à\n * l'ouest de Greenwich — la carte serait en retard d'un jour pour la moitié\n * de l'équipe, et personne ne saurait pourquoi.\n *\n * Facultative, et absente veut dire « pas d'échéance », pas « en retard » :\n * une carte qu'on n'a pas datée ne doit pas s'annoncer comme urgente.\n */\n deadline: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional(),\n\n /**\n * La couleur de la carte, en hexadécimal (`#RRGGBB`) — un liseré en haut de\n * la carte, et rien d'autre : ce qu'elle veut dire appartient à l'équipe.\n *\n * Bornée à une notation stricte plutôt qu'à une chaîne libre : cette valeur\n * finit dans un attribut `style`, et une couleur ne doit pouvoir contenir\n * qu'une couleur. Absente sur les cartes sans couleur.\n */\n color: z.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),\n /**\n * Le journal de la carte — commentaires compris.\n *\n * Optionnel, et c'est tout l'intérêt : c'est la partie qui grossit sans fin\n * (une IA bavarde y écrit des pages), alors les lectures de tableau ne le\n * transportent plus. `undefined` veut dire « pas chargé », et une écriture\n * qui l'omet laisse au serveur celui qu'il a en base — à ne pas confondre\n * avec `[]`, qui demanderait bel et bien de le vider.\n */\n history: z.array(KanbanCardEventSchema).optional(),\n /**\n * Ce que le journal absent laisse quand même dire : combien de commentaires,\n * et quand fut le dernier. Posés par le serveur en lecture, ignorés en\n * écriture — la carte ne les stocke pas, ils se déduisent de `history`.\n */\n commentCount: z.number().int().nonnegative().optional(),\n lastCommentAt: z.string().optional(),\n /**\n * L'auteur du dernier commentaire, pour son avatar sur la tuile. Même règle :\n * posé en lecture, ignoré en écriture. `id`/`name` absents quand le\n * commentaire précède l'estampille d'auteur — on sait alors seulement si\n * c'était une IA.\n */\n lastCommentBy: z\n .object({ id: z.string().max(128).optional(), name: z.string().max(200).optional(), author: z.enum(['ai', 'user']).optional() })\n .optional(),\n /**\n * Les entrées de journal qui ouvrent une conversation IA. Elles restent dans\n * la lecture allégée — il y en a une poignée par carte, et l'hôte s'en sert\n * pour dire, sans ouvrir la carte, qu'une IA y travaille.\n */\n conversationEvents: z.array(KanbanCardEventSchema).optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n /**\n * Quand la carte a été archivée — absente tant qu'elle est au tableau.\n *\n * Une carte archivée reste dans sa colonne en base : c'est la lecture qui la\n * retire du tableau, jamais une écriture qui la déplace. Rien à recoller donc\n * au désarchivage, et aucun cimetière où une carte pourrait se perdre.\n */\n archivedAt: z.string().optional(),\n /**\n * La colonne d'où la carte a été archivée, telle qu'elle s'appelait alors.\n *\n * L'identifiant sert à l'y remettre, le titre à le dire dans l'archive même\n * quand la colonne a disparu depuis — auquel cas le désarchivage repose la\n * carte dans la première colonne, sans se taire sur son origine.\n */\n archivedFrom: z\n .object({ columnId: z.string().max(128), columnTitle: z.string().max(200) })\n .optional(),\n /**\n * Quand la carte a été supprimée. Rien n'est effacé : la carte reste en base,\n * et toutes les lectures l'écartent.\n *\n * Une suppression est le seul geste que rien ne rattrape — sauf à ne pas\n * l'exécuter vraiment. La colonne et le tableau portent le même champ, pour\n * que supprimer l'un n'emporte jamais les cartes de l'autre.\n */\n deletedAt: z.string().optional(),\n /**\n * People assigned to the card. Names are denormalized for display; the server\n * keeps only members of the owning organization, and notifies newcomers.\n */\n assignees: z\n .array(z.object({ id: z.string().max(128), name: z.string().max(200) }))\n .max(20)\n .default([]),\n /**\n * Who first created the card. Stamped by the server the first time a card id\n * appears in a board write, never taken from the client — a member could\n * otherwise claim any authorship. Absent on cards created before this field\n * existed, so readers must treat it as unknown rather than assume.\n */\n createdBy: z\n .object({ id: z.string().max(128), name: z.string().max(200) })\n .optional(),\n});\nexport type KanbanCard = z.infer<typeof KanbanCardSchema>;\n\n// --- Column ---\nexport const KanbanColumnSchema = z.object({\n id: z.string(),\n title: z.string().min(1).max(200),\n order: z.number().int(),\n cards: z.array(KanbanCardSchema).default([]),\n /**\n * Le regroupement auquel la colonne appartient, s'il y en a un.\n *\n * Un pointeur vers le parent, et rien dans l'autre sens : le groupe ne tient\n * pas la liste de ses membres. Deux listes qui prétendent dire qui contient\n * quoi finissent par se contredire, et un déplacement devient alors deux\n * écritures au lieu d'une.\n */\n groupId: z.string().optional(),\n /**\n * Colonne de cartes finalisées : y entrer compte comme « finalisée » dans les\n * statistiques de la liste, au même titre qu'un archivage.\n */\n done: z.boolean().optional(),\n /** Supprimée, mais conservée — voir `deletedAt` sur la carte. */\n deletedAt: z.string().optional(),\n});\nexport type KanbanColumn = z.infer<typeof KanbanColumnSchema>;\n\n// --- Column group ---\n/**\n * Un regroupement de colonnes : un bandeau au-dessus d'elles, pas une colonne.\n *\n * Il ne porte aucune carte — jamais — et c'est ce qui le rend inoffensif :\n * `columnId`, les rangs fractionnaires et tout le déplacement de cartes\n * ignorent son existence. Un groupe peut en contenir un autre (`parentId`).\n *\n * Il n'a délibérément **pas** d'`order` : sa place se déduit de celle de ses\n * colonnes, dont l'ordre reste l'unique source de vérité. Un groupe qui aurait\n * son propre rang pourrait contredire celui de ses membres, et il n'existerait\n * alors aucune bonne réponse à « laquelle des deux positions gagne ».\n */\nexport const KanbanColumnGroupSchema = z.object({\n id: z.string(),\n title: z.string().min(1).max(200),\n /** La couleur du bandeau, en hexadécimal — l'interface décide du défaut. */\n color: z.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),\n /** Le groupe parent, pour les regroupements imbriqués. */\n parentId: z.string().optional(),\n /** Supprimé, mais conservé — comme une colonne. */\n deletedAt: z.string().optional(),\n});\nexport type KanbanColumnGroup = z.infer<typeof KanbanColumnGroupSchema>;\n\n// --- Board ---\nexport const KanbanBoardSchema = z.object({\n id: z.string(),\n name: z.string().min(1).max(200),\n description: z.string().max(10_000).default(''),\n /**\n * Le mode d'emploi du tableau, en texte libre : ce que veulent dire ses\n * colonnes, quand une carte a le droit d'avancer, les conventions de\n * l'équipe. Écrit par les humains, lu surtout par l'IA — il est injecté dans\n * le prompt des agents pour qu'ils travaillent selon les règles du tableau\n * plutôt que selon les leurs.\n */\n instructions: z.string().max(20_000).default(''),\n columns: z.array(KanbanColumnSchema).default([]),\n /** Les regroupements de colonnes — vide sur un tableau qui n'en a jamais eu. */\n columnGroups: z.array(KanbanColumnGroupSchema).default([]),\n /**\n * Les projets auxquels le tableau est rattaché, par leur identifiant.\n *\n * Un rattachement, pas une possession : il ne sert qu'à filtrer la liste des\n * tableaux, et un tableau sans projet (`[]`, le cas par défaut) reste visible\n * partout. Plusieurs projets sont permis parce qu'une équipe partage souvent\n * un même tableau entre deux projets — obliger à choisir l'un des deux\n * ferait disparaître le tableau de la liste de l'autre.\n *\n * Les identifiants sont ceux des projets de l'organisation ; le serveur\n * refuse ceux qu'il ne connaît pas plutôt que de garder un lien mort.\n */\n projectIds: z.array(z.string().min(1).max(128)).max(20).default([]),\n archived: z.boolean().default(false),\n /** Supprimé, mais conservé avec ses cartes — voir `deletedAt` sur la carte. */\n deletedAt: z.string().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\nexport type KanbanBoard = z.infer<typeof KanbanBoardSchema>;\n\n// --- Inputs ---\nexport const CreateKanbanBoardInput = z.object({\n name: z.string().min(1).max(200),\n description: z.string().max(10_000).optional(),\n instructions: z.string().max(20_000).optional(),\n projectIds: z.array(z.string().min(1).max(128)).max(20).optional(),\n});\nexport type CreateKanbanBoardInput = z.infer<typeof CreateKanbanBoardInput>;\n\nexport const UpdateKanbanBoardInput = z.object({\n id: z.string(),\n name: z.string().min(1).max(200).optional(),\n description: z.string().max(10_000).optional(),\n instructions: z.string().max(20_000).optional(),\n columns: z.array(KanbanColumnSchema).optional(),\n archived: z.boolean().optional(),\n projectIds: z.array(z.string().min(1).max(128)).max(20).optional(),\n});\nexport type UpdateKanbanBoardInput = z.infer<typeof UpdateKanbanBoardInput>;\n\n// --- Card links ---\n/**\n * Un lien entre deux cartes, rangé hors des tableaux.\n *\n * Le lien ne vit pas dans la carte, et c'est délibéré : une carte se réécrit\n * par tableau entier, et un client plus ancien — dont le Zod ignore le champ —\n * effacerait silencieusement le lien en sauvegardant le tableau. Dans sa propre\n * collection, il survit à toutes les écritures de tableau, y compris celles des\n * versions qui ne le connaissent pas.\n *\n * Un seul type pour l'instant, la filiation : `parent` est la carte au-dessus,\n * `child` celle qui en dépend. Une carte a au plus un parent (c'est le\n * `parent_id` habituel), et les deux extrémités peuvent vivre sur des tableaux\n * différents — la même organisation, en revanche, toujours.\n */\nexport const KanbanCardLinkSchema = z.object({\n id: z.string().max(128),\n /** Le tableau et la carte qui *dépendent* de l'autre. */\n childBoardId: z.string().max(64),\n childCardId: z.string().max(128),\n /** Le tableau et la carte *dont* on dépend. */\n parentBoardId: z.string().max(64),\n parentCardId: z.string().max(128),\n createdAt: z.string(),\n createdBy: z.object({ id: z.string().max(128), name: z.string().max(200) }).optional(),\n});\nexport type KanbanCardLink = z.infer<typeof KanbanCardLinkSchema>;\n\n/**\n * De quoi afficher une carte liée sans ouvrir son tableau : son titre, sa\n * colonne, et le tableau où elle se trouve. Résolu à la lecture plutôt que\n * recopié dans le lien — un titre recopié devient faux au premier renommage.\n */\nexport const KanbanCardRefSchema = z.object({\n cardId: z.string().max(128),\n boardId: z.string().max(64),\n boardName: z.string().max(200),\n columnId: z.string().max(128),\n columnTitle: z.string().max(200),\n title: z.string().max(500),\n /** Les mêmes informations qu'une ligne de tableau montre d'une carte d'ici. */\n assignees: z.array(z.object({ id: z.string().max(128), name: z.string().max(200) })).default([]),\n commentCount: z.number().int().nonnegative().default(0),\n});\nexport type KanbanCardRef = z.infer<typeof KanbanCardRefSchema>;\n","import { z } from 'zod';\n\n/**\n * Les clés d'API du cloud : ce qu'un système tiers présente pour alimenter un\n * kanban sans être un humain connecté.\n *\n * Distinctes des clés de `api-key.schema.ts`, qui ouvrent l'API du serveur\n * *local* et nomment des services. Celles-ci appartiennent à une organisation\n * cloud et ne parlent que de tableaux — deux mondes, deux durées de vie, deux\n * écrans : les mélanger ferait qu'une clé de CI dépendrait d'un poste allumé.\n */\n\n/**\n * Ce qu'une clé a le droit de faire. Des portées séparées plutôt qu'un booléen\n * lecture/écriture : commenter est le geste d'un robot de CI qui rend compte, et\n * il n'a aucune raison de pouvoir aussi créer ou déplacer des cartes.\n *\n * `kanban:delete` est à part pour la même raison, en plus net : effacer est le\n * seul geste que rien ne rattrape. Une clé d'alimentation qui pourrait aussi\n * supprimer transformerait un bogue de script en perte de travail.\n */\nexport const CloudApiScopeSchema = z.enum([\n 'kanban:read',\n 'kanban:write',\n 'kanban:comment',\n 'kanban:delete',\n]);\nexport type CloudApiScope = z.infer<typeof CloudApiScopeSchema>;\n\nexport const CLOUD_API_SCOPES: CloudApiScope[] = [\n 'kanban:read',\n 'kanban:write',\n 'kanban:comment',\n 'kanban:delete',\n];\n\n/**\n * Le préfixe de tout secret émis. Il ne protège rien — il se lit dans un dépôt\n * ou un journal, et c'est le but : un scanner de secrets sait quoi chercher, et\n * un humain qui voit `rk_` dans un fichier sait ce qu'il tient.\n */\nexport const CLOUD_API_KEY_PREFIX = 'rk_';\n\n/** `rk_` suivi de 64 caractères hexadécimaux — 32 octets d'aléa. */\nexport const CloudApiKeySecretSchema = z.string().regex(/^rk_[0-9a-f]{64}$/);\n\nexport const CloudApiKeySchema = z.object({\n id: z.string().max(128),\n organizationId: z.string().max(128),\n name: z.string().min(1).max(200),\n scopes: z.array(CloudApiScopeSchema).min(1).max(10),\n /**\n * Les tableaux que la clé peut atteindre, ou `null` pour « tous ceux de\n * l'organisation ».\n *\n * `null` et `[]` ne sont pas la même chose : la liste vide n'ouvre rien, et\n * c'est délibéré — un tableau supprimé ne doit pas élargir une clé qui ne le\n * nommait plus que lui.\n */\n boards: z.array(z.string().max(64)).max(200).nullable(),\n createdAt: z.string().max(64),\n /** Dernier usage constaté, pour reconnaître une clé oubliée. */\n lastUsedAt: z.string().max(64).nullable(),\n /** Qui l'a émise — une clé sans visage ne se révoque jamais sereinement. */\n createdBy: z.object({ id: z.string().max(128), name: z.string().max(200) }),\n /** Les 4 derniers caractères du secret, pour reconnaître une clé dans une liste. */\n keyPreview: z.string().max(8),\n});\nexport type CloudApiKey = z.infer<typeof CloudApiKeySchema>;\n\n/**\n * La réponse de création — la seule fois où le secret circule.\n *\n * Le serveur n'en garde qu'un condensat : personne, pas même l'organisation, ne\n * peut le relire ensuite. Perdue, une clé se remplace, elle ne se retrouve pas.\n */\nexport const CreatedCloudApiKeySchema = z.object({\n key: CloudApiKeySchema,\n secret: CloudApiKeySecretSchema,\n});\nexport type CreatedCloudApiKey = z.infer<typeof CreatedCloudApiKeySchema>;\n\nexport const CreateCloudApiKeyInput = z.object({\n organizationId: z.string().min(1).max(128),\n name: z.string().min(1).max(200),\n scopes: z.array(CloudApiScopeSchema).min(1).max(10),\n boards: z.array(z.string().max(64)).max(200).nullable().default(null),\n});\nexport type CreateCloudApiKeyInput = z.infer<typeof CreateCloudApiKeyInput>;\n\nexport const UpdateCloudApiKeyInput = z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200).optional(),\n scopes: z.array(CloudApiScopeSchema).min(1).max(10).optional(),\n boards: z.array(z.string().max(64)).max(200).nullable().optional(),\n});\nexport type UpdateCloudApiKeyInput = z.infer<typeof UpdateCloudApiKeyInput>;\n","import { z } from 'zod';\nimport { KanbanAttachmentSchema } from './kanban.schema.js';\n\n/**\n * Les intégrations de support : un outil de conversation client (Intercom,\n * HubSpot…) qui alimente un kanban du cloud.\n *\n * Le sens est **entrant seulement** : une conversation qui naît devient une\n * carte, ses messages deviennent des commentaires, sa résolution l'archive.\n * Répondre au client se fait toujours dans l'outil d'origine.\n */\n\n/** Les fournisseurs qu'on sait lire. Un de plus = un adaptateur de plus côté cloud. */\nexport const IntegrationProviderSchema = z.enum(['intercom']);\nexport type IntegrationProvider = z.infer<typeof IntegrationProviderSchema>;\n\n/** Une connexion telle que l'écran de gestion la voit — jamais son secret. */\nexport const IntegrationConnectionSchema = z.object({\n id: z.string().max(128),\n organizationId: z.string().max(128),\n provider: IntegrationProviderSchema,\n name: z.string().min(1).max(200),\n /** Le tableau et la colonne de création — seulement avec la création automatique. */\n boardId: z.string().max(64).nullable(),\n columnId: z.string().max(128).nullable(),\n enabled: z.boolean(),\n /**\n * L'URL complète du webhook à coller chez le fournisseur, construite par le\n * cloud (domaine public des webhooks). Elle contient un jeton imprévisible.\n */\n webhookUrl: z.string().max(2048),\n /** Les quatre derniers caractères du secret de signature, pour le reconnaître. */\n secretPreview: z.string().max(8),\n region: z.string().max(16),\n /** Créer une carte pour toute conversation qui n'est encore liée nulle part. */\n autoCreate: z.boolean(),\n createdBy: z.object({ id: z.string().max(128), name: z.string().max(200) }),\n createdAt: z.string().max(64),\n lastEventAt: z.string().max(64).nullable(),\n});\nexport type IntegrationConnection = z.infer<typeof IntegrationConnectionSchema>;\n\n/** L'état d'une conversation, tel que le fournisseur le dit. */\nexport const IntegrationConversationStateSchema = z.enum(['open', 'resolved']);\n\nexport const IntegrationMessageSchema = z.object({\n id: z.string().max(256),\n author: z.object({ name: z.string().max(500), role: z.enum(['customer', 'agent']) }),\n body: z.string().max(100_000),\n internal: z.boolean(),\n sentAt: z.string().max(64),\n /** Fichiers joints et images, copiés dans Runeya : ils se lisent comme ceux d'une carte. */\n attachments: z.array(KanbanAttachmentSchema).max(50),\n /** Noms des fichiers qui n'ont pas pu être copiés. */\n missingAttachments: z.array(z.string().max(500)).max(50),\n});\nexport type IntegrationMessage = z.infer<typeof IntegrationMessageSchema>;\n\n/** Une conversation telle qu'une carte la montre. */\nexport const IntegrationConversationSchema = z.object({\n id: z.string().max(256),\n connectionId: z.string().max(128),\n provider: IntegrationProviderSchema,\n externalId: z.string().max(128),\n title: z.string().max(500),\n url: z.string().max(2000).nullable(),\n state: IntegrationConversationStateSchema,\n updatedAt: z.string().max(64),\n});\nexport type IntegrationConversation = z.infer<typeof IntegrationConversationSchema>;\n\n/** Une conversation liée à une carte : son fil, et les autres cartes qui la suivent. */\nexport const CardConversationSchema = IntegrationConversationSchema.extend({\n origin: z.enum(['auto', 'manual']),\n /** Les fichiers de la conversation sont en train d'être copiés : ils vont apparaître. */\n filesPending: z.boolean(),\n linkedAt: z.string().max(64),\n opening: z.object({\n author: IntegrationMessageSchema.shape.author,\n body: z.string().max(100_000),\n attachments: z.array(KanbanAttachmentSchema).max(50),\n missingAttachments: z.array(z.string().max(500)).max(50),\n }).nullable(),\n messages: z.array(IntegrationMessageSchema),\n otherCards: z.array(z.object({ boardId: z.string().max(64), cardId: z.string().max(64), title: z.string().max(500) })),\n});\nexport type CardConversation = z.infer<typeof CardConversationSchema>;\n\n/** Un résultat de recherche chez le fournisseur, et les cartes qui la suivent déjà. */\nexport const ConversationSearchHitSchema = IntegrationConversationSchema.extend({\n preview: z.string().max(500),\n linkedCards: z.array(z.object({ boardId: z.string().max(64), cardId: z.string().max(64), title: z.string().max(500) })),\n});\nexport type ConversationSearchHit = z.infer<typeof ConversationSearchHitSchema>;\n","import { z } from 'zod';\n\n/**\n * Le journal des nouveautés, tel qu'il est publié par le cloud.\n *\n * **Deux surfaces, jamais mélangées.** `app` est l'application locale, dont la\n * version est celle du CLI publié sur npm. `cloud` est l'API et son application\n * web, déployées au push et donc sans numéro de version : leurs entrées sont\n * datées. Un même travail qui touche les deux donne DEUX entrées — c'est ce qui\n * permet à un poste resté sur une vieille version de ne pas se voir annoncer des\n * nouveautés qu'il n'a pas, et au cloud d'annoncer les siennes sans attendre une\n * publication npm.\n *\n * L'ordre se déduit de `version` seule (voir `compareChangelogVersions`) : les\n * deux formes — `1.4.2` et `2026-09-03` — se comparent par segments numériques.\n */\n\nexport const ChangelogSurfaceSchema = z.enum(['app', 'cloud']);\nexport type ChangelogSurface = z.infer<typeof ChangelogSurfaceSchema>;\n\n/** Ce que le lecteur doit comprendre en un coup d'œil : est-ce un ajout, un correctif, une rupture. */\nexport const ChangelogChangeKindSchema = z.enum(['feature', 'improvement', 'fix', 'breaking']);\nexport type ChangelogChangeKind = z.infer<typeof ChangelogChangeKindSchema>;\n\n/**\n * Les deux langues de l'interface, toutes deux obligatoires : une entrée\n * publiée dans une seule langue laisserait la moitié des lecteurs devant un\n * trou, et rien dans l'affichage ne pourrait le rattraper.\n */\nexport const ChangelogTextSchema = z.object({\n fr: z.string().min(1).max(500),\n en: z.string().min(1).max(500),\n});\nexport type ChangelogText = z.infer<typeof ChangelogTextSchema>;\n\nexport const ChangelogChangeSchema = z.object({\n kind: ChangelogChangeKindSchema,\n text: ChangelogTextSchema,\n});\nexport type ChangelogChange = z.infer<typeof ChangelogChangeSchema>;\n\n/**\n * Une entrée en attente, telle que l'écrit celui qui fait le travail.\n *\n * Elle ne porte PAS de version : au moment où on l'écrit, le numéro n'existe pas\n * encore — l'app attend sa publication npm, et le cloud n'a jamais de numéro,\n * seulement sa date. Un fichier par entrée, pour que deux branches qui en\n * ajoutent chacune une ne se marchent pas dessus : un tableau partagé produirait\n * un conflit à chaque fusion, et le réflexe sous conflit est d'en perdre une.\n *\n * `title` est facultatif : il nomme la version, pas le changement. La première\n * entrée qui en porte un le donne à sa version ; une version peut n'en avoir\n * aucun, et s'annoncer par son seul numéro.\n */\nexport const ChangelogDraftSchema = ChangelogChangeSchema.extend({\n date: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/),\n title: ChangelogTextSchema.optional(),\n});\nexport type ChangelogDraft = z.infer<typeof ChangelogDraftSchema>;\n\nexport const ChangelogReleaseSchema = z.object({\n surface: ChangelogSurfaceSchema,\n /** `1.4.2` pour l'app (version npm publiée), `2026-09-03` — ou `2026-09-03.2` — pour le cloud. */\n version: z.string().min(1).max(32).regex(/^[0-9][0-9.-]*$/),\n /** Date de publication, `YYYY-MM-DD`. */\n date: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/),\n /** Facultatif : une version peut s'annoncer par son seul numéro. */\n title: ChangelogTextSchema.optional(),\n /** Une version sans changement n'a rien à annoncer : elle n'a pas sa place ici. */\n changes: z.array(ChangelogChangeSchema).min(1).max(50),\n});\nexport type ChangelogRelease = z.infer<typeof ChangelogReleaseSchema>;\n\n/** L'index : de quoi lister et dater, sans transporter les corps. */\nexport const ChangelogIndexItemSchema = ChangelogReleaseSchema.omit({ changes: true }).extend({\n changeCount: z.number().int().nonnegative(),\n});\nexport type ChangelogIndexItem = z.infer<typeof ChangelogIndexItemSchema>;\n\n/**\n * Ordonne deux versions de changelog, quelle que soit leur forme.\n *\n * Les segments sont comparés numériquement (`1.10.0` après `1.9.0`, que la\n * comparaison de chaînes aurait inversé), et une version plus courte perd contre\n * son préfixe plus long (`2026-09-03` avant `2026-09-03.2`).\n */\nexport function compareChangelogVersions(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 const len = Math.max(pa.length, pb.length);\n for (let i = 0; i < len; i++) {\n const da = pa[i] ?? 0;\n const db = pb[i] ?? 0;\n if (da > db) return 1;\n if (da < db) return -1;\n }\n return 0;\n}\n","/**\n * Les bornes du message que le compagnon veut transmettre.\n *\n * Partagées serveur ↔ front parce que les deux en ont besoin pour la même\n * raison : le serveur extrait ce qu'il relaie, le panneau affiche la même chose\n * plutôt que le texte brut avec ses bornes. Recopiées de part et d'autre, une\n * borne renommée d'un seul côté casserait l'affichage sans rien faire échouer.\n */\nexport const COMPANION_RELAY_OPEN = '[RUNEYA_COMPAGNON_RESPONSE]';\nexport const COMPANION_RELAY_CLOSE = '[/RUNEYA_COMPAGNON_RESPONSE]';\n\n/**\n * Le contenu entre les bornes, ou `null` quand il n'y en a pas.\n *\n * La dernière ouverture l'emporte : si le compagnon s'y reprend à deux fois,\n * c'est la seconde qu'il assume. Un bloc non refermé rend ce qui suit\n * l'ouverture — la réponse a été coupée, on ne devine pas où elle s'arrêtait.\n */\nexport function extractCompanionRelay(raw: string): string | null {\n const text = (raw ?? '').trim();\n const open = text.lastIndexOf(COMPANION_RELAY_OPEN);\n if (open === -1) return null;\n const after = text.slice(open + COMPANION_RELAY_OPEN.length);\n const close = after.indexOf(COMPANION_RELAY_CLOSE);\n const inner = (close === -1 ? after : after.slice(0, close)).trim();\n return inner || null;\n}\n","/**\n * Nommage d'un lanceur de bureau — partagé entre le CLI, qui écrit les\n * fichiers, et le serveur, qui propose le raccourci depuis l'interface.\n *\n * Pur : aucune I/O, aucune dépendance à Node. L'identité d'un lanceur est une\n * fonction de son nom d'affichage, et les deux appelants doivent en tirer\n * exactement la même — sans quoi le raccourci créé depuis l'interface ne\n * porterait pas l'id que `uninstall-desktop --name` va chercher.\n */\n\n/** Turn a display name into a filesystem- and desktop-id-safe slug. */\nexport function slugifyLauncherName(name: string): string {\n const slug = name\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n return slug || 'runeya';\n}\n\n/**\n * The id is a pure function of the display name, so `uninstall-desktop --name`\n * always resolves to the launcher that `install-desktop` created. Names that\n * already slug to something starting with \"runeya\" are not prefixed again —\n * without that, the default \"Runeya — my-stack\" would yield the unreachable\n * id \"runeya-runeya-my-stack\".\n */\nexport function launcherIdFromName(name: string): string {\n const slug = slugifyLauncherName(name);\n return slug.startsWith('runeya') ? slug : `runeya-${slug}`;\n}\n\n/** Le dernier segment d'un chemin, sans dépendre de `node:path`. */\nfunction baseName(path: string): string {\n const parts = path.split(/[\\\\/]+/).filter(Boolean);\n return parts[parts.length - 1] ?? path;\n}\n\n/**\n * Derive the display name and id for a launcher.\n * Pinning a directory yields \"Runeya — <folder>\" so several stacks can each\n * have their own entry without colliding.\n */\nexport function deriveLauncherIdentity(\n explicitName: string | undefined,\n workingDir: string | null,\n): { name: string; id: string } {\n const name = explicitName ?? (workingDir ? `Runeya — ${baseName(workingDir)}` : 'Runeya');\n return { name, id: launcherIdFromName(name) };\n}\n","import type { LogSourceConfig } from '../schemas/log-source.schema.js';\n\n/**\n * Ce qui remplace une valeur qu'une IA n'a pas le droit de lire : un secret non\n * partagé (`service.getEnv`), l'identifiant d'une source de logs.\n */\nexport const MASKED_VALUE = '***';\n\n/** Une source de logs, ses identifiants remplacés par `MASKED_VALUE`. */\nexport function maskLogSourceSecrets(sources: LogSourceConfig[]): LogSourceConfig[] {\n return sources.map((src) => {\n if (src.type === 'mongo') return { ...src, connectionString: MASKED_VALUE };\n if (src.type === 'mysql' && src.password) return { ...src, password: MASKED_VALUE };\n return src;\n });\n}\n\n/** Ce qui désigne une source hors de son identifiant : la même base, la même table. */\nfunction sameSource(a: LogSourceConfig, b: LogSourceConfig): boolean {\n if (a.type === 'mongo' && b.type === 'mongo') return a.database === b.database && a.collection === b.collection;\n if (a.type === 'mysql' && b.type === 'mysql') {\n return a.host === b.host && a.port === b.port && a.user === b.user && a.database === b.database;\n }\n return false;\n}\n\n/**\n * Remettre en place les identifiants qu'une liste réécrite a laissés masqués.\n *\n * Une IA qui modifie les sources d'un service les a lues masquées : elle les\n * renvoie avec `MASKED_VALUE` là où était le secret. Il reprend alors la valeur\n * de la source existante qui désigne la même base. Un masque sans source\n * correspondante est refusé — l'écrire tel quel remplacerait l'identifiant par\n * trois astérisques.\n */\nexport function restoreLogSourceSecrets(incoming: LogSourceConfig[], existing: LogSourceConfig[]): LogSourceConfig[] {\n const unmatched = (where: string) =>\n new Error(`Log source ${where}: its credential is masked but no existing source matches it — give the real value.`);\n return incoming.map((src) => {\n if (src.type === 'mongo' && src.connectionString === MASKED_VALUE) {\n const match = existing.find((e) => sameSource(e, src));\n if (match?.type !== 'mongo') throw unmatched(`${src.database}.${src.collection}`);\n return { ...src, connectionString: match.connectionString };\n }\n if (src.type === 'mysql' && src.password === MASKED_VALUE) {\n const match = existing.find((e) => sameSource(e, src));\n if (match?.type !== 'mysql') throw unmatched(`${src.user}@${src.host}:${src.port}/${src.database}`);\n return { ...src, password: match.password };\n }\n return src;\n });\n}\n","import { createCipheriv, createDecipheriv, randomBytes, pbkdf2Sync } from 'node:crypto';\n\nconst PREFIX = 'aes256gcm:';\nconst IV_LENGTH = 12;\nconst AUTH_TAG_LENGTH = 16;\nconst KEY_LENGTH = 32;\nconst PBKDF2_ITERATIONS = 100_000;\nconst PBKDF2_DIGEST = 'sha256';\n/** Fixed salt for key derivation — the purpose is the salt (lazy to avoid Buffer at module init) */\nlet _KDF_SALT: Buffer | undefined;\nfunction getKdfSalt(): Buffer {\n if (!_KDF_SALT) _KDF_SALT = Buffer.from('runeya-log-sources-key-v1', 'utf8');\n return _KDF_SALT;\n}\n\n/**\n * Derives a 32-byte AES-256 key from `rawKey` using PBKDF2-SHA256.\n * The input key may be any Buffer (e.g. the raw passphrase bytes).\n */\nexport function deriveKey(rawKey: Buffer): Buffer {\n return pbkdf2Sync(rawKey, getKdfSalt(), PBKDF2_ITERATIONS, KEY_LENGTH, PBKDF2_DIGEST);\n}\n\n/**\n * Encrypts `plaintext` using AES-256-GCM.\n * Returns a string in the format: `aes256gcm:<iv_hex>:<authTag_hex>:<ciphertext_hex>`\n */\nexport function encrypt(plaintext: string, key: Buffer): string {\n const iv = randomBytes(IV_LENGTH);\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const authTag = cipher.getAuthTag();\n return `${PREFIX}${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted.toString('hex')}`;\n}\n\n/**\n * Decrypts a ciphertext string produced by `encrypt()`.\n * Throws if the format is invalid or authentication fails.\n */\nexport function decrypt(ciphertext: string, key: Buffer): string {\n if (!isEncrypted(ciphertext)) {\n throw new Error('Value is not in encrypted format');\n }\n const parts = ciphertext.slice(PREFIX.length).split(':');\n if (parts.length !== 3) {\n throw new Error('Invalid encrypted value format');\n }\n const [ivHex, authTagHex, encryptedHex] = parts;\n const iv = Buffer.from(ivHex, 'hex');\n const authTag = Buffer.from(authTagHex, 'hex');\n const encryptedBuffer = Buffer.from(encryptedHex, 'hex');\n\n if (iv.length !== IV_LENGTH) throw new Error('Invalid IV length');\n if (authTag.length !== AUTH_TAG_LENGTH) throw new Error('Invalid authTag length');\n\n const decipher = createDecipheriv('aes-256-gcm', key, iv, { authTagLength: 16 });\n decipher.setAuthTag(authTag);\n return Buffer.concat([decipher.update(encryptedBuffer), decipher.final()]).toString('utf8');\n}\n\n/**\n * Returns true if `value` is in the encrypted format produced by `encrypt()`.\n * Safe to call on plain-text values (returns false).\n */\nexport function isEncrypted(value: string): boolean {\n return value.startsWith(PREFIX);\n}\n","import type { JSLogParser } from './schemas/settings.schema.js';\n\n/**\n * Built-in log parsers that ship with Runeya.\n * IDs are prefixed with `native:` to distinguish from user-created parsers.\n *\n * All native parsers use the v2 pipeline signature: (line: LogLine) => LogLine\n * Each parser enriches the LogLine and passes it through. Order matters — the\n * service's parserIds array determines execution order.\n */\n\nconst epoch = new Date('2025-01-01T00:00:00Z');\n\nexport const nativeParsers: JSLogParser[] = [\n {\n id: 'native:json',\n name: 'JSON Log Parser',\n description: 'Parses JSON log lines and extracts level, message, timestamp, metadata, and the full parsed object.',\n code: `(line) => {\n var trimmed = line.message.trim();\n if (!trimmed.startsWith('{')) return line;\n try {\n var obj = JSON.parse(trimmed);\n var level = (obj.level || obj.severity || obj.loglevel || '').toString().toLowerCase();\n var levelMap = { trace: 'debug', debug: 'debug', info: 'info', warn: 'warn', warning: 'warn', error: 'error', fatal: 'fatal', err: 'error' };\n var mappedLevel = levelMap[level] || line.level;\n var message = obj.message || obj.msg || obj.text || trimmed;\n var metadata = {};\n for (var k in obj) {\n if (['level','severity','loglevel','message','msg','text','timestamp','time','ts'].indexOf(k) !== -1) continue;\n metadata[k] = typeof obj[k] === 'string' ? obj[k] : JSON.stringify(obj[k]);\n }\n var merged = {};\n for (var mk in line.metadata) merged[mk] = line.metadata[mk];\n for (var nk in metadata) merged[nk] = metadata[nk];\n return { raw: line.raw, stream: line.stream, level: mappedLevel, message: String(message).slice(0, 16384), hidden: line.hidden, metadata: merged, json: obj, jsonHeader: line.jsonHeader };\n } catch (e) { return line; }\n}`,\n enabled: true,\n builtin: true,\n createdAt: epoch,\n updatedAt: epoch,\n },\n {\n id: 'native:debug',\n name: 'Runeya Debug Parser',\n description: 'Detects Runeya internal debug logs emitted as JSON arrays: [\"runeya\", payload]. Marks them as debug level.',\n code: `(line) => {\n var trimmed = line.message.trim();\n if (!trimmed.startsWith('[')) return line;\n try {\n var parsed = JSON.parse(trimmed);\n if (!Array.isArray(parsed) || parsed[0] !== 'runeya') return line;\n var debug = parsed.length === 2 ? parsed[1] : parsed.slice(1);\n var message = typeof debug === 'string' ? debug : JSON.stringify(debug);\n var merged = {};\n for (var k in line.metadata) merged[k] = line.metadata[k];\n merged.runeya_debug = JSON.stringify(debug);\n return { raw: line.raw, stream: line.stream, level: 'debug', message: message, hidden: line.hidden, metadata: merged, jsonHeader: line.jsonHeader };\n } catch (e) { return line; }\n}`,\n enabled: true,\n builtin: true,\n createdAt: epoch,\n updatedAt: epoch,\n },\n {\n id: 'native:links',\n name: 'Link Detector',\n description: 'Detects URLs in plain-text log lines and exposes them in metadata.links for frontend rendering.',\n code: `(line) => {\n var urlRegex = /(https?|ftp):\\\\/\\\\/[\\\\w_-]+(?:\\\\.[\\\\w_-]+)+([\\\\w.,@?^=%&:/~+#-]*[\\\\w@?^=%&/~+#-])?/gi;\n var urls = line.message.match(urlRegex);\n if (!urls || urls.length === 0) return line;\n var merged = {};\n for (var k in line.metadata) merged[k] = line.metadata[k];\n merged.links = urls.join(' ');\n return { raw: line.raw, stream: line.stream, level: line.level, message: line.message, hidden: line.hidden, metadata: merged, jsonHeader: line.jsonHeader };\n}`,\n enabled: true,\n builtin: true,\n createdAt: epoch,\n updatedAt: epoch,\n },\n];\n\n/** Look up a native parser by ID */\nexport function getNativeParser(id: string): JSLogParser | undefined {\n return nativeParsers.find(p => p.id === id);\n}\n","import vm from 'node:vm';\nimport type { JSLogParser as JSLogParserDef } from './schemas/settings.schema.js';\nimport type { LogLine } from './schemas/log.schema.js';\nimport type { LogLevel } from './schemas/log.schema.js';\n\ninterface CompiledParser {\n id: string;\n name: string;\n enabled: boolean;\n fn: (line: LogLine) => LogLine;\n}\n\nconst VALID_LEVELS = new Set<string>(['debug', 'info', 'warn', 'error', 'fatal']);\n\n/** Budget CPU accordé à un parseur pour *une* ligne. */\nconst PARSE_TIMEOUT_MS = 50;\n/** Au-delà, le parseur est considéré hostile et désactivé pour la session. */\nconst MAX_CONSECUTIVE_TIMEOUTS = 10;\n\nexport class JSLogParser {\n private parsers: CompiledParser[] = [];\n\n constructor(definitions: JSLogParserDef[] = []) {\n this.setParsers(definitions);\n }\n\n setParsers(definitions: JSLogParserDef[]): void {\n this.parsers = [];\n\n for (const def of definitions) {\n if (!def.enabled) continue;\n\n try {\n const compiled = this.compileParser(def);\n this.parsers.push({\n id: def.id,\n name: def.name,\n enabled: true,\n fn: compiled,\n });\n } catch (err) {\n console.warn(\n `[js-log-parser] Failed to compile parser \"${def.name}\" (${def.id}): ${\n err instanceof Error ? err.message : String(err)\n }`\n );\n }\n }\n }\n\n parse(line: LogLine): LogLine {\n let current = line;\n\n for (const parser of this.parsers) {\n try {\n current = parser.fn(current);\n } catch (err) {\n console.warn(\n `[js-log-parser] Parser \"${parser.name}\" threw error: ${\n err instanceof Error ? err.message : String(err)\n }`\n );\n }\n }\n\n return this.sanitize(current);\n }\n\n /**\n * Compile le code utilisateur en une fonction bornée en temps.\n *\n * Le `timeout` de `runInNewContext` ne couvre que l'évaluation de la factory :\n * la closure retournée s'exécutait ensuite ligne par ligne directement sur\n * l'event loop, sans aucune borne. Une regex à backtracking exponentiel\n * fournie par l'utilisateur figeait donc l'agent entier — logs, statuts et\n * métriques de *tous* les services. Chaque invocation repasse maintenant par\n * la vm, avec son propre budget.\n */\n private compileParser(def: JSLogParserDef): (line: LogLine) => LogLine {\n const forbidden = ['require(', 'import ', 'eval('];\n for (const pat of forbidden) {\n if (def.code.includes(pat)) {\n throw new Error('Code contains forbidden patterns (require, import, eval)');\n }\n }\n\n const sandbox = {\n RegExp,\n String,\n Object,\n Array,\n JSON,\n Math,\n Date,\n undefined,\n null: null,\n };\n\n let script: vm.Script;\n try {\n script = new vm.Script(`(${def.code})`, { filename: `parser-${def.id}.js` });\n } catch (err) {\n throw new Error(`Compilation failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // Le contexte est conservé : c'est lui qui permet de ré-entrer dans la vm\n // à chaque ligne, et donc d'armer un timeout par invocation.\n const context = vm.createContext({ ...sandbox, __line: null as unknown, __result: null as unknown });\n\n let parserFn: unknown;\n try {\n parserFn = script.runInContext(context, { timeout: 100 });\n } catch (err) {\n throw new Error(`Execution failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n if (typeof parserFn !== 'function') {\n throw new Error('Parser code must export a function');\n }\n\n (context as Record<string, unknown>)['__parserFn'] = parserFn;\n const callScript = new vm.Script('__result = __parserFn(__line);', {\n filename: `parser-${def.id}-call.js`,\n });\n\n let consecutiveTimeouts = 0;\n let disabled = false;\n\n return (line: LogLine): LogLine => {\n if (disabled) return line;\n\n const ctx = context as Record<string, unknown>;\n ctx['__line'] = line;\n ctx['__result'] = null;\n try {\n callScript.runInContext(context, { timeout: PARSE_TIMEOUT_MS });\n consecutiveTimeouts = 0;\n } catch (err) {\n // `instanceof Error` est faux ici : l'erreur de timeout ne vient pas du\n // même realm que ce module. On la reconnaît par son code/message.\n const e = err as { code?: unknown; message?: unknown } | null;\n const timedOut = !!e\n && (e.code === 'ERR_SCRIPT_EXECUTION_TIMEOUT'\n || (typeof e.message === 'string' && /execution timed out/i.test(e.message)));\n if (!timedOut) throw err;\n consecutiveTimeouts += 1;\n if (consecutiveTimeouts >= MAX_CONSECUTIVE_TIMEOUTS) {\n disabled = true;\n console.warn(\n `[js-log-parser] Parser \"${def.name}\" (${def.id}) disabled after ${MAX_CONSECUTIVE_TIMEOUTS} consecutive timeouts`,\n );\n }\n return line;\n }\n\n const result = ctx['__result'];\n if (result === null || result === undefined || typeof result !== 'object') {\n return line;\n }\n return result as LogLine;\n };\n }\n\n /** Sanitize the final LogLine: truncate message, limit metadata, validate level */\n private sanitize(line: LogLine): LogLine {\n let { message, metadata, level } = line;\n\n if (message.length > 16384) {\n message = message.substring(0, 16384) + '...[truncated]';\n }\n\n metadata = metadata ?? {};\n const metaKeys = Object.keys(metadata);\n if (metaKeys.length > 100) {\n const limited: Record<string, unknown> = {};\n for (let i = 0; i < 100; i++) {\n limited[metaKeys[i]] = metadata[metaKeys[i]];\n }\n metadata = limited;\n }\n\n if (!VALID_LEVELS.has(level)) {\n level = 'info' as LogLevel;\n }\n\n if (message !== line.message || metadata !== line.metadata || level !== line.level) {\n return { ...line, message, metadata, level };\n }\n return line;\n }\n}\n","/**\n * Variables intégrées — les `{{…}}` que Runeya remplit lui-même, par opposition\n * aux `{{environment.KEY}}` que l'utilisateur définit et que le résolveur\n * d'environnement traite (`apps/server/src/services/environment-resolver.ts`).\n *\n * Cette table est la SEULE déclaration : le serveur et l'agent y lisent ce\n * qu'ils doivent produire, l'interface ce qu'elle doit proposer et documenter.\n * Elle a été introduite parce que la liste vivait en trois exemplaires — dans\n * le routeur de service, dans le gestionnaire de processus et dans le tableau\n * de variables du web — et que le web en avait déjà oublié un.\n *\n * ## Portées\n *\n * - `server` : connu à la résolution, quand le serveur prépare la config à\n * déployer (nom, ports, projet, environnement actif).\n * - `agent` : ne peut être résolu QUE sur la machine qui exécute le service —\n * son IP, son utilisateur, son système, son répertoire de travail. Les\n * résoudre côté serveur graverait la machine qui a fait le déploiement, ce\n * qui ne se voit qu'en multi-machines, et tard.\n */\n\nexport type BuiltinScope = 'server' | 'agent';\n\nexport interface BuiltinVariable {\n /** Nom tel qu'il s'écrit entre accolades, sans les accolades */\n name: string;\n scope: BuiltinScope;\n /** Suffixe de la clé i18n de l'interface : `builtins.<descriptionKey>` */\n descriptionKey: string;\n /** Nom conservé pour ne pas casser les configurations existantes */\n deprecatedAlias?: string;\n}\n\nexport const BUILTIN_VARIABLES: readonly BuiltinVariable[] = [\n // ── Le service ───────────────────────────────────────────────────────────\n { name: 'service.NAME', scope: 'server', descriptionKey: 'serviceName' },\n { name: 'service.ID', scope: 'server', descriptionKey: 'serviceId' },\n { name: 'service.PORT', scope: 'server', descriptionKey: 'servicePort' },\n { name: 'service.URL', scope: 'server', descriptionKey: 'serviceUrl' },\n { name: 'service.BASE_URL', scope: 'server', descriptionKey: 'serviceBaseUrl' },\n { name: 'service.CWD', scope: 'agent', descriptionKey: 'serviceCwd' },\n\n // ── Le projet et l'environnement actif ───────────────────────────────────\n { name: 'project.NAME', scope: 'server', descriptionKey: 'projectName' },\n { name: 'runeya.ENV_NAME', scope: 'server', descriptionKey: 'envName' },\n\n // ── Le serveur Runeya ────────────────────────────────────────────────────\n // `service.HOST` a toujours désigné l'adresse d'écoute du SERVEUR, pas une\n // propriété du service : le nom trompait, il devient un alias.\n { name: 'runeya.HOST', scope: 'server', descriptionKey: 'runeyaHost', deprecatedAlias: 'service.HOST' },\n\n // ── La machine qui exécute ───────────────────────────────────────────────\n { name: 'agent.HOST_LAN', scope: 'agent', descriptionKey: 'agentHostLan', deprecatedAlias: 'service.HOST_LAN' },\n // Le NOM de l'agent est une étiquette de la configuration du serveur, pas\n // une propriété de la machine : c'est le serveur qui le connaît et le résout.\n { name: 'agent.NAME', scope: 'server', descriptionKey: 'agentName' },\n { name: 'agent.OS', scope: 'agent', descriptionKey: 'agentOs' },\n { name: 'agent.HOME', scope: 'agent', descriptionKey: 'agentHome' },\n];\n\nexport const BUILTINS_BY_SCOPE = (scope: BuiltinScope): readonly BuiltinVariable[] =>\n BUILTIN_VARIABLES.filter((b) => b.scope === scope);\n\n/**\n * Une référence `{{nom}}`. Le nom accepte les points (`service.PORT`,\n * `services.api.URL`) mais ni espace ni accolade : une référence ne peut donc\n * pas se former à la couture entre deux morceaux de texte.\n */\nconst BUILTIN_REFERENCE_RE = /\\{\\{([A-Za-z][A-Za-z0-9_.-]*)\\}\\}/g;\n\n/** Les `{{environment.KEY}}` appartiennent au résolveur, jamais aux builtins. */\nconst ENVIRONMENT_NAMESPACE = 'environment.';\n\n/** Le préfixe sous lequel un service en nomme un autre : `services.<slug>.PORT`. */\nconst CROSS_SERVICE_NAMESPACE = 'services.';\n\n/**\n * Remplace les références présentes dans `values`, et laisse les autres\n * intactes : une passe unique, jamais récursive — une valeur qui contient\n * elle-même une référence ne relance pas la substitution, faute de quoi deux\n * variables se pointant l'une l'autre boucleraient.\n */\nexport function interpolateBuiltins(text: string, values: Record<string, string>): string {\n return text.replace(BUILTIN_REFERENCE_RE, (match, name: string) => {\n if (name.startsWith(ENVIRONMENT_NAMESPACE)) return match;\n return values[name] ?? match;\n });\n}\n\n/**\n * Les slugs de services qu'un texte nomme, via `{{services.<slug>.PROP}}`.\n *\n * C'est l'arête d'un graphe de dépendances : si une variable de A cite\n * `services.b.PORT`, c'est que A a besoin de B pour tourner. La détection\n * s'appuie sur la MÊME expression que `interpolateBuiltins`, pour ne jamais\n * annoncer un lien que l'interpolation ne ferait pas — `{{services. b.URL}}`\n * n'est pas une référence, et ne doit donc pas devenir une arête.\n *\n * Une référence sans propriété (`{{services.b}}`) ne résout rien : elle ne\n * compte pas non plus.\n */\nexport function crossServiceSlugsIn(text: string): string[] {\n const slugs = new Set<string>();\n for (const match of text.matchAll(BUILTIN_REFERENCE_RE)) {\n const name = match[1];\n if (!name || !name.startsWith(CROSS_SERVICE_NAMESPACE)) continue;\n const rest = name.slice(CROSS_SERVICE_NAMESPACE.length);\n const dot = rest.indexOf('.');\n if (dot <= 0 || dot === rest.length - 1) continue;\n slugs.add(rest.slice(0, dot));\n }\n return [...slugs];\n}\n\n/** `interpolateBuiltins` appliqué à chaque valeur d'un dictionnaire d'env. */\nexport function interpolateBuiltinsInEnv(\n env: Record<string, string>,\n values: Record<string, string>,\n): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [key, value] of Object.entries(env)) {\n out[key] = interpolateBuiltins(value, values);\n }\n return out;\n}\n\n/**\n * Ajoute au dictionnaire les alias hérités, pour que `{{service.HOST}}`\n * continue de rendre ce que rend `{{runeya.HOST}}`.\n */\nexport function withDeprecatedAliases(values: Record<string, string>): Record<string, string> {\n const out = { ...values };\n for (const builtin of BUILTIN_VARIABLES) {\n if (builtin.deprecatedAlias && out[builtin.name] !== undefined) {\n out[builtin.deprecatedAlias] = out[builtin.name];\n }\n }\n return out;\n}\n\n/**\n * Nom sous lequel un service est adressable depuis un autre\n * (`{{services.<slug>.PORT}}`).\n *\n * Un nom de service est libre — accents, espaces, majuscules — alors qu'une\n * référence doit rester un mot sans espace. D'où ce passage en minuscules\n * tiretées, appliqué de la même façon par le serveur qui produit les valeurs\n * et par l'interface qui les propose.\n */\nexport function serviceSlug(name: string): string {\n return name\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\n/**\n * Les slugs que deux services d'un même projet se disputent.\n *\n * Un tel slug n'est adressable pour AUCUN des deux : rendre l'un plutôt que\n * l'autre dépendrait de l'ordre de chargement. La règle est ici, et non chez\n * ses deux appelants — celui qui produit les valeurs à interpoler et celui qui\n * dessine le graphe des liens — parce qu'ils doivent dire la même chose : un\n * lien montré à l'écran mais non interpolé au démarrage serait pire que pas de\n * lien du tout.\n */\nexport function ambiguousServiceSlugs(names: readonly string[]): Set<string> {\n const counts = new Map<string, number>();\n for (const name of names) {\n const slug = serviceSlug(name);\n if (slug) counts.set(slug, (counts.get(slug) ?? 0) + 1);\n }\n return new Set([...counts].filter(([, count]) => count > 1).map(([slug]) => slug));\n}\n\n/**\n * Les ports d'un service : `service.PORT` pour le premier — celui qu'on cite\n * dans neuf cas sur dix — puis `service.PORT_2`, `_3`… pour les suivants.\n */\nexport function servicePortValues(ports: readonly number[] | undefined, prefix = 'service'): Record<string, string> {\n const values: Record<string, string> = {};\n (ports ?? []).forEach((port, i) => {\n values[i === 0 ? `${prefix}.PORT` : `${prefix}.PORT_${i + 1}`] = String(port);\n });\n return values;\n}\n\n/**\n * Une adresse d'écoute « toutes interfaces » n'est pas une adresse à laquelle\n * on se connecte. En mode LAN, le serveur écoute sur `0.0.0.0` : bâtir\n * `http://0.0.0.0:3000` donnerait une URL que rien ne peut joindre.\n */\nexport function isWildcardHost(host: string): boolean {\n const h = host.trim();\n return h === '' || h === '0.0.0.0' || h === '::' || h === '[::]';\n}\n\n/** L'adresse de bouclage, sous ses écritures possibles. */\nfunction isLoopbackHost(host: string): boolean {\n const h = host.trim();\n return h === '127.0.0.1' || h === '::1' || h === '[::1]';\n}\n\n/**\n * L'hôte à écrire dans une URL, à partir de l'adresse d'écoute du serveur.\n *\n * La boucle locale devient `localhost` : c'est le nom que les développeurs\n * écrivent, celui des origines autorisées du dépôt, et celui qu'on colle dans\n * un navigateur. `{{runeya.HOST}}` continue de rendre l'adresse réelle — c'est\n * elle qu'un service met dans son bind, et la traduire là serait faux.\n *\n * Un hôte explicitement configuré (une IP de LAN, un nom de machine) n'est\n * jamais réécrit : le seul cas traduit est celui où l'adresse ne désigne que\n * « cette machine ». Une adresse « toutes interfaces » rend `null` — à\n * l'appelant de décider, l'agent connaissant seul son IP joignable.\n */\nexport function urlHostFor(host: string): string | null {\n if (isWildcardHost(host)) return null;\n return isLoopbackHost(host) ? 'localhost' : host.trim();\n}\n\n/**\n * Les URL par lesquelles on joint un service, une par port : `service.URL`,\n * `service.URL_2`… numérotées comme les ports, si bien que `URL_2` désigne\n * toujours le service sur `PORT_2`.\n *\n * Un domaine local est déclaré AVEC son port (c'est ce que le proxy route) :\n * l'URL d'un port est donc son domaine s'il en a un, sinon l'hôte et le port.\n * Un domaine déclaré sur un port absent de la liste des ports est ajouté à la\n * suite, pour ne pas se perdre.\n *\n * À ne pas confondre avec le champ `url` du service — son « URL de base »,\n * saisie librement, souvent l'adresse publique : celle-là s'écrit\n * `{{service.BASE_URL}}`. Faire rendre l'une par l'autre romprait la\n * correspondance entre `URL_n` et `PORT_n`.\n */\nexport function serviceUrlValues(service: {\n ports?: number[];\n localUrls?: { url: string; port: number }[];\n}, host: string, prefix = 'service'): Record<string, string> {\n const domainByPort = new Map((service.localUrls ?? []).map((lu) => [lu.port, lu.url]));\n const ports = [...(service.ports ?? [])];\n for (const local of service.localUrls ?? []) {\n if (!ports.includes(local.port)) ports.push(local.port);\n }\n\n const values: Record<string, string> = {};\n ports.forEach((port, i) => {\n const domain = domainByPort.get(port);\n values[i === 0 ? `${prefix}.URL` : `${prefix}.URL_${i + 1}`] =\n domain ? `http://${domain}` : `http://${host}:${port}`;\n });\n return values;\n}\n\n/** Les clés `services.<slug>.*` exposées pour un service voisin. */\nexport function crossServiceValues(service: {\n name: string;\n id: string;\n ports?: number[];\n localUrls?: { url: string; port: number }[];\n url?: string;\n}, host: string): Record<string, string> {\n const slug = serviceSlug(service.name);\n if (!slug) return {};\n return {\n [`services.${slug}.NAME`]: service.name,\n [`services.${slug}.ID`]: service.id,\n ...servicePortValues(service.ports, `services.${slug}`),\n ...serviceUrlValues(service, host, `services.${slug}`),\n ...(service.url ? { [`services.${slug}.BASE_URL`]: service.url } : {}),\n };\n}\n\n/** Une référence qu'aucune étape ne remplira : elle arrivera telle quelle dans le process. */\nexport interface UnresolvedReference {\n key: string;\n reference: string;\n}\n\n/** Les ports et URL numérotés que le serveur produit en plus des noms déclarés : `service.PORT_2`. */\nconst NUMBERED_SERVICE_BUILTIN_RE = /^service\\.(PORT|URL)_\\d+$/;\n\nfunction builtinScopeOf(name: string): BuiltinScope | null {\n const builtin = BUILTIN_VARIABLES.find((b) => b.name === name || b.deprecatedAlias === name);\n if (builtin) return builtin.scope;\n if (NUMBERED_SERVICE_BUILTIN_RE.test(name) || name.startsWith(CROSS_SERVICE_NAMESPACE)) return 'server';\n return null;\n}\n\n/**\n * Les références restées en place dans un env résolu, et qui le resteront.\n *\n * Le résolveur d'environnement, puis le serveur, puis l'agent remplissent\n * chacun les leurs et laissent intactes les autres — si bien qu'une faute de\n * frappe (`{{environment.DB_HSOT}}`) arrive au process comme du texte, sans\n * que rien ne le signale. Ce qui est signalé dépend de l'étape atteinte :\n *\n * - une référence d'environnement : toujours, le résolveur est déjà passé ;\n * - une variable intégrée du serveur : si `serverResolved` — sinon elle attend\n * le déploiement ; mais un nom qui n'en est pas une est une faute dans les\n * deux cas ;\n * - une variable intégrée de l'agent : jamais, elle se remplit au démarrage.\n *\n * `skipKeys` tait des clés — celles dont la valeur est masquée : la forme d'un\n * secret, références comprises, n'a pas à sortir.\n */\nexport function findUnresolvedReferences(\n env: Record<string, string>,\n opts: { serverResolved: boolean; skipKeys?: Iterable<string> },\n): UnresolvedReference[] {\n const skip = new Set(opts.skipKeys ?? []);\n const out: UnresolvedReference[] = [];\n for (const [key, value] of Object.entries(env)) {\n if (skip.has(key)) continue;\n for (const match of value.matchAll(BUILTIN_REFERENCE_RE)) {\n const reference = match[1]!;\n if (!reference.startsWith(ENVIRONMENT_NAMESPACE)) {\n const scope = builtinScopeOf(reference);\n if (scope === 'agent') continue;\n if (scope === 'server' && !opts.serverResolved) continue;\n }\n out.push({ key, reference });\n }\n }\n return out;\n}\n\n/** Une valeur recopiée, et la référence qui la suivrait. */\nexport interface BuiltinSuggestion {\n literal: string;\n reference: string;\n}\n\n/** Les variables intégrées qui valent la peine d'être reconnues : ports et adresses, du service ou d'un voisin. */\nconst SUGGESTABLE_BUILTIN_RE = /^(service|services\\.[^.]+)\\.(PORT|URL|BASE_URL)(_\\d+)?$/;\n\n/**\n * Les ports et URL de services recopiés dans une valeur, avec la référence qui\n * les remplacerait.\n *\n * Recopier `http://localhost:3211` fige l'adresse du front telle qu'elle est sur\n * ce poste, aujourd'hui : elle ne suit ni un changement de port ni un domaine\n * local. `{{services.front.URL}}`, si. `builtins` est ce que le serveur calcule\n * pour le service concerné (`buildServerBuiltins`).\n *\n * La plus longue valeur l'emporte (une URL avant le port qu'elle contient), et\n * à longueur égale la référence du service lui-même avant celle qui le nomme de\n * l'extérieur. Un nombre n'est reconnu qu'entier, et rien n'est lu à\n * l'intérieur d'une référence déjà écrite. Ce ne sont que des suggestions : la\n * valeur n'est jamais réécrite.\n */\nexport function suggestBuiltinReferences(text: string, builtins: Record<string, string>): BuiltinSuggestion[] {\n const candidates = Object.entries(builtins)\n .filter(([name, value]) => SUGGESTABLE_BUILTIN_RE.test(name) && value.length > 1 && !value.includes('{{'))\n .sort(([nameA, a], [nameB, b]) => b.length - a.length || Number(nameA.startsWith('services.')) - Number(nameB.startsWith('services.')));\n\n const claimed: [number, number][] = [...text.matchAll(BUILTIN_REFERENCE_RE)].map((m) => [m.index, m.index + m[0].length]);\n const overlaps = (start: number, end: number) => claimed.some(([s, e]) => start < e && end > s);\n const isDigit = (c: string | undefined) => c !== undefined && c >= '0' && c <= '9';\n\n const suggestions: BuiltinSuggestion[] = [];\n for (const [name, literal] of candidates) {\n let from = 0;\n for (let at = text.indexOf(literal, from); at !== -1; at = text.indexOf(literal, from)) {\n const end = at + literal.length;\n from = at + 1;\n if (overlaps(at, end)) continue;\n if (isDigit(literal[0]) && isDigit(text[at - 1])) continue;\n if (isDigit(literal[literal.length - 1]) && isDigit(text[end])) continue;\n claimed.push([at, end]);\n if (!suggestions.some((s) => s.literal === literal)) suggestions.push({ literal, reference: `{{${name}}}` });\n }\n }\n return suggestions;\n}\n","export const PROCESS_STATES = ['starting', 'running', 'stopped', 'errored'] as const;\nexport type ProcessStateValue = typeof PROCESS_STATES[number];\n","export const LOG_LEVELS = ['debug', 'info', 'warn', 'error', 'fatal'] as const;\nexport type LogLevelValue = typeof LOG_LEVELS[number];\n\nexport const LOG_LEVEL_PRIORITY: Record<LogLevelValue, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n fatal: 4,\n};\n","export const GLOBAL_ROLES = ['owner', 'admin', 'member'] as const;\nexport type GlobalRoleValue = typeof GLOBAL_ROLES[number];\n\nexport const PROJECT_ROLES = ['admin', 'editor', 'viewer'] as const;\nexport type ProjectRoleValue = typeof PROJECT_ROLES[number];\n","/** Health check default interval (ms) */\nexport const HEALTH_CHECK_INTERVAL = 30_000;\n\n/** Metrics collection interval (ms) */\nexport const METRICS_INTERVAL = 5_000;\n\n/** Agent health polling interval (ms) */\nexport const AGENT_HEALTH_POLL_INTERVAL = 15_000;\n\n/** UI search/filter debounce (ms) */\nexport const SEARCH_DEBOUNCE = 300;\n\n/** Health check initial delay before first check (ms) */\nexport const HEALTH_CHECK_INITIAL_DELAY = 5_000;\n\n/** Agent health WS interval (ms) */\nexport const HEALTH_WS_INTERVAL = 10_000;\n","/** Default log ring buffer size */\nexport const LOG_BUFFER_SIZE = 5_000;\n\n/** Max log entries displayed in UI */\nexport const LOG_DISPLAY_LIMIT = 500;\n","/** Default process grace period before SIGKILL (ms) */\nexport const GRACE_PERIOD = 10_000;\n\n/** HTTP fetch timeout for agent calls (ms) */\nexport const AGENT_FETCH_TIMEOUT = 10_000;\n\n/** HTTP fetch timeout for long-running agent calls like shortcuts/ad-hoc commands (ms) — 10 minutes */\nexport const AGENT_LONG_FETCH_TIMEOUT = 600_000;\n\n/** HTTP fetch timeout for process stop calls (ms) — grace period + generous buffer */\nexport const AGENT_STOP_FETCH_TIMEOUT = GRACE_PERIOD + 15_000;\n\n/** Passphrase extraction timeout during agent spawn (ms) */\nexport const PASSPHRASE_TIMEOUT = 30_000;\n\n/** Min WS reconnect delay (ms) */\nexport const WS_RECONNECT_MIN = 1_000;\n\n/** Max WS reconnect delay (ms) */\nexport const WS_RECONNECT_MAX = 15_000;\n\n/** Max WS reconnect attempts */\nexport const WS_RECONNECT_MAX_ATTEMPTS = 5;\n\n/** Base retry delay for subscriptions (ms) */\nexport const SUBSCRIPTION_RETRY_BASE = 1_000;\n","export interface EditorDefinition {\n key: string;\n name: string;\n command: string;\n}\n\nexport const SUPPORTED_EDITORS: EditorDefinition[] = [\n { key: 'vscode', name: 'Visual Studio Code', command: 'code' },\n { key: 'cursor', name: 'Cursor', command: 'cursor' },\n { key: 'windsurf', name: 'Windsurf', command: 'windsurf' },\n { key: 'sublime', name: 'Sublime Text', command: 'subl' },\n { key: 'atom', name: 'Atom', command: 'atom' },\n { key: 'antigravity', name: 'Antigravity', command: 'antigravity' },\n { key: 'intellij', name: 'IntelliJ IDEA', command: 'idea' },\n { key: 'android-studio', name: 'Android Studio', command: 'studio' },\n { key: 'webstorm', name: 'WebStorm', command: 'webstorm' },\n { key: 'zed', name: 'Zed', command: 'zed' },\n { key: 'neovim', name: 'Neovim', command: 'nvim' },\n { key: 'vim', name: 'Vim', command: 'vim' },\n { key: 'emacs', name: 'Emacs', command: 'emacs' },\n { key: 'fleet', name: 'Fleet', command: 'fleet' },\n];\n\nexport const EDITOR_BY_KEY = new Map<string, EditorDefinition>(\n SUPPORTED_EDITORS.map((e) => [e.key, e]),\n);\n","import * as Y from 'yjs';\n\n/**\n * Generic JSON ↔ Yjs mapping.\n *\n * The cloud must share exactly what git shares: the contents of the `.runeya`\n * files, whatever fields they happen to carry today. Enumerating those fields\n * would make this a hand-maintained allowlist — adding a field to a schema and\n * forgetting it here would not break anything, it would just silently stop\n * syncing. So nothing here names a field: any JSON shape round-trips.\n *\n * The mapping is structural rather than blob-per-file, because a blob makes\n * every concurrent edit last-writer-wins across a whole file. Mapping objects to\n * `Y.Map` and arrays to `Y.Array` lets Yjs merge edits to different fields — and\n * different array elements — the way it is meant to.\n *\n * Every write is a *diff*: identical input must produce no Yjs update at all.\n * Anything less loops forever (local → doc → local → doc).\n */\n\nexport type Json = null | boolean | number | string | Json[] | { [k: string]: Json };\n\n/**\n * Strip `undefined` and other non-JSON values by round-tripping.\n *\n * Zod leaves optional fields absent while JS code tends to set them to\n * `undefined`; `Y.Map.set(k, undefined)` is not `delete(k)`, so without this the\n * diff would see a change on every pass and never settle.\n */\nexport function normalize(value: unknown): Json {\n return JSON.parse(JSON.stringify(value ?? null)) as Json;\n}\n\nfunction isPlainObject(v: unknown): v is Record<string, Json> {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n\n/** Yjs value → plain JSON. */\nexport function toPlain(value: unknown): Json {\n if (value instanceof Y.Map) {\n const out: Record<string, Json> = {};\n for (const [k, v] of value.entries()) out[k] = toPlain(v);\n return out;\n }\n if (value instanceof Y.Array) return value.toArray().map(toPlain);\n return (value ?? null) as Json;\n}\n\n/**\n * Identity of an array element, used to align two versions of an array.\n *\n * An element with an `id` keeps that identity across edits, so a concurrent\n * change to one element and an insertion of another merge cleanly. Anything\n * else (scalars, objects with no id) is identified by its whole value: editing\n * it reads as delete + insert, i.e. last-writer-wins for that element.\n */\nfunction identityOf(value: Json): string {\n if (isPlainObject(value) && typeof value['id'] === 'string') return `id:${value['id']}`;\n return `v:${JSON.stringify(value)}`;\n}\n\nfunction identityOfY(value: unknown): string {\n if (value instanceof Y.Map) {\n const id = value.get('id');\n if (typeof id === 'string') return `id:${id}`;\n }\n return `v:${JSON.stringify(toPlain(value))}`;\n}\n\n/** Convert a JSON value into the Yjs type that represents it. */\nfunction toY(value: Json): unknown {\n if (Array.isArray(value)) {\n const arr = new Y.Array<unknown>();\n if (value.length > 0) arr.insert(0, value.map(toY));\n return arr;\n }\n if (isPlainObject(value)) {\n const map = new Y.Map<unknown>();\n for (const [k, v] of Object.entries(value)) map.set(k, toY(v));\n return map;\n }\n return value;\n}\n\n/**\n * Diff `next` into a `Y.Map`, recursing into nested objects and arrays and\n * deleting keys that `next` no longer has.\n */\nexport function applyToMap(map: Y.Map<unknown>, next: Record<string, Json>): void {\n for (const key of Array.from(map.keys())) {\n if (!(key in next)) map.delete(key);\n }\n for (const [key, value] of Object.entries(next)) {\n const current = map.get(key);\n if (Array.isArray(value)) {\n if (!(current instanceof Y.Array)) map.set(key, toY(value));\n else applyToArray(current, value);\n } else if (isPlainObject(value)) {\n if (!(current instanceof Y.Map)) map.set(key, toY(value));\n else applyToMap(current, value);\n } else if (current instanceof Y.Map || current instanceof Y.Array || current !== value) {\n map.set(key, value);\n }\n }\n}\n\n/**\n * Diff `next` into a `Y.Array` by aligning elements on their identity.\n *\n * Targeted inserts/deletes are what let Yjs keep both sides of a concurrent\n * append; rewriting the array wholesale (delete-all + insert) would drop one of\n * them, which is exactly the data loss this mapping exists to avoid.\n */\nexport function applyToArray(arr: Y.Array<unknown>, next: Json[]): void {\n const wanted = next.map(identityOf);\n const wantedCount = new Map<string, number>();\n for (const k of wanted) wantedCount.set(k, (wantedCount.get(k) ?? 0) + 1);\n\n // Drop elements `next` no longer contains (respecting duplicate counts).\n const seen = new Map<string, number>();\n for (let i = arr.length - 1; i >= 0; i--) {\n const key = identityOfY(arr.get(i));\n const used = seen.get(key) ?? 0;\n if (used >= (wantedCount.get(key) ?? 0)) arr.delete(i, 1);\n else seen.set(key, used + 1);\n }\n\n // Walk both sides in order: recurse into matches, insert what is missing.\n for (let j = 0; j < next.length; j++) {\n const key = wanted[j]!;\n if (j < arr.length && identityOfY(arr.get(j)) === key) {\n const current = arr.get(j);\n const value = next[j]!;\n if (current instanceof Y.Map && isPlainObject(value)) applyToMap(current, value);\n else if (current instanceof Y.Array && Array.isArray(value)) applyToArray(current, value);\n continue;\n }\n // Pull a later match into place rather than re-creating it, so a reorder\n // does not read as a delete + insert of unrelated content.\n let found = -1;\n for (let k = j + 1; k < arr.length; k++) {\n if (identityOfY(arr.get(k)) === key) {\n found = k;\n break;\n }\n }\n if (found !== -1) {\n const moved = toPlain(arr.get(found));\n arr.delete(found, 1);\n arr.insert(j, [toY(moved)]);\n } else {\n arr.insert(j, [toY(next[j]!)]);\n }\n }\n}\n\n/** A collection of entities keyed by id: `doc.getMap(name)` → `{ [id]: Y.Map }`. */\nexport function getCollection(doc: Y.Doc, name: string): Y.Map<unknown> {\n return doc.getMap(name);\n}\n\n/** Read one entity as plain JSON, or null when absent/malformed. */\nexport function readEntity(collection: Y.Map<unknown>, id: string): Record<string, Json> | null {\n const entity = collection.get(id);\n if (!(entity instanceof Y.Map)) return null;\n const plain = toPlain(entity);\n return isPlainObject(plain) ? plain : null;\n}\n\n/**\n * Write one entity, mutating only what differs. Must run inside\n * `doc.transact(..., origin)` so the bridge can tell local writes from remote.\n */\nexport function writeEntity(collection: Y.Map<unknown>, id: string, entity: unknown): void {\n const next = normalize(entity);\n if (!isPlainObject(next)) return;\n const current = collection.get(id);\n if (!(current instanceof Y.Map)) {\n collection.set(id, toY(next));\n return;\n }\n applyToMap(current, next);\n}\n","/**\n * Les adresses auxquelles un service répond, par ordre de préférence.\n *\n * Partagé parce que deux surfaces posent la même question : l'en-tête de\n * service dans l'interface, qui les affiche toutes, et l'icône de barre\n * système, qui n'ouvre que la première. Écrire deux fois cet ordre de\n * préférence, c'est se donner deux endroits où « Ouvrir » peut mener ailleurs\n * que le bouton juste à côté.\n */\n\n/** D'où vient un lien — l'appelant s'en sert pour choisir une icône. */\nexport type ServiceLinkSource = 'cloud' | 'port' | 'custom';\n\nexport type ServiceLink = {\n url: string;\n source: ServiceLinkSource;\n};\n\ntype LinkableService = {\n /** Adresses publiques servies par le cloud, avec le port qu'elles couvrent. */\n localUrls?: { url: string; port: number }[] | undefined;\n ports?: number[] | undefined;\n url?: string | undefined;\n};\n\nconst LOOPBACK_HOSTNAMES = new Set(['localhost', '127.0.0.1', '::1', '[::1]']);\n\n/**\n * Ce qui fait que deux liens mènent au même endroit.\n *\n * Un slash final ne désigne pas une autre page, et `127.0.0.1` est un autre\n * nom pour `localhost` — l'« URL de base » peut redire ainsi ce qu'un port\n * produit déjà. En revanche une IP de LAN N'EST PAS ramenée à `localhost` :\n * l'une se joint depuis le réseau, l'autre seulement depuis cette machine, et\n * les confondre ferait disparaître un point d'accès.\n */\nfunction dedupeKey(url: string): string {\n const trimmed = url.trim().replace(/\\/+$/, '');\n try {\n const parsed = new URL(trimmed);\n if (LOOPBACK_HOSTNAMES.has(parsed.hostname)) parsed.hostname = 'localhost';\n return parsed.toString().replace(/\\/+$/, '');\n } catch {\n return trimmed;\n }\n}\n\n/**\n * @param host L'hôte auquel joindre les ports — `localhost`, ou l'adresse du\n * poste en mode réseau local. L'appelant seul sait laquelle il présente.\n */\nexport function serviceLinks(service: LinkableService, host: string): ServiceLink[] {\n // Un port déjà servi par une adresse publique ne mérite pas un second lien\n // vers la même chose en local.\n const served = new Set((service.localUrls ?? []).map((lu) => lu.port));\n\n const candidates: ServiceLink[] = [\n ...(service.localUrls ?? []).map((lu): ServiceLink => ({ url: `https://${lu.url}`, source: 'cloud' })),\n ...(service.ports ?? [])\n .filter((port) => !served.has(port))\n .map((port): ServiceLink => ({ url: `http://${host}:${port}`, source: 'port' })),\n ...(service.url ? [{ url: service.url, source: 'custom' as const }] : []),\n ];\n\n const seen = new Set<string>();\n return candidates.filter(({ url }) => {\n const key = dedupeKey(url);\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\n/** La première adresse d'un service, ou `null` s'il n'en expose aucune. */\nexport function primaryServiceLink(service: LinkableService, host: string): string | null {\n return serviceLinks(service, host)[0]?.url ?? null;\n}\n"],"mappings":"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","names":["z","z","z","z","z","z","z","z","clearable","z","z"]}
1
+ {"version":3,"sources":["../src/index.ts","../../ai-capabilities/src/capabilities.ts","../../ai-capabilities/src/adapters/json-schema.ts","../../ai-capabilities/src/adapters/anthropic.ts","../../ai-capabilities/src/adapters/openai.ts","../../ai-capabilities/src/adapters/prompt.ts","../../ai-capabilities/src/adapters/mcp.ts","../../ai-capabilities/src/trpc-caller.ts","../../ai-capabilities/src/project-anchor.ts","../../shared/src/schemas/user.schema.ts","../../shared/src/schemas/org.schema.ts","../../shared/src/schemas/project.schema.ts","../../shared/src/schemas/service.schema.ts","../../shared/src/schemas/settings.schema.ts","../../shared/src/schemas/scenario.schema.ts","../../shared/src/schemas/log-source.schema.ts","../../shared/src/schemas/process.schema.ts","../../shared/src/schemas/log.schema.ts","../../shared/src/schemas/agent.schema.ts","../../shared/src/schemas/permission.schema.ts","../../shared/src/schemas/sync.schema.ts","../../shared/src/schemas/audit.schema.ts","../../shared/src/schemas/metrics.schema.ts","../../shared/src/schemas/environment.schema.ts","../../shared/src/schemas/environment-overrides.schema.ts","../../shared/src/schemas/api-key.schema.ts","../../shared/src/schemas/image.schema.ts","../../shared/src/schemas/kanban.schema.ts","../../shared/src/schemas/cloud-api-key.schema.ts","../../shared/src/schemas/integration.schema.ts","../../shared/src/schemas/changelog.schema.ts","../../shared/src/utils/companion-markers.ts","../../shared/src/utils/launcher-identity.ts","../../shared/src/utils/log-source-secrets.ts","../../shared/src/utils/crypto.ts","../../shared/src/native-parsers.ts","../../shared/src/js-log-parser.ts","../../shared/src/builtins.ts","../../shared/src/constants/process-states.ts","../../shared/src/constants/log-levels.ts","../../shared/src/constants/roles.ts","../../shared/src/constants/intervals.ts","../../shared/src/constants/buffers.ts","../../shared/src/constants/timeouts.ts","../../shared/src/constants/editors.ts","../../shared/src/sync/json-crdt.ts","../../shared/src/utils/service-links.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport { RUNEYA_CAPABILITIES, applyProjectAnchor, buildMcpShape, runCapability, toRawParams } from '@runeya/packages-ai-capabilities';\n\nconst BASE_URL = process.env['RUNEYA_BASE_URL'] ?? 'http://localhost:4000';\nconst CONVERSATION_ID = process.env['RUNEYA_CONVERSATION_ID'] ?? '';\nconst INTERNAL_TOKEN = process.env['RUNEYA_INTERNAL_TOKEN'] ?? '';\nconst ENV_TOKEN = process.env['RUNEYA_API_TOKEN'] ?? '';\n// Le projet dans lequel Runeya a lancé ce CLI. Absent hors conversation\n// (un CLI démarré à la main), et alors rien n'est ancré.\nconst PROJECT_ANCHOR = {\n projectId: process.env['RUNEYA_PROJECT_ID'] || undefined,\n orgId: process.env['RUNEYA_ORG_ID'] || undefined,\n};\n\nconst server = new McpServer({ name: 'runeya', version: '1.0.0' });\n\n// ─── Register each capability as an MCP tool ─────────────────────────────────\n\nfor (const cap of RUNEYA_CAPABILITIES) {\n server.tool(cap.name, cap.description, buildMcpShape(cap), async (input) => {\n try {\n const rawParams = toRawParams(input as Record<string, unknown>, cap);\n const raw = rawParams['authToken'];\n const authToken = (raw && !raw.startsWith('$')) ? raw : (ENV_TOKEN || INTERNAL_TOKEN || undefined);\n if (!authToken) throw new Error('No auth token available');\n\n const params = applyProjectAnchor(cap, rawParams, PROJECT_ANCHOR);\n const result = await runCapability(cap, BASE_URL, params, authToken);\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: `Error: ${(err as Error).message}` }],\n isError: true,\n };\n }\n });\n}\n\n// ─── ask_user tool (scenario mode only) ─────────────────────────────────────\n\nif (CONVERSATION_ID && INTERNAL_TOKEN) {\n server.tool(\n 'ask_user',\n 'Ask the user a question and wait for their reply. Use this when you need clarification or input from the user to proceed.',\n { question: z.string().describe('The question to ask the user') },\n async ({ question }) => {\n try {\n const res = await fetch(`${BASE_URL}/api/trpc/scenario.requestInput`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${INTERNAL_TOKEN}`,\n },\n body: JSON.stringify({ conversationId: CONVERSATION_ID, question }),\n signal: AbortSignal.timeout(300_000), // 5 min\n });\n const json = await res.json() as Record<string, unknown>;\n const result = (json['result'] as Record<string, unknown> | undefined)?.['data'] ?? json;\n const text = typeof result === 'string' ? result : JSON.stringify(result);\n return { content: [{ type: 'text' as const, text }] };\n } catch (err) {\n return { content: [{ type: 'text' as const, text: `Error: ${(err as Error).message}` }], isError: true };\n }\n },\n );\n}\n\n// ─── Start the stdio transport ───────────────────────────────────────────────\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\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\nimport { z } from 'zod';\nimport {\n BootstrapCommandSchema, DockerConfigSchema, HealthCheckSchema, RestartStrategySchema,\n BUILTIN_VARIABLES, ServiceCommandSchema, ServiceConfigSchema, ServiceShortcutSchema, maskLogSourceSecrets,\n} from '@runeya/packages-shared';\nimport type { LogSourceConfig } from '@runeya/packages-shared';\n\nexport interface CapabilityParam {\n name: string;\n description: string;\n required: boolean;\n /**\n * Le type réel du paramètre. Absent : un texte. Présent, il est donné tel\n * quel au modèle (JSON Schema pour le chat, Zod pour le MCP) et relu contre\n * lui dans `buildInput`, qui reçoit toujours des chaînes.\n */\n schema?: z.ZodType;\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 * Filtre la réponse avant qu'elle n'atteigne le modèle — pour ce qu'une route\n * rend à l'interface et qu'une IA ne doit pas lire.\n */\n transformOutput?: (result: unknown) => unknown;\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\n/**\n * La cible d'une commande git : un service, ou à défaut un projet.\n *\n * Les quatre champs sont facultatifs côté route (`gitTargetShape`), qui résout\n * elle-même l'agent et le répertoire. On ne transmet que ce que le modèle a\n * réellement donné : un `serviceId` vide ferait échouer la résolution.\n */\nfunction gitTarget(p: Record<string, string | undefined>): Record<string, unknown> {\n return {\n ...(p.serviceId ? { serviceId: p.serviceId } : {}),\n ...(p.projectId ? { projectId: p.projectId } : {}),\n ...(p.agentId ? { agentId: p.agentId } : {}),\n ...(p.orgId ? { orgId: p.orgId } : {}),\n };\n}\n\nconst toBool = (raw: string) => raw.trim().toLowerCase() === 'true';\n\nconst newId = () => globalThis.crypto.randomUUID();\n\n/** Un élément de liste tel qu'un modèle l'énumère : `3000` est un nombre, `api` un texte. */\nfunction listItem(raw: string): unknown {\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return raw;\n }\n}\n\n/**\n * Lire un paramètre typé, arrivé en chaîne, contre son schéma.\n *\n * Dans l'ordre : la chaîne telle quelle (un texte), son JSON (un objet, un\n * nombre, `null`), puis une énumération à virgules (une liste). Le résultat est\n * la sortie du schéma, défauts compris. Une valeur refusée échoue avec le nom\n * du champ : l'agent sait quoi corriger au lieu de conclure le geste impossible.\n */\nfunction parseTyped(name: string, schema: z.ZodType, raw: string | undefined): unknown {\n if (raw === undefined) return undefined;\n // « null » efface quand le champ l'accepte, avant d'être lu comme le texte « null ».\n let result = raw.trim() === 'null' ? schema.safeParse(null) : schema.safeParse(raw);\n if (!result.success && raw.trim() === 'null') result = schema.safeParse(raw);\n if (!result.success) {\n const text = raw.trim();\n const json = listItem(text);\n if (json !== text) result = schema.safeParse(json);\n if (!result.success && !/^[[{]/.test(text)) {\n const list = schema.safeParse(toList(text).map(listItem));\n if (list.success) result = list;\n }\n }\n if (!result.success) throw new Error(`${name}: ${z.prettifyError(result.error)}`);\n return result.data;\n}\n\n/** Un id pour chaque élément qui n'en donne pas, comme l'interface le fait à l'ajout. */\nfunction withIds<T extends { id?: string }>(items: T[]): (T & { id: string })[] {\n return items.map((item) => ({ ...item, id: item.id || newId() }));\n}\n\nconst optionalId = <T extends z.ZodObject<{ id: z.ZodString }>>(schema: T) =>\n schema.extend({ id: z.string().min(1).max(64).optional() });\n\n/**\n * La configuration Docker, telle qu'un agent doit la donner pour que le\n * conteneur démarre : exactement une source d'image — `image` à tirer, ou un\n * `dockerfile` à construire. Le schéma partagé ne l'impose pas (l'interface\n * garde l'autre champ en mémoire pendant qu'on bascule), l'outil si.\n */\nconst DockerConfigInput = DockerConfigSchema.extend({\n bootstrapCommands: z.array(optionalId(BootstrapCommandSchema)).max(20).default([]),\n}).refine((c) => !!c.image !== !!c.dockerfile, {\n message: 'dockerConfig needs exactly one of \"image\" (an image to pull) or \"dockerfile\" (a Dockerfile to build)',\n});\n\ninterface ServiceField {\n name: string;\n description: string;\n /** Absent : un texte simple. */\n schema?: z.ZodType;\n /** `service.update` accepte `null` pour effacer ce champ. */\n clearable?: boolean;\n}\n\n/**\n * Chaque champ écrivable d'un service, typé par le schéma partagé\n * (`ServiceConfigSchema`). `capabilities-routes.test.ts` vérifie qu'il n'en\n * manque aucun de ceux que les routes acceptent.\n */\nconst SERVICE_FIELDS: ServiceField[] = [\n { name: 'description', description: 'What the service is, in a sentence' },\n { name: 'agentId', description: 'The agent that runs it, from list_agents. Omit to inherit from the environment.', clearable: true },\n { name: 'cwd', description: \"Working directory, RELATIVE to the project root (e.g. \\\"apps/web\\\", or omit for the root). The project is synced between machines and lives in a different folder on each: Runeya resolves a relative cwd against each machine's own project folder, while an absolute path (/home/you/…) breaks on every other machine. Use an absolute path only for something outside the project, written with ~ or an environment variable ($NAME) rather than a literal home directory.\", clearable: true },\n { name: 'command', description: 'Shortcut for a single command line (e.g. \"npm run dev\"). Replaces every existing command. Use commands for several.' },\n { name: 'commands', description: 'The processes of the service. They all start AT THE SAME TIME, in parallel, and the service runs while they run — not one after another. Use several for processes that live side by side (a web server and a worker). Steps that must follow each other (build, then install, then launch) go in ONE command chained with &&. A one-off action the user triggers by hand (build, deploy, read logs) is a shortcut, not a command. Each command runs in the service cwd, or its own \"cwd\", relative to the project root. No absolute paths of this machine: the service is synced to other machines. Replaces every existing command. \"id\" is generated when omitted; \"shell\" runs the line through a shell (default true).', schema: z.array(optionalId(ServiceCommandSchema)).max(50) },\n { name: 'ports', description: 'Ports the service listens on. Declare them: they become {{service.PORT}}, {{service.URL}} and {{services.<slug>.URL}} for the other services, which environment variables should reference instead of repeating the numbers.', schema: ServiceConfigSchema.shape.ports.unwrap().unwrap() },\n { name: 'groups', description: 'Groups the service belongs to. Replaces the current ones.', schema: ServiceConfigSchema.shape.groups.unwrap().unwrap() },\n { name: 'url', description: 'URL where the service is reached' },\n { name: 'localUrls', description: 'Local domain names routed to a port of the service (e.g. {\"url\":\"api.localhost.dev\",\"port\":3000})', schema: ServiceConfigSchema.shape.localUrls.unwrap().unwrap() },\n { name: 'openapiUrl', description: 'URL of its OpenAPI document' },\n { name: 'docsPath', description: \"Where its markdown docs live, relative to cwd or absolute. Defaults to cwd.\" },\n { name: 'git', description: 'Its git repository: \"remote\" URL and \"home\" page', schema: ServiceConfigSchema.shape.git.unwrap(), clearable: true },\n { name: 'meta', description: 'Free key/value metadata (strings)', schema: ServiceConfigSchema.shape.meta.unwrap(), clearable: true },\n { name: 'runner', description: '\"native\" runs the commands on the machine; \"docker\" runs the service in a container and then needs dockerConfig', schema: ServiceConfigSchema.shape.runner.unwrap().unwrap() },\n { name: 'dockerConfig', description: 'With runner \"docker\": the container. Exactly one of \"image\" (pull) or \"dockerfile\" (inline Dockerfile, built with \"buildContext\", \"buildArgs\", \"targetStage\"). Ports and volumes use Docker syntax (\"8080:80\", \"./data:/data\"); host paths in volumes relative to the service directory, never an absolute path of this machine. \"useNativeCommand\" runs the service commands inside the container instead of its CMD (\"nativeCommandMode\": one shared container or one per command). \"bootstrapCommands\" run once when the container starts. Replaces the whole Docker configuration: read it first with get_service to keep what you do not change.', schema: DockerConfigInput },\n { name: 'healthCheck', description: 'How to tell the service is ready: an HTTP \"path\" to call, or a \"command\" that must succeed', schema: HealthCheckSchema, clearable: true },\n { name: 'autoRestart', description: 'Restart the service when it crashes', schema: z.boolean() },\n { name: 'restartStrategy', description: 'When to restart it', schema: RestartStrategySchema.unwrap() },\n { name: 'maxRestarts', description: 'Give up after this many restarts', schema: ServiceConfigSchema.shape.maxRestarts.unwrap() },\n { name: 'restartBackoffMs', description: 'Delay before a restart, in milliseconds', schema: ServiceConfigSchema.shape.restartBackoffMs.unwrap().unwrap() },\n { name: 'clearLogsOnStart', description: 'Clear the logs each time the service starts', schema: z.boolean() },\n { name: 'shortcuts', description: 'One-click actions shown on the service, run on demand and independently of the running commands (build, deploy, migrate, read logs). Same path rules as commands: relative to the project root, never an absolute path of this machine. Replaces the current ones. \"id\" is generated when omitted.', schema: z.array(optionalId(ServiceShortcutSchema)).max(50) },\n { name: 'parserIds', description: 'Log parsers applied to its output, by id', schema: ServiceConfigSchema.shape.parserIds.unwrap() },\n { name: 'logSources', description: 'Extra log sources beyond the console output (files, databases…). Replaces the current ones. Credentials (mongo connectionString, mysql password) read as \"***\": send \"***\" back to keep the stored value, or the real value to change it.', schema: ServiceConfigSchema.shape.logSources.unwrap().unwrap() },\n];\n\nfunction serviceParams(clearable: boolean): CapabilityParam[] {\n return SERVICE_FIELDS.map((f) => {\n const nullable = clearable && f.clearable;\n const base = f.schema ?? (nullable ? z.string() : undefined);\n return {\n name: f.name,\n description: nullable ? `${f.description} null clears it.` : f.description,\n required: false,\n ...(base ? { schema: nullable ? base.nullable() : base } : {}),\n };\n });\n}\n\nfunction serviceFields(p: Record<string, string | undefined>, params: CapabilityParam[]): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const param of params) {\n if (p[param.name] === undefined || param.name === 'command') continue;\n out[param.name] = param.schema ? parseTyped(param.name, param.schema, p[param.name]) : p[param.name];\n }\n if (p.command !== undefined && p.commands === undefined) out['commands'] = [{ label: '', command: p.command, shell: true }];\n if (Array.isArray(out['commands'])) out['commands'] = withIds(out['commands'] as { id?: string }[]);\n if (Array.isArray(out['shortcuts'])) out['shortcuts'] = withIds(out['shortcuts'] as { id?: string }[]);\n const docker = out['dockerConfig'] as { bootstrapCommands?: { id?: string }[] } | undefined;\n if (docker?.bootstrapCommands) out['dockerConfig'] = { ...docker, bootstrapCommands: withIds(docker.bootstrapCommands) };\n return out;\n}\n\n/**\n * Un service, ou une liste de services, tels qu'une IA peut les lire : les\n * identifiants de leurs sources de logs masqués. `service.get` les rend en clair\n * parce que l'interface les édite ; `update_service` accepte le masque en retour\n * et garde la valeur en place (`restoreLogSourceSecrets`).\n */\nfunction maskServices(result: unknown): unknown {\n if (Array.isArray(result)) return result.map(maskServices);\n if (result && typeof result === 'object' && Array.isArray((result as { logSources?: unknown }).logSources)) {\n const service = result as { logSources: LogSourceConfig[] };\n return { ...service, logSources: maskLogSourceSecrets(service.logSources) };\n }\n return result;\n}\n\n/**\n * Les variables intégrées, telles qu'un modèle doit les connaître pour composer\n * une valeur : tirées de `BUILTIN_VARIABLES`, la seule déclaration, pour qu'un\n * ajout y parvienne sans que personne pense à la description.\n */\nconst refs = (scope: 'server' | 'agent') => BUILTIN_VARIABLES\n .filter((b) => b.scope === scope)\n .map((b) => `{{${b.name}}}`)\n .join(', ');\nconst BUILTINS_HELP = `Built-in references Runeya fills itself — filled when the service is deployed, from the service that receives the variable: ${refs('server')}, the numbered {{service.PORT_2}} / {{service.URL_2}}… for its other ports, and {{services.<slug>.PORT}}, .URL, .BASE_URL, .NAME, .ID for a sibling service of the project (slug = its name in lowercase-dashes). Filled on the machine when the service starts: ${refs('agent')}.`;\n\nconst CREATE_SERVICE_PARAMS = serviceParams(false);\nconst UPDATE_SERVICE_PARAMS = serviceParams(true);\n\nexport const RUNEYA_CAPABILITIES: RuneyaCapability[] = [\n {\n name: 'list_services',\n transformOutput: maskServices,\n description: \"List services, with the serviceId and agentId to use in other calls. Pass the projectId your context names to stay on the project the user is looking at, or another one from list_projects to look elsewhere. Called with no project, this can answer for every project of every organization on the machine — far more than the interface shows.\",\n route: 'service.list',\n method: 'GET',\n params: [\n { name: 'projectId', description: 'Restrict to this project, from list_projects. Omit to list every service on the machine.', required: false },\n { name: 'orgId', description: 'Its organization. Needed only when the same project id exists in several.', required: false },\n ],\n buildInput: (p) => (p.projectId\n ? { projectId: p.projectId, ...(p.orgId ? { orgId: p.orgId } : {}) }\n : undefined),\n },\n {\n name: 'get_service_status',\n description: \"Get the current status (running, stopped, etc.) of a service. A service that has never been started on this agent has no process yet, and this answers 404 Process not found — that means STOPPED, not forbidden and not missing. Start it, or read its configuration with get_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, comments and the support conversations they follow (title, messages, internal notes, and the names of message authors) — accent- and case-insensitive. Archived cards are included. Searches every board of the organization unless boardId narrows it down. createdBy narrows to the cards someone created (\"les cartes créées par Isabelle\"), alone or with a query.',\n route: 'kanban.searchCards',\n method: 'GET',\n params: [\n { name: 'query', description: 'Text to look for in card titles, bodies, comments and followed conversations. Optional when createdBy is given.', required: false },\n { name: 'createdBy', description: 'Only cards created by this author: a user id, or a name (accent- and case-insensitive, partial match).', required: false },\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 ...(p.query ? { query: p.query } : {}),\n ...(p.createdBy ? { createdBy: p.createdBy } : {}),\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 { name: 'organizationId', description: 'Which organization the attachment belongs to. Optional: needed only when the account belongs to several and the error message asks for it.', required: false },\n ],\n buildInput: (p) => ({\n attachmentId: p.attachmentId,\n ...(p.organizationId ? { orgId: p.organizationId } : {}),\n }),\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_conversations',\n description: 'Read the customer support conversations (Intercom…) linked to one kanban card: for each, its title, provider, state (open/resolved), link, the opening message and the thread of messages (author name, customer or team, internal note or not, date, text, attached files — fetch their bytes with kanban_download_attachment), plus the other cards following the same conversation. These messages are NOT comments of the card — read them here.',\n route: 'kanban.getCardConversations',\n method: 'GET',\n params: [\n { name: 'boardId', description: 'The kanban board ID', required: true },\n { name: 'cardId', description: 'The card ID whose conversations to read', required: true },\n { name: 'limit', description: 'How many of the most recent messages to return per conversation (1-500). Default: 100.', required: false },\n ],\n buildInput: (p) => ({\n boardId: p.boardId,\n cardId: p.cardId,\n ...(p.limit ? { limit: Number(p.limit) } : {}),\n }),\n usageHint: '\"regarde la conversation Intercom de la carte\" / \"qu\\'a dit le client\" → kanban_get_card_conversations(boardId, cardId).',\n },\n {\n name: 'kanban_search_conversations',\n description: \"Search customer support conversations (Intercom…) at the providers connected to the board's organization, by words of the conversation title, or by conversation number or URL. Read-only at the provider. Each result gives connectionId and externalId (needed to link it), title, state, a preview and the cards already following it.\",\n route: 'kanban.searchConversations',\n method: 'GET',\n params: [\n { name: 'boardId', description: 'Any kanban board ID of the organization to search in', required: true },\n { name: 'query', description: 'Words of the conversation title, a conversation number, or a conversation URL', required: true },\n ],\n buildInput: (p) => ({ boardId: p.boardId, query: p.query }),\n },\n {\n name: 'kanban_link_conversation',\n description: 'Link a customer support conversation found with kanban_search_conversations to a kanban card. Its whole thread is imported and new messages keep arriving on the card. A conversation can be linked to several cards. Nothing is written at the provider.',\n route: 'kanban.linkConversation',\n method: 'POST',\n params: [\n { name: 'boardId', description: 'The kanban board ID of the card', required: true },\n { name: 'cardId', description: 'The card to link the conversation to', required: true },\n { name: 'connectionId', description: 'The connectionId of the search result', required: true },\n { name: 'externalId', description: 'The externalId of the search result', required: true },\n ],\n buildInput: (p) => ({ boardId: p.boardId, cardId: p.cardId, connectionId: p.connectionId, externalId: p.externalId }),\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 // ─── Lecture seule ───────────────────────────────────────────────────────\n //\n // Tout ce qui se consulte sans rien changer. Les écritures s'ajoutent au cas\n // par cas : aujourd'hui les services et leurs variables, plus bas.\n //\n // Volontairement absentes, et à ne pas ajouter sans y regarder à deux fois,\n // parce qu'elles rendent un secret : `environment.list` / `get` / `resolve` /\n // `resolveFlat` (un `Environment` porte ses variables, valeurs comprises),\n // `apiKeys.list` / `reveal`, `setup.getEncryptionKeyHex` et `getOrgKeys`\n // (clés de chiffrement), `settings.get` et `settings.listAIProviders` (clés\n // de fournisseurs d'IA — `settings.getPaths` et `getNetwork`, eux, ne\n // rendent que des chemins et une adresse, d'où leur présence ci-dessous),\n // `cloudAuth.session`, `agent.getPassthroughEnv`. Un agent n'a pas besoin de\n // ces valeurs pour travailler, et ce qu'il lit finit dans une transcription.\n //\n // La seule exception est `service.getEnv` (`get_service_env` ci-dessous),\n // et elle n'en est une que parce qu'elle filtre : les variables publiques, et\n // les seuls secrets que leur auteur a partagés avec les IA (`isSharedWithAi`\n // — « Lisible par l'IA », ou l'injection, qui vaut la lecture). Un secret non\n // partagé n'y apparaît pas, pas même par son nom.\n {\n name: 'list_processes',\n description: \"List every process across all agents with its current state (running, stopped, exit code, uptime). Use this to see the whole machine at once, rather than calling get_service_status service by service. An agent only learns about a service when it is first started, so this lists what is deployed, not what is configured: an empty list means nothing has been started, not that you cannot see them — list_services shows what exists.\",\n route: 'process.list',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'get_service',\n transformOutput: maskServices,\n description: 'Read the full configuration of one service: its commands, ports, groups, runner, log sources and restart policy. list_services gives the ids.',\n route: 'service.get',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'The service ID', required: true },\n ],\n buildInput: (p) => ({ id: p.serviceId }),\n },\n {\n name: 'get_service_env',\n description: \"Read the environment variables a service runs with, and the project's variable inventory. `env` lists every key the service receives; a value reads \\\"***\\\" when it is a secret whose author did not share it with AI (sharing = ticking \\\"AI read\\\", or injecting it into the agents\\u0027 environment, which grants reading too). `envSecrets` says which keys are secret, `hiddenKeys` which ones are masked. A masked key is set on the service: never treat it as missing, never suggest adding it, and never pass \\\"***\\\" as a value — ask the user for it. `variables` describes every variable of the project — which environment defines it and its scope, its description, its flags, whether this machine overrides it, and `inService: false` for the ones this service does not receive. Use it to say where a variable must be changed instead of guessing. On an overridden variable, `sharedValue` is what the machine-local override replaces (the team's value, masked as \\\"***\\\" when unreadable); no other value appears there. This is the resolver: the values are what the service would receive — inheritance, {{environment.KEY}} references, this machine's overrides and server built-ins applied; agent built-ins stay as written until the service starts. Use it to check a variable you just composed. `unresolvedReferences` lists references nothing will fill (a typo, a variable that does not exist): fix them.\",\n route: 'service.getEnv',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'The service ID', required: true },\n { name: 'environmentId', description: 'A global environment of the project to resolve in instead of the active one, without activating it (from list_environments). Omit for the active one.', required: false },\n ],\n buildInput: (p) => ({ id: p.serviceId, ...(p.environmentId ? { environmentId: p.environmentId } : {}) }),\n },\n // ─── Écrire un service et ses variables ────────────────────────────────────\n //\n // Les variables s'écrivent à l'aveugle (`environment.setVariableBlind`) : une\n // IA remplace la valeur d'un secret sans la lire, et ne peut ni le rendre\n // public, ni le partager avec les IA. La règle tient côté serveur, dans la\n // route ; ces outils ne passent jamais par une route qui renvoie des valeurs\n // (`upsertVariable`, `removeVariable`, `update` rendent l'environnement entier).\n {\n name: 'create_service',\n transformOutput: maskServices,\n description: \"Create a service, native or Docker, in a project: it joins the project and gets its environments in the same call. Pass the projectId your context names. Projects are synced between machines, so write paths relative to the project root and put machine-specific values (a device serial, a local token) in environment variables, referenced as $NAME in commands — see the cwd, commands and shortcuts parameters. Then set its variables with set_environment_variable.\",\n route: 'service.create',\n method: 'POST',\n params: [\n { name: 'name', description: 'The service name', required: true },\n { name: 'projectId', description: 'The project it joins: the one your context names, or another from list_projects. Without it, the service belongs to no project.', required: false },\n { name: 'orgId', description: 'Its organization. Needed only when the same project id exists in several.', required: false },\n ...CREATE_SERVICE_PARAMS,\n ],\n buildInput: (p) => {\n const fields = serviceFields(p, CREATE_SERVICE_PARAMS);\n if (fields['runner'] === 'docker' && !fields['dockerConfig']) {\n throw new Error('dockerConfig: required with runner \"docker\" — give an \"image\" or a \"dockerfile\"');\n }\n return {\n name: p.name,\n ...fields,\n ...(p.projectId ? { projectId: p.projectId } : {}),\n ...(p.orgId ? { orgId: p.orgId } : {}),\n };\n },\n },\n {\n name: 'add_service_to_project',\n description: \"Add an existing service to a project, and create its environments — one for each of the project's environments, where its own variables go. Not needed after create_service, which already does it; calling it again changes nothing.\",\n route: 'project.addService',\n method: 'POST',\n params: [\n { name: 'projectId', description: 'The project ID, from list_projects', required: true },\n { name: 'serviceId', description: 'The service ID', required: true },\n { name: 'orgId', description: 'Its organization. Needed only when the same project id exists in several.', required: false },\n ],\n buildInput: (p) => ({ projectId: p.projectId, serviceId: p.serviceId, ...(p.orgId ? { orgId: p.orgId } : {}) }),\n },\n {\n name: 'update_service',\n transformOutput: maskServices,\n description: 'Change any part of a service configuration — commands, ports, health check, restart policy, shortcuts, log sources, whether it runs natively or in Docker (runner, dockerConfig)… Only the fields you pass change; a list or an object you pass replaces the current one whole. Read the service first with get_service.',\n route: 'service.update',\n method: 'POST',\n params: [\n { name: 'serviceId', description: 'The service ID', required: true },\n { name: 'name', description: 'New name', required: false },\n { name: 'orgId', description: 'Move the service to this organization vault. Leave unset unless asked.', required: false, schema: z.string().max(128).nullable() },\n ...UPDATE_SERVICE_PARAMS,\n ],\n buildInput: (p) => ({\n id: p.serviceId,\n ...(p.name ? { name: p.name } : {}),\n ...(p.orgId !== undefined ? { orgId: parseTyped('orgId', z.string().max(128).nullable(), p.orgId) } : {}),\n ...serviceFields(p, UPDATE_SERVICE_PARAMS),\n }),\n },\n {\n name: 'list_environments',\n description: \"List the environments of a project, with no value: each one's id, name and scope (global = shared by the whole project, service = one service's own variables), which global environment is active, which service a service environment belongs to and which global environment activates it, its parents (it inherits their variables), `isolated` when a service environment does not inherit from its global one, and the variables it defines with their flags. Empty environments are listed too — a service you just created has one per global environment, where its own variables go. Use it to find the environmentId before set_environment_variable.\",\n route: 'environment.listForAi',\n method: 'GET',\n params: [\n { name: 'projectId', description: 'The project ID: the one your context names, or another from list_projects', required: true },\n { name: 'orgId', description: 'Its organization. Needed only when the same project id exists in several.', required: false },\n ],\n buildInput: (p) => ({ projectId: p.projectId, ...(p.orgId ? { orgId: p.orgId } : {}) }),\n },\n {\n name: 'resolve_environment',\n description: \"Resolve one environment alone — its variables with those inherited from its parents and this machine's overrides — as an AI may read it: secrets not shared with AI read \\\"***\\\". Built-in references ({{service.*}}, {{services.*}}, {{agent.*}}…) are NOT filled, since they depend on the service that receives the variable; use get_service_env for a service's final values. `unresolvedReferences` lists references nothing will fill: a misspelled {{environment.KEY}}, or a name that is no built-in.\",\n route: 'environment.resolveForAi',\n method: 'GET',\n params: [\n { name: 'environmentId', description: 'The environment, from list_environments', required: true },\n ],\n buildInput: (p) => ({ environmentId: p.environmentId }),\n },\n {\n name: 'set_environment_variable',\n description: `Create or change an environment variable, by name, in one environment — global or service, same rules for both. Find the environmentId with list_environments. Where it belongs: a value shared by several services (a database host, an API base URL) goes ONCE in the active global environment; services inherit it. A value only one service needs goes in that service's environment (scope service, activated by the active global one), where it also overrides a global variable of the same name. Never hardcode what Runeya already knows: a service's own port is {{service.PORT}}, its own URL {{service.URL}}, another service's address {{services.<slug>.URL}} — a copied \"3210\" or \"http://localhost:3211\" breaks as soon as a port changes or the project runs on another machine. If the port a variable needs is not declared on its service, declare it there (update_service, ports) instead of writing the number. When a written value contains a port or URL of a project service, the response lists \\`suggestions\\`: rewrite the value with those references. Compose instead of copying: a value can reference another variable of the resolved environment as {{environment.KEY}} (e.g. \"postgres://{{environment.DB_USER}}@{{environment.DB_HOST}}:5432\"). ${BUILTINS_HELP} After writing, check the result with get_service_env (a service, optionally in another global environment) or resolve_environment (an environment alone). References are substituted in one pass: a reference to a variable whose own value is only a reference may stay unexpanded, so point at the variable that holds the actual value. $NAME is not a reference here: it only expands inside a shell command. pre and post are concatenated around the value, each resolved separately. You can replace a secret's value without reading it, and create a variable as secret. You cannot make a secret public nor make it readable by AI: that stays the user's decision. Never pass \"***\" as a value. The response never contains the value.`,\n route: 'environment.setVariableBlind',\n method: 'POST',\n params: [\n { name: 'environmentId', description: 'The environment that holds the variable, from list_environments', required: true },\n { name: 'key', description: 'The variable name, e.g. DATABASE_URL', required: true },\n { name: 'value', description: 'The new value, possibly with {{environment.KEY}} references. Omit to leave it unchanged.', required: false },\n { name: 'pre', description: 'Text put before the value (e.g. \"https://\"). Omit to leave it unchanged.', required: false },\n { name: 'post', description: 'Text put after the value (e.g. \"/api\"). Omit to leave it unchanged.', required: false },\n { name: 'isSecret', description: '\"true\" to store it as a secret. On an existing public variable, makes it secret.', required: false },\n { name: 'description', description: 'What the variable is for, in markdown', required: false },\n ],\n buildInput: (p) => ({\n environmentId: p.environmentId,\n key: p.key,\n ...(p.value !== undefined ? { value: p.value } : {}),\n ...(p.pre !== undefined ? { pre: p.pre } : {}),\n ...(p.post !== undefined ? { post: p.post } : {}),\n ...(p.isSecret !== undefined ? { isSecret: toBool(p.isSecret) } : {}),\n ...(p.description !== undefined ? { description: p.description } : {}),\n }),\n },\n {\n name: 'set_environment_inheritance',\n description: \"Switch whether a service environment inherits the variables of the global environment that activates it (the default), or is isolated from it and receives only its own variables. list_environments shows this as `isolated`. Isolating a service is unusual: it loses every shared variable of the project. Do it only when the user asks, and never to work around a variable — override it in the service environment instead.\",\n route: 'environment.setInheritanceBlind',\n method: 'POST',\n params: [\n { name: 'environmentId', description: 'A service environment (scope service), from list_environments', required: true },\n { name: 'inherit', description: '\"true\" to inherit from the global environment, \"false\" to isolate', required: true, schema: z.boolean() },\n ],\n buildInput: (p) => ({ environmentId: p.environmentId, inherit: toBool(p.inherit ?? 'true') }),\n },\n {\n name: 'remove_environment_variable',\n description: 'Delete an environment variable, by name, from one environment. Its value is lost.',\n route: 'environment.removeVariableBlind',\n method: 'POST',\n params: [\n { name: 'environmentId', description: 'The environment that holds the variable', required: true },\n { name: 'key', description: 'The variable name', required: true },\n ],\n buildInput: (p) => ({ environmentId: p.environmentId, key: p.key }),\n destructive: true,\n },\n {\n name: 'get_service_metrics',\n description: 'Read the CPU and memory currently used by a running service.',\n route: 'process.metrics',\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: 'list_agents',\n description: 'List the agents connected to this Runeya, with their status and whether they run on this machine. Passphrases are never returned.',\n route: 'agent.list',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'list_projects',\n description: 'List the projects known to this Runeya, with their ids and the services they hold.',\n route: 'project.list',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'get_project',\n description: 'Read one project: its services, its active environment, its organization.',\n route: 'project.get',\n method: 'GET',\n params: [\n { name: 'projectId', description: 'The project ID, from list_projects', required: true },\n { name: 'orgId', description: 'Its organization. Needed only when the same project id exists in several.', required: false },\n ],\n buildInput: (p) => ({ id: p.projectId, ...(p.orgId ? { orgId: p.orgId } : {}) }),\n },\n {\n name: 'list_project_paths',\n description: 'Where each project lives on this machine. Use it to find the directory to work in before reading or editing files.',\n route: 'project.localPaths',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'git_status',\n description: 'Read the git working tree of a service or a project: staged, modified and untracked files, current branch, ahead/behind counts.',\n route: 'git.status',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'Target the repository of this service', required: false },\n { name: 'projectId', description: 'Target the repository of this project, when no service is given', required: false },\n { name: 'agentId', description: 'The agent hosting the repository', required: false },\n { name: 'orgId', description: 'Its organization, when a project id alone is ambiguous', required: false },\n ],\n buildInput: (p) => gitTarget(p),\n },\n {\n name: 'git_log',\n description: 'Read the recent commits of a service or project repository: hash, author, date, message.',\n route: 'git.log',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'Target the repository of this service', required: false },\n { name: 'projectId', description: 'Target the repository of this project, when no service is given', required: false },\n { name: 'agentId', description: 'The agent hosting the repository', required: false },\n { name: 'orgId', description: 'Its organization, when a project id alone is ambiguous', required: false },\n { name: 'limit', description: 'How many commits to return (1-200). Default: 50.', required: false },\n ],\n buildInput: (p) => ({ ...gitTarget(p), ...(p.limit ? { limit: Number(p.limit) } : {}) }),\n },\n {\n name: 'git_branches',\n description: 'List the local and remote branches of a service or project repository.',\n route: 'git.branches',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'Target the repository of this service', required: false },\n { name: 'projectId', description: 'Target the repository of this project, when no service is given', required: false },\n { name: 'agentId', description: 'The agent hosting the repository', required: false },\n { name: 'orgId', description: 'Its organization, when a project id alone is ambiguous', required: false },\n ],\n buildInput: (p) => gitTarget(p),\n },\n {\n name: 'git_diff',\n description: 'Read the diff of a service or project repository — everything, or one file. Use it to see what changed before describing or reviewing it.',\n route: 'git.diff',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'Target the repository of this service', required: false },\n { name: 'projectId', description: 'Target the repository of this project, when no service is given', required: false },\n { name: 'agentId', description: 'The agent hosting the repository', required: false },\n { name: 'orgId', description: 'Its organization, when a project id alone is ambiguous', required: false },\n { name: 'path', description: 'Restrict the diff to this file path', required: false },\n { name: 'staged', description: 'Set to \"true\" to read the staged diff instead of the working tree', required: false },\n { name: 'untracked', description: 'Set to \"true\" to include untracked files', required: false },\n ],\n buildInput: (p) => ({\n ...gitTarget(p),\n ...(p.path ? { path: p.path } : {}),\n ...(p.staged !== undefined ? { staged: p.staged === 'true' } : {}),\n ...(p.untracked !== undefined ? { untracked: p.untracked === 'true' } : {}),\n }),\n },\n {\n name: 'list_docs',\n description: 'List the markdown documentation files of a scope, as a tree. Pair it with read_doc to answer from the project\\'s own docs rather than from guesswork.',\n route: 'wiki.list',\n method: 'GET',\n params: [\n { name: 'scope', description: '\"global\" for this Runeya, or \"service:<serviceId>\" for one service\\'s repository', required: true },\n ],\n buildInput: (p) => ({ scope: p.scope }),\n },\n {\n name: 'read_doc',\n description: 'Read one markdown documentation file. Paths come from list_docs; only .md and .markdown can be read.',\n route: 'wiki.read',\n method: 'GET',\n params: [\n { name: 'scope', description: '\"global\" for this Runeya, or \"service:<serviceId>\" for one service\\'s repository', required: true },\n { name: 'path', description: 'Relative path of the file, as returned by list_docs', required: true },\n ],\n buildInput: (p) => ({ scope: p.scope, path: p.path }),\n },\n {\n name: 'get_server_logs',\n description: \"Read Runeya's own recent log entries. Use it to explain why Runeya itself misbehaved — not to read a service's output, which is get_logs.\",\n route: 'diagnostics.recentLogs',\n method: 'GET',\n params: [\n { name: 'limit', description: 'How many entries to return (1-2000). Default: 500.', required: false },\n ],\n buildInput: (p) => (p.limit ? { limit: Number(p.limit) } : undefined),\n },\n {\n name: 'get_kanban_queue_state',\n description: 'Read the state of the kanban task queue: what is running, what is waiting. Use it before queuing work, or to explain why a card has not started.',\n route: 'kanbanQueue.getState',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'export_project',\n description: \"Read a project and every service it holds in one call, with secrets stripped out. Cheaper and safer than calling get_service for each service — prefer it whenever you need the whole picture of a project.\",\n route: 'project.export',\n method: 'GET',\n params: [\n { name: 'projectId', description: 'The project ID, from list_projects', required: true },\n { name: 'orgId', description: 'Its organization. Needed only when the same project id exists in several.', required: false },\n ],\n buildInput: (p) => ({ id: p.projectId, ...(p.orgId ? { orgId: p.orgId } : {}) }),\n },\n {\n name: 'git_remotes',\n description: 'List the git remotes of a service or project repository, with their URLs.',\n route: 'git.remotes',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'Target the repository of this service', required: false },\n { name: 'projectId', description: 'Target the repository of this project, when no service is given', required: false },\n { name: 'agentId', description: 'The agent hosting the repository', required: false },\n { name: 'orgId', description: 'Its organization, when a project id alone is ambiguous', required: false },\n ],\n buildInput: (p) => gitTarget(p),\n },\n {\n name: 'git_stash_list',\n description: 'List the stashes of a service or project repository. Useful before assuming work was lost: it may simply be stashed.',\n route: 'git.stashList',\n method: 'GET',\n params: [\n { name: 'serviceId', description: 'Target the repository of this service', required: false },\n { name: 'projectId', description: 'Target the repository of this project, when no service is given', required: false },\n { name: 'agentId', description: 'The agent hosting the repository', required: false },\n { name: 'orgId', description: 'Its organization, when a project id alone is ambiguous', required: false },\n ],\n buildInput: (p) => gitTarget(p),\n },\n {\n name: 'get_runeya_version',\n description: 'Read the version of Runeya running here, the latest published one, and whether this install is up to date. Use it before blaming a bug on the code: the machine may simply be behind.',\n route: 'health.versionInfo',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'get_runeya_paths',\n description: \"Read where Runeya keeps its things on this machine: its launch directory, its data directory, and the machine-wide directory holding cloud projects.\",\n route: 'settings.getPaths',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'get_network_info',\n description: 'Read where this Runeya listens (host and port) and whether it is reachable from the local network, with the URLs to use. Use it to give someone a working link instead of guessing one.',\n route: 'settings.getNetwork',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'list_runeya_instances',\n description: 'List every Runeya answering on this machine, this one included, with its port and directory. Use it when a port is taken or when two instances seem to disagree.',\n route: 'diagnostics.instances',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n {\n name: 'get_cloud_status',\n description: 'Say whether this Runeya is linked to a cloud account, and to which cloud. A kanban tool failing for lack of a cloud link is explained here.',\n route: 'cloudAuth.status',\n method: 'GET',\n params: [],\n buildInput: () => undefined,\n },\n];\n","import { z } from 'zod';\nimport type { CapabilityParam } from '../capabilities.js';\n\n/** La propriété JSON Schema d'un paramètre : son schéma réel s'il en a un, une chaîne sinon. */\nexport function paramJsonSchema(param: CapabilityParam): Record<string, unknown> {\n if (!param.schema) return { type: 'string', description: param.description };\n const { $schema: _ignored, ...schema } = z.toJSONSchema(param.schema, { io: 'input', unrepresentable: 'any' }) as Record<string, unknown>;\n return { ...schema, description: param.description };\n}\n","import type { RuneyaCapability } from '../capabilities.js';\nimport { paramJsonSchema } from './json-schema.js';\n\nexport interface AnthropicTool {\n name: string;\n description: string;\n input_schema: {\n type: 'object';\n properties: Record<string, Record<string, unknown>>;\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, paramJsonSchema(p)]),\n ),\n required: cap.params.filter(p => p.required).map(p => p.name),\n },\n }));\n}\n","import type { RuneyaCapability } from '../capabilities.js';\nimport { paramJsonSchema } from './json-schema.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, Record<string, unknown>>;\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, paramJsonSchema(p)]),\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","import { z } from 'zod';\nimport type { RuneyaCapability } from '../capabilities.js';\n\n/**\n * Le schéma d'entrée d'un outil MCP : le schéma réel de chaque paramètre typé,\n * une chaîne pour les autres. Le client MCP le transmet au modèle tel quel,\n * types, énumérations et valeurs par défaut compris.\n */\nexport function buildMcpShape(cap: RuneyaCapability): Record<string, z.ZodType> {\n const shape: Record<string, z.ZodType> = {};\n for (const param of cap.params) {\n const base = (param.schema ?? z.string()).describe(param.description);\n shape[param.name] = param.required ? base : base.optional();\n }\n // authToken is MCP-specific: CLI runners pass the JWT here\n shape['authToken'] = z.string().describe('Bearer token for authentication').optional();\n return shape;\n}\n\n/**\n * Ce qu'un modèle envoie, ramené aux chaînes que `buildInput` lit : un objet ou\n * une liste en JSON, un nombre ou un booléen en texte. Les paramètres typés\n * sont relus contre leur schéma dans `buildInput` ; passer la capacité garde le\n * `null` qui les efface.\n */\nexport function toRawParams(input: Record<string, unknown>, cap?: RuneyaCapability): Record<string, string | undefined> {\n // `null` sur un paramètre typé efface le champ ; sur un texte, il vaut absence.\n const typed = new Set(cap?.params.filter((p) => p.schema).map((p) => p.name));\n return Object.fromEntries(Object.entries(input).map(([k, v]) => [\n k,\n v === null && typed.has(k) ? 'null'\n : v == null ? undefined\n : typeof v === 'object' ? JSON.stringify(v) : String(v as string | number | boolean | bigint),\n ]));\n}\n","import type { RuneyaCapability } from './capabilities.js';\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 fetchImpl: typeof fetch = fetch,\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 fetchImpl(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\n/**\n * Exécuter une capacité : l'appel tRPC, puis le filtre de sa réponse. Le seul\n * chemin du MCP comme du chat intégré — un filtre posé sur la capacité vaut\n * donc pour les deux.\n */\nexport async function runCapability(\n cap: RuneyaCapability,\n baseUrl: string,\n params: Record<string, string | undefined>,\n authToken: string,\n fetchImpl: typeof fetch = fetch,\n): Promise<unknown> {\n const result = await callTrpc(baseUrl, cap.route, cap.method, cap.buildInput(params), authToken, fetchImpl);\n return cap.transformOutput ? cap.transformOutput(result) : result;\n}\n","import type { RuneyaCapability } from './capabilities.js';\n\n/** Le projet de la conversation : celui où Runeya a lancé le serveur MCP, ou celui du chat intégré. */\nexport interface ProjectAnchor {\n projectId?: string;\n orgId?: string;\n}\n\n/**\n * Ancrer un appel sur le projet de la conversation.\n *\n * `service.list` rend tout le poste : chaque coffre, donc chaque projet de\n * chaque organisation de la machine. L'interface n'en montre qu'un, et le\n * prompt de l'agent ne décrit que celui-là — mais la tool, elle, répondait 88\n * services quand l'écran en montrait trois. L'agent citait alors des services\n * que l'utilisateur n'a jamais vus, et concluait à un problème de permissions.\n *\n * Le projet est donc posé par Runeya au lancement du serveur MCP, et complété\n * ici plutôt que laissé à la bonne lecture d'une consigne.\n *\n * Ne complète QUE ce que la capability déclare et que l'appelant a laissé vide :\n * un `projectId` donné explicitement gagne toujours, ce qui laisse l'agent\n * interroger un autre projet — `list_projects` les nomme tous.\n */\nexport function applyProjectAnchor(\n cap: Pick<RuneyaCapability, 'params'>,\n params: Record<string, string | undefined>,\n anchor: ProjectAnchor,\n): Record<string, string | undefined> {\n if (!anchor.projectId) return params;\n\n const accepts = (name: string) => cap.params.some((p) => p.name === name);\n if (!accepts('projectId') || params['projectId']) return params;\n\n return {\n ...params,\n projectId: anchor.projectId,\n // L'organisation n'accompagne le projet que si la capability la comprend :\n // ailleurs, ce serait un champ de trop, refusé par le schéma de la route.\n ...(anchor.orgId && accepts('orgId') && !params['orgId'] ? { orgId: anchor.orgId } : {}),\n };\n}\n","import { z } from 'zod';\n\nexport const UserSchema = z.object({\n id: z.string().max(128),\n email: z.string().email().max(320),\n name: z.string().min(1).max(500),\n avatar: z.string().url().max(2048).nullable().optional(),\n});\n\nexport type User = z.infer<typeof UserSchema>;\n","import { z } from 'zod';\n\nexport const OrgSchema = z.object({\n id: z.string().max(128),\n name: z.string().min(1).max(100),\n slug: z.string().min(1).max(100).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/),\n ownerId: z.string().max(128),\n});\n\nexport type Org = z.infer<typeof OrgSchema>;\n\nexport const OrgMemberSchema = z.object({\n id: z.string().max(128),\n orgId: z.string().max(128),\n userId: z.string().max(128),\n globalRole: z.enum(['owner', 'admin', 'member']),\n invitedAt: z.coerce.date(),\n joinedAt: z.coerce.date().nullable().optional(),\n});\n\nexport type OrgMember = z.infer<typeof OrgMemberSchema>;\n","import { z } from 'zod';\n\nexport const ProjectSchema = z.object({\n id: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n name: z.string().min(1).max(200),\n description: z.string().max(10000).optional().default(''),\n serviceIds: z.array(z.string().max(128)).max(10000).default([]),\n\n // Environment support\n // NOTE: activeEnvironmentId is runtime-only (not persisted to JSON)\n // It's initialized to 'local' by default at load time\n activeEnvironmentId: z.string().max(128).optional(),\n environmentIds: z.array(z.string().max(128)).max(100).default([]),\n\n // Ordre d'affichage des groupes de services dans la sidebar (noms de groupes).\n // Les groupes absents de cette liste sont affichés après, par ordre alphabétique.\n groupOrder: z.array(z.string().max(200)).max(100).default([]),\n});\n\nexport type Project = z.infer<typeof ProjectSchema>;\n\nexport const CreateProjectSchema = ProjectSchema.omit({ id: true }).partial().required({ name: true });\nexport type CreateProject = z.infer<typeof CreateProjectSchema>;\n\nexport const UpdateProjectSchema = ProjectSchema.partial().required({ id: true });\nexport type UpdateProject = z.infer<typeof UpdateProjectSchema>;\n","import { z } from 'zod';\nimport { JSLogParserSchema } from './settings.schema.js';\nimport { LogSourceConfigSchema } from './log-source.schema.js';\n\nexport const HealthCheckSchema = z.object({\n type: z.enum(['http', 'command']).default('http'),\n // HTTP-specific (required when type=http)\n path: z.string().min(1).max(500).startsWith('/').optional(),\n method: z.enum(['GET', 'HEAD', 'POST', 'PUT']).optional().default('GET'),\n expectedStatus: z.number().int().min(100).max(599).optional().default(200),\n // Command-specific (required when type=command)\n command: z.string().min(1).max(4096).optional(),\n // Shared\n interval: z.number().int().positive().default(1000),\n timeout: z.number().int().positive().default(1000),\n retries: z.number().int().nonnegative().default(3),\n initialDelay: z.number().int().nonnegative().optional().default(0),\n}).refine(\n (data) => data.type === 'http' ? !!data.path : !!data.command,\n { message: 'HTTP type requires path; command type requires command' },\n);\n\nexport type HealthCheck = z.infer<typeof HealthCheckSchema>;\n\nexport const BootstrapCommandSchema = z.object({\n id: z.string().min(1).max(64),\n label: z.string().max(200).default(''),\n entrypoint: z.string().max(4096).optional(),\n command: z.string().max(4096).default(''),\n user: z.string().max(256).optional(),\n});\n\nexport type BootstrapCommand = z.infer<typeof BootstrapCommandSchema>;\n\nexport const DockerConfigSchema = z.object({\n // Image mode (pull from registry) — mutually exclusive with build mode in UI\n image: z.string().min(1).max(1024).optional(),\n\n // Build mode — Dockerfile stored inline in services.json\n dockerfile: z.string().max(65536).optional(),\n buildContext: z.string().max(4096).optional(),\n buildArgs: z.record(z.string().max(256), z.string().max(4096)).default({}).refine(\n (obj) => Object.keys(obj).length <= 50,\n { message: 'Max 50 build args' },\n ),\n targetStage: z.string().max(256).optional(),\n\n // Runtime config\n networkMode: z.enum(['host', 'bridge']).default('host'),\n ports: z.array(z.string().max(64)).max(100).default([]),\n volumes: z.array(z.string().max(1024)).max(100).default([]),\n mountRootpath: z.boolean().default(false),\n entrypoint: z.string().max(4096).optional(),\n command: z.string().max(4096).optional(),\n user: z.string().max(256).optional(),\n useNativeCommand: z.boolean().default(false),\n nativeCommandMode: z.enum(['shared', 'isolated']).default('isolated'),\n nativeShell: z.string().max(256).default('sh'),\n bootstrapCommands: z.array(BootstrapCommandSchema).max(20).default([]),\n});\n\nexport type DockerConfig = z.infer<typeof DockerConfigSchema>;\n\nexport const RestartStrategySchema = z.enum(['none', 'on-failure', 'always', 'unless-stopped']).default('none');\nexport type RestartStrategy = z.infer<typeof RestartStrategySchema>;\n\nexport const ServiceShortcutSchema = z.object({\n id: z.string().min(1).max(64),\n label: z.string().max(200).default(''),\n command: z.string().max(4096).default(''),\n cwd: z.string().max(4096).optional(),\n});\n\nexport type ServiceShortcut = z.infer<typeof ServiceShortcutSchema>;\n\nexport const ServiceCommandSchema = z.object({\n id: z.string().min(1).max(64),\n label: z.string().max(200).default(''),\n command: z.string().max(4096).default(''),\n cwd: z.string().max(4096).optional(),\n shell: z.boolean().optional().default(true),\n});\n\nexport type ServiceCommand = z.infer<typeof ServiceCommandSchema>;\n\n// --- Variable Slot Schema ---\n// A VariableSlot represents a single value with optional pre/post concatenation.\n// The final resolved value is: pre + interpolate(value) + post\nexport const VariableSlotSchema = z.object({\n value: z.string().max(8192).default(''),\n pre: z.string().max(8192).default(''),\n post: z.string().max(8192).default(''),\n isSecret: z.boolean().default(false),\n // Deux décisions distinctes, et il ne faut pas les confondre :\n //\n // - `shareWithAi` est une permission de **lecture** : une IA (le chat de\n // Runeya, un agent par le serveur MCP) peut voir la valeur de ce secret.\n // Une variable publique est lisible de toute façon, le drapeau ne la\n // concerne pas.\n // - `injectIntoAi` est une **exécution** : la variable est posée dans\n // l'environnement du process des agents (Claude Code, Codex, …) lancés\n // depuis Runeya pendant que cet environnement est actif.\n //\n // Les deux sont opt-in : sans rien cocher, aucun secret ne part vers une IA.\n // Injecter implique lire (ce que le process reçoit, l'agent le voit), donc\n // la lecture accepte l'un OU l'autre : voir `isSharedWithAi`, qui est le seul\n // endroit où cette règle s'écrit.\n shareWithAi: z.boolean().default(false),\n injectIntoAi: z.boolean().default(false),\n // Une variable obligatoire doit avoir une valeur finale non vide avant qu'un\n // service de cet environnement puisse démarrer. Le démarrage est refusé\n // sinon, avec la liste des manquantes — l'assistant est le moyen de remplir.\n required: z.boolean().default(false),\n // Une variable « seulement surchargeable » n'a jamais de valeur partagée :\n // `value` reste vide dans le document synchronisé, et chaque poste DOIT\n // fournir sa propre surcharge machine-locale (chemin local, jeton personnel).\n // `pre` et `post` restent partagés — ils décrivent la forme, pas le secret.\n overrideOnly: z.boolean().default(false),\n // À quoi sert cette variable, pour quelqu'un qui doit la remplir. Affichée\n // par l'assistant de complétion et dans l'éditeur.\n //\n // Du **markdown**, pas du texte brut : une description gagne à pouvoir\n // pointer vers la console qui délivre le jeton. Écrite et relue par le même\n // éditeur Tiptap (`packages/editor-ui`), jamais injectée en HTML — Tiptap\n // analyse le markdown dans son propre schéma, si bien qu'une description\n // arrivée d'un autre poste par la synchronisation ne peut rien exécuter.\n description: z.string().max(2000).default(''),\n}).refine(\n (slot) => !slot.overrideOnly || slot.value === '',\n { message: 'An override-only variable cannot carry a shared value', path: ['value'] },\n);\n\nexport type VariableSlot = z.infer<typeof VariableSlotSchema>;\n\n/**\n * Son auteur a-t-il partagé cette variable avec les IA ?\n *\n * Deux cases mènent au même oui : `shareWithAi`, le partage en lecture, et\n * `injectIntoAi`, car une variable posée dans l'environnement du process d'un\n * agent est de fait lisible par lui — la lui refuser à la lecture tout en la\n * lui passant ne protégerait rien et rendrait l'interface menteuse.\n *\n * Le seul endroit où cette règle s'écrit. Deux précautions d'emploi :\n *\n * - Le drapeau ne décide que du sort des **secrets**. Une variable publique est\n * lisible de toute façon, et savoir laquelle est secrète n'est pas affaire de\n * définition : une variable non marquée qui référence un secret le devient à\n * la résolution. C'est donc au filtre de croiser les deux.\n * - Il se lit sur la **définition**, jamais sur un slot de surcharge : une\n * surcharge remplace le slot entier et n'en porte aucun drapeau (même piège\n * que `findMissingVariables`).\n */\nexport function isSharedWithAi(slot: Pick<VariableSlot, 'shareWithAi' | 'injectIntoAi'>): boolean {\n return slot.shareWithAi || slot.injectIntoAi;\n}\n\n/** Pourquoi une variable est réclamée par l'assistant de complétion. */\nexport const MissingVariableReasonSchema = z.enum(['required', 'overrideOnly']);\nexport type MissingVariableReason = z.infer<typeof MissingVariableReasonSchema>;\n\n/** Une variable qu'il faut remplir avant de démarrer. */\nexport const MissingVariableSchema = z.object({\n variableId: z.string().max(128),\n key: z.string().max(256),\n description: z.string().max(2000),\n reason: MissingVariableReasonSchema,\n isSecret: z.boolean(),\n environmentId: z.string().max(128),\n environmentName: z.string().max(200),\n});\n\nexport type MissingVariable = z.infer<typeof MissingVariableSchema>;\n\n// A Variable has a key (env var name) and a value slot.\nexport const VariableSchema = z.object({\n key: z.string().min(1).max(256),\n value: VariableSlotSchema,\n});\n\nexport type Variable = z.infer<typeof VariableSchema>;\n\n// Record of variableId → Variable. Max 200 entries.\n// The key is a unique variable ID (UUID), the Variable contains the env var name in `key`.\nexport const VariablesRecordSchema = z.record(\n z.string().max(128),\n VariableSchema,\n).refine(\n (obj) => Object.keys(obj).length <= 200,\n { message: 'Max 200 variables' },\n);\n\nexport type VariablesRecord = z.infer<typeof VariablesRecordSchema>;\n\n// Record of variable name → VariableSlot (used on disk for base values and overrides separately)\nexport const VariableSlotsRecordSchema = z.record(\n z.string().max(256),\n VariableSlotSchema,\n).refine(\n (obj) => Object.keys(obj).length <= 200,\n { message: 'Max 200 variable slots' },\n);\n\nexport type VariableSlotsRecord = z.infer<typeof VariableSlotsRecordSchema>;\n\nexport const ServiceConfigSchema = z.object({\n id: z.string().max(128),\n orgId: z.string().max(128).nullable().optional(),\n agentId: z.string().max(128).optional(), // Optional: if absent, inherited from active environment's agentId\n name: z.string().min(1).max(200),\n commands: z.array(ServiceCommandSchema).max(50).optional().default([]),\n cwd: z.string().max(4096).optional(),\n ports: z.array(z.number().int().positive().max(65535)).max(20).optional().default([]),\n\n // Metadata fields (migration from old Runeya)\n groups: z.array(z.string().max(200)).max(20).optional().default([]),\n description: z.string().max(2000).optional(),\n /** Path (relative to service.cwd or absolute) where the service's docs/wiki markdown files live. Optional — defaults to service.cwd. */\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).regex(/^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,}$/),\n port: z.number().int().min(1).max(65535),\n })).max(20).optional().default([]),\n openapiUrl: z.string().max(2048).optional(),\n git: z.object({\n remote: z.string().max(2048).optional(),\n home: z.string().max(2048).optional(),\n }).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\n // Transient env dict (resolved by server before deployment, used directly by agent runner — NOT persisted)\n env: z.record(z.string().max(256), z.string().max(8192)).default({}).refine(\n (obj) => Object.keys(obj).length <= 200,\n { message: 'Too many env vars (max 200)' },\n ),\n envSecrets: z.array(z.string().max(256)).max(200).default([]),\n\n // Transient: resolved JS log parsers (from parserIds, resolved by server before deployment — NOT persisted)\n resolvedLogParsers: z.array(JSLogParserSchema).default([]).optional(),\n\n // Transient: resolved working directory (cwd with env vars expanded — NOT persisted)\n resolvedCwd: z.string().optional(),\n\n runner: z.enum(['native', 'docker']).optional().default('native'),\n dockerConfig: DockerConfigSchema.optional(),\n healthCheck: HealthCheckSchema.optional(),\n parserIds: z.array(z.string().max(128)).max(50).default([]),\n shortcuts: z.array(ServiceShortcutSchema).max(50).optional().default([]),\n autoRestart: z.boolean().optional().default(false),\n clearLogsOnStart: 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\n // Log sources additionnelles (au-delà du stdout/stderr console par défaut)\n logSources: z.array(LogSourceConfigSchema).max(20).optional().default([]),\n});\n\nexport type ServiceConfig = z.infer<typeof ServiceConfigSchema>;\n\nexport const CreateServiceSchema = ServiceConfigSchema.omit({ id: true }).partial().required({ name: true });\nexport type CreateService = z.infer<typeof CreateServiceSchema>;\n\nexport const UpdateServiceSchema = ServiceConfigSchema.partial().required({ id: true }).extend({\n agentId: z.string().max(128).nullable().optional(), // null = clear (inherit from env), undefined = no change\n cwd: z.string().max(4096).nullable().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 healthCheck: HealthCheckSchema.nullable().optional(),\n});\nexport type UpdateService = z.infer<typeof UpdateServiceSchema>;\n","import { z } from 'zod';\nimport { ScenarioSchema } from './scenario.schema.js';\n\nexport const AI_PROVIDERS = ['anthropic', 'openai', 'mistral', 'groq', 'ollama'] as const;\nexport type AIProviderType = (typeof AI_PROVIDERS)[number];\n\nexport const AIProviderSchema = z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200),\n provider: z.enum(AI_PROVIDERS),\n encryptedApiKey: z.string().max(2000).default(''),\n model: z.string().max(200).optional(),\n active: z.boolean().default(false),\n createdAt: z.coerce.date(),\n updatedAt: z.coerce.date(),\n});\n\nexport type AIProvider = z.infer<typeof AIProviderSchema>;\n\nexport const JSLogParserSchema = z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200),\n description: z.string().max(2000).optional(),\n code: z.string().min(1).max(50000).refine(\n (s) => !s.includes('require(') && !s.includes('import ') && !s.includes('eval('),\n { message: 'Code must not contain require, import, or eval patterns' }\n ),\n enabled: z.boolean().default(true),\n builtin: z.boolean().optional(),\n createdAt: z.coerce.date(),\n updatedAt: z.coerce.date(),\n});\n\nexport type JSLogParser = z.infer<typeof JSLogParserSchema>;\n\nexport const NOTIFICATION_CATEGORIES = [\n 'scenario_waiting_input',\n 'ai_conversation_complete',\n 'ai_conversation_error',\n 'service_error_log',\n 'service_status_changed',\n 'service_health_changed',\n] as const;\nexport type NotificationCategory = (typeof NOTIFICATION_CATEGORIES)[number];\n\nexport const NotificationPreferencesSchema = z.object({\n scenario_waiting_input: z.boolean().default(true),\n ai_conversation_complete: z.boolean().default(true),\n ai_conversation_error: z.boolean().default(true),\n service_error_log: z.boolean().default(true),\n service_status_changed: z.boolean().default(true),\n service_health_changed: z.boolean().default(true),\n /** Service IDs excluded from error-log notifications */\n service_error_log_excluded: z.array(z.string().max(100)).max(500).default([]),\n /** Service IDs excluded from status-change notifications */\n service_status_changed_excluded: z.array(z.string().max(100)).max(500).default([]),\n /** Service IDs excluded from health-change notifications */\n service_health_changed_excluded: z.array(z.string().max(100)).max(500).default([]),\n});\nexport type NotificationPreferences = z.infer<typeof NotificationPreferencesSchema>;\n\n/**\n * Réglages du compagnon de relecture.\n *\n * Au niveau du POSTE, en clair, et non dans le coffre d'une organisation (§9) :\n * ce n'est pas un réglage d'équipe. Il décrit comment cette machine fait\n * travailler ses agents, il ne contient aucun secret, et le ranger dans un\n * coffre chiffré le rendrait dépendant de l'organisation qu'on regarde — un\n * même poste aurait autant de compagnons que d'organisations, sans raison.\n */\nexport const CompanionSettingsSchema = z.object({\n /** Activer le compagnon d'office sur les conversations créées ensuite. */\n enabledByDefault: z.boolean().default(false),\n /**\n * Spécificités ajoutées aux consignes Runeya.\n *\n * Vide — l'absence — signifie « aucune spécificité ». On ne recopie pas le\n * texte par défaut dans le réglage : les consignes Runeya restent dans le\n * code, pour profiter de leurs corrections.\n *\n * Rejeté au-delà de la borne plutôt que tronqué (§1) : un prompt coupé en\n * plein milieu produirait des relectures incohérentes sans rien signaler.\n */\n prompt: z.string().max(20_000).optional(),\n});\n\nexport type CompanionSettings = z.infer<typeof CompanionSettingsSchema>;\n\nexport const SettingsSchema = z.object({\n mode: z.enum(['local-simple', 'cloud']),\n cloudUrl: z.string().url().max(2048).nullable().optional(),\n logParsers: z.array(JSLogParserSchema).max(100).default([]),\n scenarios: z.array(ScenarioSchema).max(100).default([]),\n /** Absolute path to the folder where the global wiki/docs markdown files live. Optional. */\n globalDocsPath: z.string().max(4096).optional(),\n /**\n * Optionnel plutôt que défauté : un réglage absent est un réglage jamais\n * touché, et le rendre obligatoire dans le type forcerait chaque appelant qui\n * construit un objet de réglages à inventer une valeur.\n */\n companion: CompanionSettingsSchema.optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n\n\nexport const TraefikConfigSchema = z.object({\n enabled: z.boolean().default(false),\n acmeEmail: z.string().email().max(256).optional(),\n wildcardDomain: z.string().max(253).optional(),\n httpPort: z.number().int().min(1).max(65535).default(80),\n httpsPort: z.number().int().min(1).max(65535).default(443),\n dnsProvider: z.string().max(64).optional(),\n dnsCredentials: z.record(z.string().max(64), z.string().max(2048)).default({}),\n acmeStaging: z.boolean().default(false),\n encryptedCert: z.string().max(65536).optional(),\n encryptedCertKey: z.string().max(65536).optional(),\n});\n\nexport type TraefikConfig = z.infer<typeof TraefikConfigSchema>;\n\n\nexport const SettingsPrivateSchema = z.object({\n aiProviders: z.array(AIProviderSchema).max(50).default([]),\n scenarios: z.array(ScenarioSchema).max(100).default([]),\n notifications: NotificationPreferencesSchema.default(() => ({\n scenario_waiting_input: true,\n ai_conversation_complete: true,\n ai_conversation_error: true,\n service_error_log: true,\n service_status_changed: true,\n service_health_changed: true,\n service_error_log_excluded: [],\n service_status_changed_excluded: [],\n service_health_changed_excluded: [],\n })),\n traefikConfig: TraefikConfigSchema.optional(),\n});\n\nexport type SettingsPrivate = z.infer<typeof SettingsPrivateSchema>;\n\nexport const SchemaVersionSchema = z.object({\n version: z.number().int().positive(),\n migratedAt: z.coerce.date(),\n});\n\nexport type SchemaVersion = z.infer<typeof SchemaVersionSchema>;\n","import { z } from 'zod';\n\nconst PositionSchema = z.object({\n x: z.number(),\n y: z.number(),\n});\n\nexport const ScenarioGroupSchema = z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200),\n description: z.string().max(1000).optional(),\n color: z.string().max(32).optional(),\n position: PositionSchema.default({ x: 0, y: 0 }),\n width: z.number().default(300),\n height: z.number().default(200),\n});\n\nexport type ScenarioGroup = z.infer<typeof ScenarioGroupSchema>;\n\nexport const SCENARIO_ROLES = [\n 'manager',\n 'engineer',\n 'designer',\n 'analyst',\n 'qa',\n 'devops',\n 'product',\n 'writer',\n 'researcher',\n 'other',\n] as const;\n\nexport type ScenarioRole = typeof SCENARIO_ROLES[number];\n\n// --- Presets ---\n\nexport const ScenarioPresetRoleSchema = z.object({\n id: z.string().min(1).max(64),\n name: z.string().min(1).max(200),\n systemPrompt: z.string().max(10_000).default(''),\n prompt: z.string().max(10_000).default(''),\n});\n\nexport type ScenarioPresetRole = z.infer<typeof ScenarioPresetRoleSchema>;\n\nexport const ScenarioPresetInitialDataSchema = z.object({\n leaderId: z.string().min(1).max(128),\n groups: z.array(z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200),\n description: z.string().max(1000).optional(),\n color: z.string().max(32).optional(),\n position: z.object({ x: z.number(), y: z.number() }).default({ x: 0, y: 0 }),\n width: z.number().default(300),\n height: z.number().default(200),\n })).max(100).default([]),\n nodes: z.array(z.object({\n id: z.string().min(1).max(128),\n type: z.enum(['ai', 'ask']).default('ai'),\n parentIds: z.array(z.string().max(128)).default([]),\n groupId: z.string().max(128).nullable().default(null),\n label: z.string().max(240).default(''),\n role: z.string().max(64).default('other'),\n prompt: z.string().max(50_000).default(''),\n question: z.string().max(2_000).default(''),\n autoGenerated: z.boolean().default(true),\n canAddNode: z.boolean().default(false),\n aiCli: z.enum(['claude-code', 'codex']).default('claude-code'),\n model: z.string().max(128).default('sonnet'),\n position: z.object({ x: z.number(), y: z.number() }).default({ x: 0, y: 0 }),\n })).min(1).max(500),\n});\n\nexport type ScenarioPresetInitialData = z.infer<typeof ScenarioPresetInitialDataSchema>;\n\nconst LocalizedStringSchema = z.record(z.string(), z.string().max(100));\n\nexport const ScenarioPresetLabelsSchema = z.object({\n group: LocalizedStringSchema.optional(),\n node: LocalizedStringSchema.optional(),\n role: LocalizedStringSchema.optional(),\n leader: LocalizedStringSchema.optional(),\n});\n\nexport type ScenarioPresetLabels = z.infer<typeof ScenarioPresetLabelsSchema>;\n\nexport const ScenarioPresetSchema = z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200),\n icon: z.string().max(64).optional(),\n defaultTraversalMode: z.enum(['hierarchical', 'topological']).optional(),\n canChangeTraversalMode: z.boolean().default(true),\n roles: z.array(ScenarioPresetRoleSchema).min(1).max(100),\n initialData: ScenarioPresetInitialDataSchema.optional(),\n labels: ScenarioPresetLabelsSchema.optional(),\n});\n\nexport type ScenarioPreset = z.infer<typeof ScenarioPresetSchema>;\n\n// --- Node ---\n\nexport const ScenarioNodeSchema = z.object({\n id: z.string().min(1).max(128),\n type: z.enum(['ai', 'ask']).default('ai'),\n parentIds: z.array(z.string().max(128)).default([]),\n groupId: z.string().max(128).nullable().default(null),\n label: z.string().max(240).default(''),\n role: z.string().max(64).default('other'),\n prompt: z.string().max(50_000).default(''),\n question: z.string().max(2_000).default(''),\n autoGenerated: z.boolean().default(true),\n canAddNode: z.boolean().default(false),\n aiCli: z.enum(['claude-code', 'codex']).default('claude-code'),\n model: z.string().max(128).default('sonnet'),\n position: PositionSchema.default({ x: 0, y: 0 }),\n injectParentOutputs: z.boolean().default(false),\n injectedAncestorIds: z.array(z.string().max(128)).default([]),\n});\n\nexport type ScenarioNode = z.infer<typeof ScenarioNodeSchema>;\n\nexport const ScenarioSchema = z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200),\n icon: z.string().max(64).optional(),\n description: z.string().max(2000).optional(),\n leaderId: z.string().min(1).max(128),\n groups: z.array(ScenarioGroupSchema).max(100).default([]),\n nodes: z.array(ScenarioNodeSchema).min(1).max(500),\n traversalMode: z.enum(['hierarchical', 'topological']).default('hierarchical'),\n presetId: z.string().max(128).optional(),\n isPublished: z.boolean().default(false),\n createdAt: z.number(),\n updatedAt: z.number(),\n});\n\nexport type Scenario = z.infer<typeof ScenarioSchema>;\n","import { z } from 'zod';\n\nconst safePath = z\n .string()\n .min(1)\n .max(4096)\n .refine(\n (p) => !p.includes('\\0'),\n { message: 'path must not contain null bytes' },\n )\n .refine(\n (p) => !/(^|[/\\\\])\\.\\.([/\\\\]|$)/.test(p),\n { message: 'path must not contain path-traversal sequences (..)' },\n )\n;\n\nexport const ConsoleLogSourceSchema = z.object({\n type: z.literal('console'),\n});\nexport type ConsoleLogSource = z.infer<typeof ConsoleLogSourceSchema>;\n\nexport const FileLogSourceSchema = z.object({\n type: z.literal('file'),\n path: safePath,\n encoding: z.string().max(32).default('utf-8'),\n startFromEnd: z.boolean().default(true),\n createIfNotExists: z.boolean().default(false),\n});\nexport type FileLogSource = z.infer<typeof FileLogSourceSchema>;\n\nexport const MongoLogSourceSchema = z.object({\n type: z.literal('mongo'),\n /** @sensitive — stored encrypted (AES-256-GCM) on disk */\n connectionString: z.string().min(1).max(2048),\n database: z.string().min(1).max(256),\n collection: z.string().min(1).max(256),\n filter: z.record(z.string(), z.unknown()).optional(),\n timestampField: z.string().max(128).default('timestamp'),\n messageField: z.string().max(128).default('message'),\n levelField: z.string().max(128).optional(),\n});\nexport type MongoLogSource = z.infer<typeof MongoLogSourceSchema>;\n\nexport const MySQLLogSourceSchema = z.object({\n type: z.literal('mysql'),\n host: z.string().min(1).max(253),\n port: z.number().int().min(1).max(65535).default(3306),\n user: z.string().min(1).max(256),\n /** @sensitive — stored encrypted (AES-256-GCM) on disk */\n password: z.string().max(2048),\n database: z.string().min(1).max(256),\n table: z.string().min(1).max(256),\n query: z.string().max(8192).optional(),\n timestampColumn: z.string().max(128).default('created_at'),\n messageColumn: z.string().max(128).default('message'),\n levelColumn: z.string().max(128).optional(),\n pollIntervalMs: z.number().int().min(500).max(60000).default(2000),\n});\nexport type MySQLLogSource = z.infer<typeof MySQLLogSourceSchema>;\n\nexport const LogSourceConfigSchema = z.discriminatedUnion('type', [\n ConsoleLogSourceSchema,\n FileLogSourceSchema,\n MongoLogSourceSchema,\n MySQLLogSourceSchema,\n]);\nexport type LogSourceConfig = z.infer<typeof LogSourceConfigSchema>;\nexport type LogSourceType = LogSourceConfig['type'];\n","import { z } from 'zod';\n\nexport const ProcessStateSchema = z.enum(['starting', 'running', 'stopped', 'errored']);\nexport type ProcessState = z.infer<typeof ProcessStateSchema>;\n\nexport const HealthStatusSchema = z.enum(['healthy', 'unhealthy', 'unknown']);\nexport type HealthStatus = z.infer<typeof HealthStatusSchema>;\n\nexport const ProcessStatusSchema = z.object({\n id: z.string().max(128),\n serviceId: z.string().max(128),\n agentId: z.string().max(128),\n state: ProcessStateSchema,\n pid: z.number().int().nullable().optional(),\n pids: z.array(z.number().int()).optional().default([]),\n exitCode: z.number().int().nullable().optional(),\n startedAt: z.coerce.date().nullable().optional(),\n restartCount: z.number().int().nonnegative().default(0),\n uptime: z.number().nonnegative().default(0),\n healthStatus: HealthStatusSchema.default('unknown'),\n /**\n * Le répertoire où le processus s'exécute VRAIMENT, absolutisé par l'agent.\n *\n * Rapporté par l'agent plutôt que déduit de la config : entre le `cwd` de la\n * commande, celui du service, l'ancrage sur le projet et les variables que\n * l'agent étend lui-même, la valeur affichée n'aurait rien prouvé. Ce qui\n * intéresse quand un service tourne contre le mauvais dépôt, c'est le chemin\n * final — y compris quand il retombe sur le répertoire de l'agent.\n */\n cwd: z.string().max(4096).nullable().optional(),\n});\n\nexport type ProcessStatus = z.infer<typeof ProcessStatusSchema>;\n","import { z } from 'zod';\n\nexport const LogLevelSchema = z.enum(['debug', 'info', 'warn', 'error', 'fatal']);\nexport type LogLevel = z.infer<typeof LogLevelSchema>;\n\nexport const LogLineSchema = z.object({\n /** Raw log line as received from the process (immutable context) */\n raw: z.string(),\n /** Source stream (immutable context) */\n stream: z.enum(['stdout', 'stderr']),\n /** Severity level */\n level: LogLevelSchema,\n /** Parsed/enriched message to display */\n message: z.string(),\n /** When true, the line is hidden from the log view */\n hidden: z.boolean(),\n /** Arbitrary key/value pairs shown in the detail panel */\n metadata: z.record(z.string().max(256), z.unknown()).refine(\n (obj) => Object.keys(obj).length <= 100,\n { message: 'Too many metadata keys (max 100)' },\n ),\n /** Full parsed JSON object when the line is JSON */\n json: z.record(z.string(), z.unknown()).optional(),\n /** Custom header for the JSON log card (supports HTML, sanitized before display) */\n jsonHeader: z.string().max(256).optional(),\n});\n\nexport type LogLine = z.infer<typeof LogLineSchema>;\n\nexport const LogCardDirectiveSchema = z.object({\n id: z.string().max(128),\n type: z.string().max(64),\n header: z.string().max(256),\n collapsable: z.boolean().optional(),\n collapsed: z.boolean().optional(),\n state: z.enum(['open', 'append', 'close', 'self']),\n});\nexport type LogCardDirective = z.infer<typeof LogCardDirectiveSchema>;\n\nexport const ParsedLogSchema = z.object({\n id: z.string().max(128),\n processId: z.string().max(128),\n pid: z.number().int().nullable().optional(),\n timestamp: z.coerce.date(),\n level: LogLevelSchema.default('info'),\n message: z.string().max(16384),\n raw: z.string().max(16384),\n stream: z.enum(['stdout', 'stderr']).default('stdout'),\n hidden: z.boolean().optional().default(false),\n metadata: z.record(z.string().max(256), z.unknown()).optional().refine(\n (obj) => !obj || Object.keys(obj).length <= 100,\n { message: 'Too many metadata keys (max 100)' },\n ),\n json: z.record(z.string(), z.unknown()).optional(),\n logCard: LogCardDirectiveSchema.optional(),\n sourceType: z.enum(['console', 'file', 'mongo', 'mysql']).optional(),\n sourcePath: z.string().max(4096).optional(),\n});\n\nexport type ParsedLog = z.infer<typeof ParsedLogSchema>;\n","import { z } from 'zod';\n\n/** Regex for valid POSIX environment variable names */\nexport const ENV_VAR_NAME_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nexport const AgentConfigSchema = z.object({\n id: z.string().max(128),\n name: z.string().min(1).max(100),\n url: z.string().url().max(2048),\n passphrase: z.string().min(1).max(1024),\n passthroughEnv: z.array(\n z.string().regex(ENV_VAR_NAME_REGEX).max(256),\n ).max(100).default([]),\n});\n\nexport type AgentConfig = z.infer<typeof AgentConfigSchema>;\n\nexport const AgentStatusSchema = z.object({\n connected: z.boolean(),\n lastSeen: z.string().nullable().optional(),\n uptime: z.number().nonnegative().default(0),\n runnersAvailable: z.array(z.enum(['native', 'docker'])).default(['native']),\n lanIp: z.string().optional(),\n /**\n * Ce que la machine de l'agent vaut pour les builtins de portée `agent`.\n * Sert à PRÉVISUALISER — la valeur injectée reste calculée au lancement, par\n * l'agent lui-même : une IP change, un agent se déconnecte, et un statut\n * n'est qu'un cliché.\n */\n os: z.string().max(64).optional(),\n home: z.string().max(4096).optional(),\n cwd: z.string().max(4096).optional(),\n});\n\nexport type AgentStatus = z.infer<typeof AgentStatusSchema>;\n","import { z } from 'zod';\n\nexport const GlobalRoleSchema = z.enum(['owner', 'admin', 'member']);\nexport type GlobalRole = z.infer<typeof GlobalRoleSchema>;\n\nexport const ProjectRoleSchema = z.enum(['admin', 'editor', 'viewer']);\nexport type ProjectRole = z.infer<typeof ProjectRoleSchema>;\n\nexport const ProjectMemberRoleSchema = z.object({\n id: z.string().max(128),\n projectId: z.string().max(128),\n userId: z.string().max(128),\n role: ProjectRoleSchema,\n});\n\nexport type ProjectMemberRole = z.infer<typeof ProjectMemberRoleSchema>;\n","import { z } from 'zod';\n\nexport const ConfigVersionSchema = z.object({\n id: z.string().max(128),\n entityType: z.enum(['project', 'service']),\n entityId: z.string().max(128),\n version: z.string().max(128),\n parentVersion: z.string().max(128),\n data: z.record(z.string(), z.unknown()).refine(\n (obj) => Object.keys(obj).length <= 1000,\n 'Too many data keys (max 1000)',\n ),\n patch: z.array(z.record(z.string(), z.unknown())).max(1000),\n userId: z.string().max(128),\n timestamp: z.coerce.date(),\n resolved: z.boolean().default(false),\n});\n\nexport type ConfigVersion = z.infer<typeof ConfigVersionSchema>;\n\nexport const ConfigChangeSchema = z.object({\n entityType: z.enum(['project', 'service']),\n entityId: z.string().max(128),\n version: z.string().max(128),\n parentVersion: z.string().max(128),\n data: z.record(z.string(), z.unknown()).refine(\n (obj) => Object.keys(obj).length <= 1000,\n 'Too many data keys (max 1000)',\n ),\n patch: z.array(z.record(z.string(), z.unknown())).max(1000),\n});\n\nexport type ConfigChange = z.infer<typeof ConfigChangeSchema>;\n\nexport const SyncStatusSchema = z.object({\n connected: z.boolean(),\n lastSync: z.coerce.date().nullable().optional(),\n pendingChanges: z.number().int().nonnegative().default(0),\n conflicts: z.number().int().nonnegative().default(0),\n});\n\nexport type SyncStatus = z.infer<typeof SyncStatusSchema>;\n","import { z } from 'zod';\n\nexport const AuditActionSchema = z.enum([\n 'create', 'update', 'delete',\n 'invite', 'remove',\n 'deploy', 'start', 'stop',\n 'roleChange',\n]);\n\nexport type AuditAction = z.infer<typeof AuditActionSchema>;\n\nexport const AuditEntityTypeSchema = z.enum([\n 'org', 'project', 'service', 'member', 'permission',\n]);\n\nexport type AuditEntityType = z.infer<typeof AuditEntityTypeSchema>;\n\nexport const AuditLogSchema = z.object({\n id: z.string().max(128),\n orgId: z.string().max(128),\n userId: z.string().max(128),\n action: AuditActionSchema,\n entityType: AuditEntityTypeSchema,\n entityId: z.string().max(128),\n metadata: z.record(z.string().max(256), z.unknown()).default({}).refine(\n (obj) => Object.keys(obj).length <= 100,\n { message: 'Too many metadata keys (max 100)' },\n ),\n timestamp: z.coerce.date(),\n});\n\nexport type AuditLog = z.infer<typeof AuditLogSchema>;\n","import { z } from 'zod';\n\nexport const ProcessMetricsSchema = z.object({\n processId: z.string().max(128),\n cpu: z.number().nonnegative(),\n memory: z.number().int().nonnegative(),\n timestamp: z.string(),\n});\n\nexport type ProcessMetrics = z.infer<typeof ProcessMetricsSchema>;\n","import { z } from 'zod';\nimport { VariableSchema } from './service.schema.js';\n\n// Environment schema — uses VariablesRecord for variable storage\nexport const EnvironmentVariablesSchema = z.record(\n z.string().max(256),\n VariableSchema,\n).refine(\n (obj) => Object.keys(obj).length <= 200,\n { message: 'Max 200 variables' },\n);\n\nexport const EnvironmentSchema = z.object({\n id: z.string().max(128),\n projectId: z.string().max(128),\n name: z.string().min(1).max(200),\n description: z.string().max(2000).optional().default(''),\n parentIds: z.array(z.string().max(128)).max(10).default([]),\n variables: EnvironmentVariablesSchema.default({}),\n // Scope: 'global' = project-level env, 'service' = per-service env\n scope: z.enum(['global', 'service']).default('global'),\n // When scope='service': the serviceId this env belongs to\n reference: z.string().max(128).optional(),\n // When scope='service': the globalEnvId this env activates on\n activateOn: z.string().max(128).optional(),\n immutable: z.boolean().default(false),\n default: z.boolean().optional().default(false),\n color: z.string().max(20).optional(),\n bgColor: z.string().max(20).optional(),\n // When scope='global': the default agent used by services that don't have an explicit agentId\n agentId: z.string().max(128).optional(),\n});\n\nexport type Environment = z.infer<typeof EnvironmentSchema>;\n\n// Resolved environment: flattened env dict + secrets list + source tracking\nexport const ResolvedEnvironmentSchema = z.object({\n variables: z.record(z.string().max(256), VariableSchema)\n .refine((obj) => Object.keys(obj).length <= 500, { message: 'Max 500 resolved variables' }),\n env: z.record(z.string().max(256), z.string().max(8192))\n .refine((obj) => Object.keys(obj).length <= 500, { message: 'Max 500 resolved env vars' }),\n envSecrets: z.array(z.string().max(256)).max(500),\n sources: z.record(z.string().max(256), z.object({\n environmentId: z.string().max(128),\n environmentName: z.string().max(200),\n overridden: z.boolean(),\n resolvedFrom: z.object({\n environmentId: z.string().max(128),\n environmentName: z.string().max(200),\n }).optional(),\n // Set when a machine-local override was applied to this variable, pointing\n // at the environment that carries the winning override. Distinct from\n // `overridden`, which also covers \"shadows an inherited variable\".\n overriddenBy: z.object({\n environmentId: z.string().max(128),\n environmentName: z.string().max(200),\n }).optional(),\n })).refine((obj) => Object.keys(obj).length <= 500, { message: 'Max 500 source entries' }),\n});\n\nexport type ResolvedEnvironment = z.infer<typeof ResolvedEnvironmentSchema>;\n\nexport const CreateEnvironmentSchema = EnvironmentSchema.omit({ id: true }).extend({\n description: z.string().max(2000).optional().default(''),\n parentIds: z.array(z.string().max(128)).max(10).optional().default([]),\n variables: EnvironmentVariablesSchema.optional().default({}),\n scope: z.enum(['global', 'service']).optional().default('global'),\n reference: z.string().max(128).optional(),\n activateOn: z.string().max(128).optional(),\n immutable: z.boolean().optional().default(false),\n});\nexport type CreateEnvironment = z.input<typeof CreateEnvironmentSchema>;\n\n// IMPORTANT: Do NOT simplify this to `EnvironmentSchema.partial().required({ id: true })`.\n//\n// EnvironmentSchema has .default() on several fields (variables: {}, parentIds: [], description: '',\n// scope: 'global', immutable: false, default: false). When Zod parses a partial update input that\n// omits those fields, .partial() alone does NOT strip the defaults — Zod still fills them in.\n// The store checks `input.variables !== undefined` to decide whether to overwrite, so if Zod\n// silently injects `variables: {}`, the store wipes ALL existing variables on every save.\n//\n// The .extend() below overrides those fields without .default(), making them truly optional\n// (undefined when absent). DO NOT remove it or merge the .extend() back into EnvironmentSchema.\nexport const UpdateEnvironmentSchema = EnvironmentSchema\n .partial()\n .required({ id: true })\n .extend({\n description: z.string().max(2000).optional(),\n parentIds: z.array(z.string().max(128)).max(10).optional(),\n variables: EnvironmentVariablesSchema.optional(),\n scope: z.enum(['global', 'service']).optional(),\n immutable: z.boolean().optional(),\n default: z.boolean().optional(),\n agentId: z.string().max(128).nullable().optional(), // null = clear (no default agent)\n });\nexport type UpdateEnvironment = z.infer<typeof UpdateEnvironmentSchema>;\n","import { z } from 'zod';\nimport { VariableSlotSchema } from './service.schema.js';\n\n// An override carries ONLY a value slot: the env var name always comes from the\n// variable definition in `environments.json`, looked up by variable ID. Storing\n// a `key` here would go stale as soon as the variable is renamed in the UI.\nexport const VariableOverrideSchema = z.object({\n value: VariableSlotSchema,\n});\n\nexport type VariableOverride = z.infer<typeof VariableOverrideSchema>;\n\n// Environment overrides: Record<variableId, VariableOverride>\n// Flat structure — each override is keyed by the variable's unique ID.\nexport const EnvironmentOverridesSchema = z.record(\n z.string().max(128),\n VariableOverrideSchema,\n).refine(\n (obj) => Object.keys(obj).length <= 5000,\n { message: 'Max 5000 overrides' },\n);\n\nexport type EnvironmentOverrides = z.infer<typeof EnvironmentOverridesSchema>;\n","import { z } from 'zod';\n\nexport const ApiServiceActionSchema = z.enum([\n 'service:read',\n 'service:start',\n 'service:stop',\n 'service:restart',\n 'service:healthcheck',\n 'service:status',\n 'logs:read',\n]);\nexport type ApiServiceAction = z.infer<typeof ApiServiceActionSchema>;\n\nexport const ApiEnvActionSchema = z.enum(['env:read', 'env:write']);\nexport type ApiEnvAction = z.infer<typeof ApiEnvActionSchema>;\n\nexport const ApiEnvPermSchema = z.object({\n environmentId: z.string().max(128),\n actions: z.array(ApiEnvActionSchema).max(10).default(['env:read']),\n includeSecrets: z.boolean().default(false),\n});\nexport type ApiEnvPerm = z.infer<typeof ApiEnvPermSchema>;\n\nexport const ApiServicePermSchema = z.object({\n serviceId: z.string().max(128),\n actions: z.array(ApiServiceActionSchema).max(10).default(['service:read']),\n environments: z.array(ApiEnvPermSchema).max(100).default([]),\n});\nexport type ApiServicePerm = z.infer<typeof ApiServicePermSchema>;\n\nexport const ApiKeyScopeSchema = z.object({\n services: z.array(ApiServicePermSchema).max(500).default([]),\n});\nexport type ApiKeyScope = z.infer<typeof ApiKeyScopeSchema>;\n\nexport const ApiKeySchema = z.object({\n id: z.string().max(128),\n name: z.string().min(1).max(200),\n key: z.string().regex(/^[0-9a-f]{64}$/i),\n scopes: ApiKeyScopeSchema,\n createdAt: z.string().max(64),\n isPublic: z.boolean().default(false),\n});\nexport type ApiKey = z.infer<typeof ApiKeySchema>;\n\n/**\n * Shape of an API key as it sits on disk: `key` holds the *encrypted* secret,\n * so it no longer matches the 64-hex form the in-memory type guarantees.\n * Legacy files written before encryption still parse — the store decrypts only\n * what looks encrypted and re-persists.\n */\nexport const PersistedApiKeySchema = ApiKeySchema.extend({\n key: z.string().min(1).max(4096),\n});\nexport type PersistedApiKey = z.infer<typeof PersistedApiKeySchema>;\n\nexport const ApiKeysFileSchema = z.object({\n keys: z.array(PersistedApiKeySchema).max(100),\n});\n\n/** An API key as exposed by the API: the secret is never part of it. */\nexport const MaskedApiKeySchema = ApiKeySchema.omit({ key: true }).extend({\n /** Last 4 characters of the secret, for recognising a key in a list. */\n keyPreview: z.string().max(8),\n});\nexport type MaskedApiKey = z.infer<typeof MaskedApiKeySchema>;\n\n","import { z } from 'zod';\n\nexport const ALLOWED_IMAGE_MIME_TYPES = ['image/png', 'image/jpeg', 'image/webp', 'image/gif'] as const;\n\nexport const 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, 'Must be a valid UUID'),\n url: z.string().min(1),\n mimeType: z.enum(ALLOWED_IMAGE_MIME_TYPES),\n altText: z.string().max(500).optional(),\n});\n\nexport type ImagePart = z.infer<typeof ImagePartSchema>;\n\nexport const ImageUploadResponseSchema = z.object({\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, 'Must be a valid UUID'),\n url: z.string().min(1),\n mimeType: z.enum(ALLOWED_IMAGE_MIME_TYPES),\n originalName: z.string(),\n});\n\nexport type ImageUploadResponse = z.infer<typeof ImageUploadResponseSchema>;\n\nexport const ImageMetaSchema = z.object({\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, 'Must be a valid UUID'),\n filePath: z.string().min(1),\n mimeType: z.enum(ALLOWED_IMAGE_MIME_TYPES),\n originalName: z.string().min(1),\n createdAt: z.number().positive(),\n size: z.number().positive().optional(),\n});\n\nexport type ImageMeta = z.infer<typeof ImageMetaSchema>;\n","import { z } from 'zod';\n\n// --- Attachments ---\n/**\n * A file attached to a card. The bytes live in object storage; the card keeps\n * only this descriptor, so a board document stays small no matter how many\n * files it carries.\n */\nexport const KanbanAttachmentSchema = z.object({\n /** Server-issued id, also the storage key. */\n id: z.string().max(128),\n name: z.string().max(255),\n size: z.number().int().nonnegative(),\n contentType: z.string().max(128),\n});\nexport type KanbanAttachment = z.infer<typeof KanbanAttachmentSchema>;\n\n// --- Card History ---\nexport const KanbanCardEventSchema = z.object({\n type: z.enum(['created', 'edited', 'moved', 'image_added', 'image_removed', 'title_changed', 'conversation_started', 'scenario_started', 'comment', 'archived', 'unarchived']),\n timestamp: z.string(),\n /** Extra context: old/new column name, old/new title, comment text, etc. */\n /**\n * Le texte de l'entrée : le corps d'un commentaire, ou le contexte du geste.\n *\n * Borné comme le corps d'une carte (100 000), et non plus à 5 000 : un\n * commentaire est de la prose comme une description, et rien de technique ne\n * justifiait un écart de vingt fois. La borne étroite s'est vue à l'import\n * d'un Kanbanize, où des commentaires de 12 000 caractères passaient par\n * l'API publique — bornée, elle, à 20 000 — pour écrire en base une donnée que\n * ce schéma déclarait invalide, et qu'aucune reprise depuis l'interface\n * n'aurait ensuite pu enregistrer.\n */\n detail: z.string().max(100_000).optional(),\n /**\n * Stable identity of the event, used to tell an edit from an insertion when a\n * whole history is written back. Absent on events recorded before the field\n * existed; those fall back to (type, timestamp).\n */\n id: z.string().max(128).optional(),\n /**\n * La colonne où l'événement fait entrer la carte (`created`, `moved`,\n * `unarchived`). Le `detail` n'en porte que le titre, qu'un renommage rend\n * introuvable : l'identifiant, lui, tient. Absent des événements antérieurs\n * que la migration n'a pas pu rapprocher.\n */\n columnId: z.string().max(128).optional(),\n /** Who authored this event — 'ai' or 'user'. Only set for comment events. */\n author: z.enum(['ai', 'user']).optional(),\n /**\n * Qui est derrière l'événement, estampillé par le serveur — jamais pris du\n * client, sans quoi n'importe qui pourrait signer au nom d'un autre.\n *\n * Posé sur les commentaires (c'est ce qui rend « mon propre commentaire »\n * répondable ; `author` ne sépare que l'IA de l'humain) et sur les\n * déplacements. Absent des événements écrits avant qu'on l'estampille : un\n * lecteur doit donc afficher « on ne sait pas », pas un nom vide.\n *\n * Pour une clé d'API, c'est le nom de la clé et non son porteur : la clé\n * emprunte les droits de son créateur, pas son identité — personne ne doit\n * croire qu'un humain a déplacé ce qu'un robot de CI a déplacé.\n */\n authorUser: z.object({ id: z.string().max(128), name: z.string().max(200) }).optional(),\n /** Set when the author amended their comment, so the UI can say so. */\n editedAt: z.string().optional(),\n /** Files attached to a comment — same storage as a card's own attachments. */\n attachments: z.array(KanbanAttachmentSchema).max(20).optional(),\n /** Conversation that produced this event (comments only). Used to navigate back to the conversation. */\n conversationId: z.string().optional(),\n});\nexport type KanbanCardEvent = z.infer<typeof KanbanCardEventSchema>;\n\n// --- Card ---\nexport const KanbanCardSchema = z.object({\n id: z.string(),\n title: z.string().min(1).max(500),\n markdown: z.string().max(100_000).default(''),\n /**\n * Legacy inline images, kept so boards written before object storage still\n * render. New uploads go to `attachments` instead.\n */\n images: z.array(z.string()).default([]),\n /** Files attached to the card — stored out of band, referenced here. */\n attachments: z.array(KanbanAttachmentSchema).max(50).default([]),\n order: z.number().int(),\n /**\n * La priorité de la carte, de 1 à 10 — 10 étant le plus urgent.\n *\n * Facultative, et absente veut dire « pas de priorité », pas « la plus\n * basse » : une carte qu'on n'a pas encore arbitrée ne doit pas se ranger\n * d'office au fond de la pile.\n */\n priority: z.number().int().min(1).max(10).optional(),\n\n /**\n * Les groupes de la carte — des étiquettes libres, posées par l'équipe.\n *\n * Rien ne les déclare ailleurs : un groupe existe parce qu'une carte le\n * porte, et disparaît avec la dernière qui le portait. C'est ce qui permet\n * d'en créer un en le tapant, sans passer par un écran d'administration.\n */\n groups: z.array(z.string().min(1).max(60)).max(30).optional(),\n /**\n * L'échéance de la carte : le jour où elle est attendue, `AAAA-MM-JJ`.\n *\n * Un jour, pas un instant, et c'est une décision : une équipe se dit « pour\n * vendredi », jamais « pour vendredi 23:59:59 UTC ». Stocker un instant\n * ferait afficher une échéance au 4 mars comme le 3 mars à qui travaille à\n * l'ouest de Greenwich — la carte serait en retard d'un jour pour la moitié\n * de l'équipe, et personne ne saurait pourquoi.\n *\n * Facultative, et absente veut dire « pas d'échéance », pas « en retard » :\n * une carte qu'on n'a pas datée ne doit pas s'annoncer comme urgente.\n */\n deadline: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional(),\n\n /**\n * La couleur de la carte, en hexadécimal (`#RRGGBB`) — un liseré en haut de\n * la carte, et rien d'autre : ce qu'elle veut dire appartient à l'équipe.\n *\n * Bornée à une notation stricte plutôt qu'à une chaîne libre : cette valeur\n * finit dans un attribut `style`, et une couleur ne doit pouvoir contenir\n * qu'une couleur. Absente sur les cartes sans couleur.\n */\n color: z.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),\n /**\n * Le journal de la carte — commentaires compris.\n *\n * Optionnel, et c'est tout l'intérêt : c'est la partie qui grossit sans fin\n * (une IA bavarde y écrit des pages), alors les lectures de tableau ne le\n * transportent plus. `undefined` veut dire « pas chargé », et une écriture\n * qui l'omet laisse au serveur celui qu'il a en base — à ne pas confondre\n * avec `[]`, qui demanderait bel et bien de le vider.\n */\n history: z.array(KanbanCardEventSchema).optional(),\n /**\n * Ce que le journal absent laisse quand même dire : combien de commentaires,\n * et quand fut le dernier. Posés par le serveur en lecture, ignorés en\n * écriture — la carte ne les stocke pas, ils se déduisent de `history`.\n */\n commentCount: z.number().int().nonnegative().optional(),\n lastCommentAt: z.string().optional(),\n /**\n * L'auteur du dernier commentaire, pour son avatar sur la tuile. Même règle :\n * posé en lecture, ignoré en écriture. `id`/`name` absents quand le\n * commentaire précède l'estampille d'auteur — on sait alors seulement si\n * c'était une IA.\n */\n lastCommentBy: z\n .object({ id: z.string().max(128).optional(), name: z.string().max(200).optional(), author: z.enum(['ai', 'user']).optional() })\n .optional(),\n /**\n * Les entrées de journal qui ouvrent une conversation IA. Elles restent dans\n * la lecture allégée — il y en a une poignée par carte, et l'hôte s'en sert\n * pour dire, sans ouvrir la carte, qu'une IA y travaille.\n */\n conversationEvents: z.array(KanbanCardEventSchema).optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n /**\n * Quand la carte a été archivée — absente tant qu'elle est au tableau.\n *\n * Une carte archivée reste dans sa colonne en base : c'est la lecture qui la\n * retire du tableau, jamais une écriture qui la déplace. Rien à recoller donc\n * au désarchivage, et aucun cimetière où une carte pourrait se perdre.\n */\n archivedAt: z.string().optional(),\n /**\n * La colonne d'où la carte a été archivée, telle qu'elle s'appelait alors.\n *\n * L'identifiant sert à l'y remettre, le titre à le dire dans l'archive même\n * quand la colonne a disparu depuis — auquel cas le désarchivage repose la\n * carte dans la première colonne, sans se taire sur son origine.\n */\n archivedFrom: z\n .object({ columnId: z.string().max(128), columnTitle: z.string().max(200) })\n .optional(),\n /**\n * Quand la carte a été supprimée. Rien n'est effacé : la carte reste en base,\n * et toutes les lectures l'écartent.\n *\n * Une suppression est le seul geste que rien ne rattrape — sauf à ne pas\n * l'exécuter vraiment. La colonne et le tableau portent le même champ, pour\n * que supprimer l'un n'emporte jamais les cartes de l'autre.\n */\n deletedAt: z.string().optional(),\n /**\n * People assigned to the card. Names are denormalized for display; the server\n * keeps only members of the owning organization, and notifies newcomers.\n */\n assignees: z\n .array(z.object({ id: z.string().max(128), name: z.string().max(200) }))\n .max(20)\n .default([]),\n /**\n * Who first created the card. Stamped by the server the first time a card id\n * appears in a board write, never taken from the client — a member could\n * otherwise claim any authorship. Absent on cards created before this field\n * existed, so readers must treat it as unknown rather than assume.\n */\n createdBy: z\n .object({ id: z.string().max(128), name: z.string().max(200) })\n .optional(),\n});\nexport type KanbanCard = z.infer<typeof KanbanCardSchema>;\n\n// --- Column ---\nexport const KanbanColumnSchema = z.object({\n id: z.string(),\n title: z.string().min(1).max(200),\n order: z.number().int(),\n cards: z.array(KanbanCardSchema).default([]),\n /**\n * Le regroupement auquel la colonne appartient, s'il y en a un.\n *\n * Un pointeur vers le parent, et rien dans l'autre sens : le groupe ne tient\n * pas la liste de ses membres. Deux listes qui prétendent dire qui contient\n * quoi finissent par se contredire, et un déplacement devient alors deux\n * écritures au lieu d'une.\n */\n groupId: z.string().optional(),\n /**\n * Colonne de cartes finalisées : y entrer compte comme « finalisée » dans les\n * statistiques de la liste, au même titre qu'un archivage.\n */\n done: z.boolean().optional(),\n /** Supprimée, mais conservée — voir `deletedAt` sur la carte. */\n deletedAt: z.string().optional(),\n});\nexport type KanbanColumn = z.infer<typeof KanbanColumnSchema>;\n\n// --- Column group ---\n/**\n * Un regroupement de colonnes : un bandeau au-dessus d'elles, pas une colonne.\n *\n * Il ne porte aucune carte — jamais — et c'est ce qui le rend inoffensif :\n * `columnId`, les rangs fractionnaires et tout le déplacement de cartes\n * ignorent son existence. Un groupe peut en contenir un autre (`parentId`).\n *\n * Il n'a délibérément **pas** d'`order` : sa place se déduit de celle de ses\n * colonnes, dont l'ordre reste l'unique source de vérité. Un groupe qui aurait\n * son propre rang pourrait contredire celui de ses membres, et il n'existerait\n * alors aucune bonne réponse à « laquelle des deux positions gagne ».\n */\nexport const KanbanColumnGroupSchema = z.object({\n id: z.string(),\n title: z.string().min(1).max(200),\n /** La couleur du bandeau, en hexadécimal — l'interface décide du défaut. */\n color: z.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),\n /** Le groupe parent, pour les regroupements imbriqués. */\n parentId: z.string().optional(),\n /** Supprimé, mais conservé — comme une colonne. */\n deletedAt: z.string().optional(),\n});\nexport type KanbanColumnGroup = z.infer<typeof KanbanColumnGroupSchema>;\n\n// --- Board ---\nexport const KanbanBoardSchema = z.object({\n id: z.string(),\n name: z.string().min(1).max(200),\n description: z.string().max(10_000).default(''),\n /**\n * Le mode d'emploi du tableau, en texte libre : ce que veulent dire ses\n * colonnes, quand une carte a le droit d'avancer, les conventions de\n * l'équipe. Écrit par les humains, lu surtout par l'IA — il est injecté dans\n * le prompt des agents pour qu'ils travaillent selon les règles du tableau\n * plutôt que selon les leurs.\n */\n instructions: z.string().max(20_000).default(''),\n columns: z.array(KanbanColumnSchema).default([]),\n /** Les regroupements de colonnes — vide sur un tableau qui n'en a jamais eu. */\n columnGroups: z.array(KanbanColumnGroupSchema).default([]),\n /**\n * Les projets auxquels le tableau est rattaché, par leur identifiant.\n *\n * Un rattachement, pas une possession : il ne sert qu'à filtrer la liste des\n * tableaux, et un tableau sans projet (`[]`, le cas par défaut) reste visible\n * partout. Plusieurs projets sont permis parce qu'une équipe partage souvent\n * un même tableau entre deux projets — obliger à choisir l'un des deux\n * ferait disparaître le tableau de la liste de l'autre.\n *\n * Les identifiants sont ceux des projets de l'organisation ; le serveur\n * refuse ceux qu'il ne connaît pas plutôt que de garder un lien mort.\n */\n projectIds: z.array(z.string().min(1).max(128)).max(20).default([]),\n archived: z.boolean().default(false),\n /** Supprimé, mais conservé avec ses cartes — voir `deletedAt` sur la carte. */\n deletedAt: z.string().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\nexport type KanbanBoard = z.infer<typeof KanbanBoardSchema>;\n\n// --- Inputs ---\nexport const CreateKanbanBoardInput = z.object({\n name: z.string().min(1).max(200),\n description: z.string().max(10_000).optional(),\n instructions: z.string().max(20_000).optional(),\n projectIds: z.array(z.string().min(1).max(128)).max(20).optional(),\n});\nexport type CreateKanbanBoardInput = z.infer<typeof CreateKanbanBoardInput>;\n\nexport const UpdateKanbanBoardInput = z.object({\n id: z.string(),\n name: z.string().min(1).max(200).optional(),\n description: z.string().max(10_000).optional(),\n instructions: z.string().max(20_000).optional(),\n columns: z.array(KanbanColumnSchema).optional(),\n archived: z.boolean().optional(),\n projectIds: z.array(z.string().min(1).max(128)).max(20).optional(),\n});\nexport type UpdateKanbanBoardInput = z.infer<typeof UpdateKanbanBoardInput>;\n\n// --- Card links ---\n/**\n * Un lien entre deux cartes, rangé hors des tableaux.\n *\n * Le lien ne vit pas dans la carte, et c'est délibéré : une carte se réécrit\n * par tableau entier, et un client plus ancien — dont le Zod ignore le champ —\n * effacerait silencieusement le lien en sauvegardant le tableau. Dans sa propre\n * collection, il survit à toutes les écritures de tableau, y compris celles des\n * versions qui ne le connaissent pas.\n *\n * Un seul type pour l'instant, la filiation : `parent` est la carte au-dessus,\n * `child` celle qui en dépend. Une carte a au plus un parent (c'est le\n * `parent_id` habituel), et les deux extrémités peuvent vivre sur des tableaux\n * différents — la même organisation, en revanche, toujours.\n */\nexport const KanbanCardLinkSchema = z.object({\n id: z.string().max(128),\n /** Le tableau et la carte qui *dépendent* de l'autre. */\n childBoardId: z.string().max(64),\n childCardId: z.string().max(128),\n /** Le tableau et la carte *dont* on dépend. */\n parentBoardId: z.string().max(64),\n parentCardId: z.string().max(128),\n createdAt: z.string(),\n createdBy: z.object({ id: z.string().max(128), name: z.string().max(200) }).optional(),\n});\nexport type KanbanCardLink = z.infer<typeof KanbanCardLinkSchema>;\n\n/**\n * De quoi afficher une carte liée sans ouvrir son tableau : son titre, sa\n * colonne, et le tableau où elle se trouve. Résolu à la lecture plutôt que\n * recopié dans le lien — un titre recopié devient faux au premier renommage.\n */\nexport const KanbanCardRefSchema = z.object({\n cardId: z.string().max(128),\n boardId: z.string().max(64),\n boardName: z.string().max(200),\n columnId: z.string().max(128),\n columnTitle: z.string().max(200),\n title: z.string().max(500),\n /** Les mêmes informations qu'une ligne de tableau montre d'une carte d'ici. */\n assignees: z.array(z.object({ id: z.string().max(128), name: z.string().max(200) })).default([]),\n commentCount: z.number().int().nonnegative().default(0),\n});\nexport type KanbanCardRef = z.infer<typeof KanbanCardRefSchema>;\n","import { z } from 'zod';\n\n/**\n * Les clés d'API du cloud : ce qu'un système tiers présente pour alimenter un\n * kanban sans être un humain connecté.\n *\n * Distinctes des clés de `api-key.schema.ts`, qui ouvrent l'API du serveur\n * *local* et nomment des services. Celles-ci appartiennent à une organisation\n * cloud et ne parlent que de tableaux — deux mondes, deux durées de vie, deux\n * écrans : les mélanger ferait qu'une clé de CI dépendrait d'un poste allumé.\n */\n\n/**\n * Ce qu'une clé a le droit de faire. Des portées séparées plutôt qu'un booléen\n * lecture/écriture : commenter est le geste d'un robot de CI qui rend compte, et\n * il n'a aucune raison de pouvoir aussi créer ou déplacer des cartes.\n *\n * `kanban:delete` est à part pour la même raison, en plus net : effacer est le\n * seul geste que rien ne rattrape. Une clé d'alimentation qui pourrait aussi\n * supprimer transformerait un bogue de script en perte de travail.\n */\nexport const CloudApiScopeSchema = z.enum([\n 'kanban:read',\n 'kanban:write',\n 'kanban:comment',\n 'kanban:delete',\n]);\nexport type CloudApiScope = z.infer<typeof CloudApiScopeSchema>;\n\nexport const CLOUD_API_SCOPES: CloudApiScope[] = [\n 'kanban:read',\n 'kanban:write',\n 'kanban:comment',\n 'kanban:delete',\n];\n\n/**\n * Le préfixe de tout secret émis. Il ne protège rien — il se lit dans un dépôt\n * ou un journal, et c'est le but : un scanner de secrets sait quoi chercher, et\n * un humain qui voit `rk_` dans un fichier sait ce qu'il tient.\n */\nexport const CLOUD_API_KEY_PREFIX = 'rk_';\n\n/** `rk_` suivi de 64 caractères hexadécimaux — 32 octets d'aléa. */\nexport const CloudApiKeySecretSchema = z.string().regex(/^rk_[0-9a-f]{64}$/);\n\nexport const CloudApiKeySchema = z.object({\n id: z.string().max(128),\n organizationId: z.string().max(128),\n name: z.string().min(1).max(200),\n scopes: z.array(CloudApiScopeSchema).min(1).max(10),\n /**\n * Les tableaux que la clé peut atteindre, ou `null` pour « tous ceux de\n * l'organisation ».\n *\n * `null` et `[]` ne sont pas la même chose : la liste vide n'ouvre rien, et\n * c'est délibéré — un tableau supprimé ne doit pas élargir une clé qui ne le\n * nommait plus que lui.\n */\n boards: z.array(z.string().max(64)).max(200).nullable(),\n createdAt: z.string().max(64),\n /** Dernier usage constaté, pour reconnaître une clé oubliée. */\n lastUsedAt: z.string().max(64).nullable(),\n /** Qui l'a émise — une clé sans visage ne se révoque jamais sereinement. */\n createdBy: z.object({ id: z.string().max(128), name: z.string().max(200) }),\n /** Les 4 derniers caractères du secret, pour reconnaître une clé dans une liste. */\n keyPreview: z.string().max(8),\n});\nexport type CloudApiKey = z.infer<typeof CloudApiKeySchema>;\n\n/**\n * La réponse de création — la seule fois où le secret circule.\n *\n * Le serveur n'en garde qu'un condensat : personne, pas même l'organisation, ne\n * peut le relire ensuite. Perdue, une clé se remplace, elle ne se retrouve pas.\n */\nexport const CreatedCloudApiKeySchema = z.object({\n key: CloudApiKeySchema,\n secret: CloudApiKeySecretSchema,\n});\nexport type CreatedCloudApiKey = z.infer<typeof CreatedCloudApiKeySchema>;\n\nexport const CreateCloudApiKeyInput = z.object({\n organizationId: z.string().min(1).max(128),\n name: z.string().min(1).max(200),\n scopes: z.array(CloudApiScopeSchema).min(1).max(10),\n boards: z.array(z.string().max(64)).max(200).nullable().default(null),\n});\nexport type CreateCloudApiKeyInput = z.infer<typeof CreateCloudApiKeyInput>;\n\nexport const UpdateCloudApiKeyInput = z.object({\n id: z.string().min(1).max(128),\n name: z.string().min(1).max(200).optional(),\n scopes: z.array(CloudApiScopeSchema).min(1).max(10).optional(),\n boards: z.array(z.string().max(64)).max(200).nullable().optional(),\n});\nexport type UpdateCloudApiKeyInput = z.infer<typeof UpdateCloudApiKeyInput>;\n","import { z } from 'zod';\nimport { KanbanAttachmentSchema } from './kanban.schema.js';\n\n/**\n * Les intégrations de support : un outil de conversation client (Intercom,\n * HubSpot…) qui alimente un kanban du cloud.\n *\n * Le sens est **entrant seulement** : une conversation qui naît devient une\n * carte, ses messages deviennent des commentaires, sa résolution l'archive.\n * Répondre au client se fait toujours dans l'outil d'origine.\n */\n\n/** Les fournisseurs qu'on sait lire. Un de plus = un adaptateur de plus côté cloud. */\nexport const IntegrationProviderSchema = z.enum(['intercom', 'hubspot']);\nexport type IntegrationProvider = z.infer<typeof IntegrationProviderSchema>;\n\n/** Une connexion telle que l'écran de gestion la voit — jamais son secret. */\nexport const IntegrationConnectionSchema = z.object({\n id: z.string().max(128),\n organizationId: z.string().max(128),\n provider: IntegrationProviderSchema,\n name: z.string().min(1).max(200),\n /** Le tableau et la colonne de création — seulement avec la création automatique. */\n boardId: z.string().max(64).nullable(),\n columnId: z.string().max(128).nullable(),\n enabled: z.boolean(),\n /**\n * L'URL complète du webhook à coller chez le fournisseur, construite par le\n * cloud (domaine public des webhooks). Elle contient un jeton imprévisible.\n */\n webhookUrl: z.string().max(2048),\n /** Les quatre derniers caractères du secret de signature, pour le reconnaître. */\n secretPreview: z.string().max(8),\n region: z.string().max(16),\n /** Créer une carte pour toute conversation qui n'est encore liée nulle part. */\n autoCreate: z.boolean(),\n createdBy: z.object({ id: z.string().max(128), name: z.string().max(200) }),\n createdAt: z.string().max(64),\n lastEventAt: z.string().max(64).nullable(),\n});\nexport type IntegrationConnection = z.infer<typeof IntegrationConnectionSchema>;\n\n/** L'état d'une conversation, tel que le fournisseur le dit. */\nexport const IntegrationConversationStateSchema = z.enum(['open', 'resolved']);\n\nexport const IntegrationMessageSchema = z.object({\n id: z.string().max(256),\n author: z.object({ name: z.string().max(500), role: z.enum(['customer', 'agent']) }),\n body: z.string().max(100_000),\n internal: z.boolean(),\n sentAt: z.string().max(64),\n /** Fichiers joints et images, copiés dans Runeya : ils se lisent comme ceux d'une carte. */\n attachments: z.array(KanbanAttachmentSchema).max(50),\n /** Noms des fichiers qui n'ont pas pu être copiés. */\n missingAttachments: z.array(z.string().max(500)).max(50),\n});\nexport type IntegrationMessage = z.infer<typeof IntegrationMessageSchema>;\n\n/** Une conversation telle qu'une carte la montre. */\nexport const IntegrationConversationSchema = z.object({\n id: z.string().max(256),\n connectionId: z.string().max(128),\n provider: IntegrationProviderSchema,\n externalId: z.string().max(128),\n title: z.string().max(500),\n url: z.string().max(2000).nullable(),\n state: IntegrationConversationStateSchema,\n updatedAt: z.string().max(64),\n});\nexport type IntegrationConversation = z.infer<typeof IntegrationConversationSchema>;\n\n/** Une conversation liée à une carte : son fil, et les autres cartes qui la suivent. */\nexport const CardConversationSchema = IntegrationConversationSchema.extend({\n origin: z.enum(['auto', 'manual']),\n /** Les fichiers de la conversation sont en train d'être copiés : ils vont apparaître. */\n filesPending: z.boolean(),\n linkedAt: z.string().max(64),\n opening: z.object({\n author: IntegrationMessageSchema.shape.author,\n body: z.string().max(100_000),\n attachments: z.array(KanbanAttachmentSchema).max(50),\n missingAttachments: z.array(z.string().max(500)).max(50),\n }).nullable(),\n messages: z.array(IntegrationMessageSchema),\n otherCards: z.array(z.object({ boardId: z.string().max(64), cardId: z.string().max(64), title: z.string().max(500) })),\n});\nexport type CardConversation = z.infer<typeof CardConversationSchema>;\n\n/** Un résultat de recherche chez le fournisseur, et les cartes qui la suivent déjà. */\nexport const ConversationSearchHitSchema = IntegrationConversationSchema.extend({\n preview: z.string().max(500),\n linkedCards: z.array(z.object({ boardId: z.string().max(64), cardId: z.string().max(64), title: z.string().max(500) })),\n});\nexport type ConversationSearchHit = z.infer<typeof ConversationSearchHitSchema>;\n","import { z } from 'zod';\n\n/**\n * Le journal des nouveautés, tel qu'il est publié par le cloud.\n *\n * **Deux surfaces, jamais mélangées.** `app` est l'application locale, dont la\n * version est celle du CLI publié sur npm. `cloud` est l'API et son application\n * web, déployées au push et donc sans numéro de version : leurs entrées sont\n * datées. Un même travail qui touche les deux donne DEUX entrées — c'est ce qui\n * permet à un poste resté sur une vieille version de ne pas se voir annoncer des\n * nouveautés qu'il n'a pas, et au cloud d'annoncer les siennes sans attendre une\n * publication npm.\n *\n * L'ordre se déduit de `version` seule (voir `compareChangelogVersions`) : les\n * deux formes — `1.4.2` et `2026-09-03` — se comparent par segments numériques.\n */\n\nexport const ChangelogSurfaceSchema = z.enum(['app', 'cloud']);\nexport type ChangelogSurface = z.infer<typeof ChangelogSurfaceSchema>;\n\n/** Ce que le lecteur doit comprendre en un coup d'œil : est-ce un ajout, un correctif, une rupture. */\nexport const ChangelogChangeKindSchema = z.enum(['feature', 'improvement', 'fix', 'breaking']);\nexport type ChangelogChangeKind = z.infer<typeof ChangelogChangeKindSchema>;\n\n/**\n * Les deux langues de l'interface, toutes deux obligatoires : une entrée\n * publiée dans une seule langue laisserait la moitié des lecteurs devant un\n * trou, et rien dans l'affichage ne pourrait le rattraper.\n */\nexport const ChangelogTextSchema = z.object({\n fr: z.string().min(1).max(500),\n en: z.string().min(1).max(500),\n});\nexport type ChangelogText = z.infer<typeof ChangelogTextSchema>;\n\nexport const ChangelogChangeSchema = z.object({\n kind: ChangelogChangeKindSchema,\n text: ChangelogTextSchema,\n});\nexport type ChangelogChange = z.infer<typeof ChangelogChangeSchema>;\n\n/**\n * Une entrée en attente, telle que l'écrit celui qui fait le travail.\n *\n * Elle ne porte PAS de version : au moment où on l'écrit, le numéro n'existe pas\n * encore — l'app attend sa publication npm, et le cloud n'a jamais de numéro,\n * seulement sa date. Un fichier par entrée, pour que deux branches qui en\n * ajoutent chacune une ne se marchent pas dessus : un tableau partagé produirait\n * un conflit à chaque fusion, et le réflexe sous conflit est d'en perdre une.\n *\n * `title` est facultatif : il nomme la version, pas le changement. La première\n * entrée qui en porte un le donne à sa version ; une version peut n'en avoir\n * aucun, et s'annoncer par son seul numéro.\n */\nexport const ChangelogDraftSchema = ChangelogChangeSchema.extend({\n date: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/),\n title: ChangelogTextSchema.optional(),\n});\nexport type ChangelogDraft = z.infer<typeof ChangelogDraftSchema>;\n\nexport const ChangelogReleaseSchema = z.object({\n surface: ChangelogSurfaceSchema,\n /** `1.4.2` pour l'app (version npm publiée), `2026-09-03` — ou `2026-09-03.2` — pour le cloud. */\n version: z.string().min(1).max(32).regex(/^[0-9][0-9.-]*$/),\n /** Date de publication, `YYYY-MM-DD`. */\n date: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/),\n /** Facultatif : une version peut s'annoncer par son seul numéro. */\n title: ChangelogTextSchema.optional(),\n /** Une version sans changement n'a rien à annoncer : elle n'a pas sa place ici. */\n changes: z.array(ChangelogChangeSchema).min(1).max(50),\n});\nexport type ChangelogRelease = z.infer<typeof ChangelogReleaseSchema>;\n\n/** L'index : de quoi lister et dater, sans transporter les corps. */\nexport const ChangelogIndexItemSchema = ChangelogReleaseSchema.omit({ changes: true }).extend({\n changeCount: z.number().int().nonnegative(),\n});\nexport type ChangelogIndexItem = z.infer<typeof ChangelogIndexItemSchema>;\n\n/**\n * Ordonne deux versions de changelog, quelle que soit leur forme.\n *\n * Les segments sont comparés numériquement (`1.10.0` après `1.9.0`, que la\n * comparaison de chaînes aurait inversé), et une version plus courte perd contre\n * son préfixe plus long (`2026-09-03` avant `2026-09-03.2`).\n */\nexport function compareChangelogVersions(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 const len = Math.max(pa.length, pb.length);\n for (let i = 0; i < len; i++) {\n const da = pa[i] ?? 0;\n const db = pb[i] ?? 0;\n if (da > db) return 1;\n if (da < db) return -1;\n }\n return 0;\n}\n","/**\n * Les bornes du message que le compagnon veut transmettre.\n *\n * Partagées serveur ↔ front parce que les deux en ont besoin pour la même\n * raison : le serveur extrait ce qu'il relaie, le panneau affiche la même chose\n * plutôt que le texte brut avec ses bornes. Recopiées de part et d'autre, une\n * borne renommée d'un seul côté casserait l'affichage sans rien faire échouer.\n */\nexport const COMPANION_RELAY_OPEN = '[RUNEYA_COMPAGNON_RESPONSE]';\nexport const COMPANION_RELAY_CLOSE = '[/RUNEYA_COMPAGNON_RESPONSE]';\n\n/**\n * Le contenu entre les bornes, ou `null` quand il n'y en a pas.\n *\n * La dernière ouverture l'emporte : si le compagnon s'y reprend à deux fois,\n * c'est la seconde qu'il assume. Un bloc non refermé rend ce qui suit\n * l'ouverture — la réponse a été coupée, on ne devine pas où elle s'arrêtait.\n */\nexport function extractCompanionRelay(raw: string): string | null {\n const text = (raw ?? '').trim();\n const open = text.lastIndexOf(COMPANION_RELAY_OPEN);\n if (open === -1) return null;\n const after = text.slice(open + COMPANION_RELAY_OPEN.length);\n const close = after.indexOf(COMPANION_RELAY_CLOSE);\n const inner = (close === -1 ? after : after.slice(0, close)).trim();\n return inner || null;\n}\n","/**\n * Nommage d'un lanceur de bureau — partagé entre le CLI, qui écrit les\n * fichiers, et le serveur, qui propose le raccourci depuis l'interface.\n *\n * Pur : aucune I/O, aucune dépendance à Node. L'identité d'un lanceur est une\n * fonction de son nom d'affichage, et les deux appelants doivent en tirer\n * exactement la même — sans quoi le raccourci créé depuis l'interface ne\n * porterait pas l'id que `uninstall-desktop --name` va chercher.\n */\n\n/** Turn a display name into a filesystem- and desktop-id-safe slug. */\nexport function slugifyLauncherName(name: string): string {\n const slug = name\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n return slug || 'runeya';\n}\n\n/**\n * The id is a pure function of the display name, so `uninstall-desktop --name`\n * always resolves to the launcher that `install-desktop` created. Names that\n * already slug to something starting with \"runeya\" are not prefixed again —\n * without that, the default \"Runeya — my-stack\" would yield the unreachable\n * id \"runeya-runeya-my-stack\".\n */\nexport function launcherIdFromName(name: string): string {\n const slug = slugifyLauncherName(name);\n return slug.startsWith('runeya') ? slug : `runeya-${slug}`;\n}\n\n/** Le dernier segment d'un chemin, sans dépendre de `node:path`. */\nfunction baseName(path: string): string {\n const parts = path.split(/[\\\\/]+/).filter(Boolean);\n return parts[parts.length - 1] ?? path;\n}\n\n/**\n * Derive the display name and id for a launcher.\n * Pinning a directory yields \"Runeya — <folder>\" so several stacks can each\n * have their own entry without colliding.\n */\nexport function deriveLauncherIdentity(\n explicitName: string | undefined,\n workingDir: string | null,\n): { name: string; id: string } {\n const name = explicitName ?? (workingDir ? `Runeya — ${baseName(workingDir)}` : 'Runeya');\n return { name, id: launcherIdFromName(name) };\n}\n","import type { LogSourceConfig } from '../schemas/log-source.schema.js';\n\n/**\n * Ce qui remplace une valeur qu'une IA n'a pas le droit de lire : un secret non\n * partagé (`service.getEnv`), l'identifiant d'une source de logs.\n */\nexport const MASKED_VALUE = '***';\n\n/** Une source de logs, ses identifiants remplacés par `MASKED_VALUE`. */\nexport function maskLogSourceSecrets(sources: LogSourceConfig[]): LogSourceConfig[] {\n return sources.map((src) => {\n if (src.type === 'mongo') return { ...src, connectionString: MASKED_VALUE };\n if (src.type === 'mysql' && src.password) return { ...src, password: MASKED_VALUE };\n return src;\n });\n}\n\n/** Ce qui désigne une source hors de son identifiant : la même base, la même table. */\nfunction sameSource(a: LogSourceConfig, b: LogSourceConfig): boolean {\n if (a.type === 'mongo' && b.type === 'mongo') return a.database === b.database && a.collection === b.collection;\n if (a.type === 'mysql' && b.type === 'mysql') {\n return a.host === b.host && a.port === b.port && a.user === b.user && a.database === b.database;\n }\n return false;\n}\n\n/**\n * Remettre en place les identifiants qu'une liste réécrite a laissés masqués.\n *\n * Une IA qui modifie les sources d'un service les a lues masquées : elle les\n * renvoie avec `MASKED_VALUE` là où était le secret. Il reprend alors la valeur\n * de la source existante qui désigne la même base. Un masque sans source\n * correspondante est refusé — l'écrire tel quel remplacerait l'identifiant par\n * trois astérisques.\n */\nexport function restoreLogSourceSecrets(incoming: LogSourceConfig[], existing: LogSourceConfig[]): LogSourceConfig[] {\n const unmatched = (where: string) =>\n new Error(`Log source ${where}: its credential is masked but no existing source matches it — give the real value.`);\n return incoming.map((src) => {\n if (src.type === 'mongo' && src.connectionString === MASKED_VALUE) {\n const match = existing.find((e) => sameSource(e, src));\n if (match?.type !== 'mongo') throw unmatched(`${src.database}.${src.collection}`);\n return { ...src, connectionString: match.connectionString };\n }\n if (src.type === 'mysql' && src.password === MASKED_VALUE) {\n const match = existing.find((e) => sameSource(e, src));\n if (match?.type !== 'mysql') throw unmatched(`${src.user}@${src.host}:${src.port}/${src.database}`);\n return { ...src, password: match.password };\n }\n return src;\n });\n}\n","import { createCipheriv, createDecipheriv, randomBytes, pbkdf2Sync } from 'node:crypto';\n\nconst PREFIX = 'aes256gcm:';\nconst IV_LENGTH = 12;\nconst AUTH_TAG_LENGTH = 16;\nconst KEY_LENGTH = 32;\nconst PBKDF2_ITERATIONS = 100_000;\nconst PBKDF2_DIGEST = 'sha256';\n/** Fixed salt for key derivation — the purpose is the salt (lazy to avoid Buffer at module init) */\nlet _KDF_SALT: Buffer | undefined;\nfunction getKdfSalt(): Buffer {\n if (!_KDF_SALT) _KDF_SALT = Buffer.from('runeya-log-sources-key-v1', 'utf8');\n return _KDF_SALT;\n}\n\n/**\n * Derives a 32-byte AES-256 key from `rawKey` using PBKDF2-SHA256.\n * The input key may be any Buffer (e.g. the raw passphrase bytes).\n */\nexport function deriveKey(rawKey: Buffer): Buffer {\n return pbkdf2Sync(rawKey, getKdfSalt(), PBKDF2_ITERATIONS, KEY_LENGTH, PBKDF2_DIGEST);\n}\n\n/**\n * Encrypts `plaintext` using AES-256-GCM.\n * Returns a string in the format: `aes256gcm:<iv_hex>:<authTag_hex>:<ciphertext_hex>`\n */\nexport function encrypt(plaintext: string, key: Buffer): string {\n const iv = randomBytes(IV_LENGTH);\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const authTag = cipher.getAuthTag();\n return `${PREFIX}${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted.toString('hex')}`;\n}\n\n/**\n * Decrypts a ciphertext string produced by `encrypt()`.\n * Throws if the format is invalid or authentication fails.\n */\nexport function decrypt(ciphertext: string, key: Buffer): string {\n if (!isEncrypted(ciphertext)) {\n throw new Error('Value is not in encrypted format');\n }\n const parts = ciphertext.slice(PREFIX.length).split(':');\n if (parts.length !== 3) {\n throw new Error('Invalid encrypted value format');\n }\n const [ivHex, authTagHex, encryptedHex] = parts;\n const iv = Buffer.from(ivHex, 'hex');\n const authTag = Buffer.from(authTagHex, 'hex');\n const encryptedBuffer = Buffer.from(encryptedHex, 'hex');\n\n if (iv.length !== IV_LENGTH) throw new Error('Invalid IV length');\n if (authTag.length !== AUTH_TAG_LENGTH) throw new Error('Invalid authTag length');\n\n const decipher = createDecipheriv('aes-256-gcm', key, iv, { authTagLength: 16 });\n decipher.setAuthTag(authTag);\n return Buffer.concat([decipher.update(encryptedBuffer), decipher.final()]).toString('utf8');\n}\n\n/**\n * Returns true if `value` is in the encrypted format produced by `encrypt()`.\n * Safe to call on plain-text values (returns false).\n */\nexport function isEncrypted(value: string): boolean {\n return value.startsWith(PREFIX);\n}\n","import type { JSLogParser } from './schemas/settings.schema.js';\n\n/**\n * Built-in log parsers that ship with Runeya.\n * IDs are prefixed with `native:` to distinguish from user-created parsers.\n *\n * All native parsers use the v2 pipeline signature: (line: LogLine) => LogLine\n * Each parser enriches the LogLine and passes it through. Order matters — the\n * service's parserIds array determines execution order.\n */\n\nconst epoch = new Date('2025-01-01T00:00:00Z');\n\nexport const nativeParsers: JSLogParser[] = [\n {\n id: 'native:json',\n name: 'JSON Log Parser',\n description: 'Parses JSON log lines and extracts level, message, timestamp, metadata, and the full parsed object.',\n code: `(line) => {\n var trimmed = line.message.trim();\n if (!trimmed.startsWith('{')) return line;\n try {\n var obj = JSON.parse(trimmed);\n var level = (obj.level || obj.severity || obj.loglevel || '').toString().toLowerCase();\n var levelMap = { trace: 'debug', debug: 'debug', info: 'info', warn: 'warn', warning: 'warn', error: 'error', fatal: 'fatal', err: 'error' };\n var mappedLevel = levelMap[level] || line.level;\n var message = obj.message || obj.msg || obj.text || trimmed;\n var metadata = {};\n for (var k in obj) {\n if (['level','severity','loglevel','message','msg','text','timestamp','time','ts'].indexOf(k) !== -1) continue;\n metadata[k] = typeof obj[k] === 'string' ? obj[k] : JSON.stringify(obj[k]);\n }\n var merged = {};\n for (var mk in line.metadata) merged[mk] = line.metadata[mk];\n for (var nk in metadata) merged[nk] = metadata[nk];\n return { raw: line.raw, stream: line.stream, level: mappedLevel, message: String(message).slice(0, 16384), hidden: line.hidden, metadata: merged, json: obj, jsonHeader: line.jsonHeader };\n } catch (e) { return line; }\n}`,\n enabled: true,\n builtin: true,\n createdAt: epoch,\n updatedAt: epoch,\n },\n {\n id: 'native:debug',\n name: 'Runeya Debug Parser',\n description: 'Detects Runeya internal debug logs emitted as JSON arrays: [\"runeya\", payload]. Marks them as debug level.',\n code: `(line) => {\n var trimmed = line.message.trim();\n if (!trimmed.startsWith('[')) return line;\n try {\n var parsed = JSON.parse(trimmed);\n if (!Array.isArray(parsed) || parsed[0] !== 'runeya') return line;\n var debug = parsed.length === 2 ? parsed[1] : parsed.slice(1);\n var message = typeof debug === 'string' ? debug : JSON.stringify(debug);\n var merged = {};\n for (var k in line.metadata) merged[k] = line.metadata[k];\n merged.runeya_debug = JSON.stringify(debug);\n return { raw: line.raw, stream: line.stream, level: 'debug', message: message, hidden: line.hidden, metadata: merged, jsonHeader: line.jsonHeader };\n } catch (e) { return line; }\n}`,\n enabled: true,\n builtin: true,\n createdAt: epoch,\n updatedAt: epoch,\n },\n {\n id: 'native:links',\n name: 'Link Detector',\n description: 'Detects URLs in plain-text log lines and exposes them in metadata.links for frontend rendering.',\n code: `(line) => {\n var urlRegex = /(https?|ftp):\\\\/\\\\/[\\\\w_-]+(?:\\\\.[\\\\w_-]+)+([\\\\w.,@?^=%&:/~+#-]*[\\\\w@?^=%&/~+#-])?/gi;\n var urls = line.message.match(urlRegex);\n if (!urls || urls.length === 0) return line;\n var merged = {};\n for (var k in line.metadata) merged[k] = line.metadata[k];\n merged.links = urls.join(' ');\n return { raw: line.raw, stream: line.stream, level: line.level, message: line.message, hidden: line.hidden, metadata: merged, jsonHeader: line.jsonHeader };\n}`,\n enabled: true,\n builtin: true,\n createdAt: epoch,\n updatedAt: epoch,\n },\n];\n\n/** Look up a native parser by ID */\nexport function getNativeParser(id: string): JSLogParser | undefined {\n return nativeParsers.find(p => p.id === id);\n}\n","import vm from 'node:vm';\nimport type { JSLogParser as JSLogParserDef } from './schemas/settings.schema.js';\nimport type { LogLine } from './schemas/log.schema.js';\nimport type { LogLevel } from './schemas/log.schema.js';\n\ninterface CompiledParser {\n id: string;\n name: string;\n enabled: boolean;\n fn: (line: LogLine) => LogLine;\n}\n\nconst VALID_LEVELS = new Set<string>(['debug', 'info', 'warn', 'error', 'fatal']);\n\n/** Budget CPU accordé à un parseur pour *une* ligne. */\nconst PARSE_TIMEOUT_MS = 50;\n/** Au-delà, le parseur est considéré hostile et désactivé pour la session. */\nconst MAX_CONSECUTIVE_TIMEOUTS = 10;\n\nexport class JSLogParser {\n private parsers: CompiledParser[] = [];\n\n constructor(definitions: JSLogParserDef[] = []) {\n this.setParsers(definitions);\n }\n\n setParsers(definitions: JSLogParserDef[]): void {\n this.parsers = [];\n\n for (const def of definitions) {\n if (!def.enabled) continue;\n\n try {\n const compiled = this.compileParser(def);\n this.parsers.push({\n id: def.id,\n name: def.name,\n enabled: true,\n fn: compiled,\n });\n } catch (err) {\n console.warn(\n `[js-log-parser] Failed to compile parser \"${def.name}\" (${def.id}): ${\n err instanceof Error ? err.message : String(err)\n }`\n );\n }\n }\n }\n\n parse(line: LogLine): LogLine {\n let current = line;\n\n for (const parser of this.parsers) {\n try {\n current = parser.fn(current);\n } catch (err) {\n console.warn(\n `[js-log-parser] Parser \"${parser.name}\" threw error: ${\n err instanceof Error ? err.message : String(err)\n }`\n );\n }\n }\n\n return this.sanitize(current);\n }\n\n /**\n * Compile le code utilisateur en une fonction bornée en temps.\n *\n * Le `timeout` de `runInNewContext` ne couvre que l'évaluation de la factory :\n * la closure retournée s'exécutait ensuite ligne par ligne directement sur\n * l'event loop, sans aucune borne. Une regex à backtracking exponentiel\n * fournie par l'utilisateur figeait donc l'agent entier — logs, statuts et\n * métriques de *tous* les services. Chaque invocation repasse maintenant par\n * la vm, avec son propre budget.\n */\n private compileParser(def: JSLogParserDef): (line: LogLine) => LogLine {\n const forbidden = ['require(', 'import ', 'eval('];\n for (const pat of forbidden) {\n if (def.code.includes(pat)) {\n throw new Error('Code contains forbidden patterns (require, import, eval)');\n }\n }\n\n const sandbox = {\n RegExp,\n String,\n Object,\n Array,\n JSON,\n Math,\n Date,\n undefined,\n null: null,\n };\n\n let script: vm.Script;\n try {\n script = new vm.Script(`(${def.code})`, { filename: `parser-${def.id}.js` });\n } catch (err) {\n throw new Error(`Compilation failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // Le contexte est conservé : c'est lui qui permet de ré-entrer dans la vm\n // à chaque ligne, et donc d'armer un timeout par invocation.\n const context = vm.createContext({ ...sandbox, __line: null as unknown, __result: null as unknown });\n\n let parserFn: unknown;\n try {\n parserFn = script.runInContext(context, { timeout: 100 });\n } catch (err) {\n throw new Error(`Execution failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n if (typeof parserFn !== 'function') {\n throw new Error('Parser code must export a function');\n }\n\n (context as Record<string, unknown>)['__parserFn'] = parserFn;\n const callScript = new vm.Script('__result = __parserFn(__line);', {\n filename: `parser-${def.id}-call.js`,\n });\n\n let consecutiveTimeouts = 0;\n let disabled = false;\n\n return (line: LogLine): LogLine => {\n if (disabled) return line;\n\n const ctx = context as Record<string, unknown>;\n ctx['__line'] = line;\n ctx['__result'] = null;\n try {\n callScript.runInContext(context, { timeout: PARSE_TIMEOUT_MS });\n consecutiveTimeouts = 0;\n } catch (err) {\n // `instanceof Error` est faux ici : l'erreur de timeout ne vient pas du\n // même realm que ce module. On la reconnaît par son code/message.\n const e = err as { code?: unknown; message?: unknown } | null;\n const timedOut = !!e\n && (e.code === 'ERR_SCRIPT_EXECUTION_TIMEOUT'\n || (typeof e.message === 'string' && /execution timed out/i.test(e.message)));\n if (!timedOut) throw err;\n consecutiveTimeouts += 1;\n if (consecutiveTimeouts >= MAX_CONSECUTIVE_TIMEOUTS) {\n disabled = true;\n console.warn(\n `[js-log-parser] Parser \"${def.name}\" (${def.id}) disabled after ${MAX_CONSECUTIVE_TIMEOUTS} consecutive timeouts`,\n );\n }\n return line;\n }\n\n const result = ctx['__result'];\n if (result === null || result === undefined || typeof result !== 'object') {\n return line;\n }\n return result as LogLine;\n };\n }\n\n /** Sanitize the final LogLine: truncate message, limit metadata, validate level */\n private sanitize(line: LogLine): LogLine {\n let { message, metadata, level } = line;\n\n if (message.length > 16384) {\n message = message.substring(0, 16384) + '...[truncated]';\n }\n\n metadata = metadata ?? {};\n const metaKeys = Object.keys(metadata);\n if (metaKeys.length > 100) {\n const limited: Record<string, unknown> = {};\n for (let i = 0; i < 100; i++) {\n limited[metaKeys[i]] = metadata[metaKeys[i]];\n }\n metadata = limited;\n }\n\n if (!VALID_LEVELS.has(level)) {\n level = 'info' as LogLevel;\n }\n\n if (message !== line.message || metadata !== line.metadata || level !== line.level) {\n return { ...line, message, metadata, level };\n }\n return line;\n }\n}\n","/**\n * Variables intégrées — les `{{…}}` que Runeya remplit lui-même, par opposition\n * aux `{{environment.KEY}}` que l'utilisateur définit et que le résolveur\n * d'environnement traite (`apps/server/src/services/environment-resolver.ts`).\n *\n * Cette table est la SEULE déclaration : le serveur et l'agent y lisent ce\n * qu'ils doivent produire, l'interface ce qu'elle doit proposer et documenter.\n * Elle a été introduite parce que la liste vivait en trois exemplaires — dans\n * le routeur de service, dans le gestionnaire de processus et dans le tableau\n * de variables du web — et que le web en avait déjà oublié un.\n *\n * ## Portées\n *\n * - `server` : connu à la résolution, quand le serveur prépare la config à\n * déployer (nom, ports, projet, environnement actif).\n * - `agent` : ne peut être résolu QUE sur la machine qui exécute le service —\n * son IP, son utilisateur, son système, son répertoire de travail. Les\n * résoudre côté serveur graverait la machine qui a fait le déploiement, ce\n * qui ne se voit qu'en multi-machines, et tard.\n */\n\nexport type BuiltinScope = 'server' | 'agent';\n\nexport interface BuiltinVariable {\n /** Nom tel qu'il s'écrit entre accolades, sans les accolades */\n name: string;\n scope: BuiltinScope;\n /** Suffixe de la clé i18n de l'interface : `builtins.<descriptionKey>` */\n descriptionKey: string;\n /** Nom conservé pour ne pas casser les configurations existantes */\n deprecatedAlias?: string;\n}\n\nexport const BUILTIN_VARIABLES: readonly BuiltinVariable[] = [\n // ── Le service ───────────────────────────────────────────────────────────\n { name: 'service.NAME', scope: 'server', descriptionKey: 'serviceName' },\n { name: 'service.ID', scope: 'server', descriptionKey: 'serviceId' },\n { name: 'service.PORT', scope: 'server', descriptionKey: 'servicePort' },\n { name: 'service.URL', scope: 'server', descriptionKey: 'serviceUrl' },\n { name: 'service.BASE_URL', scope: 'server', descriptionKey: 'serviceBaseUrl' },\n { name: 'service.CWD', scope: 'agent', descriptionKey: 'serviceCwd' },\n\n // ── Le projet et l'environnement actif ───────────────────────────────────\n { name: 'project.NAME', scope: 'server', descriptionKey: 'projectName' },\n { name: 'runeya.ENV_NAME', scope: 'server', descriptionKey: 'envName' },\n\n // ── Le serveur Runeya ────────────────────────────────────────────────────\n // `service.HOST` a toujours désigné l'adresse d'écoute du SERVEUR, pas une\n // propriété du service : le nom trompait, il devient un alias.\n { name: 'runeya.HOST', scope: 'server', descriptionKey: 'runeyaHost', deprecatedAlias: 'service.HOST' },\n\n // ── La machine qui exécute ───────────────────────────────────────────────\n { name: 'agent.HOST_LAN', scope: 'agent', descriptionKey: 'agentHostLan', deprecatedAlias: 'service.HOST_LAN' },\n // Le NOM de l'agent est une étiquette de la configuration du serveur, pas\n // une propriété de la machine : c'est le serveur qui le connaît et le résout.\n { name: 'agent.NAME', scope: 'server', descriptionKey: 'agentName' },\n { name: 'agent.OS', scope: 'agent', descriptionKey: 'agentOs' },\n { name: 'agent.HOME', scope: 'agent', descriptionKey: 'agentHome' },\n];\n\nexport const BUILTINS_BY_SCOPE = (scope: BuiltinScope): readonly BuiltinVariable[] =>\n BUILTIN_VARIABLES.filter((b) => b.scope === scope);\n\n/**\n * Une référence `{{nom}}`. Le nom accepte les points (`service.PORT`,\n * `services.api.URL`) mais ni espace ni accolade : une référence ne peut donc\n * pas se former à la couture entre deux morceaux de texte.\n */\nconst BUILTIN_REFERENCE_RE = /\\{\\{([A-Za-z][A-Za-z0-9_.-]*)\\}\\}/g;\n\n/** Les `{{environment.KEY}}` appartiennent au résolveur, jamais aux builtins. */\nconst ENVIRONMENT_NAMESPACE = 'environment.';\n\n/** Le préfixe sous lequel un service en nomme un autre : `services.<slug>.PORT`. */\nconst CROSS_SERVICE_NAMESPACE = 'services.';\n\n/**\n * Remplace les références présentes dans `values`, et laisse les autres\n * intactes : une passe unique, jamais récursive — une valeur qui contient\n * elle-même une référence ne relance pas la substitution, faute de quoi deux\n * variables se pointant l'une l'autre boucleraient.\n */\nexport function interpolateBuiltins(text: string, values: Record<string, string>): string {\n return text.replace(BUILTIN_REFERENCE_RE, (match, name: string) => {\n if (name.startsWith(ENVIRONMENT_NAMESPACE)) return match;\n return values[name] ?? match;\n });\n}\n\n/**\n * Les slugs de services qu'un texte nomme, via `{{services.<slug>.PROP}}`.\n *\n * C'est l'arête d'un graphe de dépendances : si une variable de A cite\n * `services.b.PORT`, c'est que A a besoin de B pour tourner. La détection\n * s'appuie sur la MÊME expression que `interpolateBuiltins`, pour ne jamais\n * annoncer un lien que l'interpolation ne ferait pas — `{{services. b.URL}}`\n * n'est pas une référence, et ne doit donc pas devenir une arête.\n *\n * Une référence sans propriété (`{{services.b}}`) ne résout rien : elle ne\n * compte pas non plus.\n */\nexport function crossServiceSlugsIn(text: string): string[] {\n const slugs = new Set<string>();\n for (const match of text.matchAll(BUILTIN_REFERENCE_RE)) {\n const name = match[1];\n if (!name || !name.startsWith(CROSS_SERVICE_NAMESPACE)) continue;\n const rest = name.slice(CROSS_SERVICE_NAMESPACE.length);\n const dot = rest.indexOf('.');\n if (dot <= 0 || dot === rest.length - 1) continue;\n slugs.add(rest.slice(0, dot));\n }\n return [...slugs];\n}\n\n/** `interpolateBuiltins` appliqué à chaque valeur d'un dictionnaire d'env. */\nexport function interpolateBuiltinsInEnv(\n env: Record<string, string>,\n values: Record<string, string>,\n): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [key, value] of Object.entries(env)) {\n out[key] = interpolateBuiltins(value, values);\n }\n return out;\n}\n\n/**\n * Ajoute au dictionnaire les alias hérités, pour que `{{service.HOST}}`\n * continue de rendre ce que rend `{{runeya.HOST}}`.\n */\nexport function withDeprecatedAliases(values: Record<string, string>): Record<string, string> {\n const out = { ...values };\n for (const builtin of BUILTIN_VARIABLES) {\n if (builtin.deprecatedAlias && out[builtin.name] !== undefined) {\n out[builtin.deprecatedAlias] = out[builtin.name];\n }\n }\n return out;\n}\n\n/**\n * Nom sous lequel un service est adressable depuis un autre\n * (`{{services.<slug>.PORT}}`).\n *\n * Un nom de service est libre — accents, espaces, majuscules — alors qu'une\n * référence doit rester un mot sans espace. D'où ce passage en minuscules\n * tiretées, appliqué de la même façon par le serveur qui produit les valeurs\n * et par l'interface qui les propose.\n */\nexport function serviceSlug(name: string): string {\n return name\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\n/**\n * Les slugs que deux services d'un même projet se disputent.\n *\n * Un tel slug n'est adressable pour AUCUN des deux : rendre l'un plutôt que\n * l'autre dépendrait de l'ordre de chargement. La règle est ici, et non chez\n * ses deux appelants — celui qui produit les valeurs à interpoler et celui qui\n * dessine le graphe des liens — parce qu'ils doivent dire la même chose : un\n * lien montré à l'écran mais non interpolé au démarrage serait pire que pas de\n * lien du tout.\n */\nexport function ambiguousServiceSlugs(names: readonly string[]): Set<string> {\n const counts = new Map<string, number>();\n for (const name of names) {\n const slug = serviceSlug(name);\n if (slug) counts.set(slug, (counts.get(slug) ?? 0) + 1);\n }\n return new Set([...counts].filter(([, count]) => count > 1).map(([slug]) => slug));\n}\n\n/**\n * Les ports d'un service : `service.PORT` pour le premier — celui qu'on cite\n * dans neuf cas sur dix — puis `service.PORT_2`, `_3`… pour les suivants.\n */\nexport function servicePortValues(ports: readonly number[] | undefined, prefix = 'service'): Record<string, string> {\n const values: Record<string, string> = {};\n (ports ?? []).forEach((port, i) => {\n values[i === 0 ? `${prefix}.PORT` : `${prefix}.PORT_${i + 1}`] = String(port);\n });\n return values;\n}\n\n/**\n * Une adresse d'écoute « toutes interfaces » n'est pas une adresse à laquelle\n * on se connecte. En mode LAN, le serveur écoute sur `0.0.0.0` : bâtir\n * `http://0.0.0.0:3000` donnerait une URL que rien ne peut joindre.\n */\nexport function isWildcardHost(host: string): boolean {\n const h = host.trim();\n return h === '' || h === '0.0.0.0' || h === '::' || h === '[::]';\n}\n\n/** L'adresse de bouclage, sous ses écritures possibles. */\nfunction isLoopbackHost(host: string): boolean {\n const h = host.trim();\n return h === '127.0.0.1' || h === '::1' || h === '[::1]';\n}\n\n/**\n * L'hôte à écrire dans une URL, à partir de l'adresse d'écoute du serveur.\n *\n * La boucle locale devient `localhost` : c'est le nom que les développeurs\n * écrivent, celui des origines autorisées du dépôt, et celui qu'on colle dans\n * un navigateur. `{{runeya.HOST}}` continue de rendre l'adresse réelle — c'est\n * elle qu'un service met dans son bind, et la traduire là serait faux.\n *\n * Un hôte explicitement configuré (une IP de LAN, un nom de machine) n'est\n * jamais réécrit : le seul cas traduit est celui où l'adresse ne désigne que\n * « cette machine ». Une adresse « toutes interfaces » rend `null` — à\n * l'appelant de décider, l'agent connaissant seul son IP joignable.\n */\nexport function urlHostFor(host: string): string | null {\n if (isWildcardHost(host)) return null;\n return isLoopbackHost(host) ? 'localhost' : host.trim();\n}\n\n/**\n * Les URL par lesquelles on joint un service, une par port : `service.URL`,\n * `service.URL_2`… numérotées comme les ports, si bien que `URL_2` désigne\n * toujours le service sur `PORT_2`.\n *\n * Un domaine local est déclaré AVEC son port (c'est ce que le proxy route) :\n * l'URL d'un port est donc son domaine s'il en a un, sinon l'hôte et le port.\n * Un domaine déclaré sur un port absent de la liste des ports est ajouté à la\n * suite, pour ne pas se perdre.\n *\n * À ne pas confondre avec le champ `url` du service — son « URL de base »,\n * saisie librement, souvent l'adresse publique : celle-là s'écrit\n * `{{service.BASE_URL}}`. Faire rendre l'une par l'autre romprait la\n * correspondance entre `URL_n` et `PORT_n`.\n */\nexport function serviceUrlValues(service: {\n ports?: number[];\n localUrls?: { url: string; port: number }[];\n}, host: string, prefix = 'service'): Record<string, string> {\n const domainByPort = new Map((service.localUrls ?? []).map((lu) => [lu.port, lu.url]));\n const ports = [...(service.ports ?? [])];\n for (const local of service.localUrls ?? []) {\n if (!ports.includes(local.port)) ports.push(local.port);\n }\n\n const values: Record<string, string> = {};\n ports.forEach((port, i) => {\n const domain = domainByPort.get(port);\n values[i === 0 ? `${prefix}.URL` : `${prefix}.URL_${i + 1}`] =\n domain ? `http://${domain}` : `http://${host}:${port}`;\n });\n return values;\n}\n\n/** Les clés `services.<slug>.*` exposées pour un service voisin. */\nexport function crossServiceValues(service: {\n name: string;\n id: string;\n ports?: number[];\n localUrls?: { url: string; port: number }[];\n url?: string;\n}, host: string): Record<string, string> {\n const slug = serviceSlug(service.name);\n if (!slug) return {};\n return {\n [`services.${slug}.NAME`]: service.name,\n [`services.${slug}.ID`]: service.id,\n ...servicePortValues(service.ports, `services.${slug}`),\n ...serviceUrlValues(service, host, `services.${slug}`),\n ...(service.url ? { [`services.${slug}.BASE_URL`]: service.url } : {}),\n };\n}\n\n/** Une référence qu'aucune étape ne remplira : elle arrivera telle quelle dans le process. */\nexport interface UnresolvedReference {\n key: string;\n reference: string;\n}\n\n/** Les ports et URL numérotés que le serveur produit en plus des noms déclarés : `service.PORT_2`. */\nconst NUMBERED_SERVICE_BUILTIN_RE = /^service\\.(PORT|URL)_\\d+$/;\n\nfunction builtinScopeOf(name: string): BuiltinScope | null {\n const builtin = BUILTIN_VARIABLES.find((b) => b.name === name || b.deprecatedAlias === name);\n if (builtin) return builtin.scope;\n if (NUMBERED_SERVICE_BUILTIN_RE.test(name) || name.startsWith(CROSS_SERVICE_NAMESPACE)) return 'server';\n return null;\n}\n\n/**\n * Les références restées en place dans un env résolu, et qui le resteront.\n *\n * Le résolveur d'environnement, puis le serveur, puis l'agent remplissent\n * chacun les leurs et laissent intactes les autres — si bien qu'une faute de\n * frappe (`{{environment.DB_HSOT}}`) arrive au process comme du texte, sans\n * que rien ne le signale. Ce qui est signalé dépend de l'étape atteinte :\n *\n * - une référence d'environnement : toujours, le résolveur est déjà passé ;\n * - une variable intégrée du serveur : si `serverResolved` — sinon elle attend\n * le déploiement ; mais un nom qui n'en est pas une est une faute dans les\n * deux cas ;\n * - une variable intégrée de l'agent : jamais, elle se remplit au démarrage.\n *\n * `skipKeys` tait des clés — celles dont la valeur est masquée : la forme d'un\n * secret, références comprises, n'a pas à sortir.\n */\nexport function findUnresolvedReferences(\n env: Record<string, string>,\n opts: { serverResolved: boolean; skipKeys?: Iterable<string> },\n): UnresolvedReference[] {\n const skip = new Set(opts.skipKeys ?? []);\n const out: UnresolvedReference[] = [];\n for (const [key, value] of Object.entries(env)) {\n if (skip.has(key)) continue;\n for (const match of value.matchAll(BUILTIN_REFERENCE_RE)) {\n const reference = match[1]!;\n if (!reference.startsWith(ENVIRONMENT_NAMESPACE)) {\n const scope = builtinScopeOf(reference);\n if (scope === 'agent') continue;\n if (scope === 'server' && !opts.serverResolved) continue;\n }\n out.push({ key, reference });\n }\n }\n return out;\n}\n\n/** Une valeur recopiée, et la référence qui la suivrait. */\nexport interface BuiltinSuggestion {\n literal: string;\n reference: string;\n}\n\n/** Les variables intégrées qui valent la peine d'être reconnues : ports et adresses, du service ou d'un voisin. */\nconst SUGGESTABLE_BUILTIN_RE = /^(service|services\\.[^.]+)\\.(PORT|URL|BASE_URL)(_\\d+)?$/;\n\n/**\n * Les ports et URL de services recopiés dans une valeur, avec la référence qui\n * les remplacerait.\n *\n * Recopier `http://localhost:3211` fige l'adresse du front telle qu'elle est sur\n * ce poste, aujourd'hui : elle ne suit ni un changement de port ni un domaine\n * local. `{{services.front.URL}}`, si. `builtins` est ce que le serveur calcule\n * pour le service concerné (`buildServerBuiltins`).\n *\n * La plus longue valeur l'emporte (une URL avant le port qu'elle contient), et\n * à longueur égale la référence du service lui-même avant celle qui le nomme de\n * l'extérieur. Un nombre n'est reconnu qu'entier, et rien n'est lu à\n * l'intérieur d'une référence déjà écrite. Ce ne sont que des suggestions : la\n * valeur n'est jamais réécrite.\n */\nexport function suggestBuiltinReferences(text: string, builtins: Record<string, string>): BuiltinSuggestion[] {\n const candidates = Object.entries(builtins)\n .filter(([name, value]) => SUGGESTABLE_BUILTIN_RE.test(name) && value.length > 1 && !value.includes('{{'))\n .sort(([nameA, a], [nameB, b]) => b.length - a.length || Number(nameA.startsWith('services.')) - Number(nameB.startsWith('services.')));\n\n const claimed: [number, number][] = [...text.matchAll(BUILTIN_REFERENCE_RE)].map((m) => [m.index, m.index + m[0].length]);\n const overlaps = (start: number, end: number) => claimed.some(([s, e]) => start < e && end > s);\n const isDigit = (c: string | undefined) => c !== undefined && c >= '0' && c <= '9';\n\n const suggestions: BuiltinSuggestion[] = [];\n for (const [name, literal] of candidates) {\n let from = 0;\n for (let at = text.indexOf(literal, from); at !== -1; at = text.indexOf(literal, from)) {\n const end = at + literal.length;\n from = at + 1;\n if (overlaps(at, end)) continue;\n if (isDigit(literal[0]) && isDigit(text[at - 1])) continue;\n if (isDigit(literal[literal.length - 1]) && isDigit(text[end])) continue;\n claimed.push([at, end]);\n if (!suggestions.some((s) => s.literal === literal)) suggestions.push({ literal, reference: `{{${name}}}` });\n }\n }\n return suggestions;\n}\n","export const PROCESS_STATES = ['starting', 'running', 'stopped', 'errored'] as const;\nexport type ProcessStateValue = typeof PROCESS_STATES[number];\n","export const LOG_LEVELS = ['debug', 'info', 'warn', 'error', 'fatal'] as const;\nexport type LogLevelValue = typeof LOG_LEVELS[number];\n\nexport const LOG_LEVEL_PRIORITY: Record<LogLevelValue, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n fatal: 4,\n};\n","export const GLOBAL_ROLES = ['owner', 'admin', 'member'] as const;\nexport type GlobalRoleValue = typeof GLOBAL_ROLES[number];\n\nexport const PROJECT_ROLES = ['admin', 'editor', 'viewer'] as const;\nexport type ProjectRoleValue = typeof PROJECT_ROLES[number];\n","/** Health check default interval (ms) */\nexport const HEALTH_CHECK_INTERVAL = 30_000;\n\n/** Metrics collection interval (ms) */\nexport const METRICS_INTERVAL = 5_000;\n\n/** Agent health polling interval (ms) */\nexport const AGENT_HEALTH_POLL_INTERVAL = 15_000;\n\n/** UI search/filter debounce (ms) */\nexport const SEARCH_DEBOUNCE = 300;\n\n/** Health check initial delay before first check (ms) */\nexport const HEALTH_CHECK_INITIAL_DELAY = 5_000;\n\n/** Agent health WS interval (ms) */\nexport const HEALTH_WS_INTERVAL = 10_000;\n","/** Default log ring buffer size */\nexport const LOG_BUFFER_SIZE = 5_000;\n\n/** Max log entries displayed in UI */\nexport const LOG_DISPLAY_LIMIT = 500;\n","/** Default process grace period before SIGKILL (ms) */\nexport const GRACE_PERIOD = 10_000;\n\n/** HTTP fetch timeout for agent calls (ms) */\nexport const AGENT_FETCH_TIMEOUT = 10_000;\n\n/** HTTP fetch timeout for long-running agent calls like shortcuts/ad-hoc commands (ms) — 10 minutes */\nexport const AGENT_LONG_FETCH_TIMEOUT = 600_000;\n\n/** HTTP fetch timeout for process stop calls (ms) — grace period + generous buffer */\nexport const AGENT_STOP_FETCH_TIMEOUT = GRACE_PERIOD + 15_000;\n\n/** Passphrase extraction timeout during agent spawn (ms) */\nexport const PASSPHRASE_TIMEOUT = 30_000;\n\n/** Min WS reconnect delay (ms) */\nexport const WS_RECONNECT_MIN = 1_000;\n\n/** Max WS reconnect delay (ms) */\nexport const WS_RECONNECT_MAX = 15_000;\n\n/** Max WS reconnect attempts */\nexport const WS_RECONNECT_MAX_ATTEMPTS = 5;\n\n/** Base retry delay for subscriptions (ms) */\nexport const SUBSCRIPTION_RETRY_BASE = 1_000;\n","export interface EditorDefinition {\n key: string;\n name: string;\n command: string;\n}\n\nexport const SUPPORTED_EDITORS: EditorDefinition[] = [\n { key: 'vscode', name: 'Visual Studio Code', command: 'code' },\n { key: 'cursor', name: 'Cursor', command: 'cursor' },\n { key: 'windsurf', name: 'Windsurf', command: 'windsurf' },\n { key: 'sublime', name: 'Sublime Text', command: 'subl' },\n { key: 'atom', name: 'Atom', command: 'atom' },\n { key: 'antigravity', name: 'Antigravity', command: 'antigravity' },\n { key: 'intellij', name: 'IntelliJ IDEA', command: 'idea' },\n { key: 'android-studio', name: 'Android Studio', command: 'studio' },\n { key: 'webstorm', name: 'WebStorm', command: 'webstorm' },\n { key: 'zed', name: 'Zed', command: 'zed' },\n { key: 'neovim', name: 'Neovim', command: 'nvim' },\n { key: 'vim', name: 'Vim', command: 'vim' },\n { key: 'emacs', name: 'Emacs', command: 'emacs' },\n { key: 'fleet', name: 'Fleet', command: 'fleet' },\n];\n\nexport const EDITOR_BY_KEY = new Map<string, EditorDefinition>(\n SUPPORTED_EDITORS.map((e) => [e.key, e]),\n);\n","import * as Y from 'yjs';\n\n/**\n * Generic JSON ↔ Yjs mapping.\n *\n * The cloud must share exactly what git shares: the contents of the `.runeya`\n * files, whatever fields they happen to carry today. Enumerating those fields\n * would make this a hand-maintained allowlist — adding a field to a schema and\n * forgetting it here would not break anything, it would just silently stop\n * syncing. So nothing here names a field: any JSON shape round-trips.\n *\n * The mapping is structural rather than blob-per-file, because a blob makes\n * every concurrent edit last-writer-wins across a whole file. Mapping objects to\n * `Y.Map` and arrays to `Y.Array` lets Yjs merge edits to different fields — and\n * different array elements — the way it is meant to.\n *\n * Every write is a *diff*: identical input must produce no Yjs update at all.\n * Anything less loops forever (local → doc → local → doc).\n */\n\nexport type Json = null | boolean | number | string | Json[] | { [k: string]: Json };\n\n/**\n * Strip `undefined` and other non-JSON values by round-tripping.\n *\n * Zod leaves optional fields absent while JS code tends to set them to\n * `undefined`; `Y.Map.set(k, undefined)` is not `delete(k)`, so without this the\n * diff would see a change on every pass and never settle.\n */\nexport function normalize(value: unknown): Json {\n return JSON.parse(JSON.stringify(value ?? null)) as Json;\n}\n\nfunction isPlainObject(v: unknown): v is Record<string, Json> {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n\n/** Yjs value → plain JSON. */\nexport function toPlain(value: unknown): Json {\n if (value instanceof Y.Map) {\n const out: Record<string, Json> = {};\n for (const [k, v] of value.entries()) out[k] = toPlain(v);\n return out;\n }\n if (value instanceof Y.Array) return value.toArray().map(toPlain);\n return (value ?? null) as Json;\n}\n\n/**\n * Identity of an array element, used to align two versions of an array.\n *\n * An element with an `id` keeps that identity across edits, so a concurrent\n * change to one element and an insertion of another merge cleanly. Anything\n * else (scalars, objects with no id) is identified by its whole value: editing\n * it reads as delete + insert, i.e. last-writer-wins for that element.\n */\nfunction identityOf(value: Json): string {\n if (isPlainObject(value) && typeof value['id'] === 'string') return `id:${value['id']}`;\n return `v:${JSON.stringify(value)}`;\n}\n\nfunction identityOfY(value: unknown): string {\n if (value instanceof Y.Map) {\n const id = value.get('id');\n if (typeof id === 'string') return `id:${id}`;\n }\n return `v:${JSON.stringify(toPlain(value))}`;\n}\n\n/** Convert a JSON value into the Yjs type that represents it. */\nfunction toY(value: Json): unknown {\n if (Array.isArray(value)) {\n const arr = new Y.Array<unknown>();\n if (value.length > 0) arr.insert(0, value.map(toY));\n return arr;\n }\n if (isPlainObject(value)) {\n const map = new Y.Map<unknown>();\n for (const [k, v] of Object.entries(value)) map.set(k, toY(v));\n return map;\n }\n return value;\n}\n\n/**\n * Diff `next` into a `Y.Map`, recursing into nested objects and arrays and\n * deleting keys that `next` no longer has.\n */\nexport function applyToMap(map: Y.Map<unknown>, next: Record<string, Json>): void {\n for (const key of Array.from(map.keys())) {\n if (!(key in next)) map.delete(key);\n }\n for (const [key, value] of Object.entries(next)) {\n const current = map.get(key);\n if (Array.isArray(value)) {\n if (!(current instanceof Y.Array)) map.set(key, toY(value));\n else applyToArray(current, value);\n } else if (isPlainObject(value)) {\n if (!(current instanceof Y.Map)) map.set(key, toY(value));\n else applyToMap(current, value);\n } else if (current instanceof Y.Map || current instanceof Y.Array || current !== value) {\n map.set(key, value);\n }\n }\n}\n\n/**\n * Diff `next` into a `Y.Array` by aligning elements on their identity.\n *\n * Targeted inserts/deletes are what let Yjs keep both sides of a concurrent\n * append; rewriting the array wholesale (delete-all + insert) would drop one of\n * them, which is exactly the data loss this mapping exists to avoid.\n */\nexport function applyToArray(arr: Y.Array<unknown>, next: Json[]): void {\n const wanted = next.map(identityOf);\n const wantedCount = new Map<string, number>();\n for (const k of wanted) wantedCount.set(k, (wantedCount.get(k) ?? 0) + 1);\n\n // Drop elements `next` no longer contains (respecting duplicate counts).\n const seen = new Map<string, number>();\n for (let i = arr.length - 1; i >= 0; i--) {\n const key = identityOfY(arr.get(i));\n const used = seen.get(key) ?? 0;\n if (used >= (wantedCount.get(key) ?? 0)) arr.delete(i, 1);\n else seen.set(key, used + 1);\n }\n\n // Walk both sides in order: recurse into matches, insert what is missing.\n for (let j = 0; j < next.length; j++) {\n const key = wanted[j]!;\n if (j < arr.length && identityOfY(arr.get(j)) === key) {\n const current = arr.get(j);\n const value = next[j]!;\n if (current instanceof Y.Map && isPlainObject(value)) applyToMap(current, value);\n else if (current instanceof Y.Array && Array.isArray(value)) applyToArray(current, value);\n continue;\n }\n // Pull a later match into place rather than re-creating it, so a reorder\n // does not read as a delete + insert of unrelated content.\n let found = -1;\n for (let k = j + 1; k < arr.length; k++) {\n if (identityOfY(arr.get(k)) === key) {\n found = k;\n break;\n }\n }\n if (found !== -1) {\n const moved = toPlain(arr.get(found));\n arr.delete(found, 1);\n arr.insert(j, [toY(moved)]);\n } else {\n arr.insert(j, [toY(next[j]!)]);\n }\n }\n}\n\n/** A collection of entities keyed by id: `doc.getMap(name)` → `{ [id]: Y.Map }`. */\nexport function getCollection(doc: Y.Doc, name: string): Y.Map<unknown> {\n return doc.getMap(name);\n}\n\n/** Read one entity as plain JSON, or null when absent/malformed. */\nexport function readEntity(collection: Y.Map<unknown>, id: string): Record<string, Json> | null {\n const entity = collection.get(id);\n if (!(entity instanceof Y.Map)) return null;\n const plain = toPlain(entity);\n return isPlainObject(plain) ? plain : null;\n}\n\n/**\n * Write one entity, mutating only what differs. Must run inside\n * `doc.transact(..., origin)` so the bridge can tell local writes from remote.\n */\nexport function writeEntity(collection: Y.Map<unknown>, id: string, entity: unknown): void {\n const next = normalize(entity);\n if (!isPlainObject(next)) return;\n const current = collection.get(id);\n if (!(current instanceof Y.Map)) {\n collection.set(id, toY(next));\n return;\n }\n applyToMap(current, next);\n}\n","/**\n * Les adresses auxquelles un service répond, par ordre de préférence.\n *\n * Partagé parce que deux surfaces posent la même question : l'en-tête de\n * service dans l'interface, qui les affiche toutes, et l'icône de barre\n * système, qui n'ouvre que la première. Écrire deux fois cet ordre de\n * préférence, c'est se donner deux endroits où « Ouvrir » peut mener ailleurs\n * que le bouton juste à côté.\n */\n\n/** D'où vient un lien — l'appelant s'en sert pour choisir une icône. */\nexport type ServiceLinkSource = 'cloud' | 'port' | 'custom';\n\nexport type ServiceLink = {\n url: string;\n source: ServiceLinkSource;\n};\n\ntype LinkableService = {\n /** Adresses publiques servies par le cloud, avec le port qu'elles couvrent. */\n localUrls?: { url: string; port: number }[] | undefined;\n ports?: number[] | undefined;\n url?: string | undefined;\n};\n\nconst LOOPBACK_HOSTNAMES = new Set(['localhost', '127.0.0.1', '::1', '[::1]']);\n\n/**\n * Ce qui fait que deux liens mènent au même endroit.\n *\n * Un slash final ne désigne pas une autre page, et `127.0.0.1` est un autre\n * nom pour `localhost` — l'« URL de base » peut redire ainsi ce qu'un port\n * produit déjà. En revanche une IP de LAN N'EST PAS ramenée à `localhost` :\n * l'une se joint depuis le réseau, l'autre seulement depuis cette machine, et\n * les confondre ferait disparaître un point d'accès.\n */\nfunction dedupeKey(url: string): string {\n const trimmed = url.trim().replace(/\\/+$/, '');\n try {\n const parsed = new URL(trimmed);\n if (LOOPBACK_HOSTNAMES.has(parsed.hostname)) parsed.hostname = 'localhost';\n return parsed.toString().replace(/\\/+$/, '');\n } catch {\n return trimmed;\n }\n}\n\n/**\n * @param host L'hôte auquel joindre les ports — `localhost`, ou l'adresse du\n * poste en mode réseau local. L'appelant seul sait laquelle il présente.\n */\nexport function serviceLinks(service: LinkableService, host: string): ServiceLink[] {\n // Un port déjà servi par une adresse publique ne mérite pas un second lien\n // vers la même chose en local.\n const served = new Set((service.localUrls ?? []).map((lu) => lu.port));\n\n const candidates: ServiceLink[] = [\n ...(service.localUrls ?? []).map((lu): ServiceLink => ({ url: `https://${lu.url}`, source: 'cloud' })),\n ...(service.ports ?? [])\n .filter((port) => !served.has(port))\n .map((port): ServiceLink => ({ url: `http://${host}:${port}`, source: 'port' })),\n ...(service.url ? [{ url: service.url, source: 'custom' as const }] : []),\n ];\n\n const seen = new Set<string>();\n return candidates.filter(({ url }) => {\n const key = dedupeKey(url);\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\n/** La première adresse d'un service, ou `null` s'il n'en expose aucune. */\nexport function primaryServiceLink(service: LinkableService, host: string): string | null {\n return serviceLinks(service, host)[0]?.url ?? null;\n}\n"],"mappings":"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","names":["z","z","z","z","z","z","z","z","clearable","z","z"]}